From 608c34de0b3d7bd15340a95ef758b4d8b81ebfc6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 1 Sep 2016 17:54:31 -0300 Subject: perf symbols: Mark if a symbol is idle in the library This was being done just in 'perf top', but grouping idle symbols should be useful in other places as well, so remove one more symbol_filter_t user by moving this to the symbol library. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-5r7xitjkzjr9jak1zy3d8u5l@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e091900..6f48df1 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -679,9 +679,6 @@ static int symbol_filter(struct map *map, struct symbol *sym) strstr(name, "_text_end")) return 1; - if (symbol__is_idle(sym)) - sym->idle = 1; - return 0; } diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 295d314..bd91a4f 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1127,7 +1127,7 @@ new_symbol: if (filter && filter(curr_map, f)) symbol__delete(f); else { - symbols__insert(&curr_dso->symbols[curr_map->type], f); + __symbols__insert(&curr_dso->symbols[curr_map->type], f, dso->kernel); nr++; } } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 98cd503..4c5788f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -28,6 +28,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, symbol_filter_t filter); static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, symbol_filter_t filter); +static bool symbol__is_idle(const char *name); + int vmlinux_path__nr_entries; char **vmlinux_path; @@ -277,13 +279,24 @@ void symbols__delete(struct rb_root *symbols) } } -void symbols__insert(struct rb_root *symbols, struct symbol *sym) +void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel) { struct rb_node **p = &symbols->rb_node; struct rb_node *parent = NULL; const u64 ip = sym->start; struct symbol *s; + if (kernel) { + const char *name = sym->name; + /* + * ppc64 uses function descriptors and appends a '.' to the + * start of every instruction address. Remove it. + */ + if (name[0] == '.') + name++; + sym->idle = symbol__is_idle(name); + } + while (*p != NULL) { parent = *p; s = rb_entry(parent, struct symbol, rb_node); @@ -296,6 +309,11 @@ void symbols__insert(struct rb_root *symbols, struct symbol *sym) rb_insert_color(&sym->rb_node, symbols); } +void symbols__insert(struct rb_root *symbols, struct symbol *sym) +{ + __symbols__insert(symbols, sym, false); +} + static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) { struct rb_node *n; @@ -424,7 +442,7 @@ void dso__reset_find_symbol_cache(struct dso *dso) void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym) { - symbols__insert(&dso->symbols[type], sym); + __symbols__insert(&dso->symbols[type], sym, dso->kernel); /* update the symbol cache if necessary */ if (dso->last_find_result[type].addr >= sym->start && @@ -546,7 +564,7 @@ struct process_kallsyms_args { * These are symbols in the kernel image, so make sure that * sym is from a kernel DSO. */ -bool symbol__is_idle(struct symbol *sym) +static bool symbol__is_idle(const char *name) { const char * const idle_symbols[] = { "cpu_idle", @@ -563,14 +581,10 @@ bool symbol__is_idle(struct symbol *sym) "pseries_dedicated_idle_sleep", NULL }; - int i; - if (!sym) - return false; - for (i = 0; idle_symbols[i]; i++) { - if (!strcmp(idle_symbols[i], sym->name)) + if (!strcmp(idle_symbols[i], name)) return true; } @@ -599,7 +613,7 @@ static int map__process_kallsym_symbol(void *arg, const char *name, * We will pass the symbols to the filter later, in * map__split_kallsyms, when we have split the maps per module */ - symbols__insert(root, sym); + __symbols__insert(root, sym, !strchr(name, '[')); return 0; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index e54ee7c..72d2931 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -294,7 +294,6 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp); bool symbol_type__is_a(char symbol_type, enum map_type map_type); bool symbol__restricted_filename(const char *filename, const char *restricted_filename); -bool symbol__is_idle(struct symbol *sym); int symbol__config_symfs(const struct option *opt __maybe_unused, const char *dir, int unset __maybe_unused); @@ -304,6 +303,7 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map, symbol_filter_t filter); +void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel); void symbols__insert(struct rb_root *symbols, struct symbol *sym); void symbols__fixup_duplicate(struct rb_root *symbols); void symbols__fixup_end(struct rb_root *symbols); -- cgit v0.10.2 From b6220212d48a9bfbc694d10b38dbdfbaab81f4a0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 1 Sep 2016 18:47:15 -0300 Subject: perf top: Remove old kernel-only symbol filter Not needed, we already have code to prune aliases. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-1ysyce7qjgui93gi1efbjwhf@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 6f48df1..4007857 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -657,31 +657,6 @@ repeat: return NULL; } -static int symbol_filter(struct map *map, struct symbol *sym) -{ - const char *name = sym->name; - - if (!__map__is_kernel(map)) - return 0; - /* - * ppc64 uses function descriptors and appends a '.' to the - * start of every instruction address. Remove it. - */ - if (name[0] == '.') - name++; - - if (!strcmp(name, "_text") || - !strcmp(name, "_etext") || - !strcmp(name, "_sinittext") || - !strncmp("init_module", name, 11) || - !strncmp("cleanup_module", name, 14) || - strstr(name, "_text_start") || - strstr(name, "_text_end")) - return 1; - - return 0; -} - static int hist_iter__top_callback(struct hist_entry_iter *iter, struct addr_location *al, bool single, void *arg) @@ -946,8 +921,6 @@ static int __cmd_top(struct perf_top *top) if (top->session == NULL) return -1; - machines__set_symbol_filter(&top->session->machines, symbol_filter); - if (!objdump_path) { ret = perf_env__lookup_objdump(&top->session->header.env); if (ret) -- cgit v0.10.2 From 0890e97c20333c439a9bda6a94dd16ed5f508429 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 1 Sep 2016 18:53:58 -0300 Subject: perf machine: Remove machine->symbol_filter and friends Including machines__set_symbol_filter(), not used anymore. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-7o1qgmrpvzuis4a9f0t8mnri@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index e20438b..2f91183 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -1286,7 +1286,7 @@ try_again: * must be done prior to using kernel maps. */ if (load_map) - map__load(al->map, machine->symbol_filter); + map__load(al->map, NULL); al->addr = al->map->map_ip(al->map, al->addr); } } @@ -1297,8 +1297,7 @@ void thread__find_addr_location(struct thread *thread, { thread__find_addr_map(thread, cpumode, type, addr, al); if (al->map != NULL) - al->sym = map__find_symbol(al->map, al->addr, - thread->mg->machine->symbol_filter); + al->sym = map__find_symbol(al->map, al->addr, NULL); else al->sym = NULL; } @@ -1359,8 +1358,7 @@ int machine__resolve(struct machine *machine, struct addr_location *al, al->filtered |= (1 << HIST_FILTER__DSO); } - al->sym = map__find_symbol(al->map, al->addr, - machine->symbol_filter); + al->sym = map__find_symbol(al->map, al->addr, NULL); } if (symbol_conf.sym_list && diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index 749e6f2..240b095 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c @@ -346,7 +346,7 @@ static int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip) goto out_put; /* Load maps to ensure dso->is_64_bit has been updated */ - map__load(al.map, machine->symbol_filter); + map__load(al.map, NULL); x86_64 = al.map->dso->is_64_bit; diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 551ff6f..d594052 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -477,7 +477,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, start_ip = *ip; /* Load maps to ensure dso->is_64_bit has been updated */ - map__load(al.map, machine->symbol_filter); + map__load(al.map, NULL); x86_64 = al.map->dso->is_64_bit; @@ -1294,7 +1294,7 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip) if (!map) return 0; - if (map__load(map, machine->symbol_filter)) + if (map__load(map, NULL)) return 0; start = dso__first_symbol(map->dso, MAP__FUNCTION); diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index cb6388d..7940ddc 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -41,7 +41,6 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) machine->pid = pid; - machine->symbol_filter = NULL; machine->id_hdr_size = 0; machine->kptr_restrict_warned = false; machine->comm_exec = false; @@ -148,7 +147,6 @@ void machines__init(struct machines *machines) { machine__init(&machines->host, "", HOST_KERNEL_ID); machines->guests = RB_ROOT; - machines->symbol_filter = NULL; } void machines__exit(struct machines *machines) @@ -172,8 +170,6 @@ struct machine *machines__add(struct machines *machines, pid_t pid, return NULL; } - machine->symbol_filter = machines->symbol_filter; - while (*p != NULL) { parent = *p; pos = rb_entry(parent, struct machine, rb_node); @@ -189,21 +185,6 @@ struct machine *machines__add(struct machines *machines, pid_t pid, return machine; } -void machines__set_symbol_filter(struct machines *machines, - symbol_filter_t symbol_filter) -{ - struct rb_node *nd; - - machines->symbol_filter = symbol_filter; - machines->host.symbol_filter = symbol_filter; - - for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { - struct machine *machine = rb_entry(nd, struct machine, rb_node); - - machine->symbol_filter = symbol_filter; - } -} - void machines__set_comm_exec(struct machines *machines, bool comm_exec) { struct rb_node *nd; @@ -2115,7 +2096,7 @@ int machine__get_kernel_start(struct machine *machine) */ machine->kernel_start = 1ULL << 63; if (map) { - err = map__load(map, machine->symbol_filter); + err = map__load(map, NULL); if (map->start) machine->kernel_start = map->start; } diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 20739f7..b9e5588 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -41,7 +41,6 @@ struct machine { struct map_groups kmaps; struct map *vmlinux_maps[MAP__NR_TYPES]; u64 kernel_start; - symbol_filter_t symbol_filter; pid_t *current_tid; union { /* Tool specific area */ void *priv; @@ -110,7 +109,6 @@ typedef void (*machine__process_t)(struct machine *machine, void *data); struct machines { struct machine host; struct rb_root guests; - symbol_filter_t symbol_filter; }; void machines__init(struct machines *machines); @@ -128,8 +126,6 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid); void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size); char *machine__mmap_name(struct machine *machine, char *bf, size_t size); -void machines__set_symbol_filter(struct machines *machines, - symbol_filter_t symbol_filter); void machines__set_comm_exec(struct machines *machines, bool comm_exec); struct machine *machine__new_host(void); -- cgit v0.10.2 From c79c809197bf4faaf109d1a7bdc27ecedac375de Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 1 Sep 2016 19:22:02 -0300 Subject: perf test vmlinux: Remove dead symbol_filter_t code We don't need to initialize that area as we're not using it afterwards, leftover, ditch it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-jb2un8buy4rqawz73mcdm1sn@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 77513bf..e6925d6 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -8,14 +8,6 @@ #include "debug.h" #include "machine.h" -static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused, - struct symbol *sym) -{ - bool *visited = symbol__priv(sym); - *visited = true; - return 0; -} - #define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x)) int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) @@ -100,8 +92,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) * maps__reloc_vmlinux will notice and set proper ->[un]map_ip routines * to fixup the symbols. */ - if (machine__load_vmlinux_path(&vmlinux, type, - vmlinux_matches_kallsyms_filter) <= 0) { + if (machine__load_vmlinux_path(&vmlinux, type, NULL) <= 0) { pr_debug("Couldn't find a vmlinux that matches the kernel running on this machine, skipping test\n"); err = TEST_SKIP; goto out; -- cgit v0.10.2 From be39db9f2932f0ce4e116c71ba5ae2b542e536a7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 1 Sep 2016 19:25:52 -0300 Subject: perf symbols: Remove symbol_filter_t machinery We're not using it anymore, few users were, but we really could do without it, simplify lots of functions by removing it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-1zng8wdznn00iiz08bb7q3vn@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index 35745a7..ed9d5d1 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c @@ -108,7 +108,7 @@ void arch__post_process_probe_trace_events(struct perf_probe_event *pev, int i = 0; map = get_target_map(pev->target, pev->uprobes); - if (!map || map__load(map, NULL) < 0) + if (!map || map__load(map) < 0) return; for (i = 0; i < ntevs; i++) { diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 73c1c4c..b9bc7e3 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -429,7 +429,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, if (al.map != NULL) { if (!al.map->dso->hit) { al.map->dso->hit = 1; - if (map__load(al.map, NULL) >= 0) { + if (map__load(al.map) >= 0) { dso__inject_build_id(al.map->dso, tool, machine); /* * If this fails, too bad, let the other side diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index fdde1bd..d426dcb 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -330,7 +330,7 @@ static int build_alloc_func_list(void) } kernel_map = machine__kernel_map(machine); - if (map__load(kernel_map, NULL) < 0) { + if (map__load(kernel_map) < 0) { pr_err("cannot load kernel map\n"); return -ENOENT; } @@ -979,7 +979,7 @@ static void __print_slab_result(struct rb_root *root, if (is_caller) { addr = data->call_site; if (!raw_ip) - sym = machine__find_kernel_function(machine, addr, &map, NULL); + sym = machine__find_kernel_function(machine, addr, &map); } else addr = data->ptr; @@ -1043,8 +1043,7 @@ static void __print_page_alloc_result(struct perf_session *session, int n_lines) char *caller = buf; data = rb_entry(next, struct page_stat, node); - sym = machine__find_kernel_function(machine, data->callsite, - &map, NULL); + sym = machine__find_kernel_function(machine, data->callsite, &map); if (sym && sym->name) caller = sym->name; else @@ -1086,8 +1085,7 @@ static void __print_page_caller_result(struct perf_session *session, int n_lines char *caller = buf; data = rb_entry(next, struct page_stat, node); - sym = machine__find_kernel_function(machine, data->callsite, - &map, NULL); + sym = machine__find_kernel_function(machine, data->callsite, &map); if (sym && sym->name) caller = sym->name; else diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 6b3c8b0..7228d14 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -522,11 +522,11 @@ static void print_sample_brstacksym(struct perf_sample *sample, thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf); if (alf.map) - alf.sym = map__find_symbol(alf.map, alf.addr, NULL); + alf.sym = map__find_symbol(alf.map, alf.addr); thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt); if (alt.map) - alt.sym = map__find_symbol(alt.map, alt.addr, NULL); + alt.sym = map__find_symbol(alt.map, alt.addr); symbol__fprintf_symname_offs(alf.sym, &alf, stdout); putchar('/'); diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 2af156a..ff5bc63 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -263,7 +263,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, * Converting addresses for use by objdump requires more information. * map__load() does that. See map__rip_2objdump() for details. */ - if (map__load(al.map, NULL)) + if (map__load(al.map)) return -1; /* objdump struggles with kcore - try each map only once */ @@ -511,7 +511,7 @@ static int do_test_code_reading(bool try_kcore) /* Load kernel map */ map = machine__kernel_map(machine); - ret = map__load(map, NULL); + ret = map__load(map); if (ret < 0) { pr_debug("map__load failed\n"); goto out_err; diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index e6925d6..a508233 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -54,7 +54,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) * be compacted against the list of modules found in the "vmlinux" * code and with the one got from /proc/modules from the "kallsyms" code. */ - if (__machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, true, NULL) <= 0) { + if (__machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, true) <= 0) { pr_debug("dso__load_kallsyms "); goto out; } @@ -92,7 +92,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) * maps__reloc_vmlinux will notice and set proper ->[un]map_ip routines * to fixup the symbols. */ - if (machine__load_vmlinux_path(&vmlinux, type, NULL) <= 0) { + if (machine__load_vmlinux_path(&vmlinux, type) <= 0) { pr_debug("Couldn't find a vmlinux that matches the kernel running on this machine, skipping test\n"); err = TEST_SKIP; goto out; @@ -118,7 +118,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) mem_end = vmlinux_map->unmap_ip(vmlinux_map, sym->end); first_pair = machine__find_kernel_symbol(&kallsyms, type, - mem_start, NULL, NULL); + mem_start, NULL); pair = first_pair; if (pair && UM(pair->start) == mem_start) { @@ -147,7 +147,7 @@ next_pair: */ continue; } else { - pair = machine__find_kernel_symbol_by_name(&kallsyms, type, sym->name, NULL, NULL); + pair = machine__find_kernel_symbol_by_name(&kallsyms, type, sym->name, NULL); if (pair) { if (UM(pair->start) == mem_start) goto next_pair; diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 2e2d100..4c18271 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -495,7 +495,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, if (!ins__is_call(dl->ins)) return false; - if (map_groups__find_ams(&target, NULL) || + if (map_groups__find_ams(&target) || map__rip_2objdump(target.map, target.map->map_ip(target.map, target.addr)) != dl->ops.target.addr) { diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c index 8091277..98a3466 100644 --- a/tools/perf/ui/browsers/map.c +++ b/tools/perf/ui/browsers/map.c @@ -52,9 +52,9 @@ static int map_browser__search(struct map_browser *browser) if (target[0] == '0' && tolower(target[1]) == 'x') { u64 addr = strtoull(target, NULL, 16); - sym = map__find_symbol(browser->map, addr, NULL); + sym = map__find_symbol(browser->map, addr); } else - sym = map__find_symbol_by_name(browser->map, target, NULL); + sym = map__find_symbol_by_name(browser->map, target); if (sym != NULL) { u32 *idx = symbol__browser_index(sym); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 1b59e31..2ff6bd7 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1077,7 +1077,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, .addr = dl->ops.target.addr, }; - if (!map_groups__find_ams(&target, NULL) && + if (!map_groups__find_ams(&target) && target.sym->start == target.al_addr) dl->ops.target.name = strdup(target.sym->name); } diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 2f91183..9ad7d32 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -1286,7 +1286,7 @@ try_again: * must be done prior to using kernel maps. */ if (load_map) - map__load(al->map, NULL); + map__load(al->map); al->addr = al->map->map_ip(al->map, al->addr); } } @@ -1297,7 +1297,7 @@ void thread__find_addr_location(struct thread *thread, { thread__find_addr_map(thread, cpumode, type, addr, al); if (al->map != NULL) - al->sym = map__find_symbol(al->map, al->addr, NULL); + al->sym = map__find_symbol(al->map, al->addr); else al->sym = NULL; } @@ -1358,7 +1358,7 @@ int machine__resolve(struct machine *machine, struct addr_location *al, al->filtered |= (1 << HIST_FILTER__DSO); } - al->sym = map__find_symbol(al->map, al->addr, NULL); + al->sym = map__find_symbol(al->map, al->addr); } if (symbol_conf.sym_list && @@ -1414,5 +1414,5 @@ void thread__resolve(struct thread *thread, struct addr_location *al, al->sym = NULL; if (al->map) - al->sym = map__find_symbol(al->map, al->addr, NULL); + al->sym = map__find_symbol(al->map, al->addr); } diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index 240b095..f545ec1 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c @@ -346,7 +346,7 @@ static int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip) goto out_put; /* Load maps to ensure dso->is_64_bit has been updated */ - map__load(al.map, NULL); + map__load(al.map); x86_64 = al.map->dso->is_64_bit; diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index d594052..b9cc353 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -477,7 +477,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn, start_ip = *ip; /* Load maps to ensure dso->is_64_bit has been updated */ - map__load(al.map, NULL); + map__load(al.map); x86_64 = al.map->dso->is_64_bit; @@ -1294,7 +1294,7 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip) if (!map) return 0; - if (map__load(map, NULL)) + if (map__load(map)) return 0; start = dso__first_symbol(map->dso, MAP__FUNCTION); diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 7940ddc..18e4519 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -897,10 +897,10 @@ int machines__create_kernel_maps(struct machines *machines, pid_t pid) } int __machine__load_kallsyms(struct machine *machine, const char *filename, - enum map_type type, bool no_kcore, symbol_filter_t filter) + enum map_type type, bool no_kcore) { struct map *map = machine__kernel_map(machine); - int ret = __dso__load_kallsyms(map->dso, filename, map, no_kcore, filter); + int ret = __dso__load_kallsyms(map->dso, filename, map, no_kcore); if (ret > 0) { dso__set_loaded(map->dso, type); @@ -916,16 +916,15 @@ int __machine__load_kallsyms(struct machine *machine, const char *filename, } int machine__load_kallsyms(struct machine *machine, const char *filename, - enum map_type type, symbol_filter_t filter) + enum map_type type) { - return __machine__load_kallsyms(machine, filename, type, false, filter); + return __machine__load_kallsyms(machine, filename, type, false); } -int machine__load_vmlinux_path(struct machine *machine, enum map_type type, - symbol_filter_t filter) +int machine__load_vmlinux_path(struct machine *machine, enum map_type type) { struct map *map = machine__kernel_map(machine); - int ret = dso__load_vmlinux_path(map->dso, map, filter); + int ret = dso__load_vmlinux_path(map->dso, map); if (ret > 0) dso__set_loaded(map->dso, type); @@ -1294,7 +1293,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine, /* * preload dso of guest kernel and modules */ - dso__load(kernel, machine__kernel_map(machine), NULL); + dso__load(kernel, machine__kernel_map(machine)); } } return 0; @@ -2096,7 +2095,7 @@ int machine__get_kernel_start(struct machine *machine) */ machine->kernel_start = 1ULL << 63; if (map) { - err = map__load(map, NULL); + err = map__load(map); if (map->start) machine->kernel_start = map->start; } @@ -2112,7 +2111,7 @@ char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, ch { struct machine *machine = vmachine; struct map *map; - struct symbol *sym = map_groups__find_symbol(&machine->kmaps, MAP__FUNCTION, *addrp, &map, NULL); + struct symbol *sym = map_groups__find_symbol(&machine->kmaps, MAP__FUNCTION, *addrp, &map); if (sym == NULL) return NULL; diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index b9e5588..354de6e 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -174,40 +174,33 @@ size_t machine__fprintf(struct machine *machine, FILE *fp); static inline struct symbol *machine__find_kernel_symbol(struct machine *machine, enum map_type type, u64 addr, - struct map **mapp, - symbol_filter_t filter) + struct map **mapp) { - return map_groups__find_symbol(&machine->kmaps, type, addr, - mapp, filter); + return map_groups__find_symbol(&machine->kmaps, type, addr, mapp); } static inline struct symbol *machine__find_kernel_symbol_by_name(struct machine *machine, enum map_type type, const char *name, - struct map **mapp, - symbol_filter_t filter) + struct map **mapp) { - return map_groups__find_symbol_by_name(&machine->kmaps, type, name, - mapp, filter); + return map_groups__find_symbol_by_name(&machine->kmaps, type, name, mapp); } static inline struct symbol *machine__find_kernel_function(struct machine *machine, u64 addr, - struct map **mapp, - symbol_filter_t filter) + struct map **mapp) { return machine__find_kernel_symbol(machine, MAP__FUNCTION, addr, - mapp, filter); + mapp); } static inline struct symbol *machine__find_kernel_function_by_name(struct machine *machine, const char *name, - struct map **mapp, - symbol_filter_t filter) + struct map **mapp) { - return map_groups__find_function_by_name(&machine->kmaps, name, mapp, - filter); + return map_groups__find_function_by_name(&machine->kmaps, name, mapp); } struct map *machine__findnew_module_map(struct machine *machine, u64 start, @@ -215,11 +208,10 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start, int arch__fix_module_text_start(u64 *start, const char *name); int __machine__load_kallsyms(struct machine *machine, const char *filename, - enum map_type type, bool no_kcore, symbol_filter_t filter); + enum map_type type, bool no_kcore); int machine__load_kallsyms(struct machine *machine, const char *filename, - enum map_type type, symbol_filter_t filter); -int machine__load_vmlinux_path(struct machine *machine, enum map_type type, - symbol_filter_t filter); + enum map_type type); +int machine__load_vmlinux_path(struct machine *machine, enum map_type type); size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 728129a..0c54adb 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -279,7 +279,7 @@ void map__fixup_end(struct map *map) #define DSO__DELETED "(deleted)" -int map__load(struct map *map, symbol_filter_t filter) +int map__load(struct map *map) { const char *name = map->dso->long_name; int nr; @@ -287,7 +287,7 @@ int map__load(struct map *map, symbol_filter_t filter) if (dso__loaded(map->dso, map->type)) return 0; - nr = dso__load(map->dso, map, filter); + nr = dso__load(map->dso, map); if (nr < 0) { if (map->dso->has_build_id) { char sbuild_id[SBUILD_ID_SIZE]; @@ -312,9 +312,6 @@ int map__load(struct map *map, symbol_filter_t filter) pr_warning("%.*s was updated (is prelink enabled?). " "Restart the long running apps that use it!\n", (int)real_len, name); - } else if (filter) { - pr_warning("no symbols passed the given filter.\n"); - return -2; /* Empty but maybe by the filter */ } else { pr_warning("no symbols found in %s, maybe install " "a debug package?\n", name); @@ -331,19 +328,17 @@ int __weak arch__compare_symbol_names(const char *namea, const char *nameb) return strcmp(namea, nameb); } -struct symbol *map__find_symbol(struct map *map, u64 addr, - symbol_filter_t filter) +struct symbol *map__find_symbol(struct map *map, u64 addr) { - if (map__load(map, filter) < 0) + if (map__load(map) < 0) return NULL; return dso__find_symbol(map->dso, map->type, addr); } -struct symbol *map__find_symbol_by_name(struct map *map, const char *name, - symbol_filter_t filter) +struct symbol *map__find_symbol_by_name(struct map *map, const char *name) { - if (map__load(map, filter) < 0) + if (map__load(map) < 0) return NULL; if (!dso__sorted_by_name(map->dso, map->type)) @@ -556,23 +551,22 @@ void map_groups__put(struct map_groups *mg) struct symbol *map_groups__find_symbol(struct map_groups *mg, enum map_type type, u64 addr, - struct map **mapp, - symbol_filter_t filter) + struct map **mapp) { struct map *map = map_groups__find(mg, type, addr); /* Ensure map is loaded before using map->map_ip */ - if (map != NULL && map__load(map, filter) >= 0) { + if (map != NULL && map__load(map) >= 0) { if (mapp != NULL) *mapp = map; - return map__find_symbol(map, map->map_ip(map, addr), filter); + return map__find_symbol(map, map->map_ip(map, addr)); } return NULL; } struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, - struct map **mapp, symbol_filter_t filter) + struct map **mapp) { struct symbol *sym; struct rb_node *nd; @@ -582,7 +576,7 @@ struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) { struct map *pos = rb_entry(nd, struct map, rb_node); - sym = map__find_symbol_by_name(pos, name, filter); + sym = map__find_symbol_by_name(pos, name); if (sym == NULL) continue; @@ -600,15 +594,14 @@ out: struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, enum map_type type, const char *name, - struct map **mapp, - symbol_filter_t filter) + struct map **mapp) { - struct symbol *sym = maps__find_symbol_by_name(&mg->maps[type], name, mapp, filter); + struct symbol *sym = maps__find_symbol_by_name(&mg->maps[type], name, mapp); return sym; } -int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter) +int map_groups__find_ams(struct addr_map_symbol *ams) { if (ams->addr < ams->map->start || ams->addr >= ams->map->end) { if (ams->map->groups == NULL) @@ -620,7 +613,7 @@ int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter) } ams->al_addr = ams->map->map_ip(ams->map, ams->addr); - ams->sym = map__find_symbol(ams->map, ams->al_addr, filter); + ams->sym = map__find_symbol(ams->map, ams->al_addr); return ams->sym ? 0 : -1; } diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index d83396c..abdacf8 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -127,17 +127,14 @@ struct thread; * @map: the 'struct map *' in which symbols itereated * @sym_name: the symbol name * @pos: the 'struct symbol *' to use as a loop cursor - * @filter: to use when loading the DSO */ -#define __map__for_each_symbol_by_name(map, sym_name, pos, filter) \ - for (pos = map__find_symbol_by_name(map, sym_name, filter); \ +#define __map__for_each_symbol_by_name(map, sym_name, pos) \ + for (pos = map__find_symbol_by_name(map, sym_name); \ pos && arch__compare_symbol_names(pos->name, sym_name) == 0; \ pos = symbol__next_by_name(pos)) #define map__for_each_symbol_by_name(map, sym_name, pos) \ - __map__for_each_symbol_by_name(map, sym_name, (pos), NULL) - -typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); + __map__for_each_symbol_by_name(map, sym_name, (pos)) int arch__compare_symbol_names(const char *namea, const char *nameb); void map__init(struct map *map, enum map_type type, @@ -173,11 +170,9 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp); int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, FILE *fp); -int map__load(struct map *map, symbol_filter_t filter); -struct symbol *map__find_symbol(struct map *map, - u64 addr, symbol_filter_t filter); -struct symbol *map__find_symbol_by_name(struct map *map, const char *name, - symbol_filter_t filter); +int map__load(struct map *map); +struct symbol *map__find_symbol(struct map *map, u64 addr); +struct symbol *map__find_symbol_by_name(struct map *map, const char *name); void map__fixup_start(struct map *map); void map__fixup_end(struct map *map); @@ -191,7 +186,7 @@ struct map *maps__find(struct maps *maps, u64 addr); struct map *maps__first(struct maps *maps); struct map *map__next(struct map *map); struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, - struct map **mapp, symbol_filter_t filter); + struct map **mapp); void map_groups__init(struct map_groups *mg, struct machine *machine); void map_groups__exit(struct map_groups *mg); int map_groups__clone(struct thread *thread, @@ -231,25 +226,22 @@ static inline struct map *map_groups__next(struct map *map) struct symbol *map_groups__find_symbol(struct map_groups *mg, enum map_type type, u64 addr, - struct map **mapp, - symbol_filter_t filter); + struct map **mapp); struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, enum map_type type, const char *name, - struct map **mapp, - symbol_filter_t filter); + struct map **mapp); struct addr_map_symbol; -int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter); +int map_groups__find_ams(struct addr_map_symbol *ams); static inline struct symbol *map_groups__find_function_by_name(struct map_groups *mg, - const char *name, struct map **mapp, - symbol_filter_t filter) + const char *name, struct map **mapp) { - return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter); + return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp); } int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index a543e9c..bc60ce4 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -110,13 +110,12 @@ void exit_probe_symbol_maps(void) static struct symbol *__find_kernel_function_by_name(const char *name, struct map **mapp) { - return machine__find_kernel_function_by_name(host_machine, name, mapp, - NULL); + return machine__find_kernel_function_by_name(host_machine, name, mapp); } static struct symbol *__find_kernel_function(u64 addr, struct map **mapp) { - return machine__find_kernel_function(host_machine, addr, mapp, NULL); + return machine__find_kernel_function(host_machine, addr, mapp); } static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void) @@ -125,7 +124,7 @@ static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void) struct kmap *kmap; struct map *map = machine__kernel_map(host_machine); - if (map__load(map, NULL) < 0) + if (map__load(map) < 0) return NULL; kmap = map__kmap(map); @@ -351,9 +350,9 @@ static int kernel_get_module_dso(const char *module, struct dso **pdso) vmlinux_name = symbol_conf.vmlinux_name; dso->load_errno = 0; if (vmlinux_name) - ret = dso__load_vmlinux(dso, map, vmlinux_name, false, NULL); + ret = dso__load_vmlinux(dso, map, vmlinux_name, false); else - ret = dso__load_vmlinux_path(dso, map, NULL); + ret = dso__load_vmlinux_path(dso, map); found: *pdso = dso; return ret; @@ -1999,7 +1998,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp, map = dso__new_map(tp->module); if (!map) goto out; - sym = map__find_symbol(map, addr, NULL); + sym = map__find_symbol(map, addr); } else { if (tp->symbol && !addr) { if (kernel_get_symbol_address_by_name(tp->symbol, @@ -2704,7 +2703,7 @@ static int find_probe_functions(struct map *map, char *name, struct symbol *sym; struct rb_node *tmp; - if (map__load(map, NULL) < 0) + if (map__load(map) < 0) return 0; map__for_each_symbol(map, sym, tmp) { @@ -3368,7 +3367,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter, return -EINVAL; } - ret = map__load(map, NULL); + ret = map__load(map); if (ret) { if (ret == -2) { char *str = strfilter__string(_filter); diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index bd91a4f..99400b0 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -254,8 +254,7 @@ static char *demangle_sym(struct dso *dso, int kmodule, const char *elf_name) * 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). */ -int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map, - symbol_filter_t filter) +int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map) { uint32_t nr_rel_entries, idx; GElf_Sym sym; @@ -351,12 +350,8 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map * if (!f) goto out_elf_end; - if (filter && filter(map, f)) - symbol__delete(f); - else { - symbols__insert(&dso->symbols[map->type], f); - ++nr; - } + symbols__insert(&dso->symbols[map->type], f); + ++nr; } } else if (shdr_rel_plt.sh_type == SHT_REL) { GElf_Rel pos_mem, *pos; @@ -381,12 +376,8 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map * if (!f) goto out_elf_end; - if (filter && filter(map, f)) - symbol__delete(f); - else { - symbols__insert(&dso->symbols[map->type], f); - ++nr; - } + symbols__insert(&dso->symbols[map->type], f); + ++nr; } } @@ -825,9 +816,8 @@ static u64 ref_reloc(struct kmap *kmap) void __weak arch__sym_update(struct symbol *s __maybe_unused, GElf_Sym *sym __maybe_unused) { } -int dso__load_sym(struct dso *dso, struct map *map, - struct symsrc *syms_ss, struct symsrc *runtime_ss, - symbol_filter_t filter, int kmodule) +int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, + struct symsrc *runtime_ss, int kmodule) { struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; struct map_groups *kmaps = kmap ? map__kmaps(map) : NULL; @@ -1124,12 +1114,8 @@ new_symbol: arch__sym_update(f, &sym); - if (filter && filter(curr_map, f)) - symbol__delete(f); - else { - __symbols__insert(&curr_dso->symbols[curr_map->type], f, dso->kernel); - nr++; - } + __symbols__insert(&curr_dso->symbols[curr_map->type], f, dso->kernel); + nr++; } /* diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 4890633..11cdde9 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -287,8 +287,7 @@ void symsrc__destroy(struct symsrc *ss) int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused, struct symsrc *ss __maybe_unused, - struct map *map __maybe_unused, - symbol_filter_t filter __maybe_unused) + struct map *map __maybe_unused) { return 0; } @@ -334,7 +333,6 @@ enum dso_type dso__type_fd(int fd) int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, struct symsrc *ss, struct symsrc *runtime_ss __maybe_unused, - symbol_filter_t filter __maybe_unused, int kmodule __maybe_unused) { unsigned char build_id[BUILD_ID_SIZE]; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 4c5788f..19c9c55 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -24,10 +24,8 @@ #include #include -static int dso__load_kernel_sym(struct dso *dso, struct map *map, - symbol_filter_t filter); -static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, - symbol_filter_t filter); +static int dso__load_kernel_sym(struct dso *dso, struct map *map); +static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map); static bool symbol__is_idle(const char *name); int vmlinux_path__nr_entries; @@ -630,8 +628,7 @@ static int dso__load_all_kallsyms(struct dso *dso, const char *filename, return kallsyms__parse(filename, &args, map__process_kallsym_symbol); } -static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, - symbol_filter_t filter) +static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map) { struct map_groups *kmaps = map__kmaps(map); struct map *curr_map; @@ -660,7 +657,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, curr_map = map_groups__find(kmaps, map->type, pos->start); - if (!curr_map || (filter && filter(curr_map, pos))) { + if (!curr_map) { symbol__delete(pos); continue; } @@ -683,8 +680,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, * 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 *dso, struct map *map, u64 delta, - symbol_filter_t filter) +static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta) { struct map_groups *kmaps = map__kmaps(map); struct machine *machine; @@ -761,7 +757,7 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, if (count == 0) { curr_map = map; - goto filter_symbol; + goto add_symbol; } if (dso->kernel == DSO_TYPE_GUEST_KERNEL) @@ -793,18 +789,18 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, pos->start -= delta; pos->end -= delta; } -filter_symbol: - if (filter && filter(curr_map, pos)) { -discard_symbol: rb_erase(&pos->rb_node, root); - symbol__delete(pos); - } else { - if (curr_map != map) { - rb_erase(&pos->rb_node, root); - symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); - ++moved; - } else - ++count; - } +add_symbol: + if (curr_map != map) { + rb_erase(&pos->rb_node, root); + symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); + ++moved; + } else + ++count; + + continue; +discard_symbol: + rb_erase(&pos->rb_node, root); + symbol__delete(pos); } if (curr_map != map && @@ -1244,7 +1240,7 @@ static int kallsyms__delta(struct map *map, const char *filename, u64 *delta) } int __dso__load_kallsyms(struct dso *dso, const char *filename, - struct map *map, bool no_kcore, symbol_filter_t filter) + struct map *map, bool no_kcore) { u64 delta = 0; @@ -1266,19 +1262,18 @@ int __dso__load_kallsyms(struct dso *dso, const char *filename, dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; if (!no_kcore && !dso__load_kcore(dso, map, filename)) - return dso__split_kallsyms_for_kcore(dso, map, filter); + return dso__split_kallsyms_for_kcore(dso, map); else - return dso__split_kallsyms(dso, map, delta, filter); + return dso__split_kallsyms(dso, map, delta); } int dso__load_kallsyms(struct dso *dso, const char *filename, - struct map *map, symbol_filter_t filter) + struct map *map) { - return __dso__load_kallsyms(dso, filename, map, false, filter); + return __dso__load_kallsyms(dso, filename, map, false); } -static int dso__load_perf_map(struct dso *dso, struct map *map, - symbol_filter_t filter) +static int dso__load_perf_map(struct dso *dso, struct map *map) { char *line = NULL; size_t n; @@ -1320,12 +1315,8 @@ static int dso__load_perf_map(struct dso *dso, struct map *map, if (sym == NULL) goto out_delete_line; - if (filter && filter(map, sym)) - symbol__delete(sym); - else { - symbols__insert(&dso->symbols[map->type], sym); - nr_syms++; - } + symbols__insert(&dso->symbols[map->type], sym); + nr_syms++; } free(line); @@ -1381,7 +1372,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, } } -int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) +int dso__load(struct dso *dso, struct map *map) { char *name; int ret = -1; @@ -1404,9 +1395,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) if (dso->kernel) { if (dso->kernel == DSO_TYPE_KERNEL) - ret = dso__load_kernel_sym(dso, map, filter); + ret = dso__load_kernel_sym(dso, map); else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) - ret = dso__load_guest_kernel_sym(dso, map, filter); + ret = dso__load_guest_kernel_sym(dso, map); goto out; } @@ -1430,7 +1421,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) goto out; } - ret = dso__load_perf_map(dso, map, filter); + ret = dso__load_perf_map(dso, map); dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : DSO_BINARY_TYPE__NOT_FOUND; goto out; @@ -1521,14 +1512,14 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) kmod = true; if (syms_ss) - ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod); + ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod); else ret = -1; if (ret > 0) { int nr_plt; - nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter); + nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map); if (nr_plt > 0) ret += nr_plt; } @@ -1567,8 +1558,7 @@ out_unlock: } int dso__load_vmlinux(struct dso *dso, struct map *map, - const char *vmlinux, bool vmlinux_allocated, - symbol_filter_t filter) + const char *vmlinux, bool vmlinux_allocated) { int err = -1; struct symsrc ss; @@ -1588,7 +1578,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) return -1; - err = dso__load_sym(dso, map, &ss, &ss, filter, 0); + err = dso__load_sym(dso, map, &ss, &ss, 0); symsrc__destroy(&ss); if (err > 0) { @@ -1604,8 +1594,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, return err; } -int dso__load_vmlinux_path(struct dso *dso, struct map *map, - symbol_filter_t filter) +int dso__load_vmlinux_path(struct dso *dso, struct map *map) { int i, err = 0; char *filename = NULL; @@ -1614,7 +1603,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, vmlinux_path__nr_entries + 1); for (i = 0; i < vmlinux_path__nr_entries; ++i) { - err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter); + err = dso__load_vmlinux(dso, map, vmlinux_path[i], false); if (err > 0) goto out; } @@ -1622,7 +1611,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, if (!symbol_conf.ignore_vmlinux_buildid) filename = dso__build_id_filename(dso, NULL, 0); if (filename != NULL) { - err = dso__load_vmlinux(dso, map, filename, true, filter); + err = dso__load_vmlinux(dso, map, filename, true); if (err > 0) goto out; free(filename); @@ -1736,8 +1725,7 @@ proc_kallsyms: return strdup(path); } -static int dso__load_kernel_sym(struct dso *dso, struct map *map, - symbol_filter_t filter) +static int dso__load_kernel_sym(struct dso *dso, struct map *map) { int err; const char *kallsyms_filename = NULL; @@ -1763,12 +1751,11 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, } if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { - return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, - false, filter); + return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false); } if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { - err = dso__load_vmlinux_path(dso, map, filter); + err = dso__load_vmlinux_path(dso, map); if (err > 0) return err; } @@ -1784,7 +1771,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, kallsyms_filename = kallsyms_allocated_filename; do_kallsyms: - err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); + err = dso__load_kallsyms(dso, kallsyms_filename, map); if (err > 0) pr_debug("Using %s for symbols\n", kallsyms_filename); free(kallsyms_allocated_filename); @@ -1799,8 +1786,7 @@ do_kallsyms: return err; } -static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, - symbol_filter_t filter) +static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map) { int err; const char *kallsyms_filename = NULL; @@ -1822,7 +1808,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, if (symbol_conf.default_guest_vmlinux_name != NULL) { err = dso__load_vmlinux(dso, map, symbol_conf.default_guest_vmlinux_name, - false, filter); + false); return err; } @@ -1834,7 +1820,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, kallsyms_filename = path; } - err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); + err = dso__load_kallsyms(dso, kallsyms_filename, map); if (err > 0) pr_debug("Using %s for symbols\n", kallsyms_filename); if (err > 0 && !dso__is_kcore(dso)) { diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 72d2931..0dacfb7 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -241,16 +241,13 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, bool symsrc__has_symtab(struct symsrc *ss); bool symsrc__possibly_runtime(struct symsrc *ss); -int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); +int dso__load(struct dso *dso, struct map *map); int dso__load_vmlinux(struct dso *dso, struct map *map, - const char *vmlinux, bool vmlinux_allocated, - symbol_filter_t filter); -int dso__load_vmlinux_path(struct dso *dso, struct map *map, - symbol_filter_t filter); + const char *vmlinux, bool vmlinux_allocated); +int dso__load_vmlinux_path(struct dso *dso, struct map *map); int __dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, - bool no_kcore, symbol_filter_t filter); -int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, - symbol_filter_t filter); + bool no_kcore); +int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map); void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym); @@ -298,10 +295,9 @@ int symbol__config_symfs(const struct option *opt __maybe_unused, const char *dir, int unset __maybe_unused); int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, - struct symsrc *runtime_ss, symbol_filter_t filter, - int kmodule); + struct symsrc *runtime_ss, int kmodule); int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, - struct map *map, symbol_filter_t filter); + struct map *map); void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel); void symbols__insert(struct rb_root *symbols, struct symbol *sym); -- cgit v0.10.2 From 0ac3348e502423cf2fe86beca83b8835a2e6d289 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Tue, 6 Sep 2016 04:58:27 +0000 Subject: perf tools: Recognize hugetlb mapping as anon mapping Hugetlbfs mapping should be recognized as anon mapping so user has a chance to create /tmp/perf-.map file for symbol resolving. This patch utilizes MAP_HUGETLB to identify hugetlb mapping. After this patch, if perf is started before a program starts using huge pages (so perf gets MMAP2 events from kernel), perf is able to recognize hugetlb mapping as anon mapping. Signed-off-by: Wang Nan Cc: He Kuang Cc: Nilay Vaish Cc: Zefan Li Link: http://lkml.kernel.org/r/1473137909-142064-2-git-send-email-wangnan0@huawei.com Signed-off-by: Hou Pengyang Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 0c54adb..d51a125 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "map.h" #include "thread.h" #include "strlist.h" @@ -24,9 +25,15 @@ const char *map_type__name[MAP__NR_TYPES] = { [MAP__VARIABLE] = "Variables", }; -static inline int is_anon_memory(const char *filename) +static inline int is_anon_memory(const char *filename, u32 flags) { - return !strcmp(filename, "//anon") || + u32 anon_flags = 0; + +#ifdef MAP_HUGETLB + anon_flags |= MAP_HUGETLB; +#endif + return flags & anon_flags || + !strcmp(filename, "//anon") || !strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) || !strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1); } @@ -155,7 +162,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, int anon, no_dso, vdso, android; android = is_android_lib(filename); - anon = is_anon_memory(filename); + anon = is_anon_memory(filename, flags); vdso = is_vdso_map(filename); no_dso = is_no_dso_memory(filename); -- cgit v0.10.2 From 5e7be3e1f9d71ed03fac27df25e143815be662d2 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Tue, 6 Sep 2016 04:58:28 +0000 Subject: tools lib api fs: Add hugetlbfs filesystem detector Detect hugetlbfs. hugetlbfs__mountpoint() will be used during recording to help identifying hugetlb mmaps: which should be recognized as anon mapping. Signed-off-by: Wang Nan Reviewed-by: Nilay Vaish Cc: He Kuang Cc: Hou Pengyang Cc: Zefan Li Link: http://lkml.kernel.org/r/1473137909-142064-3-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index ba7094b..f99f49e4 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -34,6 +34,10 @@ #define TRACEFS_MAGIC 0x74726163 #endif +#ifndef HUGETLBFS_MAGIC +#define HUGETLBFS_MAGIC 0x958458f6 +#endif + static const char * const sysfs__fs_known_mountpoints[] = { "/sys", 0, @@ -67,6 +71,10 @@ static const char * const tracefs__known_mountpoints[] = { 0, }; +static const char * const hugetlbfs__known_mountpoints[] = { + 0, +}; + struct fs { const char *name; const char * const *mounts; @@ -80,6 +88,7 @@ enum { FS__PROCFS = 1, FS__DEBUGFS = 2, FS__TRACEFS = 3, + FS__HUGETLBFS = 4, }; #ifndef TRACEFS_MAGIC @@ -107,6 +116,11 @@ static struct fs fs__entries[] = { .mounts = tracefs__known_mountpoints, .magic = TRACEFS_MAGIC, }, + [FS__HUGETLBFS] = { + .name = "hugetlbfs", + .mounts = hugetlbfs__known_mountpoints, + .magic = HUGETLBFS_MAGIC, + }, }; static bool fs__read_mounts(struct fs *fs) @@ -265,6 +279,7 @@ FS(sysfs, FS__SYSFS); FS(procfs, FS__PROCFS); FS(debugfs, FS__DEBUGFS); FS(tracefs, FS__TRACEFS); +FS(hugetlbfs, FS__HUGETLBFS); int filename__read_int(const char *filename, int *value) { diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index 16c9c2e..a63269f 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -21,6 +21,7 @@ FS(sysfs) FS(procfs) FS(debugfs) FS(tracefs) +FS(hugetlbfs) #undef FS -- cgit v0.10.2 From d7e404af115bb4996afa4a0236020969ab007554 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Tue, 6 Sep 2016 04:58:29 +0000 Subject: perf record: Mark MAP_HUGETLB when synthesizing mmap events When synthesizing mmap events, add MAP_HUGETLB map flag if the source of mapping is file in hugetlbfs. After this patch, perf can identify hugetlb mapping even if perf is started after the mapping of huge pages (like with 'perf top'). Signed-off-by: Wang Nan Reviewed-by: Nilay Vaish Cc: He Kuang Cc: Hou Pengyang Cc: Zefan Li Link: http://lkml.kernel.org/r/1473137909-142064-4-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 9ad7d32..6c30171 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -1,5 +1,6 @@ #include #include +#include #include "event.h" #include "debug.h" #include "hist.h" @@ -248,6 +249,10 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool, bool truncation = false; unsigned long long timeout = proc_map_timeout * 1000000ULL; int rc = 0; +#ifdef MAP_HUGETLB + const char *hugetlbfs_mnt = hugetlbfs__mountpoint(); + int hugetlbfs_mnt_len = hugetlbfs_mnt ? strlen(hugetlbfs_mnt) : 0; +#endif if (machine__is_default_guest(machine)) return 0; @@ -342,6 +347,12 @@ out: if (!strcmp(execname, "")) strcpy(execname, anonstr); +#ifdef MAP_HUGETLB + if (!strncmp(execname, hugetlbfs_mnt, hugetlbfs_mnt_len)) { + strcpy(execname, anonstr); + event->mmap2.flags |= MAP_HUGETLB; + } +#endif size = strlen(execname) + 1; memcpy(event->mmap2.filename, execname, size); -- cgit v0.10.2 From 70fbe0574558e934f93bde26e4949c8c206bae43 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 5 Sep 2016 16:08:12 -0300 Subject: perf annotate: Add branch stack / basic block I wanted to know the hottest path through a function and figured the branch-stack (LBR) information should be able to help out with that. The below uses the branch-stack to create basic blocks and generate statistics from them. from to branch_i * ----> * | | block v * ----> * from to branch_i+1 The blocks are broken down into non-overlapping ranges, while tracking if the start of each range is an entry point and/or the end of a range is a branch. Each block iterates all ranges it covers (while splitting where required to exactly match the block) and increments the 'coverage' count. For the range including the branch we increment the taken counter, as well as the pred counter if flags.predicted. Using these number we can find if an instruction: - had coverage; given by: br->coverage / br->sym->max_coverage This metric ensures each symbol has a 100% spot, which reflects the observation that each symbol must have a most covered/hottest block. - is a branch target: br->is_target && br->start == add - for targets, how much of a branch's coverages comes from it: target->entry / branch->coverage - is a branch: br->is_branch && br->end == addr - for branches, how often it was taken: br->taken / br->coverage after all, all execution that didn't take the branch would have incremented the coverage and continued onward to a later branch. - for branches, how often it was predicted: br->pred / br->taken The coverage percentage is used to color the address and asm sections; for low (<1%) coverage we use NORMAL (uncolored), indicating that these instructions are not 'important'. For high coverage (>75%) we color the address RED. For each branch, we add an asm comment after the instruction with information on how often it was taken and predicted. Output looks like (sans color, which does loose a lot of the information :/) $ perf record --branch-filter u,any -e cycles:p ./branches 27 $ perf annotate branches Percent | Source code & Disassembly of branches for cycles:pu (217 samples) --------------------------------------------------------------------------------- : branches(): 0.00 : 40057a: push %rbp 0.00 : 40057b: mov %rsp,%rbp 0.00 : 40057e: sub $0x20,%rsp 0.00 : 400582: mov %rdi,-0x18(%rbp) 0.00 : 400586: mov %rsi,-0x20(%rbp) 0.00 : 40058a: mov -0x18(%rbp),%rax 0.00 : 40058e: mov %rax,-0x10(%rbp) 0.00 : 400592: movq $0x0,-0x8(%rbp) 0.00 : 40059a: jmpq 400656 1.84 : 40059f: mov -0x10(%rbp),%rax # +100.00% 3.23 : 4005a3: and $0x1,%eax 1.84 : 4005a6: test %rax,%rax 0.00 : 4005a9: je 4005bf # -54.50% (p:42.00%) 0.46 : 4005ab: mov 0x200bbe(%rip),%rax # 601170 12.90 : 4005b2: add $0x1,%rax 2.30 : 4005b6: mov %rax,0x200bb3(%rip) # 601170 0.46 : 4005bd: jmp 4005d1 # -100.00% (p:100.00%) 0.92 : 4005bf: mov 0x200baa(%rip),%rax # 601170 # +49.54% 13.82 : 4005c6: sub $0x1,%rax 0.46 : 4005ca: mov %rax,0x200b9f(%rip) # 601170 2.30 : 4005d1: mov -0x10(%rbp),%rax # +50.46% 0.46 : 4005d5: mov %rax,%rdi 0.46 : 4005d8: callq 400526 # -100.00% (p:100.00%) 0.00 : 4005dd: mov %rax,-0x10(%rbp) # +100.00% 0.92 : 4005e1: mov -0x18(%rbp),%rax 0.00 : 4005e5: and $0x1,%eax 0.00 : 4005e8: test %rax,%rax 0.00 : 4005eb: je 4005ff # -100.00% (p:100.00%) 0.00 : 4005ed: mov 0x200b7c(%rip),%rax # 601170 0.00 : 4005f4: shr $0x2,%rax 0.00 : 4005f8: mov %rax,0x200b71(%rip) # 601170 0.00 : 4005ff: mov -0x10(%rbp),%rax # +100.00% 7.37 : 400603: and $0x1,%eax 3.69 : 400606: test %rax,%rax 0.00 : 400609: jne 400612 # -59.25% (p:42.99%) 1.84 : 40060b: mov $0x1,%eax 14.29 : 400610: jmp 400617 # -100.00% (p:100.00%) 1.38 : 400612: mov $0x0,%eax # +57.65% 10.14 : 400617: test %al,%al # +42.35% 0.00 : 400619: je 40062f # -57.65% (p:100.00%) 0.46 : 40061b: mov 0x200b4e(%rip),%rax # 601170 2.76 : 400622: sub $0x1,%rax 0.00 : 400626: mov %rax,0x200b43(%rip) # 601170 0.46 : 40062d: jmp 400641 # -100.00% (p:100.00%) 0.92 : 40062f: mov 0x200b3a(%rip),%rax # 601170 # +56.13% 2.30 : 400636: add $0x1,%rax 0.92 : 40063a: mov %rax,0x200b2f(%rip) # 601170 0.92 : 400641: mov -0x10(%rbp),%rax # +43.87% 2.30 : 400645: mov %rax,%rdi 0.00 : 400648: callq 400526 # -100.00% (p:100.00%) 0.00 : 40064d: mov %rax,-0x10(%rbp) # +100.00% 1.84 : 400651: addq $0x1,-0x8(%rbp) 0.92 : 400656: mov -0x8(%rbp),%rax 5.07 : 40065a: cmp -0x20(%rbp),%rax 0.00 : 40065e: jb 40059f # -100.00% (p:100.00%) 0.00 : 400664: nop 0.00 : 400665: leaveq 0.00 : 400666: retq (Note: the --branch-filter u,any was used to avoid spurious target and branch points due to interrupts/faults, they show up as very small -/+ annotations on 'weird' locations) Committer note: Please take a look at: http://vger.kernel.org/~acme/perf/annotate_basic_blocks.png To see the colors. Signed-off-by: Peter Zijlstra (Intel) Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: Anshuman Khandual Cc: David Carrillo-Cisneros Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Namhyung Kim Cc: Stephane Eranian [ Moved sym->max_coverage to 'struct annotate', aka symbol__annotate(sym) ] Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index f07b230..ebb6283 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -30,6 +30,7 @@ #include "util/tool.h" #include "util/data.h" #include "arch/common.h" +#include "util/block-range.h" #include #include @@ -46,6 +47,103 @@ struct perf_annotate { DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); }; +/* + * Given one basic block: + * + * from to branch_i + * * ----> * + * | + * | block + * v + * * ----> * + * from to branch_i+1 + * + * where the horizontal are the branches and the vertical is the executed + * block of instructions. + * + * We count, for each 'instruction', the number of blocks that covered it as + * well as count the ratio each branch is taken. + * + * We can do this without knowing the actual instruction stream by keeping + * track of the address ranges. We break down ranges such that there is no + * overlap and iterate from the start until the end. + * + * @acme: once we parse the objdump output _before_ processing the samples, + * we can easily fold the branch.cycles IPC bits in. + */ +static void process_basic_block(struct addr_map_symbol *start, + struct addr_map_symbol *end, + struct branch_flags *flags) +{ + struct symbol *sym = start->sym; + struct annotation *notes = sym ? symbol__annotation(sym) : NULL; + struct block_range_iter iter; + struct block_range *entry; + + /* + * Sanity; NULL isn't executable and the CPU cannot execute backwards + */ + if (!start->addr || start->addr > end->addr) + return; + + iter = block_range__create(start->addr, end->addr); + if (!block_range_iter__valid(&iter)) + return; + + /* + * First block in range is a branch target. + */ + entry = block_range_iter(&iter); + assert(entry->is_target); + entry->entry++; + + do { + entry = block_range_iter(&iter); + + entry->coverage++; + entry->sym = sym; + + if (notes) + notes->max_coverage = max(notes->max_coverage, entry->coverage); + + } while (block_range_iter__next(&iter)); + + /* + * Last block in rage is a branch. + */ + entry = block_range_iter(&iter); + assert(entry->is_branch); + entry->taken++; + if (flags->predicted) + entry->pred++; +} + +static void process_branch_stack(struct branch_stack *bs, struct addr_location *al, + struct perf_sample *sample) +{ + struct addr_map_symbol *prev = NULL; + struct branch_info *bi; + int i; + + if (!bs || !bs->nr) + return; + + bi = sample__resolve_bstack(sample, al); + if (!bi) + return; + + for (i = bs->nr - 1; i >= 0; i--) { + /* + * XXX filter against symbol + */ + if (prev) + process_basic_block(prev, &bi[i].from, &bi[i].flags); + prev = &bi[i].to; + } + + free(bi); +} + static int perf_evsel__add_sample(struct perf_evsel *evsel, struct perf_sample *sample, struct addr_location *al, @@ -72,6 +170,12 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, return 0; } + /* + * XXX filtered samples can still have branch entires pointing into our + * symbol and are missed. + */ + process_branch_stack(sample->branch_stack, al, sample); + sample->period = 1; sample->weight = 1; diff --git a/tools/perf/util/Build b/tools/perf/util/Build index f1a6d17..96f99d6 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -1,5 +1,6 @@ libperf-y += alias.o libperf-y += annotate.o +libperf-y += block-range.o libperf-y += build-id.o libperf-y += config.o libperf-y += ctype.o diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 2ff6bd7..7a80c73 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -17,6 +17,7 @@ #include "debug.h" #include "annotate.h" #include "evsel.h" +#include "block-range.h" #include #include #include @@ -859,6 +860,89 @@ double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, return percent; } +static const char *annotate__address_color(struct block_range *br) +{ + double cov = block_range__coverage(br); + + if (cov >= 0) { + /* mark red for >75% coverage */ + if (cov > 0.75) + return PERF_COLOR_RED; + + /* mark dull for <1% coverage */ + if (cov < 0.01) + return PERF_COLOR_NORMAL; + } + + return PERF_COLOR_MAGENTA; +} + +static const char *annotate__asm_color(struct block_range *br) +{ + double cov = block_range__coverage(br); + + if (cov >= 0) { + /* mark dull for <1% coverage */ + if (cov < 0.01) + return PERF_COLOR_NORMAL; + } + + return PERF_COLOR_BLUE; +} + +static void annotate__branch_printf(struct block_range *br, u64 addr) +{ + bool emit_comment = true; + + if (!br) + return; + +#if 1 + if (br->is_target && br->start == addr) { + struct block_range *branch = br; + double p; + + /* + * Find matching branch to our target. + */ + while (!branch->is_branch) + branch = block_range__next(branch); + + p = 100 *(double)br->entry / branch->coverage; + + if (p > 0.1) { + if (emit_comment) { + emit_comment = false; + printf("\t#"); + } + + /* + * The percentage of coverage joined at this target in relation + * to the next branch. + */ + printf(" +%.2f%%", p); + } + } +#endif + if (br->is_branch && br->end == addr) { + double p = 100*(double)br->taken / br->coverage; + + if (p > 0.1) { + if (emit_comment) { + emit_comment = false; + printf("\t#"); + } + + /* + * The percentage of coverage leaving at this branch, and + * its prediction ratio. + */ + printf(" -%.2f%% (p:%.2f%%)", p, 100*(double)br->pred / br->taken); + } + } +} + + static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, int max_lines, struct disasm_line *queue) @@ -878,6 +962,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st s64 offset = dl->offset; const u64 addr = start + offset; struct disasm_line *next; + struct block_range *br; next = disasm__get_next_ip_line(¬es->src->source, dl); @@ -947,8 +1032,12 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st } printf(" : "); - color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); - color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); + + br = block_range__find(addr); + color_fprintf(stdout, annotate__address_color(br), " %" PRIx64 ":", addr); + color_fprintf(stdout, annotate__asm_color(br), "%s", dl->line); + annotate__branch_printf(br, addr); + printf("\n"); if (ppercents != &percent) free(ppercents); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index e96f4da..ea44e4f 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -130,6 +130,7 @@ struct annotated_source { struct annotation { pthread_mutex_t lock; + u64 max_coverage; struct annotated_source *src; }; diff --git a/tools/perf/util/block-range.c b/tools/perf/util/block-range.c new file mode 100644 index 0000000..7b3e1d7 --- /dev/null +++ b/tools/perf/util/block-range.c @@ -0,0 +1,328 @@ +#include "block-range.h" +#include "annotate.h" + +struct { + struct rb_root root; + u64 blocks; +} block_ranges; + +static void block_range__debug(void) +{ + /* + * XXX still paranoid for now; see if we can make this depend on + * DEBUG=1 builds. + */ +#if 1 + struct rb_node *rb; + u64 old = 0; /* NULL isn't executable */ + + for (rb = rb_first(&block_ranges.root); rb; rb = rb_next(rb)) { + struct block_range *entry = rb_entry(rb, struct block_range, node); + + assert(old < entry->start); + assert(entry->start <= entry->end); /* single instruction block; jump to a jump */ + + old = entry->end; + } +#endif +} + +struct block_range *block_range__find(u64 addr) +{ + struct rb_node **p = &block_ranges.root.rb_node; + struct rb_node *parent = NULL; + struct block_range *entry; + + while (*p != NULL) { + parent = *p; + entry = rb_entry(parent, struct block_range, node); + + if (addr < entry->start) + p = &parent->rb_left; + else if (addr > entry->end) + p = &parent->rb_right; + else + return entry; + } + + return NULL; +} + +static inline void rb_link_left_of_node(struct rb_node *left, struct rb_node *node) +{ + struct rb_node **p = &node->rb_left; + while (*p) { + node = *p; + p = &node->rb_right; + } + rb_link_node(left, node, p); +} + +static inline void rb_link_right_of_node(struct rb_node *right, struct rb_node *node) +{ + struct rb_node **p = &node->rb_right; + while (*p) { + node = *p; + p = &node->rb_left; + } + rb_link_node(right, node, p); +} + +/** + * block_range__create + * @start: branch target starting this basic block + * @end: branch ending this basic block + * + * Create all the required block ranges to precisely span the given range. + */ +struct block_range_iter block_range__create(u64 start, u64 end) +{ + struct rb_node **p = &block_ranges.root.rb_node; + struct rb_node *n, *parent = NULL; + struct block_range *next, *entry = NULL; + struct block_range_iter iter = { NULL, NULL }; + + while (*p != NULL) { + parent = *p; + entry = rb_entry(parent, struct block_range, node); + + if (start < entry->start) + p = &parent->rb_left; + else if (start > entry->end) + p = &parent->rb_right; + else + break; + } + + /* + * Didn't find anything.. there's a hole at @start, however @end might + * be inside/behind the next range. + */ + if (!*p) { + if (!entry) /* tree empty */ + goto do_whole; + + /* + * If the last node is before, advance one to find the next. + */ + n = parent; + if (entry->end < start) { + n = rb_next(n); + if (!n) + goto do_whole; + } + next = rb_entry(n, struct block_range, node); + + if (next->start <= end) { /* add head: [start...][n->start...] */ + struct block_range *head = malloc(sizeof(struct block_range)); + if (!head) + return iter; + + *head = (struct block_range){ + .start = start, + .end = next->start - 1, + .is_target = 1, + .is_branch = 0, + }; + + rb_link_left_of_node(&head->node, &next->node); + rb_insert_color(&head->node, &block_ranges.root); + block_range__debug(); + + iter.start = head; + goto do_tail; + } + +do_whole: + /* + * The whole [start..end] range is non-overlapping. + */ + entry = malloc(sizeof(struct block_range)); + if (!entry) + return iter; + + *entry = (struct block_range){ + .start = start, + .end = end, + .is_target = 1, + .is_branch = 1, + }; + + rb_link_node(&entry->node, parent, p); + rb_insert_color(&entry->node, &block_ranges.root); + block_range__debug(); + + iter.start = entry; + iter.end = entry; + goto done; + } + + /* + * We found a range that overlapped with ours, split if needed. + */ + if (entry->start < start) { /* split: [e->start...][start...] */ + struct block_range *head = malloc(sizeof(struct block_range)); + if (!head) + return iter; + + *head = (struct block_range){ + .start = entry->start, + .end = start - 1, + .is_target = entry->is_target, + .is_branch = 0, + + .coverage = entry->coverage, + .entry = entry->entry, + }; + + entry->start = start; + entry->is_target = 1; + entry->entry = 0; + + rb_link_left_of_node(&head->node, &entry->node); + rb_insert_color(&head->node, &block_ranges.root); + block_range__debug(); + + } else if (entry->start == start) + entry->is_target = 1; + + iter.start = entry; + +do_tail: + /* + * At this point we've got: @iter.start = [@start...] but @end can still be + * inside or beyond it. + */ + entry = iter.start; + for (;;) { + /* + * If @end is inside @entry, split. + */ + if (end < entry->end) { /* split: [...end][...e->end] */ + struct block_range *tail = malloc(sizeof(struct block_range)); + if (!tail) + return iter; + + *tail = (struct block_range){ + .start = end + 1, + .end = entry->end, + .is_target = 0, + .is_branch = entry->is_branch, + + .coverage = entry->coverage, + .taken = entry->taken, + .pred = entry->pred, + }; + + entry->end = end; + entry->is_branch = 1; + entry->taken = 0; + entry->pred = 0; + + rb_link_right_of_node(&tail->node, &entry->node); + rb_insert_color(&tail->node, &block_ranges.root); + block_range__debug(); + + iter.end = entry; + goto done; + } + + /* + * If @end matches @entry, done + */ + if (end == entry->end) { + entry->is_branch = 1; + iter.end = entry; + goto done; + } + + next = block_range__next(entry); + if (!next) + goto add_tail; + + /* + * If @end is in beyond @entry but not inside @next, add tail. + */ + if (end < next->start) { /* add tail: [...e->end][...end] */ + struct block_range *tail; +add_tail: + tail = malloc(sizeof(struct block_range)); + if (!tail) + return iter; + + *tail = (struct block_range){ + .start = entry->end + 1, + .end = end, + .is_target = 0, + .is_branch = 1, + }; + + rb_link_right_of_node(&tail->node, &entry->node); + rb_insert_color(&tail->node, &block_ranges.root); + block_range__debug(); + + iter.end = tail; + goto done; + } + + /* + * If there is a hole between @entry and @next, fill it. + */ + if (entry->end + 1 != next->start) { + struct block_range *hole = malloc(sizeof(struct block_range)); + if (!hole) + return iter; + + *hole = (struct block_range){ + .start = entry->end + 1, + .end = next->start - 1, + .is_target = 0, + .is_branch = 0, + }; + + rb_link_left_of_node(&hole->node, &next->node); + rb_insert_color(&hole->node, &block_ranges.root); + block_range__debug(); + } + + entry = next; + } + +done: + assert(iter.start->start == start && iter.start->is_target); + assert(iter.end->end == end && iter.end->is_branch); + + block_ranges.blocks++; + + return iter; +} + + +/* + * Compute coverage as: + * + * br->coverage / br->sym->max_coverage + * + * This ensures each symbol has a 100% spot, to reflect that each symbol has a + * most covered section. + * + * Returns [0-1] for coverage and -1 if we had no data what so ever or the + * symbol does not exist. + */ +double block_range__coverage(struct block_range *br) +{ + struct symbol *sym; + + if (!br) { + if (block_ranges.blocks) + return 0; + + return -1; + } + + sym = br->sym; + if (!sym) + return -1; + + return (double)br->coverage / symbol__annotation(sym)->max_coverage; +} diff --git a/tools/perf/util/block-range.h b/tools/perf/util/block-range.h new file mode 100644 index 0000000..a8c8413 --- /dev/null +++ b/tools/perf/util/block-range.h @@ -0,0 +1,71 @@ +#ifndef __PERF_BLOCK_RANGE_H +#define __PERF_BLOCK_RANGE_H + +#include "symbol.h" + +/* + * struct block_range - non-overlapping parts of basic blocks + * @node: treenode + * @start: inclusive start of range + * @end: inclusive end of range + * @is_target: @start is a jump target + * @is_branch: @end is a branch instruction + * @coverage: number of blocks that cover this range + * @taken: number of times the branch is taken (requires @is_branch) + * @pred: number of times the taken branch was predicted + */ +struct block_range { + struct rb_node node; + + struct symbol *sym; + + u64 start; + u64 end; + + int is_target, is_branch; + + u64 coverage; + u64 entry; + u64 taken; + u64 pred; +}; + +static inline struct block_range *block_range__next(struct block_range *br) +{ + struct rb_node *n = rb_next(&br->node); + if (!n) + return NULL; + return rb_entry(n, struct block_range, node); +} + +struct block_range_iter { + struct block_range *start; + struct block_range *end; +}; + +static inline struct block_range *block_range_iter(struct block_range_iter *iter) +{ + return iter->start; +} + +static inline bool block_range_iter__next(struct block_range_iter *iter) +{ + if (iter->start == iter->end) + return false; + + iter->start = block_range__next(iter->start); + return true; +} + +static inline bool block_range_iter__valid(struct block_range_iter *iter) +{ + if (!iter->start || !iter->end) + return false; + return true; +} + +extern struct block_range *block_range__find(u64 addr); +extern struct block_range_iter block_range__create(u64 start, u64 end); +extern double block_range__coverage(struct block_range *br); + +#endif /* __PERF_BLOCK_RANGE_H */ -- cgit v0.10.2 From 9f21b815be863218192f42f9f5bf78b75f8738e0 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 8 Sep 2016 11:21:51 +0100 Subject: perf evlist: Only open events on CPUs an evsel permits In systems with heterogeneous CPU PMUs, it's possible for each evsel to cover a distinct set of CPUs, and hence the cpu_map associated with each evsel may have a distinct idx<->id mapping. Any of these may be distinct from the evlist's cpu map. Events can be tied to the same fd so long as they use the same per-cpu ringbuffer (i.e. so long as they are on the same CPU). To acquire the correct FDs, we must compare the Linux logical IDs rather than the evsel or evlist indices. This path adds logic to perf_evlist__mmap_per_evsel to handle this, translating IDs as required. As PMUs may cover a subset of CPUs from the evlist, we skip the CPUs a PMU cannot handle. Without this patch, perf record may try to mmap erroneous FDs on heterogeneous systems, and will bail out early rather than running the workload. Signed-off-by: Mark Rutland Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Mark Rutland Cc: Peter Zijlstra Cc: Will Deacon Link: http://lkml.kernel.org/r/1473330112-28528-7-git-send-email-mark.rutland@arm.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 097b3ed..ea34c5a 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1032,16 +1032,18 @@ perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused, } static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, - struct mmap_params *mp, int cpu, + struct mmap_params *mp, int cpu_idx, int thread, int *_output, int *_output_backward) { struct perf_evsel *evsel; int revent; + int evlist_cpu = cpu_map__cpu(evlist->cpus, cpu_idx); evlist__for_each_entry(evlist, evsel) { struct perf_mmap *maps = evlist->mmap; int *output = _output; int fd; + int cpu; if (evsel->attr.write_backward) { output = _output_backward; @@ -1060,6 +1062,10 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, if (evsel->system_wide && thread) continue; + cpu = cpu_map__idx(evsel->cpus, evlist_cpu); + if (cpu == -1) + continue; + fd = FD(evsel, cpu, thread); if (*output == -1) { -- cgit v0.10.2 From 7e3fcffe955440101493cd8f32f75840ddf87b6f Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 8 Sep 2016 11:21:52 +0100 Subject: perf pmu: Support alternative sysfs cpumask The perf tools can read a cpumask file for a PMU, describing a subset of CPUs which that PMU covers. So far this has only been used to cater for uncore PMUs, which in practice happen to only have a single CPU described in the mask. Until recently, the perf tools only correctly handled cpumask containing a single CPU, and only when monitoring in system-wide mode. For example, prior to commit 00e727bb389359c8 ("perf stat: Balance opening and reading events"), a mask with more than a single CPU could cause perf stat to hang. When a CPU PMU covers a subset of CPUs, but lacks a cpumask, perf record will fail to open events (on the cores the PMU does not support), and gives up. For systems with heterogeneous CPUs such as ARM big.LITTLE systems, this presents a problem. We have a PMU for each microarchitecture (e.g. a big PMU and a little PMU), and would like to expose a cpumask for each (so as to allow perf record and other tools to do the right thing). However, doing so kernel-side will cause old perf binaries to not function (e.g. hitting the issue solved by 00e727bb389359c8), and thus commits the cardinal sin of breaking (existing) userspace. To address this chicken-and-egg problem, this patch adds support got a new file, cpus, which is largely identical to the existing cpumask file. A kernel can expose this file, knowing that new perf binaries will correctly support it, while old perf binaries will not look for it (and thus will not be broken). Signed-off-by: Mark Rutland Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Mark Rutland Cc: Peter Zijlstra Cc: Will Deacon Link: http://lkml.kernel.org/r/1473330112-28528-8-git-send-email-mark.rutland@arm.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index ddb0261..2babcdf 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -445,14 +445,23 @@ static struct cpu_map *pmu_cpumask(const char *name) FILE *file; struct cpu_map *cpus; const char *sysfs = sysfs__mountpoint(); + const char *templates[] = { + "%s/bus/event_source/devices/%s/cpumask", + "%s/bus/event_source/devices/%s/cpus", + NULL + }; + const char **template; if (!sysfs) return NULL; - snprintf(path, PATH_MAX, - "%s/bus/event_source/devices/%s/cpumask", sysfs, name); + for (template = templates; *template; template++) { + snprintf(path, PATH_MAX, *template, sysfs, name); + if (stat(path, &st) == 0) + break; + } - if (stat(path, &st) < 0) + if (!*template) return NULL; file = fopen(path, "r"); -- cgit v0.10.2 From 25b8592e912f085ce2ff736a2927584ddeab238c Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Wed, 31 Aug 2016 13:33:11 +0530 Subject: perf powerpc: Fix build-test failure 'make -C tools/perf build-test' is failing with below log for poewrpc. In file included from /tmp/tmp.3eEwmGlYaF/perf-4.8.0-rc4/tools/perf/perf.h:15:0, from util/cpumap.h:8, from util/env.c:1: /tmp/tmp.3eEwmGlYaF/perf-4.8.0-rc4/tools/perf/perf-sys.h:23:56: fatal error: ../../arch/powerpc/include/uapi/asm/unistd.h: No such file or directory compilation terminated. I bisected it and found it's failing from commit ad430729ae00 ("Remove: kernel unistd*h files from perf's MANIFEST, not used"). Header file '../../arch/powerpc/include/uapi/asm/unistd.h' is included only for powerpc in tools/perf/perf-sys.h. By looking closly at commit history, I found little weird thing: Commit f2d9cae9ea9e ("perf powerpc: Use uapi/unistd.h to fix build error") replaced 'asm/unistd.h' with 'uapi/asm/unistd.h' Commit d2709c7ce4c5 ("perf: Make perf build for x86 with UAPI disintegration applied") removes all arch specific 'uapi/asm/unistd.h' for all archs and adds generic . Commit f0b9abfb0446 ("Merge branch 'linus' into perf/core") again includes 'uapi/asm/unistd.h' for powerpc. Don't know how exactly this happened as this change is not part of commit also. Signed-off-by: Ravi Bangoria Cc: Alexander Shishkin Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1472630591-5089-1-git-send-email-ravi.bangoria@linux.vnet.ibm.com Fixes: ad430729ae00 ("Remove: kernel unistd*h files from perf's MANIFEST, not used") Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/perf-sys.h b/tools/perf/perf-sys.h index 7ed72a4..e4b717e 100644 --- a/tools/perf/perf-sys.h +++ b/tools/perf/perf-sys.h @@ -20,7 +20,6 @@ #endif #ifdef __powerpc__ -#include "../../arch/powerpc/include/uapi/asm/unistd.h" #define CPUINFO_PROC {"cpu"} #endif -- cgit v0.10.2