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

perf report: Display columns Predicted/Abort/Cycles in --branch-history

The original commit message:

"
Use current sort mechanism but the real .se_cmp() just returns 0 so
that new columns "Predicted", "Abort" and "Cycles" are created in display
but actually these keys are not the sort keys.

For example:

Overhead Source:Line Symbol Shared Object Predicted Abort Cycles
........ ............ ........ ............. ......... ..... ......

38.25% div.c:45 [.] main div 97.6% 0 3
"

Update missed commit from series "perf report: Show branch flags/cycles
in --branch-history callgraph view" to apply to current repository so that
new columns described above are visible.

Link to original series:
https://lore.kernel.org/lkml/1477876794-30749-1-git-send-email-yao.jin@linux.intel.com/

Reported-by: Dr. David Alan Gilbert <linux@treblig.org>
Suggested-by: Kan Liang <kan.liang@linux.intel.com>
Co-developed-by: Jin Yao <yao.jin@linux.intel.com>
Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Tested-by: Thomas Falcon <thomas.falcon@intel.com>
Signed-off-by: Thomas Falcon <thomas.falcon@intel.com>
Link: https://lore.kernel.org/r/20241010184046.203822-1-thomas.falcon@intel.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Thomas Falcon and committed by
Namhyung Kim
48966a5a 8c25df7a

