perf pmu: Change aliases from list to hashmap
authorIan Rogers <irogers@google.com>
Mon, 12 May 2025 19:46:21 +0000 (12:46 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 13 May 2025 19:36:43 +0000 (16:36 -0300)
Finding an alias for things like perf_pmu__have_event() would need to
search the aliases list, whilst this happens relatively infrequently it
can be a significant overhead in testing.

Switch to using a hashmap. Move common initialization code to
perf_pmu__init(). Refactor the test 'struct perf_pmu_test_pmu' to not
have perf pmu within it to better support the perf_pmu__init() function.

Before:
```
$ time perf test "Parsing of PMU event table metrics"
 10.3: Parsing of PMU event table metrics                            : Ok
 10.4: Parsing of PMU event table metrics with fake PMUs             : Ok

real    0m13.287s
user    0m13.026s
sys     0m0.532s
```

After:
```
$ time perf test "Parsing of PMU event table metrics"
 10.3: Parsing of PMU event table metrics                            : Ok
 10.4: Parsing of PMU event table metrics with fake PMUs             : Ok

real    0m13.011s
user    0m12.885s
sys     0m0.485s
```

Committer testing:

  root@number:~# grep -m1 'model name' /proc/cpuinfo
  model name : AMD Ryzen 9 9950X3D 16-Core Processor
  root@number:~#

Before:

  root@number:~# time perf test "Parsing of PMU event table metrics"
   10.3: Parsing of PMU event table metrics                            : Ok
   10.4: Parsing of PMU event table metrics with fake PMUs             : Ok

  real 0m9.296s
  user 0m9.361s
  sys 0m0.063s
  root@number:~#

After:

  root@number:~# time perf test "Parsing of PMU event table metrics"
   10.3: Parsing of PMU event table metrics                            : Ok
   10.4: Parsing of PMU event table metrics with fake PMUs             : Ok

  real 0m9.286s
  user 0m9.354s
  sys 0m0.062s
  root@number:~#

Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Namhyung Kim <namhyung@kernel.org>
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@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Xu Yang <xu.yang_2@nxp.com>
Link: https://lore.kernel.org/r/20250512194622.33258-3-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/tests/pmu-events.c
tools/perf/util/hwmon_pmu.c
tools/perf/util/pmu.c
tools/perf/util/pmu.h
tools/perf/util/tool_pmu.c

index db004d26fcb005f3d91080b769d6b31df159f759..815b400974285013c48bf4aa144e8fe05adfa37c 100644 (file)
@@ -38,7 +38,9 @@ struct perf_pmu_test_event {
 };
 
 struct perf_pmu_test_pmu {
-       struct perf_pmu pmu;
+       const char *pmu_name;
+       bool pmu_is_uncore;
+       const char *pmu_id;
        struct perf_pmu_test_event const *aliases[10];
 };
 
@@ -553,11 +555,10 @@ static int __test_core_pmu_event_aliases(const char *pmu_name, int *count)
        if (!pmu)
                return -1;
 
-       INIT_LIST_HEAD(&pmu->format);
-       INIT_LIST_HEAD(&pmu->aliases);
-       INIT_LIST_HEAD(&pmu->caps);
-       INIT_LIST_HEAD(&pmu->list);
-       pmu->name = strdup(pmu_name);
+       if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, pmu_name) != 0) {
+               perf_pmu__delete(pmu);
+               return -1;
+       }
        pmu->is_core = true;
 
        pmu->events_table = table;
@@ -594,14 +595,30 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
 {
        int alias_count = 0, to_match_count = 0, matched_count = 0;
        struct perf_pmu_test_event const **table;
-       struct perf_pmu *pmu = &test_pmu->pmu;
-       const char *pmu_name = pmu->name;
+       struct perf_pmu *pmu;
        const struct pmu_events_table *events_table;
        int res = 0;
 
        events_table = find_core_events_table("testarch", "testcpu");
        if (!events_table)
                return -1;
+
+       pmu = zalloc(sizeof(*pmu));
+       if (!pmu)
+               return -1;
+
+       if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, test_pmu->pmu_name) != 0) {
+               perf_pmu__delete(pmu);
+               return -1;
+       }
+       pmu->is_uncore = test_pmu->pmu_is_uncore;
+       if (test_pmu->pmu_id) {
+               pmu->id = strdup(test_pmu->pmu_id);
+               if (!pmu->id) {
+                       perf_pmu__delete(pmu);
+                       return -1;
+               }
+       }
        pmu->events_table = events_table;
        pmu_add_cpu_aliases_table(pmu, events_table);
        pmu->cpu_aliases_added = true;
