perf pmu: Count sys and cpuid JSON events separately

Sys events are eagerly loaded as each event has a compat option that may
mean the event is or isn't associated with the PMU.

These shouldn't be counted as loaded_json_events as that is used for
JSON events matching the CPUID that may or may not have been loaded. The
mismatch causes issues on ARM64 that uses sys events.

Fixes: e6ff1eed35 ("perf pmu: Lazily add JSON events")
Closes: https://lore.kernel.org/lkml/20240510024729.1075732-1-justin.he@arm.com/
Reported-by: Jia He <justin.he@arm.com>
Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
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: John Garry <john.g.garry@oracle.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20240511003601.2666907-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Ian Rogers 2024-05-10 17:36:01 -07:00 committed by Arnaldo Carvalho de Melo
parent 193a9e3020
commit d9c5f5f94c
2 changed files with 53 additions and 23 deletions

View File

@ -36,6 +36,18 @@ struct perf_pmu perf_pmu__fake = {
#define UNIT_MAX_LEN 31 /* max length for event unit name */
enum event_source {
/* An event loaded from /sys/devices/<pmu>/events. */
EVENT_SRC_SYSFS,
/* An event loaded from a CPUID matched json file. */
EVENT_SRC_CPU_JSON,
/*
* An event loaded from a /sys/devices/<pmu>/identifier matched json
* file.
*/
EVENT_SRC_SYS_JSON,
};
/**
* struct perf_pmu_alias - An event either read from sysfs or builtin in
* pmu-events.c, created by parsing the pmu-events json files.
@ -521,7 +533,7 @@ static int update_alias(const struct pmu_event *pe,
static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
const char *desc, const char *val, FILE *val_fd,
const struct pmu_event *pe)
const struct pmu_event *pe, enum event_source src)
{
struct perf_pmu_alias *alias;
int ret;
@ -574,25 +586,30 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
}
snprintf(alias->unit, sizeof(alias->unit), "%s", unit);
}
if (!pe) {
/* Update an event from sysfs with json data. */
struct update_alias_data data = {
.pmu = pmu,
.alias = alias,
};
switch (src) {
default:
case EVENT_SRC_SYSFS:
alias->from_sysfs = true;
if (pmu->events_table) {
/* Update an event from sysfs with json data. */
struct update_alias_data data = {
.pmu = pmu,
.alias = alias,
};
if (pmu_events_table__find_event(pmu->events_table, pmu, name,
update_alias, &data) == 0)
pmu->loaded_json_aliases++;
pmu->cpu_json_aliases++;
}
}
if (!pe)
pmu->sysfs_aliases++;
else
pmu->loaded_json_aliases++;
break;
case EVENT_SRC_CPU_JSON:
pmu->cpu_json_aliases++;
break;
case EVENT_SRC_SYS_JSON:
pmu->sys_json_aliases++;
break;
}
list_add_tail(&alias->list, &pmu->aliases);
return 0;
}
@ -653,7 +670,8 @@ static int __pmu_aliases_parse(struct perf_pmu *pmu, int events_dir_fd)
}
if (perf_pmu__new_alias(pmu, name, /*desc=*/ NULL,
/*val=*/ NULL, file, /*pe=*/ NULL) < 0)
/*val=*/ NULL, file, /*pe=*/ NULL,
EVENT_SRC_SYSFS) < 0)
pr_debug("Cannot set up %s\n", name);
fclose(file);
}
@ -946,7 +964,8 @@ static int pmu_add_cpu_aliases_map_callback(const struct pmu_event *pe,
{
struct perf_pmu *pmu = vdata;
perf_pmu__new_alias(pmu, pe->name, pe->desc, pe->event, /*val_fd=*/ NULL, pe);
perf_pmu__new_alias(pmu, pe->name, pe->desc, pe->event, /*val_fd=*/ NULL,
pe, EVENT_SRC_CPU_JSON);
return 0;
}
@ -981,13 +1000,14 @@ static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe,
return 0;
if (pmu_uncore_alias_match(pe->pmu, pmu->name) &&
pmu_uncore_identifier_match(pe->compat, pmu->id)) {
pmu_uncore_identifier_match(pe->compat, pmu->id)) {
perf_pmu__new_alias(pmu,
pe->name,
pe->desc,
pe->event,
/*val_fd=*/ NULL,
pe);
pe,
EVENT_SRC_SYS_JSON);
}
return 0;
@ -1082,6 +1102,12 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char
pmu->max_precise = pmu_max_precise(dirfd, pmu);
pmu->alias_name = pmu_find_alias_name(pmu, dirfd);
pmu->events_table = perf_pmu__find_events_table(pmu);
/*
* Load the sys json events/aliases when loading the PMU as each event
* may have a different compat regular expression. We therefore can't
* know the number of sys json events/aliases without computing the
* regular expressions for them all.
*/
pmu_add_sys_aliases(pmu);
list_add_tail(&pmu->list, pmus);
@ -1739,12 +1765,14 @@ size_t perf_pmu__num_events(struct perf_pmu *pmu)
size_t nr;
pmu_aliases_parse(pmu);
nr = pmu->sysfs_aliases;
nr = pmu->sysfs_aliases + pmu->sys_json_aliases;;
if (pmu->cpu_aliases_added)
nr += pmu->loaded_json_aliases;
nr += pmu->cpu_json_aliases;
else if (pmu->events_table)
nr += pmu_events_table__num_events(pmu->events_table, pmu) - pmu->loaded_json_aliases;
nr += pmu_events_table__num_events(pmu->events_table, pmu) - pmu->cpu_json_aliases;
else
assert(pmu->cpu_json_aliases == 0);
return pmu->selectable ? nr + 1 : nr;
}

View File

@ -123,8 +123,10 @@ struct perf_pmu {
const struct pmu_events_table *events_table;
/** @sysfs_aliases: Number of sysfs aliases loaded. */
uint32_t sysfs_aliases;
/** @sysfs_aliases: Number of json event aliases loaded. */
uint32_t loaded_json_aliases;
/** @cpu_json_aliases: Number of json event aliases loaded specific to the CPUID. */
uint32_t cpu_json_aliases;
/** @sys_json_aliases: Number of json event aliases loaded matching the PMU's identifier. */
uint32_t sys_json_aliases;
/** @sysfs_aliases_loaded: Are sysfs aliases loaded from disk? */
bool sysfs_aliases_loaded;
/**