diff options
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r-- | tools/perf/builtin-record.c | 100 |
1 files changed, 65 insertions, 35 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 9b899ba1b410..f4f0240d2302 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 | ||
@@ -52,7 +54,8 @@ static int nr_poll; | |||
52 | static int nr_cpu; | 54 | static int nr_cpu; |
53 | 55 | ||
54 | static int file_new = 1; | 56 | static int file_new = 1; |
55 | static struct perf_file_header file_header; | 57 | |
58 | struct perf_header *header; | ||
56 | 59 | ||
57 | struct mmap_event { | 60 | struct mmap_event { |
58 | struct perf_event_header header; | 61 | struct perf_event_header header; |
@@ -328,7 +331,7 @@ static void pid_synthesize_mmap_samples(pid_t pid) | |||
328 | fclose(fp); | 331 | fclose(fp); |
329 | } | 332 | } |
330 | 333 | ||
331 | static void synthesize_samples(void) | 334 | static void synthesize_all(void) |
332 | { | 335 | { |
333 | DIR *proc; | 336 | DIR *proc; |
334 | struct dirent dirent, *next; | 337 | struct dirent dirent, *next; |
@@ -352,10 +355,35 @@ static void synthesize_samples(void) | |||
352 | 355 | ||
353 | static int group_fd; | 356 | static int group_fd; |
354 | 357 | ||
358 | static struct perf_header_attr *get_header_attr(struct perf_counter_attr *a, int nr) | ||
359 | { | ||
360 | struct perf_header_attr *h_attr; | ||
361 | |||
362 | if (nr < header->attrs) { | ||
363 | h_attr = header->attr[nr]; | ||
364 | } else { | ||
365 | h_attr = perf_header_attr__new(a); | ||
366 | perf_header__add_attr(header, h_attr); | ||
367 | } | ||
368 | |||
369 | return h_attr; | ||
370 | } | ||
371 | |||
355 | static void create_counter(int counter, int cpu, pid_t pid) | 372 | static void create_counter(int counter, int cpu, pid_t pid) |
356 | { | 373 | { |
357 | struct perf_counter_attr *attr = attrs + counter; | 374 | struct perf_counter_attr *attr = attrs + counter; |
358 | int track = 1; | 375 | struct perf_header_attr *h_attr; |
376 | int track = !counter; /* only the first counter needs these */ | ||
377 | struct { | ||
378 | u64 count; | ||
379 | u64 time_enabled; | ||
380 | u64 time_running; | ||
381 | u64 id; | ||
382 | } read_data; | ||
383 | |||
384 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | ||
385 | PERF_FORMAT_TOTAL_TIME_RUNNING | | ||
386 | PERF_FORMAT_ID; | ||
359 | 387 | ||
360 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 388 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
361 | 389 | ||
@@ -368,22 +396,11 @@ static void create_counter(int counter, int cpu, pid_t pid) | |||
368 | if (call_graph) | 396 | if (call_graph) |
369 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | 397 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; |
370 | 398 | ||
371 | if (file_new) { | ||
372 | file_header.sample_type = attr->sample_type; | ||
373 | } else { | ||
374 | if (file_header.sample_type != attr->sample_type) { | ||
375 | fprintf(stderr, "incompatible append\n"); | ||
376 | exit(-1); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | attr->mmap = track; | 399 | attr->mmap = track; |
381 | attr->comm = track; | 400 | attr->comm = track; |
382 | attr->inherit = (cpu < 0) && inherit; | 401 | attr->inherit = (cpu < 0) && inherit; |
383 | attr->disabled = 1; | 402 | attr->disabled = 1; |
384 | 403 | ||
385 | track = 0; /* only the first counter needs these */ | ||
386 | |||
387 | try_again: | 404 | try_again: |
388 | fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0); | 405 | fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0); |
389 | 406 | ||
@@ -414,6 +431,19 @@ try_again: | |||
414 | exit(-1); | 431 | exit(-1); |
415 | } | 432 | } |
416 | 433 | ||
434 | h_attr = get_header_attr(attr, counter); | ||
435 | |||
436 | if (!file_new) { | ||
437 | if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { | ||
438 | fprintf(stderr, "incompatible append\n"); | ||
439 | exit(-1); | ||
440 | } | ||
441 | } | ||
442 | |||
443 | read(fd[nr_cpu][counter], &read_data, sizeof(read_data)); | ||
444 | |||
445 | perf_header_attr__add_id(h_attr, read_data.id); | ||
446 | |||
417 | assert(fd[nr_cpu][counter] >= 0); | 447 | assert(fd[nr_cpu][counter] >= 0); |
418 | fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); | 448 | fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); |
419 | 449 | ||
@@ -444,11 +474,6 @@ static void open_counters(int cpu, pid_t pid) | |||
444 | { | 474 | { |
445 | int counter; | 475 | int counter; |
446 | 476 | ||
447 | if (pid > 0) { | ||
448 | pid_synthesize_comm_event(pid, 0); | ||
449 | pid_synthesize_mmap_samples(pid); | ||
450 | } | ||
451 | |||
452 | group_fd = -1; | 477 | group_fd = -1; |
453 | for (counter = 0; counter < nr_counters; counter++) | 478 | for (counter = 0; counter < nr_counters; counter++) |
454 | create_counter(counter, cpu, pid); | 479 | create_counter(counter, cpu, pid); |
@@ -458,17 +483,16 @@ static void open_counters(int cpu, pid_t pid) | |||
458 | 483 | ||
459 | static void atexit_header(void) | 484 | static void atexit_header(void) |
460 | { | 485 | { |
461 | file_header.data_size += bytes_written; | 486 | header->data_size += bytes_written; |
462 | 487 | ||
463 | if (pwrite(output, &file_header, sizeof(file_header), 0) == -1) | 488 | perf_header__write(header, output); |
464 | perror("failed to write on file headers"); | ||
465 | } | 489 | } |
466 | 490 | ||
467 | static int __cmd_record(int argc, const char **argv) | 491 | static int __cmd_record(int argc, const char **argv) |
468 | { | 492 | { |
469 | int i, counter; | 493 | int i, counter; |
470 | struct stat st; | 494 | struct stat st; |
471 | pid_t pid; | 495 | pid_t pid = 0; |
472 | int flags; | 496 | int flags; |
473 | int ret; | 497 | int ret; |
474 | 498 | ||
@@ -499,22 +523,31 @@ static int __cmd_record(int argc, const char **argv) | |||
499 | exit(-1); | 523 | exit(-1); |
500 | } | 524 | } |
501 | 525 | ||
502 | if (!file_new) { | 526 | if (!file_new) |
503 | if (read(output, &file_header, sizeof(file_header)) == -1) { | 527 | header = perf_header__read(output); |
504 | perror("failed to read file headers"); | 528 | else |
505 | exit(-1); | 529 | header = perf_header__new(); |
506 | } | ||
507 | |||
508 | lseek(output, file_header.data_size, SEEK_CUR); | ||
509 | } | ||
510 | 530 | ||
511 | atexit(atexit_header); | 531 | atexit(atexit_header); |
512 | 532 | ||
513 | if (!system_wide) { | 533 | if (!system_wide) { |
514 | open_counters(-1, target_pid != -1 ? target_pid : getpid()); | 534 | pid = target_pid; |
535 | if (pid == -1) | ||
536 | pid = getpid(); | ||
537 | |||
538 | open_counters(-1, pid); | ||
515 | } else for (i = 0; i < nr_cpus; i++) | 539 | } else for (i = 0; i < nr_cpus; i++) |
516 | open_counters(i, target_pid); | 540 | open_counters(i, target_pid); |
517 | 541 | ||
542 | if (file_new) | ||
543 | perf_header__write(header, output); | ||
544 | |||
545 | if (!system_wide) { | ||
546 | pid_synthesize_comm_event(pid, 0); | ||
547 | pid_synthesize_mmap_samples(pid); | ||
548 | } else | ||
549 | synthesize_all(); | ||
550 | |||
518 | if (target_pid == -1 && argc) { | 551 | if (target_pid == -1 && argc) { |
519 | pid = fork(); | 552 | pid = fork(); |
520 | if (pid < 0) | 553 | if (pid < 0) |
@@ -538,9 +571,6 @@ static int __cmd_record(int argc, const char **argv) | |||
538 | } | 571 | } |
539 | } | 572 | } |
540 | 573 | ||
541 | if (system_wide) | ||
542 | synthesize_samples(); | ||
543 | |||
544 | while (!done) { | 574 | while (!done) { |
545 | int hits = samples; | 575 | int hits = samples; |
546 | 576 | ||