brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · ab760e2 Raw
230 lines · c
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		409616#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	else27		st->counts[flags->type]++;28 29	if (flags->type == PERF_BR_COND) {30		if (to > from)31			st->cond_fwd++;32		else33			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 be51 * 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#else60		"ARCH_1",61		"ARCH_2",62		"ARCH_3",63		"ARCH_4",64		"ARCH_5"65#endif66	};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 deref93	};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}230