Commit fab828ee authored by Anshuman Khandual's avatar Anshuman Khandual Committed by Junhao He
Browse files

perf branch: Extend branch type classification

mainline inclusion
from mainline-v6.1-rc1
commit 0ddea8e2
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8EC9K
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=0ddea8e2a0c20ff32a28ef21574f704d8f4699a2



--------------------------------

This updates the perf tool with generic branch type classification with new
ABI extender place holder i.e PERF_BR_EXTEND_ABI, the new 4 bit branch type
field i.e perf_branch_entry.new_type, new generic page fault related branch
types and some arch specific branch types as added earlier in the kernel.

Committer note:

Add an extra entry to the branch_type_name array to cope with
PERF_BR_EXTEND_ABI, to address build warnings on some compiler/systems,
like:

  75     8.89 ubuntu:20.04-x-powerpc64el    : FAIL gcc version 10.3.0 (Ubuntu 10.3.0-1ubuntu1~20.04)
        inlined from 'branch_type_stat_display' at util/branch.c:152:4:
    /usr/powerpc64le-linux-gnu/include/bits/stdio2.h:100:10: error: '%8s' directive argument is null [-Werror=format-overflow=]
      100 |   return __fprintf_chk (__stream, __USE_FORTIFY_LEVEL - 1, __fmt,
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      101 |    __va_arg_pack ());
          |    ~~~~~~~~~~~~~~~~~

Signed-off-by: default avatarAnshuman Khandual <anshuman.khandual@arm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Link: https://lore.kernel.org/r/20220824044822.70230-7-anshuman.khandual@arm.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarJunhao He <hejunhao3@huawei.com>
parent 388dd1cc
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -239,9 +239,22 @@ enum {
	PERF_BR_IRQ		= 12,	/* irq */
	PERF_BR_SERROR		= 13,	/* system error */
	PERF_BR_NO_TX		= 14,	/* not in transaction */
	PERF_BR_EXTEND_ABI	= 15,	/* extend ABI */
	PERF_BR_MAX,
};

enum {
	PERF_BR_NEW_FAULT_ALGN		= 0,    /* Alignment fault */
	PERF_BR_NEW_FAULT_DATA		= 1,    /* Data fault */
	PERF_BR_NEW_FAULT_INST		= 2,    /* Inst fault */
	PERF_BR_NEW_ARCH_1		= 3,    /* Architecture specific */
	PERF_BR_NEW_ARCH_2		= 4,    /* Architecture specific */
	PERF_BR_NEW_ARCH_3		= 5,    /* Architecture specific */
	PERF_BR_NEW_ARCH_4		= 6,    /* Architecture specific */
	PERF_BR_NEW_ARCH_5		= 7,    /* Architecture specific */
	PERF_BR_NEW_MAX,
};

#define PERF_SAMPLE_BRANCH_PLM_ALL \
	(PERF_SAMPLE_BRANCH_USER|\
	 PERF_SAMPLE_BRANCH_KERNEL|\
@@ -1288,7 +1301,8 @@ struct perf_branch_entry {
		abort:1,    /* transaction abort */
		cycles:16,  /* cycle count to last branch */
		type:4,     /* branch type */
		reserved:40;
		new_type:4, /* additional branch type */
		reserved:36;
};

union perf_sample_weight {
+1 −1
Original line number Diff line number Diff line
@@ -821,7 +821,7 @@ static int print_bstack_flags(FILE *fp, struct branch_entry *br)
		       br->flags.in_tx ? 'X' : '-',
		       br->flags.abort ? 'A' : '-',
		       br->flags.cycles,
		       br->flags.type ? branch_type_name(br->flags.type) : "-");
		       get_branch_type(br));
}

