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
];