perf stat aggregation: Add separate core member
[linux-2.6-microblaze.git] / tools / perf / builtin-stat.c
index fddc97c..8cc2496 100644 (file)
@@ -56,7 +56,7 @@
 #include "util/cpumap.h"
 #include "util/thread_map.h"
 #include "util/counts.h"
-#include "util/group.h"
+#include "util/topdown.h"
 #include "util/session.h"
 #include "util/tool.h"
 #include "util/string2.h"
@@ -128,6 +128,15 @@ static const char * topdown_attrs[] = {
        NULL,
 };
 
+static const char *topdown_metric_attrs[] = {
+       "slots",
+       "topdown-retiring",
+       "topdown-bad-spec",
+       "topdown-fe-bound",
+       "topdown-be-bound",
+       NULL,
+};
+
 static const char *smi_cost_attrs = {
        "{"
        "msr/aperf/,"
@@ -261,7 +270,7 @@ static void perf_stat__reset_stats(void)
 {
        int i;
 
-       perf_evlist__reset_stats(evsel_list);
+       evlist__reset_stats(evsel_list);
        perf_stat__reset_shadow_stats();
 
        for (i = 0; i < stat_config.stats_num; i++)
@@ -525,7 +534,7 @@ static void disable_counters(void)
 static volatile int workload_exec_errno;
 
 /*
- * perf_evlist__prepare_workload will send a SIGUSR1
+ * evlist__prepare_workload will send a SIGUSR1
  * if the fork fails, since we asked by setting its
  * want_signal to true.
  */
@@ -578,6 +587,7 @@ static void process_evlist(struct evlist *evlist, unsigned int interval)
                                process_interval();
                        pr_info(EVLIST_DISABLED_MSG);
                        break;
+               case EVLIST_CTL_CMD_SNAPSHOT:
                case EVLIST_CTL_CMD_ACK:
                case EVLIST_CTL_CMD_UNSUPPORTED:
                default:
@@ -714,8 +724,7 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
        bool second_pass = false;
 
        if (forks) {
-               if (perf_evlist__prepare_workload(evsel_list, &target, argv, is_pipe,
-                                                 workload_exec_failed_signal) < 0) {
+               if (evlist__prepare_workload(evsel_list, &target, argv, is_pipe, workload_exec_failed_signal) < 0) {
                        perror("failed to prepare workload");
                        return -1;
                }
@@ -723,7 +732,7 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
        }
 
        if (group)
-               perf_evlist__set_leader(evsel_list);
+               evlist__set_leader(evsel_list);
 
        if (affinity__setup(&affinity) < 0)
                return -1;
@@ -750,7 +759,7 @@ try_again:
                                if ((errno == EINVAL || errno == EBADF) &&
                                    counter->leader != counter &&
                                    counter->weak_group) {
-                                       perf_evlist__reset_weak_group(evsel_list, counter, false);
+                                       evlist__reset_weak_group(evsel_list, counter, false);
                                        assert(counter->reset_group);
                                        second_pass = true;
                                        continue;
@@ -833,7 +842,7 @@ try_again_reset:
                        return -1;
        }
 
-       if (perf_evlist__apply_filters(evsel_list, &counter)) {
+       if (evlist__apply_filters(evsel_list, &counter)) {
                pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n",
                        counter->filter, evsel__name(counter), errno,
                        str_error_r(errno, msg, sizeof(msg)));
@@ -866,7 +875,7 @@ try_again_reset:
        clock_gettime(CLOCK_MONOTONIC, &ref_time);
 
        if (forks) {
-               perf_evlist__start_workload(evsel_list);
+               evlist__start_workload(evsel_list);
                enable_counters();
 
                if (interval || timeout || evlist__ctlfd_initialized(evsel_list))
@@ -904,10 +913,10 @@ try_again_reset:
                update_stats(&walltime_nsecs_stats, t1 - t0);
 
                if (stat_config.aggr_mode == AGGR_GLOBAL)
-                       perf_evlist__save_aggr_prev_raw_counts(evsel_list);
+                       evlist__save_aggr_prev_raw_counts(evsel_list);
 
-               perf_evlist__copy_prev_raw_counts(evsel_list);
-               perf_evlist__reset_prev_raw_counts(evsel_list);
+               evlist__copy_prev_raw_counts(evsel_list);
+               evlist__reset_prev_raw_counts(evsel_list);
                runtime_stat_reset(&stat_config);
                perf_stat__reset_shadow_per_stat(&rt_stat);
        } else
@@ -962,9 +971,10 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
        /* Do not print anything if we record to the pipe. */
        if (STAT_RECORD && perf_stat.data.is_pipe)
                return;
+       if (stat_config.quiet)
+               return;
 
-       perf_evlist__print_counters(evsel_list, &stat_config, &target,
-                                   ts, argc, argv);
+       evlist__print_counters(evsel_list, &stat_config, &target, ts, argc, argv);
 }
 
 static volatile int signr = -1;
@@ -1045,27 +1055,20 @@ static int parse_control_option(const struct option *opt,
                                const char *str,
                                int unset __maybe_unused)
 {
-       char *comma = NULL, *endptr = NULL;
-       struct perf_stat_config *config = (struct perf_stat_config *)opt->value;
-
-       if (strncmp(str, "fd:", 3))
-               return -EINVAL;
-
-       config->ctl_fd = strtoul(&str[3], &endptr, 0);
-       if (endptr == &str[3])
-               return -EINVAL;
+       struct perf_stat_config *config = opt->value;
 
-       comma = strchr(str, ',');
-       if (comma) {
-               if (endptr != comma)
-                       return -EINVAL;
+       return evlist__parse_control(str, &config->ctl_fd, &config->ctl_fd_ack, &config->ctl_fd_close);
+}
 
-               config->ctl_fd_ack = strtoul(comma + 1, &endptr, 0);
-               if (endptr == comma + 1 || *endptr != '\0')
-                       return -EINVAL;
+static int parse_stat_cgroups(const struct option *opt,
+                             const char *str, int unset)
+{
+       if (stat_config.cgroup_list) {
+               pr_err("--cgroup and --for-each-cgroup cannot be used together\n");
+               return -1;
        }
 
-       return 0;
+       return parse_cgroups(opt, str, unset);
 }
 
 static struct option stat_options[] = {
@@ -1111,7 +1114,9 @@ static struct option stat_options[] = {
        OPT_STRING('x', "field-separator", &stat_config.csv_sep, "separator",
                   "print counts with custom separator"),
        OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
-                    "monitor event in cgroup name only", parse_cgroups),
+                    "monitor event in cgroup name only", parse_stat_cgroups),
+       OPT_STRING(0, "for-each-cgroup", &stat_config.cgroup_list, "name",
+                   "expand events for each cgroup"),
        OPT_STRING('o', "output", &output_name, "file", "output file name"),
        OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
        OPT_INTEGER(0, "log-fd", &output_fd,
@@ -1166,77 +1171,82 @@ static struct option stat_options[] = {
                    "threads of same physical core"),
        OPT_BOOLEAN(0, "summary", &stat_config.summary,
                       "print summary for interval mode"),
+       OPT_BOOLEAN(0, "quiet", &stat_config.quiet,
+                       "don't print output (useful with record)"),
 #ifdef HAVE_LIBPFM
        OPT_CALLBACK(0, "pfm-events", &evsel_list, "event",
                "libpfm4 event selector. use 'perf list' to list available events",
                parse_libpfm_events_option),
 #endif
-       OPT_CALLBACK(0, "control", &stat_config, "fd:ctl-fd[,ack-fd]",
+       OPT_CALLBACK(0, "control", &stat_config, "fd:ctl-fd[,ack-fd] or fifo:ctl-fifo[,ack-fifo]",
                     "Listen on ctl-fd descriptor for command to control measurement ('enable': enable events, 'disable': disable events).\n"
-                    "\t\t\t  Optionally send control command completion ('ack\\n') to ack-fd descriptor.",
+                    "\t\t\t  Optionally send control command completion ('ack\\n') to ack-fd descriptor.\n"
+                    "\t\t\t  Alternatively, ctl-fifo / ack-fifo will be opened and used as ctl-fd / ack-fd.",
                      parse_control_option),
        OPT_END()
 };
 
-static int perf_stat__get_socket(struct perf_stat_config *config __maybe_unused,
+static struct aggr_cpu_id perf_stat__get_socket(struct perf_stat_config *config __maybe_unused,
                                 struct perf_cpu_map *map, int cpu)
 {
        return cpu_map__get_socket(map, cpu, NULL);
 }
 
-static int perf_stat__get_die(struct perf_stat_config *config __maybe_unused,
+static struct aggr_cpu_id perf_stat__get_die(struct perf_stat_config *config __maybe_unused,
                              struct perf_cpu_map *map, int cpu)
 {
        return cpu_map__get_die(map, cpu, NULL);
 }
 
-static int perf_stat__get_core(struct perf_stat_config *config __maybe_unused,
+static struct aggr_cpu_id perf_stat__get_core(struct perf_stat_config *config __maybe_unused,
                               struct perf_cpu_map *map, int cpu)
 {
        return cpu_map__get_core(map, cpu, NULL);
 }
 
-static int perf_stat__get_node(struct perf_stat_config *config __maybe_unused,
+static struct aggr_cpu_id perf_stat__get_node(struct perf_stat_config *config __maybe_unused,
                               struct perf_cpu_map *map, int cpu)
 {
        return cpu_map__get_node(map, cpu, NULL);
 }
 
-static int perf_stat__get_aggr(struct perf_stat_config *config,
+static struct aggr_cpu_id perf_stat__get_aggr(struct perf_stat_config *config,
                               aggr_get_id_t get_id, struct perf_cpu_map *map, int idx)
 {
        int cpu;
+       struct aggr_cpu_id id = cpu_map__empty_aggr_cpu_id();
 
        if (idx >= map->nr)
-               return -1;
+               return id;
 
        cpu = map->map[idx];
 
-       if (config->cpus_aggr_map->map[cpu] == -1)
+       if (cpu_map__aggr_cpu_id_is_empty(config->cpus_aggr_map->map[cpu]))
                config->cpus_aggr_map->map[cpu] = get_id(config, map, idx);
 
-       return config->cpus_aggr_map->map[cpu];
+       id = config->cpus_aggr_map->map[cpu];
+       return id;
 }
 
-static int perf_stat__get_socket_cached(struct perf_stat_config *config,
+static struct aggr_cpu_id perf_stat__get_socket_cached(struct perf_stat_config *config,
                                        struct perf_cpu_map *map, int idx)
 {
        return perf_stat__get_aggr(config, perf_stat__get_socket, map, idx);
 }
 
-static int perf_stat__get_die_cached(struct perf_stat_config *config,
+static struct aggr_cpu_id perf_stat__get_die_cached(struct perf_stat_config *config,
                                        struct perf_cpu_map *map, int idx)
 {
        return perf_stat__get_aggr(config, perf_stat__get_die, map, idx);
 }
 
-static int perf_stat__get_core_cached(struct perf_stat_config *config,
+static struct aggr_cpu_id perf_stat__get_core_cached(struct perf_stat_config *config,
                                      struct perf_cpu_map *map, int idx)
 {
        return perf_stat__get_aggr(config, perf_stat__get_core, map, idx);
 }
 
-static int perf_stat__get_node_cached(struct perf_stat_config *config,
+static struct aggr_cpu_id perf_stat__get_node_cached(struct perf_stat_config *config,
                                      struct perf_cpu_map *map, int idx)
 {
        return perf_stat__get_aggr(config, perf_stat__get_node, map, idx);
@@ -1310,14 +1320,29 @@ static int perf_stat_init_aggr_mode(void)
         * the aggregation translate cpumap.
         */
        nr = perf_cpu_map__max(evsel_list->core.cpus);
-       stat_config.cpus_aggr_map = perf_cpu_map__empty_new(nr + 1);
+       stat_config.cpus_aggr_map = cpu_aggr_map__empty_new(nr + 1);
        return stat_config.cpus_aggr_map ? 0 : -ENOMEM;
 }
 
+static void cpu_aggr_map__delete(struct cpu_aggr_map *map)
+{
+       if (map) {
+               WARN_ONCE(refcount_read(&map->refcnt) != 0,
+                         "cpu_aggr_map refcnt unbalanced\n");
+               free(map);
+       }
+}
+
+static void cpu_aggr_map__put(struct cpu_aggr_map *map)
+{
+       if (map && refcount_dec_and_test(&map->refcnt))
+               cpu_aggr_map__delete(map);
+}
+
 static void perf_stat__exit_aggr_mode(void)
 {
-       perf_cpu_map__put(stat_config.aggr_map);
-       perf_cpu_map__put(stat_config.cpus_aggr_map);
+       cpu_aggr_map__put(stat_config.aggr_map);
+       cpu_aggr_map__put(stat_config.cpus_aggr_map);
        stat_config.aggr_map = NULL;
        stat_config.cpus_aggr_map = NULL;
 }
@@ -1337,117 +1362,108 @@ static inline int perf_env__get_cpu(struct perf_env *env, struct perf_cpu_map *m
        return cpu;
 }
 
-static int perf_env__get_socket(struct perf_cpu_map *map, int idx, void *data)
+static struct aggr_cpu_id perf_env__get_socket(struct perf_cpu_map *map, int idx, void *data)
 {
        struct perf_env *env = data;
        int cpu = perf_env__get_cpu(env, map, idx);
+       struct aggr_cpu_id id = cpu_map__empty_aggr_cpu_id();
+
+       if (cpu != -1)
+               id.socket = env->cpu[cpu].socket_id;
 
-       return cpu == -1 ? -1 : env->cpu[cpu].socket_id;
+       return id;
 }
 
-static int perf_env__get_die(struct perf_cpu_map *map, int idx, void *data)
+static struct aggr_cpu_id perf_env__get_die(struct perf_cpu_map *map, int idx, void *data)
 {
        struct perf_env *env = data;
-       int die_id = -1, cpu = perf_env__get_cpu(env, map, idx);
+       struct aggr_cpu_id id = cpu_map__empty_aggr_cpu_id();
+       int cpu = perf_env__get_cpu(env, map, idx);
 
        if (cpu != -1) {
                /*
-                * Encode socket in bit range 15:8
-                * die_id is relative to socket,
-                * we need a global id. So we combine
-                * socket + die id
+                * die_id is relative to socket, so start
+                * with the socket ID and then add die to
+                * make a unique ID.
                 */
-               if (WARN_ONCE(env->cpu[cpu].socket_id >> 8, "The socket id number is too big.\n"))
-                       return -1;
-
-               if (WARN_ONCE(env->cpu[cpu].die_id >> 8, "The die id number is too big.\n"))
-                       return -1;
-
-               die_id = (env->cpu[cpu].socket_id << 8) | (env->cpu[cpu].die_id & 0xff);
+               id.socket = env->cpu[cpu].socket_id;
+               id.die = env->cpu[cpu].die_id;
        }
 
-       return die_id;
+       return id;
 }
 
-static int perf_env__get_core(struct perf_cpu_map *map, int idx, void *data)
+static struct aggr_cpu_id perf_env__get_core(struct perf_cpu_map *map, int idx, void *data)
 {
        struct perf_env *env = data;
-       int core = -1, cpu = perf_env__get_cpu(env, map, idx);
+       struct aggr_cpu_id id = cpu_map__empty_aggr_cpu_id();
+       int cpu = perf_env__get_cpu(env, map, idx);
 
        if (cpu != -1) {
                /*
-                * Encode socket in bit range 31:24
-                * encode die id in bit range 23:16
                 * core_id is relative to socket and die,
-                * we need a global id. So we combine
-                * socket + die id + core id
+                * we need a global id. So we set
+                * socket, die id and core id
                 */
-               if (WARN_ONCE(env->cpu[cpu].socket_id >> 8, "The socket id number is too big.\n"))
-                       return -1;
-
-               if (WARN_ONCE(env->cpu[cpu].die_id >> 8, "The die id number is too big.\n"))
-                       return -1;
-
-               if (WARN_ONCE(env->cpu[cpu].core_id >> 16, "The core id number is too big.\n"))
-                       return -1;
-
-               core = (env->cpu[cpu].socket_id << 24) |
-                      (env->cpu[cpu].die_id << 16) |
-                      (env->cpu[cpu].core_id & 0xffff);
+               id.socket = env->cpu[cpu].socket_id;
+               id.die = env->cpu[cpu].die_id;
+               id.core = env->cpu[cpu].core_id;
        }
 
-       return core;
+       return id;
 }
 
-static int perf_env__get_node(struct perf_cpu_map *map, int idx, void *data)
+static struct aggr_cpu_id perf_env__get_node(struct perf_cpu_map *map, int idx, void *data)
 {
        int cpu = perf_env__get_cpu(data, map, idx);
+       struct aggr_cpu_id id = cpu_map__empty_aggr_cpu_id();
 
-       return perf_env__numa_node(data, cpu);
+       id.node = perf_env__numa_node(data, cpu);
+       return id;
 }
 
 static int perf_env__build_socket_map(struct perf_env *env, struct perf_cpu_map *cpus,
-                                     struct perf_cpu_map **sockp)
+                                     struct cpu_aggr_map **sockp)
 {
        return cpu_map__build_map(cpus, sockp, perf_env__get_socket, env);
 }
 
 static int perf_env__build_die_map(struct perf_env *env, struct perf_cpu_map *cpus,
-                                  struct perf_cpu_map **diep)
+                                  struct cpu_aggr_map **diep)
 {
        return cpu_map__build_map(cpus, diep, perf_env__get_die, env);
 }
 
 static int perf_env__build_core_map(struct perf_env *env, struct perf_cpu_map *cpus,
-                                   struct perf_cpu_map **corep)
+                                   struct cpu_aggr_map **corep)
 {
        return cpu_map__build_map(cpus, corep, perf_env__get_core, env);
 }
 
 static int perf_env__build_node_map(struct perf_env *env, struct perf_cpu_map *cpus,
-                                   struct perf_cpu_map **nodep)
+                                   struct cpu_aggr_map **nodep)
 {
        return cpu_map__build_map(cpus, nodep, perf_env__get_node, env);
 }
 
-static int perf_stat__get_socket_file(struct perf_stat_config *config __maybe_unused,
+static struct aggr_cpu_id perf_stat__get_socket_file(struct perf_stat_config *config __maybe_unused,
                                      struct perf_cpu_map *map, int idx)
 {
        return perf_env__get_socket(map, idx, &perf_stat.session->header.env);
 }
-static int perf_stat__get_die_file(struct perf_stat_config *config __maybe_unused,
+static struct aggr_cpu_id perf_stat__get_die_file(struct perf_stat_config *config __maybe_unused,
                                   struct perf_cpu_map *map, int idx)
 {
        return perf_env__get_die(map, idx, &perf_stat.session->header.env);
 }
 
-static int perf_stat__get_core_file(struct perf_stat_config *config __maybe_unused,
+static struct aggr_cpu_id perf_stat__get_core_file(struct perf_stat_config *config __maybe_unused,
                                    struct perf_cpu_map *map, int idx)
 {
        return perf_env__get_core(map, idx, &perf_stat.session->header.env);
 }
 
-static int perf_stat__get_node_file(struct perf_stat_config *config __maybe_unused,
+static struct aggr_cpu_id perf_stat__get_node_file(struct perf_stat_config *config __maybe_unused,
                                    struct perf_cpu_map *map, int idx)
 {
        return perf_env__get_node(map, idx, &perf_stat.session->header.env);
@@ -1497,55 +1513,6 @@ static int perf_stat_init_aggr_mode_file(struct perf_stat *st)
        return 0;
 }
 
-static int topdown_filter_events(const char **attr, char **str, bool use_group)
-{
-       int off = 0;
-       int i;
-       int len = 0;
-       char *s;
-
-       for (i = 0; attr[i]; i++) {
-               if (pmu_have_event("cpu", attr[i])) {
-                       len += strlen(attr[i]) + 1;
-                       attr[i - off] = attr[i];
-               } else
-                       off++;
-       }
-       attr[i - off] = NULL;
-
-       *str = malloc(len + 1 + 2);
-       if (!*str)
-               return -1;
-       s = *str;
-       if (i - off == 0) {
-               *s = 0;
-               return 0;
-       }
-       if (use_group)
-               *s++ = '{';
-       for (i = 0; attr[i]; i++) {
-               strcpy(s, attr[i]);
-               s += strlen(s);
-               *s++ = ',';
-       }
-       if (use_group) {
-               s[-1] = '}';
-               *s = 0;
-       } else
-               s[-1] = 0;
-       return 0;
-}
-
-__weak bool arch_topdown_check_group(bool *warn)
-{
-       *warn = false;
-       return false;
-}
-
-__weak void arch_topdown_group_warn(void)
-{
-}
-
 /*
  * Add default attributes, if there were no attributes specified or
  * if -d/--detailed, -d -d or -d -d -d is used:
@@ -1742,6 +1709,24 @@ static int add_default_attributes(void)
                char *str = NULL;
                bool warn = false;
 
+               if (!force_metric_only)
+                       stat_config.metric_only = true;
+
+               if (topdown_filter_events(topdown_metric_attrs, &str, 1) < 0) {
+                       pr_err("Out of memory\n");
+                       return -1;
+               }
+               if (topdown_metric_attrs[0] && str) {
+                       if (!stat_config.interval && !stat_config.metric_only) {
+                               fprintf(stat_config.output,
+                                       "Topdown accuracy may decrease when measuring long periods.\n"
+                                       "Please print the result regularly, e.g. -I1000\n");
+                       }
+                       goto setup_metrics;
+               }
+
+               zfree(&str);
+
                if (stat_config.aggr_mode != AGGR_GLOBAL &&
                    stat_config.aggr_mode != AGGR_CORE) {
                        pr_err("top down event configuration requires --per-core mode\n");
@@ -1753,8 +1738,6 @@ static int add_default_attributes(void)
                        return -1;
                }
 
-               if (!force_metric_only)
-                       stat_config.metric_only = true;
                if (topdown_filter_events(topdown_attrs, &str,
                                arch_topdown_check_group(&warn)) < 0) {
                        pr_err("Out of memory\n");
@@ -1763,6 +1746,7 @@ static int add_default_attributes(void)
                if (topdown_attrs[0] && str) {
                        if (warn)
                                arch_topdown_group_warn();
+setup_metrics:
                        err = parse_events(evsel_list, str, &errinfo);
                        if (err) {
                                fprintf(stderr,
@@ -1930,7 +1914,7 @@ static int set_maps(struct perf_stat *st)
 
        perf_evlist__set_maps(&evsel_list->core, st->cpus, st->threads);
 
-       if (perf_evlist__alloc_stats(evsel_list, true))
+       if (evlist__alloc_stats(evsel_list, true))
                return -ENOMEM;
 
        st->maps_allocated = true;
@@ -2063,8 +2047,10 @@ static void setup_system_wide(int forks)
                struct evsel *counter;
 
                evlist__for_each_entry(evsel_list, counter) {
-                       if (!counter->core.system_wide)
+                       if (!counter->core.system_wide &&
+                           strcmp(counter->name, "duration_time")) {
                                return;
+                       }
                }
 
                if (evsel_list->core.nr_entries)
@@ -2156,7 +2142,7 @@ int cmd_stat(int argc, const char **argv)
                goto out;
        }
 
-       if (!output) {
+       if (!output && !stat_config.quiet) {
                struct timespec tm;
                mode = append_file ? "a" : "w";
 
@@ -2250,12 +2236,28 @@ int cmd_stat(int argc, const char **argv)
        if (add_default_attributes())
                goto out;
 
+       if (stat_config.cgroup_list) {
+               if (nr_cgroups > 0) {
+                       pr_err("--cgroup and --for-each-cgroup cannot be used together\n");
+                       parse_options_usage(stat_usage, stat_options, "G", 1);
+                       parse_options_usage(NULL, stat_options, "for-each-cgroup", 0);
+                       goto out;
+               }
+
+               if (evlist__expand_cgroup(evsel_list, stat_config.cgroup_list,
+                                         &stat_config.metric_events, true) < 0) {
+                       parse_options_usage(stat_usage, stat_options,
+                                           "for-each-cgroup", 0);
+                       goto out;
+               }
+       }
+
        target__validate(&target);
 
        if ((stat_config.aggr_mode == AGGR_THREAD) && (target.system_wide))
                target.per_thread = true;
 
-       if (perf_evlist__create_maps(evsel_list, &target) < 0) {
+       if (evlist__create_maps(evsel_list, &target) < 0) {
                if (target__has_task(&target)) {
                        pr_err("Problems finding threads of monitor\n");
                        parse_options_usage(stat_usage, stat_options, "p", 1);
@@ -2314,7 +2316,7 @@ int cmd_stat(int argc, const char **argv)
                goto out;
        }
 
-       if (perf_evlist__alloc_stats(evsel_list, interval))
+       if (evlist__alloc_stats(evsel_list, interval))
                goto out;
 
        if (perf_stat_init_aggr_mode())
@@ -2354,7 +2356,7 @@ int cmd_stat(int argc, const char **argv)
                                run_idx + 1);
 
                if (run_idx != 0)
-                       perf_evlist__reset_prev_raw_counts(evsel_list);
+                       evlist__reset_prev_raw_counts(evsel_list);
 
                status = run_perf_stat(argc, argv, run_idx);
                if (forever && status != -1 && !interval) {
@@ -2405,7 +2407,7 @@ int cmd_stat(int argc, const char **argv)
        }
 
        perf_stat__exit_aggr_mode();
-       perf_evlist__free_stats(evsel_list);
+       evlist__free_stats(evsel_list);
 out:
        zfree(&stat_config.walltime_run);
 
@@ -2416,6 +2418,7 @@ out:
 
        metricgroup__rblist_exit(&stat_config.metric_events);
        runtime_stat_delete(&stat_config);
+       evlist__close_control(stat_config.ctl_fd, stat_config.ctl_fd_ack, &stat_config.ctl_fd_close);
 
        return status;
 }