Linux Audio

Check our new training course

Loading...
v5.4
  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}
v6.8
  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	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
 42const 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
 74const 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
101const 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
112void branch_type_stat_display(FILE *fp, const 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
169static 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
174int branch_type_str(const 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}
215
216const char *branch_spec_desc(int spec)
217{
218	const char *branch_spec_outcomes[PERF_BR_SPEC_MAX] = {
219		"N/A",
220		"SPEC_WRONG_PATH",
221		"NON_SPEC_CORRECT_PATH",
222		"SPEC_CORRECT_PATH",
223	};
224
225	if (spec >= 0 && spec < PERF_BR_SPEC_MAX)
226		return branch_spec_outcomes[spec];
227
228	return NULL;
229}