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: "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>
This commit is contained in:
committed by
Arnaldo Carvalho de Melo
parent
314d9f63f3
commit
7ae92e744e
@@ -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 @@ retry:
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
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)
|
|||||||
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 {
|
|||||||
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;
|
||||||
|
Reference in New Issue
Block a user