perf_stat__print_shadow_stats(&stat_config, ev2,
                                                      evsel_script(ev2)->val,
                                                      sample->cpu,
-                                                     &ctx,
-                                                     NULL);
+                                                     &ctx);
                }
                evsel_script(leader)->gnum = 0;
        }
 
                                                stat_config.metric_no_threshold,
                                                stat_config.user_requested_cpu_list,
                                                stat_config.system_wide,
-                                               stat_config.hardware_aware_grouping,
-                                               &stat_config.metric_events);
+                                               stat_config.hardware_aware_grouping);
                goto out;
        }
 
                                                stat_config.metric_no_threshold,
                                                stat_config.user_requested_cpu_list,
                                                stat_config.system_wide,
-                                               stat_config.hardware_aware_grouping,
-                                               &stat_config.metric_events);
+                                               stat_config.hardware_aware_grouping);
                goto out;
        }
 
                                                /*metric_no_threshold=*/true,
                                                stat_config.user_requested_cpu_list,
                                                stat_config.system_wide,
-                                               stat_config.hardware_aware_grouping,
-                                               &stat_config.metric_events) < 0) {
+                                               stat_config.hardware_aware_grouping) < 0) {
                        ret = -1;
                        goto out;
                }
                                                        /*metric_no_threshold=*/true,
                                                        stat_config.user_requested_cpu_list,
                                                        stat_config.system_wide,
-                                                       stat_config.hardware_aware_grouping,
-                                                       &stat_config.metric_events) < 0) {
+                                                       stat_config.hardware_aware_grouping) < 0) {
                                ret = -1;
                                goto out;
                        }
                                evsel->default_metricgroup = true;
 
                        evlist__splice_list_tail(evlist, &metric_evlist->core.entries);
+                       metricgroup__copy_metric_events(evlist, /*cgrp=*/NULL,
+                                                       &evlist->metric_events,
+                                                       &metric_evlist->metric_events);
                        evlist__delete(metric_evlist);
                }
        }
        }
        parse_events_error__exit(&err);
        evlist__splice_list_tail(evsel_list, &evlist->core.entries);
+       metricgroup__copy_metric_events(evsel_list, /*cgrp=*/NULL,
+                                       &evsel_list->metric_events,
+                                       &evlist->metric_events);
        evlist__delete(evlist);
        return ret;
 }
                                                stat_config.metric_no_threshold,
                                                stat_config.user_requested_cpu_list,
                                                stat_config.system_wide,
-                                               stat_config.hardware_aware_grouping,
-                                               &stat_config.metric_events);
+                                               stat_config.hardware_aware_grouping);
 
                zfree(&metrics);
                if (ret) {
                        goto out;
                }
 