static int perf_sample__fprintf_brstack(struct perf_sample *sample,
+53 −2
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags,
	if (flags->type == PERF_BR_UNKNOWN || from == 0)
		return;

	if (flags->type == PERF_BR_EXTEND_ABI)
		st->new_counts[flags->new_type]++;
	else
		st->counts[flags->type]++;

	if (flags->type == PERF_BR_COND) {
@@ -36,6 +39,25 @@ void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags,
		st->cross_4k++;
}

const char *branch_new_type_name(int new_type)
{
	const char *branch_new_names[PERF_BR_NEW_MAX] = {
		"FAULT_ALGN",
		"FAULT_DATA",
		"FAULT_INST",
		"ARCH_1",
		"ARCH_2",
		"ARCH_3",
		"ARCH_4",
		"ARCH_5"
	};

	if (new_type >= 0 && new_type < PERF_BR_NEW_MAX)
		return branch_new_names[new_type];

	return NULL;
}

const char *branch_type_name(int type)
{
	const char *branch_names[PERF_BR_MAX] = {
@@ -53,7 +75,8 @@ const char *branch_type_name(int type)
		"ERET",
		"IRQ",
		"SERROR",
		"NO_TX"
		"NO_TX",
		"", // Needed for PERF_BR_EXTEND_ABI that ends up triggering some compiler warnings about NULL deref
	};

	if (type >= 0 && type < PERF_BR_MAX)
@@ -62,6 +85,17 @@ const char *branch_type_name(int type)
	return NULL;
}

const char *get_branch_type(struct branch_entry *e)
{
	if (e->flags.type == PERF_BR_UNKNOWN)
		return "";

	if (e->flags.type == PERF_BR_EXTEND_ABI)
		return branch_new_type_name(e->flags.new_type);

	return branch_type_name(e->flags.type);
}

void branch_type_stat_display(FILE *fp, struct branch_type_stat *st)
{
	u64 total = 0;
@@ -108,6 +142,15 @@ void branch_type_stat_display(FILE *fp, struct branch_type_stat *st)
				100.0 *
				(double)st->counts[i] / (double)total);
	}

	for (i = 0; i < PERF_BR_NEW_MAX; i++) {
		if (st->new_counts[i] > 0)
			fprintf(fp, "\n%8s: %5.1f%%",
				branch_new_type_name(i),
				100.0 *
				(double)st->new_counts[i] / (double)total);
	}

}

static int count_str_scnprintf(int idx, const char *str, char *bf, int size)
@@ -123,6 +166,9 @@ int branch_type_str(struct branch_type_stat *st, char *bf, int size)
	for (i = 0; i < PERF_BR_MAX; i++)
		total += st->counts[i];

	for (i = 0; i < PERF_BR_NEW_MAX; i++)
		total += st->new_counts[i];

	if (total == 0)
		return 0;

@@ -140,6 +186,11 @@ int branch_type_str(struct branch_type_stat *st, char *bf, int size)
			printed += count_str_scnprintf(j++, branch_type_name(i), bf + printed, size - printed);
	}

	for (i = 0; i < PERF_BR_NEW_MAX; i++) {
		if (st->new_counts[i] > 0)
			printed += count_str_scnprintf(j++, branch_new_type_name(i), bf + printed, size - printed);
	}

	if (st->cross_4k > 0)
		printed += count_str_scnprintf(j++, "CROSS_4K", bf + printed, size - printed);

+5 −1
Original line number Diff line number Diff line
@@ -24,7 +24,8 @@ struct branch_flags {
			u64 abort:1;
			u64 cycles:16;
			u64 type:4;
			u64 reserved:40;
			u64 new_type:4;
			u64 reserved:36;
		};
	};
};
@@ -72,6 +73,7 @@ static inline struct branch_entry *perf_sample__branch_entries(struct perf_sampl
struct branch_type_stat {
	bool	branch_to;
	u64	counts[PERF_BR_MAX];
	u64	new_counts[PERF_BR_NEW_MAX];
	u64	cond_fwd;
	u64	cond_bwd;
	u64	cross_4k;
@@ -82,6 +84,8 @@ void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags,
		       u64 from, u64 to);

const char *branch_type_name(int type);
const char *branch_new_type_name(int new_type);
const char *get_branch_type(struct branch_entry *e);
void branch_type_stat_display(FILE *fp, struct branch_type_stat *st);
int branch_type_str(struct branch_type_stat *st, char *bf, int bfsize);

+1 −1
Original line number Diff line number Diff line
@@ -1137,7 +1137,7 @@ static void branch_stack__printf(struct perf_sample *sample, bool callstack)
				e->flags.abort ? "A" : " ",
				e->flags.in_tx ? "T" : " ",
				(unsigned)e->flags.reserved,
				e->flags.type ? branch_type_name(e->flags.type) : "");
				get_branch_type(e));
		} else {
			printf("..... %2"PRIu64": %016" PRIx64 "\n",
				i, i > 0 ? e->from : e->to);