perf pmu: Lazily add JSON events
authorIan Rogers <irogers@google.com>
Thu, 24 Aug 2023 04:13:25 +0000 (21:13 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 24 Aug 2023 14:08:47 +0000 (11:08 -0300)
Rather than scanning all JSON events and adding them when a PMU is
created, add the alias when the JSON event is needed.

Average core PMU scanning run time reduced by 60.2%. Average PMU
scanning run time reduced by 15%. Page faults with no events reduced by
74 page faults, 4% of total.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Gaosheng Cui <cuigaosheng1@huawei.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jing Zhang <renyu.zj@linux.alibaba.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Kajol Jain <kjain@linux.ibm.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>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/20230824041330.266337-14-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/pmu-events/empty-pmu-events.c
tools/perf/pmu-events/jevents.py
tools/perf/pmu-events/pmu-events.h
tools/perf/tests/pmu-events.c
tools/perf/util/pmu.c
tools/perf/util/pmu.h

index ef18d40..12bd043 100644 (file)
@@ -298,6 +298,20 @@ int pmu_events_table__find_event(const struct pmu_events_table *table,
         return -1000;
 }
 
+size_t pmu_events_table__num_events(const struct pmu_events_table *table,
+                                    struct perf_pmu *pmu)
+{
+        size_t count = 0;
+
+       for (const struct pmu_event *pe = &table->entries[0]; pe->name; pe++) {
+                if (pmu && !pmu__name_match(pmu, pe->pmu))
+                        continue;
+
+               count++;
+       }
+        return count;
+}
+
 int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn,
                                      void *data)
 {
index f07864f..01335a4 100755 (executable)
@@ -909,6 +909,21 @@ int pmu_events_table__find_event(const struct pmu_events_table *table,
         return -1000;
 }
 
+size_t pmu_events_table__num_events(const struct pmu_events_table *table,
+                                    struct perf_pmu *pmu)
+{
+        size_t count = 0;
+
+        for (size_t i = 0; i < table->num_pmus; i++) {
+                const struct pmu_table_entry *table_pmu = &table->pmus[i];
+                const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset];
+
+                if (pmu__name_match(pmu, pmu_name))
+                        count += table_pmu->num_entries;
+        }
+        return count;
+}
+
 static int pmu_metrics_table__for_each_metric_pmu(const struct pmu_metrics_table *table,
                                                 const struct pmu_table_entry *pmu,
                                                 pmu_metric_iter_fn fn,
index 9882b71..f5aa96f 100644 (file)
@@ -3,6 +3,7 @@
 #define PMU_EVENTS_H
 
 #include <stdbool.h>
+#include <stddef.h>
 
 struct perf_pmu;
 
@@ -86,6 +87,9 @@ int pmu_events_table__find_event(const struct pmu_events_table *table,
                                  const char *name,
                                  pmu_event_iter_fn fn,
                                 void *data);
+size_t pmu_events_table__num_events(const struct pmu_events_table *table,
+                                   struct perf_pmu *pmu);
+
 int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn,
                                     void *data);
 
index 4fcb84f..9ac893a 100644 (file)
@@ -546,6 +546,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
 
        pmu->events_table = table;
        pmu_add_cpu_aliases_table(pmu, table);
+       pmu->cpu_aliases_added = true;
 
        res = pmu_events_table__find_event(table, pmu, "bp_l1_btb_correct", NULL, NULL);
        if (res != 0) {
@@ -586,6 +587,7 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
                return -1;
        pmu->events_table = events_table;
        pmu_add_cpu_aliases_table(pmu, events_table);
+       pmu->cpu_aliases_added = true;
        pmu_add_sys_aliases(pmu);
 
        /* Count how many aliases we generated */
index 685903c..b6a1182 100644 (file)
@@ -523,8 +523,9 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, int dirfd, const char *name
        if (!pe) {
                /* Update an event from sysfs with json data. */
                if (pmu->events_table) {
-                       pmu_events_table__find_event(pmu->events_table, pmu, name,
-                                                    update_alias, alias);
+                       if (pmu_events_table__find_event(pmu->events_table, pmu, name,
+                                                        update_alias, alias) == 0)
+                               pmu->loaded_json_aliases++;
                }
        }
 
@@ -548,6 +549,10 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, int dirfd, const char *name
                                         "%s=%s", term->config, term->val.str);
        }
        alias->str = strdup(newval);
+       if (!pe)
+               pmu->sysfs_aliases++;
+       else
+               pmu->loaded_json_aliases++;
        list_add_tail(&alias->list, &pmu->aliases);
        return 0;
 }
@@ -878,7 +883,11 @@ static void pmu_add_cpu_aliases(struct perf_pmu *pmu)
        if (!pmu->events_table)
                return;
 
