Commit 7ae92e74 authored by Yan, Zheng's avatar Yan, Zheng Committed by Arnaldo Carvalho de Melo

perf stat: Check PMU cpumask file

If user doesn't explicitly specify CPU list, perf-stat only collects
events on CPUs listed in the PMU cpumask file.
Signed-off-by: default avatar"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.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 314d9f63
...@@ -215,6 +215,16 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) ...@@ -215,6 +215,16 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
evsel->priv = NULL; 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_nsecs_stats[MAX_NR_CPUS];
static struct stats runtime_cycles_stats[MAX_NR_CPUS]; static struct stats runtime_cycles_stats[MAX_NR_CPUS];
static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
...@@ -246,7 +256,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel, ...@@ -246,7 +256,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
if (perf_target__has_cpu(&target)) { 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) if (ret)
goto check_ret; goto check_ret;
return 0; return 0;
...@@ -327,7 +337,7 @@ static int read_counter_aggr(struct perf_evsel *counter) ...@@ -327,7 +337,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
u64 *count = counter->counts->aggr.values; u64 *count = counter->counts->aggr.values;
int i; 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) evsel_list->threads->nr, scale) < 0)
return -1; return -1;
...@@ -356,7 +366,7 @@ static int read_counter(struct perf_evsel *counter) ...@@ -356,7 +366,7 @@ static int read_counter(struct perf_evsel *counter)
u64 *count; u64 *count;
int cpu; 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) if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
return -1; return -1;
...@@ -495,12 +505,12 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv) ...@@ -495,12 +505,12 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv)
if (no_aggr) { if (no_aggr) {
list_for_each_entry(counter, &evsel_list->entries, node) { list_for_each_entry(counter, &evsel_list->entries, node) {
read_counter(counter); 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 { } else {
list_for_each_entry(counter, &evsel_list->entries, node) { list_for_each_entry(counter, &evsel_list->entries, node) {
read_counter_aggr(counter); 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); evsel_list->threads->nr);
} }
} }
...@@ -538,7 +548,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) ...@@ -538,7 +548,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
if (no_aggr) if (no_aggr)
sprintf(cpustr, "CPU%*d%s", sprintf(cpustr, "CPU%*d%s",
csv_output ? 0 : -4, 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)); 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) ...@@ -750,7 +760,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
if (no_aggr) if (no_aggr)
sprintf(cpustr, "CPU%*d%s", sprintf(cpustr, "CPU%*d%s",
csv_output ? 0 : -4, csv_output ? 0 : -4,
evsel_list->cpus->map[cpu], csv_sep); perf_evsel__cpus(evsel)->map[cpu], csv_sep);
else else
cpu = 0; cpu = 0;
...@@ -911,14 +921,14 @@ static void print_counter(struct perf_evsel *counter) ...@@ -911,14 +921,14 @@ static void print_counter(struct perf_evsel *counter)
u64 ena, run, val; u64 ena, run, val;
int cpu; 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; val = counter->counts->cpu[cpu].val;
ena = counter->counts->cpu[cpu].ena; ena = counter->counts->cpu[cpu].ena;
run = counter->counts->cpu[cpu].run; run = counter->counts->cpu[cpu].run;
if (run == 0 || ena == 0) { if (run == 0 || ena == 0) {
fprintf(output, "CPU%*d%s%*s%s%*s", fprintf(output, "CPU%*d%s%*s%s%*s",
csv_output ? 0 : -4, csv_output ? 0 : -4,
evsel_list->cpus->map[cpu], csv_sep, perf_evsel__cpus(counter)->map[cpu], csv_sep,
csv_output ? 0 : 18, csv_output ? 0 : 18,
counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
csv_sep, csv_sep,
...@@ -1217,7 +1227,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -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) { list_for_each_entry(pos, &evsel_list->entries, node) {
if (perf_evsel__alloc_stat_priv(pos) < 0 || 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; goto out_free_fd;
} }
......
...@@ -38,24 +38,19 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus) ...@@ -38,24 +38,19 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
return 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; struct cpu_map *cpus = NULL;
FILE *onlnf;
int nr_cpus = 0; int nr_cpus = 0;
int *tmp_cpus = NULL, *tmp; int *tmp_cpus = NULL, *tmp;
int max_entries = 0; int max_entries = 0;
int n, cpu, prev; int n, cpu, prev;
char sep; char sep;
onlnf = fopen("/sys/devices/system/cpu/online", "r");
if (!onlnf)
return cpu_map__default_new();
sep = 0; sep = 0;
prev = -1; prev = -1;
for (;;) { for (;;) {
n = fscanf(onlnf, "%u%c", &cpu, &sep); n = fscanf(file, "%u%c", &cpu, &sep);
if (n <= 0) if (n <= 0)
break; break;
if (prev >= 0) { if (prev >= 0) {
...@@ -95,6 +90,19 @@ static struct cpu_map *cpu_map__read_all_cpu_map(void) ...@@ -95,6 +90,19 @@ static struct cpu_map *cpu_map__read_all_cpu_map(void)
cpus = cpu_map__default_new(); cpus = cpu_map__default_new();
out_free_tmp: out_free_tmp:
free(tmp_cpus); 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); fclose(onlnf);
return cpus; return cpus;
} }
......
...@@ -11,7 +11,7 @@ struct cpu_map { ...@@ -11,7 +11,7 @@ struct cpu_map {
struct cpu_map *cpu_map__new(const char *cpu_list); struct cpu_map *cpu_map__new(const char *cpu_list);
struct cpu_map *cpu_map__dummy_new(void); struct cpu_map *cpu_map__dummy_new(void);
void cpu_map__delete(struct cpu_map *map); 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); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
#endif /* __PERF_CPUMAP_H */ #endif /* __PERF_CPUMAP_H */
...@@ -66,6 +66,7 @@ struct perf_evsel { ...@@ -66,6 +66,7 @@ struct perf_evsel {
void *func; void *func;
void *data; void *data;
} handler; } handler;
struct cpu_map *cpus;
unsigned int sample_size; unsigned int sample_size;
bool supported; bool supported;
/* parse modifier helper */ /* parse modifier helper */
......
...@@ -239,8 +239,11 @@ const char *event_type(int type) ...@@ -239,8 +239,11 @@ const char *event_type(int type)
return "unknown"; 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 perf_evsel *evsel;
struct list_head *list = *_list; struct list_head *list = *_list;
...@@ -260,6 +263,7 @@ static int add_event(struct list_head **_list, int *idx, ...@@ -260,6 +263,7 @@ static int add_event(struct list_head **_list, int *idx,
return -ENOMEM; return -ENOMEM;
} }
evsel->cpus = cpus;
if (name) if (name)
evsel->name = strdup(name); evsel->name = strdup(name);
list_add_tail(&evsel->node, list); list_add_tail(&evsel->node, list);
...@@ -267,6 +271,12 @@ static int add_event(struct list_head **_list, int *idx, ...@@ -267,6 +271,12 @@ static int add_event(struct list_head **_list, int *idx,
return 0; 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) static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
{ {
int i, j; int i, j;
...@@ -607,8 +617,8 @@ int parse_events_add_pmu(struct list_head **list, int *idx, ...@@ -607,8 +617,8 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
if (perf_pmu__config(pmu, &attr, head_config)) if (perf_pmu__config(pmu, &attr, head_config))
return -EINVAL; return -EINVAL;
return add_event(list, idx, &attr, return __add_event(list, idx, &attr, pmu_event_name(head_config),
pmu_event_name(head_config)); pmu->cpus);
} }
int parse_events__modifier_group(struct list_head *list, int parse_events__modifier_group(struct list_head *list,
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "util.h" #include "util.h"
#include "pmu.h" #include "pmu.h"
#include "parse-events.h" #include "parse-events.h"
#include "cpumap.h"
#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
...@@ -253,6 +254,33 @@ static void pmu_read_sysfs(void) ...@@ -253,6 +254,33 @@ static void pmu_read_sysfs(void)
closedir(dir); 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) static struct perf_pmu *pmu_lookup(char *name)
{ {
struct perf_pmu *pmu; struct perf_pmu *pmu;
...@@ -275,6 +303,8 @@ static struct perf_pmu *pmu_lookup(char *name) ...@@ -275,6 +303,8 @@ static struct perf_pmu *pmu_lookup(char *name)
if (!pmu) if (!pmu)
return NULL; return NULL;
pmu->cpus = pmu_cpumask(name);
pmu_aliases(name, &aliases); pmu_aliases(name, &aliases);
INIT_LIST_HEAD(&pmu->format); INIT_LIST_HEAD(&pmu->format);
......
...@@ -28,6 +28,7 @@ struct perf_pmu__alias { ...@@ -28,6 +28,7 @@ struct perf_pmu__alias {
struct perf_pmu { struct perf_pmu {
char *name; char *name;
__u32 type; __u32 type;
struct cpu_map *cpus;
struct list_head format; struct list_head format;
struct list_head aliases; struct list_head aliases;
struct list_head list; struct list_head list;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment