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

perf branch: Extend branch type classification

This updates the perf tool with generic branch type classification with new
ABI extender place holder i.e PERF_BR_EXTEND_ABI, the new 4 bit branch type
field i.e perf_branch_entry.new_type, new generic page fault related branch
types and some arch specific branch types as added earlier in the kernel.

Committer note:

Add an extra entry to the branch_type_name array to cope with
PERF_BR_EXTEND_ABI, to address build warnings on some compiler/systems,
like:

75 8.89 ubuntu:20.04-x-powerpc64el : FAIL gcc version 10.3.0 (Ubuntu 10.3.0-1ubuntu1~20.04)
inlined from 'branch_type_stat_display' at util/branch.c:152:4:
/usr/powerpc64le-linux-gnu/include/bits/stdio2.h:100:10: error: '%8s' directive argument is null [-Werror=format-overflow=]
100 | return __fprintf_chk (__stream, __USE_FORTIFY_LEVEL - 1, __fmt,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
101 | __va_arg_pack ());
| ~~~~~~~~~~~~~~~~~

Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Link: https://lore.kernel.org/r/20220824044822.70230-7-anshuman.khandual@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Anshuman Khandual and committed by
Arnaldo Carvalho de Melo
0ddea8e2 1c96b6e4

+75 -6
+15 -1
tools/include/uapi/linux/perf_event.h
··· 255 255 PERF_BR_IRQ = 12, /* irq */ 256 256 PERF_BR_SERROR = 13, /* system error */ 257 257 PERF_BR_NO_TX = 14, /* not in transaction */ 258 + PERF_BR_EXTEND_ABI = 15, /* extend ABI */ 258 259 PERF_BR_MAX, 260 + }; 261 + 262 + enum { 263 + PERF_BR_NEW_FAULT_ALGN = 0, /* Alignment fault */ 264 + PERF_BR_NEW_FAULT_DATA = 1, /* Data fault */ 265 + PERF_BR_NEW_FAULT_INST = 2, /* Inst fault */ 266 + PERF_BR_NEW_ARCH_1 = 3, /* Architecture specific */ 267 + PERF_BR_NEW_ARCH_2 = 4, /* Architecture specific */ 268 + PERF_BR_NEW_ARCH_3 = 5, /* Architecture specific */ 269 + PERF_BR_NEW_ARCH_4 = 6, /* Architecture specific */ 270 + PERF_BR_NEW_ARCH_5 = 7, /* Architecture specific */ 271 + PERF_BR_NEW_MAX, 259 272 }; 260 273 261 274 #define PERF_SAMPLE_BRANCH_PLM_ALL \ ··· 1388 1375 abort:1, /* transaction abort */ 1389 1376 cycles:16, /* cycle count to last branch */ 1390 1377 type:4, /* branch type */ 1391 - reserved:40; 1378 + new_type:4, /* additional branch type */ 1379 + reserved:36; 1392 1380 }; 1393 1381 1394 1382 union perf_sample_weight {
+1 -1
tools/perf/builtin-script.c
··· 882 882 br->flags.in_tx ? 'X' : '-', 883 883 br->flags.abort ? 'A' : '-', 884 884 br->flags.cycles, 885 - br->flags.type ? branch_type_name(br->flags.type) : "-"); 885 + get_branch_type(br)); 886 886 } 887 887 888 888 static int perf_sample__fprintf_brstack(struct perf_sample *sample,
+53 -2
tools/perf/util/branch.c
··· 21 21 if (flags->type == PERF_BR_UNKNOWN || from == 0) 22 22 return; 23 23 24 - st->counts[flags->type]++; 24 + if (flags->type == PERF_BR_EXTEND_ABI) 25 + st->new_counts[flags->new_type]++; 26 + else 27 + st->counts[flags->type]++; 25 28 26 29 if (flags->type == PERF_BR_COND) { 27 30 if (to > from) ··· 37 34 st->cross_2m++; 38 35 else if (cross_area(from, to, AREA_4K)) 39 36 st->cross_4k++; 37 + } 38 + 39 + const char *branch_new_type_name(int new_type) 40 + { 41 + const char *branch_new_names[PERF_BR_NEW_MAX] = { 42 + "FAULT_ALGN", 43 + "FAULT_DATA", 44 + "FAULT_INST", 45 + "ARCH_1", 46 + "ARCH_2", 47 + "ARCH_3", 48 + "ARCH_4", 49 + "ARCH_5" 50 + }; 51 + 52 + if (new_type >= 0 && new_type < PERF_BR_NEW_MAX) 53 + return branch_new_names[new_type]; 54 + 55 + return NULL; 40 56 } 41 57 42 58 const char *branch_type_name(int type) ··· 75 53 "ERET", 76 54 "IRQ", 77 55 "SERROR", 78 - "NO_TX" 56 + "NO_TX", 57 + "", // Needed for PERF_BR_EXTEND_ABI that ends up triggering some compiler warnings about NULL deref 79 58 }; 80 59 81 60 if (type >= 0 && type < PERF_BR_MAX) 82 61 return branch_names[type]; 83 62 84 63 return NULL; 64 + } 65 + 66 + const char *get_branch_type(struct branch_entry *e) 67 + { 68 + if (e->flags.type == PERF_BR_UNKNOWN) 69 + return ""; 70 + 71 + if (e->flags.type == PERF_BR_EXTEND_ABI) 72 + return branch_new_type_name(e->flags.new_type); 73 + 74 + return branch_type_name(e->flags.type); 85 75 } 86 76 87 77 void branch_type_stat_display(FILE *fp, struct branch_type_stat *st) ··· 142 108 100.0 * 143 109 (double)st->counts[i] / (double)total); 144 110 } 111 + 112 + for (i = 0; i < PERF_BR_NEW_MAX; i++) { 113 + if (st->new_counts[i] > 0) 114 + fprintf(fp, "\n%8s: %5.1f%%", 115 + branch_new_type_name(i), 116 + 100.0 * 117 + (double)st->new_counts[i] / (double)total); 118 + } 119 + 145 120 } 146 121 147 122 static int count_str_scnprintf(int idx, const char *str, char *bf, int size) ··· 165 122 166 123 for (i = 0; i < PERF_BR_MAX; i++) 167 124 total += st->counts[i]; 125 + 126 + for (i = 0; i < PERF_BR_NEW_MAX; i++) 127 + total += st->new_counts[i]; 168 128 169 129 if (total == 0) 170 130 return 0; ··· 184 138 185 139 if (st->counts[i] > 0) 186 140 printed += count_str_scnprintf(j++, branch_type_name(i), bf + printed, size - printed); 141 + } 142 + 143 + for (i = 0; i < PERF_BR_NEW_MAX; i++) { 144 + if (st->new_counts[i] > 0) 145 + printed += count_str_scnprintf(j++, branch_new_type_name(i), bf + printed, size - printed); 187 146 } 188 147 189 148 if (st->cross_4k > 0)
+5 -1
tools/perf/util/branch.h
··· 24 24 u64 abort:1; 25 25 u64 cycles:16; 26 26 u64 type:4; 27 - u64 reserved:40; 27 + u64 new_type:4; 28 + u64 reserved:36; 28 29 }; 29 30 }; 30 31 }; ··· 73 72 struct branch_type_stat { 74 73 bool branch_to; 75 74 u64 counts[PERF_BR_MAX]; 75 + u64 new_counts[PERF_BR_NEW_MAX]; 76 76 u64 cond_fwd; 77 77 u64 cond_bwd; 78 78 u64 cross_4k; ··· 84 82 u64 from, u64 to); 85 83 86 84 const char *branch_type_name(int type); 85 + const char *branch_new_type_name(int new_type); 86 + const char *get_branch_type(struct branch_entry *e); 87 87 void branch_type_stat_display(FILE *fp, struct branch_type_stat *st); 88 88 int branch_type_str(struct branch_type_stat *st, char *bf, int bfsize); 89 89
+1 -1
tools/perf/util/session.c
··· 1180 1180 e->flags.abort ? "A" : " ", 1181 1181 e->flags.in_tx ? "T" : " ", 1182 1182 (unsigned)e->flags.reserved, 1183 - e->flags.type ? branch_type_name(e->flags.type) : ""); 1183 + get_branch_type(e)); 1184 1184 } else { 1185 1185 if (i == 0) { 1186 1186 printf("..... %2"PRIu64": %016" PRIx64 "\n"