From 016e92fbc9ef33689cf654f343a94383d43235e7 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 7 Oct 2009 12:47:31 +0200 Subject: perf tools: Unify perf.data mapping and events handling This librarizes the perf.data file mapping and handling in various perf tools, roughly reducing the amount of code and fixing the places that mmap from beginning of the file whereas we want to mmap from the beginning of the data, leading to page fault because the mmap window is too small since the trace info are written in the file too. TODO: - convert perf timechart too Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras Cc: Arjan van de Ven LKML-Reference: <20091007104729.GD5043@nowhere> Signed-off-by: Ingo Molnar --- tools/perf/util/data_map.c | 222 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 tools/perf/util/data_map.c (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c new file mode 100644 index 00000000000..242b0555ab9 --- /dev/null +++ b/tools/perf/util/data_map.c @@ -0,0 +1,222 @@ +#include "data_map.h" +#include "symbol.h" +#include "util.h" +#include "debug.h" + + +static struct perf_file_handler *curr_handler; +static unsigned long mmap_window = 32; +static char __cwd[PATH_MAX]; + +static int +process_event_stub(event_t *event __used, + unsigned long offset __used, + unsigned long head __used) +{ + return 0; +} + +void register_perf_file_handler(struct perf_file_handler *handler) +{ + if (!handler->process_sample_event) + handler->process_sample_event = process_event_stub; + if (!handler->process_mmap_event) + handler->process_mmap_event = process_event_stub; + if (!handler->process_comm_event) + handler->process_comm_event = process_event_stub; + if (!handler->process_fork_event) + handler->process_fork_event = process_event_stub; + if (!handler->process_exit_event) + handler->process_exit_event = process_event_stub; + if (!handler->process_lost_event) + handler->process_lost_event = process_event_stub; + if (!handler->process_read_event) + handler->process_read_event = process_event_stub; + if (!handler->process_throttle_event) + handler->process_throttle_event = process_event_stub; + if (!handler->process_unthrottle_event) + handler->process_unthrottle_event = process_event_stub; + + curr_handler = handler; +} + +static int +process_event(event_t *event, unsigned long offset, unsigned long head) +{ + trace_event(event); + + switch (event->header.type) { + case PERF_RECORD_SAMPLE: + return curr_handler->process_sample_event(event, offset, head); + case PERF_RECORD_MMAP: + return curr_handler->process_mmap_event(event, offset, head); + case PERF_RECORD_COMM: + return curr_handler->process_comm_event(event, offset, head); + case PERF_RECORD_FORK: + return curr_handler->process_fork_event(event, offset, head); + case PERF_RECORD_EXIT: + return curr_handler->process_exit_event(event, offset, head); + case PERF_RECORD_LOST: + return curr_handler->process_lost_event(event, offset, head); + case PERF_RECORD_READ: + return curr_handler->process_read_event(event, offset, head); + case PERF_RECORD_THROTTLE: + return curr_handler->process_throttle_event(event, offset, head); + case PERF_RECORD_UNTHROTTLE: + return curr_handler->process_unthrottle_event(event, offset, head); + default: + curr_handler->total_unknown++; + return -1; + } +} + +int mmap_dispatch_perf_file(struct perf_header **pheader, + const char *input_name, + int force, + int full_paths, + int *cwdlen, + char **cwd) +{ + int ret, rc = EXIT_FAILURE; + struct perf_header *header; + unsigned long head, shift; + unsigned long offset = 0; + struct stat input_stat; + size_t page_size; + u64 sample_type; + event_t *event; + uint32_t size; + int input; + char *buf; + + if (!curr_handler) + die("Forgot to register perf file handler"); + + page_size = getpagesize(); + + input = open(input_name, O_RDONLY); + if (input < 0) { + fprintf(stderr, " failed to open file: %s", input_name); + if (!strcmp(input_name, "perf.data")) + fprintf(stderr, " (try 'perf record' first)"); + fprintf(stderr, "\n"); + exit(-1); + } + + ret = fstat(input, &input_stat); + if (ret < 0) { + perror("failed to stat file"); + exit(-1); + } + + if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { + fprintf(stderr, "file: %s not owned by current user or root\n", + input_name); + exit(-1); + } + + if (!input_stat.st_size) { + fprintf(stderr, "zero-sized file, nothing to do!\n"); + exit(0); + } + + *pheader = perf_header__read(input); + header = *pheader; + head = header->data_offset; + + sample_type = perf_header__sample_type(header); + + if (curr_handler->sample_type_check) + if (curr_handler->sample_type_check(sample_type) < 0) + exit(-1); + + if (load_kernel() < 0) { + perror("failed to load kernel symbols"); + return EXIT_FAILURE; + } + + if (!full_paths) { + if (getcwd(__cwd, sizeof(__cwd)) == NULL) { + perror("failed to get the current directory"); + return EXIT_FAILURE; + } + *cwd = __cwd; + *cwdlen = strlen(*cwd); + } else { + *cwd = NULL; + *cwdlen = 0; + } + + shift = page_size * (head / page_size); + offset += shift; + head -= shift; + +remap: + buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, + MAP_SHARED, input, offset); + if (buf == MAP_FAILED) { + perror("failed to mmap file"); + exit(-1); + } + +more: + event = (event_t *)(buf + head); + + size = event->header.size; + if (!size) + size = 8; + + if (head + event->header.size >= page_size * mmap_window) { + int munmap_ret; + + shift = page_size * (head / page_size); + + munmap_ret = munmap(buf, page_size * mmap_window); + assert(munmap_ret == 0); + + offset += shift; + head -= shift; + goto remap; + } + + size = event->header.size; + + dump_printf("\n%p [%p]: event: %d\n", + (void *)(offset + head), + (void *)(long)event->header.size, + event->header.type); + + if (!size || process_event(event, offset, head) < 0) { + + dump_printf("%p [%p]: skipping unknown header type: %d\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->header.type); + + /* + * assume we lost track of the stream, check alignment, and + * increment a single u64 in the hope to catch on again 'soon'. + */ + + if (unlikely(head & 7)) + head &= ~7ULL; + + size = 8; + } + + head += size; + + if (offset + head >= header->data_offset + header->data_size) + goto done; + + if (offset + head < (unsigned long)input_stat.st_size) + goto more; + +done: + rc = EXIT_SUCCESS; + close(input); + + return rc; +} + + -- cgit v1.2.3-70-g09d2 From e42049926ebdcae24fdfdc8f0e3ff8f05f24a60b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 20 Oct 2009 14:25:40 -0200 Subject: perf annotate: Use the sym_priv_size area for the histogram We have this sym_priv_size mechanism for attaching private areas to struct symbol entries but annotate wasn't using it, adding private areas to struct symbol in addition to a ->priv pointer. Scrap all that and use the sym_priv_size mechanism. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Mike Galbraith LKML-Reference: <1256055940-19511-1-git-send-email-acme@redhat.com> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 109 ++++++++++++++++++++++++++++++------------ tools/perf/builtin-report.c | 2 +- tools/perf/util/data_map.c | 2 +- tools/perf/util/event.h | 8 +++- tools/perf/util/map.c | 21 +++++++- tools/perf/util/symbol.c | 56 ++++++++-------------- tools/perf/util/symbol.h | 17 +++---- 7 files changed, 132 insertions(+), 83 deletions(-) (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 06f10278b28..245692530de 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -37,12 +37,44 @@ static int print_line; static unsigned long page_size; static unsigned long mmap_window = 32; +struct sym_hist { + u64 sum; + u64 ip[0]; +}; + struct sym_ext { struct rb_node node; double percent; char *path; }; +struct sym_priv { + struct sym_hist *hist; + struct sym_ext *ext; +}; + +static const char *sym_hist_filter; + +static int symbol_filter(struct map *map, struct symbol *sym) +{ + if (strcmp(sym->name, sym_hist_filter) == 0) { + struct sym_priv *priv = dso__sym_priv(map->dso, sym); + const int size = (sizeof(*priv->hist) + + (sym->end - sym->start) * sizeof(u64)); + + priv->hist = malloc(size); + if (priv->hist) + memset(priv->hist, 0, size); + return 0; + } + /* + * FIXME: We should really filter it out, as we don't want to go thru symbols + * we're not interested, and if a DSO ends up with no symbols, delete it too, + * but right now the kernel loading routines in symbol.c bail out if no symbols + * are found, fix it later. + */ + return 0; +} /* * collect histogram counts @@ -51,10 +83,16 @@ static void hist_hit(struct hist_entry *he, u64 ip) { unsigned int sym_size, offset; struct symbol *sym = he->sym; + struct sym_priv *priv; + struct sym_hist *h; he->count++; - if (!sym || !sym->hist) + if (!sym || !he->map) + return; + + priv = dso__sym_priv(he->map->dso, sym); + if (!priv->hist) return; sym_size = sym->end - sym->start; @@ -67,15 +105,16 @@ static void hist_hit(struct hist_entry *he, u64 ip) if (offset >= sym_size) return; - sym->hist_sum++; - sym->hist[offset]++; + h = priv->hist; + h->sum++; + h->ip[offset]++; if (verbose >= 3) printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", (void *)(unsigned long)he->sym->start, he->sym->name, (void *)(unsigned long)ip, ip - he->sym->start, - sym->hist[offset]); + h->ip[offset]); } static int hist_entry__add(struct thread *thread, struct map *map, @@ -162,7 +201,9 @@ got_map: static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct map *map = map__new(&event->mmap, NULL, 0); + struct map *map = map__new(&event->mmap, NULL, 0, + sizeof(struct sym_priv), symbol_filter, + verbose); struct thread *thread = threads__findnew(event->mmap.pid); dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n", @@ -314,17 +355,19 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) unsigned int hits = 0; double percent = 0.0; const char *color; - struct sym_ext *sym_ext = sym->priv; + struct sym_priv *priv = dso__sym_priv(he->map->dso, sym); + struct sym_ext *sym_ext = priv->ext; + struct sym_hist *h = priv->hist; offset = line_ip - start; if (offset < len) - hits = sym->hist[offset]; + hits = h->ip[offset]; if (offset < len && sym_ext) { path = sym_ext[offset].path; percent = sym_ext[offset].percent; - } else if (sym->hist_sum) - percent = 100.0 * hits / sym->hist_sum; + } else if (h->sum) + percent = 100.0 * hits / h->sum; color = get_percent_color(percent); @@ -377,9 +420,10 @@ static void insert_source_line(struct sym_ext *sym_ext) rb_insert_color(&sym_ext->node, &root_sym_ext); } -static void free_source_line(struct symbol *sym, int len) +static void free_source_line(struct hist_entry *he, int len) { - struct sym_ext *sym_ext = sym->priv; + struct sym_priv *priv = dso__sym_priv(he->map->dso, he->sym); + struct sym_ext *sym_ext = priv->ext; int i; if (!sym_ext) @@ -389,7 +433,7 @@ static void free_source_line(struct symbol *sym, int len) free(sym_ext[i].path); free(sym_ext); - sym->priv = NULL; + priv->ext = NULL; root_sym_ext = RB_ROOT; } @@ -402,15 +446,16 @@ get_source_line(struct hist_entry *he, int len, const char *filename) int i; char cmd[PATH_MAX * 2]; struct sym_ext *sym_ext; + struct sym_priv *priv = dso__sym_priv(he->map->dso, sym); + struct sym_hist *h = priv->hist; - if (!sym->hist_sum) + if (!h->sum) return; - sym->priv = calloc(len, sizeof(struct sym_ext)); - if (!sym->priv) + sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext)); + if (!priv->ext) return; - sym_ext = sym->priv; start = he->map->unmap_ip(he->map, sym->start); for (i = 0; i < len; i++) { @@ -419,7 +464,7 @@ get_source_line(struct hist_entry *he, int len, const char *filename) u64 offset; FILE *fp; - sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum; + sym_ext[i].percent = 100.0 * h->ip[i] / h->sum; if (sym_ext[i].percent <= 0.5) continue; @@ -530,7 +575,7 @@ static void annotate_sym(struct hist_entry *he) pclose(file); if (print_line) - free_source_line(sym, len); + free_source_line(he, len); } static void find_annotations(void) @@ -540,19 +585,23 @@ static void find_annotations(void) for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); + struct sym_priv *priv; - if (he->sym && he->sym->hist) { - annotate_sym(he); - count++; - /* - * Since we have a hist_entry per IP for the same - * symbol, free he->sym->hist to signal we already - * processed this symbol. - */ - free(he->sym->hist); - he->sym->hist = NULL; + if (he->sym == NULL) + continue; - } + priv = dso__sym_priv(he->map->dso, he->sym); + if (priv->hist == NULL) + continue; + + annotate_sym(he); + count++; + /* + * Since we have a hist_entry per IP for the same symbol, free + * he->sym->hist to signal we already processed this symbol. + */ + free(priv->hist); + priv->hist = NULL; } if (!count) @@ -593,7 +642,7 @@ static int __cmd_annotate(void) exit(0); } - if (load_kernel() < 0) { + if (load_kernel(sizeof(struct sym_priv), symbol_filter) < 0) { perror("failed to load kernel symbols"); return EXIT_FAILURE; } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index a4f8cc20915..bee207ce589 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -680,7 +680,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct map *map = map__new(&event->mmap, cwd, cwdlen); + struct map *map = map__new(&event->mmap, cwd, cwdlen, 0, NULL, verbose); struct thread *thread = threads__findnew(event->mmap.pid); dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n", diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index 242b0555ab9..18accb8fee4 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -130,7 +130,7 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, if (curr_handler->sample_type_check(sample_type) < 0) exit(-1); - if (load_kernel() < 0) { + if (load_kernel(0, NULL) < 0) { perror("failed to load kernel symbols"); return EXIT_FAILURE; } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 6b5be56a827..db59c8bbe49 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -101,7 +101,13 @@ static inline u64 identity__map_ip(struct map *map __used, u64 ip) return ip; } -struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen); +struct symbol; + +typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); + +struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, + unsigned int sym_priv_size, symbol_filter_t filter, + int v); struct map *map__clone(struct map *self); int map__overlap(struct map *l, struct map *r); size_t map__fprintf(struct map *self, FILE *fp); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 4e203d144f9..55079c0200e 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -3,6 +3,7 @@ #include #include #include +#include "debug.h" static inline int is_anon_memory(const char *filename) { @@ -19,7 +20,9 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen) return n; } - struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen) +struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, + unsigned int sym_priv_size, symbol_filter_t filter, + int v) { struct map *self = malloc(sizeof(*self)); @@ -27,6 +30,7 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen) const char *filename = event->filename; char newfilename[PATH_MAX]; int anon; + bool new_dso; if (cwd) { int n = strcommon(filename, cwd, cwdlen); @@ -49,10 +53,23 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen) self->end = event->start + event->len; self->pgoff = event->pgoff; - self->dso = dsos__findnew(filename); + self->dso = dsos__findnew(filename, sym_priv_size, &new_dso); if (self->dso == NULL) goto out_delete; + if (new_dso) { + int nr = dso__load(self->dso, self, filter, v); + + if (nr < 0) + eprintf("Failed to open %s, continuing " + "without symbols\n", + self->dso->long_name); + else if (nr == 0) + eprintf("No symbols found in %s, maybe " + "install a debug package?\n", + self->dso->long_name); + } + if (self->dso == vdso || anon) self->map_ip = self->unmap_ip = identity__map_ip; else { diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 3350119f690..0a4898480d6 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -11,8 +11,6 @@ #include #include -const char *sym_hist_filter; - enum dso_origin { DSO__ORIG_KERNEL = 0, DSO__ORIG_JAVA_JIT, @@ -86,22 +84,16 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name, if (!self) return NULL; - if (v > 2) - printf("new symbol: %016Lx [%08lx]: %s, hist: %p\n", - start, (unsigned long)len, name, self->hist); - - self->hist = NULL; - self->hist_sum = 0; - - if (sym_hist_filter && !strcmp(name, sym_hist_filter)) - self->hist = calloc(sizeof(u64), len); - if (priv_size) { memset(self, 0, priv_size); self = ((void *)self) + priv_size; } self->start = start; self->end = len ? start + len - 1 : start; + + if (v > 2) + printf("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); + memcpy(self->name, name, namelen); return self; @@ -919,7 +911,8 @@ char dso__symtab_origin(const struct dso *self) return origin[self->origin]; } -int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, int v) +int dso__load(struct dso *self, struct map *map, + symbol_filter_t filter, int v) { int size = PATH_MAX; char *name = malloc(size), *build_id = NULL; @@ -1335,33 +1328,21 @@ static struct dso *dsos__find(const char *name) return NULL; } -struct dso *dsos__findnew(const char *name) +struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size, + bool *is_new) { struct dso *dso = dsos__find(name); - int nr; - - if (dso) - return dso; - - dso = dso__new(name, 0); - if (!dso) - goto out_delete_dso; - nr = dso__load(dso, NULL, NULL, verbose); - if (nr < 0) { - eprintf("Failed to open: %s\n", name); - goto out_delete_dso; - } - if (!nr) - eprintf("No symbols found in: %s, maybe install a debug package?\n", name); - - dsos__add(dso); + if (!dso) { + dso = dso__new(name, sym_priv_size); + if (dso) { + dsos__add(dso); + *is_new = true; + } + } else + *is_new = false; return dso; - -out_delete_dso: - dso__delete(dso); - return NULL; } void dsos__fprintf(FILE *fp) @@ -1372,9 +1353,10 @@ void dsos__fprintf(FILE *fp) dso__fprintf(pos, fp); } -int load_kernel(void) +int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter) { - if (dsos__load_kernel(vmlinux_name, 0, NULL, verbose, modules) <= 0) + if (dsos__load_kernel(vmlinux_name, sym_priv_size, + filter, verbose, modules) <= 0) return -1; vdso = dso__new("[vdso]", 0); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 2e4522edeb0..c2a777de9b7 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -2,6 +2,7 @@ #define __PERF_SYMBOL 1 #include +#include #include "types.h" #include #include @@ -35,9 +36,6 @@ struct symbol { struct rb_node rb_node; u64 start; u64 end; - u64 hist_sum; - u64 *hist; - void *priv; char name[0]; }; @@ -54,10 +52,6 @@ struct dso { char name[0]; }; -extern const char *sym_hist_filter; - -typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); - struct dso *dso__new(const char *name, unsigned int sym_priv_size); void dso__delete(struct dso *self); @@ -70,15 +64,16 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip); int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, symbol_filter_t filter, int verbose, int modules); -int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, - int verbose); -struct dso *dsos__findnew(const char *name); +struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size, + bool *is_new); +int dso__load(struct dso *self, struct map *map, + symbol_filter_t filter, int v); void dsos__fprintf(FILE *fp); size_t dso__fprintf(struct dso *self, FILE *fp); char dso__symtab_origin(const struct dso *self); -int load_kernel(void); +int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter); void symbol__init(void); -- cgit v1.2.3-70-g09d2 From 00a192b395b0606ad0265243844b3cd68e73420a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 30 Oct 2009 16:28:24 -0200 Subject: perf tools: Simplify the symbol priv area mechanism Before we were storing this in the DSO, but in fact this is a property of the 'symbol' class, not something that will vary among DSOs, so move it to a global variable and initialize it using the existing symbol__init routine. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Mike Galbraith LKML-Reference: <1256927305-4628-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 21 ++++++------ tools/perf/builtin-report.c | 4 +-- tools/perf/builtin-sched.c | 2 +- tools/perf/builtin-timechart.c | 2 +- tools/perf/builtin-top.c | 12 +++---- tools/perf/builtin-trace.c | 2 +- tools/perf/util/data_map.c | 2 +- tools/perf/util/event.h | 3 +- tools/perf/util/map.c | 5 ++- tools/perf/util/symbol.c | 73 ++++++++++++++++++++---------------------- tools/perf/util/symbol.h | 24 +++++++------- 11 files changed, 70 insertions(+), 80 deletions(-) (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 8688bfee42a..77d50a6d680 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -55,11 +55,11 @@ struct sym_priv { static const char *sym_hist_filter; -static int symbol_filter(struct map *map, struct symbol *sym) +static int symbol_filter(struct map *map __used, struct symbol *sym) { if (sym_hist_filter == NULL || strcmp(sym->name, sym_hist_filter) == 0) { - struct sym_priv *priv = dso__sym_priv(map->dso, sym); + struct sym_priv *priv = symbol__priv(sym); const int size = (sizeof(*priv->hist) + (sym->end - sym->start) * sizeof(u64)); @@ -92,7 +92,7 @@ static void hist_hit(struct hist_entry *he, u64 ip) if (!sym || !he->map) return; - priv = dso__sym_priv(he->map->dso, sym); + priv = symbol__priv(sym); if (!priv->hist) return; @@ -202,8 +202,7 @@ got_map: static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct map *map = map__new(&event->mmap, NULL, 0, - sizeof(struct sym_priv)); + struct map *map = map__new(&event->mmap, NULL, 0); struct thread *thread = threads__findnew(event->mmap.pid); dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n", @@ -355,7 +354,7 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) unsigned int hits = 0; double percent = 0.0; const char *color; - struct sym_priv *priv = dso__sym_priv(he->map->dso, sym); + struct sym_priv *priv = symbol__priv(sym); struct sym_ext *sym_ext = priv->ext; struct sym_hist *h = priv->hist; @@ -422,7 +421,7 @@ static void insert_source_line(struct sym_ext *sym_ext) static void free_source_line(struct hist_entry *he, int len) { - struct sym_priv *priv = dso__sym_priv(he->map->dso, he->sym); + struct sym_priv *priv = symbol__priv(he->sym); struct sym_ext *sym_ext = priv->ext; int i; @@ -446,7 +445,7 @@ get_source_line(struct hist_entry *he, int len, const char *filename) int i; char cmd[PATH_MAX * 2]; struct sym_ext *sym_ext; - struct sym_priv *priv = dso__sym_priv(he->map->dso, sym); + struct sym_priv *priv = symbol__priv(sym); struct sym_hist *h = priv->hist; if (!h->sum) @@ -589,7 +588,7 @@ static void find_annotations(void) if (he->sym == NULL) continue; - priv = dso__sym_priv(he->map->dso, he->sym); + priv = symbol__priv(he->sym); if (priv->hist == NULL) continue; @@ -637,7 +636,7 @@ static int __cmd_annotate(void) exit(0); } - if (load_kernel(sizeof(struct sym_priv), symbol_filter) < 0) { + if (load_kernel(symbol_filter) < 0) { perror("failed to load kernel symbols"); return EXIT_FAILURE; } @@ -769,7 +768,7 @@ static void setup_sorting(void) int cmd_annotate(int argc, const char **argv, const char *prefix __used) { - symbol__init(); + symbol__init(sizeof(struct sym_priv)); page_size = getpagesize(); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index f1bcd35bd22..1a806d5f05c 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -751,7 +751,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct map *map = map__new(&event->mmap, cwd, cwdlen, 0); + struct map *map = map__new(&event->mmap, cwd, cwdlen); struct thread *thread = threads__findnew(event->mmap.pid); dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n", @@ -1093,7 +1093,7 @@ static void setup_list(struct strlist **list, const char *list_str, int cmd_report(int argc, const char **argv, const char *prefix __used) { - symbol__init(); + symbol__init(0); argc = parse_options(argc, argv, options, report_usage, 0); diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 9a48d9626be..df44b756cec 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1937,7 +1937,7 @@ static int __cmd_record(int argc, const char **argv) int cmd_sched(int argc, const char **argv, const char *prefix __used) { - symbol__init(); + symbol__init(0); argc = parse_options(argc, argv, sched_options, sched_usage, PARSE_OPT_STOP_AT_NON_OPTION); diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 0a2f22261c3..665877e4a94 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1266,7 +1266,7 @@ static const struct option options[] = { int cmd_timechart(int argc, const char **argv, const char *prefix __used) { - symbol__init(); + symbol__init(0); page_size = getpagesize(); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ee87640b335..2aea913f7eb 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -789,7 +789,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) strstr(name, "_text_end")) return 1; - syme = dso__sym_priv(map->dso, sym); + syme = symbol__priv(sym); syme->map = map; pthread_mutex_init(&syme->source_lock, NULL); if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) @@ -807,8 +807,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) static int parse_symbols(void) { - if (dsos__load_kernel(vmlinux_name, sizeof(struct sym_entry), - symbol_filter, 1) <= 0) + if (dsos__load_kernel(vmlinux_name, symbol_filter, 1) <= 0) return -1; if (dump_symtab) @@ -859,7 +858,7 @@ static void event__process_sample(const event_t *self, int counter) return; } - syme = dso__sym_priv(map->dso, sym); + syme = symbol__priv(sym); if (!syme->skip) { syme->count[counter]++; @@ -878,8 +877,7 @@ static void event__process_mmap(event_t *self) struct thread *thread = threads__findnew(self->mmap.pid); if (thread != NULL) { - struct map *map = map__new(&self->mmap, NULL, 0, - sizeof(struct sym_entry)); + struct map *map = map__new(&self->mmap, NULL, 0); if (map != NULL) thread__insert_map(thread, map); } @@ -1176,7 +1174,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) { int counter; - symbol__init(); + symbol__init(sizeof(struct sym_entry)); page_size = sysconf(_SC_PAGE_SIZE); diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index e566bbe3f22..d042d656c56 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -151,7 +151,7 @@ static const struct option options[] = { int cmd_trace(int argc, const char **argv, const char *prefix __used) { - symbol__init(); + symbol__init(0); argc = parse_options(argc, argv, options, annotate_usage, 0); if (argc) { diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index 18accb8fee4..c458db9ede6 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -130,7 +130,7 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, if (curr_handler->sample_type_check(sample_type) < 0) exit(-1); - if (load_kernel(0, NULL) < 0) { + if (load_kernel(NULL) < 0) { perror("failed to load kernel symbols"); return EXIT_FAILURE; } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 4a158a01bb9..0a443bea68d 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -107,8 +107,7 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); void map__init(struct map *self, u64 start, u64 end, u64 pgoff, struct dso *dso); -struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, - unsigned int sym_priv_size); +struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen); struct map *map__clone(struct map *self); int map__overlap(struct map *l, struct map *r); size_t map__fprintf(struct map *self, FILE *fp); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 3b7ce1bf9f8..679011c1b6d 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -32,8 +32,7 @@ void map__init(struct map *self, u64 start, u64 end, u64 pgoff, RB_CLEAR_NODE(&self->rb_node); } -struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, - unsigned int sym_priv_size) +struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen) { struct map *self = malloc(sizeof(*self)); @@ -60,7 +59,7 @@ struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, filename = newfilename; } - dso = dsos__findnew(filename, sym_priv_size); + dso = dsos__findnew(filename); if (dso == NULL) goto out_delete; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 13677b5dbe5..cf2c7f77886 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -26,6 +26,7 @@ static void dsos__add(struct dso *dso); static struct dso *dsos__find(const char *name); static struct map *map__new2(u64 start, struct dso *dso); static void kernel_maps__insert(struct map *map); +unsigned int symbol__priv_size; static struct rb_root kernel_maps; @@ -75,18 +76,17 @@ static void kernel_maps__fixup_end(void) } } -static struct symbol *symbol__new(u64 start, u64 len, const char *name, - unsigned int priv_size) +static struct symbol *symbol__new(u64 start, u64 len, const char *name) { size_t namelen = strlen(name) + 1; - struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); - + struct symbol *self = calloc(1, (symbol__priv_size + + sizeof(*self) + namelen)); if (!self) return NULL; - if (priv_size) { - memset(self, 0, priv_size); - self = ((void *)self) + priv_size; + if (symbol__priv_size) { + memset(self, 0, symbol__priv_size); + self = ((void *)self) + symbol__priv_size; } self->start = start; self->end = len ? start + len - 1 : start; @@ -98,9 +98,9 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name, return self; } -static void symbol__delete(struct symbol *self, unsigned int priv_size) +static void symbol__delete(struct symbol *self) { - free(((void *)self) - priv_size); + free(((void *)self) - symbol__priv_size); } static size_t symbol__fprintf(struct symbol *self, FILE *fp) @@ -109,7 +109,7 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp) self->start, self->end, self->name); } -struct dso *dso__new(const char *name, unsigned int sym_priv_size) +struct dso *dso__new(const char *name) { struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); @@ -118,7 +118,6 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size) self->long_name = self->name; self->short_name = self->name; self->syms = RB_ROOT; - self->sym_priv_size = sym_priv_size; self->find_symbol = dso__find_symbol; self->slen_calculated = 0; self->origin = DSO__ORIG_NOT_FOUND; @@ -136,7 +135,7 @@ static void dso__delete_symbols(struct dso *self) pos = rb_entry(next, struct symbol, rb_node); next = rb_next(&pos->rb_node); rb_erase(&pos->rb_node, &self->syms); - symbol__delete(pos, self->sym_priv_size); + symbol__delete(pos); } } @@ -250,8 +249,7 @@ static int kernel_maps__load_all_kallsyms(void) /* * Will fix up the end later, when we have all symbols sorted. */ - sym = symbol__new(start, 0, symbol_name, - kernel_map->dso->sym_priv_size); + sym = symbol__new(start, 0, symbol_name); if (sym == NULL) goto out_delete_line; @@ -317,8 +315,7 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules) snprintf(dso_name, sizeof(dso_name), "[kernel].%d", kernel_range++); - dso = dso__new(dso_name, - kernel_map->dso->sym_priv_size); + dso = dso__new(dso_name); if (dso == NULL) return -1; @@ -336,7 +333,7 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules) if (filter && filter(map, pos)) { delete_symbol: rb_erase(&pos->rb_node, &kernel_map->dso->syms); - symbol__delete(pos, kernel_map->dso->sym_priv_size); + symbol__delete(pos); } else { if (map != kernel_map) { rb_erase(&pos->rb_node, &kernel_map->dso->syms); @@ -417,14 +414,13 @@ static int dso__load_perf_map(struct dso *self, struct map *map, if (len + 2 >= line_len) continue; - sym = symbol__new(start, size, line + len, - self->sym_priv_size); + sym = symbol__new(start, size, line + len); if (sym == NULL) goto out_delete_line; if (filter && filter(map, sym)) - symbol__delete(sym, self->sym_priv_size); + symbol__delete(sym); else { dso__insert_symbol(self, sym); nr_syms++; @@ -616,7 +612,7 @@ static int dso__synthesize_plt_symbols(struct dso *self) "%s@plt", elf_sym__name(&sym, symstrs)); f = symbol__new(plt_offset, shdr_plt.sh_entsize, - sympltname, self->sym_priv_size); + sympltname); if (!f) goto out_elf_end; @@ -634,7 +630,7 @@ static int dso__synthesize_plt_symbols(struct dso *self) "%s@plt", elf_sym__name(&sym, symstrs)); f = symbol__new(plt_offset, shdr_plt.sh_entsize, - sympltname, self->sym_priv_size); + sympltname); if (!f) goto out_elf_end; @@ -769,7 +765,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, if (kmodule) start += map->start + shdr.sh_offset; - curr_dso = dso__new(dso_name, self->sym_priv_size); + curr_dso = dso__new(dso_name); if (curr_dso == NULL) goto out_elf_end; curr_map = map__new2(start, curr_dso); @@ -803,14 +799,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, if (demangled != NULL) elf_name = demangled; new_symbol: - f = symbol__new(sym.st_value, sym.st_size, elf_name, - curr_dso->sym_priv_size); + f = symbol__new(sym.st_value, sym.st_size, elf_name); free(demangled); if (!f) goto out_elf_end; if (filter && filter(curr_map, f)) - symbol__delete(f, curr_dso->sym_priv_size); + symbol__delete(f); else { dso__insert_symbol(curr_dso, f); nr++; @@ -1141,7 +1136,7 @@ static struct map *map__new2(u64 start, struct dso *dso) return self; } -static int dsos__load_modules(unsigned int sym_priv_size) +static int dsos__load_modules(void) { char *line = NULL; size_t n; @@ -1180,7 +1175,7 @@ static int dsos__load_modules(unsigned int sym_priv_size) *sep = '\0'; snprintf(name, sizeof(name), "[%s]", line); - dso = dso__new(name, sym_priv_size); + dso = dso__new(name); if (dso == NULL) goto out_delete_line; @@ -1224,11 +1219,11 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, return err; } -int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, - symbol_filter_t filter, int use_modules) +int dsos__load_kernel(const char *vmlinux, symbol_filter_t filter, + int use_modules) { int err = -1; - struct dso *dso = dso__new(vmlinux, sym_priv_size); + struct dso *dso = dso__new(vmlinux); if (dso == NULL) return -1; @@ -1240,7 +1235,7 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; - if (use_modules && dsos__load_modules(sym_priv_size) < 0) { + if (use_modules && dsos__load_modules() < 0) { pr_warning("Failed to load list of modules in use! " "Continuing...\n"); use_modules = 0; @@ -1312,12 +1307,12 @@ static struct dso *dsos__find(const char *name) return NULL; } -struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size) +struct dso *dsos__findnew(const char *name) { struct dso *dso = dsos__find(name); if (!dso) { - dso = dso__new(name, sym_priv_size); + dso = dso__new(name); if (dso != NULL) dsos__add(dso); } @@ -1333,13 +1328,12 @@ void dsos__fprintf(FILE *fp) dso__fprintf(pos, fp); } -int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter) +int load_kernel(symbol_filter_t filter) { - if (dsos__load_kernel(vmlinux_name, sym_priv_size, filter, - modules) <= 0) + if (dsos__load_kernel(vmlinux_name, filter, modules) <= 0) return -1; - vdso = dso__new("[vdso]", 0); + vdso = dso__new("[vdso]"); if (!vdso) return -1; @@ -1348,7 +1342,8 @@ int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter) return 0; } -void symbol__init(void) +void symbol__init(unsigned int priv_size) { elf_version(EV_CURRENT); + symbol__priv_size = priv_size; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 432edbca780..a471a384073 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -39,11 +39,17 @@ struct symbol { char name[0]; }; +extern unsigned int symbol__priv_size; + +static inline void *symbol__priv(struct symbol *self) +{ + return ((void *)self) - symbol__priv_size; +} + struct dso { struct list_head node; struct rb_root syms; struct symbol *(*find_symbol)(struct dso *, u64 ip); - unsigned int sym_priv_size; unsigned char adjust_symbols; unsigned char slen_calculated; bool loaded; @@ -53,28 +59,22 @@ struct dso { char name[0]; }; -struct dso *dso__new(const char *name, unsigned int sym_priv_size); +struct dso *dso__new(const char *name); void dso__delete(struct dso *self); -static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) -{ - return ((void *)sym) - self->sym_priv_size; -} - struct symbol *dso__find_symbol(struct dso *self, u64 ip); -int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, - symbol_filter_t filter, int modules); -struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size); +int dsos__load_kernel(const char *vmlinux, symbol_filter_t filter, int modules); +struct dso *dsos__findnew(const char *name); int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); void dsos__fprintf(FILE *fp); size_t dso__fprintf(struct dso *self, FILE *fp); char dso__symtab_origin(const struct dso *self); -int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter); +int load_kernel(symbol_filter_t filter); -void symbol__init(void); +void symbol__init(unsigned int priv_size); extern struct list_head dsos; extern struct map *kernel_map; -- cgit v1.2.3-70-g09d2 From 8d06367fa79c053a4a56a2ce0bb9e840f5da1236 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 4 Nov 2009 18:50:43 -0200 Subject: perf symbols: Use the buildids if present With this change 'perf record' will intercept PERF_RECORD_MMAP calls, creating a linked list of DSOs, then when the session finishes, it will traverse this list and read the buildids, stashing them at the end of the file and will set up a new feature bit in the header bitmask. 'perf report' will then notice this feature and populate the 'dsos' list and set the build ids. When reading the symtabs it will refuse to load from a file that doesn't have the same build id. This improves the reliability of the profiler output, as symbols and profiling data is more guaranteed to match. Example: [root@doppio ~]# perf report | head /home/acme/bin/perf with build id b1ea544ac3746e7538972548a09aadecc5753868 not found, continuing without symbols # Samples: 2621434559 # # Overhead Command Shared Object Symbol # ........ ............... ............................. ...... # 7.91% init [kernel] [k] read_hpet 7.64% init [kernel] [k] mwait_idle_with_hints 7.60% swapper [kernel] [k] read_hpet 7.60% swapper [kernel] [k] mwait_idle_with_hints 3.65% init [kernel] [k] 0xffffffffa02339d9 [root@doppio ~]# In this case the 'perf' binary was an older one, vanished, so its symbols probably wouldn't match or would cause subtly different (and misleading) output. Next patches will support the kernel as well, reading the build id notes for it and the modules from /sys. Another patch should also introduce a new plumbing command: 'perf list-buildids' that will then be used in porcelain that is distro specific to fetch -debuginfo packages where such buildids are present. This will in turn allow for one to run 'perf record' in one machine and 'perf report' in another. Future work on having the buildid sent directly from the kernel in the PERF_RECORD_MMAP event is needed to close races, as the DSO can be changed during a 'perf record' session, but this patch at least helps with non-corner cases and current/older kernels. Signed-off-by: Arnaldo Carvalho de Melo Cc: Ananth N Mavinakayanahalli Cc: Christoph Hellwig Cc: Frank Ch. Eigler Cc: Frederic Weisbecker Cc: Jason Baron Cc: Jim Keniston Cc: K. Prasad Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Roland McGrath Cc: Srikar Dronamraju Cc: Steven Rostedt LKML-Reference: <1257367843-26224-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-record.c | 49 ++++++++++++++++++++++++++-- tools/perf/util/data_map.c | 37 +++++++++++++++++++++ tools/perf/util/event.h | 7 ++++ tools/perf/util/header.c | 10 ++++++ tools/perf/util/header.h | 4 +++ tools/perf/util/map.c | 14 ++++++-- tools/perf/util/symbol.c | 78 ++++++++++++++++++++++++++++++++------------- tools/perf/util/symbol.h | 10 ++++-- 8 files changed, 179 insertions(+), 30 deletions(-) (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 4a73d89ce5d..ab333812ace 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -17,6 +17,7 @@ #include "util/header.h" #include "util/event.h" #include "util/debug.h" +#include "util/symbol.h" #include #include @@ -109,9 +110,21 @@ static void write_output(void *buf, size_t size) } } +static void write_event(event_t *buf, size_t size) +{ + /* + * Add it to the list of DSOs, so that when we finish this + * record session we can pick the available build-ids. + */ + if (buf->header.type == PERF_RECORD_MMAP) + dsos__findnew(buf->mmap.filename); + + write_output(buf, size); +} + static int process_synthesized_event(event_t *event) { - write_output(event, event->header.size); + write_event(event, event->header.size); return 0; } @@ -163,14 +176,14 @@ static void mmap_read(struct mmap_data *md) size = md->mask + 1 - (old & md->mask); old += size; - write_output(buf, size); + write_event(buf, size); } buf = &data[old & md->mask]; size = head - old; old += size; - write_output(buf, size); + write_event(buf, size); md->prev = old; mmap_write_tail(md, old); @@ -365,10 +378,38 @@ static void open_counters(int cpu, pid_t pid) nr_cpu++; } +static bool write_buildid_table(void) +{ + struct dso *pos; + bool have_buildid = false; + + list_for_each_entry(pos, &dsos, node) { + struct build_id_event b; + size_t len; + + if (filename__read_build_id(pos->long_name, + &b.build_id, + sizeof(b.build_id)) < 0) + continue; + have_buildid = true; + memset(&b.header, 0, sizeof(b.header)); + len = strlen(pos->long_name) + 1; + len = ALIGN(len, 64); + b.header.size = sizeof(b) + len; + write_output(&b, sizeof(b)); + write_output(pos->long_name, len); + } + + return have_buildid; +} + static void atexit_header(void) { header->data_size += bytes_written; + if (write_buildid_table()) + perf_header__set_feat(header, HEADER_BUILD_ID); + perf_header__write(header, output); } @@ -572,6 +613,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) { int counter; + symbol__init(0); + argc = parse_options(argc, argv, options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (!argc && target_pid == -1 && !system_wide) diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index c458db9ede6..00a9c114c8d 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -70,6 +70,39 @@ process_event(event_t *event, unsigned long offset, unsigned long head) } } +static int perf_header__read_build_ids(const struct perf_header *self, + int input, off_t file_size) +{ + off_t offset = self->data_offset + self->data_size; + struct build_id_event bev; + char filename[PATH_MAX]; + int err = -1; + + if (lseek(input, offset, SEEK_SET) < 0) + return -1; + + while (offset < file_size) { + struct dso *dso; + ssize_t len; + + if (read(input, &bev, sizeof(bev)) != sizeof(bev)) + goto out; + + len = bev.header.size - sizeof(bev); + if (read(input, filename, len) != len) + goto out; + + dso = dsos__findnew(filename); + if (dso != NULL) + dso__set_build_id(dso, &bev.build_id); + + offset += bev.header.size; + } + err = 0; +out: + return err; +} + int mmap_dispatch_perf_file(struct perf_header **pheader, const char *input_name, int force, @@ -130,6 +163,10 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, if (curr_handler->sample_type_check(sample_type) < 0) exit(-1); + if (perf_header__has_feat(header, HEADER_BUILD_ID) && + perf_header__read_build_ids(header, input, input_stat.st_size)) + pr_debug("failed to read buildids, continuing...\n"); + if (load_kernel(NULL) < 0) { perror("failed to load kernel symbols"); return EXIT_FAILURE; diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 0a443bea68d..34c6fcb82d9 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -61,6 +61,13 @@ struct sample_event{ u64 array[]; }; +#define BUILD_ID_SIZE 20 + +struct build_id_event { + struct perf_event_header header; + u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; + char filename[]; +}; typedef union event_union { struct perf_event_header header; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 7d26659b806..050f543fd96 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -149,6 +149,16 @@ void perf_header__feat_trace_info(struct perf_header *header) set_bit(HEADER_TRACE_INFO, header->adds_features); } +void perf_header__set_feat(struct perf_header *self, int feat) +{ + set_bit(feat, self->adds_features); +} + +bool perf_header__has_feat(const struct perf_header *self, int feat) +{ + return test_bit(feat, self->adds_features); +} + static void do_write(int fd, void *buf, size_t size) { while (size) { diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 2ea9dfb1236..2f233c5db7e 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -3,6 +3,7 @@ #include "../../../include/linux/perf_event.h" #include +#include #include "types.h" #include @@ -15,6 +16,7 @@ struct perf_header_attr { }; #define HEADER_TRACE_INFO 1 +#define HEADER_BUILD_ID 2 #define HEADER_FEAT_BITS 256 @@ -48,6 +50,8 @@ u64 perf_header__sample_type(struct perf_header *header); struct perf_event_attr * perf_header__find_attr(u64 id, struct perf_header *header); void perf_header__feat_trace_info(struct perf_header *header); +void perf_header__set_feat(struct perf_header *self, int feat); +bool perf_header__has_feat(const struct perf_header *self, int feat); struct perf_header *perf_header__new(void); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 33f868420d7..94ca95073c4 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -84,8 +84,18 @@ map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter) int nr = dso__load(self->dso, self, filter); if (nr < 0) { - pr_warning("Failed to open %s, continuing without symbols\n", - self->dso->long_name); + if (self->dso->has_build_id) { + char sbuild_id[BUILD_ID_SIZE * 2 + 1]; + + build_id__sprintf(self->dso->build_id, + sizeof(self->dso->build_id), + sbuild_id); + pr_warning("%s with build id %s not found", + self->dso->long_name, sbuild_id); + } else + pr_warning("Failed to open %s", + self->dso->long_name); + pr_warning(", continuing without symbols\n"); return NULL; } else if (nr == 0) { const char *name = self->dso->long_name; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e7c7cdb851c..a2e95ce1f22 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -121,7 +121,8 @@ struct dso *dso__new(const char *name) self->find_symbol = dso__find_symbol; self->slen_calculated = 0; self->origin = DSO__ORIG_NOT_FOUND; - self->loaded = false; + self->loaded = 0; + self->has_build_id = 0; } return self; @@ -148,6 +149,12 @@ void dso__delete(struct dso *self) free(self); } +void dso__set_build_id(struct dso *self, void *build_id) +{ + memcpy(self->build_id, build_id, sizeof(self->build_id)); + self->has_build_id = 1; +} + static void dso__insert_symbol(struct dso *self, struct symbol *sym) { struct rb_node **p = &self->syms.rb_node; @@ -190,11 +197,30 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip) return NULL; } -size_t dso__fprintf(struct dso *self, FILE *fp) +int build_id__sprintf(u8 *self, int len, char *bf) { - size_t ret = fprintf(fp, "dso: %s\n", self->short_name); + char *bid = bf; + u8 *raw = self; + int i; + for (i = 0; i < len; ++i) { + sprintf(bid, "%02x", *raw); + ++raw; + bid += 2; + } + + return raw - self; +} + +size_t dso__fprintf(struct dso *self, FILE *fp) +{ + char sbuild_id[BUILD_ID_SIZE * 2 + 1]; struct rb_node *nd; + size_t ret; + + build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); + ret = fprintf(fp, "dso: %s (%s)\n", self->short_name, sbuild_id); + for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { struct symbol *pos = rb_entry(nd, struct symbol, rb_node); ret += symbol__fprintf(pos, fp); @@ -825,8 +851,6 @@ out_close: return err; } -#define BUILD_ID_SIZE 20 - int filename__read_build_id(const char *filename, void *bf, size_t size) { int fd, err = -1; @@ -845,7 +869,7 @@ int filename__read_build_id(const char *filename, void *bf, size_t size) elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); if (elf == NULL) { - pr_err("%s: cannot read %s ELF file.\n", __func__, filename); + pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); goto out_close; } @@ -874,9 +898,9 @@ out: static char *dso__read_build_id(struct dso *self) { - int i, len; - char *build_id = NULL, *bid; - unsigned char rawbf[BUILD_ID_SIZE], *raw; + int len; + char *build_id = NULL; + unsigned char rawbf[BUILD_ID_SIZE]; len = filename__read_build_id(self->long_name, rawbf, sizeof(rawbf)); if (len < 0) @@ -885,15 +909,8 @@ static char *dso__read_build_id(struct dso *self) build_id = malloc(len * 2 + 1); if (build_id == NULL) goto out; - bid = build_id; - raw = rawbf; - for (i = 0; i < len; ++i) { - sprintf(bid, "%02x", *raw); - ++raw; - bid += 2; - } - pr_debug2("%s(%s): %s\n", __func__, self->long_name, build_id); + build_id__sprintf(rawbf, len, build_id); out: return build_id; } @@ -922,7 +939,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) int ret = -1; int fd; - self->loaded = true; + self->loaded = 1; if (!name) return -1; @@ -940,6 +957,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) more: do { + int berr = 0; + self->origin++; switch (self->origin) { case DSO__ORIG_FEDORA: @@ -956,8 +975,7 @@ more: snprintf(name, size, "/usr/lib/debug/.build-id/%.2s/%s.debug", build_id, build_id + 2); - free(build_id); - break; + goto compare_build_id; } self->origin++; /* Fall thru */ @@ -969,6 +987,22 @@ more: goto out; } + if (self->has_build_id) { + bool match; + build_id = malloc(BUILD_ID_SIZE); + if (build_id == NULL) + goto more; + berr = filename__read_build_id(name, build_id, + BUILD_ID_SIZE); +compare_build_id: + match = berr > 0 && memcmp(build_id, self->build_id, + sizeof(self->build_id)) == 0; + free(build_id); + build_id = NULL; + if (!match) + goto more; + } + fd = open(name, O_RDONLY); } while (fd < 0); @@ -1034,7 +1068,7 @@ static int dso__load_module_sym(struct dso *self, struct map *map, { int err = 0, fd = open(self->long_name, O_RDONLY); - self->loaded = true; + self->loaded = 1; if (fd < 0) { pr_err("%s: cannot open %s\n", __func__, self->long_name); @@ -1225,7 +1259,7 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, { int err, fd = open(vmlinux, O_RDONLY); - self->loaded = true; + self->loaded = 1; if (fd < 0) return -1; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index e0d4a583f8d..f8c1899af48 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -60,10 +60,12 @@ struct dso { struct list_head node; struct rb_root syms; struct symbol *(*find_symbol)(struct dso *, u64 ip); - unsigned char adjust_symbols; - unsigned char slen_calculated; - bool loaded; + u8 adjust_symbols:1; + u8 slen_calculated:1; + u8 loaded:1; + u8 has_build_id:1; unsigned char origin; + u8 build_id[BUILD_ID_SIZE]; const char *short_name; char *long_name; char name[0]; @@ -81,8 +83,10 @@ void dsos__fprintf(FILE *fp); size_t dso__fprintf(struct dso *self, FILE *fp); char dso__symtab_origin(const struct dso *self); +void dso__set_build_id(struct dso *self, void *build_id); int filename__read_build_id(const char *filename, void *bf, size_t size); +int build_id__sprintf(u8 *self, int len, char *bf); int load_kernel(symbol_filter_t filter); -- cgit v1.2.3-70-g09d2 From 4778d2e4f410c6eea32f594cb2be9590bcb28b84 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 11 Nov 2009 04:51:05 +0100 Subject: perf tools: Read the build-ids from the header layer Keep the build-ids reading implementation in the data mapping but move its call to the headers so that we have a better control on it (offset seeking, size passing, etc..). Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras Cc: Hitoshi Mitake LKML-Reference: <1257911467-28276-4-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/data_map.c | 8 ++------ tools/perf/util/data_map.h | 2 ++ tools/perf/util/header.c | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 8 deletions(-) (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index 00a9c114c8d..66e58aaecce 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -70,8 +70,8 @@ process_event(event_t *event, unsigned long offset, unsigned long head) } } -static int perf_header__read_build_ids(const struct perf_header *self, - int input, off_t file_size) +int perf_header__read_build_ids(const struct perf_header *self, + int input, off_t file_size) { off_t offset = self->data_offset + self->data_size; struct build_id_event bev; @@ -163,10 +163,6 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, if (curr_handler->sample_type_check(sample_type) < 0) exit(-1); - if (perf_header__has_feat(header, HEADER_BUILD_ID) && - perf_header__read_build_ids(header, input, input_stat.st_size)) - pr_debug("failed to read buildids, continuing...\n"); - if (load_kernel(NULL) < 0) { perror("failed to load kernel symbols"); return EXIT_FAILURE; diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h index 716d1053b07..c4122810e48 100644 --- a/tools/perf/util/data_map.h +++ b/tools/perf/util/data_map.h @@ -27,5 +27,7 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, int full_paths, int *cwdlen, char **cwd); +int perf_header__read_build_ids(const struct perf_header *self, + int input, off_t file_size); #endif diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 2f702c23f71..915b56edbf0 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -9,6 +9,8 @@ #include "../perf.h" #include "trace-event.h" #include "symbol.h" +#include "data_map.h" +#include "debug.h" /* * Create new perf.data header attribute: @@ -322,6 +324,14 @@ static void perf_header__adds_read(struct perf_header *self, int fd) trace_report(fd); lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); } + + if (perf_header__has_feat(self, HEADER_BUILD_ID)) { + struct stat input_stat; + + fstat(fd, &input_stat); + if (perf_header__read_build_ids(self, fd, input_stat.st_size)) + pr_debug("failed to read buildids, continuing...\n"); + } }; struct perf_header *perf_header__read(int fd) @@ -382,14 +392,14 @@ struct perf_header *perf_header__read(int fd) memcpy(&self->adds_features, &f_header.adds_features, sizeof(f_header.adds_features)); - perf_header__adds_read(self, fd); - self->event_offset = f_header.event_types.offset; self->event_size = f_header.event_types.size; self->data_offset = f_header.data.offset; self->data_size = f_header.data.size; + perf_header__adds_read(self, fd); + lseek(fd, self->data_offset, SEEK_SET); self->frozen = 1; -- cgit v1.2.3-70-g09d2 From 9e827dd00a94136b944a538bede67c944d0b740a Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 11 Nov 2009 04:51:07 +0100 Subject: perf tools: Bring linear set of section headers for features Build a set of section headers for features right after the datas. Each implemented feature will have one of such section header that provides the offset and the size of the data manipulated by the feature. The trace informations have moved after the data and are recorded on exit time. The new layout is as follows: ----------------------- ___ [ magic ] | [ header size ] | [ attr size ] | [ attr content offset ] | [ attr content size ] | [ data offset ] File Headers [ data size ] | [ event_types offset ] | [ event_types size ] | [ feature bitmap ] v [ attr section ] [ events section ] ___ [ X ] | [ X ] | [ X ] Datas [ X ] | [ X ] v ___ [ Feature 1 offset ] | [ Feature 1 size ] Features headers [ Feature 2 offset ] | [ Feature 2 size ] v [ Feature 1 content ] [ Feature 2 content ] ----------------------- We have as many feature's section headers as we have features in use for the current file. Say Feat 1 and Feat 3 are used by the file, but not Feat 2. Then the feature headers will be like follows: [ Feature 1 offset ] | [ Feature 1 size ] Features headers [ Feature 3 offset ] | [ Feature 3 size ] v There is no hole to cover Feature 2 that is not in use here. We only need to cover the needed headers in order, from the lowest feature bit to the highest. Currently we have two features: HEADER_TRACE_INFO and HEADER_BUILD_ID. Both have their contents that follow the feature headers. Putting the contents right after the feature headers is not mandatory though. While we keep the feature headers right after the data and in order, their offsets can point everywhere. We have just put the two above feature contents in the end of the file for convenience. The purpose of this layout change is to have a file format that scales while keeping it simple: having such linear feature headers is less error prone wrt forward/backward compatibility as the content of a feature can be put anywhere, its location can even change by the time, it's fine because its headers will tell where it is. And we know how to find these headers, following the above rules. Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras Cc: Hitoshi Mitake LKML-Reference: <1257911467-28276-6-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/util/data_map.c | 11 ++-- tools/perf/util/data_map.h | 3 +- tools/perf/util/header.c | 110 ++++++++++++++++++++++----------- tools/perf/util/include/linux/bitmap.h | 1 + tools/perf/util/include/linux/ctype.h | 2 +- tools/perf/util/util.h | 3 + 6 files changed, 85 insertions(+), 45 deletions(-) (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index 66e58aaecce..aacb814a4ef 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -70,18 +70,15 @@ process_event(event_t *event, unsigned long offset, unsigned long head) } } -int perf_header__read_build_ids(const struct perf_header *self, - int input, off_t file_size) +int perf_header__read_build_ids(int input, off_t size) { - off_t offset = self->data_offset + self->data_size; struct build_id_event bev; char filename[PATH_MAX]; + off_t offset = lseek(input, 0, SEEK_CUR); + off_t limit = offset + size; int err = -1; - if (lseek(input, offset, SEEK_SET) < 0) - return -1; - - while (offset < file_size) { + while (offset < limit) { struct dso *dso; ssize_t len; diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h index c4122810e48..20b4037a823 100644 --- a/tools/perf/util/data_map.h +++ b/tools/perf/util/data_map.h @@ -27,7 +27,6 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, int full_paths, int *cwdlen, char **cwd); -int perf_header__read_build_ids(const struct perf_header *self, - int input, off_t file_size); +int perf_header__read_build_ids(int input, off_t file_size); #endif diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 9709d38113b..ebed4f44ed3 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -186,41 +186,58 @@ static void write_buildid_table(int fd, struct list_head *id_head) } static void -perf_header__adds_write(struct perf_header *self, int fd, bool at_exit) +perf_header__adds_write(struct perf_header *self, int fd) { - struct perf_file_section trace_sec; - u64 cur_offset = lseek(fd, 0, SEEK_CUR); + LIST_HEAD(id_list); + int nr_sections; + struct perf_file_section *feat_sec; + int sec_size; + u64 sec_start; + int idx = 0; + + if (fetch_build_id_table(&id_list)) + perf_header__set_feat(self, HEADER_BUILD_ID); + + nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); + if (!nr_sections) + return; + + feat_sec = calloc(sizeof(*feat_sec), nr_sections); + if (!feat_sec) + die("No memory"); + + sec_size = sizeof(*feat_sec) * nr_sections; + + sec_start = self->data_offset + self->data_size; + lseek(fd, sec_start + sec_size, SEEK_SET); if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { + struct perf_file_section *trace_sec; + + trace_sec = &feat_sec[idx++]; + /* Write trace info */ - trace_sec.offset = lseek(fd, sizeof(trace_sec), SEEK_CUR); + trace_sec->offset = lseek(fd, 0, SEEK_CUR); read_tracing_data(fd, attrs, nr_counters); - trace_sec.size = lseek(fd, 0, SEEK_CUR) - trace_sec.offset; - - /* Write trace info headers */ - lseek(fd, cur_offset, SEEK_SET); - do_write(fd, &trace_sec, sizeof(trace_sec)); - - /* - * Update cur_offset. So that other (future) - * features can set their own infos in this place. But if we are - * the only feature, at least that seeks to the place the data - * should begin. - */ - cur_offset = lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); + trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; } - if (at_exit) { - LIST_HEAD(id_list); - if (fetch_build_id_table(&id_list)) { - lseek(fd, self->data_offset + self->data_size, SEEK_SET); - perf_header__set_feat(self, HEADER_BUILD_ID); - write_buildid_table(fd, &id_list); - lseek(fd, cur_offset, SEEK_SET); - } + if (perf_header__has_feat(self, HEADER_BUILD_ID)) { + struct perf_file_section *buildid_sec; + + buildid_sec = &feat_sec[idx++]; + + /* Write build-ids */ + buildid_sec->offset = lseek(fd, 0, SEEK_CUR); + write_buildid_table(fd, &id_list); + buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; } -}; + + lseek(fd, sec_start, SEEK_SET); + do_write(fd, feat_sec, sec_size); + free(feat_sec); +} void perf_header__write(struct perf_header *self, int fd, bool at_exit) { @@ -260,10 +277,11 @@ void perf_header__write(struct perf_header *self, int fd, bool at_exit) if (events) do_write(fd, events, self->event_size); - perf_header__adds_write(self, fd, at_exit); - self->data_offset = lseek(fd, 0, SEEK_CUR); + if (at_exit) + perf_header__adds_write(self, fd); + f_header = (struct perf_file_header){ .magic = PERF_MAGIC, .size = sizeof(f_header), @@ -308,22 +326,44 @@ static void do_read(int fd, void *buf, size_t size) static void perf_header__adds_read(struct perf_header *self, int fd) { + struct perf_file_section *feat_sec; + int nr_sections; + int sec_size; + int idx = 0; + + + nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); + if (!nr_sections) + return; + + feat_sec = calloc(sizeof(*feat_sec), nr_sections); + if (!feat_sec) + die("No memory"); + + sec_size = sizeof(*feat_sec) * nr_sections; + + lseek(fd, self->data_offset + self->data_size, SEEK_SET); + + do_read(fd, feat_sec, sec_size); + if (perf_header__has_feat(self, HEADER_TRACE_INFO)) { - struct perf_file_section trace_sec; + struct perf_file_section *trace_sec; - do_read(fd, &trace_sec, sizeof(trace_sec)); - lseek(fd, trace_sec.offset, SEEK_SET); + trace_sec = &feat_sec[idx++]; + lseek(fd, trace_sec->offset, SEEK_SET); trace_report(fd); - lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); } if (perf_header__has_feat(self, HEADER_BUILD_ID)) { - struct stat input_stat; + struct perf_file_section *buildid_sec; - fstat(fd, &input_stat); - if (perf_header__read_build_ids(self, fd, input_stat.st_size)) + buildid_sec = &feat_sec[idx++]; + lseek(fd, buildid_sec->offset, SEEK_SET); + if (perf_header__read_build_ids(fd, buildid_sec->size)) pr_debug("failed to read buildids, continuing...\n"); } + + free(feat_sec); }; struct perf_header *perf_header__read(int fd) diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h index 821c1033bcc..94507639a8c 100644 --- a/tools/perf/util/include/linux/bitmap.h +++ b/tools/perf/util/include/linux/bitmap.h @@ -1,2 +1,3 @@ #include "../../../../include/linux/bitmap.h" #include "../../../../include/asm-generic/bitops/find.h" +#include diff --git a/tools/perf/util/include/linux/ctype.h b/tools/perf/util/include/linux/ctype.h index bae5783282e..a53d4ee1e0b 100644 --- a/tools/perf/util/include/linux/ctype.h +++ b/tools/perf/util/include/linux/ctype.h @@ -1 +1 @@ -#include "../../../../include/linux/ctype.h" +#include "../util.h" diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 9de2329dd44..7bd5bdaeb23 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -306,6 +306,7 @@ static inline int has_extension(const char *filename, const char *ext) #undef isascii #undef isspace #undef isdigit +#undef isxdigit #undef isalpha #undef isprint #undef isalnum @@ -323,6 +324,8 @@ extern unsigned char sane_ctype[256]; #define isascii(x) (((x) & ~0x7f) == 0) #define isspace(x) sane_istest(x,GIT_SPACE) #define isdigit(x) sane_istest(x,GIT_DIGIT) +#define isxdigit(x) \ + (sane_istest(toupper(x), GIT_ALPHA | GIT_DIGIT) && toupper(x) < 'G') #define isalpha(x) sane_istest(x,GIT_ALPHA) #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) #define isprint(x) sane_istest(x,GIT_PRINT) -- cgit v1.2.3-70-g09d2 From 84fe8488ade7922afa9f3aa77c22d2d92beb9660 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 16 Nov 2009 16:32:41 -0200 Subject: perf symbols: Pass the offset to perf_header__read_build_ids() Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <1258396365-29217-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/data_map.c | 3 +-- tools/perf/util/data_map.h | 2 +- tools/perf/util/header.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index aacb814a4ef..14cb8465eb0 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -70,11 +70,10 @@ process_event(event_t *event, unsigned long offset, unsigned long head) } } -int perf_header__read_build_ids(int input, off_t size) +int perf_header__read_build_ids(int input, off_t offset, off_t size) { struct build_id_event bev; char filename[PATH_MAX]; - off_t offset = lseek(input, 0, SEEK_CUR); off_t limit = offset + size; int err = -1; diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h index 20b4037a823..ae036ecd762 100644 --- a/tools/perf/util/data_map.h +++ b/tools/perf/util/data_map.h @@ -27,6 +27,6 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, int full_paths, int *cwdlen, char **cwd); -int perf_header__read_build_ids(int input, off_t file_size); +int perf_header__read_build_ids(int input, off_t offset, off_t file_size); #endif diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ebed4f44ed3..ca0d657eefa 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -359,7 +359,7 @@ static void perf_header__adds_read(struct perf_header *self, int fd) buildid_sec = &feat_sec[idx++]; lseek(fd, buildid_sec->offset, SEEK_SET); - if (perf_header__read_build_ids(fd, buildid_sec->size)) + if (perf_header__read_build_ids(fd, buildid_sec->offset, buildid_sec->size)) pr_debug("failed to read buildids, continuing...\n"); } -- cgit v1.2.3-70-g09d2 From 4dc0a04bb18fe9b80cefa08694f46a3a19ebfe50 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Nov 2009 14:55:55 -0200 Subject: perf tools: perf_header__read() shouldn't die() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And also don't call the constructor in it, this way it adheres to the model the other methods follow. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1258649757-17554-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-record.c | 16 +++++++------ tools/perf/builtin-timechart.c | 17 ++++++++++---- tools/perf/util/data_map.c | 18 +++++++++++---- tools/perf/util/header.c | 52 +++++++++++++++++++++++++----------------- tools/perf/util/header.h | 7 +++--- 5 files changed, 70 insertions(+), 40 deletions(-) (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 82260c56db3..c97cb2ca8fa 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -400,7 +400,7 @@ static int __cmd_record(int argc, const char **argv) struct stat st; pid_t pid = 0; int flags; - int ret; + int err; unsigned long waking = 0; page_size = sysconf(_SC_PAGE_SIZE); @@ -434,16 +434,18 @@ static int __cmd_record(int argc, const char **argv) exit(-1); } - if (!file_new) - header = perf_header__read(output); - else - header = perf_header__new(); - + header = perf_header__new(); if (header == NULL) { pr_err("Not enough memory for reading perf file header\n"); return -1; } + if (!file_new) { + err = perf_header__read(header, output); + if (err < 0) + return err; + } + if (raw_samples) { perf_header__set_feat(header, HEADER_TRACE_INFO); } else { @@ -527,7 +529,7 @@ static int __cmd_record(int argc, const char **argv) if (hits == samples) { if (done) break; - ret = poll(event_array, nr_poll, -1); + err = poll(event_array, nr_poll, -1); waking++; } diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 665877e4a94..dd4d82ac7aa 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1093,7 +1093,7 @@ static void process_samples(void) static int __cmd_timechart(void) { - int ret, rc = EXIT_FAILURE; + int err, rc = EXIT_FAILURE; unsigned long offset = 0; unsigned long head, shift; struct stat statbuf; @@ -1111,8 +1111,8 @@ static int __cmd_timechart(void) exit(-1); } - ret = fstat(input, &statbuf); - if (ret < 0) { + err = fstat(input, &statbuf); + if (err < 0) { perror("failed to stat file"); exit(-1); } @@ -1122,7 +1122,16 @@ static int __cmd_timechart(void) exit(0); } - header = perf_header__read(input); + header = perf_header__new(); + if (header == NULL) + return -ENOMEM; + + err = perf_header__read(header, input); + if (err < 0) { + perf_header__delete(header); + return err; + } + head = header->data_offset; sample_type = perf_header__sample_type(header); diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index 14cb8465eb0..b8fc0fa2f63 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -106,7 +106,7 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, int *cwdlen, char **cwd) { - int ret, rc = EXIT_FAILURE; + int err, rc = EXIT_FAILURE; struct perf_header *header; unsigned long head, shift; unsigned long offset = 0; @@ -132,8 +132,8 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, exit(-1); } - ret = fstat(input, &input_stat); - if (ret < 0) { + err = fstat(input, &input_stat); + if (err < 0) { perror("failed to stat file"); exit(-1); } @@ -149,8 +149,16 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, exit(0); } - *pheader = perf_header__read(input); - header = *pheader; + header = perf_header__new(); + if (header == NULL) + return -ENOMEM; + + err = perf_header__read(header, input); + if (err < 0) { + perf_header__delete(header); + return err; + } + *pheader = header; head = header->data_offset; sample_type = perf_header__sample_type(header); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 425a29ba01a..e66c7bd4cc8 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -78,16 +78,24 @@ struct perf_header *perf_header__new(void) return self; } +void perf_header__delete(struct perf_header *self) +{ + int i; + + for (i = 0; i < self->attrs; ++i) + perf_header_attr__delete(self->attr[i]); + + free(self->attr); + free(self); +} + int perf_header__add_attr(struct perf_header *self, struct perf_header_attr *attr) { - int pos = self->attrs; - if (self->frozen) return -1; - self->attrs++; - if (self->attrs > self->size) { + if (self->attrs == self->size) { int nsize = self->size * 2; struct perf_header_attr **nattr; @@ -98,7 +106,8 @@ int perf_header__add_attr(struct perf_header *self, self->size = nsize; self->attr = nattr; } - self->attr[pos] = attr; + + self->attr[self->attrs++] = attr; return 0; } @@ -441,19 +450,17 @@ static int perf_file_section__process(struct perf_file_section *self, return 0; } -struct perf_header *perf_header__read(int fd) +int perf_header__read(struct perf_header *self, int fd) { - struct perf_header *self = perf_header__new(); struct perf_file_header f_header; struct perf_file_attr f_attr; u64 f_id; int nr_attrs, nr_ids, i, j; - if (self == NULL) - die("nomem"); - - if (perf_file_header__read(&f_header, self, fd) < 0) - die("incompatible file format"); + if (perf_file_header__read(&f_header, self, fd) < 0) { + pr_debug("incompatible file format\n"); + return -EINVAL; + } nr_attrs = f_header.attrs.size / sizeof(f_attr); lseek(fd, f_header.attrs.offset, SEEK_SET); @@ -467,7 +474,7 @@ struct perf_header *perf_header__read(int fd) attr = perf_header_attr__new(&f_attr.attr); if (attr == NULL) - die("nomem"); + return -ENOMEM; nr_ids = f_attr.ids.size / sizeof(u64); lseek(fd, f_attr.ids.offset, SEEK_SET); @@ -475,11 +482,15 @@ struct perf_header *perf_header__read(int fd) for (j = 0; j < nr_ids; j++) { do_read(fd, &f_id, sizeof(f_id)); - if (perf_header_attr__add_id(attr, f_id) < 0) - die("nomem"); + if (perf_header_attr__add_id(attr, f_id) < 0) { + perf_header_attr__delete(attr); + return -ENOMEM; + } + } + if (perf_header__add_attr(self, attr) < 0) { + perf_header_attr__delete(attr); + return -ENOMEM; } - if (perf_header__add_attr(self, attr) < 0) - die("nomem"); lseek(fd, tmp, SEEK_SET); } @@ -487,8 +498,8 @@ struct perf_header *perf_header__read(int fd) if (f_header.event_types.size) { lseek(fd, f_header.event_types.offset, SEEK_SET); events = malloc(f_header.event_types.size); - if (!events) - die("nomem"); + if (events == NULL) + return -ENOMEM; do_read(fd, events, f_header.event_types.size); event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); } @@ -498,8 +509,7 @@ struct perf_header *perf_header__read(int fd) lseek(fd, self->data_offset, SEEK_SET); self->frozen = 1; - - return self; + return 0; } u64 perf_header__sample_type(struct perf_header *header) diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index f46a94e09ee..dc8fedb066a 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -55,7 +55,10 @@ struct perf_header { DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); }; -struct perf_header *perf_header__read(int fd); +struct perf_header *perf_header__new(void); +void perf_header__delete(struct perf_header *self); + +int perf_header__read(struct perf_header *self, int fd); void perf_header__write(struct perf_header *self, int fd, bool at_exit); int perf_header__add_attr(struct perf_header *self, @@ -75,8 +78,6 @@ perf_header__find_attr(u64 id, struct perf_header *header); void perf_header__set_feat(struct perf_header *self, int feat); bool perf_header__has_feat(const struct perf_header *self, int feat); -struct perf_header *perf_header__new(void); - int perf_header__process_sections(struct perf_header *self, int fd, int (*process)(struct perf_file_section *self, int feat, int fd)); -- cgit v1.2.3-70-g09d2 From 6b0cb5f9f7033c72b19697c33deab83f0dd9848d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Nov 2009 14:55:57 -0200 Subject: perf tools: Don't die() in mmap_dispatch_perf_file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Propagate the error, that, interestingly, are already handled by all callers :-) Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1258649757-17554-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/data_map.c | 80 +++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 36 deletions(-) (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index b8fc0fa2f63..5543e7d0487 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -106,7 +106,7 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, int *cwdlen, char **cwd) { - int err, rc = EXIT_FAILURE; + int err; struct perf_header *header; unsigned long head, shift; unsigned long offset = 0; @@ -118,64 +118,69 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, int input; char *buf; - if (!curr_handler) - die("Forgot to register perf file handler"); + if (curr_handler == NULL) { + pr_debug("Forgot to register perf file handler\n"); + return -EINVAL; + } page_size = getpagesize(); input = open(input_name, O_RDONLY); if (input < 0) { - fprintf(stderr, " failed to open file: %s", input_name); + pr_err("Failed to open file: %s", input_name); if (!strcmp(input_name, "perf.data")) - fprintf(stderr, " (try 'perf record' first)"); - fprintf(stderr, "\n"); - exit(-1); + pr_err(" (try 'perf record' first)"); + pr_err("\n"); + return -errno; } - err = fstat(input, &input_stat); - if (err < 0) { - perror("failed to stat file"); - exit(-1); + if (fstat(input, &input_stat) < 0) { + pr_err("failed to stat file"); + err = -errno; + goto out_close; } + err = -EACCES; if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { - fprintf(stderr, "file: %s not owned by current user or root\n", + pr_err("file: %s not owned by current user or root\n", input_name); - exit(-1); + goto out_close; } - if (!input_stat.st_size) { - fprintf(stderr, "zero-sized file, nothing to do!\n"); - exit(0); + if (input_stat.st_size == 0) { + pr_info("zero-sized file, nothing to do!\n"); + goto done; } + err = -ENOMEM; header = perf_header__new(); if (header == NULL) - return -ENOMEM; + goto out_close; err = perf_header__read(header, input); - if (err < 0) { - perf_header__delete(header); - return err; - } + if (err < 0) + goto out_delete; *pheader = header; head = header->data_offset; sample_type = perf_header__sample_type(header); - if (curr_handler->sample_type_check) - if (curr_handler->sample_type_check(sample_type) < 0) - exit(-1); + err = -EINVAL; + if (curr_handler->sample_type_check && + curr_handler->sample_type_check(sample_type) < 0) + goto out_delete; + err = -ENOMEM; if (load_kernel(NULL) < 0) { - perror("failed to load kernel symbols"); - return EXIT_FAILURE; + pr_err("failed to load kernel symbols\n"); + goto out_delete; } if (!full_paths) { if (getcwd(__cwd, sizeof(__cwd)) == NULL) { - perror("failed to get the current directory"); - return EXIT_FAILURE; + pr_err("failed to get the current directory\n"); + err = -errno; + goto out_delete; } *cwd = __cwd; *cwdlen = strlen(*cwd); @@ -189,11 +194,12 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, head -= shift; remap: - buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, - MAP_SHARED, input, offset); + buf = mmap(NULL, page_size * mmap_window, PROT_READ, + MAP_SHARED, input, offset); if (buf == MAP_FAILED) { - perror("failed to mmap file"); - exit(-1); + pr_err("failed to mmap file\n"); + err = -errno; + goto out_delete; } more: @@ -250,10 +256,12 @@ more: goto more; done: - rc = EXIT_SUCCESS; + err = 0; +out_close: close(input); - return rc; + return err; +out_delete: + perf_header__delete(header); + goto out_close; } - - -- cgit v1.2.3-70-g09d2 From 6671cb1674e69e2aba3d610714bdd3e97a7b51ff Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 20 Nov 2009 20:51:24 -0200 Subject: perf symbols: Remove unrelated actions from dso__load_kernel_sym MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It should just load kernel symbols, not load the list of modules. There are more stuff to move to other routines, but lets do it in several steps. End goal is to be able to defer symbol table loading till we find a hit for that map address range. So that the kernel & modules are handled just like all the other DSOs in the system. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1258757489-5978-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 5 +++-- tools/perf/builtin-report.c | 3 ++- tools/perf/builtin-top.c | 10 +++++++++- tools/perf/util/data_map.c | 2 +- tools/perf/util/symbol.c | 46 ++++++++++++++++++------------------------- tools/perf/util/symbol.h | 7 ++++--- 6 files changed, 38 insertions(+), 35 deletions(-) (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 77d50a6d680..b6da1476ab1 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -33,6 +33,7 @@ static int input; static int full_paths; static int print_line; +static bool use_modules; static unsigned long page_size; static unsigned long mmap_window = 32; @@ -636,7 +637,7 @@ static int __cmd_annotate(void) exit(0); } - if (load_kernel(symbol_filter) < 0) { + if (load_kernel(symbol_filter, use_modules) < 0) { perror("failed to load kernel symbols"); return EXIT_FAILURE; } @@ -742,7 +743,7 @@ static const struct option options[] = { OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), - OPT_BOOLEAN('m', "modules", &modules, + OPT_BOOLEAN('m', "modules", &use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), OPT_BOOLEAN('l', "print-line", &print_line, "print matching source lines (may be slow)"), diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1a806d5f05c..0af48401f08 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -38,6 +38,7 @@ static char *dso_list_str, *comm_list_str, *sym_list_str, static struct strlist *dso_list, *comm_list, *sym_list; static int force; +static bool use_modules; static int full_paths; static int show_nr_samples; @@ -1023,7 +1024,7 @@ static const struct option options[] = { "dump raw trace in ASCII"), OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), - OPT_BOOLEAN('m', "modules", &modules, + OPT_BOOLEAN('m', "modules", &use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, "Show a column with the number of samples"), diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 6d770ac7be0..48cc1084bc3 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -953,8 +953,16 @@ static int parse_symbols(void) if (kernel == NULL) return -1; + if (dsos__load_modules() < 0) + pr_debug("Couldn't read the complete list of modules, " + "continuing...\n"); + + if (dsos__load_modules_sym(symbol_filter) < 0) + pr_warning("Failed to read module symbols, continuing...\n"); + if (dso__load_kernel_sym(kernel, symbol_filter, 1) <= 0) - return -1; + pr_debug("Couldn't read the complete list of kernel symbols, " + "continuing...\n"); if (dump_symtab) dsos__fprintf(stderr); diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index 5543e7d0487..a444a2645c8 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -171,7 +171,7 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, goto out_delete; err = -ENOMEM; - if (load_kernel(NULL) < 0) { + if (load_kernel(NULL, 1) < 0) { pr_err("failed to load kernel symbols\n"); goto out_delete; } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 4d75e745288..3b23c18cd36 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1230,7 +1230,7 @@ failure: return -1; } -static int dsos__load_modules_sym(symbol_filter_t filter) +int dsos__load_modules_sym(symbol_filter_t filter) { struct utsname uts; char modules_path[PATH_MAX]; @@ -1352,33 +1352,18 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, return err; } -int dso__load_kernel_sym(struct dso *self, symbol_filter_t filter, int use_modules) +int dso__load_kernel_sym(struct dso *self, symbol_filter_t filter, + int use_modules) { - int err = -1; + int err; kernel_map = map__new2(0, self); if (kernel_map == NULL) - goto out_delete_dso; + return -1; kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; - if (use_modules && dsos__load_modules() < 0) { - pr_warning("Failed to load list of modules in use! " - "Continuing...\n"); - use_modules = 0; - } - err = dso__load_vmlinux(self, kernel_map, self->name, filter); - if (err > 0 && use_modules) { - int syms = dsos__load_modules_sym(filter); - - if (syms < 0) - pr_warning("Failed to read module symbols!" - " Continuing...\n"); - else - err += syms; - } - if (err <= 0) err = kernel_maps__load_kallsyms(filter, use_modules); @@ -1404,17 +1389,12 @@ int dso__load_kernel_sym(struct dso *self, symbol_filter_t filter, int use_modul } return err; - -out_delete_dso: - dso__delete(self); - return -1; } LIST_HEAD(dsos); struct dso *vdso; const char *vmlinux_name = "vmlinux"; -int modules; static void dsos__add(struct dso *dso) { @@ -1488,14 +1468,26 @@ struct dso *dsos__load_kernel(void) return kernel; } -int load_kernel(symbol_filter_t filter) +int load_kernel(symbol_filter_t filter, bool use_modules) { struct dso *kernel = dsos__load_kernel(); if (kernel == NULL) return -1; - return dso__load_kernel_sym(kernel, filter, modules); + if (use_modules) { + if (dsos__load_modules() < 0) + pr_warning("Failed to load list of modules in use, " + "continuing...\n"); + else if (dsos__load_modules_sym(filter) < 0) + pr_warning("Failed to read module symbols, " + "continuing...\n"); + } + + if (dso__load_kernel_sym(kernel, filter, use_modules) < 0) + pr_warning("Failed to read kernel symbols, continuing...\n"); + + return 0; } void symbol__init(unsigned int priv_size) diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index f0593a649c3..3d9d346d101 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -78,9 +78,11 @@ void dso__delete(struct dso *self); struct symbol *dso__find_symbol(struct dso *self, u64 ip); int dsos__load_modules(void); +int dsos__load_modules_sym(symbol_filter_t filter); struct dso *dsos__findnew(const char *name); int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); -int dso__load_kernel_sym(struct dso *self, symbol_filter_t filter, int modules); +int dso__load_kernel_sym(struct dso *self, symbol_filter_t filter, + int use_modules); void dsos__fprintf(FILE *fp); size_t dsos__fprintf_buildid(FILE *fp); @@ -95,7 +97,7 @@ bool dsos__read_build_ids(void); int build_id__sprintf(u8 *self, int len, char *bf); struct dso *dsos__load_kernel(void); -int load_kernel(symbol_filter_t filter); +int load_kernel(symbol_filter_t filter, bool use_modules); void symbol__init(unsigned int priv_size); @@ -103,5 +105,4 @@ extern struct list_head dsos; extern struct map *kernel_map; extern struct dso *vdso; extern const char *vmlinux_name; -extern int modules; #endif /* __PERF_SYMBOL */ -- cgit v1.2.3-70-g09d2 From c338aee853db197e1855b393e6d6cc667784537f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 20 Nov 2009 20:51:27 -0200 Subject: perf symbols: Do lazy symtab loading for the kernel & modules too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just like we do with the other DSOs. This also simplifies the kernel_maps setup process, now all that the tools need to do is to call kernel_maps__init and the maps for the modules and kernel will be created, then, later, when kernel_maps__find_symbol() is used, it will also call maps__find_symbol that already checks if the symtab was loaded, loading it if needed. Now if one does 'perf top --hide_kernel_symbols' we won't pay the price of loading the (many) symbols in /proc/kallsyms or vmlinux. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1258757489-5978-4-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 8 +- tools/perf/builtin-report.c | 6 +- tools/perf/builtin-top.c | 35 ++------- tools/perf/util/data_map.c | 4 +- tools/perf/util/event.h | 3 + tools/perf/util/header.c | 6 +- tools/perf/util/map.c | 23 ++++++ tools/perf/util/symbol.c | 173 ++++++++++++++---------------------------- tools/perf/util/symbol.h | 9 +-- tools/perf/util/thread.h | 3 +- 10 files changed, 109 insertions(+), 161 deletions(-) (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index b6da1476ab1..203152729a6 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -157,7 +157,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) if (event->header.misc & PERF_RECORD_MISC_KERNEL) { level = 'k'; - sym = kernel_maps__find_symbol(ip, &map); + sym = kernel_maps__find_symbol(ip, &map, symbol_filter); dump_printf(" ...... dso: %s\n", map ? map->dso->long_name : ""); } else if (event->header.misc & PERF_RECORD_MISC_USER) { @@ -637,9 +637,9 @@ static int __cmd_annotate(void) exit(0); } - if (load_kernel(symbol_filter, use_modules) < 0) { - perror("failed to load kernel symbols"); - return EXIT_FAILURE; + if (kernel_maps__init(use_modules) < 0) { + pr_err("failed to create kernel maps for symbol resolution\b"); + return -1; } remap: diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 0af48401f08..0d39e805be2 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -449,7 +449,7 @@ got_map: * trick of looking in the whole kernel symbol list. */ if ((long long)ip < 0) - return kernel_maps__find_symbol(ip, mapp); + return kernel_maps__find_symbol(ip, mapp, NULL); } dump_printf(" ...... dso: %s\n", map ? map->dso->long_name : ""); @@ -496,7 +496,7 @@ static struct symbol **resolve_callchain(struct thread *thread, struct map *map, case PERF_CONTEXT_HV: break; case PERF_CONTEXT_KERNEL: - sym = kernel_maps__find_symbol(ip, &map); + sym = kernel_maps__find_symbol(ip, &map, NULL); break; default: sym = resolve_symbol(thread, &map, &ip); @@ -716,7 +716,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) if (cpumode == PERF_RECORD_MISC_KERNEL) { level = 'k'; - sym = kernel_maps__find_symbol(ip, &map); + sym = kernel_maps__find_symbol(ip, &map, NULL); dump_printf(" ...... dso: %s\n", map ? map->dso->long_name : ""); } else if (cpumode == PERF_RECORD_MISC_USER) { diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 48cc1084bc3..ea49c2e9dda 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -830,6 +830,8 @@ static void handle_keypress(int c) case 'q': case 'Q': printf("exiting.\n"); + if (dump_symtab) + dsos__fprintf(stderr); exit(0); case 's': prompt_symbol(&sym_filter_entry, "Enter details symbol"); @@ -946,30 +948,6 @@ static int symbol_filter(struct map *map, struct symbol *sym) return 0; } -static int parse_symbols(void) -{ - struct dso *kernel = dsos__load_kernel(); - - if (kernel == NULL) - return -1; - - if (dsos__load_modules() < 0) - pr_debug("Couldn't read the complete list of modules, " - "continuing...\n"); - - if (dsos__load_modules_sym(symbol_filter) < 0) - pr_warning("Failed to read module symbols, continuing...\n"); - - if (dso__load_kernel_sym(kernel, symbol_filter, 1) <= 0) - pr_debug("Couldn't read the complete list of kernel symbols, " - "continuing...\n"); - - if (dump_symtab) - dsos__fprintf(stderr); - - return 0; -} - static void event__process_sample(const event_t *self, int counter) { u64 ip = self->ip.ip; @@ -1012,7 +990,7 @@ static void event__process_sample(const event_t *self, int counter) if (hide_kernel_symbols) return; - sym = kernel_maps__find_symbol(ip, &map); + sym = kernel_maps__find_symbol(ip, &map, symbol_filter); if (sym == NULL) return; break; @@ -1339,7 +1317,7 @@ static const struct option options[] = { int cmd_top(int argc, const char **argv, const char *prefix __used) { - int counter; + int counter, err; page_size = sysconf(_SC_PAGE_SIZE); @@ -1363,10 +1341,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) if (delay_secs < 1) delay_secs = 1; - parse_symbols(); + err = kernel_maps__init(true); + if (err < 0) + return err; parse_source(sym_filter_entry); - /* * User specified count overrides default frequency. */ diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index a444a2645c8..e7b6c2bea3d 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -171,8 +171,8 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, goto out_delete; err = -ENOMEM; - if (load_kernel(NULL, 1) < 0) { - pr_err("failed to load kernel symbols\n"); + if (kernel_maps__init(true) < 0) { + pr_err("failed to setup the kernel maps to resolve symbols\n"); goto out_delete; } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 34c6fcb82d9..f1e39261265 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -115,10 +115,13 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); void map__init(struct map *self, u64 start, u64 end, u64 pgoff, struct dso *dso); struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen); +void map__delete(struct map *self); struct map *map__clone(struct map *self); int map__overlap(struct map *l, struct map *r); size_t map__fprintf(struct map *self, FILE *fp); struct symbol *map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter); +void map__fixup_start(struct map *self); +void map__fixup_end(struct map *self); int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); void event__synthesize_threads(int (*process)(event_t *event)); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index d5c81ebc0a8..ac3410b8e9e 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -253,11 +253,11 @@ static int perf_header__adds_write(struct perf_header *self, int fd) buildid_sec = &feat_sec[idx++]; - dsos__load_kernel(); /* - * Read the list of loaded modules with its build_ids + * Read the kernel buildid nad the list of loaded modules with + * its build_ids: */ - dsos__load_modules(); + kernel_maps__init(true); /* Write build-ids */ buildid_sec->offset = lseek(fd, 0, SEEK_CUR); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 94ca95073c4..09412321a80 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -75,6 +75,29 @@ out_delete: return NULL; } +void map__delete(struct map *self) +{ + free(self); +} + +void map__fixup_start(struct map *self) +{ + struct rb_node *nd = rb_first(&self->dso->syms); + if (nd != NULL) { + struct symbol *sym = rb_entry(nd, struct symbol, rb_node); + self->start = sym->start; + } +} + +void map__fixup_end(struct map *self) +{ + struct rb_node *nd = rb_last(&self->dso->syms); + if (nd != NULL) { + struct symbol *sym = rb_entry(nd, struct symbol, rb_node); + self->end = sym->end; + } +} + #define DSO__DELETED "(deleted)" struct symbol * diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index c324bdf8bab..cb086cbe6b1 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -27,6 +27,8 @@ static void dsos__add(struct dso *dso); static struct dso *dsos__find(const char *name); static struct map *map__new2(u64 start, struct dso *dso); static void kernel_maps__insert(struct map *map); +static int dso__load_kernel_sym(struct dso *self, struct map *map, + symbol_filter_t filter); unsigned int symbol__priv_size; static struct rb_root kernel_maps; @@ -69,12 +71,6 @@ static void kernel_maps__fixup_end(void) curr = rb_entry(nd, struct map, rb_node); prev->end = curr->start - 1; } - - nd = rb_last(&curr->dso->syms); - if (nd) { - struct symbol *sym = rb_entry(nd, struct symbol, rb_node); - curr->end = sym->end; - } } static struct symbol *symbol__new(u64 start, u64 len, const char *name) @@ -324,7 +320,7 @@ out_failure: * kernel range is broken in several maps, named [kernel].N, as we don't have * the original ELF section names vmlinux have. */ -static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules) +static int kernel_maps__split_kallsyms(symbol_filter_t filter) { struct map *map = kernel_map; struct symbol *pos; @@ -340,9 +336,6 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules) module = strchr(pos->name, '\t'); if (module) { - if (!use_modules) - goto delete_symbol; - *module++ = '\0'; if (strcmp(map->dso->name, module)) { @@ -382,7 +375,6 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules) } if (filter && filter(map, pos)) { -delete_symbol: rb_erase(&pos->rb_node, &kernel_map->dso->syms); symbol__delete(pos); } else { @@ -398,17 +390,18 @@ delete_symbol: } -static int kernel_maps__load_kallsyms(symbol_filter_t filter, int use_modules) +static int kernel_maps__load_kallsyms(symbol_filter_t filter) { if (kernel_maps__load_all_kallsyms()) return -1; dso__fixup_sym_end(kernel_map->dso); + kernel_map->dso->origin = DSO__ORIG_KERNEL; - return kernel_maps__split_kallsyms(filter, use_modules); + return kernel_maps__split_kallsyms(filter); } -static size_t kernel_maps__fprintf(FILE *fp) +size_t kernel_maps__fprintf(FILE *fp) { size_t printed = fprintf(fp, "Kernel maps:\n"); struct rb_node *nd; @@ -1042,13 +1035,17 @@ char dso__symtab_origin(const struct dso *self) int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) { int size = PATH_MAX; - char *name = malloc(size); + char *name; u8 build_id[BUILD_ID_SIZE]; int ret = -1; int fd; self->loaded = 1; + if (self->kernel) + return dso__load_kernel_sym(self, map, filter); + + name = malloc(size); if (!name) return -1; @@ -1139,7 +1136,8 @@ static void kernel_maps__insert(struct map *map) maps__insert(&kernel_maps, map); } -struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp) +struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp, + symbol_filter_t filter) { struct map *map = maps__find(&kernel_maps, ip); @@ -1148,7 +1146,7 @@ struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp) if (map) { ip = map->map_ip(map, ip); - return map->dso->find_symbol(map->dso, ip); + return map__find_symbol(map, ip, filter); } return NULL; @@ -1168,28 +1166,9 @@ struct map *kernel_maps__find_by_dso_name(const char *name) return NULL; } -static int dso__load_module_sym(struct dso *self, struct map *map, - symbol_filter_t filter) -{ - int err = 0, fd = open(self->long_name, O_RDONLY); - - self->loaded = 1; - - if (fd < 0) { - pr_err("%s: cannot open %s\n", __func__, self->long_name); - return err; - } - - err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1); - close(fd); - - return err; -} - -static int dsos__load_modules_sym_dir(char *dirname, symbol_filter_t filter) +static int dsos__set_modules_path_dir(char *dirname) { struct dirent *dent; - int nr_symbols = 0, err; DIR *dir = opendir(dirname); if (!dir) { @@ -1207,14 +1186,12 @@ static int dsos__load_modules_sym_dir(char *dirname, symbol_filter_t filter) snprintf(path, sizeof(path), "%s/%s", dirname, dent->d_name); - err = dsos__load_modules_sym_dir(path, filter); - if (err < 0) + if (dsos__set_modules_path_dir(path) < 0) goto failure; } else { char *dot = strrchr(dent->d_name, '.'), dso_name[PATH_MAX]; struct map *map; - struct rb_node *last; char *long_name; if (dot == NULL || strcmp(dot, ".ko")) @@ -1234,36 +1211,16 @@ static int dsos__load_modules_sym_dir(char *dirname, symbol_filter_t filter) if (long_name == NULL) goto failure; dso__set_long_name(map->dso, long_name); - dso__set_basename(map->dso); - - err = dso__load_module_sym(map->dso, map, filter); - if (err < 0) - goto failure; - last = rb_last(&map->dso->syms); - if (last) { - struct symbol *sym; - /* - * We do this here as well, even having the - * symbol size found in the symtab because - * misannotated ASM symbols may have the size - * set to zero. - */ - dso__fixup_sym_end(map->dso); - - sym = rb_entry(last, struct symbol, rb_node); - map->end = map->start + sym->end; - } } - nr_symbols += err; } - return nr_symbols; + return 0; failure: closedir(dir); return -1; } -int dsos__load_modules_sym(symbol_filter_t filter) +static int dsos__set_modules_path(void) { struct utsname uts; char modules_path[PATH_MAX]; @@ -1274,7 +1231,7 @@ int dsos__load_modules_sym(symbol_filter_t filter) snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", uts.release); - return dsos__load_modules_sym_dir(modules_path, filter); + return dsos__set_modules_path_dir(modules_path); } /* @@ -1296,7 +1253,7 @@ static struct map *map__new2(u64 start, struct dso *dso) return self; } -int dsos__load_modules(void) +static int kernel_maps__create_module_maps(void) { char *line = NULL; size_t n; @@ -1360,7 +1317,13 @@ int dsos__load_modules(void) free(line); fclose(file); - return 0; + /* + * Now that we have all sorted out, just set the ->end of all + * maps: + */ + kernel_maps__fixup_end(); + + return dsos__set_modules_path(); out_delete_line: free(line); @@ -1385,40 +1348,17 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, return err; } -int dso__load_kernel_sym(struct dso *self, symbol_filter_t filter, - int use_modules) +static int dso__load_kernel_sym(struct dso *self, struct map *map, + symbol_filter_t filter) { - int err; + int err = dso__load_vmlinux(self, map, self->name, filter); - kernel_map = map__new2(0, self); - if (kernel_map == NULL) - return -1; - - kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; - - err = dso__load_vmlinux(self, kernel_map, self->name, filter); if (err <= 0) - err = kernel_maps__load_kallsyms(filter, use_modules); + err = kernel_maps__load_kallsyms(filter); if (err > 0) { - struct rb_node *node = rb_first(&self->syms); - struct symbol *sym = rb_entry(node, struct symbol, rb_node); - - kernel_map->start = sym->start; - node = rb_last(&self->syms); - sym = rb_entry(node, struct symbol, rb_node); - kernel_map->end = sym->end; - - self->origin = DSO__ORIG_KERNEL; - kernel_maps__insert(kernel_map); - /* - * Now that we have all sorted out, just set the ->end of all - * maps: - */ - kernel_maps__fixup_end(); - - if (verbose) - kernel_maps__fprintf(stderr); + map__fixup_start(map); + map__fixup_end(map); } return err; @@ -1479,46 +1419,51 @@ size_t dsos__fprintf_buildid(FILE *fp) return ret; } -struct dso *dsos__load_kernel(void) +static int kernel_maps__create_kernel_map(void) { struct dso *kernel = dso__new(vmlinux_name); if (kernel == NULL) - return NULL; + return -1; + + kernel_map = map__new2(0, kernel); + if (kernel_map == NULL) + goto out_delete_kernel_dso; + + kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; kernel->short_name = "[kernel]"; + kernel->kernel = 1; vdso = dso__new("[vdso]"); - if (!vdso) - return NULL; + if (vdso == NULL) + goto out_delete_kernel_map; if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, sizeof(kernel->build_id)) == 0) kernel->has_build_id = true; + kernel_maps__insert(kernel_map); dsos__add(kernel); dsos__add(vdso); - return kernel; + return 0; + +out_delete_kernel_map: + map__delete(kernel_map); + kernel_map = NULL; +out_delete_kernel_dso: + dso__delete(kernel); + return -1; } -int load_kernel(symbol_filter_t filter, bool use_modules) +int kernel_maps__init(bool use_modules) { - struct dso *kernel = dsos__load_kernel(); - - if (kernel == NULL) + if (kernel_maps__create_kernel_map() < 0) return -1; - if (use_modules) { - if (dsos__load_modules() < 0) - pr_warning("Failed to load list of modules in use, " - "continuing...\n"); - else if (dsos__load_modules_sym(filter) < 0) - pr_warning("Failed to read module symbols, " - "continuing...\n"); - } - - if (dso__load_kernel_sym(kernel, filter, use_modules) < 0) - pr_warning("Failed to read kernel symbols, continuing...\n"); + if (use_modules && kernel_maps__create_module_maps() < 0) + pr_warning("Failed to load list of modules in use, " + "continuing...\n"); return 0; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 3d9d346d101..7a129047c47 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -64,6 +64,7 @@ struct dso { u8 slen_calculated:1; u8 loaded:1; u8 has_build_id:1; + u8 kernel:1; unsigned char origin; u8 build_id[BUILD_ID_SIZE]; u16 long_name_len; @@ -77,12 +78,8 @@ void dso__delete(struct dso *self); struct symbol *dso__find_symbol(struct dso *self, u64 ip); -int dsos__load_modules(void); -int dsos__load_modules_sym(symbol_filter_t filter); struct dso *dsos__findnew(const char *name); int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); -int dso__load_kernel_sym(struct dso *self, symbol_filter_t filter, - int use_modules); void dsos__fprintf(FILE *fp); size_t dsos__fprintf_buildid(FILE *fp); @@ -96,8 +93,8 @@ int sysfs__read_build_id(const char *filename, void *bf, size_t size); bool dsos__read_build_ids(void); int build_id__sprintf(u8 *self, int len, char *bf); -struct dso *dsos__load_kernel(void); -int load_kernel(symbol_filter_t filter, bool use_modules); +int kernel_maps__init(bool use_modules); +size_t kernel_maps__fprintf(FILE *fp); void symbol__init(unsigned int priv_size); diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 53addd77ce8..e4b8d437725 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -26,7 +26,8 @@ size_t threads__fprintf(FILE *fp); void maps__insert(struct rb_root *maps, struct map *map); struct map *maps__find(struct rb_root *maps, u64 ip); -struct symbol *kernel_maps__find_symbol(const u64 ip, struct map **mapp); +struct symbol *kernel_maps__find_symbol(const u64 ip, struct map **mapp, + symbol_filter_t filter); struct map *kernel_maps__find_by_dso_name(const char *name); static inline struct map *thread__find_map(struct thread *self, u64 ip) -- cgit v1.2.3-70-g09d2 From cc612d8199089413719397c9d92e5823da578eac Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 23 Nov 2009 16:39:10 -0200 Subject: perf symbols: Look for vmlinux in more places MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we can check the buildid to see if it really matches, this can be done safely: vmlinux /boot/vmlinux /boot/vmlinux- /lib/modules//build/vmlinux /usr/lib/debug/lib/modules/%s/vmlinux More can be added - if you know about distros that put the vmlinux somewhere else please let us know. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1259001550-8194-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 3 +- tools/perf/builtin-kmem.c | 2 +- tools/perf/builtin-report.c | 6 ++- tools/perf/builtin-sched.c | 3 +- tools/perf/builtin-top.c | 3 +- tools/perf/builtin-trace.c | 3 +- tools/perf/util/data_map.c | 4 +- tools/perf/util/data_map.h | 2 + tools/perf/util/header.c | 2 +- tools/perf/util/symbol.c | 113 +++++++++++++++++++++++++++++++++++++----- tools/perf/util/symbol.h | 4 +- 11 files changed, 122 insertions(+), 23 deletions(-) (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 203152729a6..6b13a1ecf1e 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -37,6 +37,7 @@ static bool use_modules; static unsigned long page_size; static unsigned long mmap_window = 32; +const char *vmlinux_name; struct sym_hist { u64 sum; @@ -637,7 +638,7 @@ static int __cmd_annotate(void) exit(0); } - if (kernel_maps__init(use_modules) < 0) { + if (kernel_maps__init(vmlinux_name, true, use_modules) < 0) { pr_err("failed to create kernel maps for symbol resolution\b"); return -1; } diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 4145049e7bf..5d8aeae5000 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -291,7 +291,7 @@ static int read_events(void) register_idle_thread(); register_perf_file_handler(&file_handler); - return mmap_dispatch_perf_file(&header, input_name, 0, 0, + return mmap_dispatch_perf_file(&header, input_name, NULL, false, 0, 0, &cwdlen, &cwd); } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 7e690f73b51..fe474b7f8ad 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -52,6 +52,7 @@ static char *pretty_printing_style = default_pretty_printing_style; static int exclude_other = 1; static char callchain_default_opt[] = "fractal,0.5"; +const char *vmlinux_name; static char *cwd; static int cwdlen; @@ -925,8 +926,9 @@ static int __cmd_report(void) register_perf_file_handler(&file_handler); - ret = mmap_dispatch_perf_file(&header, input_name, force, full_paths, - &cwdlen, &cwd); + ret = mmap_dispatch_perf_file(&header, input_name, vmlinux_name, + !vmlinux_name, force, + full_paths, &cwdlen, &cwd); if (ret) return ret; diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index df44b756cec..260f57a72ee 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1718,7 +1718,8 @@ static int read_events(void) register_idle_thread(); register_perf_file_handler(&file_handler); - return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd); + return mmap_dispatch_perf_file(&header, input_name, NULL, false, 0, 0, + &cwdlen, &cwd); } static void print_bad_events(void) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ea49c2e9dda..eef9caab6ee 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -79,6 +79,7 @@ static int dump_symtab = 0; static bool hide_kernel_symbols = false; static bool hide_user_symbols = false; static struct winsize winsize; +const char *vmlinux_name; static const char *graph_line = "_____________________________________________________________________" "_____________________________________________________________________"; @@ -1341,7 +1342,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) if (delay_secs < 1) delay_secs = 1; - err = kernel_maps__init(true); + err = kernel_maps__init(vmlinux_name, !vmlinux_name, true); if (err < 0) return err; parse_source(sym_filter_entry); diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index d042d656c56..b71198e5dc1 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -131,7 +131,8 @@ static int __cmd_trace(void) register_idle_thread(); register_perf_file_handler(&file_handler); - return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd); + return mmap_dispatch_perf_file(&header, input_name, NULL, false, + 0, 0, &cwdlen, &cwd); } static const char * const annotate_usage[] = { diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index e7b6c2bea3d..f318d19b256 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -101,6 +101,8 @@ out: int mmap_dispatch_perf_file(struct perf_header **pheader, const char *input_name, + const char *vmlinux_name, + bool try_vmlinux_path, int force, int full_paths, int *cwdlen, @@ -171,7 +173,7 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, goto out_delete; err = -ENOMEM; - if (kernel_maps__init(true) < 0) { + if (kernel_maps__init(vmlinux_name, try_vmlinux_path, true) < 0) { pr_err("failed to setup the kernel maps to resolve symbols\n"); goto out_delete; } diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h index ae036ecd762..3f0d21b3819 100644 --- a/tools/perf/util/data_map.h +++ b/tools/perf/util/data_map.h @@ -23,6 +23,8 @@ struct perf_file_handler { void register_perf_file_handler(struct perf_file_handler *handler); int mmap_dispatch_perf_file(struct perf_header **pheader, const char *input_name, + const char *vmlinux_name, + bool try_vmlinux_path, int force, int full_paths, int *cwdlen, diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index ac3410b8e9e..1332f8ec04a 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -257,7 +257,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd) * Read the kernel buildid nad the list of loaded modules with * its build_ids: */ - kernel_maps__init(true); + kernel_maps__init(NULL, false, true); /* Write build-ids */ buildid_sec->offset = lseek(fd, 0, SEEK_CUR); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 74b5b8a1695..44d81d5ae8c 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -34,6 +34,8 @@ static void kernel_maps__insert(struct map *map); static int dso__load_kernel_sym(struct dso *self, struct map *map, symbol_filter_t filter); unsigned int symbol__priv_size; +static int vmlinux_path__nr_entries; +static char **vmlinux_path; static struct rb_root kernel_maps; @@ -1386,15 +1388,43 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, static int dso__load_kernel_sym(struct dso *self, struct map *map, symbol_filter_t filter) { - int err = dso__load_vmlinux(self, map, self->name, filter); + int err; + bool is_kallsyms; + + if (vmlinux_path != NULL) { + int i; + pr_debug("Looking at the vmlinux_path (%d entries long)\n", + vmlinux_path__nr_entries); + for (i = 0; i < vmlinux_path__nr_entries; ++i) { + err = dso__load_vmlinux(self, map, vmlinux_path[i], + filter); + if (err > 0) { + pr_debug("Using %s for symbols\n", + vmlinux_path[i]); + dso__set_long_name(self, + strdup(vmlinux_path[i])); + goto out_fixup; + } + } + } + + is_kallsyms = self->long_name[0] == '['; + if (is_kallsyms) + goto do_kallsyms; + err = dso__load_vmlinux(self, map, self->long_name, filter); if (err <= 0) { + pr_info("The file %s cannot be used, " + "trying to use /proc/kallsyms...", self->long_name); + sleep(2); +do_kallsyms: err = kernel_maps__load_kallsyms(filter); - if (err > 0) + if (err > 0 && !is_kallsyms) dso__set_long_name(self, strdup("[kernel.kallsyms]")); } if (err > 0) { +out_fixup: map__fixup_start(map); map__fixup_end(map); } @@ -1403,9 +1433,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, } LIST_HEAD(dsos); -struct dso *vdso; - -const char *vmlinux_name = "vmlinux"; +struct dso *vdso; static void dsos__add(struct dso *dso) { @@ -1457,9 +1485,9 @@ size_t dsos__fprintf_buildid(FILE *fp) return ret; } -static int kernel_maps__create_kernel_map(void) +static int kernel_maps__create_kernel_map(const char *vmlinux_name) { - struct dso *kernel = dso__new(vmlinux_name); + struct dso *kernel = dso__new(vmlinux_name ?: "[kernel.kallsyms]"); if (kernel == NULL) return -1; @@ -1468,10 +1496,10 @@ static int kernel_maps__create_kernel_map(void) if (kernel_map == NULL) goto out_delete_kernel_dso; - kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; + kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; + kernel->short_name = "[kernel]"; + kernel->kernel = 1; - kernel->short_name = "[kernel]"; - kernel->kernel = 1; vdso = dso__new("[vdso]"); if (vdso == NULL) goto out_delete_kernel_map; @@ -1494,11 +1522,72 @@ out_delete_kernel_dso: return -1; } -int kernel_maps__init(bool use_modules) +static void vmlinux_path__exit(void) +{ + while (--vmlinux_path__nr_entries >= 0) { + free(vmlinux_path[vmlinux_path__nr_entries]); + vmlinux_path[vmlinux_path__nr_entries] = NULL; + } + + free(vmlinux_path); + vmlinux_path = NULL; +} + +static int vmlinux_path__init(void) +{ + struct utsname uts; + char bf[PATH_MAX]; + + if (uname(&uts) < 0) + return -1; + + vmlinux_path = malloc(sizeof(char *) * 5); + if (vmlinux_path == NULL) + return -1; + + vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); + if (vmlinux_path[vmlinux_path__nr_entries] == NULL) + goto out_fail; + ++vmlinux_path__nr_entries; + vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); + if (vmlinux_path[vmlinux_path__nr_entries] == NULL) + goto out_fail; + ++vmlinux_path__nr_entries; + snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); + vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); + if (vmlinux_path[vmlinux_path__nr_entries] == NULL) + goto out_fail; + ++vmlinux_path__nr_entries; + snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); + vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); + if (vmlinux_path[vmlinux_path__nr_entries] == NULL) + goto out_fail; + ++vmlinux_path__nr_entries; + snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", + uts.release); + vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); + if (vmlinux_path[vmlinux_path__nr_entries] == NULL) + goto out_fail; + ++vmlinux_path__nr_entries; + + return 0; + +out_fail: + vmlinux_path__exit(); + return -1; +} + +int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path, + bool use_modules) { - if (kernel_maps__create_kernel_map() < 0) + if (try_vmlinux_path && vmlinux_path__init() < 0) return -1; + if (kernel_maps__create_kernel_map(vmlinux_name) < 0) { + vmlinux_path__exit(); + return -1; + } + if (use_modules && kernel_maps__create_module_maps() < 0) pr_debug("Failed to load list of modules in use, " "continuing...\n"); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 7a129047c47..8c4d026e067 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -93,7 +93,8 @@ int sysfs__read_build_id(const char *filename, void *bf, size_t size); bool dsos__read_build_ids(void); int build_id__sprintf(u8 *self, int len, char *bf); -int kernel_maps__init(bool use_modules); +int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path, + bool use_modules); size_t kernel_maps__fprintf(FILE *fp); void symbol__init(unsigned int priv_size); @@ -101,5 +102,4 @@ void symbol__init(unsigned int priv_size); extern struct list_head dsos; extern struct map *kernel_map; extern struct dso *vdso; -extern const char *vmlinux_name; #endif /* __PERF_SYMBOL */ -- cgit v1.2.3-70-g09d2 From b32d133aec5dc882cf783a293f393bfb3f4379e1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 24 Nov 2009 12:05:15 -0200 Subject: perf symbols: Simplify symbol machinery setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And also express its configuration toggles via a struct. Now all one has to do is to call symbol__init(NULL) if the defaults are OK, or pass a struct symbol_conf pointer with the desired configuration. If a tool uses kernel_maps__find_symbol() to look at the kernel and modules mappings for a symbol but didn't call symbol__init() first, that will generate a one time warning too, alerting the subcommand developer that symbol__init() must be called. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1259071517-3242-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 20 ++++++++++---------- tools/perf/builtin-kmem.c | 2 +- tools/perf/builtin-report.c | 15 ++++++++------- tools/perf/builtin-sched.c | 2 +- tools/perf/builtin-top.c | 24 +++++++++++++----------- tools/perf/builtin-trace.c | 2 +- tools/perf/util/data_map.c | 8 -------- tools/perf/util/data_map.h | 2 -- tools/perf/util/header.c | 6 ------ tools/perf/util/include/asm/bug.h | 22 ++++++++++++++++++++++ tools/perf/util/symbol.c | 31 +++++++++++++++++++++---------- tools/perf/util/symbol.h | 11 ++++++++--- 12 files changed, 85 insertions(+), 60 deletions(-) create mode 100644 tools/perf/util/include/asm/bug.h (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 59b6123abec..cd97c2b1cc3 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -34,11 +34,9 @@ static int input; static int full_paths; static int print_line; -static bool use_modules; static unsigned long page_size; static unsigned long mmap_window = 32; -const char *vmlinux_name; struct sym_hist { u64 sum; @@ -56,6 +54,11 @@ struct sym_priv { struct sym_ext *ext; }; +static struct symbol_conf symbol_conf = { + .priv_size = sizeof(struct sym_priv), + .try_vmlinux_path = true, +}; + static const char *sym_hist_filter; static int symbol_filter(struct map *map __used, struct symbol *sym) @@ -586,11 +589,6 @@ static int __cmd_annotate(void) exit(0); } - if (kernel_maps__init(vmlinux_name, true, use_modules) < 0) { - pr_err("failed to create kernel maps for symbol resolution\b"); - return -1; - } - remap: buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, MAP_SHARED, input, offset); @@ -691,8 +689,9 @@ static const struct option options[] = { "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), - OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), - OPT_BOOLEAN('m', "modules", &use_modules, + OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, + "file", "vmlinux pathname"), + OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), OPT_BOOLEAN('l', "print-line", &print_line, "print matching source lines (may be slow)"), @@ -718,7 +717,8 @@ static void setup_sorting(void) int cmd_annotate(int argc, const char **argv, const char *prefix __used) { - symbol__init(sizeof(struct sym_priv)); + if (symbol__init(&symbol_conf) < 0) + return -1; page_size = getpagesize(); diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 173d6db42ec..330dbc762f9 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -412,7 +412,7 @@ static int read_events(void) register_idle_thread(); register_perf_file_handler(&file_handler); - return mmap_dispatch_perf_file(&header, input_name, NULL, false, 0, 0, + return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd); } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1826be719b5..0ee3d05a040 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -39,7 +39,6 @@ static char *dso_list_str, *comm_list_str, *sym_list_str, static struct strlist *dso_list, *comm_list, *sym_list; static int force; -static bool use_modules; static int full_paths; static int show_nr_samples; @@ -53,12 +52,13 @@ static char *pretty_printing_style = default_pretty_printing_style; static int exclude_other = 1; static char callchain_default_opt[] = "fractal,0.5"; -const char *vmlinux_name; static struct perf_header *header; static u64 sample_type; +struct symbol_conf symbol_conf; + static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) @@ -865,8 +865,7 @@ static int __cmd_report(void) register_perf_file_handler(&file_handler); - ret = mmap_dispatch_perf_file(&header, input_name, vmlinux_name, - !vmlinux_name, force, + ret = mmap_dispatch_perf_file(&header, input_name, force, full_paths, &cwdlen, &cwd); if (ret) return ret; @@ -963,9 +962,10 @@ static const struct option options[] = { "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), - OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), + OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, + "file", "vmlinux pathname"), OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), - OPT_BOOLEAN('m', "modules", &use_modules, + OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, "Show a column with the number of samples"), @@ -1035,7 +1035,8 @@ static void setup_list(struct strlist **list, const char *list_str, int cmd_report(int argc, const char **argv, const char *prefix __used) { - symbol__init(0); + if (symbol__init(&symbol_conf) < 0) + return -1; argc = parse_options(argc, argv, options, report_usage, 0); diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 260f57a72ee..dbf089b12de 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1718,7 +1718,7 @@ static int read_events(void) register_idle_thread(); register_perf_file_handler(&file_handler); - return mmap_dispatch_perf_file(&header, input_name, NULL, false, 0, 0, + return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd); } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index b9a321fd184..a21247543fc 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -79,7 +79,7 @@ static int dump_symtab = 0; static bool hide_kernel_symbols = false; static bool hide_user_symbols = false; static struct winsize winsize; -const char *vmlinux_name; +struct symbol_conf symbol_conf; /* * Source @@ -128,7 +128,7 @@ struct sym_entry { static inline struct symbol *sym_entry__symbol(struct sym_entry *self) { - return ((void *)self) + symbol__priv_size; + return ((void *)self) + symbol_conf.priv_size; } static void get_term_dimensions(struct winsize *ws) @@ -695,7 +695,7 @@ static void print_mapped_keys(void) fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); - if (vmlinux_name) { + if (symbol_conf.vmlinux_name) { fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); fprintf(stdout, "\t[S] stop annotation.\n"); @@ -732,7 +732,7 @@ static int key_mapped(int c) case 'F': case 's': case 'S': - return vmlinux_name ? 1 : 0; + return symbol_conf.vmlinux_name ? 1 : 0; default: break; } @@ -1261,7 +1261,8 @@ static const struct option options[] = { "system-wide collection from all CPUs"), OPT_INTEGER('C', "CPU", &profile_cpu, "CPU to profile on"), - OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), + OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, + "file", "vmlinux pathname"), OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, "hide kernel symbols"), OPT_INTEGER('m', "mmap-pages", &mmap_pages, @@ -1295,7 +1296,7 @@ static const struct option options[] = { int cmd_top(int argc, const char **argv, const char *prefix __used) { - int counter, err; + int counter; page_size = sysconf(_SC_PAGE_SIZE); @@ -1313,15 +1314,16 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) if (!nr_counters) nr_counters = 1; - symbol__init(sizeof(struct sym_entry) + - (nr_counters + 1) * sizeof(unsigned long)); + symbol_conf.priv_size = (sizeof(struct sym_entry) + + (nr_counters + 1) * sizeof(unsigned long)); + if (symbol_conf.vmlinux_name == NULL) + symbol_conf.try_vmlinux_path = true; + if (symbol__init(&symbol_conf) < 0) + return -1; if (delay_secs < 1) delay_secs = 1; - err = kernel_maps__init(vmlinux_name, !vmlinux_name, true); - if (err < 0) - return err; parse_source(sym_filter_entry); /* diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index b71198e5dc1..75972fd073d 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -131,7 +131,7 @@ static int __cmd_trace(void) register_idle_thread(); register_perf_file_handler(&file_handler); - return mmap_dispatch_perf_file(&header, input_name, NULL, false, + return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd); } diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index f318d19b256..b238462b898 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -101,8 +101,6 @@ out: int mmap_dispatch_perf_file(struct perf_header **pheader, const char *input_name, - const char *vmlinux_name, - bool try_vmlinux_path, int force, int full_paths, int *cwdlen, @@ -172,12 +170,6 @@ int mmap_dispatch_perf_file(struct perf_header **pheader, curr_handler->sample_type_check(sample_type) < 0) goto out_delete; - err = -ENOMEM; - if (kernel_maps__init(vmlinux_name, try_vmlinux_path, true) < 0) { - pr_err("failed to setup the kernel maps to resolve symbols\n"); - goto out_delete; - } - if (!full_paths) { if (getcwd(__cwd, sizeof(__cwd)) == NULL) { pr_err("failed to get the current directory\n"); diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h index 3f0d21b3819..ae036ecd762 100644 --- a/tools/perf/util/data_map.h +++ b/tools/perf/util/data_map.h @@ -23,8 +23,6 @@ struct perf_file_handler { void register_perf_file_handler(struct perf_file_handler *handler); int mmap_dispatch_perf_file(struct perf_header **pheader, const char *input_name, - const char *vmlinux_name, - bool try_vmlinux_path, int force, int full_paths, int *cwdlen, diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1332f8ec04a..271a1600e6f 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -253,12 +253,6 @@ static int perf_header__adds_write(struct perf_header *self, int fd) buildid_sec = &feat_sec[idx++]; - /* - * Read the kernel buildid nad the list of loaded modules with - * its build_ids: - */ - kernel_maps__init(NULL, false, true); - /* Write build-ids */ buildid_sec->offset = lseek(fd, 0, SEEK_CUR); err = dsos__write_buildid_table(fd); diff --git a/tools/perf/util/include/asm/bug.h b/tools/perf/util/include/asm/bug.h new file mode 100644 index 00000000000..7fcc6810adc --- /dev/null +++ b/tools/perf/util/include/asm/bug.h @@ -0,0 +1,22 @@ +#ifndef _PERF_ASM_GENERIC_BUG_H +#define _PERF_ASM_GENERIC_BUG_H + +#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0) + +#define WARN(condition, format...) ({ \ + int __ret_warn_on = !!(condition); \ + if (unlikely(__ret_warn_on)) \ + __WARN_printf(format); \ + unlikely(__ret_warn_on); \ +}) + +#define WARN_ONCE(condition, format...) ({ \ + static int __warned; \ + int __ret_warn_once = !!(condition); \ + \ + if (unlikely(__ret_warn_once)) \ + if (WARN(!__warned, format)) \ + __warned = 1; \ + unlikely(__ret_warn_once); \ +}) +#endif diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 44d81d5ae8c..c4ca974b36e 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -6,6 +6,7 @@ #include "debug.h" +#include #include #include #include @@ -37,6 +38,11 @@ unsigned int symbol__priv_size; static int vmlinux_path__nr_entries; static char **vmlinux_path; +static struct symbol_conf symbol_conf__defaults = { + .use_modules = true, + .try_vmlinux_path = true, +}; + static struct rb_root kernel_maps; static void dso__fixup_sym_end(struct dso *self) @@ -1166,7 +1172,9 @@ struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp, if (map) { ip = map->map_ip(map, ip); return map__find_symbol(map, ip, filter); - } + } else + WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps), + "Empty kernel_maps, was symbol__init() called?\n"); return NULL; } @@ -1485,9 +1493,9 @@ size_t dsos__fprintf_buildid(FILE *fp) return ret; } -static int kernel_maps__create_kernel_map(const char *vmlinux_name) +static int kernel_maps__create_kernel_map(const struct symbol_conf *conf) { - struct dso *kernel = dso__new(vmlinux_name ?: "[kernel.kallsyms]"); + struct dso *kernel = dso__new(conf->vmlinux_name ?: "[kernel.kallsyms]"); if (kernel == NULL) return -1; @@ -1577,18 +1585,21 @@ out_fail: return -1; } -int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path, - bool use_modules) +static int kernel_maps__init(const struct symbol_conf *conf) { - if (try_vmlinux_path && vmlinux_path__init() < 0) + const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; + + symbol__priv_size = pconf->priv_size; + + if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) return -1; - if (kernel_maps__create_kernel_map(vmlinux_name) < 0) { + if (kernel_maps__create_kernel_map(pconf) < 0) { vmlinux_path__exit(); return -1; } - if (use_modules && kernel_maps__create_module_maps() < 0) + if (pconf->use_modules && kernel_maps__create_module_maps() < 0) pr_debug("Failed to load list of modules in use, " "continuing...\n"); /* @@ -1598,8 +1609,8 @@ int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path, return 0; } -void symbol__init(unsigned int priv_size) +int symbol__init(struct symbol_conf *conf) { elf_version(EV_CURRENT); - symbol__priv_size = priv_size; + return kernel_maps__init(conf); } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 8c4d026e067..5538691494a 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -49,6 +49,13 @@ struct symbol { char name[0]; }; +struct symbol_conf { + unsigned short priv_size; + bool try_vmlinux_path, + use_modules; + const char *vmlinux_name; +}; + extern unsigned int symbol__priv_size; static inline void *symbol__priv(struct symbol *self) @@ -93,11 +100,9 @@ int sysfs__read_build_id(const char *filename, void *bf, size_t size); bool dsos__read_build_ids(void); int build_id__sprintf(u8 *self, int len, char *bf); -int kernel_maps__init(const char *vmlinux_name, bool try_vmlinux_path, - bool use_modules); size_t kernel_maps__fprintf(FILE *fp); -void symbol__init(unsigned int priv_size); +int symbol__init(struct symbol_conf *conf); extern struct list_head dsos; extern struct map *kernel_map; -- cgit v1.2.3-70-g09d2 From 62daacb51a2bf8480e6f6b3696b03f102fc15eb0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 27 Nov 2009 16:29:22 -0200 Subject: perf tools: Reorganize event processing routines, lotsa dups killed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While implementing event__preprocess_sample, that will do all of the symbol lookup in one convenient function, I noticed that util/process_event.[ch] were not being used at all, then started looking if there were other functions that could be shared and... All those functions really don't need to receive offset + head, the only thing they did was common to all of them, so do it at one place instead. Stats about number of each type of event processed now is done in a central place. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: John Kacur Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1259346563-12568-11-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/Makefile | 2 -- tools/perf/builtin-annotate.c | 63 ++++++++-------------------------- tools/perf/builtin-kmem.c | 33 +++--------------- tools/perf/builtin-report.c | 72 +++++++++++--------------------------- tools/perf/builtin-sched.c | 42 +++-------------------- tools/perf/builtin-top.c | 19 ----------- tools/perf/builtin-trace.c | 40 +++------------------- tools/perf/util/data_map.c | 56 +++++++++++++++++++++++------- tools/perf/util/data_map.h | 2 +- tools/perf/util/event.c | 74 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/event.h | 17 +++++++++ tools/perf/util/hist.c | 7 ---- tools/perf/util/process_event.c | 53 ---------------------------- tools/perf/util/process_event.h | 29 ---------------- tools/perf/util/process_events.c | 64 ---------------------------------- tools/perf/util/process_events.h | 35 ------------------- 16 files changed, 183 insertions(+), 425 deletions(-) delete mode 100644 tools/perf/util/process_event.c delete mode 100644 tools/perf/util/process_event.h delete mode 100644 tools/perf/util/process_events.c delete mode 100644 tools/perf/util/process_events.h (limited to 'tools/perf/util/data_map.c') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index de37d492e10..f1537a94a05 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -369,7 +369,6 @@ LIB_H += util/sort.h LIB_H += util/hist.h LIB_H += util/thread.h LIB_H += util/data_map.h -LIB_H += util/process_events.h LIB_OBJS += util/abspath.o LIB_OBJS += util/alias.o @@ -412,7 +411,6 @@ LIB_OBJS += util/svghelper.o LIB_OBJS += util/sort.o LIB_OBJS += util/hist.o LIB_OBJS += util/data_map.o -LIB_OBJS += util/process_events.o BUILTIN_OBJS += builtin-annotate.o diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 3ebd70b1ef9..7d39bd2b19b 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -19,12 +19,12 @@ #include "perf.h" #include "util/debug.h" +#include "util/event.h" #include "util/parse-options.h" #include "util/parse-events.h" #include "util/thread.h" #include "util/sort.h" #include "util/hist.h" -#include "util/process_events.h" static char const *input_name = "perf.data"; @@ -136,8 +136,7 @@ static int hist_entry__add(struct thread *thread, struct map *map, return 0; } -static int -process_sample_event(event_t *event, unsigned long offset, unsigned long head) +static int process_sample_event(event_t *event) { char level; u64 ip = event->ip.ip; @@ -145,12 +144,8 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) struct symbol *sym = NULL; struct thread *thread = threads__findnew(event->ip.pid); - dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->header.misc, - event->ip.pid, - (void *)(long)ip); + dump_printf("(IP, %d): %d: %p\n", event->header.misc, + event->ip.pid, (void *)(long)ip); if (thread == NULL) { fprintf(stderr, "problem processing %d event, skipping it.\n", @@ -198,46 +193,24 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) "skipping event\n"); return -1; } - total++; return 0; } -static int -process_comm_event(event_t *event, unsigned long offset, unsigned long head) +static int event__process(event_t *self) { - struct thread *thread = threads__findnew(event->comm.pid); - - dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->comm.comm, event->comm.pid); - - if (thread == NULL || - thread__set_comm(thread, event->comm.comm)) { - dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); - return -1; - } - total_comm++; - - return 0; -} - -static int -process_event(event_t *event, unsigned long offset, unsigned long head) -{ - switch (event->header.type) { + switch (self->header.type) { case PERF_RECORD_SAMPLE: - return process_sample_event(event, offset, head); + return process_sample_event(self); case PERF_RECORD_MMAP: - return process_mmap_event(event, offset, head); + return event__process_mmap(self); case PERF_RECORD_COMM: - return process_comm_event(event, offset, head); + return event__process_comm(self); case PERF_RECORD_FORK: - return process_task_event(event, offset, head); + return event__process_task(self); /* * We dont process them right now but they are fine: */ @@ -621,15 +594,12 @@ more: (void *)(long)event->header.size, event->header.type); - if (!size || process_event(event, offset, head) < 0) { + if (!size || event__process(event) < 0) { dump_printf("%p [%p]: skipping unknown header type: %d\n", (void *)(offset + head), (void *)(long)(event->header.size), event->header.type); - - total_unknown++; - /* * assume we lost track of the stream, check alignment, and * increment a single u64 in the hope to catch on again 'soon'. @@ -649,14 +619,11 @@ more: rc = EXIT_SUCCESS; close(input); - dump_printf(" IP events: %10ld\n", total); - dump_printf(" mmap events: %10ld\n", total_mmap); - dump_printf(" comm events: %10ld\n", total_comm); - dump_printf(" fork events: %10ld\n", total_fork); - dump_printf(" unknown events: %10ld\n", total_unknown); - if (dump_trace) + if (dump_trace) { + event__print_totals(); return 0; + } if (verbose > 3) threads__fprintf(stdout); @@ -665,7 +632,7 @@ more: dsos__fprintf(stdout); collapse__resort(); - output__resort(total); + output__resort(event__total[0]); find_annotations(); diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 35722fafc4d..e7294c8fc62 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -33,9 +33,6 @@ static bool raw_ip; static char default_sort_order[] = "frag,hit,bytes"; -static char *cwd; -static int cwdlen; - static int *cpunode_map; static int max_cpu_num; @@ -126,25 +123,6 @@ static void setup_cpunode_map(void) } } -static int -process_comm_event(event_t *event, unsigned long offset, unsigned long head) -{ - struct thread *thread = threads__findnew(event->comm.pid); - - dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->comm.comm, event->comm.pid); - - if (thread == NULL || - thread__set_comm(thread, event->comm.comm)) { - dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); - return -1; - } - - return 0; -} - static void insert_alloc_stat(unsigned long call_site, unsigned long ptr, int bytes_req, int bytes_alloc, int cpu) { @@ -340,8 +318,7 @@ process_raw_event(event_t *raw_event __used, void *more_data, } } -static int -process_sample_event(event_t *event, unsigned long offset, unsigned long head) +static int process_sample_event(event_t *event) { u64 ip = event->ip.ip; u64 timestamp = -1; @@ -366,9 +343,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) more_data += sizeof(u64); } - dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", - (void *)(offset + head), - (void *)(long)(event->header.size), + dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", event->header.misc, event->ip.pid, event->ip.tid, (void *)(long)ip, @@ -403,7 +378,7 @@ static int sample_type_check(u64 type) static struct perf_file_handler file_handler = { .process_sample_event = process_sample_event, - .process_comm_event = process_comm_event, + .process_comm_event = event__process_comm, .sample_type_check = sample_type_check, }; @@ -413,7 +388,7 @@ static int read_events(void) register_perf_file_handler(&file_handler); return mmap_dispatch_perf_file(&header, input_name, 0, 0, - &cwdlen, &cwd); + &event__cwdlen, &event__cwd); } static double fragmentation(unsigned long n_req, unsigned long n_alloc) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 9bd20c2ee3d..01ef35cac5f 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -30,7 +30,6 @@ #include "util/thread.h" #include "util/sort.h" #include "util/hist.h" -#include "util/process_events.h" static char const *input_name = "perf.data"; @@ -655,8 +654,7 @@ static int validate_chain(struct ip_callchain *chain, event_t *event) return 0; } -static int -process_sample_event(event_t *event, unsigned long offset, unsigned long head) +static int process_sample_event(event_t *event) { char level; struct symbol *sym = NULL; @@ -673,9 +671,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) more_data += sizeof(u64); } - dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", - (void *)(offset + head), - (void *)(long)(event->header.size), + dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", event->header.misc, event->ip.pid, event->ip.tid, (void *)(long)ip, @@ -743,47 +739,27 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) return -1; } - total += period; + event__stats.total += period; return 0; } -static int -process_comm_event(event_t *event, unsigned long offset, unsigned long head) +static int process_comm_event(event_t *event) { struct thread *thread = threads__findnew(event->comm.pid); - dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->comm.comm, event->comm.pid); + dump_printf(": %s:%d\n", event->comm.comm, event->comm.pid); if (thread == NULL || thread__set_comm_adjust(thread, event->comm.comm)) { dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); return -1; } - total_comm++; - - return 0; -} - -static int -process_lost_event(event_t *event, unsigned long offset, unsigned long head) -{ - dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->lost.id, - event->lost.lost); - - total_lost += event->lost.lost; return 0; } -static int -process_read_event(event_t *event, unsigned long offset, unsigned long head) +static int process_read_event(event_t *event) { struct perf_event_attr *attr; @@ -799,14 +775,9 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head) event->read.value); } - dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->read.pid, - event->read.tid, - attr ? __event_name(attr->type, attr->config) - : "FAIL", - event->read.value); + dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid, + attr ? __event_name(attr->type, attr->config) : "FAIL", + event->read.value); return 0; } @@ -842,11 +813,11 @@ static int sample_type_check(u64 type) static struct perf_file_handler file_handler = { .process_sample_event = process_sample_event, - .process_mmap_event = process_mmap_event, + .process_mmap_event = event__process_mmap, .process_comm_event = process_comm_event, - .process_exit_event = process_task_event, - .process_fork_event = process_task_event, - .process_lost_event = process_lost_event, + .process_exit_event = event__process_task, + .process_fork_event = event__process_task, + .process_lost_event = event__process_lost, .process_read_event = process_read_event, .sample_type_check = sample_type_check, }; @@ -866,19 +837,14 @@ static int __cmd_report(void) register_perf_file_handler(&file_handler); ret = mmap_dispatch_perf_file(&header, input_name, force, - full_paths, &cwdlen, &cwd); + full_paths, &event__cwdlen, &event__cwd); if (ret) return ret; - dump_printf(" IP events: %10ld\n", total); - dump_printf(" mmap events: %10ld\n", total_mmap); - dump_printf(" comm events: %10ld\n", total_comm); - dump_printf(" fork events: %10ld\n", total_fork); - dump_printf(" lost events: %10ld\n", total_lost); - dump_printf(" unknown events: %10ld\n", file_handler.total_unknown); - - if (dump_trace) + if (dump_trace) { + event__print_totals(); return 0; + } if (verbose > 3) threads__fprintf(stdout); @@ -887,8 +853,8 @@ static int __cmd_report(void) dsos__fprintf(stdout); collapse__resort(); - output__resort(total); - output__fprintf(stdout, total); + output__resort(event__stats.total); + output__fprintf(stdout, event__stats.total); if (show_threads) perf_read_values_destroy(&show_threads_values); diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 19eb708a706..26b782f26ee 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -22,8 +22,6 @@ static char const *input_name = "perf.data"; -static unsigned long total_comm = 0; - static struct perf_header *header; static u64 sample_type; @@ -32,9 +30,6 @@ static char *sort_order = default_sort_order; static int profile_cpu = -1; -static char *cwd; -static int cwdlen; - #define PR_SET_NAME 15 /* Set process name */ #define MAX_CPUS 4096 @@ -633,27 +628,6 @@ static void test_calibrations(void) printf("the sleep test took %Ld nsecs\n", T1-T0); } -static int -process_comm_event(event_t *event, unsigned long offset, unsigned long head) -{ - struct thread *thread = threads__findnew(event->comm.tid); - - dump_printf("%p [%p]: perf_event_comm: %s:%d\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->comm.comm, event->comm.pid); - - if (thread == NULL || - thread__set_comm(thread, event->comm.comm)) { - dump_printf("problem processing perf_event_comm, skipping event.\n"); - return -1; - } - total_comm++; - - return 0; -} - - struct raw_event_sample { u32 size; char data[0]; @@ -1622,8 +1596,7 @@ process_raw_event(event_t *raw_event __used, void *more_data, process_sched_migrate_task_event(raw, event, cpu, timestamp, thread); } -static int -process_sample_event(event_t *event, unsigned long offset, unsigned long head) +static int process_sample_event(event_t *event) { struct thread *thread; u64 ip = event->ip.ip; @@ -1653,9 +1626,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) more_data += sizeof(u64); } - dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", - (void *)(offset + head), - (void *)(long)(event->header.size), + dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", event->header.misc, event->ip.pid, event->ip.tid, (void *)(long)ip, @@ -1677,10 +1648,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) return 0; } -static int -process_lost_event(event_t *event __used, - unsigned long offset __used, - unsigned long head __used) +static int process_lost_event(event_t *event __used) { nr_lost_chunks++; nr_lost_events += event->lost.lost; @@ -1704,7 +1672,7 @@ static int sample_type_check(u64 type) static struct perf_file_handler file_handler = { .process_sample_event = process_sample_event, - .process_comm_event = process_comm_event, + .process_comm_event = event__process_comm, .process_lost_event = process_lost_event, .sample_type_check = sample_type_check, }; @@ -1715,7 +1683,7 @@ static int read_events(void) register_perf_file_handler(&file_handler); return mmap_dispatch_perf_file(&header, input_name, 0, 0, - &cwdlen, &cwd); + &event__cwdlen, &event__cwd); } static void print_bad_events(void) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index bf6730c7603..7a3c0c7aad3 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -991,25 +991,6 @@ static void event__process_sample(const event_t *self, int counter) } } -static void event__process_mmap(event_t *self) -{ - struct thread *thread = threads__findnew(self->mmap.pid); - - if (thread != NULL) { - struct map *map = map__new(&self->mmap, MAP__FUNCTION, NULL, 0); - if (map != NULL) - thread__insert_map(thread, map); - } -} - -static void event__process_comm(event_t *self) -{ - struct thread *thread = threads__findnew(self->comm.pid); - - if (thread != NULL) - thread__set_comm(thread, self->comm.comm); -} - static int event__process(event_t *event) { switch (event->header.type) { diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 75972fd073d..a7750256c40 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -16,38 +16,10 @@ static char const *input_name = "perf.data"; -static unsigned long total = 0; -static unsigned long total_comm = 0; - static struct perf_header *header; static u64 sample_type; -static char *cwd; -static int cwdlen; - - -static int -process_comm_event(event_t *event, unsigned long offset, unsigned long head) -{ - struct thread *thread = threads__findnew(event->comm.pid); - - dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->comm.comm, event->comm.pid); - - if (thread == NULL || - thread__set_comm(thread, event->comm.comm)) { - dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); - return -1; - } - total_comm++; - - return 0; -} - -static int -process_sample_event(event_t *event, unsigned long offset, unsigned long head) +static int process_sample_event(event_t *event) { u64 ip = event->ip.ip; u64 timestamp = -1; @@ -72,9 +44,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) more_data += sizeof(u64); } - dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", - (void *)(offset + head), - (void *)(long)(event->header.size), + dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", event->header.misc, event->ip.pid, event->ip.tid, (void *)(long)ip, @@ -101,7 +71,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) */ print_event(cpu, raw->data, raw->size, timestamp, thread->comm); } - total += period; + event__stats.total += period; return 0; } @@ -122,7 +92,7 @@ static int sample_type_check(u64 type) static struct perf_file_handler file_handler = { .process_sample_event = process_sample_event, - .process_comm_event = process_comm_event, + .process_comm_event = event__process_comm, .sample_type_check = sample_type_check, }; @@ -132,7 +102,7 @@ static int __cmd_trace(void) register_perf_file_handler(&file_handler); return mmap_dispatch_perf_file(&header, input_name, - 0, 0, &cwdlen, &cwd); + 0, 0, &event__cwdlen, &event__cwd); } static const char * const annotate_usage[] = { diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c index b238462b898..ca0bedf637c 100644 --- a/tools/perf/util/data_map.c +++ b/tools/perf/util/data_map.c @@ -8,11 +8,9 @@ static struct perf_file_handler *curr_handler; static unsigned long mmap_window = 32; static char __cwd[PATH_MAX]; -static int -process_event_stub(event_t *event __used, - unsigned long offset __used, - unsigned long head __used) +static int process_event_stub(event_t *event __used) { + dump_printf(": unhandled!\n"); return 0; } @@ -40,30 +38,62 @@ void register_perf_file_handler(struct perf_file_handler *handler) curr_handler = handler; } +static const char *event__name[] = { + [0] = "TOTAL", + [PERF_RECORD_MMAP] = "MMAP", + [PERF_RECORD_LOST] = "LOST", + [PERF_RECORD_COMM] = "COMM", + [PERF_RECORD_EXIT] = "EXIT", + [PERF_RECORD_THROTTLE] = "THROTTLE", + [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE", + [PERF_RECORD_FORK] = "FORK", + [PERF_RECORD_READ] = "READ", + [PERF_RECORD_SAMPLE] = "SAMPLE", +}; + +unsigned long event__total[PERF_RECORD_MAX]; + +void event__print_totals(void) +{ + int i; + for (i = 0; i < PERF_RECORD_MAX; ++i) + pr_info("%10s events: %10ld\n", + event__name[i], event__total[i]); +} + static int process_event(event_t *event, unsigned long offset, unsigned long head) { trace_event(event); + if (event->header.type < PERF_RECORD_MAX) { + dump_printf("%p [%p]: PERF_RECORD_%s", + (void *)(offset + head), + (void *)(long)(event->header.size), + event__name[event->header.type]); + ++event__total[0]; + ++event__total[event->header.type]; + } + switch (event->header.type) { case PERF_RECORD_SAMPLE: - return curr_handler->process_sample_event(event, offset, head); + return curr_handler->process_sample_event(event); case PERF_RECORD_MMAP: - return curr_handler->process_mmap_event(event, offset, head); + return curr_handler->process_mmap_event(event); case PERF_RECORD_COMM: - return curr_handler->process_comm_event(event, offset, head); + return curr_handler->process_comm_event(event); case PERF_RECORD_FORK: - return curr_handler->process_fork_event(event, offset, head); + return curr_handler->process_fork_event(event); case PERF_RECORD_EXIT: - return curr_handler->process_exit_event(event, offset, head); + return curr_handler->process_exit_event(event); case PERF_RECORD_LOST: - return curr_handler->process_lost_event(event, offset, head); + return curr_handler->process_lost_event(event); case PERF_RECORD_READ: - return curr_handler->process_read_event(event, offset, head); + return curr_handler->process_read_event(event); case PERF_RECORD_THROTTLE: - return curr_handler->process_throttle_event(event, offset, head); + return curr_handler->process_throttle_event(event); case PERF_RECORD_UNTHROTTLE: - return curr_handler->process_unthrottle_event(event, offset, head); + return curr_handler->process_unthrottle_event(event); default: curr_handler->total_unknown++; return -1; diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h index ae036ecd762..3180ff7e363 100644 --- a/tools/perf/util/data_map.h +++ b/tools/perf/util/data_map.h @@ -4,7 +4,7 @@ #include "event.h" #include "header.h" -typedef int (*event_type_handler_t)(event_t *, unsigned long, unsigned long); +typedef int (*event_type_handler_t)(event_t *); struct perf_file_handler { event_type_handler_t process_sample_event; diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 1dae7e3b400..70b4aa03b47 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -2,6 +2,7 @@ #include "event.h" #include "debug.h" #include "string.h" +#include "thread.h" static pid_t event__synthesize_comm(pid_t pid, int full, int (*process)(event_t *event)) @@ -175,3 +176,76 @@ void event__synthesize_threads(int (*process)(event_t *event)) closedir(proc); } + +char *event__cwd; +int event__cwdlen; + +struct events_stats event__stats; + +int event__process_comm(event_t *self) +{ + struct thread *thread = threads__findnew(self->comm.pid); + + dump_printf("PERF_RECORD_COMM: %s:%d\n", + self->comm.comm, self->comm.pid); + + if (thread == NULL || thread__set_comm(thread, self->comm.comm)) { + dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); + return -1; + } + + return 0; +} + +int event__process_lost(event_t *self) +{ + dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); + event__stats.lost += self->lost.lost; + return 0; +} + +int event__process_mmap(event_t *self) +{ + struct thread *thread = threads__findnew(self->mmap.pid); + struct map *map = map__new(&self->mmap, MAP__FUNCTION, + event__cwd, event__cwdlen); + + dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", + self->mmap.pid, self->mmap.tid, + (void *)(long)self->mmap.start, + (void *)(long)self->mmap.len, + (void *)(long)self->mmap.pgoff, + self->mmap.filename); + + if (thread == NULL || map == NULL) + dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); + else + thread__insert_map(thread, map); + + return 0; +} + +int event__process_task(event_t *self) +{ + struct thread *thread = threads__findnew(self->fork.pid); + struct thread *parent = threads__findnew(self->fork.ppid); + + dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, + self->fork.ppid, self->fork.ptid); + /* + * A thread clone will have the same PID for both parent and child. + */ + if (thread == parent) + return 0; + + if (self->header.type == PERF_RECORD_EXIT) + return 0; + + if (thread == NULL || parent == NULL || + thread__fork(thread, parent) < 0) { + dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); + return -1; + } + + return 0; +} diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 3ae3c964c90..13c12c75f97 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -80,6 +80,13 @@ typedef union event_union { struct sample_event sample; } event_t; +struct events_stats { + unsigned long total; + unsigned long lost; +}; + +void event__print_totals(void); + enum map_type { MAP__FUNCTION = 0, @@ -135,4 +142,14 @@ void map__fixup_end(struct map *self); int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); void event__synthesize_threads(int (*process)(event_t *event)); +extern char *event__cwd; +extern int event__cwdlen; +extern struct events_stats event__stats; +extern unsigned long event__total[PERF_RECORD_MAX]; + +int event__process_comm(event_t *self); +int event__process_lost(event_t *self); +int event__process_mmap(event_t *self); +int event__process_task(event_t *self); + #endif /* __PERF_RECORD_H */ diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 7393a02fd8d..f26cd9ba00f 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -10,13 +10,6 @@ struct callchain_param callchain_param = { .min_percent = 0.5 }; -unsigned long total; -unsigned long total_mmap; -unsigned long total_comm; -unsigned long total_fork; -unsigned long total_unknown; -unsigned long total_lost; - /* * histogram, sorted on item, collects counts */ diff --git a/tools/perf/util/process_event.c b/tools/perf/util/process_event.c deleted file mode 100644 index a970789581a..00000000000 --- a/tools/perf/util/process_event.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "process_event.h" - -char *cwd; -int cwdlen; - -int -process_mmap_event(event_t *event, unsigned long offset, unsigned long head) -{ - struct map *map = map__new(&event->mmap, cwd, cwdlen); - struct thread *thread = threads__findnew(event->mmap.pid); - - dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->mmap.pid, - event->mmap.tid, - (void *)(long)event->mmap.start, - (void *)(long)event->mmap.len, - (void *)(long)event->mmap.pgoff, - event->mmap.filename); - - if (thread == NULL || map == NULL) { - dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); - return 0; - } - - thread__insert_map(thread, map); - total_mmap++; - - return 0; - -} - -int -process_comm_event(event_t *event, unsigned long offset, unsigned long head) -{ - struct thread *thread = threads__findnew(event->comm.pid); - - dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->comm.comm, event->comm.pid); - - if (thread == NULL || - thread__set_comm_adjust(thread, event->comm.comm)) { - dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); - return -1; - } - total_comm++; - - return 0; -} - diff --git a/tools/perf/util/process_event.h b/tools/perf/util/process_event.h deleted file mode 100644 index 6f68c69736c..00000000000 --- a/tools/perf/util/process_event.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __PROCESS_EVENT_H -#define __PROCESS_EVENT_H - -#include "../builtin.h" -#include "util.h" - -#include "color.h" -#include -#include "cache.h" -#include -#include "symbol.h" -#include "string.h" - -#include "../perf.h" -#include "debug.h" - -#include "parse-options.h" -#include "parse-events.h" - -#include "thread.h" -#include "sort.h" -#include "hist.h" - -extern char *cwd; -extern int cwdlen; -extern int process_mmap_event(event_t *, unsigned long, unsigned long); -extern int process_comm_event(event_t *, unsigned long , unsigned long); - -#endif /* __PROCESS_H */ diff --git a/tools/perf/util/process_events.c b/tools/perf/util/process_events.c deleted file mode 100644 index 53778684641..00000000000 --- a/tools/perf/util/process_events.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "process_events.h" - -char *cwd; -int cwdlen; - -int -process_mmap_event(event_t *event, unsigned long offset, unsigned long head) -{ - struct map *map = map__new(&event->mmap, MAP__FUNCTION, cwd, cwdlen); - struct thread *thread = threads__findnew(event->mmap.pid); - - dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->mmap.pid, - event->mmap.tid, - (void *)(long)event->mmap.start, - (void *)(long)event->mmap.len, - (void *)(long)event->mmap.pgoff, - event->mmap.filename); - - if (thread == NULL || map == NULL) { - dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); - return 0; - } - - thread__insert_map(thread, map); - total_mmap++; - - return 0; -} - -int -process_task_event(event_t *event, unsigned long offset, unsigned long head) -{ - struct thread *thread = threads__findnew(event->fork.pid); - struct thread *parent = threads__findnew(event->fork.ppid); - - dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT", - event->fork.pid, event->fork.tid, - event->fork.ppid, event->fork.ptid); - - /* - * A thread clone will have the same PID for both - * parent and child. - */ - if (thread == parent) - return 0; - - if (event->header.type == PERF_RECORD_EXIT) - return 0; - - if (!thread || !parent || thread__fork(thread, parent)) { - dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); - return -1; - } - total_fork++; - - return 0; -} - diff --git a/tools/perf/util/process_events.h b/tools/perf/util/process_events.h deleted file mode 100644 index 73d092f8328..00000000000 --- a/tools/perf/util/process_events.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __PROCESS_EVENTS_H -#define __PROCESS_EVENTS_H - -#include "../builtin.h" - -#include "util.h" -#include "color.h" -#include -#include "cache.h" -#include -#include "symbol.h" -#include "string.h" -#include "callchain.h" -#include "strlist.h" -#include "values.h" - -#include "../perf.h" -#include "debug.h" -#include "header.h" - -#include "parse-options.h" -#include "parse-events.h" - -#include "data_map.h" -#include "thread.h" -#include "sort.h" -#include "hist.h" - -extern char *cwd; -extern int cwdlen; - -extern int process_mmap_event(event_t *, unsigned long , unsigned long); -extern int process_task_event(event_t *, unsigned long, unsigned long); - -#endif /* __PROCESS_EVENTS_H */ -- cgit v1.2.3-70-g09d2