-               if (evlist__expand_cgroup(evsel_list, stat_config.cgroup_list,
-                                         &stat_config.metric_events, true) < 0) {
+               if (evlist__expand_cgroup(evsel_list, stat_config.cgroup_list, true) < 0) {
                        parse_options_usage(stat_usage, stat_options,
                                            "for-each-cgroup", 0);
                        goto out;
 
        evlist__delete(evsel_list);
 
-       metricgroup__rblist_exit(&stat_config.metric_events);
        evlist__close_control(stat_config.ctl_fd, stat_config.ctl_fd_ack, &stat_config.ctl_fd_close);
 
        return status;
 
 #include <stdlib.h>
 #include <string.h>
 
-static int test_expand_events(struct evlist *evlist,
-                             struct rblist *metric_events)
+static int test_expand_events(struct evlist *evlist)
 {
        int i, ret = TEST_FAIL;
        int nr_events;
        was_group_event = evsel__is_group_event(evlist__first(evlist));
        nr_members = evlist__first(evlist)->core.nr_members;
 
-       ret = evlist__expand_cgroup(evlist, cgrp_str, metric_events, false);
+       ret = evlist__expand_cgroup(evlist, cgrp_str, false);
        if (ret < 0) {
                pr_debug("failed to expand events for cgroups\n");
                goto out;
 static int expand_default_events(void)
 {
        int ret;
-       struct rblist metric_events;
        struct evlist *evlist = evlist__new_default();
 
        TEST_ASSERT_VAL("failed to get evlist", evlist);
 
-       rblist__init(&metric_events);
-       ret = test_expand_events(evlist, &metric_events);
+       ret = test_expand_events(evlist);
        evlist__delete(evlist);
        return ret;
 }
 {
        int ret;
        struct evlist *evlist;
-       struct rblist metric_events;
        struct parse_events_error err;
        const char event_str[] = "{cycles,instructions}";
 
                goto out;
        }
 
-       rblist__init(&metric_events);
-       ret = test_expand_events(evlist, &metric_events);
+       ret = test_expand_events(evlist);
 out:
        parse_events_error__exit(&err);
        evlist__delete(evlist);
 {
        int ret;
        struct evlist *evlist;
-       struct rblist metric_events;
        const char event_str[] = "CYCLES";
        struct option opt = {
                .value = &evlist,
                goto out;
        }
 
-       rblist__init(&metric_events);
-       ret = test_expand_events(evlist, &metric_events);
+       ret = test_expand_events(evlist);
 out:
        evlist__delete(evlist);
        return ret;
 {
        int ret;
        struct evlist *evlist;
-       struct rblist metric_events;
        const char metric_str[] = "CPI";
        const struct pmu_metrics_table *pme_test;
 
        evlist = evlist__new();
        TEST_ASSERT_VAL("failed to get evlist", evlist);
 
-       rblist__init(&metric_events);
        pme_test = find_core_metrics_table("testarch", "testcpu");
-       ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str, &metric_events);
+       ret = metricgroup__parse_groups_test(evlist, pme_test, metric_str);
        if (ret < 0) {
                pr_debug("failed to parse '%s' metric\n", metric_str);
                goto out;
        }
 
-       ret = test_expand_events(evlist, &metric_events);
+       ret = test_expand_events(evlist);
 
 out:
-       metricgroup__rblist_exit(&metric_events);
        evlist__delete(evlist);
        return ret;
 }
 
        }
 }
 
-static double compute_single(struct rblist *metric_events, struct evlist *evlist,
-                            const char *name)
+static double compute_single(struct evlist *evlist, const char *name)
 {
        struct metric_expr *mexp;
        struct metric_event *me;
        struct evsel *evsel;
 
        evlist__for_each_entry(evlist, evsel) {
-               me = metricgroup__lookup(metric_events, evsel, false);
+               me = metricgroup__lookup(&evlist->metric_events, evsel, false);
                if (me != NULL) {
                        list_for_each_entry (mexp, &me->head, nd) {
                                if (strcmp(mexp->metric_name, name))
                            const char *name1, double *ratio1,
                            const char *name2, double *ratio2)
 {
-       struct rblist metric_events = {
-               .nr_entries = 0,
-       };
        const struct pmu_metrics_table *pme_test;
        struct perf_cpu_map *cpus;
        struct evlist *evlist;
 
        /* Parse the metric into metric_events list. */
        pme_test = find_core_metrics_table("testarch", "testcpu");
-       err = metricgroup__parse_groups_test(evlist, pme_test, name,
-                                            &metric_events);
+       err = metricgroup__parse_groups_test(evlist, pme_test, name);
        if (err)
                goto out;
 
 
        /* And execute the metric */
        if (name1 && ratio1)
-               *ratio1 = compute_single(&metric_events, evlist, name1);
+               *ratio1 = compute_single(evlist, name1);
        if (name2 && ratio2)
-               *ratio2 = compute_single(&metric_events, evlist, name2);
+               *ratio2 = compute_single(evlist, name2);
 
 out:
        /* ... cleanup. */
-       metricgroup__rblist_exit(&metric_events);
        evlist__free_stats(evlist);
        perf_cpu_map__put(cpus);
        evlist__delete(evlist);
 
        struct evlist *evlist;
        struct perf_cpu_map *cpus;
        struct evsel *evsel;
-       struct rblist metric_events = {
-               .nr_entries = 0,
-       };
        int err = 0;
 
        if (!pm->metric_expr)
 
        perf_evlist__set_maps(&evlist->core, cpus, NULL);
 
-       err = metricgroup__parse_groups_test(evlist, table, pm->metric_name, &metric_events);
+       err = metricgroup__parse_groups_test(evlist, table, pm->metric_name);
        if (err) {
                if (!strcmp(pm->metric_name, "M1") || !strcmp(pm->metric_name, "M2") ||
                    !strcmp(pm->metric_name, "M3")) {
                k++;
        }
        evlist__for_each_entry(evlist, evsel) {
-               struct metric_event *me = metricgroup__lookup(&metric_events, evsel, false);
+               struct metric_event *me = metricgroup__lookup(&evlist->metric_events, evsel, false);
 
                if (me != NULL) {
                        struct metric_expr *mexp;
                pr_debug("Broken metric %s\n", pm->metric_name);
 
        /* ... cleanup. */
-       metricgroup__rblist_exit(&metric_events);
        evlist__free_stats(evlist);
        perf_cpu_map__put(cpus);
        evlist__delete(evlist);
 
        return !!strpbrk(str, "{}[]()|*+?^$");
 }
 
-int evlist__expand_cgroup(struct evlist *evlist, const char *str,
-                         struct rblist *metric_events, bool open_cgroup)
+int evlist__expand_cgroup(struct evlist *evlist, const char *str, bool open_cgroup)
 {
        struct evlist *orig_list, *tmp_list;
        struct evsel *pos, *evsel, *leader;
        evlist__splice_list_tail(orig_list, &evlist->core.entries);
        evlist->core.nr_entries = 0;
 
-       if (metric_events) {
-               orig_metric_events = *metric_events;
-               rblist__init(metric_events);
-       } else {
-               rblist__init(&orig_metric_events);
-       }
+       orig_metric_events = evlist->metric_events;
+       metricgroup__rblist_init(&evlist->metric_events);
 
        if (has_pattern_string(str))
                prefix_len = match_cgroups(str);
                cgroup__put(cgrp);
                nr_cgroups++;
 
-               if (metric_events) {
-                       if (metricgroup__copy_metric_events(tmp_list, cgrp,
-                                                           metric_events,
-                                                           &orig_metric_events) < 0)
-                               goto out_err;
-               }
+               if (metricgroup__copy_metric_events(tmp_list, cgrp,
+                                                   &evlist->metric_events,
+                                                   &orig_metric_events) < 0)
+                       goto out_err;
 
                evlist__splice_list_tail(evlist, &tmp_list->core.entries);
                tmp_list->core.nr_entries = 0;
 out_err:
        evlist__delete(orig_list);
        evlist__delete(tmp_list);
-       rblist__exit(&orig_metric_events);
+       metricgroup__rblist_exit(&orig_metric_events);
        release_cgroup_list();
 
        return ret;
 
 
 struct cgroup *cgroup__new(const char *name, bool do_open);
 struct cgroup *evlist__findnew_cgroup(struct evlist *evlist, const char *name);
-int evlist__expand_cgroup(struct evlist *evlist, const char *cgroups,
-                         struct rblist *metric_events, bool open_cgroup);
+int evlist__expand_cgroup(struct evlist *evlist, const char *cgroups, bool open_cgroup);
 
 void evlist__set_default_cgroup(struct evlist *evlist, struct cgroup *cgroup);
 
 
 #include "util/util.h"
 #include "util/env.h"
 #include "util/intel-tpebs.h"
+#include "util/metricgroup.h"
 #include "util/strbuf.h"
 #include <signal.h>
 #include <unistd.h>
        evlist->ctl_fd.ack = -1;
        evlist->ctl_fd.pos = -1;
        evlist->nr_br_cntr = -1;
+       metricgroup__rblist_init(&evlist->metric_events);
 }
 
 struct evlist *evlist__new(void)
 
 void evlist__exit(struct evlist *evlist)
 {
+       metricgroup__rblist_exit(&evlist->metric_events);
        event_enable_timer__exit(&evlist->eet);
        zfree(&evlist->mmap);
        zfree(&evlist->overwrite_mmap);
 
 #include <perf/evlist.h>
 #include "events_stats.h"
 #include "evsel.h"
+#include "rblist.h"
 #include <pthread.h>
 #include <signal.h>
 #include <unistd.h>
                int     pos;    /* index at evlist core object to check signals */
        } ctl_fd;
        struct event_enable_timer *eet;
+       /**
+        * @metric_events: A list of struct metric_event which each have a list
+        * of struct metric_expr.
+        */
+       struct rblist   metric_events;
 };
 
 struct evsel_str_handler {
 
        free(me);
 }
 
-static void metricgroup__rblist_init(struct rblist *metric_events)
+void metricgroup__rblist_init(struct rblist *metric_events)
 {
        rblist__init(metric_events);
        metric_events->node_cmp = metric_event_cmp;
                        const char *user_requested_cpu_list,
                        bool system_wide,
                        bool fake_pmu,
-                       struct rblist *metric_events_list,
                        const struct pmu_metrics_table *table)
 {
        struct evlist *combined_evlist = NULL;
        bool is_default = !strcmp(str, "Default");
        int ret;
 
-       if (metric_events_list->nr_entries == 0)
-               metricgroup__rblist_init(metric_events_list);
        ret = metricgroup__add_metric_list(pmu, str, metric_no_group, metric_no_threshold,
                                           user_requested_cpu_list,
                                           system_wide, &metric_list, table);
                        goto out;
                }
 
-               me = metricgroup__lookup(metric_events_list, metric_events[0], true);
+               me = metricgroup__lookup(&perf_evlist->metric_events, metric_events[0],
+                                        /*create=*/true);
 
                expr = malloc(sizeof(struct metric_expr));
                if (!expr) {
                              bool metric_no_threshold,
                              const char *user_requested_cpu_list,
                              bool system_wide,
-                             bool hardware_aware_grouping,
-                             struct rblist *metric_events)
+                             bool hardware_aware_grouping)
 {
        const struct pmu_metrics_table *table = pmu_metrics_table__find();
 
 
        return parse_groups(perf_evlist, pmu, str, metric_no_group, metric_no_merge,
                            metric_no_threshold, user_requested_cpu_list, system_wide,
-                           /*fake_pmu=*/false, metric_events, table);
+                           /*fake_pmu=*/false, table);
 }
 
 int metricgroup__parse_groups_test(struct evlist *evlist,
                                   const struct pmu_metrics_table *table,
-                                  const char *str,
-                                  struct rblist *metric_events)
+                                  const char *str)
 {
        return parse_groups(evlist, "all", str,
                            /*metric_no_group=*/false,
                            /*metric_no_threshold=*/false,
                            /*user_requested_cpu_list=*/NULL,
                            /*system_wide=*/false,
-                           /*fake_pmu=*/true, metric_events, table);
+                           /*fake_pmu=*/true, table);
 }
 
 struct metricgroup__has_metric_data {
                evsel = evlist__find_evsel(evlist, old_me->evsel->core.idx);
                if (!evsel)
                        return -EINVAL;
-               new_me = metricgroup__lookup(new_metric_events, evsel, true);
+               new_me = metricgroup__lookup(new_metric_events, evsel, /*create=*/true);
                if (!new_me)
                        return -ENOMEM;
 
 
                              bool metric_no_threshold,
                              const char *user_requested_cpu_list,
                              bool system_wide,
-                             bool hardware_aware_grouping,
-                             struct rblist *metric_events);
+                             bool hardware_aware_grouping);
 int metricgroup__parse_groups_test(struct evlist *evlist,
                                   const struct pmu_metrics_table *table,
-                                  const char *str,
-                                  struct rblist *metric_events);
+                                  const char *str);
 
 int metricgroup__for_each_metric(const struct pmu_metrics_table *table, pmu_metric_iter_fn fn,
                                 void *data);
 bool metricgroup__has_metric_or_groups(const char *pmu, const char *metric_or_groups);
 unsigned int metricgroups__topdown_max_level(void);
 int arch_get_runtimeparam(const struct pmu_metric *pm);
+void metricgroup__rblist_init(struct rblist *metric_events);
 void metricgroup__rblist_exit(struct rblist *metric_events);
 
 int metricgroup__copy_metric_events(struct evlist *evlist, struct cgroup *cgrp,
 
 #include "strbuf.h"
 #include "thread_map.h"
 #include "trace-event.h"
+#include "metricgroup.h"
 #include "mmap.h"
 #include "util/sample.h"
 #include <internal/lib.h>
 
                evlist__add(&pevlist->evlist, &pevsel->evsel);
        }
+       metricgroup__copy_metric_events(&pevlist->evlist, /*cgrp=*/NULL,
+                                       &pevlist->evlist.metric_events,
+                                       &evlist->metric_events);
        return (PyObject *)pevlist;
 }
 
 
                                print_noise(config, os, counter, noise, /*before_metric=*/true);
                                print_running(config, os, run, ena, /*before_metric=*/true);
                                from = perf_stat__print_shadow_stats_metricgroup(config, counter, aggr_idx,
-                                                                                &num, from, &out,
-                                                                                &config->metric_events);
+                                                                                &num, from, &out);
                        } while (from != NULL);
