From 8b40f521cf1c9750eab0c04da9075e7484675e9c Mon Sep 17 00:00:00 2001 From: John Kacur Date: Thu, 24 Sep 2009 18:02:18 +0200 Subject: perf tools: Protect header files with a consistent style There was a colorful mix of header guards - standardize them. Signed-off-by: John Kacur LKML-Reference: Signed-off-by: Ingo Molnar --- tools/perf/util/thread.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tools/perf/util/thread.h') diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 32aea3c1c2a..693ed1ea10b 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -1,3 +1,6 @@ +#ifndef __PERF_THREAD_H +#define __PERF_THREAD_H + #include #include #include @@ -20,3 +23,5 @@ void thread__insert_map(struct thread *self, struct map *map); int thread__fork(struct thread *self, struct thread *parent); struct map *thread__find_map(struct thread *self, u64 ip); size_t threads__fprintf(FILE *fp, struct rb_root *threads); + +#endif /* __PERF_THREAD_H */ -- cgit v1.2.3-70-g09d2 From 1b46cddfccfec4cc67b187fb53d78198de6a057c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 Sep 2009 14:48:46 -0300 Subject: perf tools: Use rb_tree for maps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Threads can have many and kernel modules will be represented as a tree of maps as well. Ah, and for a perf.data with 146607 samples: Before: [root@doppio ~]# perf stat -r 5 perf report > /dev/null Performance counter stats for 'perf report' (5 runs): 699.823680 task-clock-msecs # 0.991 CPUs ( +- 0.454% ) 74 context-switches # 0.000 M/sec ( +- 1.709% ) 2 CPU-migrations # 0.000 M/sec ( +- 17.008% ) 23114 page-faults # 0.033 M/sec ( +- 0.000% ) 1381257019 cycles # 1973.721 M/sec ( +- 0.290% ) 1456894438 instructions # 1.055 IPC ( +- 0.007% ) 18779818 cache-references # 26.835 M/sec ( +- 0.380% ) 641799 cache-misses # 0.917 M/sec ( +- 1.200% ) 0.705972729 seconds time elapsed ( +- 0.501% ) [root@doppio ~]# After Performance counter stats for 'perf report' (5 runs): 691.261451 task-clock-msecs # 0.993 CPUs ( +- 0.307% ) 72 context-switches # 0.000 M/sec ( +- 0.829% ) 6 CPU-migrations # 0.000 M/sec ( +- 18.409% ) 23127 page-faults # 0.033 M/sec ( +- 0.000% ) 1366395876 cycles # 1976.670 M/sec ( +- 0.153% ) 1443136016 instructions # 1.056 IPC ( +- 0.012% ) 17956402 cache-references # 25.976 M/sec ( +- 0.325% ) 661924 cache-misses # 0.958 M/sec ( +- 1.335% ) 0.696127275 seconds time elapsed ( +- 0.377% ) I.e. we see some speedup too. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Peter Zijlstra Cc: Mike Galbraith Cc: "H. Peter Anvin" LKML-Reference: <20090928174846.GA3361@ghostprotocols.net> Signed-off-by: Ingo Molnar --- tools/perf/Makefile | 1 + tools/perf/util/event.h | 4 +- tools/perf/util/thread.c | 129 ++++++++++++++++++++++++++++++----------------- tools/perf/util/thread.h | 12 +++-- 4 files changed, 95 insertions(+), 51 deletions(-) (limited to 'tools/perf/util/thread.h') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 3a99a9fda64..055290a5b83 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -341,6 +341,7 @@ LIB_H += util/color.h LIB_H += util/values.h LIB_H += util/sort.h LIB_H += util/hist.h +LIB_H += util/thread.h LIB_OBJS += util/abspath.o LIB_OBJS += util/alias.o diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index c31a5da6458..4c69eb55380 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -3,7 +3,7 @@ #include "../perf.h" #include "util.h" -#include +#include enum { SHOW_KERNEL = 1, @@ -79,7 +79,7 @@ typedef union event_union { } event_t; struct map { - struct list_head node; + struct rb_node rb_node; u64 start; u64 end; u64 pgoff; diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 45efb5db0d1..9d0945cc66d 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -15,7 +15,7 @@ static struct thread *thread__new(pid_t pid) self->comm = malloc(32); if (self->comm) snprintf(self->comm, 32, ":%d", self->pid); - INIT_LIST_HEAD(&self->maps); + self->maps = RB_ROOT; } return self; @@ -31,11 +31,13 @@ int thread__set_comm(struct thread *self, const char *comm) static size_t thread__fprintf(struct thread *self, FILE *fp) { - struct map *pos; + struct rb_node *nd; size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); - list_for_each_entry(pos, &self->maps, node) + for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { + struct map *pos = rb_entry(nd, struct map, rb_node); ret += map__fprintf(pos, fp); + } return ret; } @@ -93,42 +95,90 @@ register_idle_thread(struct rb_root *threads, struct thread **last_match) return thread; } -void thread__insert_map(struct thread *self, struct map *map) +static void thread__remove_overlappings(struct thread *self, struct map *map) { - struct map *pos, *tmp; - - list_for_each_entry_safe(pos, tmp, &self->maps, node) { - if (map__overlap(pos, map)) { - if (verbose >= 2) { - printf("overlapping maps:\n"); - map__fprintf(map, stdout); - map__fprintf(pos, stdout); - } - - if (map->start <= pos->start && map->end > pos->start) - pos->start = map->end; - - if (map->end >= pos->end && map->start < pos->end) - pos->end = map->start; - - if (verbose >= 2) { - printf("after collision:\n"); - map__fprintf(pos, stdout); - } - - if (pos->start >= pos->end) { - list_del_init(&pos->node); - free(pos); - } + struct rb_node *next = rb_first(&self->maps); + + while (next) { + struct map *pos = rb_entry(next, struct map, rb_node); + next = rb_next(&pos->rb_node); + + if (!map__overlap(pos, map)) + continue; + + if (verbose >= 2) { + printf("overlapping maps:\n"); + map__fprintf(map, stdout); + map__fprintf(pos, stdout); + } + + if (map->start <= pos->start && map->end > pos->start) + pos->start = map->end; + + if (map->end >= pos->end && map->start < pos->end) + pos->end = map->start; + + if (verbose >= 2) { + printf("after collision:\n"); + map__fprintf(pos, stdout); + } + + if (pos->start >= pos->end) { + rb_erase(&pos->rb_node, &self->maps); + free(pos); } } +} + +void maps__insert(struct rb_root *maps, struct map *map) +{ + struct rb_node **p = &maps->rb_node; + struct rb_node *parent = NULL; + const u64 ip = map->start; + struct map *m; + + while (*p != NULL) { + parent = *p; + m = rb_entry(parent, struct map, rb_node); + if (ip < m->start) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&map->rb_node, parent, p); + rb_insert_color(&map->rb_node, maps); +} + +struct map *maps__find(struct rb_root *maps, u64 ip) +{ + struct rb_node **p = &maps->rb_node; + struct rb_node *parent = NULL; + struct map *m; + + while (*p != NULL) { + parent = *p; + m = rb_entry(parent, struct map, rb_node); + if (ip < m->start) + p = &(*p)->rb_left; + else if (ip > m->end) + p = &(*p)->rb_right; + else + return m; + } + + return NULL; +} - list_add_tail(&map->node, &self->maps); +void thread__insert_map(struct thread *self, struct map *map) +{ + thread__remove_overlappings(self, map); + maps__insert(&self->maps, map); } int thread__fork(struct thread *self, struct thread *parent) { - struct map *map; + struct rb_node *nd; if (self->comm) free(self->comm); @@ -136,7 +186,8 @@ int thread__fork(struct thread *self, struct thread *parent) if (!self->comm) return -ENOMEM; - list_for_each_entry(map, &parent->maps, node) { + for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) { + struct map *map = rb_entry(nd, struct map, rb_node); struct map *new = map__clone(map); if (!new) return -ENOMEM; @@ -146,20 +197,6 @@ int thread__fork(struct thread *self, struct thread *parent) return 0; } -struct map *thread__find_map(struct thread *self, u64 ip) -{ - struct map *pos; - - if (self == NULL) - return NULL; - - list_for_each_entry(pos, &self->maps, node) - if (ip >= pos->start && ip <= pos->end) - return pos; - - return NULL; -} - size_t threads__fprintf(FILE *fp, struct rb_root *threads) { size_t ret = 0; diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 693ed1ea10b..bbb37c1a52e 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -2,13 +2,12 @@ #define __PERF_THREAD_H #include -#include #include #include "symbol.h" struct thread { struct rb_node rb_node; - struct list_head maps; + struct rb_root maps; pid_t pid; char shortname[3]; char *comm; @@ -21,7 +20,14 @@ struct thread * register_idle_thread(struct rb_root *threads, struct thread **last_match); void thread__insert_map(struct thread *self, struct map *map); int thread__fork(struct thread *self, struct thread *parent); -struct map *thread__find_map(struct thread *self, u64 ip); size_t threads__fprintf(FILE *fp, struct rb_root *threads); +void maps__insert(struct rb_root *maps, struct map *map); +struct map *maps__find(struct rb_root *maps, u64 ip); + +static inline struct map *thread__find_map(struct thread *self, u64 ip) +{ + return self ? maps__find(&self->maps, ip) : NULL; +} + #endif /* __PERF_THREAD_H */ -- cgit v1.2.3-70-g09d2 From 439d473b4777de510e1322168ac6f2f377ecd5bc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 2 Oct 2009 03:29:58 -0300 Subject: perf tools: Rewrite and improve support for kernel modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Representing modules as struct map entries, backed by a DSO, etc, using /proc/modules to find where the module is loaded. DSOs now can have a short and long name, so that in verbose mode we can show exactly which .ko or vmlinux image was used. As kernel modules now are a DSO separate from the kernel, we can ask for just the hits for a particular set of kernel modules, just like we can do with shared libraries: [root@doppio linux-2.6-tip]# perf report -n --vmlinux /home/acme/git/build/tip-recvmmsg/vmlinux --modules --dsos \[drm\] | head -15 84.58% 13266 Xorg [k] drm_clflush_pages 4.02% 630 Xorg [k] trace_kmalloc.clone.0 3.95% 619 Xorg [k] drm_ioctl 2.07% 324 Xorg [k] drm_addbufs 1.68% 263 Xorg [k] drm_gem_close_ioctl 0.77% 120 Xorg [k] drm_setmaster_ioctl 0.70% 110 Xorg [k] drm_lastclose 0.68% 106 Xorg [k] drm_open 0.54% 85 Xorg [k] drm_mm_search_free [root@doppio linux-2.6-tip]# Specifying --dsos /lib/modules/2.6.31-tip/kernel/drivers/gpu/drm/drm.ko would have the same effect. Allowing specifying just 'drm.ko' is left for another patch. Processing kallsyms so that per kernel module struct map are instantiated was also left for another patch. That will allow removing the module name from each of its symbols. struct symbol was reduced by removing the ->module backpointer and moving it (well now the map) to struct symbol_entry in perf top, that is its only user right now. The total linecount went down by ~500 lines. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: "H. Peter Anvin" Cc: Peter Zijlstra Cc: Mike Galbraith Cc: Avi Kivity Signed-off-by: Ingo Molnar --- tools/perf/Makefile | 2 - tools/perf/builtin-annotate.c | 73 +++--- tools/perf/builtin-report.c | 79 +++--- tools/perf/builtin-top.c | 74 ++---- tools/perf/util/event.h | 6 +- tools/perf/util/module.c | 545 ------------------------------------------ tools/perf/util/module.h | 53 ---- tools/perf/util/sort.c | 38 +-- tools/perf/util/sort.h | 7 +- tools/perf/util/symbol.c | 447 +++++++++++++++++++++++----------- tools/perf/util/symbol.h | 20 +- tools/perf/util/thread.c | 34 +-- tools/perf/util/thread.h | 4 + 13 files changed, 453 insertions(+), 929 deletions(-) delete mode 100644 tools/perf/util/module.c delete mode 100644 tools/perf/util/module.h (limited to 'tools/perf/util/thread.h') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 055290a5b83..8e7509f2d88 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -336,7 +336,6 @@ LIB_H += util/strlist.h LIB_H += util/run-command.h LIB_H += util/sigchain.h LIB_H += util/symbol.h -LIB_H += util/module.h LIB_H += util/color.h LIB_H += util/values.h LIB_H += util/sort.h @@ -364,7 +363,6 @@ LIB_OBJS += util/usage.o LIB_OBJS += util/wrapper.o LIB_OBJS += util/sigchain.o LIB_OBJS += util/symbol.o -LIB_OBJS += util/module.o LIB_OBJS += util/color.o LIB_OBJS += util/pager.o LIB_OBJS += util/header.o diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index df516dce954..7d5a3b1bcda 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -63,6 +63,7 @@ static void hist_hit(struct hist_entry *he, u64 ip) return; sym_size = sym->end - sym->start; + ip = he->map->map_ip(he->map, ip); offset = ip - sym->start; if (offset >= sym_size) @@ -80,7 +81,7 @@ static void hist_hit(struct hist_entry *he, u64 ip) } static int -hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, +hist_entry__add(struct thread *thread, struct map *map, struct symbol *sym, u64 ip, char level) { struct rb_node **p = &hist.rb_node; @@ -89,7 +90,6 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, struct hist_entry entry = { .thread = thread, .map = map, - .dso = dso, .sym = sym, .ip = ip, .level = level, @@ -130,10 +130,10 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) { char level; int show = 0; - struct dso *dso = NULL; struct thread *thread; u64 ip = event->ip.ip; struct map *map = NULL; + struct symbol *sym = NULL; thread = threads__findnew(event->ip.pid, &threads, &last_match); @@ -155,32 +155,35 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) if (event->header.misc & PERF_RECORD_MISC_KERNEL) { show = SHOW_KERNEL; level = 'k'; - - dso = kernel_dso; - - dump_printf(" ...... dso: %s\n", dso->name); - + sym = kernel_maps__find_symbol(ip, &map); + dump_printf(" ...... dso: %s\n", + map ? map->dso->long_name : ""); } else if (event->header.misc & PERF_RECORD_MISC_USER) { - show = SHOW_USER; level = '.'; - map = thread__find_map(thread, ip); if (map != NULL) { +got_map: ip = map->map_ip(map, ip); - dso = map->dso; + sym = map->dso->find_symbol(map->dso, ip); } else { /* * If this is outside of all known maps, * and is a negative address, try to look it * up in the kernel dso, as it might be a - * vsyscall (which executes in user-mode): + * vsyscall or vdso (which executes in user-mode). + * + * XXX This is nasty, we should have a symbol list in + * the "[vdso]" dso, but for now lets use the old + * trick of looking in the whole kernel symbol list. */ - if ((long long)ip < 0) - dso = kernel_dso; + if ((long long)ip < 0) { + map = kernel_map; + goto got_map; + } } - dump_printf(" ...... dso: %s\n", dso ? dso->name : ""); - + dump_printf(" ...... dso: %s\n", + map ? map->dso->long_name : ""); } else { show = SHOW_HV; level = 'H'; @@ -188,12 +191,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) } if (show & show_mask) { - struct symbol *sym = NULL; - - if (dso) - sym = dso->find_symbol(dso, ip); - - if (hist_entry__add(thread, map, dso, sym, ip, level)) { + if (hist_entry__add(thread, map, sym, ip, level)) { fprintf(stderr, "problem incrementing symbol count, skipping event\n"); return -1; @@ -313,7 +311,7 @@ process_event(event_t *event, unsigned long offset, unsigned long head) } static int -parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) +parse_line(FILE *file, struct symbol *sym, u64 len) { char *line = NULL, *tmp, *tmp2; static const char *prev_line; @@ -363,7 +361,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) const char *color; struct sym_ext *sym_ext = sym->priv; - offset = line_ip - start; + offset = line_ip - sym->start; if (offset < len) hits = sym->hist[offset]; @@ -442,7 +440,7 @@ static void free_source_line(struct symbol *sym, int len) /* Get the filename:line for the colored entries */ static void -get_source_line(struct symbol *sym, u64 start, int len, const char *filename) +get_source_line(struct symbol *sym, int len, const char *filename) { int i; char cmd[PATH_MAX * 2]; @@ -467,7 +465,7 @@ get_source_line(struct symbol *sym, u64 start, int len, const char *filename) if (sym_ext[i].percent <= 0.5) continue; - offset = start + i; + offset = sym->start + i; sprintf(cmd, "addr2line -e %s %016llx", filename, offset); fp = popen(cmd, "r"); if (!fp) @@ -519,31 +517,23 @@ static void print_summary(const char *filename) static void annotate_sym(struct dso *dso, struct symbol *sym) { - const char *filename = dso->name, *d_filename; - u64 start, end, len; + const char *filename = dso->long_name, *d_filename; + u64 len; char command[PATH_MAX*2]; FILE *file; if (!filename) return; - if (sym->module) - filename = sym->module->path; - else if (dso == kernel_dso) - filename = vmlinux_name; - - start = sym->obj_start; - if (!start) - start = sym->start; + if (full_paths) d_filename = filename; else d_filename = basename(filename); - end = start + sym->end - sym->start + 1; len = sym->end - sym->start; if (print_line) { - get_source_line(sym, start, len, filename); + get_source_line(sym, len, filename); print_summary(filename); } @@ -552,10 +542,11 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) printf("------------------------------------------------\n"); if (verbose >= 2) - printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); + printf("annotating [%p] %30s : [%p] %30s\n", + dso, dso->long_name, sym, sym->name); sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", - (u64)start, (u64)end, filename, filename); + sym->start, sym->end, filename, filename); if (verbose >= 3) printf("doing: %s\n", command); @@ -565,7 +556,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym) return; while (!feof(file)) { - if (parse_line(file, sym, start, len) < 0) + if (parse_line(file, sym, len) < 0) break; } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index c1a54fc8527..3ed3baf96ff 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -349,22 +349,17 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm) static struct symbol * -resolve_symbol(struct thread *thread, struct map **mapp, - struct dso **dsop, u64 *ipp) +resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp) { - struct dso *dso = dsop ? *dsop : NULL; struct map *map = mapp ? *mapp : NULL; u64 ip = *ipp; - if (!thread) - return NULL; - - if (dso) - goto got_dso; - if (map) goto got_map; + if (!thread) + return NULL; + map = thread__find_map(thread, ip); if (map != NULL) { /* @@ -379,29 +374,29 @@ resolve_symbol(struct thread *thread, struct map **mapp, *mapp = map; got_map: ip = map->map_ip(map, ip); - - dso = map->dso; } else { /* * If this is outside of all known maps, * and is a negative address, try to look it * up in the kernel dso, as it might be a - * vsyscall (which executes in user-mode): + * vsyscall or vdso (which executes in user-mode). + * + * XXX This is nasty, we should have a symbol list in + * the "[vdso]" dso, but for now lets use the old + * trick of looking in the whole kernel symbol list. */ - if ((long long)ip < 0) - dso = kernel_dso; + if ((long long)ip < 0) { + map = kernel_map; + if (mapp) + *mapp = map; + } } - dump_printf(" ...... dso: %s\n", dso ? dso->name : ""); + dump_printf(" ...... dso: %s\n", + map ? map->dso->long_name : ""); dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip); *ipp = ip; - if (dsop) - *dsop = dso; - - if (!dso) - return NULL; -got_dso: - return dso->find_symbol(dso, ip); + return map ? map->dso->find_symbol(map->dso, ip) : NULL; } static int call__match(struct symbol *sym) @@ -413,7 +408,7 @@ static int call__match(struct symbol *sym) } static struct symbol ** -resolve_callchain(struct thread *thread, struct map *map __used, +resolve_callchain(struct thread *thread, struct map *map, struct ip_callchain *chain, struct hist_entry *entry) { u64 context = PERF_CONTEXT_MAX; @@ -430,8 +425,7 @@ resolve_callchain(struct thread *thread, struct map *map __used, for (i = 0; i < chain->nr; i++) { u64 ip = chain->ips[i]; - struct dso *dso = NULL; - struct symbol *sym; + struct symbol *sym = NULL; if (ip >= PERF_CONTEXT_MAX) { context = ip; @@ -440,17 +434,15 @@ resolve_callchain(struct thread *thread, struct map *map __used, switch (context) { case PERF_CONTEXT_HV: - dso = hypervisor_dso; break; case PERF_CONTEXT_KERNEL: - dso = kernel_dso; + sym = kernel_maps__find_symbol(ip, &map); break; default: + sym = resolve_symbol(thread, &map, &ip); break; } - sym = resolve_symbol(thread, NULL, &dso, &ip); - if (sym) { if (sort__has_parent && call__match(sym) && !entry->parent) @@ -469,7 +461,7 @@ resolve_callchain(struct thread *thread, struct map *map __used, */ static int -hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, +hist_entry__add(struct thread *thread, struct map *map, struct symbol *sym, u64 ip, struct ip_callchain *chain, char level, u64 count) { @@ -480,7 +472,6 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, struct hist_entry entry = { .thread = thread, .map = map, - .dso = dso, .sym = sym, .ip = ip, .level = level, @@ -641,7 +632,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) { char level; int show = 0; - struct dso *dso = NULL; + struct symbol *sym = NULL; struct thread *thread; u64 ip = event->ip.ip; u64 period = 1; @@ -700,35 +691,35 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) show = SHOW_KERNEL; level = 'k'; - dso = kernel_dso; - - dump_printf(" ...... dso: %s\n", dso->name); - + sym = kernel_maps__find_symbol(ip, &map); + dump_printf(" ...... dso: %s\n", + map ? map->dso->long_name : ""); } else if (cpumode == PERF_RECORD_MISC_USER) { show = SHOW_USER; level = '.'; + sym = resolve_symbol(thread, &map, &ip); } else { show = SHOW_HV; level = 'H'; - dso = hypervisor_dso; - dump_printf(" ...... dso: [hypervisor]\n"); } if (show & show_mask) { - struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); - - if (dso_list && (!dso || !dso->name || - !strlist__has_entry(dso_list, dso->name))) + if (dso_list && + (!map || !map->dso || + !(strlist__has_entry(dso_list, map->dso->short_name) || + (map->dso->short_name != map->dso->long_name && + strlist__has_entry(dso_list, map->dso->long_name))))) return 0; - if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name))) + if (sym_list && sym && !strlist__has_entry(sym_list, sym->name)) return 0; - if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { + if (hist_entry__add(thread, map, sym, ip, + chain, level, period)) { eprintf("problem incrementing symbol count, skipping event\n"); return -1; } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index bf464ce7e3e..befef842757 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -22,6 +22,7 @@ #include "util/symbol.h" #include "util/color.h" +#include "util/thread.h" #include "util/util.h" #include #include "util/parse-options.h" @@ -103,6 +104,7 @@ struct sym_entry { unsigned long snap_count; double weight; int skip; + struct map *map; struct source_line *source; struct source_line *lines; struct source_line **lines_tail; @@ -116,12 +118,11 @@ struct sym_entry { static void parse_source(struct sym_entry *syme) { struct symbol *sym; - struct module *module; - struct section *section = NULL; + struct map *map; FILE *file; char command[PATH_MAX*2]; - const char *path = vmlinux_name; - u64 start, end, len; + const char *path; + u64 len; if (!syme) return; @@ -132,27 +133,15 @@ static void parse_source(struct sym_entry *syme) } sym = (struct symbol *)(syme + 1); - module = sym->module; + map = syme->map; + path = map->dso->long_name; - if (module) - path = module->path; - if (!path) - return; - - start = sym->obj_start; - if (!start) - start = sym->start; - - if (module) { - section = module->sections->find_section(module->sections, ".text"); - if (section) - start -= section->vma; - } - - end = start + sym->end - sym->start + 1; len = sym->end - sym->start; - sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path); + sprintf(command, + "objdump --start-address=0x%016Lx " + "--stop-address=0x%016Lx -dS %s", + sym->start, sym->end, path); file = popen(command, "r"); if (!file) @@ -184,13 +173,11 @@ static void parse_source(struct sym_entry *syme) if (strlen(src->line)>8 && src->line[8] == ':') { src->eip = strtoull(src->line, NULL, 16); - if (section) - src->eip += section->vma; + src->eip += map->start; } if (strlen(src->line)>8 && src->line[16] == ':') { src->eip = strtoull(src->line, NULL, 16); - if (section) - src->eip += section->vma; + src->eip += map->start; } } pclose(file); @@ -242,16 +229,9 @@ static void lookup_sym_source(struct sym_entry *syme) struct symbol *symbol = (struct symbol *)(syme + 1); struct source_line *line; char pattern[PATH_MAX]; - char *idx; sprintf(pattern, "<%s>:", symbol->name); - if (symbol->module) { - idx = strstr(pattern, "\t"); - if (idx) - *idx = 0; - } - pthread_mutex_lock(&syme->source_lock); for (line = syme->lines; line; line = line->next) { if (strstr(line->line, pattern)) { @@ -513,8 +493,8 @@ static void print_sym_table(void) if (verbose) printf(" - %016llx", sym->start); printf(" : %s", sym->name); - if (sym->module) - printf("\t[%s]", sym->module->name); + if (syme->map->dso->name[0] == '[') + printf(" \t%s", syme->map->dso->name); printf("\n"); } } @@ -784,7 +764,7 @@ static const char *skip_symbols[] = { NULL }; -static int symbol_filter(struct dso *self, struct symbol *sym) +static int symbol_filter(struct map *map, struct symbol *sym) { struct sym_entry *syme; const char *name = sym->name; @@ -806,7 +786,8 @@ static int symbol_filter(struct dso *self, struct symbol *sym) strstr(name, "_text_end")) return 1; - syme = dso__sym_priv(self, sym); + syme = dso__sym_priv(map->dso, sym); + syme->map = map; pthread_mutex_init(&syme->source_lock, NULL); if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) sym_filter_entry = syme; @@ -825,22 +806,14 @@ static int parse_symbols(void) { int use_modules = vmlinux_name ? 1 : 0; - kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry)); - if (kernel_dso == NULL) + if (dsos__load_kernel(vmlinux_name, sizeof(struct sym_entry), + symbol_filter, verbose, use_modules) <= 0) return -1; - if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0) - goto out_delete_dso; - if (dump_symtab) - dso__fprintf(kernel_dso, stderr); + dsos__fprintf(stderr); return 0; - -out_delete_dso: - dso__delete(kernel_dso); - kernel_dso = NULL; - return -1; } /* @@ -848,10 +821,11 @@ out_delete_dso: */ static void record_ip(u64 ip, int counter) { - struct symbol *sym = dso__find_symbol(kernel_dso, ip); + struct map *map; + struct symbol *sym = kernel_maps__find_symbol(ip, &map); if (sym != NULL) { - struct sym_entry *syme = dso__sym_priv(kernel_dso, sym); + struct sym_entry *syme = dso__sym_priv(map->dso, sym); if (!syme->skip) { syme->count[counter]++; diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 4c69eb55380..a39520e6ae8 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -3,6 +3,7 @@ #include "../perf.h" #include "util.h" +#include #include enum { @@ -79,7 +80,10 @@ typedef union event_union { } event_t; struct map { - struct rb_node rb_node; + union { + struct rb_node rb_node; + struct list_head node; + }; u64 start; u64 end; u64 pgoff; diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c deleted file mode 100644 index 0d8c85defcd..00000000000 --- a/tools/perf/util/module.c +++ /dev/null @@ -1,545 +0,0 @@ -#include "util.h" -#include "../perf.h" -#include "string.h" -#include "module.h" - -#include -#include -#include -#include -#include -#include - -static unsigned int crc32(const char *p, unsigned int len) -{ - int i; - unsigned int crc = 0; - - while (len--) { - crc ^= *p++; - for (i = 0; i < 8; i++) - crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0); - } - return crc; -} - -/* module section methods */ - -struct sec_dso *sec_dso__new_dso(const char *name) -{ - struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1); - - if (self != NULL) { - strcpy(self->name, name); - self->secs = RB_ROOT; - self->find_section = sec_dso__find_section; - } - - return self; -} - -static void sec_dso__delete_section(struct section *self) -{ - free(((void *)self)); -} - -void sec_dso__delete_sections(struct sec_dso *self) -{ - struct section *pos; - struct rb_node *next = rb_first(&self->secs); - - while (next) { - pos = rb_entry(next, struct section, rb_node); - next = rb_next(&pos->rb_node); - rb_erase(&pos->rb_node, &self->secs); - sec_dso__delete_section(pos); - } -} - -void sec_dso__delete_self(struct sec_dso *self) -{ - sec_dso__delete_sections(self); - free(self); -} - -static void sec_dso__insert_section(struct sec_dso *self, struct section *sec) -{ - struct rb_node **p = &self->secs.rb_node; - struct rb_node *parent = NULL; - const u64 hash = sec->hash; - struct section *s; - - while (*p != NULL) { - parent = *p; - s = rb_entry(parent, struct section, rb_node); - if (hash < s->hash) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - rb_link_node(&sec->rb_node, parent, p); - rb_insert_color(&sec->rb_node, &self->secs); -} - -struct section *sec_dso__find_section(struct sec_dso *self, const char *name) -{ - struct rb_node *n; - u64 hash; - int len; - - if (self == NULL) - return NULL; - - len = strlen(name); - hash = crc32(name, len); - - n = self->secs.rb_node; - - while (n) { - struct section *s = rb_entry(n, struct section, rb_node); - - if (hash < s->hash) - n = n->rb_left; - else if (hash > s->hash) - n = n->rb_right; - else { - if (!strcmp(name, s->name)) - return s; - else - n = rb_next(&s->rb_node); - } - } - - return NULL; -} - -static size_t sec_dso__fprintf_section(struct section *self, FILE *fp) -{ - return fprintf(fp, "name:%s vma:%llx path:%s\n", - self->name, self->vma, self->path); -} - -size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp) -{ - size_t ret = fprintf(fp, "dso: %s\n", self->name); - - struct rb_node *nd; - for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) { - struct section *pos = rb_entry(nd, struct section, rb_node); - ret += sec_dso__fprintf_section(pos, fp); - } - - return ret; -} - -static struct section *section__new(const char *name, const char *path) -{ - struct section *self = calloc(1, sizeof(*self)); - - if (!self) - goto out_failure; - - self->name = calloc(1, strlen(name) + 1); - if (!self->name) - goto out_failure; - - self->path = calloc(1, strlen(path) + 1); - if (!self->path) - goto out_failure; - - strcpy(self->name, name); - strcpy(self->path, path); - self->hash = crc32(self->name, strlen(name)); - - return self; - -out_failure: - if (self) { - if (self->name) - free(self->name); - if (self->path) - free(self->path); - free(self); - } - - return NULL; -} - -/* module methods */ - -struct mod_dso *mod_dso__new_dso(const char *name) -{ - struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1); - - if (self != NULL) { - strcpy(self->name, name); - self->mods = RB_ROOT; - self->find_module = mod_dso__find_module; - } - - return self; -} - -static void mod_dso__delete_module(struct module *self) -{ - free(((void *)self)); -} - -void mod_dso__delete_modules(struct mod_dso *self) -{ - struct module *pos; - struct rb_node *next = rb_first(&self->mods); - - while (next) { - pos = rb_entry(next, struct module, rb_node); - next = rb_next(&pos->rb_node); - rb_erase(&pos->rb_node, &self->mods); - mod_dso__delete_module(pos); - } -} - -void mod_dso__delete_self(struct mod_dso *self) -{ - mod_dso__delete_modules(self); - free(self); -} - -static void mod_dso__insert_module(struct mod_dso *self, struct module *mod) -{ - struct rb_node **p = &self->mods.rb_node; - struct rb_node *parent = NULL; - const u64 hash = mod->hash; - struct module *m; - - while (*p != NULL) { - parent = *p; - m = rb_entry(parent, struct module, rb_node); - if (hash < m->hash) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - rb_link_node(&mod->rb_node, parent, p); - rb_insert_color(&mod->rb_node, &self->mods); -} - -struct module *mod_dso__find_module(struct mod_dso *self, const char *name) -{ - struct rb_node *n; - u64 hash; - int len; - - if (self == NULL) - return NULL; - - len = strlen(name); - hash = crc32(name, len); - - n = self->mods.rb_node; - - while (n) { - struct module *m = rb_entry(n, struct module, rb_node); - - if (hash < m->hash) - n = n->rb_left; - else if (hash > m->hash) - n = n->rb_right; - else { - if (!strcmp(name, m->name)) - return m; - else - n = rb_next(&m->rb_node); - } - } - - return NULL; -} - -static size_t mod_dso__fprintf_module(struct module *self, FILE *fp) -{ - return fprintf(fp, "name:%s path:%s\n", self->name, self->path); -} - -size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp) -{ - struct rb_node *nd; - size_t ret; - - ret = fprintf(fp, "dso: %s\n", self->name); - - for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) { - struct module *pos = rb_entry(nd, struct module, rb_node); - - ret += mod_dso__fprintf_module(pos, fp); - } - - return ret; -} - -static struct module *module__new(const char *name, const char *path) -{ - struct module *self = calloc(1, sizeof(*self)); - - if (!self) - goto out_failure; - - self->name = calloc(1, strlen(name) + 1); - if (!self->name) - goto out_failure; - - self->path = calloc(1, strlen(path) + 1); - if (!self->path) - goto out_failure; - - strcpy(self->name, name); - strcpy(self->path, path); - self->hash = crc32(self->name, strlen(name)); - - return self; - -out_failure: - if (self) { - if (self->name) - free(self->name); - if (self->path) - free(self->path); - free(self); - } - - return NULL; -} - -static int mod_dso__load_sections(struct module *mod) -{ - int count = 0, path_len; - struct dirent *entry; - char *line = NULL; - char *dir_path; - DIR *dir; - size_t n; - - path_len = strlen("/sys/module/"); - path_len += strlen(mod->name); - path_len += strlen("/sections/"); - - dir_path = calloc(1, path_len + 1); - if (dir_path == NULL) - goto out_failure; - - strcat(dir_path, "/sys/module/"); - strcat(dir_path, mod->name); - strcat(dir_path, "/sections/"); - - dir = opendir(dir_path); - if (dir == NULL) - goto out_free; - - while ((entry = readdir(dir))) { - struct section *section; - char *path, *vma; - int line_len; - FILE *file; - - if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name)) - continue; - - path = calloc(1, path_len + strlen(entry->d_name) + 1); - if (path == NULL) - break; - strcat(path, dir_path); - strcat(path, entry->d_name); - - file = fopen(path, "r"); - if (file == NULL) { - free(path); - break; - } - - line_len = getline(&line, &n, file); - if (line_len < 0) { - free(path); - fclose(file); - break; - } - - if (!line) { - free(path); - fclose(file); - break; - } - - line[--line_len] = '\0'; /* \n */ - - vma = strstr(line, "0x"); - if (!vma) { - free(path); - fclose(file); - break; - } - vma += 2; - - section = section__new(entry->d_name, path); - if (!section) { - fprintf(stderr, "load_sections: allocation error\n"); - free(path); - fclose(file); - break; - } - - hex2u64(vma, §ion->vma); - sec_dso__insert_section(mod->sections, section); - - free(path); - fclose(file); - count++; - } - - closedir(dir); - free(line); - free(dir_path); - - return count; - -out_free: - free(dir_path); - -out_failure: - return count; -} - -static int mod_dso__load_module_paths(struct mod_dso *self) -{ - struct utsname uts; - int count = 0, len, err = -1; - char *line = NULL; - FILE *file; - char *dpath, *dir; - size_t n; - - if (uname(&uts) < 0) - return err; - - len = strlen("/lib/modules/"); - len += strlen(uts.release); - len += strlen("/modules.dep"); - - dpath = calloc(1, len + 1); - if (dpath == NULL) - return err; - - strcat(dpath, "/lib/modules/"); - strcat(dpath, uts.release); - strcat(dpath, "/modules.dep"); - - file = fopen(dpath, "r"); - if (file == NULL) - goto out_failure; - - dir = dirname(dpath); - if (!dir) - goto out_failure; - strcat(dir, "/"); - - while (!feof(file)) { - struct module *module; - char *name, *path, *tmp; - FILE *modfile; - int line_len; - - line_len = getline(&line, &n, file); - if (line_len < 0) - break; - - if (!line) - break; - - line[--line_len] = '\0'; /* \n */ - - path = strchr(line, ':'); - if (!path) - break; - *path = '\0'; - - path = strdup(line); - if (!path) - break; - - if (!strstr(path, dir)) { - if (strncmp(path, "kernel/", 7)) - break; - - free(path); - path = calloc(1, strlen(dir) + strlen(line) + 1); - if (!path) - break; - strcat(path, dir); - strcat(path, line); - } - - modfile = fopen(path, "r"); - if (modfile == NULL) - break; - fclose(modfile); - - name = strdup(path); - if (!name) - break; - - name = strtok(name, "/"); - tmp = name; - - while (tmp) { - tmp = strtok(NULL, "/"); - if (tmp) - name = tmp; - } - - name = strsep(&name, "."); - if (!name) - break; - - /* Quirk: replace '-' with '_' in all modules */ - for (len = strlen(name); len; len--) { - if (*(name+len) == '-') - *(name+len) = '_'; - } - - module = module__new(name, path); - if (!module) - break; - mod_dso__insert_module(self, module); - - module->sections = sec_dso__new_dso("sections"); - if (!module->sections) - break; - - module->active = mod_dso__load_sections(module); - - if (module->active > 0) - count++; - } - - if (feof(file)) - err = count; - else - fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n"); - -out_failure: - if (dpath) - free(dpath); - if (file) - fclose(file); - if (line) - free(line); - - return err; -} - -int mod_dso__load_modules(struct mod_dso *dso) -{ - int err; - - err = mod_dso__load_module_paths(dso); - - return err; -} diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h deleted file mode 100644 index 098e0412bc2..00000000000 --- a/tools/perf/util/module.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef __PERF_MODULE_ -#define __PERF_MODULE_ 1 - -#include -#include "../types.h" -#include -#include - -struct section { - struct rb_node rb_node; - u64 hash; - u64 vma; - char *name; - char *path; -}; - -struct sec_dso { - struct list_head node; - struct rb_root secs; - struct section *(*find_section)(struct sec_dso *, const char *name); - char name[0]; -}; - -struct module { - struct rb_node rb_node; - u64 hash; - char *name; - char *path; - struct sec_dso *sections; - int active; -}; - -struct mod_dso { - struct list_head node; - struct rb_root mods; - struct module *(*find_module)(struct mod_dso *, const char *name); - char name[0]; -}; - -struct sec_dso *sec_dso__new_dso(const char *name); -void sec_dso__delete_sections(struct sec_dso *self); -void sec_dso__delete_self(struct sec_dso *self); -size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp); -struct section *sec_dso__find_section(struct sec_dso *self, const char *name); - -struct mod_dso *mod_dso__new_dso(const char *name); -void mod_dso__delete_modules(struct mod_dso *self); -void mod_dso__delete_self(struct mod_dso *self); -size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp); -struct module *mod_dso__find_module(struct mod_dso *self, const char *name); -int mod_dso__load_modules(struct mod_dso *dso); - -#endif /* __PERF_MODULE_ */ diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 50e75abb1fd..40c9acd41ca 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -129,20 +129,32 @@ sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width) int64_t sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) { - struct dso *dso_l = left->dso; - struct dso *dso_r = right->dso; + struct dso *dso_l = left->map ? left->map->dso : NULL; + struct dso *dso_r = right->map ? right->map->dso : NULL; + const char *dso_name_l, *dso_name_r; if (!dso_l || !dso_r) return cmp_null(dso_l, dso_r); - return strcmp(dso_l->name, dso_r->name); + if (verbose) { + dso_name_l = dso_l->long_name; + dso_name_r = dso_r->long_name; + } else { + dso_name_l = dso_l->short_name; + dso_name_r = dso_r->short_name; + } + + return strcmp(dso_name_l, dso_name_r); } size_t sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width) { - if (self->dso) - return repsep_fprintf(fp, "%-*s", width, self->dso->name); + if (self->map && self->map->dso) { + const char *dso_name = !verbose ? self->map->dso->short_name : + self->map->dso->long_name; + return repsep_fprintf(fp, "%-*s", width, dso_name); + } return repsep_fprintf(fp, "%*llx", width, (u64)self->ip); } @@ -169,20 +181,16 @@ sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used) { size_t ret = 0; - if (verbose) - ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, - dso__symtab_origin(self->dso)); + if (verbose) { + char o = self->map ? dso__symtab_origin(self->map->dso) : '!'; + ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o); + } ret += repsep_fprintf(fp, "[%c] ", self->level); - if (self->sym) { + if (self->sym) ret += repsep_fprintf(fp, "%s", self->sym->name); - - if (self->sym->module) - ret += repsep_fprintf(fp, "\t[%s]", - self->sym->module->name); - } else { + else ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip); - } return ret; } diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 4684fd6d5c4..13806d782af 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -42,18 +42,15 @@ extern unsigned int threads__col_width; struct hist_entry { struct rb_node rb_node; - + u64 count; struct thread *thread; struct map *map; - struct dso *dso; struct symbol *sym; - struct symbol *parent; u64 ip; char level; + struct symbol *parent; struct callchain_node callchain; struct rb_root sorted_chain; - - u64 count; }; /* diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 559fb06210f..e8829689947 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -2,12 +2,14 @@ #include "../perf.h" #include "string.h" #include "symbol.h" +#include "thread.h" #include "debug.h" #include #include #include +#include const char *sym_hist_filter; @@ -18,12 +20,15 @@ enum dso_origin { DSO__ORIG_UBUNTU, DSO__ORIG_BUILDID, DSO__ORIG_DSO, + DSO__ORIG_KMODULE, DSO__ORIG_NOT_FOUND, }; -static struct symbol *symbol__new(u64 start, u64 len, - const char *name, unsigned int priv_size, - u64 obj_start, int v) +static void dsos__add(struct dso *dso); +static struct dso *dsos__find(const char *name); + +static struct symbol *symbol__new(u64 start, u64 len, const char *name, + unsigned int priv_size, int v) { size_t namelen = strlen(name) + 1; struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); @@ -32,10 +37,9 @@ static struct symbol *symbol__new(u64 start, u64 len, return NULL; if (v >= 2) - printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", - (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); + printf("new symbol: %016Lx [%08lx]: %s, hist: %p\n", + start, (unsigned long)len, name, self->hist); - self->obj_start= obj_start; self->hist = NULL; self->hist_sum = 0; @@ -60,12 +64,8 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size) static size_t symbol__fprintf(struct symbol *self, FILE *fp) { - if (!self->module) - return fprintf(fp, " %llx-%llx %s\n", + return fprintf(fp, " %llx-%llx %s\n", self->start, self->end, self->name); - else - return fprintf(fp, " %llx-%llx %s \t[%s]\n", - self->start, self->end, self->name, self->module->name); } struct dso *dso__new(const char *name, unsigned int sym_priv_size) @@ -74,6 +74,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size) if (self != NULL) { strcpy(self->name, name); + 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; @@ -100,6 +102,8 @@ static void dso__delete_symbols(struct dso *self) void dso__delete(struct dso *self) { dso__delete_symbols(self); + if (self->long_name != self->name) + free(self->long_name); free(self); } @@ -147,7 +151,7 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip) size_t dso__fprintf(struct dso *self, FILE *fp) { - size_t ret = fprintf(fp, "dso: %s\n", self->name); + size_t ret = fprintf(fp, "dso: %s\n", self->long_name); struct rb_node *nd; for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { @@ -158,7 +162,8 @@ size_t dso__fprintf(struct dso *self, FILE *fp) return ret; } -static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) +static int dso__load_kallsyms(struct dso *self, struct map *map, + symbol_filter_t filter, int v) { struct rb_node *nd, *prevnd; char *line = NULL; @@ -200,12 +205,12 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) * Well fix up the end later, when we have all sorted. */ sym = symbol__new(start, 0xdead, line + len + 2, - self->sym_priv_size, 0, v); + self->sym_priv_size, v); if (sym == NULL) goto out_delete_line; - if (filter && filter(self, sym)) + if (filter && filter(map, sym)) symbol__delete(sym, self->sym_priv_size); else { dso__insert_symbol(self, sym); @@ -241,14 +246,15 @@ out_failure: return -1; } -static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) +static int dso__load_perf_map(struct dso *self, struct map *map, + symbol_filter_t filter, int v) { char *line = NULL; size_t n; FILE *file; int nr_syms = 0; - file = fopen(self->name, "r"); + file = fopen(self->long_name, "r"); if (file == NULL) goto out_failure; @@ -279,12 +285,12 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) continue; sym = symbol__new(start, size, line + len, - self->sym_priv_size, start, v); + self->sym_priv_size, v); if (sym == NULL) goto out_delete_line; - if (filter && filter(self, sym)) + if (filter && filter(map, sym)) symbol__delete(sym, self->sym_priv_size); else { dso__insert_symbol(self, sym); @@ -410,7 +416,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v) Elf *elf; int nr = 0, symidx, fd, err = 0; - fd = open(self->name, O_RDONLY); + fd = open(self->long_name, O_RDONLY); if (fd < 0) goto out; @@ -478,7 +484,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v) "%s@plt", elf_sym__name(&sym, symstrs)); f = symbol__new(plt_offset, shdr_plt.sh_entsize, - sympltname, self->sym_priv_size, 0, v); + sympltname, self->sym_priv_size, v); if (!f) goto out_elf_end; @@ -496,7 +502,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v) "%s@plt", elf_sym__name(&sym, symstrs)); f = symbol__new(plt_offset, shdr_plt.sh_entsize, - sympltname, self->sym_priv_size, 0, v); + sympltname, self->sym_priv_size, v); if (!f) goto out_elf_end; @@ -515,12 +521,13 @@ out_close: return nr; out: fprintf(stderr, "%s: problems reading %s PLT info.\n", - __func__, self->name); + __func__, self->long_name); return 0; } -static int dso__load_sym(struct dso *self, int fd, const char *name, - symbol_filter_t filter, int v, struct module *mod) +static int dso__load_sym(struct dso *self, struct map *map, const char *name, + int fd, symbol_filter_t filter, int kernel, + int kmodule, int v) { Elf_Data *symstrs, *secstrs; uint32_t nr_syms; @@ -532,7 +539,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, GElf_Sym sym; Elf_Scn *sec, *sec_strndx; Elf *elf; - int nr = 0, kernel = !strcmp("[kernel]", self->name); + int nr = 0; elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); if (elf == NULL) { @@ -589,8 +596,6 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, struct symbol *f; const char *elf_name; char *demangled; - u64 obj_start; - struct section *section = NULL; int is_label = elf_sym__is_label(&sym); const char *section_name; @@ -607,7 +612,6 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, continue; section_name = elf_sec__name(&shdr, secstrs); - obj_start = sym.st_value; if (self->adjust_symbols) { if (v >= 2) @@ -615,18 +619,8 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); sym.st_value -= shdr.sh_addr - shdr.sh_offset; - } - - if (mod) { - section = mod->sections->find_section(mod->sections, section_name); - if (section) - sym.st_value += section->vma; - else { - fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n", - mod->name, section_name); - goto out_elf_end; - } - } + } else if (kmodule) + sym.st_value += shdr.sh_offset; /* * We need to figure out if the object was created from C++ sources * DWARF DW_compile_unit has this, but we don't always have access @@ -638,15 +632,14 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, elf_name = demangled; f = symbol__new(sym.st_value, sym.st_size, elf_name, - self->sym_priv_size, obj_start, v); + self->sym_priv_size, v); free(demangled); if (!f) goto out_elf_end; - if (filter && filter(self, f)) + if (filter && filter(map, f)) symbol__delete(f, self->sym_priv_size); else { - f->module = mod; dso__insert_symbol(self, f); nr++; } @@ -671,7 +664,7 @@ static char *dso__read_build_id(struct dso *self, int v) char *build_id = NULL, *bid; unsigned char *raw; Elf *elf; - int fd = open(self->name, O_RDONLY); + int fd = open(self->long_name, O_RDONLY); if (fd < 0) goto out; @@ -680,7 +673,7 @@ static char *dso__read_build_id(struct dso *self, int v) if (elf == NULL) { if (v) fprintf(stderr, "%s: cannot read %s ELF file.\n", - __func__, self->name); + __func__, self->long_name); goto out_close; } @@ -709,7 +702,7 @@ static char *dso__read_build_id(struct dso *self, int v) bid += 2; } if (v >= 2) - printf("%s(%s): %s\n", __func__, self->name, build_id); + printf("%s(%s): %s\n", __func__, self->long_name, build_id); out_elf_end: elf_end(elf); out_close: @@ -727,6 +720,7 @@ char dso__symtab_origin(const struct dso *self) [DSO__ORIG_UBUNTU] = 'u', [DSO__ORIG_BUILDID] = 'b', [DSO__ORIG_DSO] = 'd', + [DSO__ORIG_KMODULE] = 'K', }; if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) @@ -734,7 +728,7 @@ char dso__symtab_origin(const struct dso *self) return origin[self->origin]; } -int dso__load(struct dso *self, 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; @@ -747,7 +741,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int v) self->adjust_symbols = 0; if (strncmp(self->name, "/tmp/perf-", 10) == 0) { - ret = dso__load_perf_map(self, filter, v); + ret = dso__load_perf_map(self, map, filter, v); self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : DSO__ORIG_NOT_FOUND; return ret; @@ -760,10 +754,12 @@ more: self->origin++; switch (self->origin) { case DSO__ORIG_FEDORA: - snprintf(name, size, "/usr/lib/debug%s.debug", self->name); + snprintf(name, size, "/usr/lib/debug%s.debug", + self->long_name); break; case DSO__ORIG_UBUNTU: - snprintf(name, size, "/usr/lib/debug%s", self->name); + snprintf(name, size, "/usr/lib/debug%s", + self->long_name); break; case DSO__ORIG_BUILDID: build_id = dso__read_build_id(self, v); @@ -777,7 +773,7 @@ more: self->origin++; /* Fall thru */ case DSO__ORIG_DSO: - snprintf(name, size, "%s", self->name); + snprintf(name, size, "%s", self->long_name); break; default: @@ -787,7 +783,7 @@ more: fd = open(name, O_RDONLY); } while (fd < 0); - ret = dso__load_sym(self, fd, name, filter, v, NULL); + ret = dso__load_sym(self, map, name, fd, filter, 0, 0, v); close(fd); /* @@ -808,89 +804,247 @@ out: return ret; } -static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, - symbol_filter_t filter, int v) +static struct rb_root kernel_maps; +struct map *kernel_map; + +static void kernel_maps__insert(struct map *map) { - struct module *mod = mod_dso__find_module(mods, name); - int err = 0, fd; + maps__insert(&kernel_maps, map); +} - if (mod == NULL || !mod->active) - return err; +struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp) +{ + /* + * We can't have kernel_map in kernel_maps because it spans an address + * space that includes the modules. The right way to fix this is to + * create several maps, so that we don't have overlapping ranges with + * modules. For now lets look first on the kernel dso. + */ + struct map *map = maps__find(&kernel_maps, ip); + struct symbol *sym; + + if (map) { + ip = map->map_ip(map, ip); + sym = map->dso->find_symbol(map->dso, ip); + } else { + map = kernel_map; + sym = map->dso->find_symbol(map->dso, ip); + } - fd = open(mod->path, O_RDONLY); + if (mapp) + *mapp = map; - if (fd < 0) + return sym; +} + +struct map *kernel_maps__find_by_dso_name(const char *name) +{ + struct rb_node *nd; + + for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { + struct map *map = rb_entry(nd, struct map, rb_node); + + if (map->dso && strcmp(map->dso->name, name) == 0) + return map; + } + + return NULL; +} + +static int dso__load_module_sym(struct dso *self, struct map *map, + symbol_filter_t filter, int v) +{ + int err = 0, fd = open(self->long_name, O_RDONLY); + + if (fd < 0) { + if (v) + fprintf(stderr, "%s: cannot open %s\n", + __func__, self->long_name); return err; + } - err = dso__load_sym(self, fd, name, filter, v, mod); + err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1, v); close(fd); return err; } -int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) +static int dsos__load_modules_sym_dir(char *dirname, + symbol_filter_t filter, int v) { - struct mod_dso *mods = mod_dso__new_dso("modules"); - struct module *pos; - struct rb_node *next; - int err, count = 0; + struct dirent *dent; + int nr_symbols = 0, err; + DIR *dir = opendir(dirname); - err = mod_dso__load_modules(mods); + if (!dir) { + if (v) + fprintf(stderr, "%s: cannot open %s dir\n", __func__, + dirname); + return -1; + } - if (err <= 0) - return err; + while ((dent = readdir(dir)) != NULL) { + char path[PATH_MAX]; + + if (dent->d_type == DT_DIR) { + if (!strcmp(dent->d_name, ".") || + !strcmp(dent->d_name, "..")) + continue; + + snprintf(path, sizeof(path), "%s/%s", + dirname, dent->d_name); + err = dsos__load_modules_sym_dir(path, filter, v); + if (err < 0) + goto failure; + } else { + char *dot = strrchr(dent->d_name, '.'), + dso_name[PATH_MAX]; + struct map *map; + struct rb_node *last; + + if (dot == NULL || strcmp(dot, ".ko")) + continue; + snprintf(dso_name, sizeof(dso_name), "[%.*s]", + (int)(dot - dent->d_name), dent->d_name); + + map = kernel_maps__find_by_dso_name(dso_name); + if (map == NULL) + continue; + + snprintf(path, sizeof(path), "%s/%s", + dirname, dent->d_name); + + map->dso->long_name = strdup(path); + if (map->dso->long_name == NULL) + goto failure; + + err = dso__load_module_sym(map->dso, map, filter, v); + if (err < 0) + goto failure; + last = rb_last(&map->dso->syms); + if (last) { + struct symbol *sym; + sym = rb_entry(last, struct symbol, rb_node); + map->end = map->start + sym->end; + } + } + nr_symbols += err; + } - /* - * Iterate over modules, and load active symbols. - */ - next = rb_first(&mods->mods); - while (next) { - pos = rb_entry(next, struct module, rb_node); - err = dso__load_module(self, mods, pos->name, filter, v); + return nr_symbols; +failure: + closedir(dir); + return -1; +} - if (err < 0) - break; +static int dsos__load_modules_sym(symbol_filter_t filter, int v) +{ + struct utsname uts; + char modules_path[PATH_MAX]; - next = rb_next(&pos->rb_node); - count += err; - } + if (uname(&uts) < 0) + return -1; - if (err < 0) { - mod_dso__delete_modules(mods); - mod_dso__delete_self(mods); - return err; - } + snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", + uts.release); - return count; + return dsos__load_modules_sym_dir(modules_path, filter, v); } -static inline void dso__fill_symbol_holes(struct dso *self) +/* + * Constructor variant for modules (where we know from /proc/modules where + * they are loaded) and for vmlinux, where only after we load all the + * symbols we'll know where it starts and ends. + */ +static struct map *map__new2(u64 start, struct dso *dso) { - struct symbol *prev = NULL; - struct rb_node *nd; + struct map *self = malloc(sizeof(*self)); - for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { - struct symbol *pos = rb_entry(nd, struct symbol, rb_node); + if (self != NULL) { + self->start = start; + /* + * Will be filled after we load all the symbols + */ + self->end = 0; + + self->pgoff = 0; + self->dso = dso; + self->map_ip = map__map_ip; + RB_CLEAR_NODE(&self->rb_node); + } + return self; +} + +int dsos__load_modules(unsigned int sym_priv_size, + symbol_filter_t filter, int v) +{ + char *line = NULL; + size_t n; + FILE *file = fopen("/proc/modules", "r"); + struct map *map; - if (prev) { - u64 hole = 0; - int alias = pos->start == prev->start; + if (file == NULL) + return -1; - if (!alias) - hole = prev->start - pos->end - 1; + while (!feof(file)) { + char name[PATH_MAX]; + u64 start; + struct dso *dso; + char *sep; + int line_len; - if (hole || alias) { - if (alias) - pos->end = prev->end; - else if (hole) - pos->end = prev->start - 1; - } + line_len = getline(&line, &n, file); + if (line_len < 0) + break; + + if (!line) + goto out_failure; + + line[--line_len] = '\0'; /* \n */ + + sep = strrchr(line, 'x'); + if (sep == NULL) + continue; + + hex2u64(sep + 1, &start); + + sep = strchr(line, ' '); + if (sep == NULL) + continue; + + *sep = '\0'; + + snprintf(name, sizeof(name), "[%s]", line); + dso = dso__new(name, sym_priv_size); + + if (dso == NULL) + goto out_delete_line; + + map = map__new2(start, dso); + if (map == NULL) { + dso__delete(dso); + goto out_delete_line; } - prev = pos; + + dso->origin = DSO__ORIG_KMODULE; + kernel_maps__insert(map); + dsos__add(dso); } + + free(line); + fclose(file); + + v = 1; + return dsos__load_modules_sym(filter, v); + +out_delete_line: + free(line); +out_failure: + return -1; } -static int dso__load_vmlinux(struct dso *self, const char *vmlinux, +static int dso__load_vmlinux(struct dso *self, struct map *map, + const char *vmlinux, symbol_filter_t filter, int v) { int err, fd = open(vmlinux, O_RDONLY); @@ -898,28 +1052,36 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux, if (fd < 0) return -1; - err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); - - if (err > 0) - dso__fill_symbol_holes(self); + err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0, v); close(fd); return err; } -int dso__load_kernel(struct dso *self, const char *vmlinux, - symbol_filter_t filter, int v, int use_modules) +int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, + symbol_filter_t filter, int v, int use_modules) { int err = -1; + struct dso *dso = dso__new(vmlinux, sym_priv_size); + + if (dso == NULL) + return -1; + + dso->short_name = "[kernel]"; + kernel_map = map__new2(0, dso); + if (kernel_map == NULL) + goto out_delete_dso; + + kernel_map->map_ip = vdso__map_ip; if (vmlinux) { - err = dso__load_vmlinux(self, vmlinux, filter, v); + err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v); if (err > 0 && use_modules) { - int syms = dso__load_modules(self, filter, v); + int syms = dsos__load_modules(sym_priv_size, filter, v); if (syms < 0) { - fprintf(stderr, "dso__load_modules failed!\n"); + fprintf(stderr, "dsos__load_modules failed!\n"); return syms; } err += syms; @@ -927,18 +1089,34 @@ int dso__load_kernel(struct dso *self, const char *vmlinux, } if (err <= 0) - err = dso__load_kallsyms(self, filter, v); + err = dso__load_kallsyms(dso, kernel_map, filter, v); + + if (err > 0) { + struct rb_node *node = rb_first(&dso->syms); + struct symbol *sym = rb_entry(node, struct symbol, rb_node); - if (err > 0) - self->origin = DSO__ORIG_KERNEL; + kernel_map->start = sym->start; + node = rb_last(&dso->syms); + sym = rb_entry(node, struct symbol, rb_node); + kernel_map->end = sym->end; + + dso->origin = DSO__ORIG_KERNEL; + /* + * XXX See kernel_maps__find_symbol comment + * kernel_maps__insert(kernel_map) + */ + dsos__add(dso); + } return err; + +out_delete_dso: + dso__delete(dso); + return -1; } LIST_HEAD(dsos); -struct dso *kernel_dso; struct dso *vdso; -struct dso *hypervisor_dso; const char *vmlinux_name = "vmlinux"; int modules; @@ -970,7 +1148,7 @@ struct dso *dsos__findnew(const char *name) if (!dso) goto out_delete_dso; - nr = dso__load(dso, NULL, verbose); + nr = dso__load(dso, NULL, NULL, verbose); if (nr < 0) { eprintf("Failed to open: %s\n", name); goto out_delete_dso; @@ -995,43 +1173,20 @@ void dsos__fprintf(FILE *fp) dso__fprintf(pos, fp); } -static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) -{ - return dso__find_symbol(dso, ip); -} - int load_kernel(void) { - int err; - - kernel_dso = dso__new("[kernel]", 0); - if (!kernel_dso) + if (dsos__load_kernel(vmlinux_name, 0, NULL, verbose, modules) <= 0) return -1; - err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules); - if (err <= 0) { - dso__delete(kernel_dso); - kernel_dso = NULL; - } else - dsos__add(kernel_dso); - vdso = dso__new("[vdso]", 0); if (!vdso) return -1; - vdso->find_symbol = vdso__find_symbol; - dsos__add(vdso); - hypervisor_dso = dso__new("[hypervisor]", 0); - if (!hypervisor_dso) - return -1; - dsos__add(hypervisor_dso); - - return err; + return 0; } - void symbol__init(void) { elf_version(EV_CURRENT); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index ee164f659ed..5339fd82ec9 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -5,7 +5,6 @@ #include "types.h" #include #include -#include "module.h" #include "event.h" #ifdef HAVE_CPLUS_DEMANGLE @@ -36,10 +35,8 @@ struct symbol { struct rb_node rb_node; u64 start; u64 end; - u64 obj_start; u64 hist_sum; u64 *hist; - struct module *module; void *priv; char name[0]; }; @@ -52,12 +49,14 @@ struct dso { unsigned char adjust_symbols; unsigned char slen_calculated; unsigned char origin; + const char *short_name; + char *long_name; char name[0]; }; extern const char *sym_hist_filter; -typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym); +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); @@ -69,10 +68,12 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) struct symbol *dso__find_symbol(struct dso *self, u64 ip); -int dso__load_kernel(struct dso *self, const char *vmlinux, - symbol_filter_t filter, int verbose, int modules); -int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose); -int dso__load(struct dso *self, symbol_filter_t filter, int verbose); +int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, + symbol_filter_t filter, int verbose, int modules); +int dsos__load_modules(unsigned int sym_priv_size, symbol_filter_t filter, + int verbose); +int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, + int verbose); struct dso *dsos__findnew(const char *name); void dsos__fprintf(FILE *fp); @@ -84,9 +85,8 @@ int load_kernel(void); void symbol__init(void); extern struct list_head dsos; -extern struct dso *kernel_dso; +extern struct map *kernel_map; extern struct dso *vdso; -extern struct dso *hypervisor_dso; extern const char *vmlinux_name; extern int modules; #endif /* __PERF_SYMBOL */ diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 9d0945cc66d..3b56aebb1f4 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -16,6 +16,7 @@ static struct thread *thread__new(pid_t pid) if (self->comm) snprintf(self->comm, 32, ":%d", self->pid); self->maps = RB_ROOT; + INIT_LIST_HEAD(&self->removed_maps); } return self; @@ -32,13 +33,20 @@ int thread__set_comm(struct thread *self, const char *comm) static size_t thread__fprintf(struct thread *self, FILE *fp) { struct rb_node *nd; - size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); + struct map *pos; + size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n", + self->pid, self->comm); for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { - struct map *pos = rb_entry(nd, struct map, rb_node); + pos = rb_entry(nd, struct map, rb_node); ret += map__fprintf(pos, fp); } + ret = fprintf(fp, "Removed maps:\n"); + + list_for_each_entry(pos, &self->removed_maps, node) + ret += map__fprintf(pos, fp); + return ret; } @@ -112,21 +120,13 @@ static void thread__remove_overlappings(struct thread *self, struct map *map) map__fprintf(pos, stdout); } - if (map->start <= pos->start && map->end > pos->start) - pos->start = map->end; - - if (map->end >= pos->end && map->start < pos->end) - pos->end = map->start; - - if (verbose >= 2) { - printf("after collision:\n"); - map__fprintf(pos, stdout); - } - - if (pos->start >= pos->end) { - rb_erase(&pos->rb_node, &self->maps); - free(pos); - } + rb_erase(&pos->rb_node, &self->maps); + /* + * We may have references to this map, for instance in some + * hist_entry instances, so just move them to a separate + * list. + */ + list_add_tail(&pos->node, &self->removed_maps); } } diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index bbb37c1a52e..845d9b62f96 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -8,6 +8,7 @@ struct thread { struct rb_node rb_node; struct rb_root maps; + struct list_head removed_maps; pid_t pid; char shortname[3]; char *comm; @@ -25,6 +26,9 @@ size_t threads__fprintf(FILE *fp, struct rb_root *threads); 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 map *kernel_maps__find_by_dso_name(const char *name); + static inline struct map *thread__find_map(struct thread *self, u64 ip) { return self ? maps__find(&self->maps, ip) : NULL; -- cgit v1.2.3-70-g09d2 From 9a92b479b2f088ee2d3194243f4c8e59b1b8c9c2 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 8 Oct 2009 16:37:12 +0200 Subject: perf tools: Improve thread comm resolution in perf sched When we get sched traces that involve a task that was already created before opening the event, we won't have the comm event for it. So if we can't find the comm event for a given thread, we look at the traces that may contain these informations. Before: ata/1:371 | 0.000 ms | 1 | avg: 3988.693 ms | max: 3988.693 ms | kondemand/1:421 | 0.096 ms | 3 | avg: 345.346 ms | max: 1035.989 ms | kondemand/0:420 | 0.025 ms | 3 | avg: 421.332 ms | max: 964.014 ms | :5124:5124 | 0.103 ms | 5 | avg: 74.082 ms | max: 277.194 ms | :6244:6244 | 0.691 ms | 9 | avg: 125.655 ms | max: 271.306 ms | firefox:5080 | 0.924 ms | 5 | avg: 53.833 ms | max: 257.828 ms | npviewer.bin:6225 | 21.871 ms | 53 | avg: 22.462 ms | max: 220.835 ms | :6245:6245 | 9.631 ms | 21 | avg: 41.864 ms | max: 213.349 ms | After: ata/1:371 | 0.000 ms | 1 | avg: 3988.693 ms | max: 3988.693 ms | kondemand/1:421 | 0.096 ms | 3 | avg: 345.346 ms | max: 1035.989 ms | kondemand/0:420 | 0.025 ms | 3 | avg: 421.332 ms | max: 964.014 ms | firefox:5124 | 0.103 ms | 5 | avg: 74.082 ms | max: 277.194 ms | npviewer.bin:6244 | 0.691 ms | 9 | avg: 125.655 ms | max: 271.306 ms | firefox:5080 | 0.924 ms | 5 | avg: 53.833 ms | max: 257.828 ms | npviewer.bin:6225 | 21.871 ms | 53 | avg: 22.462 ms | max: 220.835 ms | npviewer.bin:6245 | 9.631 ms | 21 | avg: 41.864 ms | max: 213.349 ms | Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras LKML-Reference: <1255012632-7882-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/builtin-sched.c | 44 +++++++++++++++++++++++++++++++++++++++----- tools/perf/util/thread.c | 32 +++++++++++++++++++++++++------- tools/perf/util/thread.h | 3 +++ 3 files changed, 67 insertions(+), 12 deletions(-) (limited to 'tools/perf/util/thread.h') diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index e1df7055ab8..25b91e78433 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1034,6 +1034,36 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp) atoms->nb_atoms++; } +static struct thread * +threads__findnew_from_ctx(u32 pid, struct trace_switch_event *switch_event) +{ + struct thread *th; + + th = threads__findnew_nocomm(pid, &threads, &last_match); + if (th->comm) + return th; + + if (pid == switch_event->prev_pid) + thread__set_comm(th, switch_event->prev_comm); + else + thread__set_comm(th, switch_event->next_comm); + return th; +} + +static struct thread * +threads__findnew_from_wakeup(struct trace_wakeup_event *wakeup_event) +{ + struct thread *th; + + th = threads__findnew_nocomm(wakeup_event->pid, &threads, &last_match); + if (th->comm) + return th; + + thread__set_comm(th, wakeup_event->comm); + + return th; +} + static void latency_switch_event(struct trace_switch_event *switch_event, struct event *event __used, @@ -1059,8 +1089,10 @@ latency_switch_event(struct trace_switch_event *switch_event, die("hm, delta: %Ld < 0 ?\n", delta); - sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); - sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); + sched_out = threads__findnew_from_ctx(switch_event->prev_pid, + switch_event); + sched_in = threads__findnew_from_ctx(switch_event->next_pid, + switch_event); out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); if (!out_events) { @@ -1126,7 +1158,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event, if (!wakeup_event->success) return; - wakee = threads__findnew(wakeup_event->pid, &threads, &last_match); + wakee = threads__findnew_from_wakeup(wakeup_event); atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); if (!atoms) { thread_atoms_insert(wakee); @@ -1386,8 +1418,10 @@ map_switch_event(struct trace_switch_event *switch_event, die("hm, delta: %Ld < 0 ?\n", delta); - sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); - sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); + sched_out = threads__findnew_from_ctx(switch_event->prev_pid, + switch_event); + sched_in = threads__findnew_from_ctx(switch_event->next_pid, + switch_event); curr_thread[this_cpu] = sched_in; diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 3b56aebb1f4..8bd5ca2d2f2 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -6,15 +6,17 @@ #include "util.h" #include "debug.h" -static struct thread *thread__new(pid_t pid) +static struct thread *thread__new(pid_t pid, int set_comm) { struct thread *self = calloc(1, sizeof(*self)); if (self != NULL) { self->pid = pid; - self->comm = malloc(32); - if (self->comm) - snprintf(self->comm, 32, ":%d", self->pid); + if (set_comm) { + self->comm = malloc(32); + if (self->comm) + snprintf(self->comm, 32, ":%d", self->pid); + } self->maps = RB_ROOT; INIT_LIST_HEAD(&self->removed_maps); } @@ -50,8 +52,10 @@ static size_t thread__fprintf(struct thread *self, FILE *fp) return ret; } -struct thread * -threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) +static struct thread * +__threads__findnew(pid_t pid, struct rb_root *threads, + struct thread **last_match, + int set_comm) { struct rb_node **p = &threads->rb_node; struct rb_node *parent = NULL; @@ -80,7 +84,8 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) p = &(*p)->rb_right; } - th = thread__new(pid); + th = thread__new(pid, set_comm); + if (th != NULL) { rb_link_node(&th->rb_node, parent, p); rb_insert_color(&th->rb_node, threads); @@ -90,6 +95,19 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) return th; } +struct thread * +threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) +{ + return __threads__findnew(pid, threads, last_match, 1); +} + +struct thread * +threads__findnew_nocomm(pid_t pid, struct rb_root *threads, + struct thread **last_match) +{ + return __threads__findnew(pid, threads, last_match, 0); +} + struct thread * register_idle_thread(struct rb_root *threads, struct thread **last_match) { diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 845d9b62f96..75bc843950c 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -18,6 +18,9 @@ int thread__set_comm(struct thread *self, const char *comm); struct thread * threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); struct thread * +threads__findnew_nocomm(pid_t pid, struct rb_root *threads, + struct thread **last_match); +struct thread * register_idle_thread(struct rb_root *threads, struct thread **last_match); void thread__insert_map(struct thread *self, struct map *map); int thread__fork(struct thread *self, struct thread *parent); -- cgit v1.2.3-70-g09d2 From 97ea1a7fa62af0d8d49a0fc12796b0073537c9d8 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 8 Oct 2009 21:04:17 +0200 Subject: perf tools: Fix thread comm resolution in perf sched This reverts commit 9a92b479b2f088ee2d3194243f4c8e59b1b8c9c2 ("perf tools: Improve thread comm resolution in perf sched") and fixes the real bug. The bug was elsewhere: We are failing to resolve thread names in perf sched because the table of threads we are building, on top of comm events, has a per process granularity. But perf sched, unlike the other perf tools, needs a per thread granularity as we are profiling every tasks individually. So fix it by building our threads table using the tid instead of the pid as the thread identifier. v2: Revert the previous fix - it is not really needed Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras LKML-Reference: <1255028657-11158-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/builtin-sched.c | 46 ++++++---------------------------------------- tools/perf/util/thread.c | 32 +++++++------------------------- tools/perf/util/thread.h | 3 --- 3 files changed, 13 insertions(+), 68 deletions(-) (limited to 'tools/perf/util/thread.h') diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 25b91e78433..6b00529ce34 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -638,7 +638,7 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) { struct thread *thread; - thread = threads__findnew(event->comm.pid, &threads, &last_match); + thread = threads__findnew(event->comm.tid, &threads, &last_match); dump_printf("%p [%p]: perf_event_comm: %s:%d\n", (void *)(offset + head), @@ -1034,36 +1034,6 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp) atoms->nb_atoms++; } -static struct thread * -threads__findnew_from_ctx(u32 pid, struct trace_switch_event *switch_event) -{ - struct thread *th; - - th = threads__findnew_nocomm(pid, &threads, &last_match); - if (th->comm) - return th; - - if (pid == switch_event->prev_pid) - thread__set_comm(th, switch_event->prev_comm); - else - thread__set_comm(th, switch_event->next_comm); - return th; -} - -static struct thread * -threads__findnew_from_wakeup(struct trace_wakeup_event *wakeup_event) -{ - struct thread *th; - - th = threads__findnew_nocomm(wakeup_event->pid, &threads, &last_match); - if (th->comm) - return th; - - thread__set_comm(th, wakeup_event->comm); - - return th; -} - static void latency_switch_event(struct trace_switch_event *switch_event, struct event *event __used, @@ -1089,10 +1059,8 @@ latency_switch_event(struct trace_switch_event *switch_event, die("hm, delta: %Ld < 0 ?\n", delta); - sched_out = threads__findnew_from_ctx(switch_event->prev_pid, - switch_event); - sched_in = threads__findnew_from_ctx(switch_event->next_pid, - switch_event); + sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); + sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); if (!out_events) { @@ -1158,7 +1126,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event, if (!wakeup_event->success) return; - wakee = threads__findnew_from_wakeup(wakeup_event); + wakee = threads__findnew(wakeup_event->pid, &threads, &last_match); atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); if (!atoms) { thread_atoms_insert(wakee); @@ -1418,10 +1386,8 @@ map_switch_event(struct trace_switch_event *switch_event, die("hm, delta: %Ld < 0 ?\n", delta); - sched_out = threads__findnew_from_ctx(switch_event->prev_pid, - switch_event); - sched_in = threads__findnew_from_ctx(switch_event->next_pid, - switch_event); + sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); + sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); curr_thread[this_cpu] = sched_in; diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 8bd5ca2d2f2..3b56aebb1f4 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -6,17 +6,15 @@ #include "util.h" #include "debug.h" -static struct thread *thread__new(pid_t pid, int set_comm) +static struct thread *thread__new(pid_t pid) { struct thread *self = calloc(1, sizeof(*self)); if (self != NULL) { self->pid = pid; - if (set_comm) { - self->comm = malloc(32); - if (self->comm) - snprintf(self->comm, 32, ":%d", self->pid); - } + self->comm = malloc(32); + if (self->comm) + snprintf(self->comm, 32, ":%d", self->pid); self->maps = RB_ROOT; INIT_LIST_HEAD(&self->removed_maps); } @@ -52,10 +50,8 @@ static size_t thread__fprintf(struct thread *self, FILE *fp) return ret; } -static struct thread * -__threads__findnew(pid_t pid, struct rb_root *threads, - struct thread **last_match, - int set_comm) +struct thread * +threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) { struct rb_node **p = &threads->rb_node; struct rb_node *parent = NULL; @@ -84,8 +80,7 @@ __threads__findnew(pid_t pid, struct rb_root *threads, p = &(*p)->rb_right; } - th = thread__new(pid, set_comm); - + th = thread__new(pid); if (th != NULL) { rb_link_node(&th->rb_node, parent, p); rb_insert_color(&th->rb_node, threads); @@ -95,19 +90,6 @@ __threads__findnew(pid_t pid, struct rb_root *threads, return th; } -struct thread * -threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) -{ - return __threads__findnew(pid, threads, last_match, 1); -} - -struct thread * -threads__findnew_nocomm(pid_t pid, struct rb_root *threads, - struct thread **last_match) -{ - return __threads__findnew(pid, threads, last_match, 0); -} - struct thread * register_idle_thread(struct rb_root *threads, struct thread **last_match) { diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 75bc843950c..845d9b62f96 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -18,9 +18,6 @@ int thread__set_comm(struct thread *self, const char *comm); struct thread * threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); struct thread * -threads__findnew_nocomm(pid_t pid, struct rb_root *threads, - struct thread **last_match); -struct thread * register_idle_thread(struct rb_root *threads, struct thread **last_match); void thread__insert_map(struct thread *self, struct map *map); int thread__fork(struct thread *self, struct thread *parent); -- cgit v1.2.3-70-g09d2 From d5b889f2ecec7849e851ddd31c34bdfb3482b5de Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 13 Oct 2009 11:16:29 -0300 Subject: perf tools: Move threads & last_match to threads.c This was just being copy'n'pasted all over. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Mike Galbraith LKML-Reference: <20091013141629.GD21809@ghostprotocols.net> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 25 +++++++------------------ tools/perf/builtin-report.c | 26 +++++++------------------- tools/perf/builtin-sched.c | 30 +++++++++++------------------- tools/perf/builtin-trace.c | 13 +++---------- tools/perf/util/thread.c | 27 ++++++++++++++------------- tools/perf/util/thread.h | 8 +++----- 6 files changed, 45 insertions(+), 84 deletions(-) (limited to 'tools/perf/util/thread.h') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 8c84320ecb0..3fe0de03004 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -37,10 +37,6 @@ static int print_line; static unsigned long page_size; static unsigned long mmap_window = 32; -static struct rb_root threads; -static struct thread *last_match; - - struct sym_ext { struct rb_node node; double percent; @@ -96,12 +92,10 @@ static int process_sample_event(event_t *event, unsigned long offset, unsigned long head) { char level; - struct thread *thread; u64 ip = event->ip.ip; struct map *map = NULL; struct symbol *sym = NULL; - - thread = threads__findnew(event->ip.pid, &threads, &last_match); + struct thread *thread = threads__findnew(event->ip.pid); dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", (void *)(offset + head), @@ -166,10 +160,8 @@ got_map: static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread; struct map *map = map__new(&event->mmap, NULL, 0); - - thread = threads__findnew(event->mmap.pid, &threads, &last_match); + struct thread *thread = threads__findnew(event->mmap.pid); dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), @@ -194,9 +186,8 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread; + struct thread *thread = threads__findnew(event->comm.pid); - thread = threads__findnew(event->comm.pid, &threads, &last_match); dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -215,11 +206,9 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) static int process_fork_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread; - struct thread *parent; + struct thread *thread = threads__findnew(event->fork.pid); + struct thread *parent = threads__findnew(event->fork.ppid); - thread = threads__findnew(event->fork.pid, &threads, &last_match); - parent = threads__findnew(event->fork.ppid, &threads, &last_match); dump_printf("%p [%p]: PERF_RECORD_FORK: %d:%d\n", (void *)(offset + head), (void *)(long)(event->header.size), @@ -558,7 +547,7 @@ static int __cmd_annotate(void) uint32_t size; char *buf; - register_idle_thread(&threads, &last_match); + register_idle_thread(); input = open(input_name, O_RDONLY); if (input < 0) { @@ -659,7 +648,7 @@ more: return 0; if (verbose > 3) - threads__fprintf(stdout, &threads); + threads__fprintf(stdout); if (verbose > 2) dsos__fprintf(stdout); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index f57a23b19f3..015c7974596 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -55,9 +55,6 @@ static char callchain_default_opt[] = "fractal,0.5"; static char *cwd; static int cwdlen; -static struct rb_root threads; -static struct thread *last_match; - static struct perf_header *header; static u64 sample_type; @@ -593,15 +590,13 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) { char level; struct symbol *sym = NULL; - struct thread *thread; u64 ip = event->ip.ip; u64 period = 1; struct map *map = NULL; void *more_data = event->ip.__more_data; struct ip_callchain *chain = NULL; int cpumode; - - thread = threads__findnew(event->ip.pid, &threads, &last_match); + struct thread *thread = threads__findnew(event->ip.pid); if (sample_type & PERF_SAMPLE_PERIOD) { period = *(u64 *)more_data; @@ -685,10 +680,8 @@ 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 thread *thread; struct map *map = map__new(&event->mmap, cwd, cwdlen); - - thread = threads__findnew(event->mmap.pid, &threads, &last_match); + 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), @@ -714,9 +707,7 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread; - - thread = threads__findnew(event->comm.pid, &threads, &last_match); + struct thread *thread = threads__findnew(event->comm.pid); dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", (void *)(offset + head), @@ -736,11 +727,8 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) static int process_task_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread; - struct thread *parent; - - thread = threads__findnew(event->fork.pid, &threads, &last_match); - parent = threads__findnew(event->fork.ppid, &threads, &last_match); + 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), @@ -857,7 +845,7 @@ static int __cmd_report(void) struct thread *idle; int ret; - idle = register_idle_thread(&threads, &last_match); + idle = register_idle_thread(); thread__comm_adjust(idle); if (show_threads) @@ -881,7 +869,7 @@ static int __cmd_report(void) return 0; if (verbose > 3) - threads__fprintf(stdout, &threads); + threads__fprintf(stdout); if (verbose > 2) dsos__fprintf(stdout); diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 387a4423436..73bdad02973 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -24,9 +24,6 @@ static char const *input_name = "perf.data"; static unsigned long total_comm = 0; -static struct rb_root threads; -static struct thread *last_match; - static struct perf_header *header; static u64 sample_type; @@ -641,9 +638,7 @@ static void test_calibrations(void) static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread; - - thread = threads__findnew(event->comm.tid, &threads, &last_match); + struct thread *thread = threads__findnew(event->comm.tid); dump_printf("%p [%p]: perf_event_comm: %s:%d\n", (void *)(offset + head), @@ -1086,8 +1081,8 @@ latency_switch_event(struct trace_switch_event *switch_event, die("hm, delta: %Ld < 0 ?\n", delta); - sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); - sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); + sched_out = threads__findnew(switch_event->prev_pid); + sched_in = threads__findnew(switch_event->next_pid); out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); if (!out_events) { @@ -1120,13 +1115,10 @@ latency_runtime_event(struct trace_runtime_event *runtime_event, u64 timestamp, struct thread *this_thread __used) { - struct work_atoms *atoms; - struct thread *thread; + struct thread *thread = threads__findnew(runtime_event->pid); + struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); BUG_ON(cpu >= MAX_CPUS || cpu < 0); - - thread = threads__findnew(runtime_event->pid, &threads, &last_match); - atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); if (!atoms) { thread_atoms_insert(thread); atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); @@ -1153,7 +1145,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event, if (!wakeup_event->success) return; - wakee = threads__findnew(wakeup_event->pid, &threads, &last_match); + wakee = threads__findnew(wakeup_event->pid); atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); if (!atoms) { thread_atoms_insert(wakee); @@ -1202,7 +1194,7 @@ latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event, if (profile_cpu == -1) return; - migrant = threads__findnew(migrate_task_event->pid, &threads, &last_match); + migrant = threads__findnew(migrate_task_event->pid); atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid); if (!atoms) { thread_atoms_insert(migrant); @@ -1458,8 +1450,8 @@ map_switch_event(struct trace_switch_event *switch_event, die("hm, delta: %Ld < 0 ?\n", delta); - sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); - sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); + sched_out = threads__findnew(switch_event->prev_pid); + sched_in = threads__findnew(switch_event->next_pid); curr_thread[this_cpu] = sched_in; @@ -1649,7 +1641,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) if (!(sample_type & PERF_SAMPLE_RAW)) return 0; - thread = threads__findnew(event->ip.pid, &threads, &last_match); + thread = threads__findnew(event->ip.pid); if (sample_type & PERF_SAMPLE_TIME) { timestamp = *(u64 *)more_data; @@ -1725,7 +1717,7 @@ static struct perf_file_handler file_handler = { static int read_events(void) { - register_idle_thread(&threads, &last_match); + register_idle_thread(); register_perf_file_handler(&file_handler); return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd); diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index fb3f3c22021..ccf867dbab5 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -19,9 +19,6 @@ static char const *input_name = "perf.data"; static unsigned long total = 0; static unsigned long total_comm = 0; -static struct rb_root threads; -static struct thread *last_match; - static struct perf_header *header; static u64 sample_type; @@ -32,9 +29,7 @@ static int cwdlen; static int process_comm_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread; - - thread = threads__findnew(event->comm.pid, &threads, &last_match); + struct thread *thread = threads__findnew(event->comm.pid); dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", (void *)(offset + head), @@ -54,14 +49,12 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) static int process_sample_event(event_t *event, unsigned long offset, unsigned long head) { - struct thread *thread; u64 ip = event->ip.ip; u64 timestamp = -1; u32 cpu = -1; u64 period = 1; void *more_data = event->ip.__more_data; - - thread = threads__findnew(event->ip.pid, &threads, &last_match); + struct thread *thread = threads__findnew(event->ip.pid); if (sample_type & PERF_SAMPLE_TIME) { timestamp = *(u64 *)more_data; @@ -135,7 +128,7 @@ static struct perf_file_handler file_handler = { static int __cmd_trace(void) { - register_idle_thread(&threads, &last_match); + register_idle_thread(); register_perf_file_handler(&file_handler); return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 3b56aebb1f4..f53fad7c0a8 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -6,6 +6,9 @@ #include "util.h" #include "debug.h" +static struct rb_root threads; +static struct thread *last_match; + static struct thread *thread__new(pid_t pid) { struct thread *self = calloc(1, sizeof(*self)); @@ -50,10 +53,9 @@ static size_t thread__fprintf(struct thread *self, FILE *fp) return ret; } -struct thread * -threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) +struct thread *threads__findnew(pid_t pid) { - struct rb_node **p = &threads->rb_node; + struct rb_node **p = &threads.rb_node; struct rb_node *parent = NULL; struct thread *th; @@ -62,15 +64,15 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) * so most of the time we dont have to look up * the full rbtree: */ - if (*last_match && (*last_match)->pid == pid) - return *last_match; + if (last_match && last_match->pid == pid) + return last_match; while (*p != NULL) { parent = *p; th = rb_entry(parent, struct thread, rb_node); if (th->pid == pid) { - *last_match = th; + last_match = th; return th; } @@ -83,17 +85,16 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match) th = thread__new(pid); if (th != NULL) { rb_link_node(&th->rb_node, parent, p); - rb_insert_color(&th->rb_node, threads); - *last_match = th; + rb_insert_color(&th->rb_node, &threads); + last_match = th; } return th; } -struct thread * -register_idle_thread(struct rb_root *threads, struct thread **last_match) +struct thread *register_idle_thread(void) { - struct thread *thread = threads__findnew(0, threads, last_match); + struct thread *thread = threads__findnew(0); if (!thread || thread__set_comm(thread, "swapper")) { fprintf(stderr, "problem inserting idle task.\n"); @@ -197,12 +198,12 @@ int thread__fork(struct thread *self, struct thread *parent) return 0; } -size_t threads__fprintf(FILE *fp, struct rb_root *threads) +size_t threads__fprintf(FILE *fp) { size_t ret = 0; struct rb_node *nd; - for (nd = rb_first(threads); nd; nd = rb_next(nd)) { + for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { struct thread *pos = rb_entry(nd, struct thread, rb_node); ret += thread__fprintf(pos, fp); diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 845d9b62f96..1abef3b7455 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -15,13 +15,11 @@ struct thread { }; int thread__set_comm(struct thread *self, const char *comm); -struct thread * -threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); -struct thread * -register_idle_thread(struct rb_root *threads, struct thread **last_match); +struct thread *threads__findnew(pid_t pid); +struct thread *register_idle_thread(void); void thread__insert_map(struct thread *self, struct map *map); int thread__fork(struct thread *self, struct thread *parent); -size_t threads__fprintf(FILE *fp, struct rb_root *threads); +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); -- cgit v1.2.3-70-g09d2 From a4fb581b15949cfd10b64c8af37bc106e95307f3 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 22 Oct 2009 23:23:23 +0200 Subject: perf tools: Bind callchains to the first sort dimension column Currently, the callchains are displayed using a constant left margin. So depending on the current sort dimension configuration, callchains may appear to be well attached to the first sort dimension column field which is mostly the case, except when the first dimension of sorting is done by comm, because these are right aligned. This patch binds the callchain to the first letter in the first column, whatever type of column it is (dso, comm, symbol). Before: 0.80% perf [k] __lock_acquire __lock_acquire lock_acquire | |--58.33%-- _spin_lock | | | |--28.57%-- inotify_should_send_event | | fsnotify | | __fsnotify_parent After: 0.80% perf [k] __lock_acquire __lock_acquire lock_acquire | |--58.33%-- _spin_lock | | | |--28.57%-- inotify_should_send_event | | fsnotify | | __fsnotify_parent Also, for clarity, we don't put anymore the callchain as is but: - If we have a top level ancestor in the callchain, start it with a first ascii hook. Before: 0.80% perf [kernel] [k] __lock_acquire __lock_acquire lock_acquire | |--58.33%-- _spin_lock | | | |--28.57%-- inotify_should_send_event | | fsnotify [..] [..] After: 0.80% perf [kernel] [k] __lock_acquire | --- __lock_acquire lock_acquire | |--58.33%-- _spin_lock | | | |--28.57%-- inotify_should_send_event | | fsnotify [..] [..] - Otherwise, if we have several top level ancestors, then display these like we did before: 1.69% Xorg | |--21.21%-- vread_hpet | 0x7fffd85b46fc | 0x7fffd85b494d | 0x7f4fafb4e54d | |--15.15%-- exaOffscreenAlloc | |--9.09%-- I830WaitLpRing Signed-off-by: Frederic Weisbecker Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Mike Galbraith Cc: Paul Mackerras Cc: Anton Blanchard LKML-Reference: <1256246604-17156-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar --- tools/perf/builtin-report.c | 82 ++++++++++++++++++++++++++++++++++----------- tools/perf/util/sort.c | 18 +++++++--- tools/perf/util/sort.h | 10 +++++- tools/perf/util/thread.c | 11 ++++++ tools/perf/util/thread.h | 2 ++ 5 files changed, 99 insertions(+), 24 deletions(-) (limited to 'tools/perf/util/thread.h') diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 3d8c52220f1..72d58421223 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -59,12 +59,28 @@ static struct perf_header *header; static u64 sample_type; -static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask) + +static size_t +callchain__fprintf_left_margin(FILE *fp, int left_margin) +{ + int i; + int ret; + + ret = fprintf(fp, " "); + + for (i = 0; i < left_margin; i++) + ret += fprintf(fp, " "); + + return ret; +} + +static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask, + int left_margin) { int i; size_t ret = 0; - ret += fprintf(fp, "%s", " "); + ret += callchain__fprintf_left_margin(fp, left_margin); for (i = 0; i < depth; i++) if (depth_mask & (1 << i)) @@ -79,12 +95,12 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask) static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth, int depth_mask, int count, u64 total_samples, - int hits) + int hits, int left_margin) { int i; size_t ret = 0; - ret += fprintf(fp, "%s", " "); + ret += callchain__fprintf_left_margin(fp, left_margin); for (i = 0; i < depth; i++) { if (depth_mask & (1 << i)) ret += fprintf(fp, "|"); @@ -123,7 +139,8 @@ static void init_rem_hits(void) static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, - u64 total_samples, int depth, int depth_mask) + u64 total_samples, int depth, int depth_mask, + int left_margin) { struct rb_node *node, *next; struct callchain_node *child; @@ -164,7 +181,8 @@ __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, * But we keep the older depth mask for the line seperator * to keep the level link until we reach the last child */ - ret += ipchain__fprintf_graph_line(fp, depth, depth_mask); + ret += ipchain__fprintf_graph_line(fp, depth, depth_mask, + left_margin); i = 0; list_for_each_entry(chain, &child->val, list) { if (chain->ip >= PERF_CONTEXT_MAX) @@ -172,11 +190,13 @@ __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, ret += ipchain__fprintf_graph(fp, chain, depth, new_depth_mask, i++, new_total, - cumul); + cumul, + left_margin); } ret += __callchain__fprintf_graph(fp, child, new_total, depth + 1, - new_depth_mask | (1 << depth)); + new_depth_mask | (1 << depth), + left_margin); node = next; } @@ -190,17 +210,19 @@ __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, ret += ipchain__fprintf_graph(fp, &rem_hits, depth, new_depth_mask, 0, new_total, - remaining); + remaining, left_margin); } return ret; } + static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self, - u64 total_samples) + u64 total_samples, int left_margin) { struct callchain_list *chain; + bool printed = false; int i = 0; int ret = 0; @@ -208,17 +230,27 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, if (chain->ip >= PERF_CONTEXT_MAX) continue; - if (!i++ && sort_by_sym_first) + if (!i++ && sort__first_dimension == SORT_SYM) continue; + if (!printed) { + ret += callchain__fprintf_left_margin(fp, left_margin); + ret += fprintf(fp, "|\n"); + ret += callchain__fprintf_left_margin(fp, left_margin); + ret += fprintf(fp, "---"); + + left_margin += 3; + printed = true; + } else + ret += callchain__fprintf_left_margin(fp, left_margin); + if (chain->sym) - ret += fprintf(fp, " %s\n", chain->sym->name); + ret += fprintf(fp, " %s\n", chain->sym->name); else - ret += fprintf(fp, " %p\n", - (void *)(long)chain->ip); + ret += fprintf(fp, " %p\n", (void *)(long)chain->ip); } - ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1); + ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin); return ret; } @@ -251,7 +283,7 @@ callchain__fprintf_flat(FILE *fp, struct callchain_node *self, static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, - u64 total_samples) + u64 total_samples, int left_margin) { struct rb_node *rb_node; struct callchain_node *chain; @@ -271,7 +303,8 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, break; case CHAIN_GRAPH_ABS: /* Falldown */ case CHAIN_GRAPH_REL: - ret += callchain__fprintf_graph(fp, chain, total_samples); + ret += callchain__fprintf_graph(fp, chain, total_samples, + left_margin); case CHAIN_NONE: default: break; @@ -316,8 +349,19 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples) ret += fprintf(fp, "\n"); - if (callchain) - hist_entry_callchain__fprintf(fp, self, total_samples); + if (callchain) { + int left_margin = 0; + + if (sort__first_dimension == SORT_COMM) { + se = list_first_entry(&hist_entry__sort_list, typeof(*se), + list); + left_margin = se->width ? *se->width : 0; + left_margin -= thread__comm_len(self->thread); + } + + hist_entry_callchain__fprintf(fp, self, total_samples, + left_margin); + } return ret; } diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 60ced707bd6..b490354d1b2 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -7,7 +7,8 @@ char default_sort_order[] = "comm,dso,symbol"; char *sort_order = default_sort_order; int sort__need_collapse = 0; int sort__has_parent = 0; -int sort_by_sym_first; + +enum sort_type sort__first_dimension; unsigned int dsos__col_width; unsigned int comms__col_width; @@ -266,9 +267,18 @@ int sort_dimension__add(const char *tok) sort__has_parent = 1; } - if (list_empty(&hist_entry__sort_list) && - !strcmp(sd->name, "symbol")) - sort_by_sym_first = true; + if (list_empty(&hist_entry__sort_list)) { + if (!strcmp(sd->name, "pid")) + sort__first_dimension = SORT_PID; + else if (!strcmp(sd->name, "comm")) + sort__first_dimension = SORT_COMM; + else if (!strcmp(sd->name, "dso")) + sort__first_dimension = SORT_DSO; + else if (!strcmp(sd->name, "symbol")) + sort__first_dimension = SORT_SYM; + else if (!strcmp(sd->name, "parent")) + sort__first_dimension = SORT_PARENT; + } list_add_tail(&sd->entry->list, &hist_entry__sort_list); sd->taken = 1; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 24c2b709f0d..333e664ff45 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -39,7 +39,7 @@ extern struct sort_entry sort_parent; extern unsigned int dsos__col_width; extern unsigned int comms__col_width; extern unsigned int threads__col_width; -extern int sort_by_sym_first; +extern enum sort_type sort__first_dimension; struct hist_entry { struct rb_node rb_node; @@ -54,6 +54,14 @@ struct hist_entry { struct rb_root sorted_chain; }; +enum sort_type { + SORT_PID, + SORT_COMM, + SORT_DSO, + SORT_SYM, + SORT_PARENT +}; + /* * configurable sorting bits */ diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index f53fad7c0a8..8cb47f1d8a7 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -33,6 +33,17 @@ int thread__set_comm(struct thread *self, const char *comm) return self->comm ? 0 : -ENOMEM; } +int thread__comm_len(struct thread *self) +{ + if (!self->comm_len) { + if (!self->comm) + return 0; + self->comm_len = strlen(self->comm); + } + + return self->comm_len; +} + static size_t thread__fprintf(struct thread *self, FILE *fp) { struct rb_node *nd; diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 1abef3b7455..53addd77ce8 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -12,9 +12,11 @@ struct thread { pid_t pid; char shortname[3]; char *comm; + int comm_len; }; int thread__set_comm(struct thread *self, const char *comm); +int thread__comm_len(struct thread *self); struct thread *threads__findnew(pid_t pid); struct thread *register_idle_thread(void); void thread__insert_map(struct thread *self, struct map *map); -- 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/thread.h') 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 fcf1203a919c3a3d212c0ed01f5240fd592bf5ae Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 24 Nov 2009 13:01:52 -0200 Subject: perf symbols: Rename find_symbol routines to find_function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Paving the way for supporting variable in adition to function symbols. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1259074912-5924-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 4 +-- tools/perf/builtin-kmem.c | 3 +- tools/perf/builtin-report.c | 8 ++--- tools/perf/builtin-top.c | 4 +-- tools/perf/util/event.h | 7 +++-- tools/perf/util/map.c | 14 ++++----- tools/perf/util/symbol.c | 68 +++++++++++++++++++++++-------------------- tools/perf/util/symbol.h | 6 ++-- tools/perf/util/thread.h | 4 +-- 9 files changed, 62 insertions(+), 56 deletions(-) (limited to 'tools/perf/util/thread.h') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index cd97c2b1cc3..18ac5eaefc3 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -162,7 +162,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, symbol_filter); + sym = kernel_maps__find_function(ip, &map, symbol_filter); dump_printf(" ...... dso: %s\n", map ? map->dso->long_name : ""); } else if (event->header.misc & PERF_RECORD_MISC_USER) { @@ -171,7 +171,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) if (map != NULL) { got_map: ip = map->map_ip(map, ip); - sym = map__find_symbol(map, ip, symbol_filter); + sym = map__find_function(map, ip, symbol_filter); } else { /* * If this is outside of all known maps, diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 330dbc762f9..35722fafc4d 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -445,8 +445,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller) if (is_caller) { addr = data->call_site; if (!raw_ip) - sym = kernel_maps__find_symbol(addr, - NULL, NULL); + sym = kernel_maps__find_function(addr, NULL, NULL); } else addr = data->ptr; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 0ee3d05a040..e4b1004e76e 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -448,14 +448,14 @@ got_map: * trick of looking in the whole kernel symbol list. */ if ((long long)ip < 0) - return kernel_maps__find_symbol(ip, mapp, NULL); + return kernel_maps__find_function(ip, mapp, NULL); } dump_printf(" ...... dso: %s\n", map ? map->dso->long_name : ""); dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip); *ipp = ip; - return map ? map__find_symbol(map, ip, NULL) : NULL; + return map ? map__find_function(map, ip, NULL) : NULL; } static int call__match(struct symbol *sym) @@ -495,7 +495,7 @@ static struct symbol **resolve_callchain(struct thread *thread, case PERF_CONTEXT_HV: break; case PERF_CONTEXT_KERNEL: - sym = kernel_maps__find_symbol(ip, NULL, NULL); + sym = kernel_maps__find_function(ip, NULL, NULL); break; default: sym = resolve_symbol(thread, NULL, &ip); @@ -715,7 +715,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, NULL); + sym = kernel_maps__find_function(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 4c8653a86aa..ded6cf65ad9 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -948,7 +948,7 @@ static void event__process_sample(const event_t *self, int counter) map = thread__find_map(thread, ip); if (map != NULL) { ip = map->map_ip(map, ip); - sym = map__find_symbol(map, ip, symbol_filter); + sym = map__find_function(map, ip, symbol_filter); if (sym == NULL) return; userspace_samples++; @@ -968,7 +968,7 @@ static void event__process_sample(const event_t *self, int counter) if (hide_kernel_symbols) return; - sym = kernel_maps__find_symbol(ip, &map, symbol_filter); + sym = kernel_maps__find_function(ip, &map, symbol_filter); if (sym == NULL) return; break; diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index f1e39261265..882a9531db9 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -119,9 +119,10 @@ 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); +struct symbol *map__find_function(struct map *self, u64 ip, + symbol_filter_t filter); +void map__fixup_start(struct map *self, struct rb_root *symbols); +void map__fixup_end(struct map *self, struct rb_root *symbols); 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/map.c b/tools/perf/util/map.c index 09412321a80..41c5c4a2001 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -80,18 +80,18 @@ void map__delete(struct map *self) free(self); } -void map__fixup_start(struct map *self) +void map__fixup_start(struct map *self, struct rb_root *symbols) { - struct rb_node *nd = rb_first(&self->dso->syms); + struct rb_node *nd = rb_first(symbols); if (nd != NULL) { struct symbol *sym = rb_entry(nd, struct symbol, rb_node); self->start = sym->start; } } -void map__fixup_end(struct map *self) +void map__fixup_end(struct map *self, struct rb_root *symbols) { - struct rb_node *nd = rb_last(&self->dso->syms); + struct rb_node *nd = rb_last(symbols); if (nd != NULL) { struct symbol *sym = rb_entry(nd, struct symbol, rb_node); self->end = sym->end; @@ -100,8 +100,8 @@ void map__fixup_end(struct map *self) #define DSO__DELETED "(deleted)" -struct symbol * -map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter) +struct symbol *map__find_function(struct map *self, u64 ip, + symbol_filter_t filter) { if (!self->dso->loaded) { int nr = dso__load(self->dso, self, filter); @@ -136,7 +136,7 @@ map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter) } } - return self->dso->find_symbol(self->dso, ip); + return self->dso->find_function(self->dso, ip); } struct map *map__clone(struct map *self) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 8db85b4f553..4ed379b915f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -45,9 +45,9 @@ static struct symbol_conf symbol_conf__defaults = { static struct rb_root kernel_maps; -static void dso__fixup_sym_end(struct dso *self) +static void symbols__fixup_end(struct rb_root *self) { - struct rb_node *nd, *prevnd = rb_first(&self->syms); + struct rb_node *nd, *prevnd = rb_first(self); struct symbol *curr, *prev; if (prevnd == NULL) @@ -144,8 +144,8 @@ struct dso *dso__new(const char *name) strcpy(self->name, name); dso__set_long_name(self, self->name); self->short_name = self->name; - self->syms = RB_ROOT; - self->find_symbol = dso__find_symbol; + self->functions = RB_ROOT; + self->find_function = dso__find_function; self->slen_calculated = 0; self->origin = DSO__ORIG_NOT_FOUND; self->loaded = 0; @@ -155,22 +155,22 @@ struct dso *dso__new(const char *name) return self; } -static void dso__delete_symbols(struct dso *self) +static void symbols__delete(struct rb_root *self) { struct symbol *pos; - struct rb_node *next = rb_first(&self->syms); + struct rb_node *next = rb_first(self); while (next) { pos = rb_entry(next, struct symbol, rb_node); next = rb_next(&pos->rb_node); - rb_erase(&pos->rb_node, &self->syms); + rb_erase(&pos->rb_node, self); symbol__delete(pos); } } void dso__delete(struct dso *self) { - dso__delete_symbols(self); + symbols__delete(&self->functions); if (self->long_name != self->name) free(self->long_name); free(self); @@ -182,9 +182,9 @@ void dso__set_build_id(struct dso *self, void *build_id) self->has_build_id = 1; } -static void dso__insert_symbol(struct dso *self, struct symbol *sym) +static void symbols__insert(struct rb_root *self, struct symbol *sym) { - struct rb_node **p = &self->syms.rb_node; + struct rb_node **p = &self->rb_node; struct rb_node *parent = NULL; const u64 ip = sym->start; struct symbol *s; @@ -198,17 +198,17 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym) p = &(*p)->rb_right; } rb_link_node(&sym->rb_node, parent, p); - rb_insert_color(&sym->rb_node, &self->syms); + rb_insert_color(&sym->rb_node, self); } -struct symbol *dso__find_symbol(struct dso *self, u64 ip) +static struct symbol *symbols__find(struct rb_root *self, u64 ip) { struct rb_node *n; if (self == NULL) return NULL; - n = self->syms.rb_node; + n = self->rb_node; while (n) { struct symbol *s = rb_entry(n, struct symbol, rb_node); @@ -224,6 +224,11 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip) return NULL; } +struct symbol *dso__find_function(struct dso *self, u64 ip) +{ + return symbols__find(&self->functions, ip); +} + int build_id__sprintf(u8 *self, int len, char *bf) { char *bid = bf; @@ -253,9 +258,9 @@ size_t dso__fprintf(struct dso *self, FILE *fp) size_t ret = fprintf(fp, "dso: %s (", self->short_name); ret += dso__fprintf_buildid(self, fp); - ret += fprintf(fp, ")\n"); + ret += fprintf(fp, ")\nFunctions:\n"); - for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { + for (nd = rb_first(&self->functions); nd; nd = rb_next(nd)) { struct symbol *pos = rb_entry(nd, struct symbol, rb_node); ret += symbol__fprintf(pos, fp); } @@ -320,7 +325,7 @@ static int kernel_maps__load_all_kallsyms(void) * kernel_maps__split_kallsyms, when we have split the * maps per module */ - dso__insert_symbol(kernel_map->dso, sym); + symbols__insert(&kernel_map->dso->functions, sym); } free(line); @@ -344,7 +349,7 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter) struct map *map = kernel_map; struct symbol *pos; int count = 0; - struct rb_node *next = rb_first(&kernel_map->dso->syms); + struct rb_node *next = rb_first(&kernel_map->dso->functions); int kernel_range = 0; while (next) { @@ -394,12 +399,13 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter) } if (filter && filter(map, pos)) { - rb_erase(&pos->rb_node, &kernel_map->dso->syms); + rb_erase(&pos->rb_node, &kernel_map->dso->functions); symbol__delete(pos); } else { if (map != kernel_map) { - rb_erase(&pos->rb_node, &kernel_map->dso->syms); - dso__insert_symbol(map->dso, pos); + rb_erase(&pos->rb_node, + &kernel_map->dso->functions); + symbols__insert(&map->dso->functions, pos); } count++; } @@ -414,7 +420,7 @@ 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); + symbols__fixup_end(&kernel_map->dso->functions); kernel_map->dso->origin = DSO__ORIG_KERNEL; return kernel_maps__split_kallsyms(filter); @@ -485,7 +491,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map, if (filter && filter(map, sym)) symbol__delete(sym); else { - dso__insert_symbol(self, sym); + symbols__insert(&self->functions, sym); nr_syms++; } } @@ -683,7 +689,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, if (filter && filter(map, f)) symbol__delete(f); else { - dso__insert_symbol(self, f); + symbols__insert(&self->functions, f); ++nr; } } @@ -705,7 +711,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, if (filter && filter(map, f)) symbol__delete(f); else { - dso__insert_symbol(self, f); + symbols__insert(&self->functions, f); ++nr; } } @@ -879,7 +885,7 @@ new_symbol: if (filter && filter(curr_map, f)) symbol__delete(f); else { - dso__insert_symbol(curr_dso, f); + symbols__insert(&curr_dso->functions, f); nr++; } } @@ -888,7 +894,7 @@ new_symbol: * For misannotated, zeroed, ASM function sizes. */ if (nr > 0) - dso__fixup_sym_end(self); + symbols__fixup_end(&self->functions); err = nr; out_elf_end: elf_end(elf); @@ -1160,8 +1166,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, - symbol_filter_t filter) +struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp, + symbol_filter_t filter) { struct map *map = maps__find(&kernel_maps, ip); @@ -1170,7 +1176,7 @@ 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); + return map__find_function(map, ip, filter); } else WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps), "Empty kernel_maps, was symbol__init() called?\n"); @@ -1432,8 +1438,8 @@ do_kallsyms: if (err > 0) { out_fixup: - map__fixup_start(map); - map__fixup_end(map); + map__fixup_start(map, &map->dso->functions); + map__fixup_end(map, &map->dso->functions); } return err; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 5538691494a..65846d0c5df 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -65,8 +65,8 @@ static inline void *symbol__priv(struct symbol *self) struct dso { struct list_head node; - struct rb_root syms; - struct symbol *(*find_symbol)(struct dso *, u64 ip); + struct rb_root functions; + struct symbol *(*find_function)(struct dso *, u64 ip); u8 adjust_symbols:1; u8 slen_calculated:1; u8 loaded:1; @@ -83,7 +83,7 @@ struct dso { struct dso *dso__new(const char *name); void dso__delete(struct dso *self); -struct symbol *dso__find_symbol(struct dso *self, u64 ip); +struct symbol *dso__find_function(struct dso *self, u64 ip); struct dso *dsos__findnew(const char *name); int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index e4b8d437725..74cba6487ed 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -26,8 +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, - symbol_filter_t filter); +struct symbol *kernel_maps__find_function(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 23ea4a3fadc6b1692dec935397ea15e2affc1cba Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 27 Nov 2009 16:29:19 -0200 Subject: perf symbols: Kernel_maps should be an array of MAP__NR_TYPES entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So that we can support multiple symbol table types. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1259346563-12568-8-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 51 ++++++++++++++++++++++++++++++++++++------------ tools/perf/util/thread.h | 1 - 2 files changed, 38 insertions(+), 14 deletions(-) (limited to 'tools/perf/util/thread.h') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 956656fcaab..581db4c4325 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -29,6 +29,7 @@ enum dso_origin { }; static void dsos__add(struct list_head *head, struct dso *dso); +static struct map *kernel_maps__find_by_dso_name(const char *name); static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); static void kernel_maps__insert(struct map *map); struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); @@ -43,7 +44,7 @@ static struct symbol_conf symbol_conf__defaults = { .try_vmlinux_path = true, }; -static struct rb_root kernel_maps__functions; +static struct rb_root kernel_maps[MAP__NR_TYPES]; bool dso__loaded(const struct dso *self, enum map_type type) { @@ -78,10 +79,10 @@ static void symbols__fixup_end(struct rb_root *self) curr->end = roundup(curr->start, 4096); } -static void kernel_maps__fixup_end(void) +static void __kernel_maps__fixup_end(struct rb_root *root) { struct map *prev, *curr; - struct rb_node *nd, *prevnd = rb_first(&kernel_maps__functions); + struct rb_node *nd, *prevnd = rb_first(root); if (prevnd == NULL) return; @@ -101,6 +102,13 @@ static void kernel_maps__fixup_end(void) curr->end = ~0UL; } +static void kernel_maps__fixup_end(void) +{ + int i; + for (i = 0; i < MAP__NR_TYPES; ++i) + __kernel_maps__fixup_end(&kernel_maps[i]); +} + static struct symbol *symbol__new(u64 start, u64 len, const char *name) { size_t namelen = strlen(name) + 1; @@ -449,12 +457,12 @@ static int dso__load_kallsyms(struct dso *self, struct map *map, return dso__split_kallsyms(self, map, filter); } -size_t kernel_maps__fprintf(FILE *fp) +static size_t __kernel_maps__fprintf(enum map_type type, FILE *fp) { - size_t printed = fprintf(fp, "Kernel maps:\n"); + size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); struct rb_node *nd; - for (nd = rb_first(&kernel_maps__functions); nd; nd = rb_next(nd)) { + for (nd = rb_first(&kernel_maps[type]); nd; nd = rb_next(nd)) { struct map *pos = rb_entry(nd, struct map, rb_node); printed += fprintf(fp, "Map:"); @@ -465,6 +473,16 @@ size_t kernel_maps__fprintf(FILE *fp) } } + return printed; +} + +size_t kernel_maps__fprintf(FILE *fp) +{ + size_t printed = fprintf(fp, "Kernel maps:\n"); + int i; + for (i = 0; i < MAP__NR_TYPES; ++i) + printed += __kernel_maps__fprintf(i, fp); + return printed + fprintf(fp, "END kernel maps\n"); } @@ -1191,13 +1209,14 @@ out: static void kernel_maps__insert(struct map *map) { - maps__insert(&kernel_maps__functions, map); + maps__insert(&kernel_maps[map->type], map); } -struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp, - symbol_filter_t filter) +static struct symbol *kernel_maps__find_symbol(u64 ip, enum map_type type, + struct map **mapp, + symbol_filter_t filter) { - struct map *map = maps__find(&kernel_maps__functions, ip); + struct map *map = maps__find(&kernel_maps[type], ip); if (mapp) *mapp = map; @@ -1206,17 +1225,23 @@ struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp, ip = map->map_ip(map, ip); return map__find_symbol(map, ip, filter); } else - WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps__functions), + WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps[type]), "Empty kernel_maps, was symbol__init() called?\n"); return NULL; } -struct map *kernel_maps__find_by_dso_name(const char *name) +struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp, + symbol_filter_t filter) +{ + return kernel_maps__find_symbol(ip, MAP__FUNCTION, mapp, filter); +} + +static struct map *kernel_maps__find_by_dso_name(const char *name) { struct rb_node *nd; - for (nd = rb_first(&kernel_maps__functions); nd; nd = rb_next(nd)) { + for (nd = rb_first(&kernel_maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { struct map *map = rb_entry(nd, struct map, rb_node); if (map->dso && strcmp(map->dso->name, name) == 0) diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 74cba6487ed..54580bb8000 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -28,7 +28,6 @@ struct map *maps__find(struct rb_root *maps, u64 ip); struct symbol *kernel_maps__find_function(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 95011c600740837288a3b34b411244a4d9157c4e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 27 Nov 2009 16:29:20 -0200 Subject: perf symbols: Support multiple symtabs in struct thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Making the routines that were so far specific to the kernel maps useful for all threads. This is done by making the kernel maps be contained in a kernel "thread". This gets the kernel specific routines closer to the userspace counterparts, which will help in reducing the boilerplate for resolving a symbol, as will be demonstrated in the next patches. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1259346563-12568-9-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-top.c | 2 +- tools/perf/util/symbol.c | 157 ++++++++++++++++-------------------------- tools/perf/util/symbol.h | 2 +- tools/perf/util/thread.c | 115 ++++++++++++++++++++++++------- tools/perf/util/thread.h | 15 ++-- 7 files changed, 162 insertions(+), 133 deletions(-) (limited to 'tools/perf/util/thread.h') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index c32e7609b77..3ebd70b1ef9 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -167,7 +167,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) map ? map->dso->long_name : ""); } else if (event->header.misc & PERF_RECORD_MISC_USER) { level = '.'; - map = thread__find_map(thread, ip); + map = thread__find_map(thread, MAP__FUNCTION, ip); if (map != NULL) { ip = map->map_ip(map, ip); sym = map__find_symbol(map, ip, symbol_filter); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 400bef981c6..9bd20c2ee3d 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -422,7 +422,7 @@ resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp) if (!thread) return NULL; - map = thread__find_map(thread, ip); + map = thread__find_map(thread, MAP__FUNCTION, ip); if (map != NULL) { /* * We have to do this here as we may have a dso diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index abe78bbd154..bf6730c7603 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -945,7 +945,7 @@ static void event__process_sample(const event_t *self, int counter) if (thread == NULL) return; - map = thread__find_map(thread, ip); + map = thread__find_map(thread, MAP__FUNCTION, ip); if (map != NULL) { ip = map->map_ip(map, ip); sym = map__find_symbol(map, ip, symbol_filter); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 581db4c4325..b6a2941e778 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -29,12 +29,11 @@ enum dso_origin { }; static void dsos__add(struct list_head *head, struct dso *dso); -static struct map *kernel_maps__find_by_dso_name(const char *name); +static struct map *thread__find_map_by_name(struct thread *self, char *name); static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); -static void kernel_maps__insert(struct map *map); struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); static int dso__load_kernel_sym(struct dso *self, struct map *map, - symbol_filter_t filter); + struct thread *thread, symbol_filter_t filter); unsigned int symbol__priv_size; static int vmlinux_path__nr_entries; static char **vmlinux_path; @@ -44,7 +43,7 @@ static struct symbol_conf symbol_conf__defaults = { .try_vmlinux_path = true, }; -static struct rb_root kernel_maps[MAP__NR_TYPES]; +static struct thread kthread_mem, *kthread = &kthread_mem; bool dso__loaded(const struct dso *self, enum map_type type) { @@ -79,10 +78,10 @@ static void symbols__fixup_end(struct rb_root *self) curr->end = roundup(curr->start, 4096); } -static void __kernel_maps__fixup_end(struct rb_root *root) +static void __thread__fixup_maps_end(struct thread *self, enum map_type type) { struct map *prev, *curr; - struct rb_node *nd, *prevnd = rb_first(root); + struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); if (prevnd == NULL) return; @@ -102,11 +101,11 @@ static void __kernel_maps__fixup_end(struct rb_root *root) curr->end = ~0UL; } -static void kernel_maps__fixup_end(void) +static void thread__fixup_maps_end(struct thread *self) { int i; for (i = 0; i < MAP__NR_TYPES; ++i) - __kernel_maps__fixup_end(&kernel_maps[i]); + __thread__fixup_maps_end(self, i); } static struct symbol *symbol__new(u64 start, u64 len, const char *name) @@ -274,25 +273,16 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp) return fprintf(fp, "%s", sbuild_id); } -static const char * map_type__name[MAP__NR_TYPES] = { - [MAP__FUNCTION] = "Functions", -}; - -size_t dso__fprintf(struct dso *self, FILE *fp) +size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) { - int i; struct rb_node *nd; size_t ret = fprintf(fp, "dso: %s (", self->short_name); ret += dso__fprintf_buildid(self, fp); ret += fprintf(fp, ")\n"); - for (i = 0; i < MAP__NR_TYPES; ++i) { - ret += fprintf(fp, "%s:\n", map_type__name[i]); - - for (nd = rb_first(&self->symbols[i]); nd; nd = rb_next(nd)) { - struct symbol *pos = rb_entry(nd, struct symbol, rb_node); - ret += symbol__fprintf(pos, fp); - } + for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { + struct symbol *pos = rb_entry(nd, struct symbol, rb_node); + ret += symbol__fprintf(pos, fp); } return ret; @@ -373,7 +363,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 dso__split_kallsyms(struct dso *self, struct map *map, +static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread, symbol_filter_t filter) { struct map *curr_map = map; @@ -394,10 +384,10 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, *module++ = '\0'; if (strcmp(self->name, module)) { - curr_map = kernel_maps__find_by_dso_name(module); + curr_map = thread__find_map_by_name(thread, module); if (curr_map == NULL) { - pr_err("/proc/{kallsyms,modules} " - "inconsistency!\n"); + pr_debug("/proc/{kallsyms,modules} " + "inconsistency!\n"); return -1; } } @@ -425,7 +415,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, } curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; - kernel_maps__insert(curr_map); + __thread__insert_map(thread, curr_map); ++kernel_range; } @@ -446,7 +436,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, static int dso__load_kallsyms(struct dso *self, struct map *map, - symbol_filter_t filter) + struct thread *thread, symbol_filter_t filter) { if (dso__load_all_kallsyms(self, map) < 0) return -1; @@ -454,35 +444,13 @@ static int dso__load_kallsyms(struct dso *self, struct map *map, symbols__fixup_end(&self->symbols[map->type]); self->origin = DSO__ORIG_KERNEL; - return dso__split_kallsyms(self, map, filter); -} - -static size_t __kernel_maps__fprintf(enum map_type type, FILE *fp) -{ - size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); - struct rb_node *nd; - - for (nd = rb_first(&kernel_maps[type]); nd; nd = rb_next(nd)) { - struct map *pos = rb_entry(nd, struct map, rb_node); - - printed += fprintf(fp, "Map:"); - printed += map__fprintf(pos, fp); - if (verbose > 1) { - printed += dso__fprintf(pos->dso, fp); - printed += fprintf(fp, "--\n"); - } - } - - return printed; + return dso__split_kallsyms(self, map, thread, filter); } size_t kernel_maps__fprintf(FILE *fp) { size_t printed = fprintf(fp, "Kernel maps:\n"); - int i; - for (i = 0; i < MAP__NR_TYPES; ++i) - printed += __kernel_maps__fprintf(i, fp); - + printed += thread__fprintf_maps(kthread, fp); return printed + fprintf(fp, "END kernel maps\n"); } @@ -772,9 +740,9 @@ out: return 0; } -static int dso__load_sym(struct dso *self, struct map *map, const char *name, - int fd, symbol_filter_t filter, int kernel, - int kmodule) +static int dso__load_sym(struct dso *self, struct map *map, + struct thread *thread, const char *name, int fd, + symbol_filter_t filter, int kernel, int kmodule) { struct map *curr_map = map; struct dso *curr_dso = self; @@ -877,7 +845,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, snprintf(dso_name, sizeof(dso_name), "%s%s", self->short_name, section_name); - curr_map = kernel_maps__find_by_dso_name(dso_name); + curr_map = thread__find_map_by_name(thread, dso_name); if (curr_map == NULL) { u64 start = sym.st_value; @@ -896,7 +864,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, curr_map->map_ip = identity__map_ip; curr_map->unmap_ip = identity__map_ip; curr_dso->origin = DSO__ORIG_KERNEL; - kernel_maps__insert(curr_map); + __thread__insert_map(kthread, curr_map); dsos__add(&dsos__kernel, curr_dso); } else curr_dso = curr_map->dso; @@ -1121,7 +1089,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) dso__set_loaded(self, map->type); if (self->kernel) - return dso__load_kernel_sym(self, map, filter); + return dso__load_kernel_sym(self, map, kthread, filter); name = malloc(size); if (!name) @@ -1186,7 +1154,7 @@ compare_build_id: fd = open(name, O_RDONLY); } while (fd < 0); - ret = dso__load_sym(self, map, name, fd, filter, 0, 0); + ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); close(fd); /* @@ -1207,16 +1175,11 @@ out: return ret; } -static void kernel_maps__insert(struct map *map) -{ - maps__insert(&kernel_maps[map->type], map); -} - -static struct symbol *kernel_maps__find_symbol(u64 ip, enum map_type type, - struct map **mapp, - symbol_filter_t filter) +static struct symbol *thread__find_symbol(struct thread *self, u64 ip, + enum map_type type, struct map **mapp, + symbol_filter_t filter) { - struct map *map = maps__find(&kernel_maps[type], ip); + struct map *map = thread__find_map(self, type, ip); if (mapp) *mapp = map; @@ -1224,9 +1187,7 @@ static struct symbol *kernel_maps__find_symbol(u64 ip, enum map_type type, if (map) { ip = map->map_ip(map, ip); return map__find_symbol(map, ip, filter); - } else - WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps[type]), - "Empty kernel_maps, was symbol__init() called?\n"); + } return NULL; } @@ -1234,14 +1195,14 @@ static struct symbol *kernel_maps__find_symbol(u64 ip, enum map_type type, struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp, symbol_filter_t filter) { - return kernel_maps__find_symbol(ip, MAP__FUNCTION, mapp, filter); + return thread__find_symbol(kthread, ip, MAP__FUNCTION, mapp, filter); } -static struct map *kernel_maps__find_by_dso_name(const char *name) +static struct map *thread__find_map_by_name(struct thread *self, char *name) { struct rb_node *nd; - for (nd = rb_first(&kernel_maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { + for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { struct map *map = rb_entry(nd, struct map, rb_node); if (map->dso && strcmp(map->dso->name, name) == 0) @@ -1285,7 +1246,7 @@ static int dsos__set_modules_path_dir(char *dirname) (int)(dot - dent->d_name), dent->d_name); strxfrchar(dso_name, '-', '_'); - map = kernel_maps__find_by_dso_name(dso_name); + map = thread__find_map_by_name(kthread, dso_name); if (map == NULL) continue; @@ -1338,7 +1299,7 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) return self; } -static int kernel_maps__create_module_maps(void) +static int thread__create_module_maps(struct thread *self) { char *line = NULL; size_t n; @@ -1395,7 +1356,7 @@ static int kernel_maps__create_module_maps(void) dso->has_build_id = true; dso->origin = DSO__ORIG_KMODULE; - kernel_maps__insert(map); + __thread__insert_map(self, map); dsos__add(&dsos__kernel, dso); } @@ -1410,7 +1371,7 @@ out_failure: return -1; } -static int dso__load_vmlinux(struct dso *self, struct map *map, +static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread, const char *vmlinux, symbol_filter_t filter) { int err = -1, fd; @@ -1444,15 +1405,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, return -1; dso__set_loaded(self, map->type); - err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0); - + err = dso__load_sym(self, map, thread, self->long_name, fd, filter, 1, 0); close(fd); return err; } static int dso__load_kernel_sym(struct dso *self, struct map *map, - symbol_filter_t filter) + struct thread *thread, symbol_filter_t filter) { int err; bool is_kallsyms; @@ -1462,8 +1422,8 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, 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); + err = dso__load_vmlinux(self, map, thread, + vmlinux_path[i], filter); if (err > 0) { pr_debug("Using %s for symbols\n", vmlinux_path[i]); @@ -1478,12 +1438,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, if (is_kallsyms) goto do_kallsyms; - err = dso__load_vmlinux(self, map, self->long_name, filter); + err = dso__load_vmlinux(self, map, thread, self->long_name, filter); if (err <= 0) { pr_info("The file %s cannot be used, " "trying to use /proc/kallsyms...", self->long_name); do_kallsyms: - err = dso__load_kallsyms(self, map, filter); + err = dso__load_kallsyms(self, map, thread, filter); if (err > 0 && !is_kallsyms) dso__set_long_name(self, strdup("[kernel.kallsyms]")); } @@ -1535,8 +1495,11 @@ static void __dsos__fprintf(struct list_head *head, FILE *fp) { struct dso *pos; - list_for_each_entry(pos, head, node) - dso__fprintf(pos, fp); + list_for_each_entry(pos, head, node) { + int i; + for (i = 0; i < MAP__NR_TYPES; ++i) + dso__fprintf(pos, i, fp); + } } void dsos__fprintf(FILE *fp) @@ -1563,10 +1526,10 @@ size_t dsos__fprintf_buildid(FILE *fp) __dsos__fprintf_buildid(&dsos__user, fp)); } -static int kernel_maps__create_kernel_map(const struct symbol_conf *conf) +static int thread__create_kernel_map(struct thread *self, const char *vmlinux) { struct map *kmap; - struct dso *kernel = dso__new(conf->vmlinux_name ?: "[kernel.kallsyms]"); + struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); if (kernel == NULL) return -1; @@ -1588,7 +1551,7 @@ static int kernel_maps__create_kernel_map(const struct symbol_conf *conf) sizeof(kernel->build_id)) == 0) kernel->has_build_id = true; - kernel_maps__insert(kmap); + __thread__insert_map(self, kmap); dsos__add(&dsos__kernel, kernel); dsos__add(&dsos__user, vdso); @@ -1656,32 +1619,28 @@ out_fail: return -1; } -static int kernel_maps__init(const struct symbol_conf *conf) +int symbol__init(struct symbol_conf *conf) { const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; + elf_version(EV_CURRENT); symbol__priv_size = pconf->priv_size; + thread__init(kthread, 0); if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) return -1; - if (kernel_maps__create_kernel_map(pconf) < 0) { + if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) { vmlinux_path__exit(); return -1; } - if (pconf->use_modules && kernel_maps__create_module_maps() < 0) + if (pconf->use_modules && thread__create_module_maps(kthread) < 0) pr_debug("Failed to load list of modules in use, " "continuing...\n"); /* * Now that we have all the maps created, just set the ->end of them: */ - kernel_maps__fixup_end(); + thread__fixup_maps_end(kthread); return 0; } - -int symbol__init(struct symbol_conf *conf) -{ - elf_version(EV_CURRENT); - return kernel_maps__init(conf); -} diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 8934814d5a6..3f9e4a4d83d 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -92,7 +92,7 @@ void dsos__fprintf(FILE *fp); size_t dsos__fprintf_buildid(FILE *fp); size_t dso__fprintf_buildid(struct dso *self, FILE *fp); -size_t dso__fprintf(struct dso *self, FILE *fp); +size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); char dso__symtab_origin(const struct dso *self); void dso__set_build_id(struct dso *self, void *build_id); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 1796625f778..2229f82cd63 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -9,17 +9,26 @@ static struct rb_root threads; static struct thread *last_match; +void thread__init(struct thread *self, pid_t pid) +{ + int i; + self->pid = pid; + self->comm = NULL; + for (i = 0; i < MAP__NR_TYPES; ++i) { + self->maps[i] = RB_ROOT; + INIT_LIST_HEAD(&self->removed_maps[i]); + } +} + static struct thread *thread__new(pid_t pid) { struct thread *self = zalloc(sizeof(*self)); if (self != NULL) { - self->pid = pid; + thread__init(self, pid); self->comm = malloc(32); if (self->comm) snprintf(self->comm, 32, ":%d", self->pid); - self->maps = RB_ROOT; - INIT_LIST_HEAD(&self->removed_maps); } return self; @@ -44,24 +53,68 @@ int thread__comm_len(struct thread *self) return self->comm_len; } -static size_t thread__fprintf(struct thread *self, FILE *fp) +static const char *map_type__name[MAP__NR_TYPES] = { + [MAP__FUNCTION] = "Functions", +}; + +static size_t __thread__fprintf_maps(struct thread *self, + enum map_type type, FILE *fp) { + size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); struct rb_node *nd; - struct map *pos; - size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n", - self->pid, self->comm); - for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { - pos = rb_entry(nd, struct map, rb_node); - ret += map__fprintf(pos, fp); + for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { + struct map *pos = rb_entry(nd, struct map, rb_node); + printed += fprintf(fp, "Map:"); + printed += map__fprintf(pos, fp); + if (verbose > 1) { + printed += dso__fprintf(pos->dso, type, fp); + printed += fprintf(fp, "--\n"); + } } - ret = fprintf(fp, "Removed maps:\n"); + return printed; +} + +size_t thread__fprintf_maps(struct thread *self, FILE *fp) +{ + size_t printed = 0, i; + for (i = 0; i < MAP__NR_TYPES; ++i) + printed += __thread__fprintf_maps(self, i, fp); + return printed; +} - list_for_each_entry(pos, &self->removed_maps, node) - ret += map__fprintf(pos, fp); +static size_t __thread__fprintf_removed_maps(struct thread *self, + enum map_type type, FILE *fp) +{ + struct map *pos; + size_t printed = 0; + + list_for_each_entry(pos, &self->removed_maps[type], node) { + printed += fprintf(fp, "Map:"); + printed += map__fprintf(pos, fp); + if (verbose > 1) { + printed += dso__fprintf(pos->dso, type, fp); + printed += fprintf(fp, "--\n"); + } + } + return printed; +} - return ret; +static size_t thread__fprintf_removed_maps(struct thread *self, FILE *fp) +{ + size_t printed = 0, i; + for (i = 0; i < MAP__NR_TYPES; ++i) + printed += __thread__fprintf_removed_maps(self, i, fp); + return printed; +} + +static size_t thread__fprintf(struct thread *self, FILE *fp) +{ + size_t printed = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); + printed += thread__fprintf_removed_maps(self, fp); + printed += fprintf(fp, "Removed maps:\n"); + return printed + thread__fprintf_removed_maps(self, fp); } struct thread *threads__findnew(pid_t pid) @@ -117,7 +170,8 @@ struct thread *register_idle_thread(void) static void thread__remove_overlappings(struct thread *self, struct map *map) { - struct rb_node *next = rb_first(&self->maps); + struct rb_root *root = &self->maps[map->type]; + struct rb_node *next = rb_first(root); while (next) { struct map *pos = rb_entry(next, struct map, rb_node); @@ -132,13 +186,13 @@ static void thread__remove_overlappings(struct thread *self, struct map *map) map__fprintf(pos, stderr); } - rb_erase(&pos->rb_node, &self->maps); + rb_erase(&pos->rb_node, root); /* * We may have references to this map, for instance in some * hist_entry instances, so just move them to a separate * list. */ - list_add_tail(&pos->node, &self->removed_maps); + list_add_tail(&pos->node, &self->removed_maps[map->type]); } } @@ -185,12 +239,26 @@ struct map *maps__find(struct rb_root *maps, u64 ip) void thread__insert_map(struct thread *self, struct map *map) { thread__remove_overlappings(self, map); - maps__insert(&self->maps, map); + maps__insert(&self->maps[map->type], map); } -int thread__fork(struct thread *self, struct thread *parent) +static int thread__clone_maps(struct thread *self, struct thread *parent, + enum map_type type) { struct rb_node *nd; + for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) { + struct map *map = rb_entry(nd, struct map, rb_node); + struct map *new = map__clone(map); + if (new == NULL) + return -ENOMEM; + thread__insert_map(self, new); + } + return 0; +} + +int thread__fork(struct thread *self, struct thread *parent) +{ + int i; if (self->comm) free(self->comm); @@ -198,14 +266,9 @@ int thread__fork(struct thread *self, struct thread *parent) if (!self->comm) return -ENOMEM; - for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) { - struct map *map = rb_entry(nd, struct map, rb_node); - struct map *new = map__clone(map); - if (!new) + for (i = 0; i < MAP__NR_TYPES; ++i) + if (thread__clone_maps(self, parent, i) < 0) return -ENOMEM; - thread__insert_map(self, new); - } - return 0; } diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 54580bb8000..3bdd9b2276f 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -7,20 +7,22 @@ struct thread { struct rb_node rb_node; - struct rb_root maps; - struct list_head removed_maps; + struct rb_root maps[MAP__NR_TYPES]; + struct list_head removed_maps[MAP__NR_TYPES]; pid_t pid; char shortname[3]; char *comm; int comm_len; }; +void thread__init(struct thread *self, pid_t pid); int thread__set_comm(struct thread *self, const char *comm); int thread__comm_len(struct thread *self); struct thread *threads__findnew(pid_t pid); struct thread *register_idle_thread(void); void thread__insert_map(struct thread *self, struct map *map); int thread__fork(struct thread *self, struct thread *parent); +size_t thread__fprintf_maps(struct thread *self, FILE *fp); size_t threads__fprintf(FILE *fp); void maps__insert(struct rb_root *maps, struct map *map); @@ -29,9 +31,14 @@ struct map *maps__find(struct rb_root *maps, u64 ip); struct symbol *kernel_maps__find_function(const u64 ip, struct map **mapp, symbol_filter_t filter); -static inline struct map *thread__find_map(struct thread *self, u64 ip) +static inline struct map *thread__find_map(struct thread *self, + enum map_type type, u64 ip) { - return self ? maps__find(&self->maps, ip) : NULL; + return self ? maps__find(&self->maps[type], ip) : NULL; } +static inline void __thread__insert_map(struct thread *self, struct map *map) +{ + maps__insert(&self->maps[map->type], map); +} #endif /* __PERF_THREAD_H */ -- cgit v1.2.3-70-g09d2 From 1de8e24520ffdcf2a90c842eed937f59079a2abd Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 27 Nov 2009 16:29:21 -0200 Subject: perf symbols: When not using modules, discard its symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1259346563-12568-10-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 6 +++++- tools/perf/util/thread.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/thread.h') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b6a2941e778..b788c2f5d67 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -381,6 +381,9 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread module = strchr(pos->name, '\t'); if (module) { + if (!thread->use_modules) + goto discard_symbol; + *module++ = '\0'; if (strcmp(self->name, module)) { @@ -420,7 +423,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread } if (filter && filter(curr_map, pos)) { - rb_erase(&pos->rb_node, root); +discard_symbol: rb_erase(&pos->rb_node, root); symbol__delete(pos); } else { if (curr_map != map) { @@ -1635,6 +1638,7 @@ int symbol__init(struct symbol_conf *conf) return -1; } + kthread->use_modules = pconf->use_modules; if (pconf->use_modules && thread__create_module_maps(kthread) < 0) pr_debug("Failed to load list of modules in use, " "continuing...\n"); diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 3bdd9b2276f..59b0d9b577d 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -10,6 +10,7 @@ struct thread { struct rb_root maps[MAP__NR_TYPES]; struct list_head removed_maps[MAP__NR_TYPES]; pid_t pid; + bool use_modules; char shortname[3]; char *comm; int comm_len; -- cgit v1.2.3-70-g09d2 From 1ed091c45ae33b2179d387573c3fe3f3b4adf60a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 27 Nov 2009 16:29:23 -0200 Subject: perf tools: Consolidate symbol resolving across all tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now we have a very high level routine for simple tools to process IP sample events: int event__preprocess_sample(const event_t *self, struct addr_location *al, symbol_filter_t filter) It receives the event itself and will insert new threads in the global threads list and resolve the map and symbol, filling all this info into the new addr_location struct, so that tools like annotate and report can further process the event by creating hist_entries in their specific way (with or without callgraphs, etc). It in turn uses the new next layer function: void thread__find_addr_location(struct thread *self, u8 cpumode, enum map_type type, u64 addr, struct addr_location *al, symbol_filter_t filter) This one will, given a thread (userspace or the kernel kthread one), will find the given type (MAP__FUNCTION now, MAP__VARIABLE too in the near future) at the given cpumode, taking vdsos into account (userspace hit, but kernel symbol) and will fill all these details in the addr_location given. Tools that need a more compact API for plain function resolution, like 'kmem', can use this other one: struct symbol *thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter) So, to resolve a kernel symbol, that is all the 'kmem' tool needs, its just a matter of calling: sym = thread__find_function(kthread, addr, NULL); The 'filter' parameter is needed because we do lazy parsing/loading of ELF symtabs or /proc/kallsyms. With this we remove more code duplication all around, which is always good, huh? :-) 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-12-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 55 +++-------------- tools/perf/builtin-kmem.c | 2 +- tools/perf/builtin-report.c | 135 ++++++++++++------------------------------ tools/perf/builtin-top.c | 44 +++----------- tools/perf/util/event.c | 62 +++++++++++++++++++ tools/perf/util/event.h | 4 ++ tools/perf/util/hist.c | 15 +++-- tools/perf/util/hist.h | 6 +- tools/perf/util/symbol.c | 26 +------- tools/perf/util/symbol.h | 10 ++++ tools/perf/util/thread.c | 12 ++++ tools/perf/util/thread.h | 23 +++++-- 12 files changed, 172 insertions(+), 222 deletions(-) (limited to 'tools/perf/util/thread.h') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 7d39bd2b19b..7f85c6e159a 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -124,71 +124,30 @@ static void hist_hit(struct hist_entry *he, u64 ip) h->ip[offset]); } -static int hist_entry__add(struct thread *thread, struct map *map, - struct symbol *sym, u64 ip, u64 count, char level) +static int hist_entry__add(struct addr_location *al, u64 count) { bool hit; - struct hist_entry *he = __hist_entry__add(thread, map, sym, NULL, ip, - count, level, &hit); + struct hist_entry *he = __hist_entry__add(al, NULL, count, &hit); if (he == NULL) return -ENOMEM; - hist_hit(he, ip); + hist_hit(he, al->addr); return 0; } static int process_sample_event(event_t *event) { - char level; - u64 ip = event->ip.ip; - struct map *map = NULL; - struct symbol *sym = NULL; - struct thread *thread = threads__findnew(event->ip.pid); + struct addr_location al; dump_printf("(IP, %d): %d: %p\n", event->header.misc, - event->ip.pid, (void *)(long)ip); + event->ip.pid, (void *)(long)event->ip.ip); - if (thread == NULL) { + if (event__preprocess_sample(event, &al, symbol_filter) < 0) { fprintf(stderr, "problem processing %d event, skipping it.\n", event->header.type); return -1; } - dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); - - if (event->header.misc & PERF_RECORD_MISC_KERNEL) { - level = 'k'; - sym = kernel_maps__find_function(ip, &map, symbol_filter); - dump_printf(" ...... dso: %s\n", - map ? map->dso->long_name : ""); - } else if (event->header.misc & PERF_RECORD_MISC_USER) { - level = '.'; - map = thread__find_map(thread, MAP__FUNCTION, ip); - if (map != NULL) { - ip = map->map_ip(map, ip); - sym = map__find_symbol(map, ip, symbol_filter); - } else { - /* - * If this is outside of all known maps, - * and is a negative address, try to look it - * up in the kernel dso, as it might be a - * vsyscall or vdso (which executes in user-mode). - * - * XXX This is nasty, we should have a symbol list in - * the "[vdso]" dso, but for now lets use the old - * trick of looking in the whole kernel symbol list. - */ - if ((long long)ip < 0) - sym = kernel_maps__find_function(ip, &map, - symbol_filter); - } - dump_printf(" ...... dso: %s\n", - map ? map->dso->long_name : ""); - } else { - level = 'H'; - dump_printf(" ...... dso: [hypervisor]\n"); - } - - if (hist_entry__add(thread, map, sym, ip, 1, level)) { + if (hist_entry__add(&al, 1)) { fprintf(stderr, "problem incrementing symbol count, " "skipping event\n"); return -1; diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index e7294c8fc62..047fef74bd5 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -420,7 +420,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller) if (is_caller) { addr = data->call_site; if (!raw_ip) - sym = kernel_maps__find_function(addr, NULL, NULL); + sym = thread__find_function(kthread, addr, NULL); } else addr = data->ptr; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 01ef35cac5f..383c4ab4f9a 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -408,55 +408,6 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm) return 0; } - -static struct symbol * -resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp) -{ - struct map *map = mapp ? *mapp : NULL; - u64 ip = *ipp; - - if (map) - goto got_map; - - if (!thread) - return NULL; - - map = thread__find_map(thread, MAP__FUNCTION, ip); - if (map != NULL) { - /* - * We have to do this here as we may have a dso - * with no symbol hit that has a name longer than - * the ones with symbols sampled. - */ - if (!sort_dso.elide && !map->dso->slen_calculated) - dso__calc_col_width(map->dso); - - if (mapp) - *mapp = map; -got_map: - ip = map->map_ip(map, ip); - } else { - /* - * If this is outside of all known maps, - * and is a negative address, try to look it - * up in the kernel dso, as it might be a - * vsyscall or vdso (which executes in user-mode). - * - * XXX This is nasty, we should have a symbol list in - * the "[vdso]" dso, but for now lets use the old - * trick of looking in the whole kernel symbol list. - */ - if ((long long)ip < 0) - return kernel_maps__find_function(ip, mapp, NULL); - } - dump_printf(" ...... dso: %s\n", - map ? map->dso->long_name : ""); - dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip); - *ipp = ip; - - return map ? map__find_symbol(map, ip, NULL) : NULL; -} - static int call__match(struct symbol *sym) { if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) @@ -469,7 +420,7 @@ static struct symbol **resolve_callchain(struct thread *thread, struct ip_callchain *chain, struct symbol **parent) { - u64 context = PERF_CONTEXT_MAX; + u8 cpumode = PERF_RECORD_MISC_USER; struct symbol **syms = NULL; unsigned int i; @@ -483,30 +434,31 @@ static struct symbol **resolve_callchain(struct thread *thread, for (i = 0; i < chain->nr; i++) { u64 ip = chain->ips[i]; - struct symbol *sym = NULL; + struct addr_location al; if (ip >= PERF_CONTEXT_MAX) { - context = ip; + switch (ip) { + case PERF_CONTEXT_HV: + cpumode = PERF_RECORD_MISC_HYPERVISOR; break; + case PERF_CONTEXT_KERNEL: + cpumode = PERF_RECORD_MISC_KERNEL; break; + case PERF_CONTEXT_USER: + cpumode = PERF_RECORD_MISC_USER; break; + default: + break; + } continue; } - switch (context) { - case PERF_CONTEXT_HV: - break; - case PERF_CONTEXT_KERNEL: - sym = kernel_maps__find_function(ip, NULL, NULL); - break; - default: - sym = resolve_symbol(thread, NULL, &ip); - break; - } - - if (sym) { - if (sort__has_parent && !*parent && call__match(sym)) - *parent = sym; + thread__find_addr_location(thread, cpumode, MAP__FUNCTION, + ip, &al, NULL); + if (al.sym != NULL) { + if (sort__has_parent && !*parent && + call__match(al.sym)) + *parent = al.sym; if (!callchain) break; - syms[i] = sym; + syms[i] = al.sym; } } @@ -517,20 +469,17 @@ static struct symbol **resolve_callchain(struct thread *thread, * collect histogram counts */ -static int -hist_entry__add(struct thread *thread, struct map *map, - struct symbol *sym, u64 ip, struct ip_callchain *chain, - char level, u64 count) +static int hist_entry__add(struct addr_location *al, + struct ip_callchain *chain, u64 count) { struct symbol **syms = NULL, *parent = NULL; bool hit; struct hist_entry *he; if ((sort__has_parent || callchain) && chain) - syms = resolve_callchain(thread, chain, &parent); + syms = resolve_callchain(al->thread, chain, &parent); - he = __hist_entry__add(thread, map, sym, parent, - ip, count, level, &hit); + he = __hist_entry__add(al, parent, count, &hit); if (he == NULL) return -ENOMEM; @@ -656,14 +605,12 @@ static int validate_chain(struct ip_callchain *chain, event_t *event) static int process_sample_event(event_t *event) { - char level; - struct symbol *sym = NULL; u64 ip = event->ip.ip; u64 period = 1; - struct map *map = NULL; void *more_data = event->ip.__more_data; struct ip_callchain *chain = NULL; int cpumode; + struct addr_location al; struct thread *thread = threads__findnew(event->ip.pid); if (sample_type & PERF_SAMPLE_PERIOD) { @@ -709,32 +656,26 @@ static int process_sample_event(event_t *event) cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - if (cpumode == PERF_RECORD_MISC_KERNEL) { - level = 'k'; - sym = kernel_maps__find_function(ip, &map, NULL); - dump_printf(" ...... dso: %s\n", - map ? map->dso->long_name : ""); - } else if (cpumode == PERF_RECORD_MISC_USER) { - level = '.'; - sym = resolve_symbol(thread, &map, &ip); - - } else { - level = 'H'; - dump_printf(" ...... dso: [hypervisor]\n"); - } + thread__find_addr_location(thread, cpumode, + MAP__FUNCTION, ip, &al, NULL); + /* + * We have to do this here as we may have a dso with no symbol hit that + * has a name longer than the ones with symbols sampled. + */ + if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated) + dso__calc_col_width(al.map->dso); if (dso_list && - (!map || !map->dso || - !(strlist__has_entry(dso_list, map->dso->short_name) || - (map->dso->short_name != map->dso->long_name && - strlist__has_entry(dso_list, map->dso->long_name))))) + (!al.map || !al.map->dso || + !(strlist__has_entry(dso_list, al.map->dso->short_name) || + (al.map->dso->short_name != al.map->dso->long_name && + strlist__has_entry(dso_list, al.map->dso->long_name))))) return 0; - if (sym_list && sym && !strlist__has_entry(sym_list, sym->name)) + if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name)) return 0; - if (hist_entry__add(thread, map, sym, ip, - chain, level, period)) { + if (hist_entry__add(&al, chain, period)) { pr_debug("problem incrementing symbol count, skipping event\n"); return -1; } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7a3c0c7aad3..e0a374d0e43 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -929,55 +929,28 @@ static int symbol_filter(struct map *map, struct symbol *sym) static void event__process_sample(const event_t *self, int counter) { u64 ip = self->ip.ip; - struct map *map; struct sym_entry *syme; - struct symbol *sym; + struct addr_location al; u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; switch (origin) { - case PERF_RECORD_MISC_USER: { - struct thread *thread; - + case PERF_RECORD_MISC_USER: if (hide_user_symbols) return; - - thread = threads__findnew(self->ip.pid); - if (thread == NULL) - return; - - map = thread__find_map(thread, MAP__FUNCTION, ip); - if (map != NULL) { - ip = map->map_ip(map, ip); - sym = map__find_symbol(map, ip, symbol_filter); - if (sym == NULL) - return; - userspace_samples++; - break; - } - } - /* - * If this is outside of all known maps, - * and is a negative address, try to look it - * up in the kernel dso, as it might be a - * vsyscall or vdso (which executes in user-mode). - */ - if ((long long)ip >= 0) - return; - /* Fall thru */ + break; case PERF_RECORD_MISC_KERNEL: if (hide_kernel_symbols) return; - - sym = kernel_maps__find_function(ip, &map, symbol_filter); - if (sym == NULL) - return; break; default: return; } - syme = symbol__priv(sym); + if (event__preprocess_sample(self, &al, symbol_filter) < 0 || + al.sym == NULL) + return; + syme = symbol__priv(al.sym); if (!syme->skip) { syme->count[counter]++; syme->origin = origin; @@ -986,8 +959,9 @@ static void event__process_sample(const event_t *self, int counter) if (list_empty(&syme->node) || !syme->node.next) __list_insert_active_sym(syme); pthread_mutex_unlock(&active_symbols_lock); + if (origin == PERF_RECORD_MISC_USER) + ++userspace_samples; ++samples; - return; } } diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 70b4aa03b47..233d7ad9bd7 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -249,3 +249,65 @@ int event__process_task(event_t *self) return 0; } + +void thread__find_addr_location(struct thread *self, u8 cpumode, + enum map_type type, u64 addr, + struct addr_location *al, + symbol_filter_t filter) +{ + struct thread *thread = al->thread = self; + + al->addr = addr; + + if (cpumode & PERF_RECORD_MISC_KERNEL) { + al->level = 'k'; + thread = kthread; + } else if (cpumode & PERF_RECORD_MISC_USER) + al->level = '.'; + else { + al->level = 'H'; + al->map = NULL; + al->sym = NULL; + return; + } +try_again: + al->map = thread__find_map(thread, type, al->addr); + if (al->map == NULL) { + /* + * If this is outside of all known maps, and is a negative + * address, try to look it up in the kernel dso, as it might be + * a vsyscall or vdso (which executes in user-mode). + * + * XXX This is nasty, we should have a symbol list in the + * "[vdso]" dso, but for now lets use the old trick of looking + * in the whole kernel symbol list. + */ + if ((long long)al->addr < 0 && thread != kthread) { + thread = kthread; + goto try_again; + } + al->sym = NULL; + } else { + al->addr = al->map->map_ip(al->map, al->addr); + al->sym = map__find_symbol(al->map, al->addr, filter); + } +} + +int event__preprocess_sample(const event_t *self, struct addr_location *al, + symbol_filter_t filter) +{ + u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + struct thread *thread = threads__findnew(self->ip.pid); + + if (thread == NULL) + return -1; + + dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); + + thread__find_addr_location(thread, cpumode, MAP__FUNCTION, + self->ip.ip, al, filter); + dump_printf(" ...... dso: %s\n", + al->map ? al->map->dso->long_name : + al->level == 'H' ? "[hypervisor]" : ""); + return 0; +} diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 13c12c75f97..a4cc8105cf6 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -152,4 +152,8 @@ int event__process_lost(event_t *self); int event__process_mmap(event_t *self); int event__process_task(event_t *self); +struct addr_location; +int event__preprocess_sample(const event_t *self, struct addr_location *al, + symbol_filter_t filter); + #endif /* __PERF_RECORD_H */ diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index f26cd9ba00f..0ebf6ee16ca 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -14,20 +14,19 @@ struct callchain_param callchain_param = { * histogram, sorted on item, collects counts */ -struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map, - struct symbol *sym, +struct hist_entry *__hist_entry__add(struct addr_location *al, struct symbol *sym_parent, - u64 ip, u64 count, char level, bool *hit) + u64 count, bool *hit) { struct rb_node **p = &hist.rb_node; struct rb_node *parent = NULL; struct hist_entry *he; struct hist_entry entry = { - .thread = thread, - .map = map, - .sym = sym, - .ip = ip, - .level = level, + .thread = al->thread, + .map = al->map, + .sym = al->sym, + .ip = al->addr, + .level = al->level, .count = count, .parent = sym_parent, }; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ac2149c559b..3020db0c929 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -36,9 +36,9 @@ extern unsigned long total_fork; extern unsigned long total_unknown; extern unsigned long total_lost; -struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map, - struct symbol *sym, struct symbol *parent, - u64 ip, u64 count, char level, bool *hit); +struct hist_entry *__hist_entry__add(struct addr_location *al, + struct symbol *parent, + u64 count, bool *hit); extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); extern void hist_entry__free(struct hist_entry *); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b788c2f5d67..fffcb937cdc 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -43,7 +43,8 @@ static struct symbol_conf symbol_conf__defaults = { .try_vmlinux_path = true, }; -static struct thread kthread_mem, *kthread = &kthread_mem; +static struct thread kthread_mem; +struct thread *kthread = &kthread_mem; bool dso__loaded(const struct dso *self, enum map_type type) { @@ -1178,29 +1179,6 @@ out: return ret; } -static struct symbol *thread__find_symbol(struct thread *self, u64 ip, - enum map_type type, struct map **mapp, - symbol_filter_t filter) -{ - struct map *map = thread__find_map(self, type, ip); - - if (mapp) - *mapp = map; - - if (map) { - ip = map->map_ip(map, ip); - return map__find_symbol(map, ip, filter); - } - - return NULL; -} - -struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp, - symbol_filter_t filter) -{ - return thread__find_symbol(kthread, ip, MAP__FUNCTION, mapp, filter); -} - static struct map *thread__find_map_by_name(struct thread *self, char *name) { struct rb_node *nd; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 3f9e4a4d83d..17003efa0b3 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -63,6 +63,14 @@ static inline void *symbol__priv(struct symbol *self) return ((void *)self) - symbol__priv_size; } +struct addr_location { + struct thread *thread; + struct map *map; + struct symbol *sym; + u64 addr; + char level; +}; + struct dso { struct list_head node; struct rb_root symbols[MAP__NR_TYPES]; @@ -105,6 +113,8 @@ size_t kernel_maps__fprintf(FILE *fp); int symbol__init(struct symbol_conf *conf); +struct thread; +struct thread *kthread; extern struct list_head dsos__user, dsos__kernel; extern struct dso *vdso; #endif /* __PERF_SYMBOL */ diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 2229f82cd63..603f5610861 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -285,3 +285,15 @@ size_t threads__fprintf(FILE *fp) return ret; } + +struct symbol *thread__find_symbol(struct thread *self, + enum map_type type, u64 addr, + symbol_filter_t filter) +{ + struct map *map = thread__find_map(self, type, addr); + + if (map != NULL) + return map__find_symbol(map, map->map_ip(map, addr), filter); + + return NULL; +} diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 59b0d9b577d..686d6e914d9 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -27,19 +27,30 @@ size_t thread__fprintf_maps(struct thread *self, FILE *fp); 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_function(const u64 ip, struct map **mapp, - symbol_filter_t filter); +struct map *maps__find(struct rb_root *maps, u64 addr); static inline struct map *thread__find_map(struct thread *self, - enum map_type type, u64 ip) + enum map_type type, u64 addr) { - return self ? maps__find(&self->maps[type], ip) : NULL; + return self ? maps__find(&self->maps[type], addr) : NULL; } static inline void __thread__insert_map(struct thread *self, struct map *map) { maps__insert(&self->maps[map->type], map); } + +void thread__find_addr_location(struct thread *self, u8 cpumode, + enum map_type type, u64 addr, + struct addr_location *al, + symbol_filter_t filter); +struct symbol *thread__find_symbol(struct thread *self, + enum map_type type, u64 addr, + symbol_filter_t filter); + +static inline struct symbol * +thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter) +{ + return thread__find_symbol(self, MAP__FUNCTION, addr, filter); +} #endif /* __PERF_THREAD_H */ -- cgit v1.2.3-70-g09d2