diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r-- | tools/perf/builtin-script.c | 184 |
1 files changed, 119 insertions, 65 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index c16224b1fef3..a644787fa9e1 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -62,6 +62,7 @@ #include "util/record.h" #include "util/util.h" #include "util/cgroup.h" +#include "util/annotate.h" #include "perf.h" #include <linux/ctype.h> @@ -138,6 +139,7 @@ enum perf_output_field { PERF_OUTPUT_DSOFF = 1ULL << 41, PERF_OUTPUT_DISASM = 1ULL << 42, PERF_OUTPUT_BRSTACKDISASM = 1ULL << 43, + PERF_OUTPUT_BRCNTR = 1ULL << 44, }; struct perf_script { @@ -213,6 +215,7 @@ struct output_option { {.str = "cgroup", .field = PERF_OUTPUT_CGROUP}, {.str = "retire_lat", .field = PERF_OUTPUT_RETIRE_LAT}, {.str = "brstackdisasm", .field = PERF_OUTPUT_BRSTACKDISASM}, + {.str = "brcntr", .field = PERF_OUTPUT_BRCNTR}, }; enum { @@ -520,6 +523,12 @@ static int evsel__check_attr(struct evsel *evsel, struct perf_session *session) "Hint: run 'perf record -b ...'\n"); return -EINVAL; } + if (PRINT_FIELD(BRCNTR) && + !(evlist__combined_branch_type(session->evlist) & PERF_SAMPLE_BRANCH_COUNTERS)) { + pr_err("Display of branch counter requested but it's not enabled\n" + "Hint: run 'perf record -j any,counter ...'\n"); + return -EINVAL; + } if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", PERF_OUTPUT_TID|PERF_OUTPUT_PID)) return -EINVAL; @@ -789,6 +798,19 @@ static int perf_sample__fprintf_start(struct perf_script *script, int printed = 0; char tstr[128]; + /* + * Print the branch counter's abbreviation list, + * if the branch counter is available. + */ + if (PRINT_FIELD(BRCNTR) && !verbose) { + char *buf; + + if (!annotation_br_cntr_abbr_list(&buf, evsel, true)) { + printed += fprintf(stdout, "%s", buf); + free(buf); + } + } + if (PRINT_FIELD(MACHINE_PID) && sample->machine_pid) printed += fprintf(fp, "VM:%5d ", sample->machine_pid); @@ -1195,7 +1217,9 @@ static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, struct perf_insn *x, u8 *inbuf, int len, int insn, FILE *fp, int *total_cycles, struct perf_event_attr *attr, - struct thread *thread) + struct thread *thread, + struct evsel *evsel, + u64 br_cntr) { int ilen = 0; int printed = fprintf(fp, "\t%016" PRIx64 "\t", ip); @@ -1216,6 +1240,29 @@ static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, addr_location__exit(&al); } + if (PRINT_FIELD(BRCNTR)) { + struct evsel *pos = evsel__leader(evsel); + unsigned int i = 0, j, num, mask, width; + + perf_env__find_br_cntr_info(evsel__env(evsel), NULL, &width); + mask = (1L << width) - 1; + printed += fprintf(fp, "br_cntr: "); + evlist__for_each_entry_from(evsel->evlist, pos) { + if (!(pos->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS)) + continue; + if (evsel__leader(pos) != evsel__leader(evsel)) + break; + + num = (br_cntr >> (i++ * width)) & mask; + if (!verbose) { + for (j = 0; j < num; j++) + printed += fprintf(fp, "%s", pos->abbr_name); + } else + printed += fprintf(fp, "%s %d ", pos->name, num); + } + printed += fprintf(fp, "\t"); + } + printed += fprintf(fp, "#%s%s%s%s", en->flags.predicted ? " PRED" : "", en->flags.mispred ? " MISPRED" : "", @@ -1272,6 +1319,7 @@ out: } static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, + struct evsel *evsel, struct thread *thread, struct perf_event_attr *attr, struct machine *machine, FILE *fp) @@ -1285,6 +1333,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, unsigned off; struct symbol *lastsym = NULL; int total_cycles = 0; + u64 br_cntr = 0; if (!(br && br->nr)) return 0; @@ -1296,6 +1345,9 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, x.machine = machine; x.cpu = sample->cpu; + if (PRINT_FIELD(BRCNTR) && sample->branch_stack_cntr) + br_cntr = sample->branch_stack_cntr[nr - 1]; + printed += fprintf(fp, "%c", '\n'); /* Handle first from jump, of which we don't know the entry. */ @@ -1307,7 +1359,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, x.cpumode, x.cpu, &lastsym, attr, fp); printed += ip__fprintf_jump(entries[nr - 1].from, &entries[nr - 1], &x, buffer, len, 0, fp, &total_cycles, - attr, thread); + attr, thread, evsel, br_cntr); if (PRINT_FIELD(SRCCODE)) printed += print_srccode(thread, x.cpumode, entries[nr - 1].from); } @@ -1337,8 +1389,10 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp); if (ip == end) { + if (PRINT_FIELD(BRCNTR) && sample->branch_stack_cntr) + br_cntr = sample->branch_stack_cntr[i]; printed += ip__fprintf_jump(ip, &entries[i], &x, buffer + off, len - off, ++insn, fp, - &total_cycles, attr, thread); + &total_cycles, attr, thread, evsel, br_cntr); if (PRINT_FIELD(SRCCODE)) printed += print_srccode(thread, x.cpumode, ip); break; @@ -1375,7 +1429,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, * Due to pipeline delays the LBRs might be missing a branch * or two, which can result in very large or negative blocks * between final branch and sample. When this happens just - * continue walking after the last TO until we hit a branch. + * continue walking after the last TO. */ start = entries[0].to; end = sample->ip; @@ -1410,7 +1464,9 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, printed += fprintf(fp, "\n"); if (ilen == 0) break; - if (arch_is_branch(buffer + off, len - off, x.is64bit) && start + off != sample->ip) { + if ((attr->branch_sample_type == 0 || attr->branch_sample_type & PERF_SAMPLE_BRANCH_ANY) + && arch_is_uncond_branch(buffer + off, len - off, x.is64bit) + && start + off != sample->ip) { /* * Hit a missing branch. Just stop. */ @@ -1547,6 +1603,7 @@ void script_fetch_insn(struct perf_sample *sample, struct thread *thread, } static int perf_sample__fprintf_insn(struct perf_sample *sample, + struct evsel *evsel, struct perf_event_attr *attr, struct thread *thread, struct machine *machine, FILE *fp, @@ -1567,7 +1624,7 @@ static int perf_sample__fprintf_insn(struct perf_sample *sample, printed += sample__fprintf_insn_asm(sample, thread, machine, fp, al); } if (PRINT_FIELD(BRSTACKINSN) || PRINT_FIELD(BRSTACKINSNLEN) || PRINT_FIELD(BRSTACKDISASM)) - printed += perf_sample__fprintf_brstackinsn(sample, thread, attr, machine, fp); + printed += perf_sample__fprintf_brstackinsn(sample, evsel, thread, attr, machine, fp); return printed; } @@ -1639,7 +1696,7 @@ static int perf_sample__fprintf_bts(struct perf_sample *sample, if (print_srcline_last) printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); - printed += perf_sample__fprintf_insn(sample, attr, thread, machine, fp, al); + printed += perf_sample__fprintf_insn(sample, evsel, attr, thread, machine, fp, al); printed += fprintf(fp, "\n"); if (PRINT_FIELD(SRCCODE)) { int ret = map__fprintf_srccode(al->map, al->addr, stdout, @@ -2297,7 +2354,7 @@ static void process_event(struct perf_script *script, if (evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) perf_sample__fprintf_bpf_output(sample, fp); - perf_sample__fprintf_insn(sample, attr, thread, machine, fp, al); + perf_sample__fprintf_insn(sample, evsel, attr, thread, machine, fp, al); if (PRINT_FIELD(PHYS_ADDR)) fprintf(fp, "%16" PRIx64, sample->phys_addr); @@ -2399,7 +2456,7 @@ static bool filter_cpu(struct perf_sample *sample) return false; } -static int process_sample_event(struct perf_tool *tool, +static int process_sample_event(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct evsel *evsel, @@ -2486,7 +2543,7 @@ out_put: // Used when scr->per_event_dump is not set static struct evsel_script es_stdout; -static int process_attr(struct perf_tool *tool, union perf_event *event, +static int process_attr(const struct perf_tool *tool, union perf_event *event, struct evlist **pevlist) { struct perf_script *scr = container_of(tool, struct perf_script, tool); @@ -2552,7 +2609,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, return 0; } -static int print_event_with_time(struct perf_tool *tool, +static int print_event_with_time(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine, @@ -2588,14 +2645,14 @@ static int print_event_with_time(struct perf_tool *tool, return 0; } -static int print_event(struct perf_tool *tool, union perf_event *event, +static int print_event(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine, pid_t pid, pid_t tid) { return print_event_with_time(tool, event, sample, machine, pid, tid, 0); } -static int process_comm_event(struct perf_tool *tool, +static int process_comm_event(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) @@ -2607,7 +2664,7 @@ static int process_comm_event(struct perf_tool *tool, event->comm.tid); } -static int process_namespaces_event(struct perf_tool *tool, +static int process_namespaces_event(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) @@ -2619,7 +2676,7 @@ static int process_namespaces_event(struct perf_tool *tool, event->namespaces.tid); } -static int process_cgroup_event(struct perf_tool *tool, +static int process_cgroup_event(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) @@ -2631,7 +2688,7 @@ static int process_cgroup_event(struct perf_tool *tool, sample->tid); } -static int process_fork_event(struct perf_tool *tool, +static int process_fork_event(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) @@ -2643,7 +2700,7 @@ static int process_fork_event(struct perf_tool *tool, event->fork.pid, event->fork.tid, event->fork.time); } -static int process_exit_event(struct perf_tool *tool, +static int process_exit_event(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) @@ -2656,7 +2713,7 @@ static int process_exit_event(struct perf_tool *tool, return perf_event__process_exit(tool, event, sample, machine); } -static int process_mmap_event(struct perf_tool *tool, +static int process_mmap_event(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) @@ -2668,7 +2725,7 @@ static int process_mmap_event(struct perf_tool *tool, event->mmap.tid); } -static int process_mmap2_event(struct perf_tool *tool, +static int process_mmap2_event(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) @@ -2680,7 +2737,7 @@ static int process_mmap2_event(struct perf_tool *tool, event->mmap2.tid); } -static int process_switch_event(struct perf_tool *tool, +static int process_switch_event(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) @@ -2712,7 +2769,7 @@ static int process_auxtrace_error(struct perf_session *session, } static int -process_lost_event(struct perf_tool *tool, +process_lost_event(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) @@ -2722,7 +2779,7 @@ process_lost_event(struct perf_tool *tool, } static int -process_throttle_event(struct perf_tool *tool __maybe_unused, +process_throttle_event(const struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, struct machine *machine) @@ -2733,7 +2790,7 @@ process_throttle_event(struct perf_tool *tool __maybe_unused, } static int -process_finished_round_event(struct perf_tool *tool __maybe_unused, +process_finished_round_event(const struct perf_tool *tool __maybe_unused, union perf_event *event, struct ordered_events *oe __maybe_unused) @@ -2743,7 +2800,7 @@ process_finished_round_event(struct perf_tool *tool __maybe_unused, } static int -process_bpf_events(struct perf_tool *tool __maybe_unused, +process_bpf_events(const struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, struct machine *machine) @@ -2755,7 +2812,7 @@ process_bpf_events(struct perf_tool *tool __maybe_unused, sample->tid); } -static int process_text_poke_events(struct perf_tool *tool, +static int process_text_poke_events(const struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) @@ -3757,7 +3814,7 @@ static int process_thread_map_event(struct perf_session *session, union perf_event *event) { - struct perf_tool *tool = session->tool; + const struct perf_tool *tool = session->tool; struct perf_script *script = container_of(tool, struct perf_script, tool); if (dump_trace) @@ -3779,7 +3836,7 @@ static int process_cpu_map_event(struct perf_session *session, union perf_event *event) { - struct perf_tool *tool = session->tool; + const struct perf_tool *tool = session->tool; struct perf_script *script = container_of(tool, struct perf_script, tool); if (dump_trace) @@ -3809,11 +3866,10 @@ static int process_feature_event(struct perf_session *session, static int perf_script__process_auxtrace_info(struct perf_session *session, union perf_event *event) { - struct perf_tool *tool = session->tool; - int ret = perf_event__process_auxtrace_info(session, event); if (ret == 0) { + const struct perf_tool *tool = session->tool; struct perf_script *script = container_of(tool, struct perf_script, tool); ret = perf_script__setup_per_event_dump(script); @@ -3900,38 +3956,7 @@ int cmd_script(int argc, const char **argv) const char *dlfilter_file = NULL; const char **__argv; int i, j, err = 0; - struct perf_script script = { - .tool = { - .sample = process_sample_event, - .mmap = perf_event__process_mmap, - .mmap2 = perf_event__process_mmap2, - .comm = perf_event__process_comm, - .namespaces = perf_event__process_namespaces, - .cgroup = perf_event__process_cgroup, - .exit = perf_event__process_exit, - .fork = perf_event__process_fork, - .attr = process_attr, - .event_update = perf_event__process_event_update, -#ifdef HAVE_LIBTRACEEVENT - .tracing_data = perf_event__process_tracing_data, -#endif - .feature = process_feature_event, - .build_id = perf_event__process_build_id, - .id_index = perf_event__process_id_index, - .auxtrace_info = perf_script__process_auxtrace_info, - .auxtrace = perf_event__process_auxtrace, - .auxtrace_error = perf_event__process_auxtrace_error, - .stat = perf_event__process_stat_event, - .stat_round = process_stat_round_event, - .stat_config = process_stat_config_event, - .thread_map = process_thread_map_event, - .cpu_map = process_cpu_map_event, - .throttle = process_throttle_event, - .unthrottle = process_throttle_event, - .ordered_events = true, - .ordering_requires_timestamps = true, - }, - }; + struct perf_script script = {}; struct perf_data data = { .mode = PERF_DATA_MODE_READ, }; @@ -3979,7 +4004,8 @@ int cmd_script(int argc, const char **argv) "brstacksym,flags,data_src,weight,bpf-output,brstackinsn," "brstackinsnlen,brstackdisasm,brstackoff,callindent,insn,disasm,insnlen,synth," "phys_addr,metric,misc,srccode,ipc,tod,data_page_size," - "code_page_size,ins_lat,machine_pid,vcpu,cgroup,retire_lat", + "code_page_size,ins_lat,machine_pid,vcpu,cgroup,retire_lat," + "brcntr", parse_output_fields), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), @@ -4052,6 +4078,8 @@ int cmd_script(int argc, const char **argv) "Enable symbol demangling"), OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, "Enable kernel symbol demangling"), + OPT_STRING(0, "addr2line", &symbol_conf.addr2line_path, "path", + "addr2line binary to use for line numbers"), OPT_STRING(0, "time", &script.time_str, "str", "Time span of interest (start,stop)"), OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name, @@ -4103,10 +4131,8 @@ int cmd_script(int argc, const char **argv) data.path = input_name; data.force = symbol_conf.force; - if (unsorted_dump) { + if (unsorted_dump) dump_trace = true; - script.tool.ordered_events = false; - } if (symbol__validate_sym_arguments()) return -1; @@ -4297,6 +4323,34 @@ script_found: use_browser = 0; } + perf_tool__init(&script.tool, !unsorted_dump); + script.tool.sample = process_sample_event; + script.tool.mmap = perf_event__process_mmap; + script.tool.mmap2 = perf_event__process_mmap2; + script.tool.comm = perf_event__process_comm; + script.tool.namespaces = perf_event__process_namespaces; + script.tool.cgroup = perf_event__process_cgroup; + script.tool.exit = perf_event__process_exit; + script.tool.fork = perf_event__process_fork; + script.tool.attr = process_attr; + script.tool.event_update = perf_event__process_event_update; +#ifdef HAVE_LIBTRACEEVENT + script.tool.tracing_data = perf_event__process_tracing_data; +#endif + script.tool.feature = process_feature_event; + script.tool.build_id = perf_event__process_build_id; + script.tool.id_index = perf_event__process_id_index; + script.tool.auxtrace_info = perf_script__process_auxtrace_info; + script.tool.auxtrace = perf_event__process_auxtrace; + script.tool.auxtrace_error = perf_event__process_auxtrace_error; + script.tool.stat = perf_event__process_stat_event; + script.tool.stat_round = process_stat_round_event; + script.tool.stat_config = process_stat_config_event; + script.tool.thread_map = process_thread_map_event; + script.tool.cpu_map = process_cpu_map_event; + script.tool.throttle = process_throttle_event; + script.tool.unthrottle = process_throttle_event; + script.tool.ordering_requires_timestamps = true; session = perf_session__new(&data, &script.tool); if (IS_ERR(session)) return PTR_ERR(session); |