-               } else
-                       perf_stat__print_shadow_stats(config, counter, uval, aggr_idx,
-                                                     &out, &config->metric_events);
+               } else {
+                       perf_stat__print_shadow_stats(config, counter, uval, aggr_idx, &out);
+               }
        } else {
                pm(config, os, METRIC_THRESHOLD_UNKNOWN, /*format=*/NULL, /*unit=*/NULL, /*val=*/0);
        }
        ena = aggr->counts.ena;
        run = aggr->counts.run;
 
-       if (perf_stat__skip_metric_event(counter, &config->metric_events, ena, run))
+       if (perf_stat__skip_metric_event(counter, ena, run))
                return;
 
        if (val == 0 && should_skip_zero_counter(config, counter, &id))
 
                os.evsel = counter;
 
-               perf_stat__print_shadow_stats(config, counter, 0,
-                                             0,
-                                             &out,
-                                             &config->metric_events);
+               perf_stat__print_shadow_stats(config, counter, 0, 0, &out);
        }
 
        if (!config->json_output)
 
 #include <linux/zalloc.h>
 #include "iostat.h"
 #include "util/hashmap.h"
+#include "rblist.h"
 #include "tool_pmu.h"
 
 struct stats walltime_nsecs_stats;
                                                int aggr_idx,
                                                int *num,
                                                void *from,
