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

perf report: Add srcline_from/to branch sort keys

Add "srcline_from" and "srcline_to" branch sort keys that allow to show
the source lines of a branch.

That makes it much easier to track down where particular branches happen
in the program, for example to examine branch mispredictions, or to
associate it with cycle counts:

% perf record -b -e cycles:p ./tcall
% perf report --sort srcline_from,srcline_to,mispredict
...
15.10% tcall.c:18 tcall.c:10 N
14.83% tcall.c:11 tcall.c:5 N
14.12% tcall.c:7 tcall.c:12 N
14.04% tcall.c:12 tcall.c:5 N
12.42% tcall.c:17 tcall.c:18 N
12.39% tcall.c:7 tcall.c:13 N
12.27% tcall.c:13 tcall.c:17 N
...

% perf report --sort srcline_from,srcline_to,cycles
...
17.12% tcall.c:18 tcall.c:11 1
17.01% tcall.c:12 tcall.c:6 1
16.98% tcall.c:11 tcall.c:6 1
15.91% tcall.c:17 tcall.c:18 1
6.38% tcall.c:7 tcall.c:17 7
4.80% tcall.c:7 tcall.c:12 8
4.21% tcall.c:7 tcall.c:17 8
2.67% tcall.c:7 tcall.c:12 7
2.62% tcall.c:7 tcall.c:12 10
2.10% tcall.c:7 tcall.c:17 9
1.58% tcall.c:7 tcall.c:12 6
1.44% tcall.c:7 tcall.c:12 5
1.38% tcall.c:7 tcall.c:12 9
1.06% tcall.c:7 tcall.c:17 13
1.05% tcall.c:7 tcall.c:12 4
1.01% tcall.c:7 tcall.c:17 6

Open issues:

- Some kernel symbols get misresolved.

Signed-off-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/r/1463775308-32748-1-git-send-email-andi@firstfloor.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Andi Kleen and committed by
Arnaldo Carvalho de Melo
508be0df d4c6fb36

