aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-record.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2011-01-12 11:28:51 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-01-22 16:56:29 -0500
commitdd7927f4f8ee75b032ff15aeef4bda49719a443a (patch)
treee839ab6250df6ae192567531d3464c1977ff3e04 /tools/perf/builtin-record.c
parent72cb7013e08dec29631e0447f9496b7bacd3e14b (diff)
perf record: Use perf_evsel__open
Now its time to factor out the mmap handling bits into the perf_evsel class. Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r--tools/perf/builtin-record.c233
1 files changed, 113 insertions, 120 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 1614d89b476..ec43f2eb7b7 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -72,8 +72,6 @@ static struct perf_evlist *evsel_list;
72static long samples = 0; 72static long samples = 0;
73static u64 bytes_written = 0; 73static u64 bytes_written = 0;
74 74
75static int nr_cpu = 0;
76
77static int file_new = 1; 75static int file_new = 1;
78static off_t post_processing_offset; 76static off_t post_processing_offset;
79 77
@@ -208,8 +206,6 @@ static void sig_atexit(void)
208 kill(getpid(), signr); 206 kill(getpid(), signr);
209} 207}
210 208
211static int group_fd;
212
213static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) 209static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
214{ 210{
215 struct perf_header_attr *h_attr; 211 struct perf_header_attr *h_attr;
@@ -234,7 +230,6 @@ static void create_counter(struct perf_evlist *evlist,
234 char *filter = evsel->filter; 230 char *filter = evsel->filter;
235 struct perf_event_attr *attr = &evsel->attr; 231 struct perf_event_attr *attr = &evsel->attr;
236 struct perf_header_attr *h_attr; 232 struct perf_header_attr *h_attr;
237 int track = !evsel->idx; /* only the first counter needs these */
238 int thread_index; 233 int thread_index;
239 int ret; 234 int ret;
240 struct { 235 struct {
@@ -243,19 +238,77 @@ static void create_counter(struct perf_evlist *evlist,
243 u64 time_running; 238 u64 time_running;
244 u64 id; 239 u64 id;
245 } read_data; 240 } read_data;
246 /* 241
247 * Check if parse_single_tracepoint_event has already asked for 242 for (thread_index = 0; thread_index < threads->nr; thread_index++) {
248 * PERF_SAMPLE_TIME. 243 h_attr = get_header_attr(attr, evsel->idx);
249 * 244 if (h_attr == NULL)
250 * XXX this is kludgy but short term fix for problems introduced by 245 die("nomem\n");
251 * eac23d1c that broke 'perf script' by having different sample_types 246
252 * when using multiple tracepoint events when we use a perf binary 247 if (!file_new) {
253 * that tries to use sample_id_all on an older kernel. 248 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
254 * 249 fprintf(stderr, "incompatible append\n");
255 * We need to move counter creation to perf_session, support 250 exit(-1);
256 * different sample_types, etc. 251 }
257 */ 252 }
258 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; 253
254 if (read(FD(evsel, cpu, thread_index), &read_data, sizeof(read_data)) == -1) {
255 perror("Unable to read perf file descriptor");
256 exit(-1);
257 }
258
259 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
260 pr_warning("Not enough memory to add id\n");
261 exit(-1);
262 }
263
264 assert(FD(evsel, cpu, thread_index) >= 0);
265 fcntl(FD(evsel, cpu, thread_index), F_SETFL, O_NONBLOCK);
266
267 if (evsel->idx || thread_index) {
268 struct perf_evsel *first;
269 first = list_entry(evlist->entries.next, struct perf_evsel, node);
270 ret = ioctl(FD(evsel, cpu, thread_index),
271 PERF_EVENT_IOC_SET_OUTPUT,
272 FD(first, cpu, 0));
273 if (ret) {
274 error("failed to set output: %d (%s)\n", errno,
275 strerror(errno));
276 exit(-1);
277 }
278 } else {
279 mmap_array[cpu].prev = 0;
280 mmap_array[cpu].mask = mmap_pages*page_size - 1;
281 mmap_array[cpu].base = mmap(NULL, (mmap_pages+1)*page_size,
282 PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, cpu, thread_index), 0);
283 if (mmap_array[cpu].base == MAP_FAILED) {
284 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
285 exit(-1);
286 }
287
288 evlist->pollfd[evlist->nr_fds].fd = FD(evsel, cpu, thread_index);
289 evlist->pollfd[evlist->nr_fds].events = POLLIN;
290 evlist->nr_fds++;
291 }
292
293 if (filter != NULL) {
294 ret = ioctl(FD(evsel, cpu, thread_index),
295 PERF_EVENT_IOC_SET_FILTER, filter);
296 if (ret) {
297 error("failed to set filter with %d (%s)\n", errno,
298 strerror(errno));
299 exit(-1);
300 }
301 }
302 }
303
304 if (!sample_type)
305 sample_type = attr->sample_type;
306}
307
308static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
309{
310 struct perf_event_attr *attr = &evsel->attr;
311 int track = !evsel->idx; /* only the first counter needs these */
259 312
260 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 313 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
261 PERF_FORMAT_TOTAL_TIME_RUNNING | 314 PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -315,19 +368,39 @@ static void create_counter(struct perf_evlist *evlist,
315 368
316 attr->mmap = track; 369 attr->mmap = track;
317 attr->comm = track; 370 attr->comm = track;
318 attr->inherit = !no_inherit; 371
319 if (target_pid == -1 && target_tid == -1 && !system_wide) { 372 if (target_pid == -1 && target_tid == -1 && !system_wide) {
320 attr->disabled = 1; 373 attr->disabled = 1;
321 attr->enable_on_exec = 1; 374 attr->enable_on_exec = 1;
322 } 375 }
323retry_sample_id: 376}
324 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
325 377
326 for (thread_index = 0; thread_index < threads->nr; thread_index++) { 378static void open_counters(struct perf_evlist *evlist)
327try_again: 379{
328 FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0); 380 struct perf_evsel *pos;
381 int cpu;
382
383 list_for_each_entry(pos, &evlist->entries, node) {
384 struct perf_event_attr *attr = &pos->attr;
385 /*
386 * Check if parse_single_tracepoint_event has already asked for
387 * PERF_SAMPLE_TIME.
388 *
389 * XXX this is kludgy but short term fix for problems introduced by
390 * eac23d1c that broke 'perf script' by having different sample_types
391 * when using multiple tracepoint events when we use a perf binary
392 * that tries to use sample_id_all on an older kernel.
393 *
394 * We need to move counter creation to perf_session, support
395 * different sample_types, etc.
396 */
397 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
329 398
330 if (FD(evsel, nr_cpu, thread_index) < 0) { 399 config_attr(pos, evlist);
400retry_sample_id:
401 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
402try_again:
403 if (perf_evsel__open(pos, cpus, threads, group, !no_inherit) < 0) {
331 int err = errno; 404 int err = errno;
332 405
333 if (err == EPERM || err == EACCES) 406 if (err == EPERM || err == EACCES)
@@ -364,7 +437,7 @@ try_again:
364 } 437 }
365 printf("\n"); 438 printf("\n");
366 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", 439 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
367 FD(evsel, nr_cpu, thread_index), strerror(err)); 440 err, strerror(err));
368 441
369#if defined(__i386__) || defined(__x86_64__) 442#if defined(__i386__) || defined(__x86_64__)
370 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) 443 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
@@ -375,90 +448,13 @@ try_again:
375#endif 448#endif
376 449
377 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 450 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
378 exit(-1);
379 }
380
381 h_attr = get_header_attr(attr, evsel->idx);
382 if (h_attr == NULL)
383 die("nomem\n");
384
385 if (!file_new) {
386 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
387 fprintf(stderr, "incompatible append\n");
388 exit(-1);
389 }
390 }
391
392 if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) {
393 perror("Unable to read perf file descriptor");
394 exit(-1);
395 }
396
397 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
398 pr_warning("Not enough memory to add id\n");
399 exit(-1);
400 }
401
402 assert(FD(evsel, nr_cpu, thread_index) >= 0);
403 fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK);
404
405 /*
406 * First counter acts as the group leader:
407 */
408 if (group && group_fd == -1)
409 group_fd = FD(evsel, nr_cpu, thread_index);
410
411 if (evsel->idx || thread_index) {
412 struct perf_evsel *first;
413 first = list_entry(evlist->entries.next, struct perf_evsel, node);
414 ret = ioctl(FD(evsel, nr_cpu, thread_index),
415 PERF_EVENT_IOC_SET_OUTPUT,
416 FD(first, nr_cpu, 0));
417 if (ret) {
418 error("failed to set output: %d (%s)\n", errno,
419 strerror(errno));
420 exit(-1);
421 }
422 } else {
423 mmap_array[nr_cpu].prev = 0;
424 mmap_array[nr_cpu].mask = mmap_pages*page_size - 1;
425 mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size,
426 PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0);
427 if (mmap_array[nr_cpu].base == MAP_FAILED) {
428 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
429 exit(-1);
430 }
431
432 evlist->pollfd[evlist->nr_fds].fd = FD(evsel, nr_cpu, thread_index);
433 evlist->pollfd[evlist->nr_fds].events = POLLIN;
434 evlist->nr_fds++;
435 }
436
437 if (filter != NULL) {
438 ret = ioctl(FD(evsel, nr_cpu, thread_index),
439 PERF_EVENT_IOC_SET_FILTER, filter);
440 if (ret) {
441 error("failed to set filter with %d (%s)\n", errno,
442 strerror(errno));
443 exit(-1);
444 }
445 } 451 }
446 } 452 }
447 453
448 if (!sample_type) 454 for (cpu = 0; cpu < cpus->nr; ++cpu) {
449 sample_type = attr->sample_type; 455 list_for_each_entry(pos, &evlist->entries, node)
450} 456 create_counter(evlist, pos, cpu);
451 457 }
452static void open_counters(struct perf_evlist *evlist, int cpu)
453{
454 struct perf_evsel *pos;
455
456 group_fd = -1;
457
458 list_for_each_entry(pos, &evlist->entries, node)
459 create_counter(evlist, pos, cpu);
460
461 nr_cpu++;
462} 458}
463 459
464static int process_buildids(void) 460static int process_buildids(void)
@@ -533,7 +529,7 @@ static void mmap_read_all(void)
533{ 529{
534 int i; 530 int i;
535 531
536 for (i = 0; i < nr_cpu; i++) { 532 for (i = 0; i < cpus->nr; i++) {
537 if (mmap_array[i].base) 533 if (mmap_array[i].base)
538 mmap_read(&mmap_array[i]); 534 mmap_read(&mmap_array[i]);
539 } 535 }
@@ -673,12 +669,7 @@ static int __cmd_record(int argc, const char **argv)
673 close(child_ready_pipe[0]); 669 close(child_ready_pipe[0]);
674 } 670 }
675 671
676 if (!system_wide && no_inherit && !cpu_list) { 672 open_counters(evsel_list);
677 open_counters(evsel_list, -1);
678 } else {
679 for (i = 0; i < cpus->nr; i++)
680 open_counters(evsel_list, cpus->map[i]);
681 }
682 673
683 perf_session__set_sample_type(session, sample_type); 674 perf_session__set_sample_type(session, sample_type);
684 675
@@ -795,7 +786,7 @@ static int __cmd_record(int argc, const char **argv)
795 } 786 }
796 787
797 if (done) { 788 if (done) {
798 for (i = 0; i < nr_cpu; i++) { 789 for (i = 0; i < cpus->nr; i++) {
799 struct perf_evsel *pos; 790 struct perf_evsel *pos;
800 791
801 list_for_each_entry(pos, &evsel_list->entries, node) { 792 list_for_each_entry(pos, &evsel_list->entries, node) {
@@ -933,11 +924,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
933 usage_with_options(record_usage, record_options); 924 usage_with_options(record_usage, record_options);
934 } 925 }
935 926
936 cpus = cpu_map__new(cpu_list); 927 if (target_tid != -1)
937 if (cpus == NULL) { 928 cpus = cpu_map__dummy_new();
938 perror("failed to parse CPUs map"); 929 else
939 return -1; 930 cpus = cpu_map__new(cpu_list);
940 } 931
932 if (cpus == NULL)
933 usage_with_options(record_usage, record_options);
941 934
942 list_for_each_entry(pos, &evsel_list->entries, node) { 935 list_for_each_entry(pos, &evsel_list->entries, node) {
943 if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) 936 if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)