* The test cpu/soc is provided for testing.
  */
 #include "pmu-events/pmu-events.h"
+#include "util/header.h"
+#include "util/pmu.h"
 #include <string.h>
 #include <stddef.h>
 
        },
 };
 
-const struct pmu_events_map pmu_events_map[] = {
+
+/*
+ * Map a CPU to its table of PMU events. The CPU is identified by the
+ * cpuid field, which is an arch-specific identifier for the CPU.
+ * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
+ * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
+ *
+ * The  cpuid can contain any character other than the comma.
+ */
+struct pmu_events_map {
+       const char *arch;
+       const char *cpuid;
+       const struct pmu_event *table;
+};
+
+/*
+ * Global table mapping each known CPU for the architecture to its
+ * table of PMU events.
+ */
+static const struct pmu_events_map pmu_events_map[] = {
        {
                .arch = "testarch",
                .cpuid = "testcpu",
        },
 };
 
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+{
+       const struct pmu_event *table = NULL;
+       char *cpuid = perf_pmu__getcpuid(pmu);
+       int i;
+
+       /* on some platforms which uses cpus map, cpuid can be NULL for
+        * PMUs other than CORE PMUs.
+        */
+       if (!cpuid)
+               return NULL;
+
+       i = 0;
+       for (;;) {
+               const struct pmu_events_map *map = &pmu_events_map[i++];
+
+               if (!map->table)
+                       break;
+
+               if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
+                       table = map->table;
+                       break;
+               }
+       }
+       free(cpuid);
+       return table;
+}
+
+const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+{
+       for (const struct pmu_events_map *tables = &pmu_events_map[0];
+            tables->table;
+            tables++) {
+               if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
+                       return tables->table;
+       }
+       return NULL;
+}
+
+int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
+{
+       for (const struct pmu_events_map *tables = &pmu_events_map[0];
+            tables->table;
+            tables++) {
+               for (const struct pmu_event *pe = &tables->table[0];
+                    pe->name || pe->metric_group || pe->metric_name;
+                    pe++) {
+                       int ret = fn(pe, &tables->table[0], data);
+
+                       if (ret)
+                               return ret;
+               }
+       }
+       return 0;
+}
+
 const struct pmu_event *find_sys_events_table(const char *name)
 {
        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
                for (const struct pmu_event *pe = &tables->table[0];
                     pe->name || pe->metric_group || pe->metric_name;
                     pe++) {
-                       int ret = fn(pe, data);
+                       int ret = fn(pe, &tables->table[0], data);
 
                        if (ret)
                                return ret;
 
 
 def print_mapping_table(archs: Sequence[str]) -> None:
   """Read the mapfile and generate the struct from cpuid string to event table."""
-  _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
+  _args.output_file.write("""
+/*
+ * Map a CPU to its table of PMU events. The CPU is identified by the
+ * cpuid field, which is an arch-specific identifier for the CPU.
+ * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
+ * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
+ *
+ * The  cpuid can contain any character other than the comma.
+ */
+struct pmu_events_map {
+        const char *arch;
+        const char *cpuid;
+        const struct pmu_event *table;
+};
+
+/*
+ * Global table mapping each known CPU for the architecture to its
+ * table of PMU events.
+ */
+const struct pmu_events_map pmu_events_map[] = {
+""")
   for arch in archs:
     if arch == 'test':
       _args.output_file.write("""{
 \t},
 };
 
+const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
+{
+        const struct pmu_event *table = NULL;
+        char *cpuid = perf_pmu__getcpuid(pmu);
+        int i;
+
+        /* on some platforms which uses cpus map, cpuid can be NULL for
+         * PMUs other than CORE PMUs.
+         */
+        if (!cpuid)
+                return NULL;
+
+        i = 0;
+        for (;;) {
+                const struct pmu_events_map *map = &pmu_events_map[i++];
+                if (!map->table)
+                        break;
+
+                if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
+                        table = map->table;
+                        break;
+                }
+        }
+        free(cpuid);
+        return table;
+}
+
+const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
+{
+        for (const struct pmu_events_map *tables = &pmu_events_map[0];
+             tables->table;
+             tables++) {
+                if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
+                        return tables->table;
+        }
+        return NULL;
+}
+
+int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
+{
+        for (const struct pmu_events_map *tables = &pmu_events_map[0];
+             tables->table;
+             tables++) {
+                for (const struct pmu_event *pe = &tables->table[0];
+                     pe->name || pe->metric_group || pe->metric_name;
+                     pe++) {
+                        int ret = fn(pe, &tables->table[0], data);
+
+                        if (ret)
+                                return ret;
+                }
+        }
+        return 0;
+}
+
 const struct pmu_event *find_sys_events_table(const char *name)
 {
         for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
                 for (const struct pmu_event *pe = &tables->table[0];
                      pe->name || pe->metric_group || pe->metric_name;
                      pe++) {
-                        int ret = fn(pe, data);
+                        int ret = fn(pe, &tables->table[0], data);
 
                         if (ret)
                                 return ret;
 
   _args.output_file.write("""
 #include "pmu-events/pmu-events.h"
+#include "util/header.h"
+#include "util/pmu.h"
 #include <string.h>
 #include <stddef.h>
 
 
        return !strcmp(reference, test);
 }
 
-static const struct pmu_event *__test_pmu_get_events_table(void)
-{
-       for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
-               if (!strcmp(map->cpuid, "testcpu"))
-                       return map->table;
-       }
-
-       pr_err("could not find test events map\n");
-
-       return NULL;
-}
-
 static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event *e2)
 {
        if (!is_same(e1->name, e2->name)) {
                                 int subtest __maybe_unused)
 {
        const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
-       const struct pmu_event *table = __test_pmu_get_events_table();
+       const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
        int map_events = 0, expected_events;
 
        /* ignore 3x sentinels */
        struct perf_pmu *pmu;
        LIST_HEAD(aliases);
        int res = 0;
-       const struct pmu_event *table = __test_pmu_get_events_table();
+       const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
        struct perf_pmu_alias *a, *tmp;
 
        if (!table)
        LIST_HEAD(aliases);
        int res = 0;
 
-       events_table = __test_pmu_get_events_table();
+       events_table = find_core_events_table("testarch", "testcpu");
        if (!events_table)
                return -1;
        pmu_add_cpu_aliases_table(&aliases, pmu, events_table);
        return ret;
 }
 
-static void expr_failure(const char *msg, const struct pmu_event *pe)
-{
-       pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
-}
-
 struct metric {
        struct list_head list;
        struct metric_ref metric_ref;
 
 }
 
-static int test__parsing(struct test_suite *test __maybe_unused,
-                        int subtest __maybe_unused)
+static void expr_failure(const char *msg, const struct pmu_event *pe)
 {
-       const struct pmu_event *cpus_table = pmu_events_table__find();
-       const struct pmu_event *pe;
-       int i, j, k;
-       int ret = 0;
+       pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
+}
+
+
+struct test__parsing_data {
+       const struct pmu_event *cpus_table;
        struct expr_parse_ctx *ctx;
+       int failures;
+};
+
+static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_event *table,
+                                 void *vdata)
+{
+       struct test__parsing_data *data = vdata;
+       struct metric *metric, *tmp;
+       struct hashmap_entry *cur;
+       LIST_HEAD(compound_list);
+       size_t bkt;
+       int k;
        double result;
 
-       ctx = expr__ctx_new();
-       if (!ctx) {
-               pr_debug("expr__ctx_new failed");
-               return TEST_FAIL;
+       if (!pe->metric_expr)
+               return 0;
+
+       pr_debug("Found metric '%s'\n", pe->metric_name);
+
+       expr__ctx_clear(data->ctx);
+       if (expr__find_ids(pe->metric_expr, NULL, data->ctx) < 0) {
+               expr_failure("Parse find ids failed", pe);
+               data->failures++;
+               return 0;
        }
-       i = 0;
-       for (;;) {
-               const struct pmu_events_map *map = &pmu_events_map[i++];
 
-               if (!map->table)
-                       break;
-               j = 0;
-               for (;;) {
-                       struct metric *metric, *tmp;
-                       struct hashmap_entry *cur;
-                       LIST_HEAD(compound_list);
-                       size_t bkt;
-
-                       pe = &map->table[j++];
-                       if (!pe->name && !pe->metric_group && !pe->metric_name)
-                               break;
-                       if (!pe->metric_expr)
-                               continue;
-                       expr__ctx_clear(ctx);
-                       if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
-                               expr_failure("Parse find ids failed", pe);
-                               ret++;
-                               continue;
-                       }
+       if (resolve_metric_simple(data->ctx, &compound_list, table,
+                                 pe->metric_name)) {
+               expr_failure("Could not resolve metrics", pe);
+               data->failures++;
+               return TEST_FAIL; /* Don't tolerate errors due to severity */
+       }
 
-                       if (resolve_metric_simple(ctx, &compound_list, map->table,
-                                                 pe->metric_name)) {
-                               expr_failure("Could not resolve metrics", pe);
-                               ret++;
-                               goto exit; /* Don't tolerate errors due to severity */
-                       }
+       /*
+        * Add all ids with a made up value. The value may trigger divide by
+        * zero when subtracted and so try to make them unique.
+        */
+       k = 1;
+       hashmap__for_each_entry(data->ctx->ids, cur, bkt)
+               expr__add_id_val(data->ctx, strdup(cur->key), k++);
 
-                       /*
-                        * Add all ids with a made up value. The value may
-                        * trigger divide by zero when subtracted and so try to
-                        * make them unique.
-                        */
-                       k = 1;
-                       hashmap__for_each_entry(ctx->ids, cur, bkt)
-                               expr__add_id_val(ctx, strdup(cur->key), k++);
-
-                       hashmap__for_each_entry(ctx->ids, cur, bkt) {
-                               if (check_parse_cpu(cur->key, map->table == cpus_table,
-                                                  pe))
-                                       ret++;
-                       }
+       hashmap__for_each_entry(data->ctx->ids, cur, bkt) {
+               if (check_parse_cpu(cur->key, table == data->cpus_table, pe))
+                       data->failures++;
+       }
 
-                       list_for_each_entry_safe(metric, tmp, &compound_list, list) {
-                               expr__add_ref(ctx, &metric->metric_ref);
-                               free(metric);
-                       }
+       list_for_each_entry_safe(metric, tmp, &compound_list, list) {
+               expr__add_ref(data->ctx, &metric->metric_ref);
+               free(metric);
+       }
 
-                       if (expr__parse(&result, ctx, pe->metric_expr)) {
-                               /*
-                                * Parsing failed, make numbers go from large to
-                                * small which can resolve divide by zero
-                                * issues.
-                                */
-                               k = 1024;
-                               hashmap__for_each_entry(ctx->ids, cur, bkt)
-                                       expr__add_id_val(ctx, strdup(cur->key), k--);
-                               if (expr__parse(&result, ctx, pe->metric_expr)) {
-                                       expr_failure("Parse failed", pe);
-                                       ret++;
-                               }
-                       }
+       if (expr__parse(&result, data->ctx, pe->metric_expr)) {
+               /*
+                * Parsing failed, make numbers go from large to small which can
+                * resolve divide by zero issues.
+                */
+               k = 1024;
+               hashmap__for_each_entry(data->ctx->ids, cur, bkt)
+                       expr__add_id_val(data->ctx, strdup(cur->key), k--);
+               if (expr__parse(&result, data->ctx, pe->metric_expr)) {
+                       expr_failure("Parse failed", pe);
+                       data->failures++;
                }
        }
-       expr__ctx_free(ctx);
-       /* TODO: fail when not ok */
-exit:
-       return ret == 0 ? TEST_OK : TEST_SKIP;
+       return 0;
+}
+
+static int test__parsing(struct test_suite *test __maybe_unused,
+                        int subtest __maybe_unused)
+{
+       struct test__parsing_data data = {
+               .cpus_table = pmu_events_table__find(),
+               .ctx = expr__ctx_new(),
+               .failures = 0,
+       };
+
+       if (!data.ctx) {
+               pr_debug("expr__ctx_new failed");
+               return TEST_FAIL;
+       }
+       pmu_for_each_core_event(test__parsing_callback, &data);
+       pmu_for_each_sys_event(test__parsing_callback, &data);
+
+       expr__ctx_free(data.ctx);
+       return data.failures == 0 ? TEST_OK : TEST_FAIL;
 }
 
 struct test_metric {
        return ret;
 }
 
+static int test__parsing_fake_callback(const struct pmu_event *pe,
+                                      const struct pmu_event *table __maybe_unused,
+                                      void *data __maybe_unused)
+{
+       if (!pe->metric_expr)
+               return 0;
+
+       return metric_parse_fake(pe->metric_expr);
+}
+
 /*
  * Parse all the metrics for current architecture,
  * or all defined cpus via the 'fake_pmu'
 static int test__parsing_fake(struct test_suite *test __maybe_unused,
                              int subtest __maybe_unused)
 {
-       unsigned int i, j;
        int err = 0;
 
-       for (i = 0; i < ARRAY_SIZE(metrics); i++) {
+       for (size_t i = 0; i < ARRAY_SIZE(metrics); i++) {
                err = metric_parse_fake(metrics[i].str);
                if (err)
                        return err;
        }
 
-       i = 0;
-       for (;;) {
-               const struct pmu_events_map *map = &pmu_events_map[i++];
+       err = pmu_for_each_core_event(test__parsing_fake_callback, NULL);
+       if (err)
+               return err;
 
-               if (!map->table)
-                       break;
-               j = 0;
-               for (;;) {
-                       const struct pmu_event *pe = &map->table[j++];
-
-                       if (!pe->name && !pe->metric_group && !pe->metric_name)
-                               break;
-                       if (!pe->metric_expr)
-                               continue;
-                       pr_debug("Found metric '%s' for '%s'\n", pe->metric_name, map->cpuid);
-                       err = metric_parse_fake(pe->metric_expr);
-                       if (err)
-                               return err;
-               }
-       }
-
-       return 0;
+       return pmu_for_each_sys_event(test__parsing_fake_callback, NULL);
 }
 
 static struct test_case pmu_events_tests[] = {