aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-record.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r--tools/perf/builtin-record.c113
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
30enum write_mode_t { 33enum write_mode_t {
31 WRITE_FORCE, 34 WRITE_FORCE,
32 WRITE_APPEND 35 WRITE_APPEND
33}; 36};
34 37
35static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
36
37static u64 user_interval = ULLONG_MAX; 38static u64 user_interval = ULLONG_MAX;
38static u64 default_interval = 0; 39static u64 default_interval = 0;
39static u64 sample_type; 40static u64 sample_type;
@@ -81,7 +82,6 @@ static struct perf_session *session;
81static const char *cpu_list; 82static const char *cpu_list;
82 83
83struct mmap_data { 84struct 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
232static void create_counter(int counter, int cpu) 232static 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++) {
322try_again: 322try_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
447static void open_counters(int cpu) 447static 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
538static int __cmd_record(int argc, const char **argv) 539static 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
888int cmd_record(int argc, const char **argv, const char *prefix __used) 882int 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)
968out_free_event_array: 965out_free_event_array:
969 free(event_array); 966 free(event_array);
970out_free_fd: 967out_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;
977out_symbol_exit: 972out_symbol_exit: