Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf report: Display average IPC and IPC coverage per symbol

Support displaying the average IPC and IPC coverage per symbol in 'perf
report' --tui and --stdio modes.

For example,

$ perf record -b ...
$ perf report -s symbol

Overhead Symbol IPC [IPC Coverage]
39.60% [.] __random 2.30 [ 54.8%]
18.02% [.] main 0.43 [ 54.3%]
14.21% [.] compute_flag 2.29 [100.0%]
14.16% [.] rand 0.36 [100.0%]
7.06% [.] __random_r 2.57 [ 70.5%]
6.85% [.] rand@plt 0.00 [ 0.0%]

Jiri Olsa <jolsa@redhat.com> provided the patch to support the --stdio
mode. I merged Jiri's code in this patch.

$ perf report -s symbol --stdio

# Overhead Symbol IPC [IPC Coverage]
# ........ ........................... ....................
#
39.60% [.] __random 2.30 [ 54.8%]
18.02% [.] main 0.43 [ 54.3%]
14.21% [.] compute_flag 2.29 [100.0%]
14.16% [.] rand 0.36 [100.0%]
7.06% [.] __random_r 2.57 [ 70.5%]
6.85% [.] rand@plt 0.00 [ 0.0%]
0.02% [k] run_timer_softirq 1.60 [ 57.2%]

The columns "IPC" and "[IPC Coverage]" are automatically enabled when
the sort-key "symbol" is specified. If the perf.data file doesn't
contain timed LBR information, columns are filled with "-".

For example,

# Overhead Symbol IPC [IPC Coverage]
# ........ ........................... ....................
#
46.57% [.] main - -
17.60% [.] rand - -
15.84% [.] __random_r - -
11.90% [.] __random - -
6.50% [.] compute_flag - -
1.59% [.] rand@plt - -
0.00% [.] _dl_relocate_object - -
0.00% [k] tlb_flush_mmu - -
0.00% [k] perf_event_mmap - -
0.00% [k] native_sched_clock - -
0.00% [k] intel_pmu_handle_irq_v4 - -
0.00% [k] native_write_msr - -

v3:
---
Removed the sortkey 'ipc' from command-line. The columns "IPC"
and "[IPC Coverage]" are automatically enabled when "symbol"
is specified.

v2:
---
Merge in Jiri's patch to support stdio mode

Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Reviewed-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1543586097-27632-4-git-send-email-yao.jin@linux.intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Jin Yao and committed by
Arnaldo Carvalho de Melo
ec6ae74f 246fda09

