Merge branches 'acpi-scan', 'acpi-resource', 'acpi-apei', 'acpi-extlog' and 'acpi...
[sfrench/cifs-2.6.git] / tools / perf / util / branch.c
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         if (flags->type == PERF_BR_EXTEND_ABI)
25                 st->new_counts[flags->new_type]++;
26         else
27                 st->counts[flags->type]++;
28
29         if (flags->type == PERF_BR_COND) {
30                 if (to > from)
31                         st->cond_fwd++;
32                 else
33                         st->cond_bwd++;
34         }
35
36         if (cross_area(from, to, AREA_2M))
37                 st->cross_2m++;
38         else if (cross_area(from, to, AREA_4K))
39                 st->cross_4k++;
40 }
41
42 const char *branch_new_type_name(int new_type)
43 {
44         const char *branch_new_names[PERF_BR_NEW_MAX] = {
45                 "FAULT_ALGN",
46                 "FAULT_DATA",
47                 "FAULT_INST",
48 /*
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.
52  */
53 #ifdef __aarch64__
54                 "ARM64_FIQ",
55                 "ARM64_DEBUG_HALT",
56                 "ARM64_DEBUG_EXIT",
57                 "ARM64_DEBUG_INST",
58                 "ARM64_DEBUG_DATA"
59 #else
60                 "ARCH_1",
61                 "ARCH_2",
62                 "ARCH_3",
63                 "ARCH_4",
64                 "ARCH_5"
65 #endif
66         };
67
68         if (new_type >= 0 && new_type < PERF_BR_NEW_MAX)
69                 return branch_new_names[new_type];
70
71         return NULL;
72 }
73
74 const char *branch_type_name(int type)
75 {
76         const char *branch_names[PERF_BR_MAX] = {
77                 "N/A",
78                 "COND",
79                 "UNCOND",
80                 "IND",
81                 "CALL",
82                 "IND_CALL",
83                 "RET",
84                 "SYSCALL",
85                 "SYSRET",
86                 "COND_CALL",
87                 "COND_RET",
88                 "ERET",
89                 "IRQ",
90                 "SERROR",
91                 "NO_TX",
92                 "", // Needed for PERF_BR_EXTEND_ABI that ends up triggering some compiler warnings about NULL deref
93         };
94
95         if (type >= 0 && type < PERF_BR_MAX)
96                 return branch_names[type];
97
98         return NULL;
99 }
100
101 const char *get_branch_type(struct branch_entry *e)
102 {
103         if (e->flags.type == PERF_BR_UNKNOWN)
104                 return "";
105
106         if (e->flags.type == PERF_BR_EXTEND_ABI)
107                 return branch_new_type_name(e->flags.new_type);
108
109         return branch_type_name(e->flags.type);
110 }
111
112 void branch_type_stat_display(FILE *fp, struct branch_type_stat *st)
113 {
114         u64 total = 0;
115         int i;
116
117         for (i = 0; i < PERF_BR_MAX; i++)
118                 total += st->counts[i];
119
120         if (total == 0)
121                 return;
122
123         fprintf(fp, "\n#");
124         fprintf(fp, "\n# Branch Statistics:");
125         fprintf(fp, "\n#");
126
127         if (st->cond_fwd > 0) {
128                 fprintf(fp, "\n%8s: %5.1f%%",
129                         "COND_FWD",
130                         100.0 * (double)st->cond_fwd / (double)total);
131         }
132
133         if (st->cond_bwd > 0) {
134                 fprintf(fp, "\n%8s: %5.1f%%",
135                         "COND_BWD",
136                         100.0 * (double)st->cond_bwd / (double)total);
137         }
138
139         if (st->cross_4k > 0) {
140                 fprintf(fp, "\n%8s: %5.1f%%",
141                         "CROSS_4K",
142                         100.0 * (double)st->cross_4k / (double)total);
143         }
144
145         if (st->cross_2m > 0) {
146                 fprintf(fp, "\n%8s: %5.1f%%",
147                         "CROSS_2M",
148                         100.0 * (double)st->cross_2m / (double)total);
149         }
150
151         for (i = 0; i < PERF_BR_MAX; i++) {
152                 if (st->counts[i] > 0)
153                         fprintf(fp, "\n%8s: %5.1f%%",
154                                 branch_type_name(i),
155                                 100.0 *
156                                 (double)st->counts[i] / (double)total);
157         }
158
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),
163                                 100.0 *
164                                 (double)st->new_counts[i] / (double)total);
165         }
166
167 }
168
169 static int count_str_scnprintf(int idx, const char *str, char *bf, int size)
170 {
171         return scnprintf(bf, size, "%s%s", (idx) ? " " : " (", str);
172 }
173
174 int branch_type_str(struct branch_type_stat *st, char *bf, int size)
175 {
176         int i, j = 0, printed = 0;
177         u64 total = 0;
178
179         for (i = 0; i < PERF_BR_MAX; i++)
180                 total += st->counts[i];
181
182         for (i = 0; i < PERF_BR_NEW_MAX; i++)
183                 total += st->new_counts[i];
184
185         if (total == 0)
186                 return 0;
187
188         if (st->cond_fwd > 0)
189                 printed += count_str_scnprintf(j++, "COND_FWD", bf + printed, size - printed);
190
191         if (st->cond_bwd > 0)
192                 printed += count_str_scnprintf(j++, "COND_BWD", bf + printed, size - printed);
193
194         for (i = 0; i < PERF_BR_MAX; i++) {
195                 if (i == PERF_BR_COND)
196                         continue;
197
198                 if (st->counts[i] > 0)
199                         printed += count_str_scnprintf(j++, branch_type_name(i), bf + printed, size - printed);
200         }
201
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);
205         }
206
207         if (st->cross_4k > 0)
208                 printed += count_str_scnprintf(j++, "CROSS_4K", bf + printed, size - printed);
209
210         if (st->cross_2m > 0)
211                 printed += count_str_scnprintf(j++, "CROSS_2M", bf + printed, size - printed);
212
213         return printed;
214 }