+       if (pmu->cpu_aliases_added)
+               return;
+
        pmu_add_cpu_aliases_table(pmu, pmu->events_table);
+       pmu->cpu_aliases_added = true;
 }
 
 static int pmu_add_sys_aliases_iter_fn(const struct pmu_event *pe,
@@ -990,7 +999,6 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char
                pmu->id = pmu_id(name);
        pmu->max_precise = pmu_max_precise(dirfd, pmu);
        pmu->events_table = perf_pmu__find_events_table(pmu);
-       pmu_add_cpu_aliases(pmu);
        pmu_add_sys_aliases(pmu);
        list_add_tail(&pmu->list, pmus);
 
@@ -1368,6 +1376,7 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
 static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
                                             struct parse_events_term *term)
 {
+       struct perf_pmu_alias *alias;
        char *name;
 
        if (parse_events__is_hardcoded_term(term))
@@ -1388,7 +1397,18 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
                return NULL;
        }
 
-       return perf_pmu__find_alias(pmu, name);
+       alias = perf_pmu__find_alias(pmu, name);
+       if (alias || pmu->cpu_aliases_added)
+               return alias;
+
+       /* Alias doesn't exist, try to get it from the json events. */
+       if (pmu->events_table &&
+           pmu_events_table__find_event(pmu->events_table, pmu, name,
+                                        pmu_add_cpu_aliases_map_callback,
+                                        pmu) == 0) {
+               alias = perf_pmu__find_alias(pmu, name);
+       }
+       return alias;
 }
 
 
@@ -1555,18 +1575,23 @@ bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu)
        return !pmu->is_core || perf_pmus__num_core_pmus() == 1;
 }
 
-bool perf_pmu__have_event(const struct perf_pmu *pmu, const char *name)
+bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name)
 {
-       return perf_pmu__find_alias(pmu, name) != NULL;
+       if (perf_pmu__find_alias(pmu, name) != NULL)
+               return true;
+       if (pmu->cpu_aliases_added || !pmu->events_table)
+               return false;
+       return pmu_events_table__find_event(pmu->events_table, pmu, name, NULL, NULL) == 0;
 }
 
-size_t perf_pmu__num_events(const struct perf_pmu *pmu)
+size_t perf_pmu__num_events(struct perf_pmu *pmu)
 {
-       struct list_head *list;
-       size_t nr = 0;
+       size_t nr = pmu->sysfs_aliases;
 
-       list_for_each(list, &pmu->aliases)
-               nr++;
+       if (pmu->cpu_aliases_added)
+                nr += pmu->loaded_json_aliases;
+       else if (pmu->events_table)
+               nr += pmu_events_table__num_events(pmu->events_table, pmu) - pmu->loaded_json_aliases;
 
        return pmu->selectable ? nr + 1 : nr;
 }
@@ -1604,7 +1629,7 @@ static char *format_alias(char *buf, int len, const struct perf_pmu *pmu,
        return buf;
 }
 
-int perf_pmu__for_each_event(const struct perf_pmu *pmu, void *state, pmu_event_callback cb)
+int perf_pmu__for_each_event(struct perf_pmu *pmu, void *state, pmu_event_callback cb)
 {
        char buf[1024];
        struct perf_pmu_alias *event;
@@ -1613,6 +1638,7 @@ int perf_pmu__for_each_event(const struct perf_pmu *pmu, void *state, pmu_event_
        };
        int ret = 0;
 
+       pmu_add_cpu_aliases(pmu);
        list_for_each_entry(event, &pmu->aliases, list) {
                size_t buf_used;
 
index 6bf0fbd..288d290 100644 (file)
@@ -118,6 +118,15 @@ struct perf_pmu {
         * @events_table: The events table for json events in pmu-events.c.
         */
        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_aliases_added: Have all json events table entries for the PMU
+        * been added?
+        */
+       bool cpu_aliases_added;
        /** @caps_initialized: Has the list caps been initialized? */
        bool caps_initialized;
        /** @nr_caps: The length of the list caps. */
@@ -199,9 +208,9 @@ bool perf_pmu__has_format(const struct perf_pmu *pmu, const char *name);
 bool is_pmu_core(const char *name);
 bool perf_pmu__supports_legacy_cache(const struct perf_pmu *pmu);
 bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu);
-bool perf_pmu__have_event(const struct perf_pmu *pmu, const char *name);
-size_t perf_pmu__num_events(const struct perf_pmu *pmu);
-int perf_pmu__for_each_event(const struct perf_pmu *pmu, void *state, pmu_event_callback cb);
+bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name);
+size_t perf_pmu__num_events(struct perf_pmu *pmu);
+int perf_pmu__for_each_event(struct perf_pmu *pmu, void *state, pmu_event_callback cb);
 bool pmu__name_match(const struct perf_pmu *pmu, const char *pmu_name);
 
 /**