Em Thu, Oct 23, 2014 at 01:45:13PM +0300, Adrian Hunter escreveu: > This patch introduces an abstraction for exporting sample > data in a database-friendly way. The abstraction does not > implement the actual output. A subsequent patch takes this > facility into use for extending the script interface. > > The abstraction is needed because static data like symbols, > dsos, comms etc need to be exported only once. That means > allocating them a unique identifier and recording it on each > structure. The member 'db_id' is used for that. 'db_id' > is just a 64-bit sequence number. > > Exporting centres around the db_export__sample() function > which exports the associated data structures if they have > not yet been allocated a db_id.
So this ends up bloating all data structures with 8 extra bytes, can't we use the priv pointer that some of the structures already have for tooling to put tool specific stuff? In places like this: > @@ -25,6 +25,7 @@ struct thread { > bool dead; /* if set thread has exited */ > struct list_head comm_list; > int comm_len; > + u64 db_id; > > void *priv; > struct thread_stack *ts; Instead we would have: union { void *priv; u64 db_id; }; Using a unnamed union is all that is needed in struct thread case, I think, the rest of your patch that deals with 'struct thread' doesn't need to change and the end impact for other tools that have no use whatsoever fot this thread->db_id is zero. Because after all you will end up using some tool to just process samples, etc, i.e. basically a 'perf report' like tool that instead of creating hist_entries, etc will end up just populating the machines -> machine -> threads -> map_groups -> map -> dso -> symbols Hierarchy, right? Struct symbol even has a mechanism for reserving space for private use, that symbol_conf.priv_size + symbol__priv(), so that we don't incur even in the cost of the priv pointer. struct perf_evsel already has: union { void *priv; off_t id_offset; }; Just add db_id there and the rest of your patch that deals with perf_evsel will not need to be changed and again the impact for tools that do not use this will be zero. The other data structures that still don't have a ->priv area can have one added. I.e. tool specific bloating of core data structures should be avoided. Fixing up these things will allow a good chunk of this patchkit to be processed. Thanks, - Arnaldo > Signed-off-by: Adrian Hunter <adrian.hun...@intel.com> > --- > tools/perf/Makefile.perf | 2 + > tools/perf/util/comm.h | 1 + > tools/perf/util/db-export.c | 268 > ++++++++++++++++++++++++++++++++++++++++++++ > tools/perf/util/db-export.h | 86 ++++++++++++++ > tools/perf/util/dso.h | 1 + > tools/perf/util/evsel.h | 1 + > tools/perf/util/machine.h | 1 + > tools/perf/util/symbol.h | 1 + > tools/perf/util/thread.h | 1 + > 9 files changed, 362 insertions(+) > create mode 100644 tools/perf/util/db-export.c > create mode 100644 tools/perf/util/db-export.h > > diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf > index 5bbe1ff..9134c93 100644 > --- a/tools/perf/Makefile.perf > +++ b/tools/perf/Makefile.perf > @@ -305,6 +305,7 @@ LIB_H += ui/ui.h > LIB_H += util/data.h > LIB_H += util/kvm-stat.h > LIB_H += util/thread-stack.h > +LIB_H += util/db-export.h > > LIB_OBJS += $(OUTPUT)util/abspath.o > LIB_OBJS += $(OUTPUT)util/alias.o > @@ -382,6 +383,7 @@ LIB_OBJS += $(OUTPUT)util/data.o > LIB_OBJS += $(OUTPUT)util/tsc.o > LIB_OBJS += $(OUTPUT)util/cloexec.o > LIB_OBJS += $(OUTPUT)util/thread-stack.o > +LIB_OBJS += $(OUTPUT)util/db-export.o > > LIB_OBJS += $(OUTPUT)ui/setup.o > LIB_OBJS += $(OUTPUT)ui/helpline.o > diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h > index 51c10ab..99e7021 100644 > --- a/tools/perf/util/comm.h > +++ b/tools/perf/util/comm.h > @@ -10,6 +10,7 @@ struct comm_str; > struct comm { > struct comm_str *comm_str; > u64 start; > + u64 db_id; > struct list_head list; > bool exec; > }; > diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c > new file mode 100644 > index 0000000..53d0e75 > --- /dev/null > +++ b/tools/perf/util/db-export.c > @@ -0,0 +1,268 @@ > +/* > + * db-export.c: Support for exporting data suitable for import to a database > + * Copyright (c) 2014, Intel Corporation. > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + */ > + > +#include <errno.h> > + > +#include "evsel.h" > +#include "machine.h" > +#include "thread.h" > +#include "comm.h" > +#include "symbol.h" > +#include "event.h" > +#include "db-export.h" > + > +int db_export__init(struct db_export *dbe) > +{ > + memset(dbe, 0, sizeof(struct db_export)); > + return 0; > +} > + > +void db_export__exit(struct db_export *dbe __maybe_unused) > +{ > +} > + > +int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel) > +{ > + if (evsel->db_id) > + return 0; > + > + evsel->db_id = ++dbe->evsel_last_db_id; > + > + if (dbe->export_evsel) > + return dbe->export_evsel(dbe, evsel); > + > + return 0; > +} > + > +int db_export__machine(struct db_export *dbe, struct machine *machine) > +{ > + if (machine->db_id) > + return 0; > + > + machine->db_id = ++dbe->machine_last_db_id; > + > + if (dbe->export_machine) > + return dbe->export_machine(dbe, machine); > + > + return 0; > +} > + > +int db_export__thread(struct db_export *dbe, struct thread *thread, > + struct machine *machine, struct comm *comm) > +{ > + u64 main_thread_db_id = 0; > + int err; > + > + if (thread->db_id) > + return 0; > + > + thread->db_id = ++dbe->thread_last_db_id; > + > + if (thread->pid_ != -1) { > + struct thread *main_thread; > + > + if (thread->pid_ == thread->tid) { > + main_thread = thread; > + } else { > + main_thread = machine__findnew_thread(machine, > + thread->pid_, > + thread->pid_); > + if (!main_thread) > + return -ENOMEM; > + err = db_export__thread(dbe, main_thread, machine, > + comm); > + if (err) > + return err; > + if (comm) { > + err = db_export__comm_thread(dbe, comm, thread); > + if (err) > + return err; > + } > + } > + main_thread_db_id = main_thread->db_id; > + } > + > + if (dbe->export_thread) > + return dbe->export_thread(dbe, thread, main_thread_db_id, > + machine); > + > + return 0; > +} > + > +int db_export__comm(struct db_export *dbe, struct comm *comm, > + struct thread *main_thread) > +{ > + int err; > + > + if (comm->db_id) > + return 0; > + > + comm->db_id = ++dbe->comm_last_db_id; > + > + if (dbe->export_comm) { > + err = dbe->export_comm(dbe, comm); > + if (err) > + return err; > + } > + > + return db_export__comm_thread(dbe, comm, main_thread); > +} > + > +int db_export__comm_thread(struct db_export *dbe, struct comm *comm, > + struct thread *thread) > +{ > + u64 db_id; > + > + db_id = ++dbe->comm_thread_last_db_id; > + > + if (dbe->export_comm_thread) > + return dbe->export_comm_thread(dbe, db_id, comm, thread); > + > + return 0; > +} > + > +int db_export__dso(struct db_export *dbe, struct dso *dso, > + struct machine *machine) > +{ > + if (dso->db_id) > + return 0; > + > + dso->db_id = ++dbe->dso_last_db_id; > + > + if (dbe->export_dso) > + return dbe->export_dso(dbe, dso, machine); > + > + return 0; > +} > + > +int db_export__symbol(struct db_export *dbe, struct symbol *sym, > + struct dso *dso) > +{ > + if (sym->db_id) > + return 0; > + > + sym->db_id = ++dbe->symbol_last_db_id; > + > + if (dbe->export_symbol) > + return dbe->export_symbol(dbe, sym, dso); > + > + return 0; > +} > + > +static struct thread *get_main_thread(struct machine *machine, > + struct thread *thread) > +{ > + if (thread->pid_ == thread->tid) > + return thread; > + > + if (thread->pid_ == -1) > + return NULL; > + > + return machine__find_thread(machine, thread->pid_, thread->pid_); > +} > + > +static int db_ids_from_al(struct db_export *dbe, struct addr_location *al, > + u64 *dso_db_id, u64 *sym_db_id, u64 *offset) > +{ > + int err; > + > + if (al->map) { > + struct dso *dso = al->map->dso; > + > + err = db_export__dso(dbe, dso, al->machine); > + if (err) > + return err; > + *dso_db_id = dso->db_id; > + > + if (!al->sym) { > + al->sym = symbol__new(al->addr, 0, 0, "unknown"); > + if (al->sym) > + symbols__insert(&dso->symbols[al->map->type], > + al->sym); > + } > + > + if (al->sym) { > + err = db_export__symbol(dbe, al->sym, dso); > + if (err) > + return err; > + *sym_db_id = al->sym->db_id; > + *offset = al->addr - al->sym->start; > + } > + } > + > + return 0; > +} > + > +int db_export__sample(struct db_export *dbe, union perf_event *event, > + struct perf_sample *sample, struct perf_evsel *evsel, > + struct thread *thread, struct addr_location *al) > +{ > + struct export_sample es = { > + .event = event, > + .sample = sample, > + .evsel = evsel, > + .thread = thread, > + .al = al, > + }; > + struct thread *main_thread; > + struct comm *comm = NULL; > + int err; > + > + err = db_export__evsel(dbe, evsel); > + if (err) > + return err; > + > + err = db_export__machine(dbe, al->machine); > + if (err) > + return err; > + > + main_thread = get_main_thread(al->machine, thread); > + if (main_thread) > + comm = machine__thread_exec_comm(al->machine, main_thread); > + > + err = db_export__thread(dbe, thread, al->machine, comm); > + if (err) > + return err; > + > + if (comm) { > + err = db_export__comm(dbe, comm, main_thread); > + if (err) > + return err; > + es.comm_db_id = comm->db_id; > + } > + > + es.db_id = ++dbe->sample_last_db_id; > + > + err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset); > + if (err) > + return err; > + > + if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && > + sample_addr_correlates_sym(&evsel->attr)) { > + struct addr_location addr_al; > + > + perf_event__preprocess_sample_addr(event, sample, al->machine, > + thread, &addr_al); > + err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id, > + &es.addr_sym_db_id, &es.addr_offset); > + if (err) > + return err; > + } > + > + if (dbe->export_sample) > + return dbe->export_sample(dbe, &es); > + > + return 0; > +} > diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h > new file mode 100644 > index 0000000..b3643e8 > --- /dev/null > +++ b/tools/perf/util/db-export.h > @@ -0,0 +1,86 @@ > +/* > + * db-export.h: Support for exporting data suitable for import to a database > + * Copyright (c) 2014, Intel Corporation. > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + */ > + > +#ifndef __PERF_DB_EXPORT_H > +#define __PERF_DB_EXPORT_H > + > +#include <linux/types.h> > + > +struct perf_evsel; > +struct machine; > +struct thread; > +struct comm; > +struct dso; > +struct perf_sample; > +struct addr_location; > + > +struct export_sample { > + union perf_event *event; > + struct perf_sample *sample; > + struct perf_evsel *evsel; > + struct thread *thread; > + struct addr_location *al; > + u64 db_id; > + u64 comm_db_id; > + u64 dso_db_id; > + u64 sym_db_id; > + u64 offset; /* ip offset from symbol start */ > + u64 addr_dso_db_id; > + u64 addr_sym_db_id; > + u64 addr_offset; /* addr offset from symbol start */ > +}; > + > +struct db_export { > + int (*export_evsel)(struct db_export *dbe, struct perf_evsel *evsel); > + int (*export_machine)(struct db_export *dbe, struct machine *machine); > + int (*export_thread)(struct db_export *dbe, struct thread *thread, > + u64 main_thread_db_id, struct machine *machine); > + int (*export_comm)(struct db_export *dbe, struct comm *comm); > + int (*export_comm_thread)(struct db_export *dbe, u64 db_id, > + struct comm *comm, struct thread *thread); > + int (*export_dso)(struct db_export *dbe, struct dso *dso, > + struct machine *machine); > + int (*export_symbol)(struct db_export *dbe, struct symbol *sym, > + struct dso *dso); > + int (*export_sample)(struct db_export *dbe, struct export_sample *es); > + u64 evsel_last_db_id; > + u64 machine_last_db_id; > + u64 thread_last_db_id; > + u64 comm_last_db_id; > + u64 comm_thread_last_db_id; > + u64 dso_last_db_id; > + u64 symbol_last_db_id; > + u64 sample_last_db_id; > +}; > + > +int db_export__init(struct db_export *dbe); > +void db_export__exit(struct db_export *dbe); > +int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel); > +int db_export__machine(struct db_export *dbe, struct machine *machine); > +int db_export__thread(struct db_export *dbe, struct thread *thread, > + struct machine *machine, struct comm *comm); > +int db_export__comm(struct db_export *dbe, struct comm *comm, > + struct thread *main_thread); > +int db_export__comm_thread(struct db_export *dbe, struct comm *comm, > + struct thread *thread); > +int db_export__dso(struct db_export *dbe, struct dso *dso, > + struct machine *machine); > +int db_export__symbol(struct db_export *dbe, struct symbol *sym, > + struct dso *dso); > +int db_export__sample(struct db_export *dbe, union perf_event *event, > + struct perf_sample *sample, struct perf_evsel *evsel, > + struct thread *thread, struct addr_location *al); > + > +#endif > diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h > index acb651a..8463fc3 100644 > --- a/tools/perf/util/dso.h > +++ b/tools/perf/util/dso.h > @@ -111,6 +111,7 @@ struct dso { > enum dso_swap_type needs_swap; > enum dso_binary_type symtab_type; > enum dso_binary_type binary_type; > + u64 db_id; > u8 adjust_symbols:1; > u8 has_build_id:1; > u8 has_srcline:1; > diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h > index 4861e8c..4777262 100644 > --- a/tools/perf/util/evsel.h > +++ b/tools/perf/util/evsel.h > @@ -95,6 +95,7 @@ struct perf_evsel { > int sample_read; > struct perf_evsel *leader; > char *group_name; > + u64 db_id; > }; > > union u64_swap { > diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h > index 2b651a7..4bc57e5 100644 > --- a/tools/perf/util/machine.h > +++ b/tools/perf/util/machine.h > @@ -40,6 +40,7 @@ struct machine { > u64 kernel_start; > symbol_filter_t symbol_filter; > pid_t *current_tid; > + u64 db_id; > }; > > static inline > diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h > index eb2c19b..6f54ade 100644 > --- a/tools/perf/util/symbol.h > +++ b/tools/perf/util/symbol.h > @@ -73,6 +73,7 @@ struct symbol { > struct rb_node rb_node; > u64 start; > u64 end; > + u64 db_id; > u16 namelen; > u8 binding; > bool ignore; > diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h > index a057820..a3ebb21 100644 > --- a/tools/perf/util/thread.h > +++ b/tools/perf/util/thread.h > @@ -25,6 +25,7 @@ struct thread { > bool dead; /* if set thread has exited */ > struct list_head comm_list; > int comm_len; > + u64 db_id; > > void *priv; > struct thread_stack *ts; > -- > 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/