[PATCH V6 6/8] perf/tools: Extend branch type classification

German Gomez german.gomez at arm.com
Tue Jun 14 09:53:59 PDT 2022


Hi Anshuman,

On 10/06/2022 04:50, Anshuman Khandual wrote:
> 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.
>
> Cc: Peter Zijlstra <peterz at infradead.org>
> Cc: Ingo Molnar <mingo at redhat.com>
> Cc: Arnaldo Carvalho de Melo <acme at kernel.org>
> Cc: Mark Rutland <mark.rutland at arm.com>
> Cc: Alexander Shishkin <alexander.shishkin at linux.intel.com>
> Cc: Jiri Olsa <jolsa at redhat.com>
> Cc: Namhyung Kim <namhyung at kernel.org>
> Cc: Thomas Gleixner <tglx at linutronix.de>
> Cc: Will Deacon <will at kernel.org>
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-perf-users at vger.kernel.org
> Cc: linux-kernel at vger.kernel.org
> Signed-off-by: Anshuman Khandual <anshuman.khandual at arm.com>
> ---
>  tools/include/uapi/linux/perf_event.h | 16 ++++++++-
>  tools/perf/builtin-script.c           |  2 +-
>  tools/perf/util/branch.c              | 52 ++++++++++++++++++++++++++-
>  tools/perf/util/branch.h              |  6 +++-
>  tools/perf/util/session.c             |  2 +-
>  5 files changed, 73 insertions(+), 5 deletions(-)
>
> diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
> index 26d8f0b5ac0d..d29280adc3c4 100644
> --- a/tools/include/uapi/linux/perf_event.h
> +++ b/tools/include/uapi/linux/perf_event.h
> @@ -255,9 +255,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|\
> @@ -1372,7 +1385,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 {
> diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
> index c689054002cc..d4d581230f23 100644
> --- a/tools/perf/builtin-script.c
> +++ b/tools/perf/builtin-script.c
> @@ -866,7 +866,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));

(Small comment below regarding this line)

>  }
>  
>  static int perf_sample__fprintf_brstack(struct perf_sample *sample,
> diff --git a/tools/perf/util/branch.c b/tools/perf/util/branch.c
> index abc673347bee..6d962b0a4532 100644
> --- a/tools/perf/util/branch.c
> +++ b/tools/perf/util/branch.c
> @@ -21,7 +21,10 @@ void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags,
>  	if (flags->type == PERF_BR_UNKNOWN || from == 0)
>  		return;
>  
> -	st->counts[flags->type]++;
> +	if (flags->type == PERF_BR_EXTEND_ABI)
> +		st->new_counts[flags->new_type]++;
> +	else
> +		st->counts[flags->type]++;
>  
>  	if (flags->type == PERF_BR_COND) {
>  		if (to > from)
> @@ -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] = {
> @@ -62,6 +84,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 "";

There is a small change of behavior in "perf script --field brstack".
Unknown branches were printed as "-" before but now it's an empty
string.

> +
> +	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 +141,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 +165,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 +185,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);
>  
> diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h
> index 17b2ccc61094..8d251b35428a 100644
> --- a/tools/perf/util/branch.h
> +++ b/tools/perf/util/branch.h
> @@ -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);
>  
> diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
> index 0aa818977d2b..136fa03364ab 100644
> --- a/tools/perf/util/session.c
> +++ b/tools/perf/util/session.c
> @@ -1178,7 +1178,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 {
>  			if (i == 0) {
>  				printf("..... %2"PRIu64": %016" PRIx64 "\n"



More information about the linux-arm-kernel mailing list