diff options
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r-- | tools/perf/builtin-record.c | 127 |
1 files changed, 87 insertions, 40 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d7ebbd757543..d18546f37d7c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include "util/parse-events.h" | 14 | #include "util/parse-events.h" |
15 | #include "util/string.h" | 15 | #include "util/string.h" |
16 | 16 | ||
17 | #include "util/header.h" | ||
18 | |||
17 | #include <unistd.h> | 19 | #include <unistd.h> |
18 | #include <sched.h> | 20 | #include <sched.h> |
19 | 21 | ||
@@ -39,6 +41,8 @@ static int force = 0; | |||
39 | static int append_file = 0; | 41 | static int append_file = 0; |
40 | static int call_graph = 0; | 42 | static int call_graph = 0; |
41 | static int verbose = 0; | 43 | static int verbose = 0; |
44 | static int inherit_stat = 0; | ||
45 | static int no_samples = 0; | ||
42 | 46 | ||
43 | static long samples; | 47 | static long samples; |
44 | static struct timeval last_read; | 48 | static struct timeval last_read; |
@@ -52,7 +56,8 @@ static int nr_poll; | |||
52 | static int nr_cpu; | 56 | static int nr_cpu; |
53 | 57 | ||
54 | static int file_new = 1; | 58 | static int file_new = 1; |
55 | static struct perf_file_header file_header; | 59 | |
60 | struct perf_header *header; | ||
56 | 61 | ||
57 | struct mmap_event { | 62 | struct mmap_event { |
58 | struct perf_event_header header; | 63 | struct perf_event_header header; |
@@ -306,12 +311,11 @@ static void pid_synthesize_mmap_samples(pid_t pid) | |||
306 | continue; | 311 | continue; |
307 | pbf += n + 3; | 312 | pbf += n + 3; |
308 | if (*pbf == 'x') { /* vm_exec */ | 313 | if (*pbf == 'x') { /* vm_exec */ |
309 | char *execname = strrchr(bf, ' '); | 314 | char *execname = strchr(bf, '/'); |
310 | 315 | ||
311 | if (execname == NULL || execname[1] != '/') | 316 | if (execname == NULL) |
312 | continue; | 317 | continue; |
313 | 318 | ||
314 | execname += 1; | ||
315 | size = strlen(execname); | 319 | size = strlen(execname); |
316 | execname[size - 1] = '\0'; /* Remove \n */ | 320 | execname[size - 1] = '\0'; /* Remove \n */ |
317 | memcpy(mmap_ev.filename, execname, size); | 321 | memcpy(mmap_ev.filename, execname, size); |
@@ -329,7 +333,7 @@ static void pid_synthesize_mmap_samples(pid_t pid) | |||
329 | fclose(fp); | 333 | fclose(fp); |
330 | } | 334 | } |
331 | 335 | ||
332 | static void synthesize_samples(void) | 336 | static void synthesize_all(void) |
333 | { | 337 | { |
334 | DIR *proc; | 338 | DIR *proc; |
335 | struct dirent dirent, *next; | 339 | struct dirent dirent, *next; |
@@ -353,10 +357,35 @@ static void synthesize_samples(void) | |||
353 | 357 | ||
354 | static int group_fd; | 358 | static int group_fd; |
355 | 359 | ||
360 | static struct perf_header_attr *get_header_attr(struct perf_counter_attr *a, int nr) | ||
361 | { | ||
362 | struct perf_header_attr *h_attr; | ||
363 | |||
364 | if (nr < header->attrs) { | ||
365 | h_attr = header->attr[nr]; | ||
366 | } else { | ||
367 | h_attr = perf_header_attr__new(a); | ||
368 | perf_header__add_attr(header, h_attr); | ||
369 | } | ||
370 | |||
371 | return h_attr; | ||
372 | } | ||
373 | |||
356 | static void create_counter(int counter, int cpu, pid_t pid) | 374 | static void create_counter(int counter, int cpu, pid_t pid) |
357 | { | 375 | { |
358 | struct perf_counter_attr *attr = attrs + counter; | 376 | struct perf_counter_attr *attr = attrs + counter; |
359 | int track = 1; | 377 | struct perf_header_attr *h_attr; |
378 | int track = !counter; /* only the first counter needs these */ | ||
379 | struct { | ||
380 | u64 count; | ||
381 | u64 time_enabled; | ||
382 | u64 time_running; | ||
383 | u64 id; | ||
384 | } read_data; | ||
385 | |||
386 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | ||
387 | PERF_FORMAT_TOTAL_TIME_RUNNING | | ||
388 | PERF_FORMAT_ID; | ||
360 | 389 | ||
361 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 390 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
362 | 391 | ||
@@ -366,25 +395,20 @@ static void create_counter(int counter, int cpu, pid_t pid) | |||
366 | attr->sample_freq = freq; | 395 | attr->sample_freq = freq; |
367 | } | 396 | } |
368 | 397 | ||
398 | if (no_samples) | ||
399 | attr->sample_freq = 0; | ||
400 | |||
401 | if (inherit_stat) | ||
402 | attr->inherit_stat = 1; | ||
403 | |||
369 | if (call_graph) | 404 | if (call_graph) |
370 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | 405 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; |
371 | 406 | ||
372 | if (file_new) { | ||
373 | file_header.sample_type = attr->sample_type; | ||
374 | } else { | ||
375 | if (file_header.sample_type != attr->sample_type) { | ||
376 | fprintf(stderr, "incompatible append\n"); | ||
377 | exit(-1); | ||
378 | } | ||
379 | } | ||
380 | |||
381 | attr->mmap = track; | 407 | attr->mmap = track; |
382 | attr->comm = track; | 408 | attr->comm = track; |
383 | attr->inherit = (cpu < 0) && inherit; | 409 | attr->inherit = (cpu < 0) && inherit; |
384 | attr->disabled = 1; | 410 | attr->disabled = 1; |
385 | 411 | ||
386 | track = 0; /* only the first counter needs these */ | ||
387 | |||
388 | try_again: | 412 | try_again: |
389 | fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0); | 413 | fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0); |
390 | 414 | ||
@@ -415,6 +439,22 @@ try_again: | |||
415 | exit(-1); | 439 | exit(-1); |
416 | } | 440 | } |
417 | 441 | ||
442 | h_attr = get_header_attr(attr, counter); | ||
443 | |||
444 | if (!file_new) { | ||
445 | if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { | ||
446 | fprintf(stderr, "incompatible append\n"); | ||
447 | exit(-1); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | if (read(fd[nr_cpu][counter], &read_data, sizeof(read_data)) == -1) { | ||
452 | perror("Unable to read perf file descriptor\n"); | ||
453 | exit(-1); | ||
454 | } | ||
455 | |||
456 | perf_header_attr__add_id(h_attr, read_data.id); | ||
457 | |||
418 | assert(fd[nr_cpu][counter] >= 0); | 458 | assert(fd[nr_cpu][counter] >= 0); |
419 | fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); | 459 | fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); |
420 | 460 | ||
@@ -445,11 +485,6 @@ static void open_counters(int cpu, pid_t pid) | |||
445 | { | 485 | { |
446 | int counter; | 486 | int counter; |
447 | 487 | ||
448 | if (pid > 0) { | ||
449 | pid_synthesize_comm_event(pid, 0); | ||
450 | pid_synthesize_mmap_samples(pid); | ||
451 | } | ||
452 | |||
453 | group_fd = -1; | 488 | group_fd = -1; |
454 | for (counter = 0; counter < nr_counters; counter++) | 489 | for (counter = 0; counter < nr_counters; counter++) |
455 | create_counter(counter, cpu, pid); | 490 | create_counter(counter, cpu, pid); |
@@ -459,17 +494,16 @@ static void open_counters(int cpu, pid_t pid) | |||
459 | 494 | ||
460 | static void atexit_header(void) | 495 | static void atexit_header(void) |
461 | { | 496 | { |
462 | file_header.data_size += bytes_written; | 497 | header->data_size += bytes_written; |
463 | 498 | ||
464 | if (pwrite(output, &file_header, sizeof(file_header), 0) == -1) | 499 | perf_header__write(header, output); |
465 | perror("failed to write on file headers"); | ||
466 | } | 500 | } |
467 | 501 | ||
468 | static int __cmd_record(int argc, const char **argv) | 502 | static int __cmd_record(int argc, const char **argv) |
469 | { | 503 | { |
470 | int i, counter; | 504 | int i, counter; |
471 | struct stat st; | 505 | struct stat st; |
472 | pid_t pid; | 506 | pid_t pid = 0; |
473 | int flags; | 507 | int flags; |
474 | int ret; | 508 | int ret; |
475 | 509 | ||
@@ -500,22 +534,31 @@ static int __cmd_record(int argc, const char **argv) | |||
500 | exit(-1); | 534 | exit(-1); |
501 | } | 535 | } |
502 | 536 | ||
503 | if (!file_new) { | 537 | if (!file_new) |
504 | if (read(output, &file_header, sizeof(file_header)) == -1) { | 538 | header = perf_header__read(output); |
505 | perror("failed to read file headers"); | 539 | else |
506 | exit(-1); | 540 | header = perf_header__new(); |
507 | } | ||
508 | |||
509 | lseek(output, file_header.data_size, SEEK_CUR); | ||
510 | } | ||
511 | 541 | ||
512 | atexit(atexit_header); | 542 | atexit(atexit_header); |
513 | 543 | ||
514 | if (!system_wide) { | 544 | if (!system_wide) { |
515 | open_counters(-1, target_pid != -1 ? target_pid : getpid()); | 545 | pid = target_pid; |
546 | if (pid == -1) | ||
547 | pid = getpid(); | ||
548 | |||
549 | open_counters(-1, pid); | ||
516 | } else for (i = 0; i < nr_cpus; i++) | 550 | } else for (i = 0; i < nr_cpus; i++) |
517 | open_counters(i, target_pid); | 551 | open_counters(i, target_pid); |
518 | 552 | ||
553 | if (file_new) | ||
554 | perf_header__write(header, output); | ||
555 | |||
556 | if (!system_wide) { | ||
557 | pid_synthesize_comm_event(pid, 0); | ||
558 | pid_synthesize_mmap_samples(pid); | ||
559 | } else | ||
560 | synthesize_all(); | ||
561 | |||
519 | if (target_pid == -1 && argc) { | 562 | if (target_pid == -1 && argc) { |
520 | pid = fork(); | 563 | pid = fork(); |
521 | if (pid < 0) | 564 | if (pid < 0) |
@@ -539,10 +582,7 @@ static int __cmd_record(int argc, const char **argv) | |||
539 | } | 582 | } |
540 | } | 583 | } |
541 | 584 | ||
542 | if (system_wide) | 585 | for (;;) { |
543 | synthesize_samples(); | ||
544 | |||
545 | while (!done) { | ||
546 | int hits = samples; | 586 | int hits = samples; |
547 | 587 | ||
548 | for (i = 0; i < nr_cpu; i++) { | 588 | for (i = 0; i < nr_cpu; i++) { |
@@ -550,8 +590,11 @@ static int __cmd_record(int argc, const char **argv) | |||
550 | mmap_read(&mmap_array[i][counter]); | 590 | mmap_read(&mmap_array[i][counter]); |
551 | } | 591 | } |
552 | 592 | ||
553 | if (hits == samples) | 593 | if (hits == samples) { |
594 | if (done) | ||
595 | break; | ||
554 | ret = poll(event_array, nr_poll, 100); | 596 | ret = poll(event_array, nr_poll, 100); |
597 | } | ||
555 | } | 598 | } |
556 | 599 | ||
557 | /* | 600 | /* |
@@ -600,6 +643,10 @@ static const struct option options[] = { | |||
600 | "do call-graph (stack chain/backtrace) recording"), | 643 | "do call-graph (stack chain/backtrace) recording"), |
601 | OPT_BOOLEAN('v', "verbose", &verbose, | 644 | OPT_BOOLEAN('v', "verbose", &verbose, |
602 | "be more verbose (show counter open errors, etc)"), | 645 | "be more verbose (show counter open errors, etc)"), |
646 | OPT_BOOLEAN('s', "stat", &inherit_stat, | ||
647 | "per thread counts"), | ||
648 | OPT_BOOLEAN('n', "no-samples", &no_samples, | ||
649 | "don't sample"), | ||
603 | OPT_END() | 650 | OPT_END() |
604 | }; | 651 | }; |
605 | 652 | ||