xref: /linux/tools/perf/util/branch.c (revision 6fdcba32711044c35c0e1b094cbd8f3f0b4472c9)
1 #include "util/map_symbol.h"
2 #include "util/branch.h"
3 #include <linux/kernel.h>
4 
5 static 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 
18 void 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 
39 const 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 
61 void 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 
109 static 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 
114 int 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