@@ -617,7 +634,8 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
 
        if (alias_count != to_match_count) {
                pr_debug("testing aliases uncore PMU %s: mismatch expected aliases (%d) vs found (%d)\n",
-                        pmu_name, to_match_count, alias_count);
+                        pmu->name, to_match_count, alias_count);
+               perf_pmu__delete(pmu);
                return -1;
        }
 
@@ -630,9 +648,10 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
                        .count = &matched_count,
                };
 
-               if (strcmp(pmu_name, test_event.matching_pmu)) {
+               if (strcmp(pmu->name, test_event.matching_pmu)) {
                        pr_debug("testing aliases uncore PMU %s: mismatched matching_pmu, %s vs %s\n",
-                                       pmu_name, test_event.matching_pmu, pmu_name);
+                                       pmu->name, test_event.matching_pmu, pmu->name);
+                       perf_pmu__delete(pmu);
                        return -1;
                }
 
@@ -641,34 +660,32 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
                if (err) {
                        res = err;
                        pr_debug("testing aliases uncore PMU %s: could not match alias %s\n",
-                                pmu_name, event->name);
+                                pmu->name, event->name);
+                       perf_pmu__delete(pmu);
                        return -1;
                }
        }
 
        if (alias_count != matched_count) {
                pr_debug("testing aliases uncore PMU %s: mismatch found aliases (%d) vs matched (%d)\n",
-                        pmu_name, matched_count, alias_count);
+                        pmu->name, matched_count, alias_count);
                res = -1;
        }
