diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 7315f155803f..8dbe2119686a 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -525,6 +525,17 @@ include::itrace.txt[] Configure time quantum for time sort key. Default 100ms. Accepts s, us, ms, ns units. +--total-cycles:: + When --total-cycles is specified, it supports sorting for all blocks by + 'Sampled Cycles%'. This is useful to concentrate on the globally hottest + blocks. In output, there are some new columns: + + 'Sampled Cycles%' - block sampled cycles aggregation / total sampled cycles + 'Sampled Cycles' - block sampled cycles aggregation + 'Avg Cycles%' - block average sampled cycles / sum of total block average + sampled cycles + 'Avg Cycles' - block average sampled cycles + include::callchain-overhead-calculation.txt[] SEE ALSO diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index bc15b9dcccd6..992b18bdd723 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -51,6 +51,7 @@ #include "util/util.h" // perf_tip() #include "ui/ui.h" #include "ui/progress.h" +#include "util/block-info.h" #include #include @@ -96,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) @@ -290,9 +294,10 @@ 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) { + if (ui__has_annotation() || rep->symbol_ipc || rep->total_cycles_mode) { hist__account_cycles(sample->branch_stack, &al, sample, - rep->nonany_branch_mode, NULL); + rep->nonany_branch_mode, + &rep->total_cycles); } ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep); @@ -485,6 +490,7 @@ static int perf_evlist__tty_browse_hists(struct evlist *evlist, const char *help) { struct evsel *pos; + int i = 0; if (!quiet) { fprintf(stdout, "#\n# Total Lost Samples: %" PRIu64 "\n#\n", @@ -500,6 +506,13 @@ static int perf_evlist__tty_browse_hists(struct 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, + 0, pos); + continue; + } + hists__fprintf(hists, !quiet, 0, 0, rep->min_percent, stdout, !(symbol_conf.use_callchain || symbol_conf.show_branchflag_count)); @@ -925,6 +938,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); } @@ -1209,6 +1229,8 @@ int cmd_report(int argc, const char **argv) "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 = { @@ -1371,6 +1393,17 @@ repeat: goto error; } + if (report.total_cycles_mode) { + if (sort__mode != SORT_MODE__BRANCH) + report.total_cycles_mode = false; + else if (!report.use_stdio) { + pr_err("Error: --total-cycles can be only used together with --stdio\n"); + goto error; + } else { + sort_order = "sym"; + } + } + if (strcmp(input_name, "-") != 0) setup_browser(true); else @@ -1421,7 +1454,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; @@ -1482,6 +1516,10 @@ error: 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; diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 5365606e9dad..655ef7708cd0 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -558,6 +558,25 @@ static int hist_entry__block_fprintf(struct hist_entry *he, return ret; } +static int hist_entry__individual_block_fprintf(struct hist_entry *he, + char *bf, size_t size, + FILE *fp) +{ + int ret = 0; + + struct perf_hpp hpp = { + .buf = bf, + .size = size, + .skip = false, + }; + + hist_entry__snprintf(he, &hpp); + if (!hpp.skip) + ret += fprintf(fp, "%s\n", bf); + + return ret; +} + static int hist_entry__fprintf(struct hist_entry *he, size_t size, char *bf, size_t bfsz, FILE *fp, bool ignore_callchains) @@ -580,6 +599,9 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, if (symbol_conf.report_block) return hist_entry__block_fprintf(he, bf, size, fp); + if (symbol_conf.report_individual_block) + return hist_entry__individual_block_fprintf(he, bf, size, fp); + hist_entry__snprintf(he, &hpp); ret = fprintf(fp, "%s\n", bf); diff --git a/tools/perf/util/block-info.c b/tools/perf/util/block-info.c index 4a7bac95231e..ba891751a6ed 100644 --- a/tools/perf/util/block-info.c +++ b/tools/perf/util/block-info.c @@ -437,3 +437,20 @@ struct block_report *block_info__create_report(struct evlist *evlist, return block_reports; } + +int report__browse_block_hists(struct block_hist *bh, float min_percent, + struct evsel *evsel __maybe_unused) +{ + switch (use_browser) { + case 0: + symbol_conf.report_individual_block = true; + hists__fprintf(&bh->block_hists, true, 0, 0, min_percent, + stdout, true); + hists__delete_entries(&bh->block_hists); + return 0; + default: + return -1; + } + + return 0; +} diff --git a/tools/perf/util/block-info.h b/tools/perf/util/block-info.h index b5266588d476..8309297a6e8f 100644 --- a/tools/perf/util/block-info.h +++ b/tools/perf/util/block-info.h @@ -7,6 +7,7 @@ #include "hist.h" #include "symbol.h" #include "sort.h" +#include "ui/ui.h" struct block_info { struct symbol *sym; @@ -69,4 +70,7 @@ int block_info__process_sym(struct hist_entry *he, struct block_hist *bh, struct block_report *block_info__create_report(struct evlist *evlist, u64 total_cycles); +int report__browse_block_hists(struct block_hist *bh, float min_percent, + struct evsel *evsel); + #endif /* __PERF_BLOCK_H */ diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h index e6880789864c..10f1ec3e0349 100644 --- a/tools/perf/util/symbol_conf.h +++ b/tools/perf/util/symbol_conf.h @@ -40,6 +40,7 @@ struct symbol_conf { raw_trace, report_hierarchy, report_block, + report_individual_block, inline_name, disable_add2line_warn; const char *vmlinux_name,