+101 -1
+2 -1
tools/perf/Documentation/perf-report.txt
··· 103 103 104 104 If --branch-stack option is used, following sort keys are also 105 105 available: 106 - dso_from, dso_to, symbol_from, symbol_to, mispredict. 107 106 108 107 - dso_from: name of library or module branched from 109 108 - dso_to: name of library or module branched to 110 109 - symbol_from: name of function branched from 111 110 - symbol_to: name of function branched to 111 + - srcline_from: source file and line branched from 112 + - srcline_to: source file and line branched to 112 113 - mispredict: "N" for predicted branch, "Y" for mispredicted branch 113 114 - in_tx: branch in TSX transaction 114 115 - abort: TSX transaction abort.
+9
tools/perf/util/hist.c
··· 117 117 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen); 118 118 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO); 119 119 } 120 + 121 + if (h->branch_info->srcline_from) 122 + hists__new_col_len(hists, HISTC_SRCLINE_FROM, 123 + strlen(h->branch_info->srcline_from)); 124 + if (h->branch_info->srcline_to) 125 + hists__new_col_len(hists, HISTC_SRCLINE_TO, 126 + strlen(h->branch_info->srcline_to)); 120 127 } 121 128 122 129 if (h->mem_info) { ··· 1049 1042 if (he->branch_info) { 1050 1043 map__zput(he->branch_info->from.map); 1051 1044 map__zput(he->branch_info->to.map); 1045 + free_srcline(he->branch_info->srcline_from); 1046 + free_srcline(he->branch_info->srcline_to); 1052 1047 zfree(&he->branch_info); 1053 1048 } 1054 1049
+2
tools/perf/util/hist.h
··· 52 52 HISTC_MEM_IADDR_SYMBOL, 53 53 HISTC_TRANSACTION, 54 54 HISTC_CYCLES, 55 + HISTC_SRCLINE_FROM, 56 + HISTC_SRCLINE_TO, 55 57 HISTC_TRACE, 56 58 HISTC_NR_COLS, /* Last entry */ 57 59 };
+84
tools/perf/util/sort.c
··· 353 353 .se_width_idx = HISTC_SRCLINE, 354 354 }; 355 355 356 + /* --sort srcline_from */ 357 + 358 + static int64_t 359 + sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) 360 + { 361 + if (!left->branch_info->srcline_from) { 362 + struct map *map = left->branch_info->from.map; 363 + if (!map) 364 + left->branch_info->srcline_from = SRCLINE_UNKNOWN; 365 + else 366 + left->branch_info->srcline_from = get_srcline(map->dso, 367 + map__rip_2objdump(map, 368 + left->branch_info->from.al_addr), 369 + left->branch_info->from.sym, true); 370 + } 371 + if (!right->branch_info->srcline_from) { 372 + struct map *map = right->branch_info->from.map; 373 + if (!map) 374 + right->branch_info->srcline_from = SRCLINE_UNKNOWN; 375 + else 376 + right->branch_info->srcline_from = get_srcline(map->dso, 377 + map__rip_2objdump(map, 378 + right->branch_info->from.al_addr), 379 + right->branch_info->from.sym, true); 380 + } 381 + return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from); 382 + } 383 + 384 + static int hist_entry__srcline_from_snprintf(struct hist_entry *he, char *bf, 385 + size_t size, unsigned int width) 386 + { 387 + return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_from); 388 + } 389 + 390 + struct sort_entry sort_srcline_from = { 391 + .se_header = "From Source:Line", 392 + .se_cmp = sort__srcline_from_cmp, 393 + .se_snprintf = hist_entry__srcline_from_snprintf, 394 + .se_width_idx = HISTC_SRCLINE_FROM, 395 + }; 396 + 397 + /* --sort srcline_to */ 398 + 399 + static int64_t 400 + sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) 401 + { 402 + if (!left->branch_info->srcline_to) { 403 + struct map *map = left->branch_info->to.map; 404 + if (!map) 405 + left->branch_info->srcline_to = SRCLINE_UNKNOWN; 406 + else 407 + left->branch_info->srcline_to = get_srcline(map->dso, 408 + map__rip_2objdump(map, 409 + left->branch_info->to.al_addr), 410 + left->branch_info->from.sym, true); 411 + } 412 + if (!right->branch_info->srcline_to) { 413 + struct map *map = right->branch_info->to.map; 414 + if (!map) 415 + right->branch_info->srcline_to = SRCLINE_UNKNOWN; 416 + else 417 + right->branch_info->srcline_to = get_srcline(map->dso, 418 + map__rip_2objdump(map, 419 + right->branch_info->to.al_addr), 420 + right->branch_info->to.sym, true); 421 + } 422 + return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to); 423 + } 424 + 425 + static int hist_entry__srcline_to_snprintf(struct hist_entry *he, char *bf, 426 + size_t size, unsigned int width) 427 + { 428 + return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_to); 429 + } 430 + 431 + struct sort_entry sort_srcline_to = { 432 + .se_header = "To Source:Line", 433 + .se_cmp = sort__srcline_to_cmp, 434 + .se_snprintf = hist_entry__srcline_to_snprintf, 435 + .se_width_idx = HISTC_SRCLINE_TO, 436 + }; 437 + 356 438 /* --sort srcfile */ 357 439 358 440 static char no_srcfile[1]; ··· 1429 1347 DIM(SORT_IN_TX, "in_tx", sort_in_tx), 1430 1348 DIM(SORT_ABORT, "abort", sort_abort), 1431 1349 DIM(SORT_CYCLES, "cycles", sort_cycles), 1350 + DIM(SORT_SRCLINE_FROM, "srcline_from", sort_srcline_from), 1351 + DIM(SORT_SRCLINE_TO, "srcline_to", sort_srcline_to), 1432 1352 }; 1433 1353 1434 1354 #undef DIM
+2
tools/perf/util/sort.h
··· 215 215 SORT_ABORT, 216 216 SORT_IN_TX, 217 217 SORT_CYCLES, 218 + SORT_SRCLINE_FROM, 219 + SORT_SRCLINE_TO, 218 220 219 221 /* memory mode specific sort keys */ 220 222 __SORT_MEMORY_MODE,
+2
tools/perf/util/symbol.h
··· 186 186 struct addr_map_symbol from; 187 187 struct addr_map_symbol to; 188 188 struct branch_flags flags; 189 + char *srcline_from; 190 + char *srcline_to; 189 191 }; 190 192 191 193 struct mem_info {