-                                               struct perf_stat_output_ctx *out,
-                                               struct rblist *metric_events)
+                                               struct perf_stat_output_ctx *out)
 {
        struct metric_event *me;
        struct metric_expr *mexp = from;
        void *ctxp = out->ctx;
        bool header_printed = false;
        const char *name = NULL;
+       struct rblist *metric_events = &evsel->evlist->metric_events;
 
        me = metricgroup__lookup(metric_events, evsel, false);
        if (me == NULL)
 void perf_stat__print_shadow_stats(struct perf_stat_config *config,
                                   struct evsel *evsel,
                                   double avg, int aggr_idx,
-                                  struct perf_stat_output_ctx *out,
-                                  struct rblist *metric_events)
+                                  struct perf_stat_output_ctx *out)
 {
        typedef void (*stat_print_function_t)(struct perf_stat_config *config,
                                        const struct evsel *evsel,
        }
 
        perf_stat__print_shadow_stats_metricgroup(config, evsel, aggr_idx,
-                                                 &num, NULL, out, metric_events);
+                                                 &num, NULL, out);
 
        if (num == 0) {
                print_metric(config, ctxp, METRIC_THRESHOLD_UNKNOWN,
  *                               if it's not running or not the metric event.
  */
 bool perf_stat__skip_metric_event(struct evsel *evsel,
-                                 struct rblist *metric_events,
                                  u64 ena, u64 run)
 {
        if (!evsel->default_metricgroup)
        if (!ena || !run)
                return true;
 
-       return !metricgroup__lookup(metric_events, evsel, false);
+       return !metricgroup__lookup(&evsel->evlist->metric_events, evsel, false);
 }
 
 #include <sys/types.h>
 #include <sys/resource.h>
 #include "cpumap.h"
-#include "rblist.h"
 #include "counts.h"
 
 struct perf_cpu_map;
        aggr_get_id_t            aggr_get_id;
        struct cpu_aggr_map     *cpus_aggr_map;
        u64                     *walltime_run;
-       struct rblist            metric_events;
        int                      ctl_fd;
        int                      ctl_fd_ack;
        bool                     ctl_fd_close;
 void perf_stat__print_shadow_stats(struct perf_stat_config *config,
                                   struct evsel *evsel,
                                   double avg, int aggr_idx,
-                                  struct perf_stat_output_ctx *out,
-                                  struct rblist *metric_events);
-bool perf_stat__skip_metric_event(struct evsel *evsel,
-                                 struct rblist *metric_events,
-                                 u64 ena, u64 run);
+                                  struct perf_stat_output_ctx *out);
+bool perf_stat__skip_metric_event(struct evsel *evsel, u64 ena, u64 run);
 void *perf_stat__print_shadow_stats_metricgroup(struct perf_stat_config *config,
                                                struct evsel *evsel,
                                                int aggr_idx,
                                                int *num,
                                                void *from,
-                                               struct perf_stat_output_ctx *out,
-                                               struct rblist *metric_events);
+                                               struct perf_stat_output_ctx *out);
 
 int evlist__alloc_stats(struct perf_stat_config *config,
                        struct evlist *evlist, bool alloc_raw);