xref: /kernel/linux/linux-5.10/tools/perf/util/branch.c (revision 8c2ecf20)
1#include "util/map_symbol.h"
2#include "util/branch.h"
3#include <linux/kernel.h>
4
5static bool cross_area(u64 addr1, u64 addr2, int size)
6{
7	u64 align1, align2;
8
9	align1 = addr1 & ~(size - 1);
10	align2 = addr2 & ~(size - 1);
11
12	return (align1 != align2) ? true : false;
13}
14
15#define AREA_4K		4096
16#define AREA_2M		(2 * 1024 * 1024)
17
18void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags,
19		       u64 from, u64 to)
20{
21	if (flags->type == PERF_BR_UNKNOWN || from == 0)
22		return;
23
24	st->counts[flags->type]++;
25
26	if (flags->type == PERF_BR_COND) {
27		if (to > from)
28			st->cond_fwd++;
29		else
30			st->cond_bwd++;
31	}
32
33	if (cross_area(from, to, AREA_2M))
34		st->cross_2m++;
35	else if (cross_area(from, to, AREA_4K))
36		st->cross_4k++;
37}
38
39const char *branch_type_name(int type)
40{
41	const char *branch_names[PERF_BR_MAX] = {
42		"N/A",
43		"COND",
44		"UNCOND",
45		"IND",
46		"CALL",
47		"IND_CALL",
48		"RET",
49		"SYSCALL",
50		"SYSRET",
51		"COND_CALL",
52		"COND_RET"
53	};
54
55	if (type >= 0 && type < PERF_BR_MAX)
56		return branch_names[type];
57
58	return NULL;
59}
60
61void branch_type_stat_display(FILE *fp, struct branch_type_stat *st)
62{
63	u64 total = 0;
64	int i;
65
66	for (i = 0; i < PERF_BR_MAX; i++)
67		total += st->counts[i];
68
69	if (total == 0)
70		return;
71
72	fprintf(fp, "\n#");
73	fprintf(fp, "\n# Branch Statistics:");
74	fprintf(fp, "\n#");
75
76	if (st->cond_fwd > 0) {
77		fprintf(fp, "\n%8s: %5.1f%%",
78			"COND_FWD",
79			100.0 * (double)st->cond_fwd / (double)total);
80	}
81
82	if (st->cond_bwd > 0) {
83		fprintf(fp, "\n%8s: %5.1f%%",
84			"COND_BWD",
85			100.0 * (double)st->cond_bwd / (double)total);
86	}
87
88	if (st->cross_4k > 0) {
89		fprintf(fp, "\n%8s: %5.1f%%",
90			"CROSS_4K",
91			100.0 * (double)st->cross_4k / (double)total);
92	}
93
94	if (st->cross_2m > 0) {
95		fprintf(fp, "\n%8s: %5.1f%%",
96			"CROSS_2M",
97			100.0 * (double)st->cross_2m / (double)total);
98	}
99
100	for (i = 0; i < PERF_BR_MAX; i++) {
101		if (st->counts[i] > 0)
102			fprintf(fp, "\n%8s: %5.1f%%",
103				branch_type_name(i),
104				100.0 *
105				(double)st->counts[i] / (double)total);
106	}
107}
108
109static int count_str_scnprintf(int idx, const char *str, char *bf, int size)
110{
111	return scnprintf(bf, size, "%s%s", (idx) ? " " : " (", str);
112}
113
114int branch_type_str(struct branch_type_stat *st, char *bf, int size)
115{
116	int i, j = 0, printed = 0;
117	u64 total = 0;
118
119	for (i = 0; i < PERF_BR_MAX; i++)
120		total += st->counts[i];
121
122	if (total == 0)
123		return 0;
124
125	if (st->cond_fwd > 0)
126		printed += count_str_scnprintf(j++, "COND_FWD", bf + printed, size - printed);
127
128	if (st->cond_bwd > 0)
129		printed += count_str_scnprintf(j++, "COND_BWD", bf + printed, size - printed);
130
131	for (i = 0; i < PERF_BR_MAX; i++) {
132		if (i == PERF_BR_COND)
133			continue;
134
135		if (st->counts[i] > 0)
136			printed += count_str_scnprintf(j++, branch_type_name(i), bf + printed, size - printed);
137	}
138
139	if (st->cross_4k > 0)
140		printed += count_str_scnprintf(j++, "CROSS_4K", bf + printed, size - printed);
141
142	if (st->cross_2m > 0)
143		printed += count_str_scnprintf(j++, "CROSS_2M", bf + printed, size - printed);
144
145	return printed;
146}
147