evlist__for_each_entry(evlist, evsel) {
                if (evsel__is_aux_event(evsel)) {
-                       if (!strstarts(evsel->pmu_name, ARM_SPE_PMU_NAME)) {
+                       if (!strstarts(evsel->pmu->name, ARM_SPE_PMU_NAME)) {
                                pr_err("Found unexpected auxtrace event: %s\n",
-                                      evsel->pmu_name);
+                                      evsel->pmu->name);
                                return -EINVAL;
                        }
                        opts->full_auxtrace = true;
 
                return  scnprintf(bf, size, "%s", event_name);
 
        return scnprintf(bf, size, "%s/%s/",
-                        evsel->pmu_name ? evsel->pmu_name : "cpu",
+                        evsel->pmu ? evsel->pmu->name : "cpu",
                         event_name);
 }
 
                return 0;
 
        if (!evsel->core.attr.precise_ip &&
-           !(evsel->pmu_name && !strncmp(evsel->pmu_name, "ibs", 3)))
+           !(evsel->pmu && !strncmp(evsel->pmu->name, "ibs", 3)))
                return 0;
 
        /* More verbose IBS errors. */
 
 
        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
        TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type ||
-                                     strcmp(evsel->pmu_name, "cpu"));
+                                     strcmp(evsel->pmu->name, "cpu"));
        TEST_ASSERT_VAL("wrong exclude_user",
                        !evsel->core.attr.exclude_user);
        TEST_ASSERT_VAL("wrong exclude_kernel",
 
                else
                        attributes = empty_attributes;
 
-               if (asprintf(&new_name, "%s/%s/%s", pos->pmu_name, pos->name, attributes + 1)) {
+               if (asprintf(&new_name, "%s/%s/%s", pos->pmu ? pos->pmu->name : "",
+                            pos->name, attributes + 1)) {
                        free(pos->name);
                        pos->name = new_name;
                } else {
 
        evsel->metric_events = NULL;
        evsel->per_pkg_mask  = NULL;
        evsel->collect_stat  = false;
-       evsel->pmu_name      = NULL;
        evsel->group_pmu_name = NULL;
        evsel->skippable     = false;
        evsel->alternate_hw_config = PERF_COUNT_HW_MAX;
                if (evsel->group_name == NULL)
                        goto out_err;
        }
-       if (orig->pmu_name) {
-               evsel->pmu_name = strdup(orig->pmu_name);
-               if (evsel->pmu_name == NULL)
-                       goto out_err;
-       }
        if (orig->group_pmu_name) {
                evsel->group_pmu_name = strdup(orig->group_pmu_name);
                if (evsel->group_pmu_name == NULL)
        zfree(&evsel->group_name);
        zfree(&evsel->name);
        zfree(&evsel->filter);
-       zfree(&evsel->pmu_name);
        zfree(&evsel->group_pmu_name);
        zfree(&evsel->unit);
        zfree(&evsel->metric_id);
 
        struct {
                char                    *name;
                char                    *group_name;
-               const char              *pmu_name;
                const char              *group_pmu_name;
 #ifdef HAVE_LIBTRACEEVENT
                struct tep_event        *tp_format;
        unsigned long           open_flags;
        int                     precise_ip_original;
 
-       /* for missing_features */
+       /* The PMU the event is from. Used for missing_features, PMU name, etc. */
        struct perf_pmu         *pmu;
 
        /* For tool events */
 
                struct expr_id_data *val_ptr;
 
                /* Don't match events for the wrong hybrid PMU. */
-               if (!all_pmus && ev->pmu_name && evsel__is_hybrid(ev) &&
-                   strcmp(ev->pmu_name, pmu))
+               if (!all_pmus && ev->pmu && evsel__is_hybrid(ev) &&
+                   strcmp(ev->pmu->name, pmu))
                        continue;
                /*
                 * Check for duplicate events with the same name. For
 
        evsel->core.is_pmu_core = pmu ? pmu->is_core : false;
        evsel->auto_merge_stats = auto_merge_stats;
        evsel->pmu = pmu;
-       evsel->pmu_name = pmu ? strdup(pmu->name) : NULL;
        evsel->alternate_hw_config = alternate_hw_config;
 
        if (name)
 
 {
        bool need_full_name = perf_pmus__num_core_pmus() > 1;
        static const char *last_name;
-       static const char *last_pmu;
+       static const struct perf_pmu *last_pmu;
        char full_name[64];
 
        /*
         * different metric events.
         */
        if (last_name && !strcmp(last_name, name)) {
-               if (!need_full_name || !strcmp(last_pmu, evsel->pmu_name)) {
+               if (!need_full_name || last_pmu != evsel->pmu) {
                        out->print_metricgroup_header(config, ctxp, NULL);
                        return;
                }
        }
 
-       if (need_full_name)
-               scnprintf(full_name, sizeof(full_name), "%s (%s)", name, evsel->pmu_name);
+       if (need_full_name && evsel->pmu)
+               scnprintf(full_name, sizeof(full_name), "%s (%s)", name, evsel->pmu->name);
        else
                scnprintf(full_name, sizeof(full_name), "%s", name);
 
        out->print_metricgroup_header(config, ctxp, full_name);
 
        last_name = name;
-       last_pmu = evsel->pmu_name;
+       last_pmu = evsel->pmu;
 }
 
 /**
 
        if (evsel__is_clock(evsel_a) != evsel__is_clock(evsel_b))
                return false;
 
-       return !!strcmp(evsel_a->pmu_name, evsel_b->pmu_name);
+       return evsel_a->pmu != evsel_b->pmu;
 }
 
 static void evsel__merge_aliases(struct evsel *evsel)