1 #include "util/map_symbol.h"
2 #include "util/branch.h"
3 #include <linux/kernel.h>
5 static bool cross_area(u64 addr1, u64 addr2, int size)
9 align1 = addr1 & ~(size - 1);
10 align2 = addr2 & ~(size - 1);
12 return (align1 != align2) ? true : false;
16 #define AREA_2M (2 * 1024 * 1024)
18 void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags,
21 if (flags->type == PERF_BR_UNKNOWN || from == 0)
24 if (flags->type == PERF_BR_EXTEND_ABI)
25 st->new_counts[flags->new_type]++;
27 st->counts[flags->type]++;
29 if (flags->type == PERF_BR_COND) {
36 if (cross_area(from, to, AREA_2M))
38 else if (cross_area(from, to, AREA_4K))
42 const char *branch_new_type_name(int new_type)
44 const char *branch_new_names[PERF_BR_NEW_MAX] = {
49 * TODO: This switch should happen on 'session->header.env.arch'
50 * instead, because an arm64 platform perf recording could be
51 * opened for analysis on other platforms as well.
68 if (new_type >= 0 && new_type < PERF_BR_NEW_MAX)
69 return branch_new_names[new_type];
74 const char *branch_type_name(int type)
76 const char *branch_names[PERF_BR_MAX] = {
92 "", // Needed for PERF_BR_EXTEND_ABI that ends up triggering some compiler warnings about NULL deref
95 if (type >= 0 && type < PERF_BR_MAX)
96 return branch_names[type];
101 const char *get_branch_type(struct branch_entry *e)
103 if (e->flags.type == PERF_BR_UNKNOWN)
106 if (e->flags.type == PERF_BR_EXTEND_ABI)
107 return branch_new_type_name(e->flags.new_type);
109 return branch_type_name(e->flags.type);
112 void branch_type_stat_display(FILE *fp, const struct branch_type_stat *st)
117 for (i = 0; i < PERF_BR_MAX; i++)
118 total += st->counts[i];
124 fprintf(fp, "\n# Branch Statistics:");
127 if (st->cond_fwd > 0) {
128 fprintf(fp, "\n%8s: %5.1f%%",
130 100.0 * (double)st->cond_fwd / (double)total);
133 if (st->cond_bwd > 0) {
134 fprintf(fp, "\n%8s: %5.1f%%",
136 100.0 * (double)st->cond_bwd / (double)total);
139 if (st->cross_4k > 0) {
140 fprintf(fp, "\n%8s: %5.1f%%",
142 100.0 * (double)st->cross_4k / (double)total);
145 if (st->cross_2m > 0) {
146 fprintf(fp, "\n%8s: %5.1f%%",
148 100.0 * (double)st->cross_2m / (double)total);
151 for (i = 0; i < PERF_BR_MAX; i++) {
152 if (st->counts[i] > 0)
153 fprintf(fp, "\n%8s: %5.1f%%",
156 (double)st->counts[i] / (double)total);
159 for (i = 0; i < PERF_BR_NEW_MAX; i++) {
160 if (st->new_counts[i] > 0)
161 fprintf(fp, "\n%8s: %5.1f%%",
162 branch_new_type_name(i),
164 (double)st->new_counts[i] / (double)total);
169 static int count_str_scnprintf(int idx, const char *str, char *bf, int size)
171 return scnprintf(bf, size, "%s%s", (idx) ? " " : " (", str);
174 int branch_type_str(const struct branch_type_stat *st, char *bf, int size)
176 int i, j = 0, printed = 0;
179 for (i = 0; i < PERF_BR_MAX; i++)
180 total += st->counts[i];
182 for (i = 0; i < PERF_BR_NEW_MAX; i++)
183 total += st->new_counts[i];
188 if (st->cond_fwd > 0)
189 printed += count_str_scnprintf(j++, "COND_FWD", bf + printed, size - printed);
191 if (st->cond_bwd > 0)
192 printed += count_str_scnprintf(j++, "COND_BWD", bf + printed, size - printed);
194 for (i = 0; i < PERF_BR_MAX; i++) {
195 if (i == PERF_BR_COND)
198 if (st->counts[i] > 0)
199 printed += count_str_scnprintf(j++, branch_type_name(i), bf + printed, size - printed);
202 for (i = 0; i < PERF_BR_NEW_MAX; i++) {
203 if (st->new_counts[i] > 0)
204 printed += count_str_scnprintf(j++, branch_new_type_name(i), bf + printed, size - printed);
207 if (st->cross_4k > 0)
208 printed += count_str_scnprintf(j++, "CROSS_4K", bf + printed, size - printed);
210 if (st->cross_2m > 0)
211 printed += count_str_scnprintf(j++, "CROSS_2M", bf + printed, size - printed);
216 const char *branch_spec_desc(int spec)
218 const char *branch_spec_outcomes[PERF_BR_SPEC_MAX] = {
221 "NON_SPEC_CORRECT_PATH",
225 if (spec >= 0 && spec < PERF_BR_SPEC_MAX)
226 return branch_spec_outcomes[spec];