diff options
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r-- | tools/perf/builtin-record.c | 113 |
1 files changed, 54 insertions, 59 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 50efbd509b8..e68aee33bc1 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include "util/header.h" | 19 | #include "util/header.h" |
20 | #include "util/event.h" | 20 | #include "util/event.h" |
21 | #include "util/evsel.h" | ||
21 | #include "util/debug.h" | 22 | #include "util/debug.h" |
22 | #include "util/session.h" | 23 | #include "util/session.h" |
23 | #include "util/symbol.h" | 24 | #include "util/symbol.h" |
@@ -27,13 +28,13 @@ | |||
27 | #include <sched.h> | 28 | #include <sched.h> |
28 | #include <sys/mman.h> | 29 | #include <sys/mman.h> |
29 | 30 | ||
31 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | ||
32 | |||
30 | enum write_mode_t { | 33 | enum write_mode_t { |
31 | WRITE_FORCE, | 34 | WRITE_FORCE, |
32 | WRITE_APPEND | 35 | WRITE_APPEND |
33 | }; | 36 | }; |
34 | 37 | ||
35 | static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; | ||
36 | |||
37 | static u64 user_interval = ULLONG_MAX; | 38 | static u64 user_interval = ULLONG_MAX; |
38 | static u64 default_interval = 0; | 39 | static u64 default_interval = 0; |
39 | static u64 sample_type; | 40 | static u64 sample_type; |
@@ -81,7 +82,6 @@ static struct perf_session *session; | |||
81 | static const char *cpu_list; | 82 | static const char *cpu_list; |
82 | 83 | ||
83 | struct mmap_data { | 84 | struct mmap_data { |
84 | int counter; | ||
85 | void *base; | 85 | void *base; |
86 | unsigned int mask; | 86 | unsigned int mask; |
87 | unsigned int prev; | 87 | unsigned int prev; |
@@ -229,12 +229,12 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n | |||
229 | return h_attr; | 229 | return h_attr; |
230 | } | 230 | } |
231 | 231 | ||
232 | static void create_counter(int counter, int cpu) | 232 | static void create_counter(struct perf_evsel *evsel, int cpu) |
233 | { | 233 | { |
234 | char *filter = filters[counter]; | 234 | char *filter = evsel->filter; |
235 | struct perf_event_attr *attr = attrs + counter; | 235 | struct perf_event_attr *attr = &evsel->attr; |
236 | struct perf_header_attr *h_attr; | 236 | struct perf_header_attr *h_attr; |
237 | int track = !counter; /* only the first counter needs these */ | 237 | int track = !evsel->idx; /* only the first counter needs these */ |
238 | int thread_index; | 238 | int thread_index; |
239 | int ret; | 239 | int ret; |
240 | struct { | 240 | struct { |
@@ -320,10 +320,9 @@ retry_sample_id: | |||
320 | 320 | ||
321 | for (thread_index = 0; thread_index < thread_num; thread_index++) { | 321 | for (thread_index = 0; thread_index < thread_num; thread_index++) { |
322 | try_again: | 322 | try_again: |
323 | fd[nr_cpu][counter][thread_index] = sys_perf_event_open(attr, | 323 | FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, all_tids[thread_index], cpu, group_fd, 0); |
324 | all_tids[thread_index], cpu, group_fd, 0); | ||
325 | 324 | ||
326 | if (fd[nr_cpu][counter][thread_index] < 0) { | 325 | if (FD(evsel, nr_cpu, thread_index) < 0) { |
327 | int err = errno; | 326 | int err = errno; |
328 | 327 | ||
329 | if (err == EPERM || err == EACCES) | 328 | if (err == EPERM || err == EACCES) |
@@ -360,7 +359,7 @@ try_again: | |||
360 | } | 359 | } |
361 | printf("\n"); | 360 | printf("\n"); |
362 | error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", | 361 | error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", |
363 | fd[nr_cpu][counter][thread_index], strerror(err)); | 362 | FD(evsel, nr_cpu, thread_index), strerror(err)); |
364 | 363 | ||
365 | #if defined(__i386__) || defined(__x86_64__) | 364 | #if defined(__i386__) || defined(__x86_64__) |
366 | if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) | 365 | if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) |
@@ -374,7 +373,7 @@ try_again: | |||
374 | exit(-1); | 373 | exit(-1); |
375 | } | 374 | } |
376 | 375 | ||
377 | h_attr = get_header_attr(attr, counter); | 376 | h_attr = get_header_attr(attr, evsel->idx); |
378 | if (h_attr == NULL) | 377 | if (h_attr == NULL) |
379 | die("nomem\n"); | 378 | die("nomem\n"); |
380 | 379 | ||
@@ -385,7 +384,7 @@ try_again: | |||
385 | } | 384 | } |
386 | } | 385 | } |
387 | 386 | ||
388 | if (read(fd[nr_cpu][counter][thread_index], &read_data, sizeof(read_data)) == -1) { | 387 | if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) { |
389 | perror("Unable to read perf file descriptor"); | 388 | perror("Unable to read perf file descriptor"); |
390 | exit(-1); | 389 | exit(-1); |
391 | } | 390 | } |
@@ -395,43 +394,44 @@ try_again: | |||
395 | exit(-1); | 394 | exit(-1); |
396 | } | 395 | } |
397 | 396 | ||
398 | assert(fd[nr_cpu][counter][thread_index] >= 0); | 397 | assert(FD(evsel, nr_cpu, thread_index) >= 0); |
399 | fcntl(fd[nr_cpu][counter][thread_index], F_SETFL, O_NONBLOCK); | 398 | fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK); |
400 | 399 | ||
401 | /* | 400 | /* |
402 | * First counter acts as the group leader: | 401 | * First counter acts as the group leader: |
403 | */ | 402 | */ |
404 | if (group && group_fd == -1) | 403 | if (group && group_fd == -1) |
405 | group_fd = fd[nr_cpu][counter][thread_index]; | 404 | group_fd = FD(evsel, nr_cpu, thread_index); |
406 | 405 | ||
407 | if (counter || thread_index) { | 406 | if (evsel->idx || thread_index) { |
408 | ret = ioctl(fd[nr_cpu][counter][thread_index], | 407 | struct perf_evsel *first; |
409 | PERF_EVENT_IOC_SET_OUTPUT, | 408 | first = list_entry(evsel_list.next, struct perf_evsel, node); |
410 | fd[nr_cpu][0][0]); | 409 | ret = ioctl(FD(evsel, nr_cpu, thread_index), |
410 | PERF_EVENT_IOC_SET_OUTPUT, | ||
411 | FD(first, nr_cpu, 0)); | ||
411 | if (ret) { | 412 | if (ret) { |
412 | error("failed to set output: %d (%s)\n", errno, | 413 | error("failed to set output: %d (%s)\n", errno, |
413 | strerror(errno)); | 414 | strerror(errno)); |
414 | exit(-1); | 415 | exit(-1); |
415 | } | 416 | } |
416 | } else { | 417 | } else { |
417 | mmap_array[nr_cpu].counter = counter; | ||
418 | mmap_array[nr_cpu].prev = 0; | 418 | mmap_array[nr_cpu].prev = 0; |
419 | mmap_array[nr_cpu].mask = mmap_pages*page_size - 1; | 419 | mmap_array[nr_cpu].mask = mmap_pages*page_size - 1; |
420 | mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size, | 420 | mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size, |
421 | PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter][thread_index], 0); | 421 | PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0); |
422 | if (mmap_array[nr_cpu].base == MAP_FAILED) { | 422 | if (mmap_array[nr_cpu].base == MAP_FAILED) { |
423 | error("failed to mmap with %d (%s)\n", errno, strerror(errno)); | 423 | error("failed to mmap with %d (%s)\n", errno, strerror(errno)); |
424 | exit(-1); | 424 | exit(-1); |
425 | } | 425 | } |
426 | 426 | ||
427 | event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index]; | 427 | event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index); |
428 | event_array[nr_poll].events = POLLIN; | 428 | event_array[nr_poll].events = POLLIN; |
429 | nr_poll++; | 429 | nr_poll++; |
430 | } | 430 | } |
431 | 431 | ||
432 | if (filter != NULL) { | 432 | if (filter != NULL) { |
433 | ret = ioctl(fd[nr_cpu][counter][thread_index], | 433 | ret = ioctl(FD(evsel, nr_cpu, thread_index), |
434 | PERF_EVENT_IOC_SET_FILTER, filter); | 434 | PERF_EVENT_IOC_SET_FILTER, filter); |
435 | if (ret) { | 435 | if (ret) { |
436 | error("failed to set filter with %d (%s)\n", errno, | 436 | error("failed to set filter with %d (%s)\n", errno, |
437 | strerror(errno)); | 437 | strerror(errno)); |
@@ -446,11 +446,12 @@ try_again: | |||
446 | 446 | ||
447 | static void open_counters(int cpu) | 447 | static void open_counters(int cpu) |
448 | { | 448 | { |
449 | int counter; | 449 | struct perf_evsel *pos; |
450 | 450 | ||
451 | group_fd = -1; | 451 | group_fd = -1; |
452 | for (counter = 0; counter < nr_counters; counter++) | 452 | |
453 | create_counter(counter, cpu); | 453 | list_for_each_entry(pos, &evsel_list, node) |
454 | create_counter(pos, cpu); | ||
454 | 455 | ||
455 | nr_cpu++; | 456 | nr_cpu++; |
456 | } | 457 | } |
@@ -537,7 +538,7 @@ static void mmap_read_all(void) | |||
537 | 538 | ||
538 | static int __cmd_record(int argc, const char **argv) | 539 | static int __cmd_record(int argc, const char **argv) |
539 | { | 540 | { |
540 | int i, counter; | 541 | int i; |
541 | struct stat st; | 542 | struct stat st; |
542 | int flags; | 543 | int flags; |
543 | int err; | 544 | int err; |
@@ -604,7 +605,7 @@ static int __cmd_record(int argc, const char **argv) | |||
604 | goto out_delete_session; | 605 | goto out_delete_session; |
605 | } | 606 | } |
606 | 607 | ||
607 | if (have_tracepoints(attrs, nr_counters)) | 608 | if (have_tracepoints(&evsel_list)) |
608 | perf_header__set_feat(&session->header, HEADER_TRACE_INFO); | 609 | perf_header__set_feat(&session->header, HEADER_TRACE_INFO); |
609 | 610 | ||
610 | /* | 611 | /* |
@@ -666,12 +667,6 @@ static int __cmd_record(int argc, const char **argv) | |||
666 | close(child_ready_pipe[0]); | 667 | close(child_ready_pipe[0]); |
667 | } | 668 | } |
668 | 669 | ||
669 | nr_cpus = read_cpu_map(cpu_list); | ||
670 | if (nr_cpus < 1) { | ||
671 | perror("failed to collect number of CPUs"); | ||
672 | return -1; | ||
673 | } | ||
674 | |||
675 | if (!system_wide && no_inherit && !cpu_list) { | 670 | if (!system_wide && no_inherit && !cpu_list) { |
676 | open_counters(-1); | 671 | open_counters(-1); |
677 | } else { | 672 | } else { |
@@ -711,7 +706,7 @@ static int __cmd_record(int argc, const char **argv) | |||
711 | return err; | 706 | return err; |
712 | } | 707 | } |
713 | 708 | ||
714 | if (have_tracepoints(attrs, nr_counters)) { | 709 | if (have_tracepoints(&evsel_list)) { |
715 | /* | 710 | /* |
716 | * FIXME err <= 0 here actually means that | 711 | * FIXME err <= 0 here actually means that |
717 | * there were no tracepoints so its not really | 712 | * there were no tracepoints so its not really |
@@ -720,8 +715,7 @@ static int __cmd_record(int argc, const char **argv) | |||
720 | * return this more properly and also | 715 | * return this more properly and also |
721 | * propagate errors that now are calling die() | 716 | * propagate errors that now are calling die() |
722 | */ | 717 | */ |
723 | err = event__synthesize_tracing_data(output, attrs, | 718 | err = event__synthesize_tracing_data(output, &evsel_list, |
724 | nr_counters, | ||
725 | process_synthesized_event, | 719 | process_synthesized_event, |
726 | session); | 720 | session); |
727 | if (err <= 0) { | 721 | if (err <= 0) { |
@@ -795,13 +789,13 @@ static int __cmd_record(int argc, const char **argv) | |||
795 | 789 | ||
796 | if (done) { | 790 | if (done) { |
797 | for (i = 0; i < nr_cpu; i++) { | 791 | for (i = 0; i < nr_cpu; i++) { |
798 | for (counter = 0; | 792 | struct perf_evsel *pos; |
799 | counter < nr_counters; | 793 | |
800 | counter++) { | 794 | list_for_each_entry(pos, &evsel_list, node) { |
801 | for (thread = 0; | 795 | for (thread = 0; |
802 | thread < thread_num; | 796 | thread < thread_num; |
803 | thread++) | 797 | thread++) |
804 | ioctl(fd[i][counter][thread], | 798 | ioctl(FD(pos, i, thread), |
805 | PERF_EVENT_IOC_DISABLE); | 799 | PERF_EVENT_IOC_DISABLE); |
806 | } | 800 | } |
807 | } | 801 | } |
@@ -887,7 +881,8 @@ const struct option record_options[] = { | |||
887 | 881 | ||
888 | int cmd_record(int argc, const char **argv, const char *prefix __used) | 882 | int cmd_record(int argc, const char **argv, const char *prefix __used) |
889 | { | 883 | { |
890 | int i, j, err = -ENOMEM; | 884 | int err = -ENOMEM; |
885 | struct perf_evsel *pos; | ||
891 | 886 | ||
892 | argc = parse_options(argc, argv, record_options, record_usage, | 887 | argc = parse_options(argc, argv, record_options, record_usage, |
893 | PARSE_OPT_STOP_AT_NON_OPTION); | 888 | PARSE_OPT_STOP_AT_NON_OPTION); |
@@ -910,10 +905,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
910 | if (no_buildid_cache || no_buildid) | 905 | if (no_buildid_cache || no_buildid) |
911 | disable_buildid_cache(); | 906 | disable_buildid_cache(); |
912 | 907 | ||
913 | if (!nr_counters) { | 908 | if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) { |
914 | nr_counters = 1; | 909 | pr_err("Not enough memory for event selector list\n"); |
915 | attrs[0].type = PERF_TYPE_HARDWARE; | 910 | goto out_symbol_exit; |
916 | attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; | ||
917 | } | 911 | } |
918 | 912 | ||
919 | if (target_pid != -1) { | 913 | if (target_pid != -1) { |
@@ -933,12 +927,15 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
933 | thread_num = 1; | 927 | thread_num = 1; |
934 | } | 928 | } |
935 | 929 | ||
936 | for (i = 0; i < MAX_NR_CPUS; i++) { | 930 | nr_cpus = read_cpu_map(cpu_list); |
937 | for (j = 0; j < MAX_COUNTERS; j++) { | 931 | if (nr_cpus < 1) { |
938 | fd[i][j] = malloc(sizeof(int)*thread_num); | 932 | perror("failed to collect number of CPUs"); |
939 | if (!fd[i][j]) | 933 | return -1; |
940 | goto out_free_fd; | 934 | } |
941 | } | 935 | |
936 | list_for_each_entry(pos, &evsel_list, node) { | ||
937 | if (perf_evsel__alloc_fd(pos, nr_cpus, thread_num) < 0) | ||
938 | goto out_free_fd; | ||
942 | } | 939 | } |
943 | event_array = malloc( | 940 | event_array = malloc( |
944 | sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); | 941 | sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); |
@@ -968,10 +965,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
968 | out_free_event_array: | 965 | out_free_event_array: |
969 | free(event_array); | 966 | free(event_array); |
970 | out_free_fd: | 967 | out_free_fd: |
971 | for (i = 0; i < MAX_NR_CPUS; i++) { | 968 | list_for_each_entry(pos, &evsel_list, node) |
972 | for (j = 0; j < MAX_COUNTERS; j++) | 969 | perf_evsel__free_fd(pos); |
973 | free(fd[i][j]); | ||
974 | } | ||
975 | free(all_tids); | 970 | free(all_tids); |
976 | all_tids = NULL; | 971 | all_tids = NULL; |
977 | out_symbol_exit: | 972 | out_symbol_exit: |