perf: Skip and warn on unknown format 'configN' attrs
[ Upstream commit e552b7be12ed62357df84392efa525ecb01910fb ] 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: Namhyung Kim <namhyung@kernel.org> Signed-off-by: Rob Herring <robh@kernel.org> Tested-by: Leo 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: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
dea47fefa6
commit
ca4c498382
@@ -356,6 +356,9 @@ __add_event(struct list_head *list, int *idx,
|
|||||||
struct perf_cpu_map *cpus = pmu ? perf_cpu_map__get(pmu->cpus) :
|
struct perf_cpu_map *cpus = pmu ? perf_cpu_map__get(pmu->cpus) :
|
||||||
cpu_list ? perf_cpu_map__new(cpu_list) : NULL;
|
cpu_list ? perf_cpu_map__new(cpu_list) : NULL;
|
||||||
|
|
||||||
|
if (pmu)
|
||||||
|
perf_pmu__warn_invalid_formats(pmu);
|
||||||
|
|
||||||
if (pmu && attr->type == PERF_TYPE_RAW)
|
if (pmu && attr->type == PERF_TYPE_RAW)
|
||||||
perf_pmu__warn_invalid_config(pmu, attr->config, name);
|
perf_pmu__warn_invalid_config(pmu, attr->config, name);
|
||||||
|
|
||||||
|
@@ -862,6 +862,23 @@ static struct perf_pmu *pmu_lookup(const char *name)
|
|||||||
return pmu;
|
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)
|
static struct perf_pmu *pmu_find(const char *name)
|
||||||
{
|
{
|
||||||
struct perf_pmu *pmu;
|
struct perf_pmu *pmu;
|
||||||
|
@@ -15,6 +15,7 @@ enum {
|
|||||||
PERF_PMU_FORMAT_VALUE_CONFIG,
|
PERF_PMU_FORMAT_VALUE_CONFIG,
|
||||||
PERF_PMU_FORMAT_VALUE_CONFIG1,
|
PERF_PMU_FORMAT_VALUE_CONFIG1,
|
||||||
PERF_PMU_FORMAT_VALUE_CONFIG2,
|
PERF_PMU_FORMAT_VALUE_CONFIG2,
|
||||||
|
PERF_PMU_FORMAT_VALUE_CONFIG_END,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PERF_PMU_FORMAT_BITS 64
|
#define PERF_PMU_FORMAT_BITS 64
|
||||||
@@ -122,5 +123,6 @@ int perf_pmu__caps_parse(struct perf_pmu *pmu);
|
|||||||
|
|
||||||
void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
|
void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
|
||||||
char *name);
|
char *name);
|
||||||
|
void perf_pmu__warn_invalid_formats(struct perf_pmu *pmu);
|
||||||
|
|
||||||
#endif /* __PMU_H */
|
#endif /* __PMU_H */
|
||||||
|
@@ -27,8 +27,6 @@ num_dec [0-9]+
|
|||||||
|
|
||||||
{num_dec} { return value(10); }
|
{num_dec} { return value(10); }
|
||||||
config { return PP_CONFIG; }
|
config { return PP_CONFIG; }
|
||||||
config1 { return PP_CONFIG1; }
|
|
||||||
config2 { return PP_CONFIG2; }
|
|
||||||
- { return '-'; }
|
- { return '-'; }
|
||||||
: { return ':'; }
|
: { return ':'; }
|
||||||
, { return ','; }
|
, { return ','; }
|
||||||
|
@@ -20,7 +20,7 @@ do { \
|
|||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%token PP_CONFIG PP_CONFIG1 PP_CONFIG2
|
%token PP_CONFIG
|
||||||
%token PP_VALUE PP_ERROR
|
%token PP_VALUE PP_ERROR
|
||||||
%type <num> PP_VALUE
|
%type <num> PP_VALUE
|
||||||
%type <bits> bit_term
|
%type <bits> bit_term
|
||||||
@@ -47,18 +47,11 @@ PP_CONFIG ':' bits
|
|||||||
$3));
|
$3));
|
||||||
}
|
}
|
||||||
|
|
|
|
||||||
PP_CONFIG1 ':' bits
|
PP_CONFIG PP_VALUE ':' bits
|
||||||
{
|
{
|
||||||
ABORT_ON(perf_pmu__new_format(format, name,
|
ABORT_ON(perf_pmu__new_format(format, name,
|
||||||
PERF_PMU_FORMAT_VALUE_CONFIG1,
|
$2,
|
||||||
$3));
|
$4));
|
||||||
}
|
|
||||||
|
|
|
||||||
PP_CONFIG2 ':' bits
|
|
||||||
{
|
|
||||||
ABORT_ON(perf_pmu__new_format(format, name,
|
|
||||||
PERF_PMU_FORMAT_VALUE_CONFIG2,
|
|
||||||
$3));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bits:
|
bits:
|
||||||
|
Reference in New Issue
Block a user