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/util/thread.c | 129 ++++++++++++++++++++++++++++++----------------- 1 file changed, 83 insertions(+), 46 deletions(-) (limited to 'tools/perf/util/thread.c') 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; -- 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.c') 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.c') 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.c') 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.c') 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.c') 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 6beba7adbe092e63dfe8d09fbd1e3ec140474a13 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 21 Oct 2009 17:34:06 -0200 Subject: perf tools: Unify debug messages mechanisms We were using eprintf in some places, that looks at a global 'verbose' level, and at other places passing a 'v' parameter to specify the verbosity level, unify it by introducing pr_{err,warning,debug,etc}, just like in the kernel. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Mike Galbraith LKML-Reference: <1256153646-10097-1-git-send-email-acme@redhat.com> Signed-off-by: Ingo Molnar --- tools/perf/builtin-annotate.c | 3 +- tools/perf/builtin-record.c | 2 +- tools/perf/builtin-report.c | 9 ++- tools/perf/builtin-sched.c | 4 +- tools/perf/builtin-timechart.c | 13 ++-- tools/perf/builtin-top.c | 2 +- tools/perf/builtin-trace.c | 4 +- tools/perf/util/callchain.c | 2 +- tools/perf/util/debug.c | 4 +- tools/perf/util/debug.h | 3 +- tools/perf/util/event.h | 3 +- tools/perf/util/header.c | 2 +- tools/perf/util/include/linux/kernel.h | 17 +++++ tools/perf/util/map.c | 17 ++--- tools/perf/util/symbol.c | 134 +++++++++++++++------------------ tools/perf/util/symbol.h | 5 +- tools/perf/util/thread.c | 6 +- 17 files changed, 114 insertions(+), 116 deletions(-) (limited to 'tools/perf/util/thread.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 99bac6aa72c..6d63c2eea2c 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -203,8 +203,7 @@ static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { struct map *map = map__new(&event->mmap, NULL, 0, - sizeof(struct sym_priv), symbol_filter, - verbose); + sizeof(struct sym_priv), symbol_filter); struct thread *thread = threads__findnew(event->mmap.pid); dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n", diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f0467ff0d8a..ac5ddfff445 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -630,7 +630,7 @@ static int __cmd_record(int argc, const char **argv) param.sched_priority = realtime_prio; if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { - printf("Could not set realtime priority.\n"); + pr_err("Could not set realtime priority.\n"); exit(-1); } } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 72d58421223..b3d814b5455 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -689,7 +689,8 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) dump_printf("... chain: nr:%Lu\n", chain->nr); if (validate_chain(chain, event) < 0) { - eprintf("call-chain problem with event, skipping it.\n"); + pr_debug("call-chain problem with event, " + "skipping it.\n"); return 0; } @@ -700,7 +701,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) } if (thread == NULL) { - eprintf("problem processing %d event, skipping it.\n", + pr_debug("problem processing %d event, skipping it.\n", event->header.type); return -1; } @@ -738,7 +739,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) if (hist_entry__add(thread, map, sym, ip, chain, level, period)) { - eprintf("problem incrementing symbol count, skipping event\n"); + pr_debug("problem incrementing symbol count, skipping event\n"); return -1; } @@ -750,7 +751,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) static int process_mmap_event(event_t *event, unsigned long offset, unsigned long head) { - struct map *map = map__new(&event->mmap, cwd, cwdlen, 0, NULL, verbose); + struct map *map = map__new(&event->mmap, cwd, cwdlen, 0, NULL); struct thread *thread = threads__findnew(event->mmap.pid); dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n", diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 807ca66e7a8..9a48d9626be 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1666,8 +1666,8 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) (long long)period); if (thread == NULL) { - eprintf("problem processing %d event, skipping it.\n", - event->header.type); + pr_debug("problem processing %d event, skipping it.\n", + event->header.type); return -1; } diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 34fad57087f..0a2f22261c3 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -1162,12 +1162,10 @@ more: size = event->header.size; if (!size || process_event(event) < 0) { - - printf("%p [%p]: skipping unknown header type: %d\n", - (void *)(offset + head), - (void *)(long)(event->header.size), - event->header.type); - + pr_warning("%p [%p]: skipping unknown header type: %d\n", + (void *)(offset + head), + (void *)(long)(event->header.size), + event->header.type); /* * assume we lost track of the stream, check alignment, and * increment a single u64 in the hope to catch on again 'soon'. @@ -1200,7 +1198,8 @@ done: write_svg_file(output_name); - printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name); + pr_info("Written %2.1f seconds of trace to %s.\n", + (last_time - first_time) / 1000000000.0, output_name); return rc; } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index fa20345a0ab..4a9fe228be2 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -809,7 +809,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) static int parse_symbols(void) { if (dsos__load_kernel(vmlinux_name, sizeof(struct sym_entry), - symbol_filter, verbose, 1) <= 0) + symbol_filter, 1) <= 0) return -1; if (dump_symtab) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 4c129ff0bb1..e566bbe3f22 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -81,8 +81,8 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) (long long)period); if (thread == NULL) { - eprintf("problem processing %d event, skipping it.\n", - event->header.type); + pr_debug("problem processing %d event, skipping it.\n", + event->header.type); return -1; } diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 3b8380f1b47..b3b71258272 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -206,7 +206,7 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain, } node->val_nr = chain->nr - start; if (!node->val_nr) - printf("Warning: empty node in callchain tree\n"); + pr_warning("Warning: empty node in callchain tree\n"); } static void diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index e8ca98fe0bd..28d520d5a1f 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -13,12 +13,12 @@ int verbose = 0; int dump_trace = 0; -int eprintf(const char *fmt, ...) +int eprintf(int level, const char *fmt, ...) { va_list args; int ret = 0; - if (verbose) { + if (verbose >= level) { va_start(args, fmt); ret = vfprintf(stderr, fmt, args); va_end(args); diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 02d1fa1c246..e8b18a1f87a 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -5,7 +5,8 @@ extern int verbose; extern int dump_trace; -int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +int eprintf(int level, + const char *fmt, ...) __attribute__((format(printf, 2, 3))); int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void trace_event(event_t *event); diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index db59c8bbe49..d972b4b0d38 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -106,8 +106,7 @@ struct symbol; typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, - unsigned int sym_priv_size, symbol_filter_t filter, - int v); + unsigned int sym_priv_size, symbol_filter_t filter); struct map *map__clone(struct map *self); int map__overlap(struct map *l, struct map *r); size_t map__fprintf(struct map *self, FILE *fp); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 622c60e4525..7d26659b806 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -93,7 +93,7 @@ static struct perf_trace_event_type *events; void perf_header__push_event(u64 id, const char *name) { if (strlen(name) > MAX_EVENT_NAME) - printf("Event %s will be truncated\n", name); + pr_warning("Event %s will be truncated\n", name); if (!events) { events = malloc(sizeof(struct perf_trace_event_type)); diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h index 4b9204d9b26..21c0274c02f 100644 --- a/tools/perf/util/include/linux/kernel.h +++ b/tools/perf/util/include/linux/kernel.h @@ -85,4 +85,21 @@ simple_strtoul(const char *nptr, char **endptr, int base) return strtoul(nptr, endptr, base); } +#ifndef pr_fmt +#define pr_fmt(fmt) fmt +#endif + +#define pr_err(fmt, ...) \ + do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) +#define pr_warning(fmt, ...) \ + do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) +#define pr_info(fmt, ...) \ + do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) +#define pr_debug(fmt, ...) \ + eprintf(1, pr_fmt(fmt), ##__VA_ARGS__) +#define pr_debugN(n, fmt, ...) \ + eprintf(n, pr_fmt(fmt), ##__VA_ARGS__) +#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) +#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) + #endif diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 55079c0200e..c1c55682534 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -21,8 +21,7 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen) } struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, - unsigned int sym_priv_size, symbol_filter_t filter, - int v) + unsigned int sym_priv_size, symbol_filter_t filter) { struct map *self = malloc(sizeof(*self)); @@ -58,16 +57,16 @@ struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, goto out_delete; if (new_dso) { - int nr = dso__load(self->dso, self, filter, v); + int nr = dso__load(self->dso, self, filter); if (nr < 0) - eprintf("Failed to open %s, continuing " - "without symbols\n", - self->dso->long_name); + pr_warning("Failed to open %s, continuing " + "without symbols\n", + self->dso->long_name); else if (nr == 0) - eprintf("No symbols found in %s, maybe " - "install a debug package?\n", - self->dso->long_name); + pr_warning("No symbols found in %s, maybe " + "install a debug package?\n", + self->dso->long_name); } if (self->dso == vdso || anon) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 0a4898480d6..8f0208ce237 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -76,7 +76,7 @@ static void kernel_maps__fixup_end(void) } static struct symbol *symbol__new(u64 start, u64 len, const char *name, - unsigned int priv_size, int v) + unsigned int priv_size) { size_t namelen = strlen(name) + 1; struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); @@ -91,8 +91,7 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name, self->start = start; self->end = len ? start + len - 1 : start; - if (v > 2) - printf("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); + pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); memcpy(self->name, name, namelen); @@ -209,7 +208,7 @@ size_t dso__fprintf(struct dso *self, FILE *fp) * so that we can in the next step set the symbol ->end address and then * call kernel_maps__split_kallsyms. */ -static int kernel_maps__load_all_kallsyms(int v) +static int kernel_maps__load_all_kallsyms(void) { char *line = NULL; size_t n; @@ -252,7 +251,7 @@ static int kernel_maps__load_all_kallsyms(int v) * Will fix up the end later, when we have all symbols sorted. */ sym = symbol__new(start, 0, symbol_name, - kernel_map->dso->sym_priv_size, v); + kernel_map->dso->sym_priv_size); if (sym == NULL) goto out_delete_line; @@ -300,8 +299,8 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules) if (strcmp(map->dso->name, module)) { map = kernel_maps__find_by_dso_name(module); if (!map) { - fputs("/proc/{kallsyms,modules} " - "inconsistency!\n", stderr); + pr_err("/proc/{kallsyms,modules} " + "inconsistency!\n"); return -1; } } @@ -351,10 +350,9 @@ delete_symbol: } -static int kernel_maps__load_kallsyms(symbol_filter_t filter, - int use_modules, int v) +static int kernel_maps__load_kallsyms(symbol_filter_t filter, int use_modules) { - if (kernel_maps__load_all_kallsyms(v)) + if (kernel_maps__load_all_kallsyms()) return -1; dso__fixup_sym_end(kernel_map->dso); @@ -362,9 +360,9 @@ static int kernel_maps__load_kallsyms(symbol_filter_t filter, return kernel_maps__split_kallsyms(filter, use_modules); } -static size_t kernel_maps__fprintf(FILE *fp, int v) +static size_t kernel_maps__fprintf(FILE *fp) { - size_t printed = fprintf(stderr, "Kernel maps:\n"); + size_t printed = fprintf(fp, "Kernel maps:\n"); struct rb_node *nd; for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { @@ -372,17 +370,17 @@ static size_t kernel_maps__fprintf(FILE *fp, int v) printed += fprintf(fp, "Map:"); printed += map__fprintf(pos, fp); - if (v > 1) { + if (verbose > 1) { printed += dso__fprintf(pos->dso, fp); printed += fprintf(fp, "--\n"); } } - return printed + fprintf(stderr, "END kernel maps\n"); + return printed + fprintf(fp, "END kernel maps\n"); } static int dso__load_perf_map(struct dso *self, struct map *map, - symbol_filter_t filter, int v) + symbol_filter_t filter) { char *line = NULL; size_t n; @@ -420,7 +418,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map, continue; sym = symbol__new(start, size, line + len, - self->sym_priv_size, v); + self->sym_priv_size); if (sym == NULL) goto out_delete_line; @@ -534,7 +532,7 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, * And always look at the original dso, not at debuginfo packages, that * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). */ -static int dso__synthesize_plt_symbols(struct dso *self, int v) +static int dso__synthesize_plt_symbols(struct dso *self) { uint32_t nr_rel_entries, idx; GElf_Sym sym; @@ -618,7 +616,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, v); + sympltname, self->sym_priv_size); if (!f) goto out_elf_end; @@ -636,7 +634,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, v); + sympltname, self->sym_priv_size); if (!f) goto out_elf_end; @@ -654,14 +652,14 @@ out_close: if (err == 0) return nr; out: - fprintf(stderr, "%s: problems reading %s PLT info.\n", - __func__, self->long_name); + pr_warning("%s: problems reading %s PLT info.\n", + __func__, self->long_name); 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, int v) + int kmodule) { struct map *curr_map = map; struct dso *curr_dso = self; @@ -680,15 +678,12 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); if (elf == NULL) { - if (v) - fprintf(stderr, "%s: cannot read %s ELF file.\n", - __func__, name); + pr_err("%s: cannot read %s ELF file.\n", __func__, name); goto out_close; } if (gelf_getehdr(elf, &ehdr) == NULL) { - if (v) - fprintf(stderr, "%s: cannot get elf header.\n", __func__); + pr_err("%s: cannot get elf header.\n", __func__); goto out_elf_end; } @@ -794,10 +789,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, } if (curr_dso->adjust_symbols) { - if (v > 2) - printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", - (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); - + pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " + "%Lx sh_offset: %Lx\n", (u64)sym.st_value, + (u64)shdr.sh_addr, (u64)shdr.sh_offset); sym.st_value -= shdr.sh_addr - shdr.sh_offset; } /* @@ -810,7 +804,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, elf_name = demangled; new_symbol: f = symbol__new(sym.st_value, sym.st_size, elf_name, - curr_dso->sym_priv_size, v); + curr_dso->sym_priv_size); free(demangled); if (!f) goto out_elf_end; @@ -837,7 +831,7 @@ out_close: #define BUILD_ID_SIZE 128 -static char *dso__read_build_id(struct dso *self, int v) +static char *dso__read_build_id(struct dso *self) { int i; GElf_Ehdr ehdr; @@ -854,15 +848,13 @@ static char *dso__read_build_id(struct dso *self, int v) elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); if (elf == NULL) { - if (v) - fprintf(stderr, "%s: cannot read %s ELF file.\n", - __func__, self->long_name); + pr_err("%s: cannot read %s ELF file.\n", __func__, + self->long_name); goto out_close; } if (gelf_getehdr(elf, &ehdr) == NULL) { - if (v) - fprintf(stderr, "%s: cannot get elf header.\n", __func__); + pr_err("%s: cannot get elf header.\n", __func__); goto out_elf_end; } @@ -884,8 +876,7 @@ static char *dso__read_build_id(struct dso *self, int v) ++raw; bid += 2; } - if (v >= 2) - printf("%s(%s): %s\n", __func__, self->long_name, build_id); + pr_debug2("%s(%s): %s\n", __func__, self->long_name, build_id); out_elf_end: elf_end(elf); out_close: @@ -911,8 +902,7 @@ char dso__symtab_origin(const struct dso *self) return origin[self->origin]; } -int dso__load(struct dso *self, struct map *map, - symbol_filter_t filter, int v) +int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) { int size = PATH_MAX; char *name = malloc(size), *build_id = NULL; @@ -925,7 +915,7 @@ int dso__load(struct dso *self, struct map *map, self->adjust_symbols = 0; if (strncmp(self->name, "/tmp/perf-", 10) == 0) { - ret = dso__load_perf_map(self, map, filter, v); + ret = dso__load_perf_map(self, map, filter); self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : DSO__ORIG_NOT_FOUND; return ret; @@ -946,7 +936,7 @@ more: self->long_name); break; case DSO__ORIG_BUILDID: - build_id = dso__read_build_id(self, v); + build_id = dso__read_build_id(self); if (build_id != NULL) { snprintf(name, size, "/usr/lib/debug/.build-id/%.2s/%s.debug", @@ -967,7 +957,7 @@ more: fd = open(name, O_RDONLY); } while (fd < 0); - ret = dso__load_sym(self, map, name, fd, filter, 0, 0, v); + ret = dso__load_sym(self, map, name, fd, filter, 0, 0); close(fd); /* @@ -977,7 +967,7 @@ more: goto more; if (ret > 0) { - int nr_plt = dso__synthesize_plt_symbols(self, v); + int nr_plt = dso__synthesize_plt_symbols(self); if (nr_plt > 0) ret += nr_plt; } @@ -1025,34 +1015,29 @@ struct map *kernel_maps__find_by_dso_name(const char *name) } static int dso__load_module_sym(struct dso *self, struct map *map, - symbol_filter_t filter, int v) + symbol_filter_t filter) { 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); + 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, v); + 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, int v) +static int dsos__load_modules_sym_dir(char *dirname, symbol_filter_t filter) { struct dirent *dent; int nr_symbols = 0, err; DIR *dir = opendir(dirname); if (!dir) { - if (v) - fprintf(stderr, "%s: cannot open %s dir\n", __func__, - dirname); + pr_err("%s: cannot open %s dir\n", __func__, dirname); return -1; } @@ -1066,7 +1051,7 @@ static int dsos__load_modules_sym_dir(char *dirname, snprintf(path, sizeof(path), "%s/%s", dirname, dent->d_name); - err = dsos__load_modules_sym_dir(path, filter, v); + err = dsos__load_modules_sym_dir(path, filter); if (err < 0) goto failure; } else { @@ -1092,7 +1077,7 @@ static int dsos__load_modules_sym_dir(char *dirname, if (map->dso->long_name == NULL) goto failure; - err = dso__load_module_sym(map->dso, map, filter, v); + err = dso__load_module_sym(map->dso, map, filter); if (err < 0) goto failure; last = rb_last(&map->dso->syms); @@ -1119,7 +1104,7 @@ failure: return -1; } -static int dsos__load_modules_sym(symbol_filter_t filter, int v) +static int dsos__load_modules_sym(symbol_filter_t filter) { struct utsname uts; char modules_path[PATH_MAX]; @@ -1130,7 +1115,7 @@ static int dsos__load_modules_sym(symbol_filter_t filter, int v) snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", uts.release); - return dsos__load_modules_sym_dir(modules_path, filter, v); + return dsos__load_modules_sym_dir(modules_path, filter); } /* @@ -1225,15 +1210,14 @@ out_failure: } static int dso__load_vmlinux(struct dso *self, struct map *map, - const char *vmlinux, - symbol_filter_t filter, int v) + const char *vmlinux, symbol_filter_t filter) { int err, fd = open(vmlinux, O_RDONLY); if (fd < 0) return -1; - err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0, v); + err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0); close(fd); @@ -1241,7 +1225,7 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, } int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, - symbol_filter_t filter, int v, int use_modules) + symbol_filter_t filter, int use_modules) { int err = -1; struct dso *dso = dso__new(vmlinux, sym_priv_size); @@ -1257,26 +1241,26 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; if (use_modules && dsos__load_modules(sym_priv_size) < 0) { - fprintf(stderr, "Failed to load list of modules in use! " - "Continuing...\n"); + pr_warning("Failed to load list of modules in use! " + "Continuing...\n"); use_modules = 0; } if (vmlinux) { - err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v); + err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter); if (err > 0 && use_modules) { - int syms = dsos__load_modules_sym(filter, v); + int syms = dsos__load_modules_sym(filter); if (syms < 0) - fprintf(stderr, "Failed to read module symbols!" - " Continuing...\n"); + pr_warning("Failed to read module symbols!" + " Continuing...\n"); else err += syms; } } if (err <= 0) - err = kernel_maps__load_kallsyms(filter, use_modules, v); + err = kernel_maps__load_kallsyms(filter, use_modules); if (err > 0) { struct rb_node *node = rb_first(&dso->syms); @@ -1296,8 +1280,8 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, kernel_maps__fixup_end(); dsos__add(dso); - if (v > 0) - kernel_maps__fprintf(stderr, v); + if (verbose) + kernel_maps__fprintf(stderr); } return err; @@ -1355,8 +1339,8 @@ void dsos__fprintf(FILE *fp) int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter) { - if (dsos__load_kernel(vmlinux_name, sym_priv_size, - filter, verbose, modules) <= 0) + if (dsos__load_kernel(vmlinux_name, sym_priv_size, filter, + modules) <= 0) return -1; vdso = dso__new("[vdso]", 0); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index c2a777de9b7..77b7b3e4241 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -63,11 +63,10 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) struct symbol *dso__find_symbol(struct dso *self, u64 ip); int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, - symbol_filter_t filter, int verbose, int modules); + symbol_filter_t filter, int modules); struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size, bool *is_new); -int dso__load(struct dso *self, struct map *map, - symbol_filter_t filter, int v); +int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); void dsos__fprintf(FILE *fp); size_t dso__fprintf(struct dso *self, FILE *fp); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 8cb47f1d8a7..0f6d78c9863 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -127,9 +127,9 @@ static void thread__remove_overlappings(struct thread *self, struct map *map) continue; if (verbose >= 2) { - printf("overlapping maps:\n"); - map__fprintf(map, stdout); - map__fprintf(pos, stdout); + fputs("overlapping maps:\n", stderr); + map__fprintf(map, stderr); + map__fprintf(pos, stderr); } rb_erase(&pos->rb_node, &self->maps); -- cgit v1.2.3-70-g09d2 From 364794845cbc49e638b83d7ef739524291e1e961 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 24 Nov 2009 12:05:16 -0200 Subject: perf tools: Introduce zalloc() for the common calloc(1, N) case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way we type less characters and it looks more like the kzalloc kernel counterpart. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1259071517-3242-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar --- tools/perf/bench/mem-memcpy.c | 4 ++-- tools/perf/builtin-help.c | 4 ++-- tools/perf/builtin-probe.c | 4 ++-- tools/perf/builtin-sched.c | 14 +++++--------- tools/perf/builtin-top.c | 2 +- tools/perf/util/header.c | 2 +- tools/perf/util/parse-events.c | 2 +- tools/perf/util/symbol.c | 11 +++++------ tools/perf/util/thread.c | 2 +- tools/perf/util/util.h | 5 +++++ 10 files changed, 25 insertions(+), 25 deletions(-) (limited to 'tools/perf/util/thread.c') diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c index 5165fd1d8d2..89773178e89 100644 --- a/tools/perf/bench/mem-memcpy.c +++ b/tools/perf/bench/mem-memcpy.c @@ -127,11 +127,11 @@ int bench_mem_memcpy(int argc, const char **argv, return 1; } - dst = calloc(length, sizeof(char)); + dst = zalloc(length); if (!dst) die("memory allocation failed - maybe length is too large?\n"); - src = calloc(length, sizeof(char)); + src = zalloc(length); if (!src) die("memory allocation failed - maybe length is too large?\n"); diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 768f9c82631..9f810b17c25 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -179,7 +179,7 @@ static void add_man_viewer(const char *name) while (*p) p = &((*p)->next); - *p = calloc(1, (sizeof(**p) + len + 1)); + *p = zalloc(sizeof(**p) + len + 1); strncpy((*p)->name, name, len); } @@ -194,7 +194,7 @@ static void do_add_man_viewer_info(const char *name, size_t len, const char *value) { - struct man_viewer_info_list *new = calloc(1, sizeof(*new) + len + 1); + struct man_viewer_info_list *new = zalloc(sizeof(*new) + len + 1); strncpy(new->name, name, len); new->info = strdup(value); diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index d78a3d94549..a2f6daf01ec 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -309,9 +309,9 @@ static int synthesize_probe_event(struct probe_point *pp) { char *buf; int i, len, ret; - pp->probes[0] = buf = (char *)calloc(MAX_CMDLEN, sizeof(char)); + pp->probes[0] = buf = zalloc(MAX_CMDLEN); if (!buf) - die("Failed to allocate memory by calloc."); + die("Failed to allocate memory by zalloc."); ret = snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset); if (ret <= 0 || ret >= MAX_CMDLEN) goto error; diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index dbf089b12de..19eb708a706 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -225,7 +225,7 @@ static void calibrate_sleep_measurement_overhead(void) static struct sched_atom * get_new_event(struct task_desc *task, u64 timestamp) { - struct sched_atom *event = calloc(1, sizeof(*event)); + struct sched_atom *event = zalloc(sizeof(*event)); unsigned long idx = task->nr_events; size_t size; @@ -293,7 +293,7 @@ add_sched_event_wakeup(struct task_desc *task, u64 timestamp, return; } - wakee_event->wait_sem = calloc(1, sizeof(*wakee_event->wait_sem)); + wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem)); sem_init(wakee_event->wait_sem, 0, 0); wakee_event->specific_wait = 1; event->wait_sem = wakee_event->wait_sem; @@ -323,7 +323,7 @@ static struct task_desc *register_pid(unsigned long pid, const char *comm) if (task) return task; - task = calloc(1, sizeof(*task)); + task = zalloc(sizeof(*task)); task->pid = pid; task->nr = nr_tasks; strcpy(task->comm, comm); @@ -962,9 +962,7 @@ __thread_latency_insert(struct rb_root *root, struct work_atoms *data, static void thread_atoms_insert(struct thread *thread) { - struct work_atoms *atoms; - - atoms = calloc(sizeof(*atoms), 1); + struct work_atoms *atoms = zalloc(sizeof(*atoms)); if (!atoms) die("No memory"); @@ -996,9 +994,7 @@ add_sched_out_event(struct work_atoms *atoms, char run_state, u64 timestamp) { - struct work_atom *atom; - - atom = calloc(sizeof(*atom), 1); + struct work_atom *atom = zalloc(sizeof(*atom)); if (!atom) die("Non memory"); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a21247543fc..4c8653a86aa 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -181,7 +181,7 @@ static void parse_source(struct sym_entry *syme) return; if (syme->src == NULL) { - syme->src = calloc(1, sizeof(*source)); + syme->src = zalloc(sizeof(*source)); if (syme->src == NULL) return; pthread_mutex_init(&syme->src->lock, NULL); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 271a1600e6f..4b586569bb0 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -63,7 +63,7 @@ int perf_header_attr__add_id(struct perf_header_attr *self, u64 id) */ struct perf_header *perf_header__new(void) { - struct perf_header *self = calloc(sizeof(*self), 1); + struct perf_header *self = zalloc(sizeof(*self)); if (self != NULL) { self->size = 1; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 07002746927..9e5dbd66d34 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -197,7 +197,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) if (id == config) { closedir(evt_dir); closedir(sys_dir); - path = calloc(1, sizeof(path)); + path = zalloc(sizeof(path)); path->system = malloc(MAX_EVENT_LENGTH); if (!path->system) { free(path); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index c4ca974b36e..8db85b4f553 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -94,15 +94,14 @@ static void kernel_maps__fixup_end(void) static struct symbol *symbol__new(u64 start, u64 len, const char *name) { size_t namelen = strlen(name) + 1; - struct symbol *self = calloc(1, (symbol__priv_size + - sizeof(*self) + namelen)); - if (!self) + struct symbol *self = zalloc(symbol__priv_size + + sizeof(*self) + namelen); + if (self == NULL) return NULL; - if (symbol__priv_size) { - memset(self, 0, symbol__priv_size); + if (symbol__priv_size) self = ((void *)self) + symbol__priv_size; - } + self->start = start; self->end = len ? start + len - 1 : start; diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 0f6d78c9863..1796625f778 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -11,7 +11,7 @@ static struct thread *last_match; static struct thread *thread__new(pid_t pid) { - struct thread *self = calloc(1, sizeof(*self)); + struct thread *self = zalloc(sizeof(*self)); if (self != NULL) { self->pid = pid; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index e1c623e0c99..30c5517f2f9 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -302,6 +302,11 @@ extern int xdup(int fd); extern FILE *xfdopen(int fd, const char *mode); extern int xmkstemp(char *template); +static inline void *zalloc(size_t size) +{ + return calloc(1, size); +} + static inline size_t xsize_t(off_t len) { return (size_t)len; -- 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.c') 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 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.c') 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