diff options
Diffstat (limited to 'tools/perf/builtin-c2c.c')
| -rw-r--r-- | tools/perf/builtin-c2c.c | 359 |
1 files changed, 270 insertions, 89 deletions
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 15e1fce71c72..c9584dbedf77 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -12,38 +12,44 @@ */ #include <errno.h> #include <inttypes.h> + +#include <asm/bug.h> #include <linux/compiler.h> #include <linux/err.h> #include <linux/kernel.h> #include <linux/stringify.h> #include <linux/zalloc.h> -#include <asm/bug.h> #include <sys/param.h> -#include "debug.h" -#include "builtin.h" + +#include <dwarf-regs.h> #include <perf/cpumap.h> #include <subcmd/pager.h> #include <subcmd/parse-options.h> -#include "map_symbol.h" -#include "mem-events.h" -#include "session.h" -#include "hist.h" -#include "sort.h" -#include "tool.h" + +#include "builtin.h" #include "cacheline.h" #include "data.h" +#include "debug.h" #include "event.h" #include "evlist.h" #include "evsel.h" -#include "ui/browsers/hists.h" -#include "thread.h" -#include "mem2node.h" +#include "hist.h" +#include "map_symbol.h" +#include "mem-events.h" #include "mem-info.h" -#include "symbol.h" -#include "ui/ui.h" -#include "ui/progress.h" +#include "mem2node.h" #include "pmus.h" +#include "session.h" +#include "sort.h" #include "string2.h" +#include "symbol.h" +#include "thread.h" +#include "tool.h" +#include "ui/browsers/hists.h" +#include "ui/progress.h" +#include "ui/ui.h" +#include "util/annotate.h" +#include "util/symbol.h" #include "util/util.h" struct c2c_hists { @@ -62,6 +68,7 @@ struct compute_stats { struct c2c_hist_entry { struct c2c_hists *hists; + struct evsel *evsel; struct c2c_stats stats; unsigned long *cpuset; unsigned long *nodeset; @@ -152,7 +159,7 @@ static void *c2c_he_zalloc(size_t size) if (!c2c_he->nodeset) goto out_free; - c2c_he->node_stats = zalloc(c2c.nodes_cnt * sizeof(*c2c_he->node_stats)); + c2c_he->node_stats = calloc(c2c.nodes_cnt, sizeof(*c2c_he->node_stats)); if (!c2c_he->node_stats) goto out_free; @@ -177,7 +184,8 @@ static void c2c_he_free(void *he) c2c_he = container_of(he, struct c2c_hist_entry, he); if (c2c_he->hists) { - hists__delete_entries(&c2c_he->hists->hists); + hists__delete_all_entries(&c2c_he->hists->hists); + perf_hpp__reset_output_field(&c2c_he->hists->list); zfree(&c2c_he->hists); } @@ -195,12 +203,14 @@ static struct hist_entry_ops c2c_entry_ops = { static int c2c_hists__init(struct c2c_hists *hists, const char *sort, - int nr_header_lines); + int nr_header_lines, + struct perf_env *env); static struct c2c_hists* he__get_c2c_hists(struct hist_entry *he, const char *sort, - int nr_header_lines) + int nr_header_lines, + struct perf_env *env) { struct c2c_hist_entry *c2c_he; struct c2c_hists *hists; @@ -214,8 +224,10 @@ he__get_c2c_hists(struct hist_entry *he, if (!hists) return NULL; - ret = c2c_hists__init(hists, sort, nr_header_lines); + ret = c2c_hists__init(hists, sort, nr_header_lines, env); if (ret) { + perf_hpp__reset_output_field(&hists->list); + c2c_he->hists = NULL; free(hists); return NULL; } @@ -223,6 +235,12 @@ he__get_c2c_hists(struct hist_entry *he, return hists; } +static void c2c_he__set_evsel(struct c2c_hist_entry *c2c_he, + struct evsel *evsel) +{ + c2c_he->evsel = evsel; +} + static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he, struct perf_sample *sample) { @@ -230,6 +248,10 @@ static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he, "WARNING: no sample cpu value")) return; + /* cpuset bitmap has c2c.cpus_cnt bits from env->nr_cpus_avail */ + if (sample->cpu >= (unsigned int)c2c.cpus_cnt) + return; + __set_bit(sample->cpu, c2c_he->cpuset); } @@ -247,6 +269,10 @@ static void c2c_he__set_node(struct c2c_hist_entry *c2c_he, if (WARN_ONCE(node < 0, "WARNING: failed to find node\n")) return; + /* nodeset bitmap has c2c.nodes_cnt bits from env->nr_numa_nodes */ + if (node >= c2c.nodes_cnt) + return; + __set_bit(node, c2c_he->nodeset); if (c2c_he->paddr != sample->phys_addr) { @@ -273,25 +299,53 @@ static void compute_stats(struct c2c_hist_entry *c2c_he, update_stats(&cstats->load, weight); } +/* + * Return true if annotation is possible. When list is NULL, + * it means that we are called at the c2c_browser level, + * in that case we allow annotation to be initialized. When list + * is non-NULL, it means that we are called at the cacheline_browser + * level, in that case we allow annotation only if use_browser + * is set and symbol information is available. + */ +static bool perf_c2c__has_annotation(struct perf_hpp_list *list) +{ + if (use_browser != 1) + return false; + return !list || list->sym; +} + +static void perf_c2c__evsel_hists_inc_stats(struct evsel *evsel, + struct hist_entry *he, + struct perf_sample *sample) +{ + struct hists *evsel_hists = evsel__hists(evsel); + + hists__inc_nr_samples(evsel_hists, he->filtered); + evsel_hists->stats.total_period += sample->period; + if (!he->filtered) + evsel_hists->stats.total_non_filtered_period += sample->period; +} + static int process_sample_event(const struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, - struct evsel *evsel, struct machine *machine) { + struct evsel *evsel = sample->evsel; struct c2c_hists *c2c_hists = &c2c.hists; struct c2c_hist_entry *c2c_he; struct c2c_stats stats = { .nr_entries = 0, }; struct hist_entry *he; struct addr_location al; - struct mem_info *mi, *mi_dup; + struct mem_info *mi = NULL; struct callchain_cursor *cursor; int ret; addr_location__init(&al); if (machine__resolve(machine, &al, sample) < 0) { - pr_debug("problem processing %d event, skipping it.\n", - event->header.type); + pr_debug("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n", + perf_event__name(event->header.type), event->header.type, + sample->file_offset); ret = -1; goto out; } @@ -301,7 +355,7 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused, cursor = get_tls_callchain_cursor(); ret = sample__resolve_callchain(sample, cursor, NULL, - evsel, &al, sysctl_perf_event_max_stack); + &al, sysctl_perf_event_max_stack); if (ret) goto out; @@ -311,20 +365,15 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused, goto out; } - /* - * The mi object is released in hists__add_entry_ops, - * if it gets sorted out into existing data, so we need - * to take the copy now. - */ - mi_dup = mem_info__get(mi); - c2c_decode_stats(&stats, mi); he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops, &al, NULL, NULL, mi, NULL, sample, true); - if (he == NULL) - goto free_mi; + if (he == NULL) { + ret = -ENOMEM; + goto out; + } c2c_he = container_of(he, struct c2c_hist_entry, he); c2c_add_stats(&c2c_he->stats, &stats); @@ -332,8 +381,15 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused, c2c_he__set_cpu(c2c_he, sample); c2c_he__set_node(c2c_he, sample); + c2c_he__set_evsel(c2c_he, evsel); hists__inc_nr_samples(&c2c_hists->hists, he->filtered); + + if (perf_c2c__has_annotation(NULL)) { + perf_c2c__evsel_hists_inc_stats(evsel, he, sample); + addr_map_symbol__inc_samples(mem_info__iaddr(mi), sample); + } + ret = hist_entry__append_callchain(he, sample); if (!ret) { @@ -346,43 +402,48 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused, * Doing node stats only for single callchain data. */ int cpu = sample->cpu == (unsigned int) -1 ? 0 : sample->cpu; - int node = c2c.cpu2node[cpu]; + int node; - mi = mi_dup; + /* cpu2node[] has c2c.cpus_cnt entries; large u32 wraps signed negative */ + if (cpu < 0 || cpu >= c2c.cpus_cnt) + cpu = 0; + node = c2c.cpu2node[cpu]; - c2c_hists = he__get_c2c_hists(he, c2c.cl_sort, 2); - if (!c2c_hists) - goto free_mi; + c2c_hists = he__get_c2c_hists(he, c2c.cl_sort, 2, machine->env); + if (!c2c_hists) { + ret = -ENOMEM; + goto out; + } he = hists__add_entry_ops(&c2c_hists->hists, &c2c_entry_ops, &al, NULL, NULL, mi, NULL, sample, true); - if (he == NULL) - goto free_mi; + if (he == NULL) { + ret = -ENOMEM; + goto out; + } c2c_he = container_of(he, struct c2c_hist_entry, he); c2c_add_stats(&c2c_he->stats, &stats); c2c_add_stats(&c2c_hists->stats, &stats); - c2c_add_stats(&c2c_he->node_stats[node], &stats); + /* node_stats[] has c2c.nodes_cnt entries */ + if (node >= 0 && node < c2c.nodes_cnt) + c2c_add_stats(&c2c_he->node_stats[node], &stats); compute_stats(c2c_he, &stats, sample->weight); c2c_he__set_cpu(c2c_he, sample); c2c_he__set_node(c2c_he, sample); + c2c_he__set_evsel(c2c_he, evsel); hists__inc_nr_samples(&c2c_hists->hists, he->filtered); ret = hist_entry__append_callchain(he, sample); } out: + mem_info__put(mi); addr_location__exit(&al); return ret; - -free_mi: - mem_info__put(mi_dup); - mem_info__put(mi); - ret = -ENOMEM; - goto out; } static const char * const c2c_usage[] = { @@ -1966,33 +2027,38 @@ static struct c2c_fmt *get_format(const char *name) return c2c_fmt; } -static int c2c_hists__init_output(struct perf_hpp_list *hpp_list, char *name) +static int c2c_hists__init_output(struct perf_hpp_list *hpp_list, char *name, + struct perf_env *env __maybe_unused) { struct c2c_fmt *c2c_fmt = get_format(name); + int level = 0; if (!c2c_fmt) { reset_dimensions(); - return output_field_add(hpp_list, name); + return output_field_add(hpp_list, name, &level); } perf_hpp_list__column_register(hpp_list, &c2c_fmt->fmt); return 0; } -static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name) +static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name, struct perf_env *env) { struct c2c_fmt *c2c_fmt = get_format(name); struct c2c_dimension *dim; if (!c2c_fmt) { reset_dimensions(); - return sort_dimension__add(hpp_list, name, NULL, 0); + return sort_dimension__add(hpp_list, name, /*evlist=*/NULL, env, /*level=*/0); } dim = c2c_fmt->dim; if (dim == &dim_dso) hpp_list->dso = 1; + if (dim == &dim_symbol || dim == &dim_iaddr) + hpp_list->sym = 1; + perf_hpp_list__register_sort_field(hpp_list, &c2c_fmt->fmt); return 0; } @@ -2007,7 +2073,7 @@ static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name) \ for (tok = strtok_r((char *)_list, ", ", &tmp); \ tok; tok = strtok_r(NULL, ", ", &tmp)) { \ - ret = _fn(hpp_list, tok); \ + ret = _fn(hpp_list, tok, env); \ if (ret == -EINVAL) { \ pr_err("Invalid --fields key: `%s'", tok); \ break; \ @@ -2020,7 +2086,8 @@ static int c2c_hists__init_sort(struct perf_hpp_list *hpp_list, char *name) static int hpp_list__parse(struct perf_hpp_list *hpp_list, const char *output_, - const char *sort_) + const char *sort_, + struct perf_env *env) { char *output = output_ ? strdup(output_) : NULL; char *sort = sort_ ? strdup(sort_) : NULL; @@ -2051,7 +2118,8 @@ static int hpp_list__parse(struct perf_hpp_list *hpp_list, static int c2c_hists__init(struct c2c_hists *hists, const char *sort, - int nr_header_lines) + int nr_header_lines, + struct perf_env *env) { __hists__init(&hists->hists, &hists->list); @@ -2065,15 +2133,16 @@ static int c2c_hists__init(struct c2c_hists *hists, /* Overload number of header lines.*/ hists->list.nr_header_lines = nr_header_lines; - return hpp_list__parse(&hists->list, NULL, sort); + return hpp_list__parse(&hists->list, /*output=*/NULL, sort, env); } static int c2c_hists__reinit(struct c2c_hists *c2c_hists, const char *output, - const char *sort) + const char *sort, + struct perf_env *env) { perf_hpp__reset_output_field(&c2c_hists->list); - return hpp_list__parse(&c2c_hists->list, output, sort); + return hpp_list__parse(&c2c_hists->list, output, sort, env); } #define DISPLAY_LINE_LIMIT 0.001 @@ -2206,8 +2275,9 @@ static int filter_cb(struct hist_entry *he, void *arg __maybe_unused) return 0; } -static int resort_cl_cb(struct hist_entry *he, void *arg __maybe_unused) +static int resort_cl_cb(struct hist_entry *he, void *arg) { + struct perf_env *env = arg; struct c2c_hist_entry *c2c_he; struct c2c_hists *c2c_hists; bool display = he__display(he, &c2c.shared_clines_stats); @@ -2221,7 +2291,7 @@ static int resort_cl_cb(struct hist_entry *he, void *arg __maybe_unused) c2c_he->cacheline_idx = idx++; calc_width(c2c_he); - c2c_hists__reinit(c2c_hists, c2c.cl_output, c2c.cl_resort); + c2c_hists__reinit(c2c_hists, c2c.cl_output, c2c.cl_resort, env); hists__collapse_resort(&c2c_hists->hists, NULL); hists__output_resort_cb(&c2c_hists->hists, NULL, filter_cb); @@ -2263,38 +2333,39 @@ static int setup_nodes(struct perf_session *session) { struct numa_node *n; unsigned long **nodes; - int node, idx; struct perf_cpu cpu; int *cpu2node; + struct perf_env *env = perf_session__env(session); if (c2c.node_info > 2) c2c.node_info = 2; - c2c.nodes_cnt = session->header.env.nr_numa_nodes; - c2c.cpus_cnt = session->header.env.nr_cpus_avail; + c2c.nodes_cnt = env->nr_numa_nodes; + c2c.cpus_cnt = env->nr_cpus_avail; - n = session->header.env.numa_nodes; + n = env->numa_nodes; if (!n) return -EINVAL; - nodes = zalloc(sizeof(unsigned long *) * c2c.nodes_cnt); + nodes = calloc(c2c.nodes_cnt, sizeof(unsigned long *)); if (!nodes) return -ENOMEM; c2c.nodes = nodes; - cpu2node = zalloc(sizeof(int) * c2c.cpus_cnt); + cpu2node = calloc(c2c.cpus_cnt, sizeof(int)); if (!cpu2node) return -ENOMEM; - for (idx = 0; idx < c2c.cpus_cnt; idx++) + for (int idx = 0; idx < c2c.cpus_cnt; idx++) cpu2node[idx] = -1; c2c.cpu2node = cpu2node; - for (node = 0; node < c2c.nodes_cnt; node++) { + for (int node = 0; node < c2c.nodes_cnt; node++) { struct perf_cpu_map *map = n[node].map; unsigned long *set; + unsigned int idx; set = bitmap_zalloc(c2c.cpus_cnt); if (!set) @@ -2303,6 +2374,10 @@ static int setup_nodes(struct perf_session *session) nodes[node] = set; perf_cpu_map__for_each_cpu_skip_any(cpu, idx, map) { + /* topology CPU IDs from perf.data may exceed nr_cpus_avail */ + if (cpu.cpu < 0 || cpu.cpu >= c2c.cpus_cnt) + continue; + __set_bit(cpu.cpu, set); if (WARN_ONCE(cpu2node[cpu.cpu] != -1, "node/cpu topology bug")) @@ -2332,7 +2407,7 @@ static int resort_shared_cl_cb(struct hist_entry *he, void *arg __maybe_unused) return 0; } -static int hists__iterate_cb(struct hists *hists, hists__resort_cb_t cb) +static int hists__iterate_cb(struct hists *hists, hists__resort_cb_t cb, void *arg) { struct rb_node *next = rb_first_cached(&hists->entries); int ret = 0; @@ -2341,7 +2416,7 @@ static int hists__iterate_cb(struct hists *hists, hists__resort_cb_t cb) struct hist_entry *he; he = rb_entry(next, struct hist_entry, rb_node); - ret = cb(he, NULL); + ret = cb(he, arg); if (ret) break; next = rb_next(&he->rb_node); @@ -2447,7 +2522,7 @@ static void print_cacheline(struct c2c_hists *c2c_hists, hists__fprintf(&c2c_hists->hists, false, 0, 0, 0, out, false); } -static void print_pareto(FILE *out) +static void print_pareto(FILE *out, struct perf_env *env) { struct perf_hpp_list hpp_list; struct rb_node *nd; @@ -2472,7 +2547,7 @@ static void print_pareto(FILE *out) "dcacheline"; perf_hpp_list__init(&hpp_list); - ret = hpp_list__parse(&hpp_list, cl_output, NULL); + ret = hpp_list__parse(&hpp_list, cl_output, /*evlist=*/NULL, env); if (WARN_ONCE(ret, "failed to setup sort entries\n")) return; @@ -2537,10 +2612,48 @@ static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session) fprintf(out, "=================================================\n"); fprintf(out, "#\n"); - print_pareto(out); + print_pareto(out, perf_session__env(session)); } #ifdef HAVE_SLANG_SUPPORT + +static int perf_c2c__toggle_annotation(struct hist_browser *browser) +{ + struct hist_entry *he = browser->he_selection; + struct symbol *sym = NULL; + struct annotated_source *src = NULL; + struct c2c_hist_entry *c2c_he = NULL; + u64 al_addr = NO_ADDR; + + if (!perf_c2c__has_annotation(he->hists->hpp_list)) { + ui_browser__help_window(&browser->b, "No annotation support"); + return 0; + } + + if (he == NULL) { + ui_browser__help_window(&browser->b, "No entry selected for annotation"); + return 0; + } + + sym = he->ms.sym; + if (sym == NULL) { + ui_browser__help_window(&browser->b, "Can not annotate, no symbol found"); + return 0; + } + + src = symbol__hists(sym, 0); + if (src == NULL) { + ui_browser__help_window(&browser->b, "Failed to initialize annotation source"); + return 0; + } + + if (he->mem_info) + al_addr = mem_info__iaddr(he->mem_info)->al_addr; + + c2c_he = container_of(he, struct c2c_hist_entry, he); + return hist_entry__tui_annotate(he, c2c_he->evsel, NULL, al_addr); +} + static void c2c_browser__update_nr_entries(struct hist_browser *hb) { u64 nr_entries = 0; @@ -2608,6 +2721,7 @@ static int perf_c2c__browse_cacheline(struct hist_entry *he) " ENTER Toggle callchains (if present) \n" " n Toggle Node details info \n" " s Toggle full length of symbol and source line columns \n" + " a Toggle annotation view \n" " q Return back to cacheline list \n"; if (!he) @@ -2642,6 +2756,9 @@ static int perf_c2c__browse_cacheline(struct hist_entry *he) c2c.node_info = (c2c.node_info + 1) % 3; setup_nodes_header(); break; + case 'a': + perf_c2c__toggle_annotation(browser); + break; case 'q': goto out; case '?': @@ -2802,9 +2919,10 @@ static int ui_quirks(void) #define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent" -const char callchain_help[] = "Display call graph (stack chain/backtrace):\n\n" - CALLCHAIN_REPORT_HELP - "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT; +static const char callchain_help[] = + "Display call graph (stack chain/backtrace):\n\n" + CALLCHAIN_REPORT_HELP + "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT; static int parse_callchain_opt(const struct option *opt, const char *arg, int unset) @@ -2997,6 +3115,7 @@ static int perf_c2c__report(int argc, const char **argv) const char *display = NULL; const char *coalesce = NULL; bool no_source = false; + const char *disassembler_style = NULL, *objdump_path = NULL; const struct option options[] = { OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), @@ -3024,11 +3143,22 @@ static int perf_c2c__report(int argc, const char **argv) OPT_BOOLEAN(0, "stitch-lbr", &c2c.stitch_lbr, "Enable LBR callgraph stitching approach"), OPT_BOOLEAN(0, "double-cl", &chk_double_cl, "Detect adjacent cacheline false sharing"), + OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", + "Specify disassembler style (e.g. -M intel for intel syntax)"), + OPT_STRING(0, "objdump", &objdump_path, "path", + "objdump binary to use for disassembly and annotations"), OPT_PARENT(c2c_options), OPT_END() }; int err = 0; const char *output_str, *sort_str = NULL; + struct perf_env *env; + + annotation_options__init(); + + err = hists__init(); + if (err < 0) + goto out; argc = parse_options(argc, argv, options, report_c2c_usage, PARSE_OPT_STOP_AT_NON_OPTION); @@ -3042,6 +3172,27 @@ static int perf_c2c__report(int argc, const char **argv) if (c2c.stats_only) c2c.use_stdio = true; + /** + * Annotation related options disassembler_style, objdump_path are set + * in the c2c_options, so we can use them here. + */ + if (disassembler_style) { + annotate_opts.disassembler_style = strdup(disassembler_style); + if (!annotate_opts.disassembler_style) { + err = -ENOMEM; + pr_err("Failed to allocate memory for annotation options\n"); + goto out; + } + } + if (objdump_path) { + annotate_opts.objdump_path = strdup(objdump_path); + if (!annotate_opts.objdump_path) { + err = -ENOMEM; + pr_err("Failed to allocate memory for annotation options\n"); + goto out; + } + } + err = symbol__validate_sym_arguments(); if (err) goto out; @@ -3071,14 +3222,14 @@ static int perf_c2c__report(int argc, const char **argv) pr_debug("Error creating perf session\n"); goto out; } - + env = perf_session__env(session); /* * Use the 'tot' as default display type if user doesn't specify it; * since Arm64 platform doesn't support HITMs flag, use 'peer' as the * default display type. */ if (!display) { - if (!strcmp(perf_env__arch(&session->header.env), "arm64")) + if (perf_env__e_machine(env, /*e_flags=*/NULL) == EM_AARCH64) display = "peer"; else display = "tot"; @@ -3094,7 +3245,7 @@ static int perf_c2c__report(int argc, const char **argv) goto out_session; } - err = c2c_hists__init(&c2c.hists, "dcacheline", 2); + err = c2c_hists__init(&c2c.hists, "dcacheline", 2, perf_session__env(session)); if (err) { pr_debug("Failed to initialize hists\n"); goto out_session; @@ -3108,7 +3259,7 @@ static int perf_c2c__report(int argc, const char **argv) goto out_session; } - err = mem2node__init(&c2c.mem2node, &session->header.env); + err = mem2node__init(&c2c.mem2node, env); if (err) goto out_session; @@ -3116,7 +3267,39 @@ static int perf_c2c__report(int argc, const char **argv) if (err) goto out_mem2node; - if (symbol__init(&session->header.env) < 0) + if (c2c.use_stdio) + use_browser = 0; + else + use_browser = 1; + + /* + * Only in the TUI browser we are doing integrated annotation, + * so don't allocate extra space that won't be used in the stdio + * implementation. + */ + if (perf_c2c__has_annotation(NULL)) { + int ret = symbol__annotation_init(); + + if (ret < 0) + goto out_mem2node; + /* + * For searching by name on the "Browse map details". + * providing it only in verbose mode not to bloat too + * much struct symbol. + */ + if (verbose > 0) { + /* + * XXX: Need to provide a less kludgy way to ask for + * more space per symbol, the u32 is for the index on + * the ui browser. + * See symbol__browser_index. + */ + symbol_conf.priv_size += sizeof(u32); + } + annotation_config__init(); + } + + if (symbol__init(env) < 0) goto out_mem2node; /* No pipe support at the moment. */ @@ -3125,11 +3308,6 @@ static int perf_c2c__report(int argc, const char **argv) goto out_mem2node; } - if (c2c.use_stdio) - use_browser = 0; - else - use_browser = 1; - setup_browser(false); err = perf_session__process_events(session); @@ -3178,13 +3356,13 @@ static int perf_c2c__report(int argc, const char **argv) else if (c2c.display == DISPLAY_SNP_PEER) sort_str = "tot_peer"; - c2c_hists__reinit(&c2c.hists, output_str, sort_str); + c2c_hists__reinit(&c2c.hists, output_str, sort_str, perf_session__env(session)); ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting..."); hists__collapse_resort(&c2c.hists.hists, NULL); hists__output_resort_cb(&c2c.hists.hists, &prog, resort_shared_cl_cb); - hists__iterate_cb(&c2c.hists.hists, resort_cl_cb); + hists__iterate_cb(&c2c.hists.hists, resort_cl_cb, perf_session__env(session)); ui_progress__finish(); @@ -3200,6 +3378,7 @@ out_mem2node: out_session: perf_session__delete(session); out: + annotation_options__exit(); return err; } @@ -3239,6 +3418,7 @@ static int perf_c2c__record(int argc, const char **argv) { int rec_argc, i = 0, j; const char **rec_argv; + char *event_name_storage = NULL; int ret; bool all_user = false, all_kernel = false; bool event_set = false; @@ -3300,7 +3480,7 @@ static int perf_c2c__record(int argc, const char **argv) rec_argv[i++] = "--phys-data"; rec_argv[i++] = "--sample-cpu"; - ret = perf_mem_events__record_args(rec_argv, &i); + ret = perf_mem_events__record_args(rec_argv, &i, &event_name_storage); if (ret) goto out; @@ -3327,6 +3507,7 @@ static int perf_c2c__record(int argc, const char **argv) ret = cmd_record(i, rec_argv); out: + free(event_name_storage); free(rec_argv); return ret; } |
