aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-record.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2011-01-04 02:10:28 -0500
committerIngo Molnar <mingo@elte.hu>2011-01-04 02:10:28 -0500
commit928585536ff5a8f320e60efc60e2b7ef2a5f548d (patch)
tree5b12281a00ec049e8c35f1fb2810e111b22c90c0 /tools/perf/builtin-record.c
parentcc2221969906a166a638aecdbae84a3d0462719e (diff)
parentd854861c4292a4e675a5d3bfd862c5f7421c81e8 (diff)
Merge branch 'perf/test' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/core
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r--tools/perf/builtin-record.c152
1 files changed, 68 insertions, 84 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 50efbd509b8f..7bc049035484 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,18 +28,18 @@
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;
40 41
41static int nr_cpus = 0; 42static struct cpu_map *cpus;
42static unsigned int page_size; 43static unsigned int page_size;
43static unsigned int mmap_pages = 128; 44static unsigned int mmap_pages = 128;
44static unsigned int user_freq = UINT_MAX; 45static unsigned int user_freq = UINT_MAX;
@@ -53,8 +54,7 @@ static bool sample_id_all_avail = true;
53static bool system_wide = false; 54static bool system_wide = false;
54static pid_t target_pid = -1; 55static pid_t target_pid = -1;
55static pid_t target_tid = -1; 56static pid_t target_tid = -1;
56static pid_t *all_tids = NULL; 57static struct thread_map *threads;
57static int thread_num = 0;
58static pid_t child_pid = -1; 58static pid_t child_pid = -1;
59static bool no_inherit = false; 59static bool no_inherit = false;
60static enum write_mode_t write_mode = WRITE_FORCE; 60static enum write_mode_t write_mode = WRITE_FORCE;
@@ -81,7 +81,6 @@ static struct perf_session *session;
81static const char *cpu_list; 81static const char *cpu_list;
82 82
83struct mmap_data { 83struct mmap_data {
84 int counter;
85 void *base; 84 void *base;
86 unsigned int mask; 85 unsigned int mask;
87 unsigned int prev; 86 unsigned int prev;
@@ -229,12 +228,12 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
229 return h_attr; 228 return h_attr;
230} 229}
231 230
232static void create_counter(int counter, int cpu) 231static void create_counter(struct perf_evsel *evsel, int cpu)
233{ 232{
234 char *filter = filters[counter]; 233 char *filter = evsel->filter;
235 struct perf_event_attr *attr = attrs + counter; 234 struct perf_event_attr *attr = &evsel->attr;
236 struct perf_header_attr *h_attr; 235 struct perf_header_attr *h_attr;
237 int track = !counter; /* only the first counter needs these */ 236 int track = !evsel->idx; /* only the first counter needs these */
238 int thread_index; 237 int thread_index;
239 int ret; 238 int ret;
240 struct { 239 struct {
@@ -318,12 +317,11 @@ static void create_counter(int counter, int cpu)
318retry_sample_id: 317retry_sample_id:
319 attr->sample_id_all = sample_id_all_avail ? 1 : 0; 318 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
320 319
321 for (thread_index = 0; thread_index < thread_num; thread_index++) { 320 for (thread_index = 0; thread_index < threads->nr; thread_index++) {
322try_again: 321try_again:
323 fd[nr_cpu][counter][thread_index] = sys_perf_event_open(attr, 322 FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0);
324 all_tids[thread_index], cpu, group_fd, 0);
325 323
326 if (fd[nr_cpu][counter][thread_index] < 0) { 324 if (FD(evsel, nr_cpu, thread_index) < 0) {
327 int err = errno; 325 int err = errno;
328 326
329 if (err == EPERM || err == EACCES) 327 if (err == EPERM || err == EACCES)
@@ -360,7 +358,7 @@ try_again:
360 } 358 }
361 printf("\n"); 359 printf("\n");
362 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 360 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)); 361 FD(evsel, nr_cpu, thread_index), strerror(err));
364 362
365#if defined(__i386__) || defined(__x86_64__) 363#if defined(__i386__) || defined(__x86_64__)
366 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) 364 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
@@ -374,7 +372,7 @@ try_again:
374 exit(-1); 372 exit(-1);
375 } 373 }
376 374
377 h_attr = get_header_attr(attr, counter); 375 h_attr = get_header_attr(attr, evsel->idx);
378 if (h_attr == NULL) 376 if (h_attr == NULL)
379 die("nomem\n"); 377 die("nomem\n");
380 378
@@ -385,7 +383,7 @@ try_again:
385 } 383 }
386 } 384 }
387 385
388 if (read(fd[nr_cpu][counter][thread_index], &read_data, sizeof(read_data)) == -1) { 386 if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) {
389 perror("Unable to read perf file descriptor"); 387 perror("Unable to read perf file descriptor");
390 exit(-1); 388 exit(-1);
391 } 389 }
@@ -395,43 +393,44 @@ try_again:
395 exit(-1); 393 exit(-1);
396 } 394 }
397 395
398 assert(fd[nr_cpu][counter][thread_index] >= 0); 396 assert(FD(evsel, nr_cpu, thread_index) >= 0);
399 fcntl(fd[nr_cpu][counter][thread_index], F_SETFL, O_NONBLOCK); 397 fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK);
400 398
401 /* 399 /*
402 * First counter acts as the group leader: 400 * First counter acts as the group leader:
403 */ 401 */
404 if (group && group_fd == -1) 402 if (group && group_fd == -1)
405 group_fd = fd[nr_cpu][counter][thread_index]; 403 group_fd = FD(evsel, nr_cpu, thread_index);
406 404
407 if (counter || thread_index) { 405 if (evsel->idx || thread_index) {
408 ret = ioctl(fd[nr_cpu][counter][thread_index], 406 struct perf_evsel *first;
409 PERF_EVENT_IOC_SET_OUTPUT, 407 first = list_entry(evsel_list.next, struct perf_evsel, node);
410 fd[nr_cpu][0][0]); 408 ret = ioctl(FD(evsel, nr_cpu, thread_index),
409 PERF_EVENT_IOC_SET_OUTPUT,
410 FD(first, nr_cpu, 0));
411 if (ret) { 411 if (ret) {
412 error("failed to set output: %d (%s)\n", errno, 412 error("failed to set output: %d (%s)\n", errno,
413 strerror(errno)); 413 strerror(errno));
414 exit(-1); 414 exit(-1);
415 } 415 }
416 } else { 416 } else {
417 mmap_array[nr_cpu].counter = counter;
418 mmap_array[nr_cpu].prev = 0; 417 mmap_array[nr_cpu].prev = 0;
419 mmap_array[nr_cpu].mask = mmap_pages*page_size - 1; 418 mmap_array[nr_cpu].mask = mmap_pages*page_size - 1;
420 mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size, 419 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); 420 PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0);
422 if (mmap_array[nr_cpu].base == MAP_FAILED) { 421 if (mmap_array[nr_cpu].base == MAP_FAILED) {
423 error("failed to mmap with %d (%s)\n", errno, strerror(errno)); 422 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
424 exit(-1); 423 exit(-1);
425 } 424 }
426 425
427 event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index]; 426 event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index);
428 event_array[nr_poll].events = POLLIN; 427 event_array[nr_poll].events = POLLIN;
429 nr_poll++; 428 nr_poll++;
430 } 429 }
431 430
432 if (filter != NULL) { 431 if (filter != NULL) {
433 ret = ioctl(fd[nr_cpu][counter][thread_index], 432 ret = ioctl(FD(evsel, nr_cpu, thread_index),
434 PERF_EVENT_IOC_SET_FILTER, filter); 433 PERF_EVENT_IOC_SET_FILTER, filter);
435 if (ret) { 434 if (ret) {
436 error("failed to set filter with %d (%s)\n", errno, 435 error("failed to set filter with %d (%s)\n", errno,
437 strerror(errno)); 436 strerror(errno));
@@ -446,11 +445,12 @@ try_again:
446 445
447static void open_counters(int cpu) 446static void open_counters(int cpu)
448{ 447{
449 int counter; 448 struct perf_evsel *pos;
450 449
451 group_fd = -1; 450 group_fd = -1;
452 for (counter = 0; counter < nr_counters; counter++) 451
453 create_counter(counter, cpu); 452 list_for_each_entry(pos, &evsel_list, node)
453 create_counter(pos, cpu);
454 454
455 nr_cpu++; 455 nr_cpu++;
456} 456}
@@ -537,7 +537,7 @@ static void mmap_read_all(void)
537 537
538static int __cmd_record(int argc, const char **argv) 538static int __cmd_record(int argc, const char **argv)
539{ 539{
540 int i, counter; 540 int i;
541 struct stat st; 541 struct stat st;
542 int flags; 542 int flags;
543 int err; 543 int err;
@@ -604,7 +604,7 @@ static int __cmd_record(int argc, const char **argv)
604 goto out_delete_session; 604 goto out_delete_session;
605 } 605 }
606 606
607 if (have_tracepoints(attrs, nr_counters)) 607 if (have_tracepoints(&evsel_list))
608 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 608 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
609 609
610 /* 610 /*
@@ -652,7 +652,7 @@ static int __cmd_record(int argc, const char **argv)
652 } 652 }
653 653
654 if (!system_wide && target_tid == -1 && target_pid == -1) 654 if (!system_wide && target_tid == -1 && target_pid == -1)
655 all_tids[0] = child_pid; 655 threads->map[0] = child_pid;
656 656
657 close(child_ready_pipe[1]); 657 close(child_ready_pipe[1]);
658 close(go_pipe[0]); 658 close(go_pipe[0]);
@@ -666,17 +666,11 @@ static int __cmd_record(int argc, const char **argv)
666 close(child_ready_pipe[0]); 666 close(child_ready_pipe[0]);
667 } 667 }
668 668
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) { 669 if (!system_wide && no_inherit && !cpu_list) {
676 open_counters(-1); 670 open_counters(-1);
677 } else { 671 } else {
678 for (i = 0; i < nr_cpus; i++) 672 for (i = 0; i < cpus->nr; i++)
679 open_counters(cpumap[i]); 673 open_counters(cpus->map[i]);
680 } 674 }
681 675
682 perf_session__set_sample_type(session, sample_type); 676 perf_session__set_sample_type(session, sample_type);
@@ -711,7 +705,7 @@ static int __cmd_record(int argc, const char **argv)
711 return err; 705 return err;
712 } 706 }
713 707
714 if (have_tracepoints(attrs, nr_counters)) { 708 if (have_tracepoints(&evsel_list)) {
715 /* 709 /*
716 * FIXME err <= 0 here actually means that 710 * FIXME err <= 0 here actually means that
717 * there were no tracepoints so its not really 711 * there were no tracepoints so its not really
@@ -720,8 +714,7 @@ static int __cmd_record(int argc, const char **argv)
720 * return this more properly and also 714 * return this more properly and also
721 * propagate errors that now are calling die() 715 * propagate errors that now are calling die()
722 */ 716 */
723 err = event__synthesize_tracing_data(output, attrs, 717 err = event__synthesize_tracing_data(output, &evsel_list,
724 nr_counters,
725 process_synthesized_event, 718 process_synthesized_event,
726 session); 719 session);
727 if (err <= 0) { 720 if (err <= 0) {
@@ -795,13 +788,13 @@ static int __cmd_record(int argc, const char **argv)
795 788
796 if (done) { 789 if (done) {
797 for (i = 0; i < nr_cpu; i++) { 790 for (i = 0; i < nr_cpu; i++) {
798 for (counter = 0; 791 struct perf_evsel *pos;
799 counter < nr_counters; 792
800 counter++) { 793 list_for_each_entry(pos, &evsel_list, node) {
801 for (thread = 0; 794 for (thread = 0;
802 thread < thread_num; 795 thread < threads->nr;
803 thread++) 796 thread++)
804 ioctl(fd[i][counter][thread], 797 ioctl(FD(pos, i, thread),
805 PERF_EVENT_IOC_DISABLE); 798 PERF_EVENT_IOC_DISABLE);
806 } 799 }
807 } 800 }
@@ -887,7 +880,8 @@ const struct option record_options[] = {
887 880
888int cmd_record(int argc, const char **argv, const char *prefix __used) 881int cmd_record(int argc, const char **argv, const char *prefix __used)
889{ 882{
890 int i, j, err = -ENOMEM; 883 int err = -ENOMEM;
884 struct perf_evsel *pos;
891 885
892 argc = parse_options(argc, argv, record_options, record_usage, 886 argc = parse_options(argc, argv, record_options, record_usage,
893 PARSE_OPT_STOP_AT_NON_OPTION); 887 PARSE_OPT_STOP_AT_NON_OPTION);
@@ -910,38 +904,32 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
910 if (no_buildid_cache || no_buildid) 904 if (no_buildid_cache || no_buildid)
911 disable_buildid_cache(); 905 disable_buildid_cache();
912 906
913 if (!nr_counters) { 907 if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) {
914 nr_counters = 1; 908 pr_err("Not enough memory for event selector list\n");
915 attrs[0].type = PERF_TYPE_HARDWARE; 909 goto out_symbol_exit;
916 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
917 } 910 }
918 911
919 if (target_pid != -1) { 912 if (target_pid != -1)
920 target_tid = target_pid; 913 target_tid = target_pid;
921 thread_num = find_all_tid(target_pid, &all_tids);
922 if (thread_num <= 0) {
923 fprintf(stderr, "Can't find all threads of pid %d\n",
924 target_pid);
925 usage_with_options(record_usage, record_options);
926 }
927 } else {
928 all_tids=malloc(sizeof(pid_t));
929 if (!all_tids)
930 goto out_symbol_exit;
931 914
932 all_tids[0] = target_tid; 915 threads = thread_map__new(target_pid, target_tid);
933 thread_num = 1; 916 if (threads == NULL) {
917 pr_err("Problems finding threads of monitor\n");
918 usage_with_options(record_usage, record_options);
934 } 919 }
935 920
936 for (i = 0; i < MAX_NR_CPUS; i++) { 921 cpus = cpu_map__new(cpu_list);
937 for (j = 0; j < MAX_COUNTERS; j++) { 922 if (cpus == NULL) {
938 fd[i][j] = malloc(sizeof(int)*thread_num); 923 perror("failed to parse CPUs map");
939 if (!fd[i][j]) 924 return -1;
940 goto out_free_fd; 925 }
941 } 926
927 list_for_each_entry(pos, &evsel_list, node) {
928 if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
929 goto out_free_fd;
942 } 930 }
943 event_array = malloc( 931 event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS *
944 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); 932 MAX_COUNTERS * threads->nr));
945 if (!event_array) 933 if (!event_array)
946 goto out_free_fd; 934 goto out_free_fd;
947 935
@@ -968,12 +956,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
968out_free_event_array: 956out_free_event_array:
969 free(event_array); 957 free(event_array);
970out_free_fd: 958out_free_fd:
971 for (i = 0; i < MAX_NR_CPUS; i++) { 959 thread_map__delete(threads);
972 for (j = 0; j < MAX_COUNTERS; j++) 960 threads = NULL;
973 free(fd[i][j]);
974 }
975 free(all_tids);
976 all_tids = NULL;
977out_symbol_exit: 961out_symbol_exit:
978 symbol__exit(); 962 symbol__exit();
979 return err; 963 return err;