diff options
| -rw-r--r-- | tools/perf/builtin-stat.c | 30 | ||||
| -rw-r--r-- | tools/perf/util/cpumap.c | 22 | ||||
| -rw-r--r-- | tools/perf/util/cpumap.h | 2 | ||||
| -rw-r--r-- | tools/perf/util/evsel.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/parse-events.c | 18 | ||||
| -rw-r--r-- | tools/perf/util/pmu.c | 30 | ||||
| -rw-r--r-- | tools/perf/util/pmu.h | 1 |
7 files changed, 82 insertions, 22 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 3c43a3578f31..e0f65fe65944 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -215,6 +215,16 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) | |||
| 215 | evsel->priv = NULL; | 215 | evsel->priv = NULL; |
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) | ||
| 219 | { | ||
| 220 | return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus; | ||
| 221 | } | ||
| 222 | |||
| 223 | static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) | ||
| 224 | { | ||
| 225 | return perf_evsel__cpus(evsel)->nr; | ||
| 226 | } | ||
| 227 | |||
| 218 | static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; | 228 | static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; |
| 219 | static struct stats runtime_cycles_stats[MAX_NR_CPUS]; | 229 | static struct stats runtime_cycles_stats[MAX_NR_CPUS]; |
| 220 | static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; | 230 | static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; |
| @@ -246,7 +256,7 @@ retry: | |||
| 246 | evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; | 256 | evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; |
| 247 | 257 | ||
| 248 | if (perf_target__has_cpu(&target)) { | 258 | if (perf_target__has_cpu(&target)) { |
| 249 | ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus); | 259 | ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); |
| 250 | if (ret) | 260 | if (ret) |
| 251 | goto check_ret; | 261 | goto check_ret; |
| 252 | return 0; | 262 | return 0; |
| @@ -327,7 +337,7 @@ static int read_counter_aggr(struct perf_evsel *counter) | |||
| 327 | u64 *count = counter->counts->aggr.values; | 337 | u64 *count = counter->counts->aggr.values; |
| 328 | int i; | 338 | int i; |
| 329 | 339 | ||
| 330 | if (__perf_evsel__read(counter, evsel_list->cpus->nr, | 340 | if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter), |
| 331 | evsel_list->threads->nr, scale) < 0) | 341 | evsel_list->threads->nr, scale) < 0) |
| 332 | return -1; | 342 | return -1; |
| 333 | 343 | ||
| @@ -356,7 +366,7 @@ static int read_counter(struct perf_evsel *counter) | |||
| 356 | u64 *count; | 366 | u64 *count; |
| 357 | int cpu; | 367 | int cpu; |
| 358 | 368 | ||
| 359 | for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) { | 369 | for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { |
| 360 | if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0) | 370 | if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0) |
| 361 | return -1; | 371 | return -1; |
| 362 | 372 | ||
| @@ -495,12 +505,12 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv) | |||
| 495 | if (no_aggr) { | 505 | if (no_aggr) { |
| 496 | list_for_each_entry(counter, &evsel_list->entries, node) { | 506 | list_for_each_entry(counter, &evsel_list->entries, node) { |
| 497 | read_counter(counter); | 507 | read_counter(counter); |
| 498 | perf_evsel__close_fd(counter, evsel_list->cpus->nr, 1); | 508 | perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1); |
| 499 | } | 509 | } |
| 500 | } else { | 510 | } else { |
| 501 | list_for_each_entry(counter, &evsel_list->entries, node) { | 511 | list_for_each_entry(counter, &evsel_list->entries, node) { |
| 502 | read_counter_aggr(counter); | 512 | read_counter_aggr(counter); |
| 503 | perf_evsel__close_fd(counter, evsel_list->cpus->nr, | 513 | perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), |
| 504 | evsel_list->threads->nr); | 514 | evsel_list->threads->nr); |
| 505 | } | 515 | } |
| 506 | } | 516 | } |
| @@ -538,7 +548,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
| 538 | if (no_aggr) | 548 | if (no_aggr) |
| 539 | sprintf(cpustr, "CPU%*d%s", | 549 | sprintf(cpustr, "CPU%*d%s", |
| 540 | csv_output ? 0 : -4, | 550 | csv_output ? 0 : -4, |
| 541 | evsel_list->cpus->map[cpu], csv_sep); | 551 | perf_evsel__cpus(evsel)->map[cpu], csv_sep); |
| 542 | 552 | ||
| 543 | fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel)); | 553 | fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel)); |
| 544 | 554 | ||
| @@ -750,7 +760,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
| 750 | if (no_aggr) | 760 | if (no_aggr) |
| 751 | sprintf(cpustr, "CPU%*d%s", | 761 | sprintf(cpustr, "CPU%*d%s", |
| 752 | csv_output ? 0 : -4, | 762 | csv_output ? 0 : -4, |
| 753 | evsel_list->cpus->map[cpu], csv_sep); | 763 | perf_evsel__cpus(evsel)->map[cpu], csv_sep); |
| 754 | else | 764 | else |
| 755 | cpu = 0; | 765 | cpu = 0; |
| 756 | 766 | ||
| @@ -911,14 +921,14 @@ static void print_counter(struct perf_evsel *counter) | |||
| 911 | u64 ena, run, val; | 921 | u64 ena, run, val; |
| 912 | int cpu; | 922 | int cpu; |
| 913 | 923 | ||
| 914 | for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) { | 924 | for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { |
| 915 | val = counter->counts->cpu[cpu].val; | 925 | val = counter->counts->cpu[cpu].val; |
| 916 | ena = counter->counts->cpu[cpu].ena; | 926 | ena = counter->counts->cpu[cpu].ena; |
| 917 | run = counter->counts->cpu[cpu].run; | 927 | run = counter->counts->cpu[cpu].run; |
| 918 | if (run == 0 || ena == 0) { | 928 | if (run == 0 || ena == 0) { |
| 919 | fprintf(output, "CPU%*d%s%*s%s%*s", | 929 | fprintf(output, "CPU%*d%s%*s%s%*s", |
| 920 | csv_output ? 0 : -4, | 930 | csv_output ? 0 : -4, |
| 921 | evsel_list->cpus->map[cpu], csv_sep, | 931 | perf_evsel__cpus(counter)->map[cpu], csv_sep, |
| 922 | csv_output ? 0 : 18, | 932 | csv_output ? 0 : 18, |
| 923 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, | 933 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, |
| 924 | csv_sep, | 934 | csv_sep, |
| @@ -1217,7 +1227,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1217 | 1227 | ||
| 1218 | list_for_each_entry(pos, &evsel_list->entries, node) { | 1228 | list_for_each_entry(pos, &evsel_list->entries, node) { |
| 1219 | if (perf_evsel__alloc_stat_priv(pos) < 0 || | 1229 | if (perf_evsel__alloc_stat_priv(pos) < 0 || |
| 1220 | perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0) | 1230 | perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0) |
| 1221 | goto out_free_fd; | 1231 | goto out_free_fd; |
| 1222 | } | 1232 | } |
| 1223 | 1233 | ||
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index adc72f09914d..2b32ffa9ebdb 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c | |||
| @@ -38,24 +38,19 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus) | |||
| 38 | return cpus; | 38 | return cpus; |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | static struct cpu_map *cpu_map__read_all_cpu_map(void) | 41 | struct cpu_map *cpu_map__read(FILE *file) |
| 42 | { | 42 | { |
| 43 | struct cpu_map *cpus = NULL; | 43 | struct cpu_map *cpus = NULL; |
| 44 | FILE *onlnf; | ||
| 45 | int nr_cpus = 0; | 44 | int nr_cpus = 0; |
| 46 | int *tmp_cpus = NULL, *tmp; | 45 | int *tmp_cpus = NULL, *tmp; |
| 47 | int max_entries = 0; | 46 | int max_entries = 0; |
| 48 | int n, cpu, prev; | 47 | int n, cpu, prev; |
| 49 | char sep; | 48 | char sep; |
| 50 | 49 | ||
| 51 | onlnf = fopen("/sys/devices/system/cpu/online", "r"); | ||
| 52 | if (!onlnf) | ||
| 53 | return cpu_map__default_new(); | ||
| 54 | |||
| 55 | sep = 0; | 50 | sep = 0; |
| 56 | prev = -1; | 51 | prev = -1; |
| 57 | for (;;) { | 52 | for (;;) { |
| 58 | n = fscanf(onlnf, "%u%c", &cpu, &sep); | 53 | n = fscanf(file, "%u%c", &cpu, &sep); |
| 59 | if (n <= 0) | 54 | if (n <= 0) |
| 60 | break; | 55 | break; |
| 61 | if (prev >= 0) { | 56 | if (prev >= 0) { |
| @@ -95,6 +90,19 @@ static struct cpu_map *cpu_map__read_all_cpu_map(void) | |||
| 95 | cpus = cpu_map__default_new(); | 90 | cpus = cpu_map__default_new(); |
| 96 | out_free_tmp: | 91 | out_free_tmp: |
| 97 | free(tmp_cpus); | 92 | free(tmp_cpus); |
| 93 | return cpus; | ||
| 94 | } | ||
| 95 | |||
| 96 | static struct cpu_map *cpu_map__read_all_cpu_map(void) | ||
| 97 | { | ||
| 98 | struct cpu_map *cpus = NULL; | ||
| 99 | FILE *onlnf; | ||
| 100 | |||
| 101 | onlnf = fopen("/sys/devices/system/cpu/online", "r"); | ||
| 102 | if (!onlnf) | ||
| 103 | return cpu_map__default_new(); | ||
| 104 | |||
| 105 | cpus = cpu_map__read(onlnf); | ||
| 98 | fclose(onlnf); | 106 | fclose(onlnf); |
| 99 | return cpus; | 107 | return cpus; |
| 100 | } | 108 | } |
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index c41518573c6a..17b5264f6436 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h | |||
| @@ -11,7 +11,7 @@ struct cpu_map { | |||
| 11 | struct cpu_map *cpu_map__new(const char *cpu_list); | 11 | struct cpu_map *cpu_map__new(const char *cpu_list); |
| 12 | struct cpu_map *cpu_map__dummy_new(void); | 12 | struct cpu_map *cpu_map__dummy_new(void); |
| 13 | void cpu_map__delete(struct cpu_map *map); | 13 | void cpu_map__delete(struct cpu_map *map); |
| 14 | 14 | struct cpu_map *cpu_map__read(FILE *file); | |
| 15 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); | 15 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); |
| 16 | 16 | ||
| 17 | #endif /* __PERF_CPUMAP_H */ | 17 | #endif /* __PERF_CPUMAP_H */ |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index dc40fe32210b..93876bad2e52 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
| @@ -66,6 +66,7 @@ struct perf_evsel { | |||
| 66 | void *func; | 66 | void *func; |
| 67 | void *data; | 67 | void *data; |
| 68 | } handler; | 68 | } handler; |
| 69 | struct cpu_map *cpus; | ||
| 69 | unsigned int sample_size; | 70 | unsigned int sample_size; |
| 70 | bool supported; | 71 | bool supported; |
| 71 | /* parse modifier helper */ | 72 | /* parse modifier helper */ |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 44afcf40f796..bf5d033ee1b4 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -239,8 +239,11 @@ const char *event_type(int type) | |||
| 239 | return "unknown"; | 239 | return "unknown"; |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | static int add_event(struct list_head **_list, int *idx, | 242 | |
| 243 | struct perf_event_attr *attr, char *name) | 243 | |
| 244 | static int __add_event(struct list_head **_list, int *idx, | ||
| 245 | struct perf_event_attr *attr, | ||
| 246 | char *name, struct cpu_map *cpus) | ||
| 244 | { | 247 | { |
| 245 | struct perf_evsel *evsel; | 248 | struct perf_evsel *evsel; |
| 246 | struct list_head *list = *_list; | 249 | struct list_head *list = *_list; |
| @@ -260,6 +263,7 @@ static int add_event(struct list_head **_list, int *idx, | |||
| 260 | return -ENOMEM; | 263 | return -ENOMEM; |
| 261 | } | 264 | } |
| 262 | 265 | ||
| 266 | evsel->cpus = cpus; | ||
| 263 | if (name) | 267 | if (name) |
| 264 | evsel->name = strdup(name); | 268 | evsel->name = strdup(name); |
| 265 | list_add_tail(&evsel->node, list); | 269 | list_add_tail(&evsel->node, list); |
| @@ -267,6 +271,12 @@ static int add_event(struct list_head **_list, int *idx, | |||
| 267 | return 0; | 271 | return 0; |
| 268 | } | 272 | } |
| 269 | 273 | ||
| 274 | static int add_event(struct list_head **_list, int *idx, | ||
| 275 | struct perf_event_attr *attr, char *name) | ||
| 276 | { | ||
| 277 | return __add_event(_list, idx, attr, name, NULL); | ||
| 278 | } | ||
| 279 | |||
| 270 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) | 280 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) |
| 271 | { | 281 | { |
| 272 | int i, j; | 282 | int i, j; |
| @@ -607,8 +617,8 @@ int parse_events_add_pmu(struct list_head **list, int *idx, | |||
| 607 | if (perf_pmu__config(pmu, &attr, head_config)) | 617 | if (perf_pmu__config(pmu, &attr, head_config)) |
| 608 | return -EINVAL; | 618 | return -EINVAL; |
| 609 | 619 | ||
| 610 | return add_event(list, idx, &attr, | 620 | return __add_event(list, idx, &attr, pmu_event_name(head_config), |
| 611 | pmu_event_name(head_config)); | 621 | pmu->cpus); |
| 612 | } | 622 | } |
| 613 | 623 | ||
| 614 | int parse_events__modifier_group(struct list_head *list, | 624 | int parse_events__modifier_group(struct list_head *list, |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 6631d828db3d..8a2229da594f 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "util.h" | 9 | #include "util.h" |
| 10 | #include "pmu.h" | 10 | #include "pmu.h" |
| 11 | #include "parse-events.h" | 11 | #include "parse-events.h" |
| 12 | #include "cpumap.h" | ||
| 12 | 13 | ||
| 13 | #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" | 14 | #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" |
| 14 | 15 | ||
| @@ -253,6 +254,33 @@ static void pmu_read_sysfs(void) | |||
| 253 | closedir(dir); | 254 | closedir(dir); |
| 254 | } | 255 | } |
| 255 | 256 | ||
| 257 | static struct cpu_map *pmu_cpumask(char *name) | ||
| 258 | { | ||
| 259 | struct stat st; | ||
| 260 | char path[PATH_MAX]; | ||
| 261 | const char *sysfs; | ||
| 262 | FILE *file; | ||
| 263 | struct cpu_map *cpus; | ||
| 264 | |||
| 265 | sysfs = sysfs_find_mountpoint(); | ||
| 266 | if (!sysfs) | ||
| 267 | return NULL; | ||
| 268 | |||
| 269 | snprintf(path, PATH_MAX, | ||
| 270 | "%s/bus/event_source/devices/%s/cpumask", sysfs, name); | ||
| 271 | |||
| 272 | if (stat(path, &st) < 0) | ||
| 273 | return NULL; | ||
| 274 | |||
| 275 | file = fopen(path, "r"); | ||
| 276 | if (!file) | ||
| 277 | return NULL; | ||
| 278 | |||
| 279 | cpus = cpu_map__read(file); | ||
| 280 | fclose(file); | ||
| 281 | return cpus; | ||
| 282 | } | ||
| 283 | |||
| 256 | static struct perf_pmu *pmu_lookup(char *name) | 284 | static struct perf_pmu *pmu_lookup(char *name) |
| 257 | { | 285 | { |
| 258 | struct perf_pmu *pmu; | 286 | struct perf_pmu *pmu; |
| @@ -275,6 +303,8 @@ static struct perf_pmu *pmu_lookup(char *name) | |||
| 275 | if (!pmu) | 303 | if (!pmu) |
| 276 | return NULL; | 304 | return NULL; |
| 277 | 305 | ||
| 306 | pmu->cpus = pmu_cpumask(name); | ||
| 307 | |||
| 278 | pmu_aliases(name, &aliases); | 308 | pmu_aliases(name, &aliases); |
| 279 | 309 | ||
| 280 | INIT_LIST_HEAD(&pmu->format); | 310 | INIT_LIST_HEAD(&pmu->format); |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 47f68d3cc5d1..53c7794fc4be 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
| @@ -28,6 +28,7 @@ struct perf_pmu__alias { | |||
| 28 | struct perf_pmu { | 28 | struct perf_pmu { |
| 29 | char *name; | 29 | char *name; |
| 30 | __u32 type; | 30 | __u32 type; |
| 31 | struct cpu_map *cpus; | ||
| 31 | struct list_head format; | 32 | struct list_head format; |
| 32 | struct list_head aliases; | 33 | struct list_head aliases; |
| 33 | struct list_head list; | 34 | struct list_head list; |