+134 -2
+8
tools/perf/Documentation/perf-report.txt
··· 391 391 This allows to examine the path the program took to each sample. 392 392 The data collection must have used -b (or -j) and -g. 393 393 394 + Also show with some branch flags that can be: 395 + - Predicted: display the average percentage of predicated branches. 396 + (predicated number / total number) 397 + - Abort: display the number of tsx aborted branches. 398 + - Cycles: cycles in basic block. 399 + 400 + - iterations: display the average number of iterations in callchain list. 401 + 394 402 --addr2line=<path>:: 395 403 Path to addr2line binary. 396 404
+5 -1
tools/perf/builtin-report.c
··· 1271 1271 return 0; 1272 1272 } 1273 1273 1274 + #define CALLCHAIN_BRANCH_SORT_ORDER \ 1275 + "srcline,symbol,dso,callchain_branch_predicted," \ 1276 + "callchain_branch_abort,callchain_branch_cycles" 1277 + 1274 1278 int cmd_report(int argc, const char **argv) 1275 1279 { 1276 1280 struct perf_session *session; ··· 1643 1639 symbol_conf.use_callchain = true; 1644 1640 callchain_register_param(&callchain_param); 1645 1641 if (sort_order == NULL) 1646 - sort_order = "srcline,symbol,dso"; 1642 + sort_order = CALLCHAIN_BRANCH_SORT_ORDER; 1647 1643 } 1648 1644 1649 1645 if (report.mem_mode) {
+3
tools/perf/util/hist.c
··· 218 218 hists__new_col_len(hists, HISTC_LOCAL_P_STAGE_CYC, 13); 219 219 hists__new_col_len(hists, HISTC_GLOBAL_P_STAGE_CYC, 13); 220 220 hists__new_col_len(hists, HISTC_ADDR, BITS_PER_LONG / 4 + 2); 221 + hists__new_col_len(hists, HISTC_CALLCHAIN_BRANCH_PREDICTED, 9); 222 + hists__new_col_len(hists, HISTC_CALLCHAIN_BRANCH_ABORT, 5); 223 + hists__new_col_len(hists, HISTC_CALLCHAIN_BRANCH_CYCLES, 6); 221 224 222 225 if (symbol_conf.nanosecs) 223 226 hists__new_col_len(hists, HISTC_TIME, 16);
+3
tools/perf/util/hist.h
··· 87 87 HISTC_TYPE_OFFSET, 88 88 HISTC_SYMBOL_OFFSET, 89 89 HISTC_TYPE_CACHELINE, 90 + HISTC_CALLCHAIN_BRANCH_PREDICTED, 91 + HISTC_CALLCHAIN_BRANCH_ABORT, 92 + HISTC_CALLCHAIN_BRANCH_CYCLES, 90 93 HISTC_NR_COLS, /* Last entry */ 91 94 }; 92 95
+112 -1
tools/perf/util/sort.c
··· 677 677 .se_width_idx = HISTC_SYMBOL_IPC, 678 678 }; 679 679 680 + /* --sort callchain_branch_predicted */ 681 + 682 + static int64_t 683 + sort__callchain_branch_predicted_cmp(struct hist_entry *left __maybe_unused, 684 + struct hist_entry *right __maybe_unused) 685 + { 686 + return 0; 687 + } 688 + 689 + static int hist_entry__callchain_branch_predicted_snprintf( 690 + struct hist_entry *he, char *bf, size_t size, unsigned int width) 691 + { 692 + u64 branch_count, predicted_count; 693 + double percent = 0.0; 694 + char str[32]; 695 + 696 + callchain_branch_counts(he->callchain, &branch_count, 697 + &predicted_count, NULL, NULL); 698 + 699 + if (branch_count) 700 + percent = predicted_count * 100.0 / branch_count; 701 + 702 + snprintf(str, sizeof(str), "%.1f%%", percent); 703 + return repsep_snprintf(bf, size, "%-*.*s", width, width, str); 704 + } 705 + 706 + struct sort_entry sort_callchain_branch_predicted = { 707 + .se_header = "Predicted", 708 + .se_cmp = sort__callchain_branch_predicted_cmp, 709 + .se_snprintf = hist_entry__callchain_branch_predicted_snprintf, 710 + .se_width_idx = HISTC_CALLCHAIN_BRANCH_PREDICTED, 711 + }; 712 + 713 + /* --sort callchain_branch_abort */ 714 + 715 + static int64_t 716 + sort__callchain_branch_abort_cmp(struct hist_entry *left __maybe_unused, 717 + struct hist_entry *right __maybe_unused) 718 + { 719 + return 0; 720 + } 721 + 722 + static int hist_entry__callchain_branch_abort_snprintf(struct hist_entry *he, 723 + char *bf, size_t size, 724 + unsigned int width) 725 + { 726 + u64 branch_count, abort_count; 727 + char str[32]; 728 + 729 + callchain_branch_counts(he->callchain, &branch_count, 730 + NULL, &abort_count, NULL); 731 + 732 + snprintf(str, sizeof(str), "%" PRId64, abort_count); 733 + return repsep_snprintf(bf, size, "%-*.*s", width, width, str); 734 + } 735 + 736 + struct sort_entry sort_callchain_branch_abort = { 737 + .se_header = "Abort", 738 + .se_cmp = sort__callchain_branch_abort_cmp, 739 + .se_snprintf = hist_entry__callchain_branch_abort_snprintf, 740 + .se_width_idx = HISTC_CALLCHAIN_BRANCH_ABORT, 741 + }; 742 + 743 + /* --sort callchain_branch_cycles */ 744 + 745 + static int64_t 746 + sort__callchain_branch_cycles_cmp(struct hist_entry *left __maybe_unused, 747 + struct hist_entry *right __maybe_unused) 748 + { 749 + return 0; 750 + } 751 + 752 + static int hist_entry__callchain_branch_cycles_snprintf(struct hist_entry *he, 753 + char *bf, size_t size, 754 + unsigned int width) 755 + { 756 + u64 branch_count, cycles_count, cycles = 0; 757 + char str[32]; 758 + 759 + callchain_branch_counts(he->callchain, &branch_count, 760 + NULL, NULL, &cycles_count); 761 + 762 + if (branch_count) 763 + cycles = cycles_count / branch_count; 764 + 765 + snprintf(str, sizeof(str), "%" PRId64 "", cycles); 766 + return repsep_snprintf(bf, size, "%-*.*s", width, width, str); 767 + } 768 + 769 + struct sort_entry sort_callchain_branch_cycles = { 770 + .se_header = "Cycles", 771 + .se_cmp = sort__callchain_branch_cycles_cmp, 772 + .se_snprintf = hist_entry__callchain_branch_cycles_snprintf, 773 + .se_width_idx = HISTC_CALLCHAIN_BRANCH_CYCLES, 774 + }; 775 + 680 776 /* --sort srcfile */ 681 777 682 778 static char no_srcfile[1]; ··· 2552 2456 DIM(SORT_SYM_IPC, "ipc_lbr", sort_sym_ipc), 2553 2457 DIM(SORT_ADDR_FROM, "addr_from", sort_addr_from), 2554 2458 DIM(SORT_ADDR_TO, "addr_to", sort_addr_to), 2459 + DIM(SORT_CALLCHAIN_BRANCH_PREDICTED, 2460 + "callchain_branch_predicted", 2461 + sort_callchain_branch_predicted), 2462 + DIM(SORT_CALLCHAIN_BRANCH_ABORT, 2463 + "callchain_branch_abort", 2464 + sort_callchain_branch_abort), 2465 + DIM(SORT_CALLCHAIN_BRANCH_CYCLES, 2466 + "callchain_branch_cycles", 2467 + sort_callchain_branch_cycles) 2555 2468 }; 2556 2469 2557 2470 #undef DIM ··· 3589 3484 if (!sd->name || strncasecmp(tok, sd->name, strlen(tok))) 3590 3485 continue; 3591 3486 3592 - if (sort__mode != SORT_MODE__BRANCH) 3487 + if ((sort__mode != SORT_MODE__BRANCH) && 3488 + strncasecmp(tok, "callchain_branch_predicted", 3489 + strlen(tok)) && 3490 + strncasecmp(tok, "callchain_branch_abort", 3491 + strlen(tok)) && 3492 + strncasecmp(tok, "callchain_branch_cycles", 3493 + strlen(tok))) 3593 3494 return -EINVAL; 3594 3495 3595 3496 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
+3
tools/perf/util/sort.h
··· 88 88 SORT_SYM_IPC, 89 89 SORT_ADDR_FROM, 90 90 SORT_ADDR_TO, 91 + SORT_CALLCHAIN_BRANCH_PREDICTED, 92 + SORT_CALLCHAIN_BRANCH_ABORT, 93 + SORT_CALLCHAIN_BRANCH_CYCLES, 91 94 92 95 /* memory mode specific sort keys */ 93 96 __SORT_MEMORY_MODE,