Commit c64f5abf authored by Rob Herring's avatar Rob Herring Committed by Lipeng Sang
Browse files

perf: Skip and warn on unknown format 'configN' attrs

stable inclusion
from stable-v5.10.152
commit ca4c49838278344854792bec2645b01e50471ccf
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I73HJ0

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



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

[ Upstream commit e552b7be ]

If the kernel exposes a new perf_event_attr field in a format attr, perf
will return an error stating the specified PMU can't be found. For
example, a format attr with 'config3:0-63' causes an error as config3 is
unknown to perf. This causes a compatibility issue between a newer
kernel with older perf tool.

Before this change with a kernel adding 'config3' I get:

  $ perf record -e arm_spe// -- true
  event syntax error: 'arm_spe//'
                       \___ Cannot find PMU `arm_spe'. Missing kernel support?
  Run 'perf list' for a list of valid events

   Usage: perf record [<options>] [<command>]
      or: perf record [<options>] -- <command> [<options>]

      -e, --event <event>   event selector. use 'perf list' to list
  available events

After this change, I get:

  $ perf record -e arm_spe// -- true
  WARNING: 'arm_spe_0' format 'inv_event_filter' requires 'perf_event_attr::config3' which is not supported by this version of perf!
  [ perf record: Woken up 2 times to write data ]
  [ perf record: Captured and wrote 0.091 MB perf.data ]

To support unknown configN formats, rework the YACC implementation to
pass any config[0-9]+ format to perf_pmu__new_format() to handle with a
warning.

Reviewed-by: default avatarNamhyung Kim <namhyung@kernel.org>
Signed-off-by: default avatarRob Herring <robh@kernel.org>
Tested-by: default avatarLeo Yan <leo.yan@linaro.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.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: Peter Zijlstra <peterz@infradead.org>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20220914-arm-perf-tool-spe1-2-v2-v4-1-83c098e6212e@kernel.org


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarLipeng Sang <sanglipeng1@jd.com>
parent 1b849a1b
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -356,6 +356,9 @@ __add_event(struct list_head *list, int *idx,
	struct perf_cpu_map *cpus = pmu ? perf_cpu_map__get(pmu->cpus) :
			       cpu_list ? perf_cpu_map__new(cpu_list) : NULL;

	if (pmu)
		perf_pmu__warn_invalid_formats(pmu);

	if (pmu && attr->type == PERF_TYPE_RAW)
		perf_pmu__warn_invalid_config(pmu, attr->config, name);

+17 −0
Original line number Diff line number Diff line
@@ -1006,6 +1006,23 @@ static struct perf_pmu *pmu_lookup(const char *name)
	return pmu;
}

void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu)
{
	struct perf_pmu_format *format;

	/* fake pmu doesn't have format list */
	if (pmu == &perf_pmu__fake)
		return;

	list_for_each_entry(format, &pmu->format, list)
		if (format->value >= PERF_PMU_FORMAT_VALUE_CONFIG_END) {
			pr_warning("WARNING: '%s' format '%s' requires 'perf_event_attr::config%d'"
				   "which is not supported by this version of perf!\n",
				   pmu->name, format->name, format->value);
			return;
		}
}

static struct perf_pmu *pmu_find(const char *name)
{
	struct perf_pmu *pmu;
+2 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ enum {
	PERF_PMU_FORMAT_VALUE_CONFIG,
	PERF_PMU_FORMAT_VALUE_CONFIG1,
	PERF_PMU_FORMAT_VALUE_CONFIG2,
	PERF_PMU_FORMAT_VALUE_CONFIG_END,
};

#define PERF_PMU_FORMAT_BITS 64
@@ -130,5 +131,6 @@ int perf_pmu__match(char *pattern, char *name, char *tok);

void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
				   char *name);
void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu);

#endif /* __PMU_H */
+0 −2
Original line number Diff line number Diff line
@@ -27,8 +27,6 @@ num_dec [0-9]+

{num_dec}	{ return value(10); }
config		{ return PP_CONFIG; }
config1		{ return PP_CONFIG1; }
config2		{ return PP_CONFIG2; }
-		{ return '-'; }
:		{ return ':'; }
,		{ return ','; }
+4 −11
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ do { \

%}

%token PP_CONFIG PP_CONFIG1 PP_CONFIG2
%token PP_CONFIG
%token PP_VALUE PP_ERROR
%type <num> PP_VALUE
%type <bits> bit_term
@@ -47,18 +47,11 @@ PP_CONFIG ':' bits
				      $3));
}
|
PP_CONFIG1 ':' bits
PP_CONFIG PP_VALUE ':' bits
{
	ABORT_ON(perf_pmu__new_format(format, name,
				      PERF_PMU_FORMAT_VALUE_CONFIG1,
				      $3));
}
|
PP_CONFIG2 ':' bits
{
	ABORT_ON(perf_pmu__new_format(format, name,
				      PERF_PMU_FORMAT_VALUE_CONFIG2,
				      $3));
				      $2,
				      $4));
}

bits: