diff options
| author | Adrian Hunter <adrian.hunter@intel.com> | 2014-07-31 02:00:51 -0400 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2014-08-13 18:21:18 -0400 |
| commit | bf8e8f4b832972c76d64ab2e2837a48397144887 (patch) | |
| tree | 55b1b99106fe3bbb4362ac1ec80666b3ab2fbb57 | |
| parent | f247fb8191aa7f10d3f6c987e8ef0853ae789a02 (diff) | |
perf evlist: Add 'system_wide' option
Add an option to cause a selected event to be opened always without a
pid when configured by perf_evsel__config().
This is needed when using the sched_switch tracepoint to follow object
code execution.
sched_switch occurs before the task switch and so it cannot record it in
a context limited to that task. Note that also means that sched_switch
is useless when capturing data per-thread, as is the 'context-switches'
software event for the same reason.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1406786474-9306-9-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
| -rw-r--r-- | tools/perf/util/evlist.c | 45 | ||||
| -rw-r--r-- | tools/perf/util/evsel.c | 31 | ||||
| -rw-r--r-- | tools/perf/util/evsel.h | 1 |
3 files changed, 64 insertions, 13 deletions
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 3b366c085021..c74d8ecc9c70 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
| @@ -265,17 +265,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist, | |||
| 265 | return 0; | 265 | return 0; |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | static int perf_evlist__nr_threads(struct perf_evlist *evlist, | ||
| 269 | struct perf_evsel *evsel) | ||
| 270 | { | ||
| 271 | if (evsel->system_wide) | ||
| 272 | return 1; | ||
| 273 | else | ||
| 274 | return thread_map__nr(evlist->threads); | ||
| 275 | } | ||
| 276 | |||
| 268 | void perf_evlist__disable(struct perf_evlist *evlist) | 277 | void perf_evlist__disable(struct perf_evlist *evlist) |
| 269 | { | 278 | { |
| 270 | int cpu, thread; | 279 | int cpu, thread; |
| 271 | struct perf_evsel *pos; | 280 | struct perf_evsel *pos; |
| 272 | int nr_cpus = cpu_map__nr(evlist->cpus); | 281 | int nr_cpus = cpu_map__nr(evlist->cpus); |
| 273 | int nr_threads = thread_map__nr(evlist->threads); | 282 | int nr_threads; |
| 274 | 283 | ||
| 275 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 284 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
| 276 | evlist__for_each(evlist, pos) { | 285 | evlist__for_each(evlist, pos) { |
| 277 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) | 286 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) |
| 278 | continue; | 287 | continue; |
| 288 | nr_threads = perf_evlist__nr_threads(evlist, pos); | ||
| 279 | for (thread = 0; thread < nr_threads; thread++) | 289 | for (thread = 0; thread < nr_threads; thread++) |
| 280 | ioctl(FD(pos, cpu, thread), | 290 | ioctl(FD(pos, cpu, thread), |
| 281 | PERF_EVENT_IOC_DISABLE, 0); | 291 | PERF_EVENT_IOC_DISABLE, 0); |
| @@ -288,12 +298,13 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
| 288 | int cpu, thread; | 298 | int cpu, thread; |
| 289 | struct perf_evsel *pos; | 299 | struct perf_evsel *pos; |
| 290 | int nr_cpus = cpu_map__nr(evlist->cpus); | 300 | int nr_cpus = cpu_map__nr(evlist->cpus); |
| 291 | int nr_threads = thread_map__nr(evlist->threads); | 301 | int nr_threads; |
| 292 | 302 | ||
| 293 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 303 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
| 294 | evlist__for_each(evlist, pos) { | 304 | evlist__for_each(evlist, pos) { |
| 295 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) | 305 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) |
| 296 | continue; | 306 | continue; |
| 307 | nr_threads = perf_evlist__nr_threads(evlist, pos); | ||
| 297 | for (thread = 0; thread < nr_threads; thread++) | 308 | for (thread = 0; thread < nr_threads; thread++) |
| 298 | ioctl(FD(pos, cpu, thread), | 309 | ioctl(FD(pos, cpu, thread), |
| 299 | PERF_EVENT_IOC_ENABLE, 0); | 310 | PERF_EVENT_IOC_ENABLE, 0); |
| @@ -305,12 +316,14 @@ int perf_evlist__disable_event(struct perf_evlist *evlist, | |||
| 305 | struct perf_evsel *evsel) | 316 | struct perf_evsel *evsel) |
| 306 | { | 317 | { |
| 307 | int cpu, thread, err; | 318 | int cpu, thread, err; |
| 319 | int nr_cpus = cpu_map__nr(evlist->cpus); | ||
| 320 | int nr_threads = perf_evlist__nr_threads(evlist, evsel); | ||
| 308 | 321 | ||
| 309 | if (!evsel->fd) | 322 | if (!evsel->fd) |
| 310 | return 0; | 323 | return 0; |
| 311 | 324 | ||
| 312 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 325 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
| 313 | for (thread = 0; thread < evlist->threads->nr; thread++) { | 326 | for (thread = 0; thread < nr_threads; thread++) { |
| 314 | err = ioctl(FD(evsel, cpu, thread), | 327 | err = ioctl(FD(evsel, cpu, thread), |
| 315 | PERF_EVENT_IOC_DISABLE, 0); | 328 | PERF_EVENT_IOC_DISABLE, 0); |
| 316 | if (err) | 329 | if (err) |
| @@ -324,12 +337,14 @@ int perf_evlist__enable_event(struct perf_evlist *evlist, | |||
| 324 | struct perf_evsel *evsel) | 337 | struct perf_evsel *evsel) |
| 325 | { | 338 | { |
| 326 | int cpu, thread, err; | 339 | int cpu, thread, err; |
| 340 | int nr_cpus = cpu_map__nr(evlist->cpus); | ||
| 341 | int nr_threads = perf_evlist__nr_threads(evlist, evsel); | ||
| 327 | 342 | ||
| 328 | if (!evsel->fd) | 343 | if (!evsel->fd) |
| 329 | return -EINVAL; | 344 | return -EINVAL; |
| 330 | 345 | ||
| 331 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 346 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
| 332 | for (thread = 0; thread < evlist->threads->nr; thread++) { | 347 | for (thread = 0; thread < nr_threads; thread++) { |
| 333 | err = ioctl(FD(evsel, cpu, thread), | 348 | err = ioctl(FD(evsel, cpu, thread), |
| 334 | PERF_EVENT_IOC_ENABLE, 0); | 349 | PERF_EVENT_IOC_ENABLE, 0); |
| 335 | if (err) | 350 | if (err) |
| @@ -343,7 +358,16 @@ static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | |||
| 343 | { | 358 | { |
| 344 | int nr_cpus = cpu_map__nr(evlist->cpus); | 359 | int nr_cpus = cpu_map__nr(evlist->cpus); |
| 345 | int nr_threads = thread_map__nr(evlist->threads); | 360 | int nr_threads = thread_map__nr(evlist->threads); |
| 346 | int nfds = nr_cpus * nr_threads * evlist->nr_entries; | 361 | int nfds = 0; |
| 362 | struct perf_evsel *evsel; | ||
| 363 | |||
| 364 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
| 365 | if (evsel->system_wide) | ||
| 366 | nfds += nr_cpus; | ||
| 367 | else | ||
| 368 | nfds += nr_cpus * nr_threads; | ||
| 369 | } | ||
| 370 | |||
| 347 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); | 371 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); |
| 348 | return evlist->pollfd != NULL ? 0 : -ENOMEM; | 372 | return evlist->pollfd != NULL ? 0 : -ENOMEM; |
| 349 | } | 373 | } |
| @@ -636,7 +660,12 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, | |||
| 636 | struct perf_evsel *evsel; | 660 | struct perf_evsel *evsel; |
| 637 | 661 | ||
| 638 | evlist__for_each(evlist, evsel) { | 662 | evlist__for_each(evlist, evsel) { |
| 639 | int fd = FD(evsel, cpu, thread); | 663 | int fd; |
| 664 | |||
| 665 | if (evsel->system_wide && thread) | ||
| 666 | continue; | ||
| 667 | |||
| 668 | fd = FD(evsel, cpu, thread); | ||
| 640 | 669 | ||
| 641 | if (*output == -1) { | 670 | if (*output == -1) { |
| 642 | *output = fd; | 671 | *output = fd; |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 0c8919decac8..66de9a708163 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -695,6 +695,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
| 695 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 695 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) |
| 696 | { | 696 | { |
| 697 | int cpu, thread; | 697 | int cpu, thread; |
| 698 | |||
| 699 | if (evsel->system_wide) | ||
| 700 | nthreads = 1; | ||
| 701 | |||
| 698 | evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); | 702 | evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); |
| 699 | 703 | ||
| 700 | if (evsel->fd) { | 704 | if (evsel->fd) { |
| @@ -713,6 +717,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea | |||
| 713 | { | 717 | { |
| 714 | int cpu, thread; | 718 | int cpu, thread; |
| 715 | 719 | ||
| 720 | if (evsel->system_wide) | ||
| 721 | nthreads = 1; | ||
| 722 | |||
| 716 | for (cpu = 0; cpu < ncpus; cpu++) { | 723 | for (cpu = 0; cpu < ncpus; cpu++) { |
| 717 | for (thread = 0; thread < nthreads; thread++) { | 724 | for (thread = 0; thread < nthreads; thread++) { |
| 718 | int fd = FD(evsel, cpu, thread), | 725 | int fd = FD(evsel, cpu, thread), |
| @@ -743,6 +750,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
| 743 | 750 | ||
| 744 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) | 751 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) |
| 745 | { | 752 | { |
| 753 | if (evsel->system_wide) | ||
| 754 | nthreads = 1; | ||
| 755 | |||
| 746 | evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); | 756 | evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); |
| 747 | if (evsel->sample_id == NULL) | 757 | if (evsel->sample_id == NULL) |
| 748 | return -ENOMEM; | 758 | return -ENOMEM; |
| @@ -787,6 +797,9 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
| 787 | { | 797 | { |
| 788 | int cpu, thread; | 798 | int cpu, thread; |
| 789 | 799 | ||
| 800 | if (evsel->system_wide) | ||
| 801 | nthreads = 1; | ||
| 802 | |||
| 790 | for (cpu = 0; cpu < ncpus; cpu++) | 803 | for (cpu = 0; cpu < ncpus; cpu++) |
| 791 | for (thread = 0; thread < nthreads; ++thread) { | 804 | for (thread = 0; thread < nthreads; ++thread) { |
| 792 | close(FD(evsel, cpu, thread)); | 805 | close(FD(evsel, cpu, thread)); |
| @@ -875,6 +888,9 @@ int __perf_evsel__read(struct perf_evsel *evsel, | |||
| 875 | int cpu, thread; | 888 | int cpu, thread; |
| 876 | struct perf_counts_values *aggr = &evsel->counts->aggr, count; | 889 | struct perf_counts_values *aggr = &evsel->counts->aggr, count; |
| 877 | 890 | ||
| 891 | if (evsel->system_wide) | ||
| 892 | nthreads = 1; | ||
| 893 | |||
| 878 | aggr->val = aggr->ena = aggr->run = 0; | 894 | aggr->val = aggr->ena = aggr->run = 0; |
| 879 | 895 | ||
| 880 | for (cpu = 0; cpu < ncpus; cpu++) { | 896 | for (cpu = 0; cpu < ncpus; cpu++) { |
| @@ -997,13 +1013,18 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) | |||
| 997 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 1013 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
| 998 | struct thread_map *threads) | 1014 | struct thread_map *threads) |
| 999 | { | 1015 | { |
| 1000 | int cpu, thread; | 1016 | int cpu, thread, nthreads; |
| 1001 | unsigned long flags = PERF_FLAG_FD_CLOEXEC; | 1017 | unsigned long flags = PERF_FLAG_FD_CLOEXEC; |
| 1002 | int pid = -1, err; | 1018 | int pid = -1, err; |
| 1003 | enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; | 1019 | enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; |
| 1004 | 1020 | ||
| 1021 | if (evsel->system_wide) | ||
| 1022 | nthreads = 1; | ||
| 1023 | else | ||
| 1024 | nthreads = threads->nr; | ||
| 1025 | |||
| 1005 | if (evsel->fd == NULL && | 1026 | if (evsel->fd == NULL && |
| 1006 | perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) | 1027 | perf_evsel__alloc_fd(evsel, cpus->nr, nthreads) < 0) |
| 1007 | return -ENOMEM; | 1028 | return -ENOMEM; |
| 1008 | 1029 | ||
| 1009 | if (evsel->cgrp) { | 1030 | if (evsel->cgrp) { |
| @@ -1027,10 +1048,10 @@ retry_sample_id: | |||
| 1027 | 1048 | ||
| 1028 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 1049 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
| 1029 | 1050 | ||
| 1030 | for (thread = 0; thread < threads->nr; thread++) { | 1051 | for (thread = 0; thread < nthreads; thread++) { |
| 1031 | int group_fd; | 1052 | int group_fd; |
| 1032 | 1053 | ||
| 1033 | if (!evsel->cgrp) | 1054 | if (!evsel->cgrp && !evsel->system_wide) |
| 1034 | pid = threads->map[thread]; | 1055 | pid = threads->map[thread]; |
| 1035 | 1056 | ||
| 1036 | group_fd = get_group_fd(evsel, cpu, thread); | 1057 | group_fd = get_group_fd(evsel, cpu, thread); |
| @@ -1103,7 +1124,7 @@ out_close: | |||
| 1103 | close(FD(evsel, cpu, thread)); | 1124 | close(FD(evsel, cpu, thread)); |
| 1104 | FD(evsel, cpu, thread) = -1; | 1125 | FD(evsel, cpu, thread) = -1; |
| 1105 | } | 1126 | } |
| 1106 | thread = threads->nr; | 1127 | thread = nthreads; |
| 1107 | } while (--cpu >= 0); | 1128 | } while (--cpu >= 0); |
| 1108 | return err; | 1129 | return err; |
| 1109 | } | 1130 | } |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index d7f93ce0ebc1..dbb2a0d20907 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
| @@ -85,6 +85,7 @@ struct perf_evsel { | |||
| 85 | bool needs_swap; | 85 | bool needs_swap; |
| 86 | bool no_aux_samples; | 86 | bool no_aux_samples; |
| 87 | bool immediate; | 87 | bool immediate; |
| 88 | bool system_wide; | ||
| 88 | /* parse modifier helper */ | 89 | /* parse modifier helper */ |
| 89 | int exclude_GH; | 90 | int exclude_GH; |
| 90 | int nr_members; | 91 | int nr_members; |
