xref: /kernel/linux/linux-5.10/tools/perf/util/branch.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci#include "util/map_symbol.h"
28c2ecf20Sopenharmony_ci#include "util/branch.h"
38c2ecf20Sopenharmony_ci#include <linux/kernel.h>
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_cistatic bool cross_area(u64 addr1, u64 addr2, int size)
68c2ecf20Sopenharmony_ci{
78c2ecf20Sopenharmony_ci	u64 align1, align2;
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci	align1 = addr1 & ~(size - 1);
108c2ecf20Sopenharmony_ci	align2 = addr2 & ~(size - 1);
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci	return (align1 != align2) ? true : false;
138c2ecf20Sopenharmony_ci}
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define AREA_4K		4096
168c2ecf20Sopenharmony_ci#define AREA_2M		(2 * 1024 * 1024)
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_civoid branch_type_count(struct branch_type_stat *st, struct branch_flags *flags,
198c2ecf20Sopenharmony_ci		       u64 from, u64 to)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	if (flags->type == PERF_BR_UNKNOWN || from == 0)
228c2ecf20Sopenharmony_ci		return;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	st->counts[flags->type]++;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	if (flags->type == PERF_BR_COND) {
278c2ecf20Sopenharmony_ci		if (to > from)
288c2ecf20Sopenharmony_ci			st->cond_fwd++;
298c2ecf20Sopenharmony_ci		else
308c2ecf20Sopenharmony_ci			st->cond_bwd++;
318c2ecf20Sopenharmony_ci	}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	if (cross_area(from, to, AREA_2M))
348c2ecf20Sopenharmony_ci		st->cross_2m++;
358c2ecf20Sopenharmony_ci	else if (cross_area(from, to, AREA_4K))
368c2ecf20Sopenharmony_ci		st->cross_4k++;
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ciconst char *branch_type_name(int type)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	const char *branch_names[PERF_BR_MAX] = {
428c2ecf20Sopenharmony_ci		"N/A",
438c2ecf20Sopenharmony_ci		"COND",
448c2ecf20Sopenharmony_ci		"UNCOND",
458c2ecf20Sopenharmony_ci		"IND",
468c2ecf20Sopenharmony_ci		"CALL",
478c2ecf20Sopenharmony_ci		"IND_CALL",
488c2ecf20Sopenharmony_ci		"RET",
498c2ecf20Sopenharmony_ci		"SYSCALL",
508c2ecf20Sopenharmony_ci		"SYSRET",
518c2ecf20Sopenharmony_ci		"COND_CALL",
528c2ecf20Sopenharmony_ci		"COND_RET"
538c2ecf20Sopenharmony_ci	};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (type >= 0 && type < PERF_BR_MAX)
568c2ecf20Sopenharmony_ci		return branch_names[type];
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	return NULL;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_civoid branch_type_stat_display(FILE *fp, struct branch_type_stat *st)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	u64 total = 0;
648c2ecf20Sopenharmony_ci	int i;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	for (i = 0; i < PERF_BR_MAX; i++)
678c2ecf20Sopenharmony_ci		total += st->counts[i];
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	if (total == 0)
708c2ecf20Sopenharmony_ci		return;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	fprintf(fp, "\n#");
738c2ecf20Sopenharmony_ci	fprintf(fp, "\n# Branch Statistics:");
748c2ecf20Sopenharmony_ci	fprintf(fp, "\n#");
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (st->cond_fwd > 0) {
778c2ecf20Sopenharmony_ci		fprintf(fp, "\n%8s: %5.1f%%",
788c2ecf20Sopenharmony_ci			"COND_FWD",
798c2ecf20Sopenharmony_ci			100.0 * (double)st->cond_fwd / (double)total);
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (st->cond_bwd > 0) {
838c2ecf20Sopenharmony_ci		fprintf(fp, "\n%8s: %5.1f%%",
848c2ecf20Sopenharmony_ci			"COND_BWD",
858c2ecf20Sopenharmony_ci			100.0 * (double)st->cond_bwd / (double)total);
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (st->cross_4k > 0) {
898c2ecf20Sopenharmony_ci		fprintf(fp, "\n%8s: %5.1f%%",
908c2ecf20Sopenharmony_ci			"CROSS_4K",
918c2ecf20Sopenharmony_ci			100.0 * (double)st->cross_4k / (double)total);
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (st->cross_2m > 0) {
958c2ecf20Sopenharmony_ci		fprintf(fp, "\n%8s: %5.1f%%",
968c2ecf20Sopenharmony_ci			"CROSS_2M",
978c2ecf20Sopenharmony_ci			100.0 * (double)st->cross_2m / (double)total);
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	for (i = 0; i < PERF_BR_MAX; i++) {
1018c2ecf20Sopenharmony_ci		if (st->counts[i] > 0)
1028c2ecf20Sopenharmony_ci			fprintf(fp, "\n%8s: %5.1f%%",
1038c2ecf20Sopenharmony_ci				branch_type_name(i),
1048c2ecf20Sopenharmony_ci				100.0 *
1058c2ecf20Sopenharmony_ci				(double)st->counts[i] / (double)total);
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic int count_str_scnprintf(int idx, const char *str, char *bf, int size)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "%s%s", (idx) ? " " : " (", str);
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ciint branch_type_str(struct branch_type_stat *st, char *bf, int size)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	int i, j = 0, printed = 0;
1178c2ecf20Sopenharmony_ci	u64 total = 0;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	for (i = 0; i < PERF_BR_MAX; i++)
1208c2ecf20Sopenharmony_ci		total += st->counts[i];
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	if (total == 0)
1238c2ecf20Sopenharmony_ci		return 0;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (st->cond_fwd > 0)
1268c2ecf20Sopenharmony_ci		printed += count_str_scnprintf(j++, "COND_FWD", bf + printed, size - printed);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	if (st->cond_bwd > 0)
1298c2ecf20Sopenharmony_ci		printed += count_str_scnprintf(j++, "COND_BWD", bf + printed, size - printed);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	for (i = 0; i < PERF_BR_MAX; i++) {
1328c2ecf20Sopenharmony_ci		if (i == PERF_BR_COND)
1338c2ecf20Sopenharmony_ci			continue;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci		if (st->counts[i] > 0)
1368c2ecf20Sopenharmony_ci			printed += count_str_scnprintf(j++, branch_type_name(i), bf + printed, size - printed);
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (st->cross_4k > 0)
1408c2ecf20Sopenharmony_ci		printed += count_str_scnprintf(j++, "CROSS_4K", bf + printed, size - printed);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	if (st->cross_2m > 0)
1438c2ecf20Sopenharmony_ci		printed += count_str_scnprintf(j++, "CROSS_2M", bf + printed, size - printed);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	return printed;
1468c2ecf20Sopenharmony_ci}
147