perf pmu: Count sys and cpuid JSON events separately
authorIan Rogers <irogers@google.com>
Sat, 11 May 2024 00:36:01 +0000 (17:36 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Sat, 11 May 2024 16:03:13 +0000 (13:03 -0300)
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: e6ff1eed3584362d ("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>
tools/perf/util/pmu.c
tools/perf/util/pmu.h

index b3b072feef0232a2526c6ec59660d461f1c17869..888ce99122759f8028a7509e1cab952efaf43541 100644 (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;
 }
index 561716aa2b25675a6efc7532a0ab1fd2085219c6..b2d3fd291f0297f6e7c0c9b91132d4aaa331fc5e 100644 (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;
        /**