+87 -3
+23 -3
tools/perf/builtin-report.c
··· 85 85 int socket_filter; 86 86 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 87 87 struct branch_type_stat brtype_stat; 88 + bool symbol_ipc; 88 89 }; 89 90 90 91 static int report__config(const char *var, const char *value, void *cb) ··· 130 129 struct mem_info *mi; 131 130 struct branch_info *bi; 132 131 133 - if (!ui__has_annotation()) 132 + if (!ui__has_annotation() && !rep->symbol_ipc) 134 133 return 0; 135 134 136 135 hist__account_cycles(sample->branch_stack, al, sample, ··· 175 174 struct perf_evsel *evsel = iter->evsel; 176 175 int err; 177 176 178 - if (!ui__has_annotation()) 177 + if (!ui__has_annotation() && !rep->symbol_ipc) 179 178 return 0; 180 179 181 180 hist__account_cycles(sample->branch_stack, al, sample, ··· 1134 1133 .mode = PERF_DATA_MODE_READ, 1135 1134 }; 1136 1135 int ret = hists__init(); 1136 + char sort_tmp[128]; 1137 1137 1138 1138 if (ret < 0) 1139 1139 return ret; ··· 1286 1284 else 1287 1285 use_browser = 0; 1288 1286 1287 + if (sort_order && strstr(sort_order, "ipc")) { 1288 + parse_options_usage(report_usage, options, "s", 1); 1289 + goto error; 1290 + } 1291 + 1292 + if (sort_order && strstr(sort_order, "symbol")) { 1293 + if (sort__mode == SORT_MODE__BRANCH) { 1294 + snprintf(sort_tmp, sizeof(sort_tmp), "%s,%s", 1295 + sort_order, "ipc_lbr"); 1296 + report.symbol_ipc = true; 1297 + } else { 1298 + snprintf(sort_tmp, sizeof(sort_tmp), "%s,%s", 1299 + sort_order, "ipc_null"); 1300 + } 1301 + 1302 + sort_order = sort_tmp; 1303 + } 1304 + 1289 1305 if (setup_sorting(session->evlist) < 0) { 1290 1306 if (sort_order) 1291 1307 parse_options_usage(report_usage, options, "s", 1); ··· 1331 1311 * so don't allocate extra space that won't be used in the stdio 1332 1312 * implementation. 1333 1313 */ 1334 - if (ui__has_annotation()) { 1314 + if (ui__has_annotation() || report.symbol_ipc) { 1335 1315 ret = symbol__annotation_init(); 1336 1316 if (ret < 0) 1337 1317 goto error;
+1
tools/perf/util/hist.h
··· 62 62 HISTC_TRACE, 63 63 HISTC_SYM_SIZE, 64 64 HISTC_DSO_SIZE, 65 + HISTC_SYMBOL_IPC, 65 66 HISTC_NR_COLS, /* Last entry */ 66 67 }; 67 68
+61
tools/perf/util/sort.c
··· 13 13 #include "strlist.h" 14 14 #include <traceevent/event-parse.h> 15 15 #include "mem-events.h" 16 + #include "annotate.h" 16 17 #include <linux/kernel.h> 17 18 18 19 regex_t parent_regex; ··· 421 420 .se_cmp = sort__srcline_to_cmp, 422 421 .se_snprintf = hist_entry__srcline_to_snprintf, 423 422 .se_width_idx = HISTC_SRCLINE_TO, 423 + }; 424 + 425 + static int hist_entry__sym_ipc_snprintf(struct hist_entry *he, char *bf, 426 + size_t size, unsigned int width) 427 + { 428 + 429 + struct symbol *sym = he->ms.sym; 430 + struct map *map = he->ms.map; 431 + struct perf_evsel *evsel = hists_to_evsel(he->hists); 432 + struct annotation *notes; 433 + double ipc = 0.0, coverage = 0.0; 434 + char tmp[64]; 435 + 436 + if (!sym) 437 + return repsep_snprintf(bf, size, "%-*s", width, "-"); 438 + 439 + if (!sym->annotate2 && symbol__annotate2(sym, map, evsel, 440 + &annotation__default_options, NULL) < 0) { 441 + return 0; 442 + } 443 + 444 + notes = symbol__annotation(sym); 445 + 446 + if (notes->hit_cycles) 447 + ipc = notes->hit_insn / ((double)notes->hit_cycles); 448 + 449 + if (notes->total_insn) { 450 + coverage = notes->cover_insn * 100.0 / 451 + ((double)notes->total_insn); 452 + } 453 + 454 + snprintf(tmp, sizeof(tmp), "%-5.2f [%5.1f%%]", ipc, coverage); 455 + return repsep_snprintf(bf, size, "%-*s", width, tmp); 456 + } 457 + 458 + struct sort_entry sort_sym_ipc = { 459 + .se_header = "IPC [IPC Coverage]", 460 + .se_cmp = sort__sym_cmp, 461 + .se_snprintf = hist_entry__sym_ipc_snprintf, 462 + .se_width_idx = HISTC_SYMBOL_IPC, 463 + }; 464 + 465 + static int hist_entry__sym_ipc_null_snprintf(struct hist_entry *he 466 + __maybe_unused, 467 + char *bf, size_t size, 468 + unsigned int width) 469 + { 470 + char tmp[64]; 471 + 472 + snprintf(tmp, sizeof(tmp), "%-5s %2s", "-", "-"); 473 + return repsep_snprintf(bf, size, "%-*s", width, tmp); 474 + } 475 + 476 + struct sort_entry sort_sym_ipc_null = { 477 + .se_header = "IPC [IPC Coverage]", 478 + .se_cmp = sort__sym_cmp, 479 + .se_snprintf = hist_entry__sym_ipc_null_snprintf, 480 + .se_width_idx = HISTC_SYMBOL_IPC, 424 481 }; 425 482 426 483 /* --sort srcfile */ ··· 1633 1574 DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size), 1634 1575 DIM(SORT_DSO_SIZE, "dso_size", sort_dso_size), 1635 1576 DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id), 1577 + DIM(SORT_SYM_IPC_NULL, "ipc_null", sort_sym_ipc_null), 1636 1578 }; 1637 1579 1638 1580 #undef DIM ··· 1651 1591 DIM(SORT_CYCLES, "cycles", sort_cycles), 1652 1592 DIM(SORT_SRCLINE_FROM, "srcline_from", sort_srcline_from), 1653 1593 DIM(SORT_SRCLINE_TO, "srcline_to", sort_srcline_to), 1594 + DIM(SORT_SYM_IPC, "ipc_lbr", sort_sym_ipc), 1654 1595 }; 1655 1596 1656 1597 #undef DIM
+2
tools/perf/util/sort.h
··· 229 229 SORT_SYM_SIZE, 230 230 SORT_DSO_SIZE, 231 231 SORT_CGROUP_ID, 232 + SORT_SYM_IPC_NULL, 232 233 233 234 /* branch stack specific sort keys */ 234 235 __SORT_BRANCH_STACK, ··· 243 242 SORT_CYCLES, 244 243 SORT_SRCLINE_FROM, 245 244 SORT_SRCLINE_TO, 245 + SORT_SYM_IPC, 246 246 247 247 /* memory mode specific sort keys */ 248 248 __SORT_MEMORY_MODE,