diff options
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r-- | tools/perf/builtin-report.c | 174 |
1 files changed, 130 insertions, 44 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 4054eb1f98ac..830d563de889 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -8,16 +8,20 @@ */ #include "builtin.h" -#include "util/util.h" #include "util/config.h" #include "util/annotate.h" #include "util/color.h" +#include "util/dso.h" #include <linux/list.h> #include <linux/rbtree.h> #include <linux/err.h> +#include <linux/zalloc.h> #include "util/map.h" #include "util/symbol.h" +#include "util/map_symbol.h" +#include "util/mem-events.h" +#include "util/branch.h" #include "util/callchain.h" #include "util/values.h" @@ -25,8 +29,10 @@ #include "util/debug.h" #include "util/evlist.h" #include "util/evsel.h" +#include "util/evswitch.h" #include "util/header.h" #include "util/session.h" +#include "util/srcline.h" #include "util/tool.h" #include <subcmd/parse-options.h> @@ -42,14 +48,19 @@ #include "util/auxtrace.h" #include "util/units.h" #include "util/branch.h" +#include "util/util.h" // perf_tip() +#include "ui/ui.h" +#include "ui/progress.h" +#include "util/block-info.h" #include <dlfcn.h> #include <errno.h> #include <inttypes.h> #include <regex.h> -#include "sane_ctype.h" +#include <linux/ctype.h> #include <signal.h> #include <linux/bitmap.h> +#include <linux/string.h> #include <linux/stringify.h> #include <linux/time64.h> #include <sys/types.h> @@ -60,6 +71,7 @@ struct report { struct perf_tool tool; struct perf_session *session; + struct evswitch evswitch; bool use_tui, use_gtk, use_stdio; bool show_full_info; bool show_threads; @@ -85,10 +97,13 @@ struct report { float min_percent; u64 nr_entries; u64 queue_size; + u64 total_cycles; int socket_filter; DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); struct branch_type_stat brtype_stat; bool symbol_ipc; + bool total_cycles_mode; + struct block_report *block_reports; }; static int report__config(const char *var, const char *value, void *cb) @@ -128,7 +143,7 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter, int err = 0; struct report *rep = arg; struct hist_entry *he = iter->he; - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct perf_sample *sample = iter->sample; struct mem_info *mi; struct branch_info *bi; @@ -136,9 +151,6 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter, if (!ui__has_annotation() && !rep->symbol_ipc) return 0; - hist__account_cycles(sample->branch_stack, al, sample, - rep->nonany_branch_mode); - if (sort__mode == SORT_MODE__BRANCH) { bi = he->branch_info; err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); @@ -175,15 +187,12 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter, struct report *rep = arg; struct branch_info *bi; struct perf_sample *sample = iter->sample; - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; int err; if (!ui__has_annotation() && !rep->symbol_ipc) return 0; - hist__account_cycles(sample->branch_stack, al, sample, - rep->nonany_branch_mode); - bi = he->branch_info; err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); if (err) @@ -199,7 +208,7 @@ out: } static void setup_forced_leader(struct report *report, - struct perf_evlist *evlist) + struct evlist *evlist) { if (report->group_set) perf_evlist__force_leader(evlist); @@ -214,7 +223,7 @@ static int process_feature_event(struct perf_session *session, return perf_event__process_feature(session, event); if (event->feat.feat_id != HEADER_LAST_FEATURE) { - pr_err("failed: wrong feature ID: %" PRIu64 "\n", + pr_err("failed: wrong feature ID: %" PRI_lu64 "\n", event->feat.feat_id); return -1; } @@ -231,7 +240,7 @@ static int process_feature_event(struct perf_session *session, static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { struct report *rep = container_of(tool, struct report, tool); @@ -249,6 +258,9 @@ static int process_sample_event(struct perf_tool *tool, return 0; } + if (evswitch__discard(&rep->evswitch, evsel)) + return 0; + if (machine__resolve(machine, &al, sample) < 0) { pr_debug("problem processing %d event, skipping it.\n", event->header.type); @@ -282,6 +294,12 @@ static int process_sample_event(struct perf_tool *tool, if (al.map != NULL) al.map->dso->hit = 1; + if (ui__has_annotation() || rep->symbol_ipc || rep->total_cycles_mode) { + hist__account_cycles(sample->branch_stack, &al, sample, + rep->nonany_branch_mode, + &rep->total_cycles); + } + ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep); if (ret < 0) pr_debug("problem adding hist entry, skipping event\n"); @@ -293,13 +311,13 @@ out_put: static int process_read_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample __maybe_unused, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine __maybe_unused) { struct report *rep = container_of(tool, struct report, tool); if (rep->show_threads) { - const char *name = evsel ? perf_evsel__name(evsel) : "unknown"; + const char *name = perf_evsel__name(evsel); int err = perf_read_values_add_value(&rep->show_threads_values, event->read.pid, event->read.tid, evsel->idx, @@ -386,6 +404,13 @@ static int report__setup_sample_type(struct report *rep) PERF_SAMPLE_BRANCH_ANY)) rep->nonany_branch_mode = true; +#ifndef HAVE_LIBUNWIND_SUPPORT + if (dwarf_callchain_users) { + ui__warning("Please install libunwind development packages " + "during the perf build.\n"); + } +#endif + return 0; } @@ -401,7 +426,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report char unit; unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; u64 nr_events = hists->stats.total_period; - struct perf_evsel *evsel = hists_to_evsel(hists); + struct evsel *evsel = hists_to_evsel(hists); char buf[512]; size_t size = sizeof(buf); int socked_id = hists->socket_filter; @@ -415,7 +440,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report } if (perf_evsel__is_group_event(evsel)) { - struct perf_evsel *pos; + struct evsel *pos; perf_evsel__group_desc(evsel, buf, size); evname = buf; @@ -437,7 +462,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit); if (evname != NULL) { ret += fprintf(fp, " of event%s '%s'", - evsel->nr_members > 1 ? "s" : "", evname); + evsel->core.nr_members > 1 ? "s" : "", evname); } if (rep->time_str) @@ -460,11 +485,30 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report return ret + fprintf(fp, "\n#\n"); } -static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, +static int perf_evlist__tui_block_hists_browse(struct evlist *evlist, + struct report *rep) +{ + struct evsel *pos; + int i = 0, ret; + + evlist__for_each_entry(evlist, pos) { + ret = report__browse_block_hists(&rep->block_reports[i++].hist, + rep->min_percent, pos, + &rep->session->header.env, + &rep->annotation_opts); + if (ret != 0) + return ret; + } + + return 0; +} + +static int perf_evlist__tty_browse_hists(struct evlist *evlist, struct report *rep, const char *help) { - struct perf_evsel *pos; + struct evsel *pos; + int i = 0; if (!quiet) { fprintf(stdout, "#\n# Total Lost Samples: %" PRIu64 "\n#\n", @@ -480,6 +524,14 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, continue; hists__fprintf_nr_sample_events(hists, rep, evname, stdout); + + if (rep->total_cycles_mode) { + report__browse_block_hists(&rep->block_reports[i++].hist, + rep->min_percent, pos, + NULL, NULL); + continue; + } + hists__fprintf(hists, !quiet, 0, 0, rep->min_percent, stdout, !(symbol_conf.use_callchain || symbol_conf.show_branchflag_count)); @@ -533,7 +585,7 @@ static void report__warn_kptr_restrict(const struct report *rep) static int report__gtk_browse_hists(struct report *rep, const char *help) { - int (*hist_browser)(struct perf_evlist *evlist, const char *help, + int (*hist_browser)(struct evlist *evlist, const char *help, struct hist_browser_timer *timer, float min_pcnt); hist_browser = dlsym(perf_gtk_handle, "perf_evlist__gtk_browse_hists"); @@ -550,7 +602,7 @@ static int report__browse_hists(struct report *rep) { int ret; struct perf_session *session = rep->session; - struct perf_evlist *evlist = session->evlist; + struct evlist *evlist = session->evlist; const char *help = perf_tip(system_path(TIPDIR)); if (help == NULL) { @@ -562,6 +614,11 @@ static int report__browse_hists(struct report *rep) switch (use_browser) { case 1: + if (rep->total_cycles_mode) { + ret = perf_evlist__tui_block_hists_browse(evlist, rep); + break; + } + ret = perf_evlist__tui_browse_hists(evlist, help, NULL, rep->min_percent, &session->header.env, @@ -587,7 +644,7 @@ static int report__browse_hists(struct report *rep) static int report__collapse_hists(struct report *rep) { struct ui_progress prog; - struct perf_evsel *pos; + struct evsel *pos; int ret = 0; ui_progress__init(&prog, rep->nr_entries, "Merging related events..."); @@ -624,9 +681,9 @@ static int hists__resort_cb(struct hist_entry *he, void *arg) struct symbol *sym = he->ms.sym; if (rep->symbol_ipc && sym && !sym->annotate2) { - struct perf_evsel *evsel = hists_to_evsel(he->hists); + struct evsel *evsel = hists_to_evsel(he->hists); - symbol__annotate2(sym, he->ms.map, evsel, + symbol__annotate2(&he->ms, evsel, &annotation__default_options, NULL); } @@ -636,7 +693,7 @@ static int hists__resort_cb(struct hist_entry *he, void *arg) static void report__output_resort(struct report *rep) { struct ui_progress prog; - struct perf_evsel *pos; + struct evsel *pos; ui_progress__init(&prog, rep->nr_entries, "Sorting events for output..."); @@ -707,11 +764,9 @@ static struct task *tasks_list(struct task *task, struct machine *machine) static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp) { size_t printed = 0; - struct rb_node *nd; - - for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) { - struct map *map = rb_entry(nd, struct map, rb_node); + struct map *map; + maps__for_each_entry(maps, map) { printed += fprintf(fp, "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n", indent, "", map->start, map->end, map->prot & PROT_READ ? 'r' : '-', @@ -719,17 +774,12 @@ static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp) map->prot & PROT_EXEC ? 'x' : '-', map->flags & MAP_SHARED ? 's' : 'p', map->pgoff, - map->ino, map->dso->name); + map->dso->id.ino, map->dso->name); } return printed; } -static int map_groups__fprintf_task(struct map_groups *mg, int indent, FILE *fp) -{ - return maps__fprintf_task(&mg->maps, indent, fp); -} - static void task__print_level(struct task *task, FILE *fp, int level) { struct thread *thread = task->thread; @@ -740,7 +790,7 @@ static void task__print_level(struct task *task, FILE *fp, int level) fprintf(fp, "%s\n", thread__comm_str(thread)); - map_groups__fprintf_task(thread->mg, comm_indent, fp); + maps__fprintf_task(thread->maps, comm_indent, fp); if (!list_empty(&task->children)) { list_for_each_entry(child, &task->children, list) @@ -819,7 +869,7 @@ static int __cmd_report(struct report *rep) { int ret; struct perf_session *session = rep->session; - struct perf_evsel *pos; + struct evsel *pos; struct perf_data *data = session->data; signal(SIGINT, sig_handler); @@ -907,6 +957,13 @@ static int __cmd_report(struct report *rep) report__output_resort(rep); + if (rep->total_cycles_mode) { + rep->block_reports = block_info__create_report(session->evlist, + rep->total_cycles); + if (!rep->block_reports) + return -1; + } + return report__browse_hists(rep); } @@ -942,8 +999,7 @@ parse_time_quantum(const struct option *opt, const char *arg, pr_err("time quantum cannot be 0"); return -1; } - while (isspace(*end)) - end++; + end = skip_spaces(end); if (*end == 0) return 0; if (!strcmp(end, "s")) { @@ -1191,6 +1247,9 @@ int cmd_report(int argc, const char **argv) OPT_CALLBACK(0, "time-quantum", &symbol_conf.time_quantum, "time (ms|us|ns|s)", "Set time quantum for time sort key (default 100ms)", parse_time_quantum), + OPTS_EVSWITCH(&report.evswitch), + OPT_BOOLEAN(0, "total-cycles", &report.total_cycles_mode, + "Sort all blocks by 'Sampled Cycles%'"), OPT_END() }; struct perf_data data = { @@ -1256,8 +1315,15 @@ int cmd_report(int argc, const char **argv) repeat: session = perf_session__new(&data, false, &report.tool); - if (session == NULL) - return -1; + if (IS_ERR(session)) + return PTR_ERR(session); + + ret = evswitch__init(&report.evswitch, session->evlist, stderr); + if (ret) + return ret; + + if (zstd_init(&(session->zstd_data), 0) < 0) + pr_warning("Decompression initialization failed. Reported data may be incomplete.\n"); if (report.queue_size) { ordered_events__set_alloc_size(&session->ordered_events, @@ -1270,6 +1336,8 @@ repeat: has_br_stack = perf_header__has_feat(&session->header, HEADER_BRANCH_STACK); + if (perf_evlist__combined_sample_type(session->evlist) & PERF_SAMPLE_STACK_USER) + has_br_stack = false; setup_forced_leader(&report, session->evlist); @@ -1344,6 +1412,13 @@ repeat: goto error; } + if (report.total_cycles_mode) { + if (sort__mode != SORT_MODE__BRANCH) + report.total_cycles_mode = false; + else + sort_order = NULL; + } + if (strcmp(input_name, "-") != 0) setup_browser(true); else @@ -1394,7 +1469,8 @@ repeat: * so don't allocate extra space that won't be used in the stdio * implementation. */ - if (ui__has_annotation() || report.symbol_ipc) { + if (ui__has_annotation() || report.symbol_ipc || + report.total_cycles_mode) { ret = symbol__annotation_init(); if (ret < 0) goto error; @@ -1426,6 +1502,10 @@ repeat: &report.range_num); if (ret < 0) goto error; + + itrace_synth_opts__set_time_range(&itrace_synth_opts, + report.ptime_range, + report.range_num); } if (session->tevent.pevent && @@ -1447,9 +1527,15 @@ repeat: ret = 0; error: - if (report.ptime_range) + if (report.ptime_range) { + itrace_synth_opts__clear_time_range(&itrace_synth_opts); zfree(&report.ptime_range); + } + + if (report.block_reports) + zfree(&report.block_reports); + zstd_fini(&(session->zstd_data)); perf_session__delete(session); return ret; } |