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

perf annotate: Display the branch counter histogram

Display the branch counter histogram in the annotation view.

Press 'B' to display the branch counter's abbreviation list as well.

Samples: 1M of events 'anon group { branch-instructions:ppp, branch-misses }',
4000 Hz, Event count (approx.):
f3 /home/sdp/test/tchain_edit [Percent: local period]
Percent │ IPC Cycle Branch Counter (Average IPC: 1.39, IPC Coverage: 29.4%)
│ 0000000000401755 <f3>:
0.00 0.00 │ endbr64
│ push %rbp
│ mov %rsp,%rbp
│ movl $0x0,-0x4(%rbp)
0.00 0.00 │1.33 3 |A |- | ↓ jmp 25
11.03 11.03 │ 11: mov -0x4(%rbp),%eax
│ and $0x1,%eax
│ test %eax,%eax
17.13 17.13 │2.41 1 |A |- | ↓ je 21
│ addl $0x1,-0x4(%rbp)
21.84 21.84 │2.22 2 |AA |- | ↓ jmp 25
17.13 17.13 │ 21: addl $0x1,-0x4(%rbp)
21.84 21.84 │ 25: cmpl $0x270f,-0x4(%rbp)
11.03 11.03 │0.61 3 |A |- | ↑ jle 11
│ nop
│ pop %rbp
0.00 0.00 │0.24 20 |AA |B | ← ret

Originally-by: Tinghao Zhang <tinghao.zhang@intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: https://lore.kernel.org/r/20240813160208.2493643-8-kan.liang@linux.intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Kan Liang and committed by
Arnaldo Carvalho de Melo
e6952dce 20d6f555

