perf stat: Check PMU cpumask file
authorYan, Zheng <zheng.z.yan@intel.com>
Mon, 10 Sep 2012 07:53:50 +0000 (15:53 +0800)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 17 Sep 2012 16:12:02 +0000 (13:12 -0300)
If user doesn't explicitly specify CPU list, perf-stat only collects
events on CPUs listed in the PMU cpumask file.

Signed-off-by: "Yah, Zheng" <zheng.z.yan@intel.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1347263631-23175-3-git-send-email-zheng.z.yan@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-stat.c
tools/perf/util/cpumap.c
tools/perf/util/cpumap.h
tools/perf/util/evsel.h
tools/perf/util/parse-events.c
tools/perf/util/pmu.c
tools/perf/util/pmu.h

index 3c43a3578f3115885daba420bce1f2bf04383e35..e0f65fe65944cb5717ed015450df50991e8f2078 100644 (file)
@@ -215,6 +215,16 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
        evsel->priv = NULL;
 }
 
+static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
+{
+       return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus;
+}
+
+static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
+{
+       return perf_evsel__cpus(evsel)->nr;
+}
+
 static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
 static struct stats runtime_cycles_stats[MAX_NR_CPUS];
 static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
@@ -246,7 +256,7 @@ retry:
                evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
 
        if (perf_target__has_cpu(&target)) {
-               ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus);
+               ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
                if (ret)
                        goto check_ret;
                return 0;
@@ -327,7 +337,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
        u64 *count = counter->counts->aggr.values;
        int i;
 
-       if (__perf_evsel__read(counter, evsel_list->cpus->nr,
+       if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter),
                               evsel_list->threads->nr, scale) < 0)
                return -1;
 
@@ -356,7 +366,7 @@ static int read_counter(struct perf_evsel *counter)
        u64 *count;
        int cpu;
 
-       for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
+       for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
                if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
                        return -1;
 
@@ -495,12 +505,12 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv)
        if (no_aggr) {
                list_for_each_entry(counter, &evsel_list->entries, node) {
                        read_counter(counter);
-                       perf_evsel__close_fd(counter, evsel_list->cpus->nr, 1);
+                       perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1);
                }
        } else {
                list_for_each_entry(counter, &evsel_list->entries, node) {
                        read_counter_aggr(counter);
-                       perf_evsel__close_fd(counter, evsel_list->cpus->nr,
+                       perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
                                             evsel_list->threads->nr);
                }
        }
@@ -538,7 +548,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
        if (no_aggr)
                sprintf(cpustr, "CPU%*d%s",
                        csv_output ? 0 : -4,
-                       evsel_list->cpus->map[cpu], csv_sep);
+                       perf_evsel__cpus(evsel)->map[cpu], csv_sep);
 
        fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel));
 
@@ -750,7 +760,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
        if (no_aggr)
                sprintf(cpustr, "CPU%*d%s",
                        csv_output ? 0 : -4,
-                       evsel_list->cpus->map[cpu], csv_sep);
+                       perf_evsel__cpus(evsel)->map[cpu], csv_sep);
        else
                cpu = 0;
 
@@ -911,14 +921,14 @@ static void print_counter(struct perf_evsel *counter)
        u64 ena, run, val;
        int cpu;
 
-       for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
+       for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
                val = counter->counts->cpu[cpu].val;
                ena = counter->counts->cpu[cpu].ena;
                run = counter->counts->cpu[cpu].run;
                if (run == 0 || ena == 0) {
                        fprintf(output, "CPU%*d%s%*s%s%*s",
                                csv_output ? 0 : -4,
-                               evsel_list->cpus->map[cpu], csv_sep,
+                               perf_evsel__cpus(counter)->map[cpu], csv_sep,
                                csv_output ? 0 : 18,
                                counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
                                csv_sep,
@@ -1217,7 +1227,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 
        list_for_each_entry(pos, &evsel_list->entries, node) {
                if (perf_evsel__alloc_stat_priv(pos) < 0 ||
-                   perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0)
+                   perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0)
                        goto out_free_fd;
        }
 
index adc72f09914d0c8089bd104784284928da3cd1f9..2b32ffa9ebdb188e8edeb31fc4176380d99b2337 100644 (file)
@@ -38,24 +38,19 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
        return cpus;
 }
 