+       perf_pmu__delete(pmu);
        return res;
 }
 
 static struct perf_pmu_test_pmu test_pmus[] = {
        {
-               .pmu = {
-                       .name = "hisi_sccl1_ddrc2",
-                       .is_uncore = 1,
-               },
+               .pmu_name = "hisi_sccl1_ddrc2",
+               .pmu_is_uncore = 1,
                .aliases = {
                        &uncore_hisi_ddrc_flux_wcmd,
                },
        },
        {
-               .pmu = {
-                       .name = "uncore_cbox_0",
-                       .is_uncore = 1,
-               },
+               .pmu_name = "uncore_cbox_0",
+               .pmu_is_uncore = 1,
                .aliases = {
                        &unc_cbo_xsnp_response_miss_eviction,
                        &uncore_hyphen,
@@ -676,88 +693,70 @@ static struct perf_pmu_test_pmu test_pmus[] = {
                },
        },
        {
-               .pmu = {
-                       .name = "hisi_sccl3_l3c7",
-                       .is_uncore = 1,
-               },
+               .pmu_name = "hisi_sccl3_l3c7",
+               .pmu_is_uncore = 1,
                .aliases = {
                        &uncore_hisi_l3c_rd_hit_cpipe,
                },
        },
        {
-               .pmu = {
-                       .name = "uncore_imc_free_running_0",
-                       .is_uncore = 1,
-               },
+               .pmu_name = "uncore_imc_free_running_0",
+               .pmu_is_uncore = 1,
                .aliases = {
                        &uncore_imc_free_running_cache_miss,
                },
        },
        {
-               .pmu = {
-                       .name = "uncore_imc_0",
-                       .is_uncore = 1,
-               },
+               .pmu_name = "uncore_imc_0",
+               .pmu_is_uncore = 1,
                .aliases = {
                        &uncore_imc_cache_hits,
                },
        },
        {
-               .pmu = {
-                       .name = "uncore_sys_ddr_pmu0",
-                       .is_uncore = 1,
-                       .id = "v8",
-               },
+               .pmu_name = "uncore_sys_ddr_pmu0",
+               .pmu_is_uncore = 1,
+               .pmu_id = "v8",
                .aliases = {
                        &sys_ddr_pmu_write_cycles,
                },
        },
        {
-               .pmu = {
-                       .name = "uncore_sys_ccn_pmu4",
-                       .is_uncore = 1,
-                       .id = "0x01",
-               },
+               .pmu_name = "uncore_sys_ccn_pmu4",
+               .pmu_is_uncore = 1,
+               .pmu_id = "0x01",
                .aliases = {
                        &sys_ccn_pmu_read_cycles,
                },
        },
        {
-               .pmu = {
-                       .name = (char *)"uncore_sys_cmn_pmu0",
-                       .is_uncore = 1,
-                       .id = (char *)"43401",
-               },
+               .pmu_name = "uncore_sys_cmn_pmu0",
+               .pmu_is_uncore = 1,
+               .pmu_id = "43401",
                .aliases = {
                        &sys_cmn_pmu_hnf_cache_miss,
                },
        },
        {
-               .pmu = {
-                       .name = (char *)"uncore_sys_cmn_pmu0",
-                       .is_uncore = 1,
-                       .id = (char *)"43602",
-               },
+               .pmu_name = "uncore_sys_cmn_pmu0",
+               .pmu_is_uncore = 1,
+               .pmu_id = "43602",
                .aliases = {
                        &sys_cmn_pmu_hnf_cache_miss,
                },
        },
        {
-               .pmu = {
-                       .name = (char *)"uncore_sys_cmn_pmu0",
-                       .is_uncore = 1,
-                       .id = (char *)"43c03",
-               },
+               .pmu_name = "uncore_sys_cmn_pmu0",
+               .pmu_is_uncore = 1,
+               .pmu_id = "43c03",
                .aliases = {
                        &sys_cmn_pmu_hnf_cache_miss,
                },
        },
        {
-               .pmu = {
-                       .name = (char *)"uncore_sys_cmn_pmu0",
-                       .is_uncore = 1,
-                       .id = (char *)"43a01",
-               },
+               .pmu_name = "uncore_sys_cmn_pmu0",
+               .pmu_is_uncore = 1,
+               .pmu_id = "43a01",
                .aliases = {
                        &sys_cmn_pmu_hnf_cache_miss,
                },
@@ -796,10 +795,6 @@ static int test__aliases(struct test_suite *test __maybe_unused,
        for (i = 0; i < ARRAY_SIZE(test_pmus); i++) {
                int res;
 
-               INIT_LIST_HEAD(&test_pmus[i].pmu.format);
-               INIT_LIST_HEAD(&test_pmus[i].pmu.aliases);
-               INIT_LIST_HEAD(&test_pmus[i].pmu.caps);
-
                res = __test_uncore_pmu_event_aliases(&test_pmus[i]);
                if (res)
                        return res;
index 3cce77fc80041d9b8aeddbb81e1e5e77292790f1..c25e7296f1c10c22105b8433bd04da8c2708b97f 100644 (file)
@@ -346,42 +346,43 @@ struct perf_pmu *hwmon_pmu__new(struct list_head *pmus, int hwmon_dir, const cha
 {
        char buf[32];
        struct hwmon_pmu *hwm;
+       __u32 type = PERF_PMU_TYPE_HWMON_START + strtoul(sysfs_name + 5, NULL, 10);
+
+       if (type > PERF_PMU_TYPE_HWMON_END) {
+               pr_err("Unable to encode hwmon type from %s in valid PMU type\n", sysfs_name);
+               return NULL;
+       }
+
+       snprintf(buf, sizeof(buf), "hwmon_%s", name);
+       fix_name(buf + 6);
 
        hwm = zalloc(sizeof(*hwm));
        if (!hwm)
                return NULL;
 
-       hwm->hwmon_dir_fd = hwmon_dir;
-       hwm->pmu.type = PERF_PMU_TYPE_HWMON_START + strtoul(sysfs_name + 5, NULL, 10);
-       if (hwm->pmu.type > PERF_PMU_TYPE_HWMON_END) {
-               pr_err("Unable to encode hwmon type from %s in valid PMU type\n", sysfs_name);
-               goto err_out;
+       if (perf_pmu__init(&hwm->pmu, type, buf) != 0) {
+               perf_pmu__delete(&hwm->pmu);
+               return NULL;
        }
-       snprintf(buf, sizeof(buf), "hwmon_%s", name);
-       fix_name(buf + 6);
-       hwm->pmu.name = strdup(buf);
-       if (!hwm->pmu.name)
-               goto err_out;
+
+       hwm->hwmon_dir_fd = hwmon_dir;
        hwm->pmu.alias_name = strdup(sysfs_name);
-       if (!hwm->pmu.alias_name)
-               goto err_out;
+       if (!hwm->pmu.alias_name) {
+               perf_pmu__delete(&hwm->pmu);
+               return NULL;
+       }
        hwm->pmu.cpus = perf_cpu_map__new("0");
-       if (!hwm->pmu.cpus)
-               goto err_out;
+       if (!hwm->pmu.cpus) {
+               perf_pmu__delete(&hwm->pmu);
+               return NULL;
+       }
        INIT_LIST_HEAD(&hwm->pmu.format);
-       INIT_LIST_HEAD(&hwm->pmu.aliases);
        INIT_LIST_HEAD(&hwm->pmu.caps);
        hashmap__init(&hwm->events, hwmon_pmu__event_hashmap_hash,
                      hwmon_pmu__event_hashmap_equal, /*ctx=*/NULL);
 
        list_add_tail(&hwm->pmu.list, pmus);
        return &hwm->pmu;
-err_out:
-       free((char *)hwm->pmu.name);
-       free(hwm->pmu.alias_name);
-       free(hwm);
-       close(hwmon_dir);
-       return NULL;
 }
 
 void hwmon_pmu__exit(struct perf_pmu *pmu)
index 798810704f5b2c03a20e49e090912a99b886c4d5..bc1178234d3b1bf3b08af2e3089d32fb32c789e7 100644 (file)
@@ -27,6 +27,7 @@
 #include <util/pmu-flex.h>
 #include "parse-events.h"
 #include "print-events.h"
+#include "hashmap.h"
 #include "header.h"
 #include "string2.h"
 #include "strbuf.h"
@@ -66,8 +67,6 @@ struct perf_pmu_alias {
        char *topic;
        /** @terms: Owned list of the original parsed parameters. */
        struct parse_events_terms terms;
-       /** @list: List element of struct perf_pmu aliases. */
-       struct list_head list;
        /**
         * @pmu_name: The name copied from the json struct pmu_event. This can
         * differ from the PMU name as it won't have suffixes.
@@ -418,25 +417,33 @@ static void perf_pmu__parse_snapshot(struct perf_pmu *pmu, struct perf_pmu_alias
 }
 
 /* Delete an alias entry. */
-static void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
+static void perf_pmu_free_alias(struct perf_pmu_alias *alias)
 {
-       zfree(&newalias->name);
-       zfree(&newalias->desc);
-       zfree(&newalias->long_desc);
-       zfree(&newalias->topic);
-       zfree(&newalias->pmu_name);
-       parse_events_terms__exit(&newalias->terms);
-       free(newalias);
+       if (!alias)
+               return;
+
+       zfree(&alias->name);
+       zfree(&alias->desc);
+       zfree(&alias->long_desc);
+       zfree(&alias->topic);
+       zfree(&alias->pmu_name);
+       parse_events_terms__exit(&alias->terms);
+       free(alias);
 }
 
 static void perf_pmu__del_aliases(struct perf_pmu *pmu)
 {
-       struct perf_pmu_alias *alias, *tmp;
+       struct hashmap_entry *entry;
+       size_t bkt;
 
-       list_for_each_entry_safe(alias, tmp, &pmu->aliases, list) {
-               list_del(&alias->list);
-               perf_pmu_free_alias(alias);
-       }
+       if (!pmu->aliases)
+               return;
+
+       hashmap__for_each_entry(pmu->aliases, entry, bkt)
+               perf_pmu_free_alias(entry->pvalue);
+
+       hashmap__free(pmu->aliases);
+       pmu->aliases = NULL;
 }
 
 static struct perf_pmu_alias *perf_pmu__find_alias(struct perf_pmu *pmu,
@@ -444,35 +451,37 @@ static struct perf_pmu_alias *perf_pmu__find_alias(struct perf_pmu *pmu,
                                                   bool load)
 {
        struct perf_pmu_alias *alias;
+       bool has_sysfs_event;
+       char event_file_name[FILENAME_MAX + 8];
 
-       if (load && !pmu->sysfs_aliases_loaded) {
-               bool has_sysfs_event;
-               char event_file_name[FILENAME_MAX + 8];
+       if (hashmap__find(pmu->aliases, name, &alias))
+               return alias;
 
-               /*
-                * Test if alias/event 'name' exists in the PMU's sysfs/events
-                * directory. If not skip parsing the sysfs aliases. Sysfs event
-                * name must be all lower or all upper case.
-                */
-               scnprintf(event_file_name, sizeof(event_file_name), "events/%s", name);
-               for (size_t i = 7, n = 7 + strlen(name); i < n; i++)
-                       event_file_name[i] = tolower(event_file_name[i]);
+       if (!load || pmu->sysfs_aliases_loaded)
+               return NULL;
 
-               has_sysfs_event = perf_pmu__file_exists(pmu, event_file_name);
-               if (!has_sysfs_event) {
-                       for (size_t i = 7, n = 7 + strlen(name); i < n; i++)
-                               event_file_name[i] = toupper(event_file_name[i]);
+       /*
+        * Test if alias/event 'name' exists in the PMU's sysfs/events
+        * directory. If not skip parsing the sysfs aliases. Sysfs event
+        * name must be all lower or all upper case.
+        */
+       scnprintf(event_file_name, sizeof(event_file_name), "events/%s", name);
+       for (size_t i = 7, n = 7 + strlen(name); i < n; i++)
+               event_file_name[i] = tolower(event_file_name[i]);
 
-                       has_sysfs_event = perf_pmu__file_exists(pmu, event_file_name);
-               }
-               if (has_sysfs_event)
-                       pmu_aliases_parse(pmu);
+       has_sysfs_event = perf_pmu__file_exists(pmu, event_file_name);
+       if (!has_sysfs_event) {
+               for (size_t i = 7, n = 7 + strlen(name); i < n; i++)
+                       event_file_name[i] = toupper(event_file_name[i]);
 
+               has_sysfs_event = perf_pmu__file_exists(pmu, event_file_name);
        }
-       list_for_each_entry(alias, &pmu->aliases, list) {
-               if (!strcasecmp(alias->name, name))
+       if (has_sysfs_event) {
+               pmu_aliases_parse(pmu);
+               if (hashmap__find(pmu->aliases, name, &alias))
                        return alias;
        }
+
        return NULL;
 }
 
@@ -555,7 +564,7 @@ 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, enum event_source src)
 {
-       struct perf_pmu_alias *alias;
+       struct perf_pmu_alias *alias, *old_alias;
        int ret = 0;
        const char *long_desc = NULL, *topic = NULL, *unit = NULL, *pmu_name = NULL;
        bool deprecated = false, perpkg = false;
@@ -648,7 +657,8 @@ static int perf_pmu__new_alias(struct perf_pmu *pmu, const char *name,
                break;
 
        }
-       list_add_tail(&alias->list, &pmu->aliases);
+       hashmap__set(pmu->aliases, alias->name, alias, /*old_key=*/ NULL, &old_alias);
+       perf_pmu_free_alias(old_alias);
        return 0;
 }
 
@@ -1136,43 +1146,77 @@ perf_pmu__arch_init(struct perf_pmu *pmu)
                pmu->mem_events = perf_mem_events;
 }
 
+/* Variant of str_hash that does tolower on each character. */
+static size_t aliases__hash(long key, void *ctx __maybe_unused)
+{
+       const char *s = (const char *)key;
+       size_t h = 0;
+
+       while (*s) {
+               h = h * 31 + tolower(*s);
+               s++;
+       }
+       return h;
+}
+
+static bool aliases__equal(long key1, long key2, void *ctx __maybe_unused)
+{
+       return strcasecmp((const char *)key1, (const char *)key2) == 0;
+}
+
+int perf_pmu__init(struct perf_pmu *pmu, __u32 type, const char *name)
+{
+       pmu->type = type;
+       INIT_LIST_HEAD(&pmu->format);
+       INIT_LIST_HEAD(&pmu->caps);
+
+       pmu->name = strdup(name);
+       if (!pmu->name)
+               return -ENOMEM;
+
+       pmu->aliases = hashmap__new(aliases__hash, aliases__equal, /*ctx=*/ NULL);
+       if (!pmu->aliases)
+               return -ENOMEM;
+
+       return 0;
+}
+
 struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *name,
                                  bool eager_load)
 {
        struct perf_pmu *pmu;
-       __u32 type;
 
        pmu = zalloc(sizeof(*pmu));
        if (!pmu)
                return NULL;
 
-       pmu->name = strdup(name);
-       if (!pmu->name)
-               goto err;
+       if (perf_pmu__init(pmu, PERF_PMU_TYPE_FAKE, name) != 0) {
+               perf_pmu__delete(pmu);
+               return NULL;
+       }
 
        /*
         * Read type early to fail fast if a lookup name isn't a PMU. Ensure
         * that type value is successfully assigned (return 1).
         */
-       if (perf_pmu__scan_file_at(pmu, dirfd, "type", "%u", &type) != 1)
-               goto err;
-
-       INIT_LIST_HEAD(&pmu->format);
-       INIT_LIST_HEAD(&pmu->aliases);
-       INIT_LIST_HEAD(&pmu->caps);
+       if (perf_pmu__scan_file_at(pmu, dirfd, "type", "%u", &pmu->type) != 1) {
+               perf_pmu__delete(pmu);
+               return NULL;
+       }
 
        /*
         * The pmu data we store & need consists of the pmu
         * type value and format definitions. Load both right
         * now.
         */
-       if (pmu_format(pmu, dirfd, name, eager_load))
-               goto err;
+       if (pmu_format(pmu, dirfd, name, eager_load)) {
+               perf_pmu__delete(pmu);
+               return NULL;
+       }
 
        pmu->is_core = is_pmu_core(name);
        pmu->cpus = pmu_cpumask(dirfd, name, pmu->is_core);
 
-       pmu->type = type;
        pmu->is_uncore = pmu_is_uncore(dirfd, name);
        if (pmu->is_uncore)
                pmu->id = pmu_id(name);
@@ -1194,10 +1238,6 @@ struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char
                pmu_aliases_parse_eager(pmu, dirfd);
 
        return pmu;
-err:
-       zfree(&pmu->name);
-       free(pmu);
-       return NULL;
 }
 
 /* Creates the PMU when sysfs scanning fails. */
@@ -1219,7 +1259,7 @@ struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pm
        pmu->cpus = cpu_map__online();
 
        INIT_LIST_HEAD(&pmu->format);
-       INIT_LIST_HEAD(&pmu->aliases);
+       pmu->aliases = hashmap__new(aliases__hash, aliases__equal, /*ctx=*/ NULL);
        INIT_LIST_HEAD(&pmu->caps);
        list_add_tail(&pmu->list, core_pmus);
        return pmu;
@@ -1979,13 +2019,14 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
                             void *state, pmu_event_callback cb)
 {
        char buf[1024];
-       struct perf_pmu_alias *event;
        struct pmu_event_info info = {
                .pmu = pmu,
                .event_type_desc = "Kernel PMU event",
        };
        int ret = 0;
        struct strbuf sb;
+       struct hashmap_entry *entry;
+       size_t bkt;
 
        if (perf_pmu__is_hwmon(pmu))
                return hwmon_pmu__for_each_event(pmu, state, cb);
@@ -1993,7 +2034,8 @@ int perf_pmu__for_each_event(struct perf_pmu *pmu, bool skip_duplicate_pmus,
        strbuf_init(&sb, /*hint=*/ 0);
        pmu_aliases_parse(pmu);
        pmu_add_cpu_aliases(pmu);
-       list_for_each_entry(event, &pmu->aliases, list) {
+       hashmap__for_each_entry(pmu->aliases, entry, bkt) {
+               struct perf_pmu_alias *event = entry->pvalue;
                size_t buf_used, pmu_name_len;
 
                if (perf_pmu__is_tool(pmu) && tool_pmu__skip_event(event->name))
@@ -2461,6 +2503,9 @@ int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename,
 
 void perf_pmu__delete(struct perf_pmu *pmu)
 {
+       if (!pmu)
+               return;
+
        if (perf_pmu__is_hwmon(pmu))
                hwmon_pmu__exit(pmu);
 
@@ -2478,14 +2523,16 @@ void perf_pmu__delete(struct perf_pmu *pmu)
 
 const char *perf_pmu__name_from_config(struct perf_pmu *pmu, u64 config)
 {
-       struct perf_pmu_alias *event;
+       struct hashmap_entry *entry;
+       size_t bkt;
 
        if (!pmu)
                return NULL;
 
        pmu_aliases_parse(pmu);
        pmu_add_cpu_aliases(pmu);
-       list_for_each_entry(event, &pmu->aliases, list) {
+       hashmap__for_each_entry(pmu->aliases, entry, bkt) {
+               struct perf_pmu_alias *event = entry->pvalue;
                struct perf_event_attr attr = {.config = 0,};
 
                int ret = perf_pmu__config(pmu, &attr, &event->terms, /*apply_hardcoded=*/true,
index a1fdd6d50c53ffbe63684c0560e2d1569422208f..71b8636fd07d42f3b0b7057bf874bdb1deb821fc 100644 (file)
@@ -14,6 +14,7 @@
 #include "mem-events.h"
 
 struct evsel_config_term;
+struct hashmap;
 struct perf_cpu_map;
 struct print_callbacks;
 
@@ -125,7 +126,7 @@ struct perf_pmu {
         * event read from <sysfs>/bus/event_source/devices/<name>/events/ or
         * from json events in pmu-events.c.
         */
-       struct list_head aliases;
+       struct hashmap *aliases;
        /**
         * @events_table: The events table for json events in pmu-events.c.
         */
@@ -294,6 +295,7 @@ int perf_pmu__pathname_scnprintf(char *buf, size_t size,
 int perf_pmu__event_source_devices_fd(void);
 int perf_pmu__pathname_fd(int dirfd, const char *pmu_name, const char *filename, int flags);
 
+int perf_pmu__init(struct perf_pmu *pmu, __u32 type, const char *name);
 struct perf_pmu *perf_pmu__lookup(struct list_head *pmus, int dirfd, const char *lookup_name,
                                  bool eager_load);
 struct perf_pmu *perf_pmu__create_placeholder_core_pmu(struct list_head *core_pmus);
index 727a10e3f990014949beab841b592fc88c57f823..4630b8cc8e52934f9f26357d65601efffaeb10ce 100644 (file)
@@ -502,19 +502,12 @@ struct perf_pmu *tool_pmu__new(void)
        struct perf_pmu *tool = zalloc(sizeof(struct perf_pmu));
 
        if (!tool)
-               goto out;
-       tool->name = strdup("tool");
-       if (!tool->name) {
-               zfree(&tool);
-               goto out;
-       }
+               return NULL;
 
-       tool->type = PERF_PMU_TYPE_TOOL;
-       INIT_LIST_HEAD(&tool->aliases);
-       INIT_LIST_HEAD(&tool->caps);
-       INIT_LIST_HEAD(&tool->format);
+       if (perf_pmu__init(tool, PERF_PMU_TYPE_TOOL, "tool") != 0) {
+               perf_pmu__delete(tool);
+               return NULL;
+       }
        tool->events_table = find_core_events_table("common", "common");
-
-out:
        return tool;
 }