+74 -9
+7 -3
tools/perf/builtin-annotate.c
··· 927 927 sort_order = "dso,symbol"; 928 928 929 929 /* 930 - * Set SORT_MODE__BRANCH so that annotate display IPC/Cycle 931 - * if branch info is in perf data in TUI mode. 930 + * Set SORT_MODE__BRANCH so that annotate displays IPC/Cycle and 931 + * branch counters, if the corresponding branch info is available 932 + * in the perf data in the TUI mode. 932 933 */ 933 - if ((use_browser == 1 || annotate.use_stdio2) && annotate.has_br_stack) 934 + if ((use_browser == 1 || annotate.use_stdio2) && annotate.has_br_stack) { 934 935 sort__mode = SORT_MODE__BRANCH; 936 + if (annotate.session->evlist->nr_br_cntr > 0) 937 + annotate_opts.show_br_cntr = true; 938 + } 935 939 936 940 if (setup_sorting(NULL) < 0) 937 941 usage_with_options(annotate_usage, options);
+16 -2
tools/perf/ui/browsers/annotate.c
··· 156 156 struct symbol *sym = ms->sym; 157 157 struct annotation *notes = symbol__annotation(sym); 158 158 u8 pcnt_width = annotation__pcnt_width(notes); 159 + u8 cntr_width = annotation__br_cntr_width(); 159 160 int width; 160 161 int diff = 0; 161 162 ··· 206 205 207 206 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); 208 207 __ui_browser__line_arrow(browser, 209 - pcnt_width + 2 + notes->src->widths.addr + width, 208 + pcnt_width + 2 + notes->src->widths.addr + width + cntr_width, 210 209 from, to); 211 210 212 211 diff = is_fused(ab, cursor); 213 212 if (diff > 0) { 214 213 ui_browser__mark_fused(browser, 215 - pcnt_width + 3 + notes->src->widths.addr + width, 214 + pcnt_width + 3 + notes->src->widths.addr + width + cntr_width, 216 215 from - diff, diff, to > from); 217 216 } 218 217 } ··· 715 714 struct annotation *notes = symbol__annotation(ms->sym); 716 715 const char *help = "Press 'h' for help on key bindings"; 717 716 int delay_secs = hbt ? hbt->refresh : 0; 717 + char *br_cntr_text = NULL; 718 718 char title[256]; 719 719 int key; 720 720 ··· 731 729 } 732 730 733 731 nd = browser->curr_hot; 732 + 733 + annotation_br_cntr_abbr_list(&br_cntr_text, evsel, false); 734 734 735 735 while (1) { 736 736 key = ui_browser__run(&browser->b, delay_secs); ··· 800 796 "r Run available scripts\n" 801 797 "p Toggle percent type [local/global]\n" 802 798 "b Toggle percent base [period/hits]\n" 799 + "B Branch counter abbr list (Optional)\n" 803 800 "? Search string backwards\n" 804 801 "f Toggle showing offsets to full address\n"); 805 802 continue; ··· 909 904 hists__scnprintf_title(hists, title, sizeof(title)); 910 905 annotate_browser__show(&browser->b, title, help); 911 906 continue; 907 + case 'B': 908 + if (br_cntr_text) 909 + ui_browser__help_window(&browser->b, br_cntr_text); 910 + else { 911 + ui_browser__help_window(&browser->b, 912 + "\n The branch counter is not available.\n"); 913 + } 914 + continue; 912 915 case 'f': 913 916 annotation__toggle_full_addr(notes, ms); 914 917 continue; ··· 936 923 } 937 924 out: 938 925 ui_browser__hide(&browser->b); 926 + free(br_cntr_text); 939 927 return key; 940 928 } 941 929
+2 -1
tools/perf/ui/browsers/hists.c
··· 3705 3705 3706 3706 memset(&action, 0, sizeof(action)); 3707 3707 3708 - annotation_br_cntr_abbr_list(&br_cntr_text, evsel, false); 3708 + if (!annotation_br_cntr_abbr_list(&br_cntr_text, evsel, false)) 3709 + annotate_opts.show_br_cntr = true; 3709 3710 3710 3711 while (1) { 3711 3712 key = hist_browser__run(browser, "? - help", true, 0);
+37 -3
tools/perf/util/annotate.c
··· 501 501 } 502 502 } 503 503 504 - static int annotation__compute_ipc(struct annotation *notes, size_t size) 504 + static int annotation__compute_ipc(struct annotation *notes, size_t size, 505 + struct evsel *evsel) 505 506 { 507 + unsigned int br_cntr_nr = evsel->evlist->nr_br_cntr; 506 508 int err = 0; 507 509 s64 offset; 508 510 ··· 539 537 al->cycles->max = ch->cycles_max; 540 538 al->cycles->min = ch->cycles_min; 541 539 } 540 + if (al && notes->branch->br_cntr) { 541 + if (!al->br_cntr) { 542 + al->br_cntr = calloc(br_cntr_nr, sizeof(u64)); 543 + if (!al->br_cntr) { 544 + err = ENOMEM; 545 + break; 546 + } 547 + } 548 + al->num_aggr = ch->num_aggr; 549 + al->br_cntr_nr = br_cntr_nr; 550 + al->evsel = evsel; 551 + memcpy(al->br_cntr, &notes->branch->br_cntr[offset * br_cntr_nr], 552 + br_cntr_nr * sizeof(u64)); 553 + } 542 554 } 543 555 } 544 556 ··· 564 548 struct annotation_line *al; 565 549 566 550 al = annotated_source__get_line(notes->src, offset); 567 - if (al) 551 + if (al) { 568 552 zfree(&al->cycles); 553 + zfree(&al->br_cntr); 554 + } 569 555 } 570 556 } 571 557 } ··· 1978 1960 "Cycle(min/max)"); 1979 1961 } 1980 1962 1963 + if (annotate_opts.show_br_cntr) { 1964 + if (show_title) { 1965 + obj__printf(obj, "%*s ", 1966 + ANNOTATION__BR_CNTR_WIDTH, 1967 + "Branch Counter"); 1968 + } else { 1969 + char *buf; 1970 + 1971 + if (!annotation_br_cntr_entry(&buf, al->br_cntr_nr, al->br_cntr, 1972 + al->num_aggr, al->evsel)) { 1973 + obj__printf(obj, "%*s ", ANNOTATION__BR_CNTR_WIDTH, buf); 1974 + free(buf); 1975 + } 1976 + } 1977 + } 1978 + 1981 1979 if (show_title && !*al->line) { 1982 1980 ipc_coverage_string(bf, sizeof(bf), notes); 1983 1981 obj__printf(obj, "%*s", ANNOTATION__AVG_IPC_WIDTH, bf); ··· 2090 2056 annotation__set_index(notes); 2091 2057 annotation__mark_jump_targets(notes, sym); 2092 2058 2093 - err = annotation__compute_ipc(notes, size); 2059 + err = annotation__compute_ipc(notes, size, evsel); 2094 2060 if (err) 2095 2061 return err; 2096 2062
+11
tools/perf/util/annotate.h
··· 31 31 #define ANNOTATION__CYCLES_WIDTH 6 32 32 #define ANNOTATION__MINMAX_CYCLES_WIDTH 19 33 33 #define ANNOTATION__AVG_IPC_WIDTH 36 34 + #define ANNOTATION__BR_CNTR_WIDTH 30 34 35 #define ANNOTATION_DUMMY_LEN 256 35 36 36 37 struct annotation_options { ··· 45 44 show_nr_jumps, 46 45 show_minmax_cycle, 47 46 show_asm_raw, 47 + show_br_cntr, 48 48 annotate_src, 49 49 full_addr; 50 50 u8 offset_level; ··· 106 104 char *fileloc; 107 105 char *path; 108 106 struct cycles_info *cycles; 107 + int num_aggr; 108 + int br_cntr_nr; 109 + u64 *br_cntr; 110 + struct evsel *evsel; 109 111 int jump_sources; 110 112 u32 idx; 111 113 int idx_asm; ··· 357 351 static inline bool annotation_line__filter(struct annotation_line *al) 358 352 { 359 353 return annotate_opts.hide_src_code && al->offset == -1; 354 + } 355 + 356 + static inline u8 annotation__br_cntr_width(void) 357 + { 358 + return annotate_opts.show_br_cntr ? ANNOTATION__BR_CNTR_WIDTH : 0; 360 359 } 361 360 362 361 void annotation__update_column_widths(struct annotation *notes);
+1
tools/perf/util/disasm.c
··· 1015 1015 zfree_srcline(&al->path); 1016 1016 zfree(&al->line); 1017 1017 zfree(&al->cycles); 1018 + zfree(&al->br_cntr); 1018 1019 } 1019 1020 1020 1021 static size_t disasm_line_size(int nr)