-static struct cpu_map *cpu_map__read_all_cpu_map(void)
+struct cpu_map *cpu_map__read(FILE *file)
 {
        struct cpu_map *cpus = NULL;
-       FILE *onlnf;
        int nr_cpus = 0;
        int *tmp_cpus = NULL, *tmp;
        int max_entries = 0;
        int n, cpu, prev;
        char sep;
 
-       onlnf = fopen("/sys/devices/system/cpu/online", "r");
-       if (!onlnf)
-               return cpu_map__default_new();
-
        sep = 0;
        prev = -1;
        for (;;) {
-               n = fscanf(onlnf, "%u%c", &cpu, &sep);
+               n = fscanf(file, "%u%c", &cpu, &sep);
                if (n <= 0)
                        break;
                if (prev >= 0) {
@@ -95,6 +90,19 @@ static struct cpu_map *cpu_map__read_all_cpu_map(void)
                cpus = cpu_map__default_new();
 out_free_tmp:
        free(tmp_cpus);
+       return cpus;
+}
+
+static struct cpu_map *cpu_map__read_all_cpu_map(void)
+{
+       struct cpu_map *cpus = NULL;
+       FILE *onlnf;
+
+       onlnf = fopen("/sys/devices/system/cpu/online", "r");
+       if (!onlnf)
+               return cpu_map__default_new();
+
+       cpus = cpu_map__read(onlnf);
        fclose(onlnf);
        return cpus;
 }
index c41518573c6af013e5de3c16d916bfac84e92897..17b5264f6436f69393199a21913941a40ea65e3f 100644 (file)
@@ -11,7 +11,7 @@ struct cpu_map {
 struct cpu_map *cpu_map__new(const char *cpu_list);
 struct cpu_map *cpu_map__dummy_new(void);
 void cpu_map__delete(struct cpu_map *map);
-
+struct cpu_map *cpu_map__read(FILE *file);
 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
 
 #endif /* __PERF_CPUMAP_H */
index dc40fe32210b606f229aa2de4ab354b50fde79f7..93876bad2e52c12acb4604dbce1ffe9be2d4d645 100644 (file)
@@ -66,6 +66,7 @@ struct perf_evsel {
                void            *func;
                void            *data;
        } handler;
+       struct cpu_map          *cpus;
        unsigned int            sample_size;
        bool                    supported;
        /* parse modifier helper */
index 44afcf40f7963237414b4587b30009ef16c8ac9e..bf5d033ee1b4d0c4b493b3e68c9a91af9cee2a6d 100644 (file)
@@ -239,8 +239,11 @@ const char *event_type(int type)
        return "unknown";
 }
 
-static int add_event(struct list_head **_list, int *idx,
-                    struct perf_event_attr *attr, char *name)
+
+
+static int __add_event(struct list_head **_list, int *idx,
+                      struct perf_event_attr *attr,
+                      char *name, struct cpu_map *cpus)
 {
        struct perf_evsel *evsel;
        struct list_head *list = *_list;
@@ -260,6 +263,7 @@ static int add_event(struct list_head **_list, int *idx,
                return -ENOMEM;
        }
 
+       evsel->cpus = cpus;
        if (name)
                evsel->name = strdup(name);
        list_add_tail(&evsel->node, list);
@@ -267,6 +271,12 @@ static int add_event(struct list_head **_list, int *idx,
        return 0;
 }
 
+static int add_event(struct list_head **_list, int *idx,
+                    struct perf_event_attr *attr, char *name)
+{
+       return __add_event(_list, idx, attr, name, NULL);
+}
+
 static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
 {
        int i, j;
@@ -607,8 +617,8 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
        if (perf_pmu__config(pmu, &attr, head_config))
                return -EINVAL;
 
-       return add_event(list, idx, &attr,
-                        pmu_event_name(head_config));
+       return __add_event(list, idx, &attr, pmu_event_name(head_config),
+                          pmu->cpus);
 }
 
 int parse_events__modifier_group(struct list_head *list,
index 6631d828db3dc131dad22c02489bf47efe039070..8a2229da594fca292d6d0672bb40b4a10a0a52f2 100644 (file)
@@ -9,6 +9,7 @@
 #include "util.h"
 #include "pmu.h"
 #include "parse-events.h"
+#include "cpumap.h"
 
 #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
 
@@ -253,6 +254,33 @@ static void pmu_read_sysfs(void)
        closedir(dir);
 }
 
+static struct cpu_map *pmu_cpumask(char *name)
+{
+       struct stat st;
+       char path[PATH_MAX];
+       const char *sysfs;
+       FILE *file;
+       struct cpu_map *cpus;
+
+       sysfs = sysfs_find_mountpoint();
+       if (!sysfs)
+               return NULL;
+
+       snprintf(path, PATH_MAX,
+                "%s/bus/event_source/devices/%s/cpumask", sysfs, name);
+
+       if (stat(path, &st) < 0)
+               return NULL;
+
+       file = fopen(path, "r");
+       if (!file)
+               return NULL;
+
+       cpus = cpu_map__read(file);
+       fclose(file);
+       return cpus;
+}
+
 static struct perf_pmu *pmu_lookup(char *name)
 {
        struct perf_pmu *pmu;
@@ -275,6 +303,8 @@ static struct perf_pmu *pmu_lookup(char *name)
        if (!pmu)
                return NULL;
 
+       pmu->cpus = pmu_cpumask(name);
+
        pmu_aliases(name, &aliases);
 
        INIT_LIST_HEAD(&pmu->format);
index 47f68d3cc5d1e51354ae7f2df5f06cfa50372b2c..53c7794fc4be3b409c72dee5687abce438111707 100644 (file)
@@ -28,6 +28,7 @@ struct perf_pmu__alias {
 struct perf_pmu {
        char *name;
        __u32 type;
+       struct cpu_map *cpus;
        struct list_head format;
        struct list_head aliases;
        struct list_head list;