diff options
39 files changed, 1270 insertions, 178 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 095101d685bc..07b7a435bf03 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -4313,36 +4313,6 @@ static const struct pmu perf_ops_task_clock = { | |||
4313 | .read = task_clock_perf_event_read, | 4313 | .read = task_clock_perf_event_read, |
4314 | }; | 4314 | }; |
4315 | 4315 | ||
4316 | #ifdef CONFIG_EVENT_TRACING | ||
4317 | |||
4318 | void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | ||
4319 | int entry_size, struct pt_regs *regs) | ||
4320 | { | ||
4321 | struct perf_sample_data data; | ||
4322 | struct perf_raw_record raw = { | ||
4323 | .size = entry_size, | ||
4324 | .data = record, | ||
4325 | }; | ||
4326 | |||
4327 | perf_sample_data_init(&data, addr); | ||
4328 | data.raw = &raw; | ||
4329 | |||
4330 | /* Trace events already protected against recursion */ | ||
4331 | do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, | ||
4332 | &data, regs); | ||
4333 | } | ||
4334 | EXPORT_SYMBOL_GPL(perf_tp_event); | ||
4335 | |||
4336 | static int perf_tp_event_match(struct perf_event *event, | ||
4337 | struct perf_sample_data *data) | ||
4338 | { | ||
4339 | void *record = data->raw->data; | ||
4340 | |||
4341 | if (likely(!event->filter) || filter_match_preds(event->filter, record)) | ||
4342 | return 1; | ||
4343 | return 0; | ||
4344 | } | ||
4345 | |||
4346 | static void swevent_hlist_release_rcu(struct rcu_head *rcu_head) | 4316 | static void swevent_hlist_release_rcu(struct rcu_head *rcu_head) |
4347 | { | 4317 | { |
4348 | struct swevent_hlist *hlist; | 4318 | struct swevent_hlist *hlist; |
@@ -4442,6 +4412,36 @@ static int swevent_hlist_get(struct perf_event *event) | |||
4442 | return err; | 4412 | return err; |
4443 | } | 4413 | } |
4444 | 4414 | ||
4415 | #ifdef CONFIG_EVENT_TRACING | ||
4416 | |||
4417 | void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | ||
4418 | int entry_size, struct pt_regs *regs) | ||
4419 | { | ||
4420 | struct perf_sample_data data; | ||
4421 | struct perf_raw_record raw = { | ||
4422 | .size = entry_size, | ||
4423 | .data = record, | ||
4424 | }; | ||
4425 | |||
4426 | perf_sample_data_init(&data, addr); | ||
4427 | data.raw = &raw; | ||
4428 | |||
4429 | /* Trace events already protected against recursion */ | ||
4430 | do_perf_sw_event(PERF_TYPE_TRACEPOINT, event_id, count, 1, | ||
4431 | &data, regs); | ||
4432 | } | ||
4433 | EXPORT_SYMBOL_GPL(perf_tp_event); | ||
4434 | |||
4435 | static int perf_tp_event_match(struct perf_event *event, | ||
4436 | struct perf_sample_data *data) | ||
4437 | { | ||
4438 | void *record = data->raw->data; | ||
4439 | |||
4440 | if (likely(!event->filter) || filter_match_preds(event->filter, record)) | ||
4441 | return 1; | ||
4442 | return 0; | ||
4443 | } | ||
4444 | |||
4445 | static void tp_perf_event_destroy(struct perf_event *event) | 4445 | static void tp_perf_event_destroy(struct perf_event *event) |
4446 | { | 4446 | { |
4447 | perf_trace_disable(event->attr.config); | 4447 | perf_trace_disable(event->attr.config); |
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index fc46c0b40f6e..020d871c7934 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -58,7 +58,7 @@ OPTIONS | |||
58 | 58 | ||
59 | -f:: | 59 | -f:: |
60 | --force:: | 60 | --force:: |
61 | Overwrite existing data file. | 61 | Overwrite existing data file. (deprecated) |
62 | 62 | ||
63 | -c:: | 63 | -c:: |
64 | --count=:: | 64 | --count=:: |
@@ -101,7 +101,7 @@ OPTIONS | |||
101 | 101 | ||
102 | -R:: | 102 | -R:: |
103 | --raw-samples:: | 103 | --raw-samples:: |
104 | Collect raw sample records from all opened counters (typically for tracepoint counters). | 104 | Collect raw sample records from all opened counters (default for tracepoint counters). |
105 | 105 | ||
106 | SEE ALSO | 106 | SEE ALSO |
107 | -------- | 107 | -------- |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 9a9513687235..a1b99eeac3c0 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -26,15 +26,23 @@ | |||
26 | #include <unistd.h> | 26 | #include <unistd.h> |
27 | #include <sched.h> | 27 | #include <sched.h> |
28 | 28 | ||
29 | enum write_mode_t { | ||
30 | WRITE_FORCE, | ||
31 | WRITE_APPEND | ||
32 | }; | ||
33 | |||
29 | static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; | 34 | static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; |
30 | 35 | ||
36 | static unsigned int user_interval = UINT_MAX; | ||
31 | static long default_interval = 0; | 37 | static long default_interval = 0; |
32 | 38 | ||
33 | static int nr_cpus = 0; | 39 | static int nr_cpus = 0; |
34 | static unsigned int page_size; | 40 | static unsigned int page_size; |
35 | static unsigned int mmap_pages = 128; | 41 | static unsigned int mmap_pages = 128; |
42 | static unsigned int user_freq = UINT_MAX; | ||
36 | static int freq = 1000; | 43 | static int freq = 1000; |
37 | static int output; | 44 | static int output; |
45 | static int pipe_output = 0; | ||
38 | static const char *output_name = "perf.data"; | 46 | static const char *output_name = "perf.data"; |
39 | static int group = 0; | 47 | static int group = 0; |
40 | static unsigned int realtime_prio = 0; | 48 | static unsigned int realtime_prio = 0; |
@@ -47,8 +55,7 @@ static pid_t *all_tids = NULL; | |||
47 | static int thread_num = 0; | 55 | static int thread_num = 0; |
48 | static pid_t child_pid = -1; | 56 | static pid_t child_pid = -1; |
49 | static bool inherit = true; | 57 | static bool inherit = true; |
50 | static bool force = false; | 58 | static enum write_mode_t write_mode = WRITE_FORCE; |
51 | static bool append_file = false; | ||
52 | static bool call_graph = false; | 59 | static bool call_graph = false; |
53 | static bool inherit_stat = false; | 60 | static bool inherit_stat = false; |
54 | static bool no_samples = false; | 61 | static bool no_samples = false; |
@@ -103,6 +110,11 @@ static void mmap_write_tail(struct mmap_data *md, unsigned long tail) | |||
103 | pc->data_tail = tail; | 110 | pc->data_tail = tail; |
104 | } | 111 | } |
105 | 112 | ||
113 | static void advance_output(size_t size) | ||
114 | { | ||
115 | bytes_written += size; | ||
116 | } | ||
117 | |||
106 | static void write_output(void *buf, size_t size) | 118 | static void write_output(void *buf, size_t size) |
107 | { | 119 | { |
108 | while (size) { | 120 | while (size) { |
@@ -251,10 +263,19 @@ static void create_counter(int counter, int cpu) | |||
251 | if (nr_counters > 1) | 263 | if (nr_counters > 1) |
252 | attr->sample_type |= PERF_SAMPLE_ID; | 264 | attr->sample_type |= PERF_SAMPLE_ID; |
253 | 265 | ||
254 | if (freq) { | 266 | /* |
255 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 267 | * We default some events to a 1 default interval. But keep |
256 | attr->freq = 1; | 268 | * it a weak assumption overridable by the user. |
257 | attr->sample_freq = freq; | 269 | */ |
270 | if (!attr->sample_period || (user_freq != UINT_MAX && | ||
271 | user_interval != UINT_MAX)) { | ||
272 | if (freq) { | ||
273 | attr->sample_type |= PERF_SAMPLE_PERIOD; | ||
274 | attr->freq = 1; | ||
275 | attr->sample_freq = freq; | ||
276 | } else { | ||
277 | attr->sample_period = default_interval; | ||
278 | } | ||
258 | } | 279 | } |
259 | 280 | ||
260 | if (no_samples) | 281 | if (no_samples) |
@@ -420,10 +441,19 @@ static int process_buildids(void) | |||
420 | 441 | ||
421 | static void atexit_header(void) | 442 | static void atexit_header(void) |
422 | { | 443 | { |
423 | session->header.data_size += bytes_written; | 444 | if (!pipe_output) { |
445 | session->header.data_size += bytes_written; | ||
446 | |||
447 | process_buildids(); | ||
448 | perf_header__write(&session->header, output, true); | ||
449 | } else { | ||
450 | int err; | ||
424 | 451 | ||
425 | process_buildids(); | 452 | err = event__synthesize_build_ids(process_synthesized_event, |
426 | perf_header__write(&session->header, output, true); | 453 | session); |
454 | if (err < 0) | ||
455 | pr_err("Couldn't synthesize build ids.\n"); | ||
456 | } | ||
427 | } | 457 | } |
428 | 458 | ||
429 | static int __cmd_record(int argc, const char **argv) | 459 | static int __cmd_record(int argc, const char **argv) |
@@ -449,45 +479,44 @@ static int __cmd_record(int argc, const char **argv) | |||
449 | exit(-1); | 479 | exit(-1); |
450 | } | 480 | } |
451 | 481 | ||
452 | if (!stat(output_name, &st) && st.st_size) { | 482 | if (!strcmp(output_name, "-")) |
453 | if (!force) { | 483 | pipe_output = 1; |
454 | if (!append_file) { | 484 | else if (!stat(output_name, &st) && st.st_size) { |
455 | pr_err("Error, output file %s exists, use -A " | 485 | if (write_mode == WRITE_FORCE) { |
456 | "to append or -f to overwrite.\n", | ||
457 | output_name); | ||
458 | exit(-1); | ||
459 | } | ||
460 | } else { | ||
461 | char oldname[PATH_MAX]; | 486 | char oldname[PATH_MAX]; |
462 | snprintf(oldname, sizeof(oldname), "%s.old", | 487 | snprintf(oldname, sizeof(oldname), "%s.old", |
463 | output_name); | 488 | output_name); |
464 | unlink(oldname); | 489 | unlink(oldname); |
465 | rename(output_name, oldname); | 490 | rename(output_name, oldname); |
466 | } | 491 | } |
467 | } else { | 492 | } else if (write_mode == WRITE_APPEND) { |
468 | append_file = false; | 493 | write_mode = WRITE_FORCE; |
469 | } | 494 | } |
470 | 495 | ||
471 | flags = O_CREAT|O_RDWR; | 496 | flags = O_CREAT|O_RDWR; |
472 | if (append_file) | 497 | if (write_mode == WRITE_APPEND) |
473 | file_new = 0; | 498 | file_new = 0; |
474 | else | 499 | else |
475 | flags |= O_TRUNC; | 500 | flags |= O_TRUNC; |
476 | 501 | ||
477 | output = open(output_name, flags, S_IRUSR|S_IWUSR); | 502 | if (pipe_output) |
503 | output = STDOUT_FILENO; | ||
504 | else | ||
505 | output = open(output_name, flags, S_IRUSR | S_IWUSR); | ||
478 | if (output < 0) { | 506 | if (output < 0) { |
479 | perror("failed to create output file"); | 507 | perror("failed to create output file"); |
480 | exit(-1); | 508 | exit(-1); |
481 | } | 509 | } |
482 | 510 | ||
483 | session = perf_session__new(output_name, O_WRONLY, force); | 511 | session = perf_session__new(output_name, O_WRONLY, |
512 | write_mode == WRITE_FORCE); | ||
484 | if (session == NULL) { | 513 | if (session == NULL) { |
485 | pr_err("Not enough memory for reading perf file header\n"); | 514 | pr_err("Not enough memory for reading perf file header\n"); |
486 | return -1; | 515 | return -1; |
487 | } | 516 | } |
488 | 517 | ||
489 | if (!file_new) { | 518 | if (!file_new) { |
490 | err = perf_header__read(&session->header, output); | 519 | err = perf_header__read(session, output); |
491 | if (err < 0) | 520 | if (err < 0) |
492 | return err; | 521 | return err; |
493 | } | 522 | } |
@@ -513,6 +542,8 @@ static int __cmd_record(int argc, const char **argv) | |||
513 | } | 542 | } |
514 | 543 | ||
515 | if (!child_pid) { | 544 | if (!child_pid) { |
545 | if (pipe_output) | ||
546 | dup2(2, 1); | ||
516 | close(child_ready_pipe[0]); | 547 | close(child_ready_pipe[0]); |
517 | close(go_pipe[1]); | 548 | close(go_pipe[1]); |
518 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); | 549 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); |
@@ -564,7 +595,11 @@ static int __cmd_record(int argc, const char **argv) | |||
564 | open_counters(cpumap[i]); | 595 | open_counters(cpumap[i]); |
565 | } | 596 | } |
566 | 597 | ||
567 | if (file_new) { | 598 | if (pipe_output) { |
599 | err = perf_header__write_pipe(output); | ||
600 | if (err < 0) | ||
601 | return err; | ||
602 | } else if (file_new) { | ||
568 | err = perf_header__write(&session->header, output, false); | 603 | err = perf_header__write(&session->header, output, false); |
569 | if (err < 0) | 604 | if (err < 0) |
570 | return err; | 605 | return err; |
@@ -572,6 +607,34 @@ static int __cmd_record(int argc, const char **argv) | |||
572 | 607 | ||
573 | post_processing_offset = lseek(output, 0, SEEK_CUR); | 608 | post_processing_offset = lseek(output, 0, SEEK_CUR); |
574 | 609 | ||
610 | if (pipe_output) { | ||
611 | err = event__synthesize_attrs(&session->header, | ||
612 | process_synthesized_event, | ||
613 | session); | ||
614 | if (err < 0) { | ||
615 | pr_err("Couldn't synthesize attrs.\n"); | ||
616 | return err; | ||
617 | } | ||
618 | |||
619 | err = event__synthesize_event_types(process_synthesized_event, | ||
620 | session); | ||
621 | if (err < 0) { | ||
622 | pr_err("Couldn't synthesize event_types.\n"); | ||
623 | return err; | ||
624 | } | ||
625 | |||
626 | err = event__synthesize_tracing_data(output, attrs, | ||
627 | nr_counters, | ||
628 | process_synthesized_event, | ||
629 | session); | ||
630 | if (err <= 0) { | ||
631 | pr_err("Couldn't record tracing data.\n"); | ||
632 | return err; | ||
633 | } | ||
634 | |||
635 | advance_output(err); | ||
636 | } | ||
637 | |||
575 | err = event__synthesize_kernel_mmap(process_synthesized_event, | 638 | err = event__synthesize_kernel_mmap(process_synthesized_event, |
576 | session, "_text"); | 639 | session, "_text"); |
577 | if (err < 0) | 640 | if (err < 0) |
@@ -667,6 +730,8 @@ static const char * const record_usage[] = { | |||
667 | NULL | 730 | NULL |
668 | }; | 731 | }; |
669 | 732 | ||
733 | static bool force, append_file; | ||
734 | |||
670 | static const struct option options[] = { | 735 | static const struct option options[] = { |
671 | OPT_CALLBACK('e', "event", NULL, "event", | 736 | OPT_CALLBACK('e', "event", NULL, "event", |
672 | "event selector. use 'perf list' to list available events", | 737 | "event selector. use 'perf list' to list available events", |
@@ -688,14 +753,14 @@ static const struct option options[] = { | |||
688 | OPT_INTEGER('C', "profile_cpu", &profile_cpu, | 753 | OPT_INTEGER('C', "profile_cpu", &profile_cpu, |
689 | "CPU to profile on"), | 754 | "CPU to profile on"), |
690 | OPT_BOOLEAN('f', "force", &force, | 755 | OPT_BOOLEAN('f', "force", &force, |
691 | "overwrite existing data file"), | 756 | "overwrite existing data file (deprecated)"), |
692 | OPT_LONG('c', "count", &default_interval, | 757 | OPT_LONG('c', "count", &user_interval, |
693 | "event period to sample"), | 758 | "event period to sample"), |
694 | OPT_STRING('o', "output", &output_name, "file", | 759 | OPT_STRING('o', "output", &output_name, "file", |
695 | "output file name"), | 760 | "output file name"), |
696 | OPT_BOOLEAN('i', "inherit", &inherit, | 761 | OPT_BOOLEAN('i', "inherit", &inherit, |
697 | "child tasks inherit counters"), | 762 | "child tasks inherit counters"), |
698 | OPT_INTEGER('F', "freq", &freq, | 763 | OPT_INTEGER('F', "freq", &user_freq, |
699 | "profile at this frequency"), | 764 | "profile at this frequency"), |
700 | OPT_INTEGER('m', "mmap-pages", &mmap_pages, | 765 | OPT_INTEGER('m', "mmap-pages", &mmap_pages, |
701 | "number of mmap data pages"), | 766 | "number of mmap data pages"), |
@@ -716,7 +781,6 @@ static const struct option options[] = { | |||
716 | 781 | ||
717 | int cmd_record(int argc, const char **argv, const char *prefix __used) | 782 | int cmd_record(int argc, const char **argv, const char *prefix __used) |
718 | { | 783 | { |
719 | int counter; | ||
720 | int i,j; | 784 | int i,j; |
721 | 785 | ||
722 | argc = parse_options(argc, argv, options, record_usage, | 786 | argc = parse_options(argc, argv, options, record_usage, |
@@ -725,6 +789,16 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
725 | !system_wide && profile_cpu == -1) | 789 | !system_wide && profile_cpu == -1) |
726 | usage_with_options(record_usage, options); | 790 | usage_with_options(record_usage, options); |
727 | 791 | ||
792 | if (force && append_file) { | ||
793 | fprintf(stderr, "Can't overwrite and append at the same time." | ||
794 | " You need to choose between -f and -A"); | ||
795 | usage_with_options(record_usage, options); | ||
796 | } else if (append_file) { | ||
797 | write_mode = WRITE_APPEND; | ||
798 | } else { | ||
799 | write_mode = WRITE_FORCE; | ||
800 | } | ||
801 | |||
728 | symbol__init(); | 802 | symbol__init(); |
729 | 803 | ||
730 | if (!nr_counters) { | 804 | if (!nr_counters) { |
@@ -764,6 +838,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
764 | if (!event_array) | 838 | if (!event_array) |
765 | return -ENOMEM; | 839 | return -ENOMEM; |
766 | 840 | ||
841 | if (user_interval != UINT_MAX) | ||
842 | default_interval = user_interval; | ||
843 | if (user_freq != UINT_MAX) | ||
844 | freq = user_freq; | ||
845 | |||
767 | /* | 846 | /* |
768 | * User specified count overrides default frequency. | 847 | * User specified count overrides default frequency. |
769 | */ | 848 | */ |
@@ -776,12 +855,5 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
776 | exit(EXIT_FAILURE); | 855 | exit(EXIT_FAILURE); |
777 | } | 856 | } |
778 | 857 | ||
779 | for (counter = 0; counter < nr_counters; counter++) { | ||
780 | if (attrs[counter].sample_period) | ||
781 | continue; | ||
782 | |||
783 | attrs[counter].sample_period = default_interval; | ||
784 | } | ||
785 | |||
786 | return __cmd_record(argc, argv); | 858 | return __cmd_record(argc, argv); |
787 | } | 859 | } |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index daee082ab42b..7da5fb365264 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -267,8 +267,19 @@ static struct perf_event_ops event_ops = { | |||
267 | .fork = event__process_task, | 267 | .fork = event__process_task, |
268 | .lost = event__process_lost, | 268 | .lost = event__process_lost, |
269 | .read = process_read_event, | 269 | .read = process_read_event, |
270 | .attr = event__process_attr, | ||
271 | .event_type = event__process_event_type, | ||
272 | .tracing_data = event__process_tracing_data, | ||
273 | .build_id = event__process_build_id, | ||
270 | }; | 274 | }; |
271 | 275 | ||
276 | extern volatile int session_done; | ||
277 | |||
278 | static void sig_handler(int sig __attribute__((__unused__))) | ||
279 | { | ||
280 | session_done = 1; | ||
281 | } | ||
282 | |||
272 | static int __cmd_report(void) | 283 | static int __cmd_report(void) |
273 | { | 284 | { |
274 | int ret = -EINVAL; | 285 | int ret = -EINVAL; |
@@ -276,6 +287,8 @@ static int __cmd_report(void) | |||
276 | struct rb_node *next; | 287 | struct rb_node *next; |
277 | const char *help = "For a higher level overview, try: perf report --sort comm,dso"; | 288 | const char *help = "For a higher level overview, try: perf report --sort comm,dso"; |
278 | 289 | ||
290 | signal(SIGINT, sig_handler); | ||
291 | |||
279 | session = perf_session__new(input_name, O_RDONLY, force); | 292 | session = perf_session__new(input_name, O_RDONLY, force); |
280 | if (session == NULL) | 293 | if (session == NULL) |
281 | return -ENOMEM; | 294 | return -ENOMEM; |
@@ -465,7 +478,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) | |||
465 | { | 478 | { |
466 | argc = parse_options(argc, argv, options, report_usage, 0); | 479 | argc = parse_options(argc, argv, options, report_usage, 0); |
467 | 480 | ||
468 | setup_browser(); | 481 | if (strcmp(input_name, "-") != 0) |
482 | setup_browser(); | ||
469 | 483 | ||
470 | if (symbol__init() < 0) | 484 | if (symbol__init() < 0) |
471 | return -1; | 485 | return -1; |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8fc50d831540..2eefb33c9679 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -104,10 +104,23 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
104 | static struct perf_event_ops event_ops = { | 104 | static struct perf_event_ops event_ops = { |
105 | .sample = process_sample_event, | 105 | .sample = process_sample_event, |
106 | .comm = event__process_comm, | 106 | .comm = event__process_comm, |
107 | .attr = event__process_attr, | ||
108 | .event_type = event__process_event_type, | ||
109 | .tracing_data = event__process_tracing_data, | ||
110 | .build_id = event__process_build_id, | ||
107 | }; | 111 | }; |
108 | 112 | ||
113 | extern volatile int session_done; | ||
114 | |||
115 | static void sig_handler(int sig __unused) | ||
116 | { | ||
117 | session_done = 1; | ||
118 | } | ||
119 | |||
109 | static int __cmd_trace(struct perf_session *session) | 120 | static int __cmd_trace(struct perf_session *session) |
110 | { | 121 | { |
122 | signal(SIGINT, sig_handler); | ||
123 | |||
111 | return perf_session__process_events(session, &event_ops); | 124 | return perf_session__process_events(session, &event_ops); |
112 | } | 125 | } |
113 | 126 | ||
@@ -548,6 +561,65 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
548 | suffix = REPORT_SUFFIX; | 561 | suffix = REPORT_SUFFIX; |
549 | } | 562 | } |
550 | 563 | ||
564 | if (!suffix && argc >= 2 && strncmp(argv[1], "-", strlen("-")) != 0) { | ||
565 | char *record_script_path, *report_script_path; | ||
566 | int live_pipe[2]; | ||
567 | pid_t pid; | ||
568 | |||
569 | record_script_path = get_script_path(argv[1], RECORD_SUFFIX); | ||
570 | if (!record_script_path) { | ||
571 | fprintf(stderr, "record script not found\n"); | ||
572 | return -1; | ||
573 | } | ||
574 | |||
575 | report_script_path = get_script_path(argv[1], REPORT_SUFFIX); | ||
576 | if (!report_script_path) { | ||
577 | fprintf(stderr, "report script not found\n"); | ||
578 | return -1; | ||
579 | } | ||
580 | |||
581 | if (pipe(live_pipe) < 0) { | ||
582 | perror("failed to create pipe"); | ||
583 | exit(-1); | ||
584 | } | ||
585 | |||
586 | pid = fork(); | ||
587 | if (pid < 0) { | ||
588 | perror("failed to fork"); | ||
589 | exit(-1); | ||
590 | } | ||
591 | |||
592 | if (!pid) { | ||
593 | dup2(live_pipe[1], 1); | ||
594 | close(live_pipe[0]); | ||
595 | |||
596 | __argv = malloc(5 * sizeof(const char *)); | ||
597 | __argv[0] = "/bin/sh"; | ||
598 | __argv[1] = record_script_path; | ||
599 | __argv[2] = "-o"; | ||
600 | __argv[3] = "-"; | ||
601 | __argv[4] = NULL; | ||
602 | |||
603 | execvp("/bin/sh", (char **)__argv); | ||
604 | exit(-1); | ||
605 | } | ||
606 | |||
607 | dup2(live_pipe[0], 0); | ||
608 | close(live_pipe[1]); | ||
609 | |||
610 | __argv = malloc((argc + 3) * sizeof(const char *)); | ||
611 | __argv[0] = "/bin/sh"; | ||
612 | __argv[1] = report_script_path; | ||
613 | for (i = 2; i < argc; i++) | ||
614 | __argv[i] = argv[i]; | ||
615 | __argv[i++] = "-i"; | ||
616 | __argv[i++] = "-"; | ||
617 | __argv[i++] = NULL; | ||
618 | |||
619 | execvp("/bin/sh", (char **)__argv); | ||
620 | exit(-1); | ||
621 | } | ||
622 | |||
551 | if (suffix) { | 623 | if (suffix) { |
552 | script_path = get_script_path(argv[2], suffix); | 624 | script_path = get_script_path(argv[2], suffix); |
553 | if (!script_path) { | 625 | if (!script_path) { |
@@ -580,7 +652,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
580 | if (session == NULL) | 652 | if (session == NULL) |
581 | return -ENOMEM; | 653 | return -ENOMEM; |
582 | 654 | ||
583 | if (!perf_session__has_traces(session, "record -R")) | 655 | if (strcmp(input_name, "-") && |
656 | !perf_session__has_traces(session, "record -R")) | ||
584 | return -EINVAL; | 657 | return -EINVAL; |
585 | 658 | ||
586 | if (generate_script_lang) { | 659 | if (generate_script_lang) { |
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm index f869c48dc9b0..d94b40c8ac85 100644 --- a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm +++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm | |||
@@ -15,6 +15,7 @@ our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); | |||
15 | 15 | ||
16 | our @EXPORT = qw( | 16 | our @EXPORT = qw( |
17 | avg nsecs nsecs_secs nsecs_nsecs nsecs_usecs print_nsecs | 17 | avg nsecs nsecs_secs nsecs_nsecs nsecs_usecs print_nsecs |
18 | clear_term | ||
18 | ); | 19 | ); |
19 | 20 | ||
20 | our $VERSION = '0.01'; | 21 | our $VERSION = '0.01'; |
@@ -55,6 +56,11 @@ sub nsecs_str { | |||
55 | return $str; | 56 | return $str; |
56 | } | 57 | } |
57 | 58 | ||
59 | sub clear_term | ||
60 | { | ||
61 | print "\x1b[H\x1b[2J"; | ||
62 | } | ||
63 | |||
58 | 1; | 64 | 1; |
59 | __END__ | 65 | __END__ |
60 | =head1 NAME | 66 | =head1 NAME |
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-record b/tools/perf/scripts/perl/bin/failed-syscalls-record index f8885d389e6f..6ad9b8f5f009 100644 --- a/tools/perf/scripts/perl/bin/failed-syscalls-record +++ b/tools/perf/scripts/perl/bin/failed-syscalls-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_exit | 2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_exit $@ |
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-report b/tools/perf/scripts/perl/bin/failed-syscalls-report index 8bfc660e5056..f6346082a8fc 100644 --- a/tools/perf/scripts/perl/bin/failed-syscalls-report +++ b/tools/perf/scripts/perl/bin/failed-syscalls-report | |||
@@ -1,4 +1,10 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # description: system-wide failed syscalls | 2 | # description: system-wide failed syscalls |
3 | # args: [comm] | 3 | # args: [comm] |
4 | perf trace -s ~/libexec/perf-core/scripts/perl/failed-syscalls.pl $1 | 4 | if [ $# -gt 0 ] ; then |
5 | if ! expr match "$1" "-" ; then | ||
6 | comm=$1 | ||
7 | shift | ||
8 | fi | ||
9 | fi | ||
10 | perf trace $@ -s ~/libexec/perf-core/scripts/perl/failed-syscalls.pl $comm | ||
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-record b/tools/perf/scripts/perl/bin/rw-by-file-record index b25056ebf963..a828679837a8 100644 --- a/tools/perf/scripts/perl/bin/rw-by-file-record +++ b/tools/perf/scripts/perl/bin/rw-by-file-record | |||
@@ -1,2 +1,3 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_enter_write | 2 | perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@ |
3 | |||
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-report b/tools/perf/scripts/perl/bin/rw-by-file-report index eddb9ccce6a5..d83070b7eeb5 100644 --- a/tools/perf/scripts/perl/bin/rw-by-file-report +++ b/tools/perf/scripts/perl/bin/rw-by-file-report | |||
@@ -1,7 +1,13 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # description: r/w activity for a program, by file | 2 | # description: r/w activity for a program, by file |
3 | # args: <comm> | 3 | # args: <comm> |
4 | perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl $1 | 4 | if [ $# -lt 1 ] ; then |
5 | echo "usage: rw-by-file <comm>" | ||
6 | exit | ||
7 | fi | ||
8 | comm=$1 | ||
9 | shift | ||
10 | perf trace $@ -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl $comm | ||
5 | 11 | ||
6 | 12 | ||
7 | 13 | ||
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-record b/tools/perf/scripts/perl/bin/rw-by-pid-record index 8903979c5b6c..63976bf11e8b 100644 --- a/tools/perf/scripts/perl/bin/rw-by-pid-record +++ b/tools/perf/scripts/perl/bin/rw-by-pid-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write | 2 | perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ |
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-report b/tools/perf/scripts/perl/bin/rw-by-pid-report index 7f44c25cc857..7ef46983f62f 100644 --- a/tools/perf/scripts/perl/bin/rw-by-pid-report +++ b/tools/perf/scripts/perl/bin/rw-by-pid-report | |||
@@ -1,6 +1,6 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # description: system-wide r/w activity | 2 | # description: system-wide r/w activity |
3 | perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl | 3 | perf trace $@ -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl |
4 | 4 | ||
5 | 5 | ||
6 | 6 | ||
diff --git a/tools/perf/scripts/perl/bin/rwtop-record b/tools/perf/scripts/perl/bin/rwtop-record new file mode 100644 index 000000000000..63976bf11e8b --- /dev/null +++ b/tools/perf/scripts/perl/bin/rwtop-record | |||
@@ -0,0 +1,2 @@ | |||
1 | #!/bin/bash | ||
2 | perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@ | ||
diff --git a/tools/perf/scripts/perl/bin/rwtop-report b/tools/perf/scripts/perl/bin/rwtop-report new file mode 100644 index 000000000000..93e698cd3f38 --- /dev/null +++ b/tools/perf/scripts/perl/bin/rwtop-report | |||
@@ -0,0 +1,23 @@ | |||
1 | #!/bin/bash | ||
2 | # description: system-wide r/w top | ||
3 | # args: [interval] | ||
4 | n_args=0 | ||
5 | for i in "$@" | ||
6 | do | ||
7 | if expr match "$i" "-" > /dev/null ; then | ||
8 | break | ||
9 | fi | ||
10 | n_args=$(( $n_args + 1 )) | ||
11 | done | ||
12 | if [ "$n_args" -gt 1 ] ; then | ||
13 | echo "usage: rwtop-report [interval]" | ||
14 | exit | ||
15 | fi | ||
16 | if [ "$n_args" -gt 0 ] ; then | ||
17 | interval=$1 | ||
18 | shift | ||
19 | fi | ||
20 | perf trace $@ -s ~/libexec/perf-core/scripts/perl/rwtop.pl $interval | ||
21 | |||
22 | |||
23 | |||
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-record b/tools/perf/scripts/perl/bin/wakeup-latency-record index 6abedda911a4..9c0cf588ff8c 100644 --- a/tools/perf/scripts/perl/bin/wakeup-latency-record +++ b/tools/perf/scripts/perl/bin/wakeup-latency-record | |||
@@ -1,5 +1,5 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e sched:sched_switch -e sched:sched_wakeup | 2 | perf record -c 1 -f -a -M -R -e sched:sched_switch -e sched:sched_wakeup $@ |
3 | 3 | ||
4 | 4 | ||
5 | 5 | ||
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-report b/tools/perf/scripts/perl/bin/wakeup-latency-report index fce3adcb3249..a0d898f9ca1d 100644 --- a/tools/perf/scripts/perl/bin/wakeup-latency-report +++ b/tools/perf/scripts/perl/bin/wakeup-latency-report | |||
@@ -1,6 +1,6 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # description: system-wide min/max/avg wakeup latency | 2 | # description: system-wide min/max/avg wakeup latency |
3 | perf trace -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl | 3 | perf trace $@ -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl |
4 | 4 | ||
5 | 5 | ||
6 | 6 | ||
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record index fce6637b19ba..c2a1a9421133 100644 --- a/tools/perf/scripts/perl/bin/workqueue-stats-record +++ b/tools/perf/scripts/perl/bin/workqueue-stats-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion | 2 | perf record -c 1 -f -a -M -R -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@ |
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report index 71cfbd182fb9..35081132ef97 100644 --- a/tools/perf/scripts/perl/bin/workqueue-stats-report +++ b/tools/perf/scripts/perl/bin/workqueue-stats-report | |||
@@ -1,6 +1,6 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # description: workqueue stats (ins/exe/create/destroy) | 2 | # description: workqueue stats (ins/exe/create/destroy) |
3 | perf trace -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl | 3 | perf trace $@ -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl |
4 | 4 | ||
5 | 5 | ||
6 | 6 | ||
diff --git a/tools/perf/scripts/perl/rwtop.pl b/tools/perf/scripts/perl/rwtop.pl new file mode 100644 index 000000000000..ec2ab49a6f25 --- /dev/null +++ b/tools/perf/scripts/perl/rwtop.pl | |||
@@ -0,0 +1,177 @@ | |||
1 | #!/usr/bin/perl -w | ||
2 | # (c) 2010, Tom Zanussi <tzanussi@gmail.com> | ||
3 | # Licensed under the terms of the GNU GPL License version 2 | ||
4 | |||
5 | # read/write top | ||
6 | # | ||
7 | # Periodically displays system-wide r/w call activity, broken down by | ||
8 | # pid. If an [interval] arg is specified, the display will be | ||
9 | # refreshed every [interval] seconds. The default interval is 3 | ||
10 | # seconds. | ||
11 | |||
12 | use 5.010000; | ||
13 | use strict; | ||
14 | use warnings; | ||
15 | |||
16 | use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib"; | ||
17 | use lib "./Perf-Trace-Util/lib"; | ||
18 | use Perf::Trace::Core; | ||
19 | use Perf::Trace::Util; | ||
20 | |||
21 | my $default_interval = 3; | ||
22 | my $nlines = 20; | ||
23 | my $print_thread; | ||
24 | |||
25 | my %reads; | ||
26 | my %writes; | ||
27 | |||
28 | my $interval = shift; | ||
29 | if (!$interval) { | ||
30 | $interval = $default_interval; | ||
31 | } | ||
32 | |||
33 | sub syscalls::sys_exit_read | ||
34 | { | ||
35 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
36 | $common_pid, $common_comm, | ||
37 | $nr, $ret) = @_; | ||
38 | |||
39 | if ($ret > 0) { | ||
40 | $reads{$common_pid}{bytes_read} += $ret; | ||
41 | } else { | ||
42 | if (!defined ($reads{$common_pid}{bytes_read})) { | ||
43 | $reads{$common_pid}{bytes_read} = 0; | ||
44 | } | ||
45 | $reads{$common_pid}{errors}{$ret}++; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | sub syscalls::sys_enter_read | ||
50 | { | ||
51 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
52 | $common_pid, $common_comm, | ||
53 | $nr, $fd, $buf, $count) = @_; | ||
54 | |||
55 | $reads{$common_pid}{bytes_requested} += $count; | ||
56 | $reads{$common_pid}{total_reads}++; | ||
57 | $reads{$common_pid}{comm} = $common_comm; | ||
58 | } | ||
59 | |||
60 | sub syscalls::sys_exit_write | ||
61 | { | ||
62 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
63 | $common_pid, $common_comm, | ||
64 | $nr, $ret) = @_; | ||
65 | |||
66 | if ($ret <= 0) { | ||
67 | $writes{$common_pid}{errors}{$ret}++; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | sub syscalls::sys_enter_write | ||
72 | { | ||
73 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
74 | $common_pid, $common_comm, | ||
75 | $nr, $fd, $buf, $count) = @_; | ||
76 | |||
77 | $writes{$common_pid}{bytes_written} += $count; | ||
78 | $writes{$common_pid}{total_writes}++; | ||
79 | $writes{$common_pid}{comm} = $common_comm; | ||
80 | } | ||
81 | |||
82 | sub trace_begin | ||
83 | { | ||
84 | $SIG{ALRM} = \&print_totals; | ||
85 | alarm 1; | ||
86 | } | ||
87 | |||
88 | sub trace_end | ||
89 | { | ||
90 | print_unhandled(); | ||
91 | print_totals(); | ||
92 | } | ||
93 | |||
94 | sub print_totals | ||
95 | { | ||
96 | my $count; | ||
97 | |||
98 | $count = 0; | ||
99 | |||
100 | clear_term(); | ||
101 | |||
102 | printf("\nread counts by pid:\n\n"); | ||
103 | |||
104 | printf("%6s %20s %10s %10s %10s\n", "pid", "comm", | ||
105 | "# reads", "bytes_req", "bytes_read"); | ||
106 | printf("%6s %-20s %10s %10s %10s\n", "------", "--------------------", | ||
107 | "----------", "----------", "----------"); | ||
108 | |||
109 | foreach my $pid (sort {$reads{$b}{bytes_read} <=> | ||
110 | $reads{$a}{bytes_read}} keys %reads) { | ||
111 | my $comm = $reads{$pid}{comm}; | ||
112 | my $total_reads = $reads{$pid}{total_reads}; | ||
113 | my $bytes_requested = $reads{$pid}{bytes_requested}; | ||
114 | my $bytes_read = $reads{$pid}{bytes_read}; | ||
115 | |||
116 | printf("%6s %-20s %10s %10s %10s\n", $pid, $comm, | ||
117 | $total_reads, $bytes_requested, $bytes_read); | ||
118 | |||
119 | if (++$count == $nlines) { | ||
120 | last; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | $count = 0; | ||
125 | |||
126 | printf("\nwrite counts by pid:\n\n"); | ||
127 | |||
128 | printf("%6s %20s %10s %13s\n", "pid", "comm", | ||
129 | "# writes", "bytes_written"); | ||
130 | printf("%6s %-20s %10s %13s\n", "------", "--------------------", | ||
131 | "----------", "-------------"); | ||
132 | |||
133 | foreach my $pid (sort {$writes{$b}{bytes_written} <=> | ||
134 | $writes{$a}{bytes_written}} keys %writes) { | ||
135 | my $comm = $writes{$pid}{comm}; | ||
136 | my $total_writes = $writes{$pid}{total_writes}; | ||
137 | my $bytes_written = $writes{$pid}{bytes_written}; | ||
138 | |||
139 | printf("%6s %-20s %10s %13s\n", $pid, $comm, | ||
140 | $total_writes, $bytes_written); | ||
141 | |||
142 | if (++$count == $nlines) { | ||
143 | last; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | %reads = (); | ||
148 | %writes = (); | ||
149 | alarm $interval; | ||
150 | } | ||
151 | |||
152 | my %unhandled; | ||
153 | |||
154 | sub print_unhandled | ||
155 | { | ||
156 | if ((scalar keys %unhandled) == 0) { | ||
157 | return; | ||
158 | } | ||
159 | |||
160 | print "\nunhandled events:\n\n"; | ||
161 | |||
162 | printf("%-40s %10s\n", "event", "count"); | ||
163 | printf("%-40s %10s\n", "----------------------------------------", | ||
164 | "-----------"); | ||
165 | |||
166 | foreach my $event_name (keys %unhandled) { | ||
167 | printf("%-40s %10d\n", $event_name, $unhandled{$event_name}); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | sub trace_unhandled | ||
172 | { | ||
173 | my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs, | ||
174 | $common_pid, $common_comm) = @_; | ||
175 | |||
176 | $unhandled{$event_name}++; | ||
177 | } | ||
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py index 83e91435ed09..9689bc0acd9f 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py +++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py | |||
@@ -23,3 +23,6 @@ def nsecs_nsecs(nsecs): | |||
23 | def nsecs_str(nsecs): | 23 | def nsecs_str(nsecs): |
24 | str = "%5u.%09u" % (nsecs_secs(nsecs), nsecs_nsecs(nsecs)), | 24 | str = "%5u.%09u" % (nsecs_secs(nsecs), nsecs_nsecs(nsecs)), |
25 | return str | 25 | return str |
26 | |||
27 | def clear_term(): | ||
28 | print("\x1b[H\x1b[2J") | ||
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record index f8885d389e6f..6ad9b8f5f009 100644 --- a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record +++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_exit | 2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_exit $@ |
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report index 1e0c0a860c87..8c128eff9c0a 100644 --- a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report +++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report | |||
@@ -1,4 +1,10 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # description: system-wide failed syscalls, by pid | 2 | # description: system-wide failed syscalls, by pid |
3 | # args: [comm] | 3 | # args: [comm] |
4 | perf trace -s ~/libexec/perf-core/scripts/python/failed-syscalls-by-pid.py $1 | 4 | if [ $# -gt 0 ] ; then |
5 | if ! expr match "$1" "-" ; then | ||
6 | comm=$1 | ||
7 | shift | ||
8 | fi | ||
9 | fi | ||
10 | perf trace $@ -s ~/libexec/perf-core/scripts/python/failed-syscalls-by-pid.py $comm | ||
diff --git a/tools/perf/scripts/python/bin/sctop-record b/tools/perf/scripts/python/bin/sctop-record new file mode 100644 index 000000000000..27ccffa26ab4 --- /dev/null +++ b/tools/perf/scripts/python/bin/sctop-record | |||
@@ -0,0 +1,2 @@ | |||
1 | #!/bin/bash | ||
2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter $@ | ||
diff --git a/tools/perf/scripts/python/bin/sctop-report b/tools/perf/scripts/python/bin/sctop-report new file mode 100644 index 000000000000..b01c842ae7b4 --- /dev/null +++ b/tools/perf/scripts/python/bin/sctop-report | |||
@@ -0,0 +1,24 @@ | |||
1 | #!/bin/bash | ||
2 | # description: syscall top | ||
3 | # args: [comm] [interval] | ||
4 | n_args=0 | ||
5 | for i in "$@" | ||
6 | do | ||
7 | if expr match "$i" "-" > /dev/null ; then | ||
8 | break | ||
9 | fi | ||
10 | n_args=$(( $n_args + 1 )) | ||
11 | done | ||
12 | if [ "$n_args" -gt 2 ] ; then | ||
13 | echo "usage: sctop-report [comm] [interval]" | ||
14 | exit | ||
15 | fi | ||
16 | if [ "$n_args" -gt 1 ] ; then | ||
17 | comm=$1 | ||
18 | interval=$2 | ||
19 | shift 2 | ||
20 | elif [ "$n_args" -gt 0 ] ; then | ||
21 | interval=$1 | ||
22 | shift | ||
23 | fi | ||
24 | perf trace $@ -s ~/libexec/perf-core/scripts/python/sctop.py $comm $interval | ||
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record index 45a8c50359da..27ccffa26ab4 100644 --- a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record +++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter | 2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter $@ |
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-report b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report index f8044d192271..c53362e48602 100644 --- a/tools/perf/scripts/python/bin/syscall-counts-by-pid-report +++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report | |||
@@ -1,4 +1,10 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # description: system-wide syscall counts, by pid | 2 | # description: system-wide syscall counts, by pid |
3 | # args: [comm] | 3 | # args: [comm] |
4 | perf trace -s ~/libexec/perf-core/scripts/python/syscall-counts-by-pid.py $1 | 4 | if [ $# -gt 0 ] ; then |
5 | if ! expr match "$1" "-" ; then | ||
6 | comm=$1 | ||
7 | shift | ||
8 | fi | ||
9 | fi | ||
10 | perf trace $@ -s ~/libexec/perf-core/scripts/python/syscall-counts-by-pid.py $comm | ||
diff --git a/tools/perf/scripts/python/bin/syscall-counts-record b/tools/perf/scripts/python/bin/syscall-counts-record index 45a8c50359da..27ccffa26ab4 100644 --- a/tools/perf/scripts/python/bin/syscall-counts-record +++ b/tools/perf/scripts/python/bin/syscall-counts-record | |||
@@ -1,2 +1,2 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter | 2 | perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter $@ |
diff --git a/tools/perf/scripts/python/bin/syscall-counts-report b/tools/perf/scripts/python/bin/syscall-counts-report index a366aa61612f..8c21552b3cdc 100644 --- a/tools/perf/scripts/python/bin/syscall-counts-report +++ b/tools/perf/scripts/python/bin/syscall-counts-report | |||
@@ -1,4 +1,10 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # description: system-wide syscall counts | 2 | # description: system-wide syscall counts |
3 | # args: [comm] | 3 | # args: [comm] |
4 | perf trace -s ~/libexec/perf-core/scripts/python/syscall-counts.py $1 | 4 | if [ $# -gt 0 ] ; then |
5 | if ! expr match "$1" "-" ; then | ||
6 | comm=$1 | ||
7 | shift | ||
8 | fi | ||
9 | fi | ||
10 | perf trace $@ -s ~/libexec/perf-core/scripts/python/syscall-counts.py $comm | ||
diff --git a/tools/perf/scripts/python/sctop.py b/tools/perf/scripts/python/sctop.py new file mode 100644 index 000000000000..6cafad40c296 --- /dev/null +++ b/tools/perf/scripts/python/sctop.py | |||
@@ -0,0 +1,78 @@ | |||
1 | # system call top | ||
2 | # (c) 2010, Tom Zanussi <tzanussi@gmail.com> | ||
3 | # Licensed under the terms of the GNU GPL License version 2 | ||
4 | # | ||
5 | # Periodically displays system-wide system call totals, broken down by | ||
6 | # syscall. If a [comm] arg is specified, only syscalls called by | ||
7 | # [comm] are displayed. If an [interval] arg is specified, the display | ||
8 | # will be refreshed every [interval] seconds. The default interval is | ||
9 | # 3 seconds. | ||
10 | |||
11 | import thread | ||
12 | import time | ||
13 | import os | ||
14 | import sys | ||
15 | |||
16 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | ||
17 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') | ||
18 | |||
19 | from perf_trace_context import * | ||
20 | from Core import * | ||
21 | from Util import * | ||
22 | |||
23 | usage = "perf trace -s syscall-counts.py [comm] [interval]\n"; | ||
24 | |||
25 | for_comm = None | ||
26 | default_interval = 3 | ||
27 | interval = default_interval | ||
28 | |||
29 | if len(sys.argv) > 3: | ||
30 | sys.exit(usage) | ||
31 | |||
32 | if len(sys.argv) > 2: | ||
33 | for_comm = sys.argv[1] | ||
34 | interval = int(sys.argv[2]) | ||
35 | elif len(sys.argv) > 1: | ||
36 | try: | ||
37 | interval = int(sys.argv[1]) | ||
38 | except ValueError: | ||
39 | for_comm = sys.argv[1] | ||
40 | interval = default_interval | ||
41 | |||
42 | syscalls = autodict() | ||
43 | |||
44 | def trace_begin(): | ||
45 | thread.start_new_thread(print_syscall_totals, (interval,)) | ||
46 | pass | ||
47 | |||
48 | def raw_syscalls__sys_enter(event_name, context, common_cpu, | ||
49 | common_secs, common_nsecs, common_pid, common_comm, | ||
50 | id, args): | ||
51 | if for_comm is not None: | ||
52 | if common_comm != for_comm: | ||
53 | return | ||
54 | try: | ||
55 | syscalls[id] += 1 | ||
56 | except TypeError: | ||
57 | syscalls[id] = 1 | ||
58 | |||
59 | def print_syscall_totals(interval): | ||
60 | while 1: | ||
61 | clear_term() | ||
62 | if for_comm is not None: | ||
63 | print "\nsyscall events for %s:\n\n" % (for_comm), | ||
64 | else: | ||
65 | print "\nsyscall events:\n\n", | ||
66 | |||
67 | print "%-40s %10s\n" % ("event", "count"), | ||
68 | print "%-40s %10s\n" % ("----------------------------------------", \ | ||
69 | "----------"), | ||
70 | |||
71 | for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \ | ||
72 | reverse = True): | ||
73 | try: | ||
74 | print "%-40d %10d\n" % (id, val), | ||
75 | except TypeError: | ||
76 | pass | ||
77 | syscalls.clear() | ||
78 | time.sleep(interval) | ||
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 7f7cf8539cfe..e5740ea140ab 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -83,6 +83,37 @@ struct build_id_event { | |||
83 | char filename[]; | 83 | char filename[]; |
84 | }; | 84 | }; |
85 | 85 | ||
86 | enum perf_header_event_type { /* above any possible kernel type */ | ||
87 | PERF_RECORD_HEADER_ATTR = 64, | ||
88 | PERF_RECORD_HEADER_EVENT_TYPE = 65, | ||
89 | PERF_RECORD_HEADER_TRACING_DATA = 66, | ||
90 | PERF_RECORD_HEADER_BUILD_ID = 67, | ||
91 | PERF_RECORD_HEADER_MAX | ||
92 | }; | ||
93 | |||
94 | struct attr_event { | ||
95 | struct perf_event_header header; | ||
96 | struct perf_event_attr attr; | ||
97 | u64 id[]; | ||
98 | }; | ||
99 | |||
100 | #define MAX_EVENT_NAME 64 | ||
101 | |||
102 | struct perf_trace_event_type { | ||
103 | u64 event_id; | ||
104 | char name[MAX_EVENT_NAME]; | ||
105 | }; | ||
106 | |||
107 | struct event_type_event { | ||
108 | struct perf_event_header header; | ||
109 | struct perf_trace_event_type event_type; | ||
110 | }; | ||
111 | |||
112 | struct tracing_data_event { | ||
113 | struct perf_event_header header; | ||
114 | u32 size; | ||
115 | }; | ||
116 | |||
86 | typedef union event_union { | 117 | typedef union event_union { |
87 | struct perf_event_header header; | 118 | struct perf_event_header header; |
88 | struct ip_event ip; | 119 | struct ip_event ip; |
@@ -92,6 +123,10 @@ typedef union event_union { | |||
92 | struct lost_event lost; | 123 | struct lost_event lost; |
93 | struct read_event read; | 124 | struct read_event read; |
94 | struct sample_event sample; | 125 | struct sample_event sample; |
126 | struct attr_event attr; | ||
127 | struct event_type_event event_type; | ||
128 | struct tracing_data_event tracing_data; | ||
129 | struct build_id_event build_id; | ||
95 | } event_t; | 130 | } event_t; |
96 | 131 | ||
97 | struct events_stats { | 132 | struct events_stats { |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 6c9aa16ee51f..628173ba689e 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -99,13 +99,6 @@ int perf_header__add_attr(struct perf_header *self, | |||
99 | return 0; | 99 | return 0; |
100 | } | 100 | } |
101 | 101 | ||
102 | #define MAX_EVENT_NAME 64 | ||
103 | |||
104 | struct perf_trace_event_type { | ||
105 | u64 event_id; | ||
106 | char name[MAX_EVENT_NAME]; | ||
107 | }; | ||
108 | |||
109 | static int event_count; | 102 | static int event_count; |
110 | static struct perf_trace_event_type *events; | 103 | static struct perf_trace_event_type *events; |
111 | 104 | ||
@@ -427,6 +420,25 @@ out_free: | |||
427 | return err; | 420 | return err; |
428 | } | 421 | } |
429 | 422 | ||
423 | int perf_header__write_pipe(int fd) | ||
424 | { | ||
425 | struct perf_pipe_file_header f_header; | ||
426 | int err; | ||
427 | |||
428 | f_header = (struct perf_pipe_file_header){ | ||
429 | .magic = PERF_MAGIC, | ||
430 | .size = sizeof(f_header), | ||
431 | }; | ||
432 | |||
433 | err = do_write(fd, &f_header, sizeof(f_header)); | ||
434 | if (err < 0) { | ||
435 | pr_debug("failed to write perf pipe header\n"); | ||
436 | return err; | ||
437 | } | ||
438 | |||
439 | return 0; | ||
440 | } | ||
441 | |||
430 | int perf_header__write(struct perf_header *self, int fd, bool at_exit) | 442 | int perf_header__write(struct perf_header *self, int fd, bool at_exit) |
431 | { | 443 | { |
432 | struct perf_file_header f_header; | 444 | struct perf_file_header f_header; |
@@ -518,25 +530,10 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit) | |||
518 | return 0; | 530 | return 0; |
519 | } | 531 | } |
520 | 532 | ||
521 | static int do_read(int fd, void *buf, size_t size) | ||
522 | { | ||
523 | while (size) { | ||
524 | int ret = read(fd, buf, size); | ||
525 | |||
526 | if (ret <= 0) | ||
527 | return -1; | ||
528 | |||
529 | size -= ret; | ||
530 | buf += ret; | ||
531 | } | ||
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static int perf_header__getbuffer64(struct perf_header *self, | 533 | static int perf_header__getbuffer64(struct perf_header *self, |
537 | int fd, void *buf, size_t size) | 534 | int fd, void *buf, size_t size) |
538 | { | 535 | { |
539 | if (do_read(fd, buf, size)) | 536 | if (do_read(fd, buf, size) <= 0) |
540 | return -1; | 537 | return -1; |
541 | 538 | ||
542 | if (self->needs_swap) | 539 | if (self->needs_swap) |
@@ -592,7 +589,7 @@ int perf_file_header__read(struct perf_file_header *self, | |||
592 | { | 589 | { |
593 | lseek(fd, 0, SEEK_SET); | 590 | lseek(fd, 0, SEEK_SET); |
594 | 591 | ||
595 | if (do_read(fd, self, sizeof(*self)) || | 592 | if (do_read(fd, self, sizeof(*self)) <= 0 || |
596 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) | 593 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) |
597 | return -1; | 594 | return -1; |
598 | 595 | ||
@@ -662,13 +659,51 @@ static int perf_file_section__process(struct perf_file_section *self, | |||
662 | return 0; | 659 | return 0; |
663 | } | 660 | } |
664 | 661 | ||
665 | int perf_header__read(struct perf_header *self, int fd) | 662 | static int perf_file_header__read_pipe(struct perf_pipe_file_header *self, |
663 | struct perf_header *ph, int fd) | ||
664 | { | ||
665 | if (do_read(fd, self, sizeof(*self)) <= 0 || | ||
666 | memcmp(&self->magic, __perf_magic, sizeof(self->magic))) | ||
667 | return -1; | ||
668 | |||
669 | if (self->size != sizeof(*self)) { | ||
670 | u64 size = bswap_64(self->size); | ||
671 | |||
672 | if (size != sizeof(*self)) | ||
673 | return -1; | ||
674 | |||
675 | ph->needs_swap = true; | ||
676 | } | ||
677 | |||
678 | return 0; | ||
679 | } | ||
680 | |||
681 | static int perf_header__read_pipe(struct perf_session *session, int fd) | ||
682 | { | ||
683 | struct perf_header *self = &session->header; | ||
684 | struct perf_pipe_file_header f_header; | ||
685 | |||
686 | if (perf_file_header__read_pipe(&f_header, self, fd) < 0) { | ||
687 | pr_debug("incompatible file format\n"); | ||
688 | return -EINVAL; | ||
689 | } | ||
690 | |||
691 | session->fd = fd; | ||
692 | |||
693 | return 0; | ||
694 | } | ||
695 | |||
696 | int perf_header__read(struct perf_session *session, int fd) | ||
666 | { | 697 | { |
698 | struct perf_header *self = &session->header; | ||
667 | struct perf_file_header f_header; | 699 | struct perf_file_header f_header; |
668 | struct perf_file_attr f_attr; | 700 | struct perf_file_attr f_attr; |
669 | u64 f_id; | 701 | u64 f_id; |
670 | int nr_attrs, nr_ids, i, j; | 702 | int nr_attrs, nr_ids, i, j; |
671 | 703 | ||
704 | if (session->fd_pipe) | ||
705 | return perf_header__read_pipe(session, fd); | ||
706 | |||
672 | if (perf_file_header__read(&f_header, self, fd) < 0) { | 707 | if (perf_file_header__read(&f_header, self, fd) < 0) { |
673 | pr_debug("incompatible file format\n"); | 708 | pr_debug("incompatible file format\n"); |
674 | return -EINVAL; | 709 | return -EINVAL; |
@@ -765,3 +800,279 @@ perf_header__find_attr(u64 id, struct perf_header *header) | |||
765 | 800 | ||
766 | return NULL; | 801 | return NULL; |
767 | } | 802 | } |
803 | |||
804 | int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | ||
805 | event__handler_t process, | ||
806 | struct perf_session *session) | ||
807 | { | ||
808 | event_t *ev; | ||
809 | size_t size; | ||
810 | int err; | ||
811 | |||
812 | size = sizeof(struct perf_event_attr); | ||
813 | size = ALIGN(size, sizeof(u64)); | ||
814 | size += sizeof(struct perf_event_header); | ||
815 | size += ids * sizeof(u64); | ||
816 | |||
817 | ev = malloc(size); | ||
818 | |||
819 | ev->attr.attr = *attr; | ||
820 | memcpy(ev->attr.id, id, ids * sizeof(u64)); | ||
821 | |||
822 | ev->attr.header.type = PERF_RECORD_HEADER_ATTR; | ||
823 | ev->attr.header.size = size; | ||
824 | |||
825 | err = process(ev, session); | ||
826 | |||
827 | free(ev); | ||
828 | |||
829 | return err; | ||
830 | } | ||
831 | |||
832 | int event__synthesize_attrs(struct perf_header *self, | ||
833 | event__handler_t process, | ||
834 | struct perf_session *session) | ||
835 | { | ||
836 | struct perf_header_attr *attr; | ||
837 | int i, err = 0; | ||
838 | |||
839 | for (i = 0; i < self->attrs; i++) { | ||
840 | attr = self->attr[i]; | ||
841 | |||
842 | err = event__synthesize_attr(&attr->attr, attr->ids, attr->id, | ||
843 | process, session); | ||
844 | if (err) { | ||
845 | pr_debug("failed to create perf header attribute\n"); | ||
846 | return err; | ||
847 | } | ||
848 | } | ||
849 | |||
850 | return err; | ||
851 | } | ||
852 | |||
853 | int event__process_attr(event_t *self, struct perf_session *session) | ||
854 | { | ||
855 | struct perf_header_attr *attr; | ||
856 | unsigned int i, ids, n_ids; | ||
857 | |||
858 | attr = perf_header_attr__new(&self->attr.attr); | ||
859 | if (attr == NULL) | ||
860 | return -ENOMEM; | ||
861 | |||
862 | ids = self->header.size; | ||
863 | ids -= (void *)&self->attr.id - (void *)self; | ||
864 | n_ids = ids / sizeof(u64); | ||
865 | |||
866 | for (i = 0; i < n_ids; i++) { | ||
867 | if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) { | ||
868 | perf_header_attr__delete(attr); | ||
869 | return -ENOMEM; | ||
870 | } | ||
871 | } | ||
872 | |||
873 | if (perf_header__add_attr(&session->header, attr) < 0) { | ||
874 | perf_header_attr__delete(attr); | ||
875 | return -ENOMEM; | ||
876 | } | ||
877 | |||
878 | perf_session__update_sample_type(session); | ||
879 | |||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | int event__synthesize_event_type(u64 event_id, char *name, | ||
884 | event__handler_t process, | ||
885 | struct perf_session *session) | ||
886 | { | ||
887 | event_t ev; | ||
888 | size_t size = 0; | ||
889 | int err = 0; | ||
890 | |||
891 | memset(&ev, 0, sizeof(ev)); | ||
892 | |||
893 | ev.event_type.event_type.event_id = event_id; | ||
894 | memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME); | ||
895 | strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1); | ||
896 | |||
897 | ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE; | ||
898 | size = strlen(name); | ||
899 | size = ALIGN(size, sizeof(u64)); | ||
900 | ev.event_type.header.size = sizeof(ev.event_type) - | ||
901 | (sizeof(ev.event_type.event_type.name) - size); | ||
902 | |||
903 | err = process(&ev, session); | ||
904 | |||
905 | return err; | ||
906 | } | ||
907 | |||
908 | int event__synthesize_event_types(event__handler_t process, | ||
909 | struct perf_session *session) | ||
910 | { | ||
911 | struct perf_trace_event_type *type; | ||
912 | int i, err = 0; | ||
913 | |||
914 | for (i = 0; i < event_count; i++) { | ||
915 | type = &events[i]; | ||
916 | |||
917 | err = event__synthesize_event_type(type->event_id, type->name, | ||
918 | process, session); | ||
919 | if (err) { | ||
920 | pr_debug("failed to create perf header event type\n"); | ||
921 | return err; | ||
922 | } | ||
923 | } | ||
924 | |||
925 | return err; | ||
926 | } | ||
927 | |||
928 | int event__process_event_type(event_t *self, | ||
929 | struct perf_session *session __unused) | ||
930 | { | ||
931 | if (perf_header__push_event(self->event_type.event_type.event_id, | ||
932 | self->event_type.event_type.name) < 0) | ||
933 | return -ENOMEM; | ||
934 | |||
935 | return 0; | ||
936 | } | ||
937 | |||
938 | int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs, | ||
939 | int nb_events, | ||
940 | event__handler_t process, | ||
941 | struct perf_session *session __unused) | ||
942 | { | ||
943 | event_t ev; | ||
944 | ssize_t size = 0, aligned_size = 0, padding; | ||
945 | int err = 0; | ||
946 | |||
947 | memset(&ev, 0, sizeof(ev)); | ||
948 | |||
949 | ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; | ||
950 | size = read_tracing_data_size(fd, pattrs, nb_events); | ||
951 | if (size <= 0) | ||
952 | return size; | ||
953 | aligned_size = ALIGN(size, sizeof(u64)); | ||
954 | padding = aligned_size - size; | ||
955 | ev.tracing_data.header.size = sizeof(ev.tracing_data); | ||
956 | ev.tracing_data.size = aligned_size; | ||
957 | |||
958 | process(&ev, session); | ||
959 | |||
960 | err = read_tracing_data(fd, pattrs, nb_events); | ||
961 | write_padded(fd, NULL, 0, padding); | ||
962 | |||
963 | return aligned_size; | ||
964 | } | ||
965 | |||
966 | int event__process_tracing_data(event_t *self, | ||
967 | struct perf_session *session) | ||
968 | { | ||
969 | ssize_t size_read, padding, size = self->tracing_data.size; | ||
970 | off_t offset = lseek(session->fd, 0, SEEK_CUR); | ||
971 | char buf[BUFSIZ]; | ||
972 | |||
973 | /* setup for reading amidst mmap */ | ||
974 | lseek(session->fd, offset + sizeof(struct tracing_data_event), | ||
975 | SEEK_SET); | ||
976 | |||
977 | size_read = trace_report(session->fd); | ||
978 | |||
979 | padding = ALIGN(size_read, sizeof(u64)) - size_read; | ||
980 | |||
981 | if (read(session->fd, buf, padding) < 0) | ||
982 | die("reading input file"); | ||
983 | |||
984 | if (size_read + padding != size) | ||
985 | die("tracing data size mismatch"); | ||
986 | |||
987 | return size_read + padding; | ||
988 | } | ||
989 | |||
990 | int event__synthesize_build_id(struct dso *pos, u16 misc, | ||
991 | event__handler_t process, | ||
992 | struct perf_session *session) | ||
993 | { | ||
994 | event_t ev; | ||
995 | size_t len; | ||
996 | int err = 0; | ||
997 | |||
998 | if (!pos->hit) | ||
999 | return err; | ||
1000 | |||
1001 | memset(&ev, 0, sizeof(ev)); | ||
1002 | |||
1003 | len = pos->long_name_len + 1; | ||
1004 | len = ALIGN(len, NAME_ALIGN); | ||
1005 | memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id)); | ||
1006 | ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; | ||
1007 | ev.build_id.header.misc = misc; | ||
1008 | ev.build_id.header.size = sizeof(ev.build_id) + len; | ||
1009 | memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); | ||
1010 | |||
1011 | err = process(&ev, session); | ||
1012 | |||
1013 | return err; | ||
1014 | } | ||
1015 | |||
1016 | static int __event_synthesize_build_ids(struct list_head *head, u16 misc, | ||
1017 | event__handler_t process, | ||
1018 | struct perf_session *session) | ||
1019 | { | ||
1020 | struct dso *pos; | ||
1021 | |||
1022 | dsos__for_each_with_build_id(pos, head) { | ||
1023 | int err; | ||
1024 | if (!pos->hit) | ||
1025 | continue; | ||
1026 | |||
1027 | err = event__synthesize_build_id(pos, misc, process, session); | ||
1028 | if (err < 0) | ||
1029 | return err; | ||
1030 | } | ||
1031 | |||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | int event__synthesize_build_ids(event__handler_t process, | ||
1036 | struct perf_session *session) | ||
1037 | { | ||
1038 | int err; | ||
1039 | |||
1040 | if (!dsos__read_build_ids(true)) | ||
1041 | return 0; | ||
1042 | |||
1043 | err = __event_synthesize_build_ids(&dsos__kernel, | ||
1044 | PERF_RECORD_MISC_KERNEL, | ||
1045 | process, session); | ||
1046 | if (err == 0) | ||
1047 | err = __event_synthesize_build_ids(&dsos__user, | ||
1048 | PERF_RECORD_MISC_USER, | ||
1049 | process, session); | ||
1050 | |||
1051 | if (err < 0) { | ||
1052 | pr_debug("failed to synthesize build ids\n"); | ||
1053 | return err; | ||
1054 | } | ||
1055 | |||
1056 | dsos__cache_build_ids(); | ||
1057 | |||
1058 | return 0; | ||
1059 | } | ||
1060 | |||
1061 | int event__process_build_id(event_t *self, | ||
1062 | struct perf_session *session __unused) | ||
1063 | { | ||
1064 | struct list_head *head = &dsos__user; | ||
1065 | struct dso *dso; | ||
1066 | |||
1067 | if (self->build_id.header.misc & PERF_RECORD_MISC_KERNEL) | ||
1068 | head = &dsos__kernel; | ||
1069 | |||
1070 | dso = __dsos__findnew(head, self->build_id.filename); | ||
1071 | if (dso != NULL) { | ||
1072 | dso__set_build_id(dso, &self->build_id.build_id); | ||
1073 | if (head == &dsos__kernel && self->build_id.filename[0] == '[') | ||
1074 | dso->kernel = 1; | ||
1075 | } | ||
1076 | |||
1077 | return 0; | ||
1078 | } | ||
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index c059f08cf877..4214e2375650 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -39,6 +39,11 @@ struct perf_file_header { | |||
39 | DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); | 39 | DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); |
40 | }; | 40 | }; |
41 | 41 | ||
42 | struct perf_pipe_file_header { | ||
43 | u64 magic; | ||
44 | u64 size; | ||
45 | }; | ||
46 | |||
42 | struct perf_header; | 47 | struct perf_header; |
43 | 48 | ||
44 | int perf_file_header__read(struct perf_file_header *self, | 49 | int perf_file_header__read(struct perf_file_header *self, |
@@ -60,8 +65,9 @@ struct perf_header { | |||
60 | int perf_header__init(struct perf_header *self); | 65 | int perf_header__init(struct perf_header *self); |
61 | void perf_header__exit(struct perf_header *self); | 66 | void perf_header__exit(struct perf_header *self); |
62 | 67 | ||
63 | int perf_header__read(struct perf_header *self, int fd); | 68 | int perf_header__read(struct perf_session *session, int fd); |
64 | int perf_header__write(struct perf_header *self, int fd, bool at_exit); | 69 | int perf_header__write(struct perf_header *self, int fd, bool at_exit); |
70 | int perf_header__write_pipe(int fd); | ||
65 | 71 | ||
66 | int perf_header__add_attr(struct perf_header *self, | 72 | int perf_header__add_attr(struct perf_header *self, |
67 | struct perf_header_attr *attr); | 73 | struct perf_header_attr *attr); |
@@ -89,4 +95,34 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, | |||
89 | const char *name, bool is_kallsyms); | 95 | const char *name, bool is_kallsyms); |
90 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); | 96 | int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); |
91 | 97 | ||
98 | int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | ||
99 | event__handler_t process, | ||
100 | struct perf_session *session); | ||
101 | int event__synthesize_attrs(struct perf_header *self, | ||
102 | event__handler_t process, | ||
103 | struct perf_session *session); | ||
104 | int event__process_attr(event_t *self, struct perf_session *session); | ||
105 | |||
106 | int event__synthesize_event_type(u64 event_id, char *name, | ||
107 | event__handler_t process, | ||
108 | struct perf_session *session); | ||
109 | int event__synthesize_event_types(event__handler_t process, | ||
110 | struct perf_session *session); | ||
111 | int event__process_event_type(event_t *self, | ||
112 | struct perf_session *session); | ||
113 | |||
114 | int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs, | ||
115 | int nb_events, | ||
116 | event__handler_t process, | ||
117 | struct perf_session *session); | ||
118 | int event__process_tracing_data(event_t *self, | ||
119 | struct perf_session *session); | ||
120 | |||
121 | int event__synthesize_build_id(struct dso *pos, u16 misc, | ||
122 | event__handler_t process, | ||
123 | struct perf_session *session); | ||
124 | int event__synthesize_build_ids(event__handler_t process, | ||
125 | struct perf_session *session); | ||
126 | int event__process_build_id(event_t *self, struct perf_session *session); | ||
127 | |||
92 | #endif /* __PERF_HEADER_H */ | 128 | #endif /* __PERF_HEADER_H */ |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 435781e0c205..3b4ec6797565 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -410,7 +410,6 @@ static enum event_result | |||
410 | parse_single_tracepoint_event(char *sys_name, | 410 | parse_single_tracepoint_event(char *sys_name, |
411 | const char *evt_name, | 411 | const char *evt_name, |
412 | unsigned int evt_length, | 412 | unsigned int evt_length, |
413 | char *flags, | ||
414 | struct perf_event_attr *attr, | 413 | struct perf_event_attr *attr, |
415 | const char **strp) | 414 | const char **strp) |
416 | { | 415 | { |
@@ -419,13 +418,11 @@ parse_single_tracepoint_event(char *sys_name, | |||
419 | u64 id; | 418 | u64 id; |
420 | int fd; | 419 | int fd; |
421 | 420 | ||
422 | if (flags) { | 421 | attr->sample_type |= PERF_SAMPLE_RAW; |
423 | if (!strncmp(flags, "record", strlen(flags))) { | 422 | attr->sample_type |= PERF_SAMPLE_TIME; |
424 | attr->sample_type |= PERF_SAMPLE_RAW; | 423 | attr->sample_type |= PERF_SAMPLE_CPU; |
425 | attr->sample_type |= PERF_SAMPLE_TIME; | 424 | |
426 | attr->sample_type |= PERF_SAMPLE_CPU; | 425 | attr->sample_period = 1; |
427 | } | ||
428 | } | ||
429 | 426 | ||
430 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, | 427 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, |
431 | sys_name, evt_name); | 428 | sys_name, evt_name); |
@@ -533,8 +530,7 @@ static enum event_result parse_tracepoint_event(const char **strp, | |||
533 | flags); | 530 | flags); |
534 | } else | 531 | } else |
535 | return parse_single_tracepoint_event(sys_name, evt_name, | 532 | return parse_single_tracepoint_event(sys_name, evt_name, |
536 | evt_length, flags, | 533 | evt_length, attr, strp); |
537 | attr, strp); | ||
538 | } | 534 | } |
539 | 535 | ||
540 | static enum event_result | 536 | static enum event_result |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index ddf288fca3eb..0fdf3ebef1e9 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -14,6 +14,16 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
14 | { | 14 | { |
15 | struct stat input_stat; | 15 | struct stat input_stat; |
16 | 16 | ||
17 | if (!strcmp(self->filename, "-")) { | ||
18 | self->fd_pipe = true; | ||
19 | self->fd = STDIN_FILENO; | ||
20 | |||
21 | if (perf_header__read(self, self->fd) < 0) | ||
22 | pr_err("incompatible file format"); | ||
23 | |||
24 | return 0; | ||
25 | } | ||
26 | |||
17 | self->fd = open(self->filename, O_RDONLY); | 27 | self->fd = open(self->filename, O_RDONLY); |
18 | if (self->fd < 0) { | 28 | if (self->fd < 0) { |
19 | pr_err("failed to open file: %s", self->filename); | 29 | pr_err("failed to open file: %s", self->filename); |
@@ -38,7 +48,7 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
38 | goto out_close; | 48 | goto out_close; |
39 | } | 49 | } |
40 | 50 | ||
41 | if (perf_header__read(&self->header, self->fd) < 0) { | 51 | if (perf_header__read(self, self->fd) < 0) { |
42 | pr_err("incompatible file format"); | 52 | pr_err("incompatible file format"); |
43 | goto out_close; | 53 | goto out_close; |
44 | } | 54 | } |
@@ -52,6 +62,11 @@ out_close: | |||
52 | return -1; | 62 | return -1; |
53 | } | 63 | } |
54 | 64 | ||
65 | void perf_session__update_sample_type(struct perf_session *self) | ||
66 | { | ||
67 | self->sample_type = perf_header__sample_type(&self->header); | ||
68 | } | ||
69 | |||
55 | struct perf_session *perf_session__new(const char *filename, int mode, bool force) | 70 | struct perf_session *perf_session__new(const char *filename, int mode, bool force) |
56 | { | 71 | { |
57 | size_t len = filename ? strlen(filename) + 1 : 0; | 72 | size_t len = filename ? strlen(filename) + 1 : 0; |
@@ -85,7 +100,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc | |||
85 | goto out_delete; | 100 | goto out_delete; |
86 | } | 101 | } |
87 | 102 | ||
88 | self->sample_type = perf_header__sample_type(&self->header); | 103 | perf_session__update_sample_type(self); |
89 | out: | 104 | out: |
90 | return self; | 105 | return self; |
91 | out_free: | 106 | out_free: |
@@ -185,6 +200,14 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) | |||
185 | handler->throttle = process_event_stub; | 200 | handler->throttle = process_event_stub; |
186 | if (handler->unthrottle == NULL) | 201 | if (handler->unthrottle == NULL) |
187 | handler->unthrottle = process_event_stub; | 202 | handler->unthrottle = process_event_stub; |
203 | if (handler->attr == NULL) | ||
204 | handler->attr = process_event_stub; | ||
205 | if (handler->event_type == NULL) | ||
206 | handler->event_type = process_event_stub; | ||
207 | if (handler->tracing_data == NULL) | ||
208 | handler->tracing_data = process_event_stub; | ||
209 | if (handler->build_id == NULL) | ||
210 | handler->build_id = process_event_stub; | ||
188 | } | 211 | } |
189 | 212 | ||
190 | static const char *event__name[] = { | 213 | static const char *event__name[] = { |
@@ -198,16 +221,23 @@ static const char *event__name[] = { | |||
198 | [PERF_RECORD_FORK] = "FORK", | 221 | [PERF_RECORD_FORK] = "FORK", |
199 | [PERF_RECORD_READ] = "READ", | 222 | [PERF_RECORD_READ] = "READ", |
200 | [PERF_RECORD_SAMPLE] = "SAMPLE", | 223 | [PERF_RECORD_SAMPLE] = "SAMPLE", |
224 | [PERF_RECORD_HEADER_ATTR] = "ATTR", | ||
225 | [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", | ||
226 | [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", | ||
227 | [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", | ||
201 | }; | 228 | }; |
202 | 229 | ||
203 | unsigned long event__total[PERF_RECORD_MAX]; | 230 | unsigned long event__total[PERF_RECORD_HEADER_MAX]; |
204 | 231 | ||
205 | void event__print_totals(void) | 232 | void event__print_totals(void) |
206 | { | 233 | { |
207 | int i; | 234 | int i; |
208 | for (i = 0; i < PERF_RECORD_MAX; ++i) | 235 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { |
236 | if (!event__name[i]) | ||
237 | continue; | ||
209 | pr_info("%10s events: %10ld\n", | 238 | pr_info("%10s events: %10ld\n", |
210 | event__name[i], event__total[i]); | 239 | event__name[i], event__total[i]); |
240 | } | ||
211 | } | 241 | } |
212 | 242 | ||
213 | void mem_bswap_64(void *src, int byte_size) | 243 | void mem_bswap_64(void *src, int byte_size) |
@@ -261,6 +291,37 @@ static void event__read_swap(event_t *self) | |||
261 | self->read.id = bswap_64(self->read.id); | 291 | self->read.id = bswap_64(self->read.id); |
262 | } | 292 | } |
263 | 293 | ||
294 | static void event__attr_swap(event_t *self) | ||
295 | { | ||
296 | size_t size; | ||
297 | |||
298 | self->attr.attr.type = bswap_32(self->attr.attr.type); | ||
299 | self->attr.attr.size = bswap_32(self->attr.attr.size); | ||
300 | self->attr.attr.config = bswap_64(self->attr.attr.config); | ||
301 | self->attr.attr.sample_period = bswap_64(self->attr.attr.sample_period); | ||
302 | self->attr.attr.sample_type = bswap_64(self->attr.attr.sample_type); | ||
303 | self->attr.attr.read_format = bswap_64(self->attr.attr.read_format); | ||
304 | self->attr.attr.wakeup_events = bswap_32(self->attr.attr.wakeup_events); | ||
305 | self->attr.attr.bp_type = bswap_32(self->attr.attr.bp_type); | ||
306 | self->attr.attr.bp_addr = bswap_64(self->attr.attr.bp_addr); | ||
307 | self->attr.attr.bp_len = bswap_64(self->attr.attr.bp_len); | ||
308 | |||
309 | size = self->header.size; | ||
310 | size -= (void *)&self->attr.id - (void *)self; | ||
311 | mem_bswap_64(self->attr.id, size); | ||
312 | } | ||
313 | |||
314 | static void event__event_type_swap(event_t *self) | ||
315 | { | ||
316 | self->event_type.event_type.event_id = | ||
317 | bswap_64(self->event_type.event_type.event_id); | ||
318 | } | ||
319 | |||
320 | static void event__tracing_data_swap(event_t *self) | ||
321 | { | ||
322 | self->tracing_data.size = bswap_32(self->tracing_data.size); | ||
323 | } | ||
324 | |||
264 | typedef void (*event__swap_op)(event_t *self); | 325 | typedef void (*event__swap_op)(event_t *self); |
265 | 326 | ||
266 | static event__swap_op event__swap_ops[] = { | 327 | static event__swap_op event__swap_ops[] = { |
@@ -271,7 +332,11 @@ static event__swap_op event__swap_ops[] = { | |||
271 | [PERF_RECORD_LOST] = event__all64_swap, | 332 | [PERF_RECORD_LOST] = event__all64_swap, |
272 | [PERF_RECORD_READ] = event__read_swap, | 333 | [PERF_RECORD_READ] = event__read_swap, |
273 | [PERF_RECORD_SAMPLE] = event__all64_swap, | 334 | [PERF_RECORD_SAMPLE] = event__all64_swap, |
274 | [PERF_RECORD_MAX] = NULL, | 335 | [PERF_RECORD_HEADER_ATTR] = event__attr_swap, |
336 | [PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap, | ||
337 | [PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap, | ||
338 | [PERF_RECORD_HEADER_BUILD_ID] = NULL, | ||
339 | [PERF_RECORD_HEADER_MAX] = NULL, | ||
275 | }; | 340 | }; |
276 | 341 | ||
277 | static int perf_session__process_event(struct perf_session *self, | 342 | static int perf_session__process_event(struct perf_session *self, |
@@ -281,7 +346,7 @@ static int perf_session__process_event(struct perf_session *self, | |||
281 | { | 346 | { |
282 | trace_event(event); | 347 | trace_event(event); |
283 | 348 | ||
284 | if (event->header.type < PERF_RECORD_MAX) { | 349 | if (event->header.type < PERF_RECORD_HEADER_MAX) { |
285 | dump_printf("%#Lx [%#x]: PERF_RECORD_%s", | 350 | dump_printf("%#Lx [%#x]: PERF_RECORD_%s", |
286 | offset + head, event->header.size, | 351 | offset + head, event->header.size, |
287 | event__name[event->header.type]); | 352 | event__name[event->header.type]); |
@@ -311,6 +376,16 @@ static int perf_session__process_event(struct perf_session *self, | |||
311 | return ops->throttle(event, self); | 376 | return ops->throttle(event, self); |
312 | case PERF_RECORD_UNTHROTTLE: | 377 | case PERF_RECORD_UNTHROTTLE: |
313 | return ops->unthrottle(event, self); | 378 | return ops->unthrottle(event, self); |
379 | case PERF_RECORD_HEADER_ATTR: | ||
380 | return ops->attr(event, self); | ||
381 | case PERF_RECORD_HEADER_EVENT_TYPE: | ||
382 | return ops->event_type(event, self); | ||
383 | case PERF_RECORD_HEADER_TRACING_DATA: | ||
384 | /* setup for reading amidst mmap */ | ||
385 | lseek(self->fd, offset + head, SEEK_SET); | ||
386 | return ops->tracing_data(event, self); | ||
387 | case PERF_RECORD_HEADER_BUILD_ID: | ||
388 | return ops->build_id(event, self); | ||
314 | default: | 389 | default: |
315 | self->unknown_events++; | 390 | self->unknown_events++; |
316 | return -1; | 391 | return -1; |
@@ -376,6 +451,101 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se | |||
376 | return thread; | 451 | return thread; |
377 | } | 452 | } |
378 | 453 | ||
454 | int do_read(int fd, void *buf, size_t size) | ||
455 | { | ||
456 | void *buf_start = buf; | ||
457 | |||
458 | while (size) { | ||
459 | int ret = read(fd, buf, size); | ||
460 | |||
461 | if (ret <= 0) | ||
462 | return ret; | ||
463 | |||
464 | size -= ret; | ||
465 | buf += ret; | ||
466 | } | ||
467 | |||
468 | return buf - buf_start; | ||
469 | } | ||
470 | |||
471 | #define session_done() (*(volatile int *)(&session_done)) | ||
472 | volatile int session_done; | ||
473 | |||
474 | static int __perf_session__process_pipe_events(struct perf_session *self, | ||
475 | struct perf_event_ops *ops) | ||
476 | { | ||
477 | event_t event; | ||
478 | uint32_t size; | ||
479 | int skip = 0; | ||
480 | u64 head; | ||
481 | int err; | ||
482 | void *p; | ||
483 | |||
484 | perf_event_ops__fill_defaults(ops); | ||
485 | |||
486 | head = 0; | ||
487 | more: | ||
488 | err = do_read(self->fd, &event, sizeof(struct perf_event_header)); | ||
489 | if (err <= 0) { | ||
490 | if (err == 0) | ||
491 | goto done; | ||
492 | |||
493 | pr_err("failed to read event header\n"); | ||
494 | goto out_err; | ||
495 | } | ||
496 | |||
497 | if (self->header.needs_swap) | ||
498 | perf_event_header__bswap(&event.header); | ||
499 | |||
500 | size = event.header.size; | ||
501 | if (size == 0) | ||
502 | size = 8; | ||
503 | |||
504 | p = &event; | ||
505 | p += sizeof(struct perf_event_header); | ||
506 | |||
507 | err = do_read(self->fd, p, size - sizeof(struct perf_event_header)); | ||
508 | if (err <= 0) { | ||
509 | if (err == 0) { | ||
510 | pr_err("unexpected end of event stream\n"); | ||
511 | goto done; | ||
512 | } | ||
513 | |||
514 | pr_err("failed to read event data\n"); | ||
515 | goto out_err; | ||
516 | } | ||
517 | |||
518 | if (size == 0 || | ||
519 | (skip = perf_session__process_event(self, &event, ops, | ||
520 | 0, head)) < 0) { | ||
521 | dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", | ||
522 | head, event.header.size, event.header.type); | ||
523 | /* | ||
524 | * assume we lost track of the stream, check alignment, and | ||
525 | * increment a single u64 in the hope to catch on again 'soon'. | ||
526 | */ | ||
527 | if (unlikely(head & 7)) | ||
528 | head &= ~7ULL; | ||
529 | |||
530 | size = 8; | ||
531 | } | ||
532 | |||
533 | head += size; | ||
534 | |||
535 | dump_printf("\n%#Lx [%#x]: event: %d\n", | ||
536 | head, event.header.size, event.header.type); | ||
537 | |||
538 | if (skip > 0) | ||
539 | head += skip; | ||
540 | |||
541 | if (!session_done()) | ||
542 | goto more; | ||
543 | done: | ||
544 | err = 0; | ||
545 | out_err: | ||
546 | return err; | ||
547 | } | ||
548 | |||
379 | int __perf_session__process_events(struct perf_session *self, | 549 | int __perf_session__process_events(struct perf_session *self, |
380 | u64 data_offset, u64 data_size, | 550 | u64 data_offset, u64 data_size, |
381 | u64 file_size, struct perf_event_ops *ops) | 551 | u64 file_size, struct perf_event_ops *ops) |
@@ -499,9 +669,13 @@ out_getcwd_err: | |||
499 | self->cwdlen = strlen(self->cwd); | 669 | self->cwdlen = strlen(self->cwd); |
500 | } | 670 | } |
501 | 671 | ||
502 | err = __perf_session__process_events(self, self->header.data_offset, | 672 | if (!self->fd_pipe) |
503 | self->header.data_size, | 673 | err = __perf_session__process_events(self, |
504 | self->size, ops); | 674 | self->header.data_offset, |
675 | self->header.data_size, | ||
676 | self->size, ops); | ||
677 | else | ||
678 | err = __perf_session__process_pipe_events(self, ops); | ||
505 | out_err: | 679 | out_err: |
506 | return err; | 680 | return err; |
507 | } | 681 | } |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 27f4c2dc715b..0ac14d42dc28 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -27,6 +27,7 @@ struct perf_session { | |||
27 | u64 sample_type; | 27 | u64 sample_type; |
28 | struct ref_reloc_sym ref_reloc_sym; | 28 | struct ref_reloc_sym ref_reloc_sym; |
29 | int fd; | 29 | int fd; |
30 | bool fd_pipe; | ||
30 | int cwdlen; | 31 | int cwdlen; |
31 | char *cwd; | 32 | char *cwd; |
32 | char filename[0]; | 33 | char filename[0]; |
@@ -43,7 +44,11 @@ struct perf_event_ops { | |||
43 | lost, | 44 | lost, |
44 | read, | 45 | read, |
45 | throttle, | 46 | throttle, |
46 | unthrottle; | 47 | unthrottle, |
48 | attr, | ||
49 | event_type, | ||
50 | tracing_data, | ||
51 | build_id; | ||
47 | }; | 52 | }; |
48 | 53 | ||
49 | struct perf_session *perf_session__new(const char *filename, int mode, bool force); | 54 | struct perf_session *perf_session__new(const char *filename, int mode, bool force); |
@@ -92,6 +97,9 @@ static inline struct map * | |||
92 | return map_groups__new_module(&self->kmaps, start, filename); | 97 | return map_groups__new_module(&self->kmaps, start, filename); |
93 | } | 98 | } |
94 | 99 | ||
100 | int do_read(int fd, void *buf, size_t size); | ||
101 | void perf_session__update_sample_type(struct perf_session *self); | ||
102 | |||
95 | #ifdef NO_NEWT_SUPPORT | 103 | #ifdef NO_NEWT_SUPPORT |
96 | static inline int perf_session__browse_hists(struct rb_root *hists __used, | 104 | static inline int perf_session__browse_hists(struct rb_root *hists __used, |
97 | u64 nr_hists __used, | 105 | u64 nr_hists __used, |
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 5ea8973ad331..30cd9b575953 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c | |||
@@ -154,10 +154,17 @@ static void put_tracing_file(char *file) | |||
154 | free(file); | 154 | free(file); |
155 | } | 155 | } |
156 | 156 | ||
157 | static ssize_t calc_data_size; | ||
158 | |||
157 | static ssize_t write_or_die(const void *buf, size_t len) | 159 | static ssize_t write_or_die(const void *buf, size_t len) |
158 | { | 160 | { |
159 | int ret; | 161 | int ret; |
160 | 162 | ||
163 | if (calc_data_size) { | ||
164 | calc_data_size += len; | ||
165 | return len; | ||
166 | } | ||
167 | |||
161 | ret = write(output_fd, buf, len); | 168 | ret = write(output_fd, buf, len); |
162 | if (ret < 0) | 169 | if (ret < 0) |
163 | die("writing to '%s'", output_file); | 170 | die("writing to '%s'", output_file); |
@@ -526,3 +533,20 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events) | |||
526 | 533 | ||
527 | return 0; | 534 | return 0; |
528 | } | 535 | } |
536 | |||
537 | ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs, | ||
538 | int nb_events) | ||
539 | { | ||
540 | ssize_t size; | ||
541 | int err = 0; | ||
542 | |||
543 | calc_data_size = 1; | ||
544 | err = read_tracing_data(fd, pattrs, nb_events); | ||
545 | size = calc_data_size - 1; | ||
546 | calc_data_size = 0; | ||
547 | |||
548 | if (err < 0) | ||
549 | return err; | ||
550 | |||
551 | return size; | ||
552 | } | ||
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 17d6d66ed766..d6ef414075a6 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -761,7 +761,7 @@ static int field_is_string(struct format_field *field) | |||
761 | 761 | ||
762 | static int field_is_dynamic(struct format_field *field) | 762 | static int field_is_dynamic(struct format_field *field) |
763 | { | 763 | { |
764 | if (!strcmp(field->type, "__data_loc")) | 764 | if (!strncmp(field->type, "__data_loc", 10)) |
765 | return 1; | 765 | return 1; |
766 | 766 | ||
767 | return 0; | 767 | return 0; |
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 7cd1193918c7..44889c9b5630 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
@@ -50,14 +50,37 @@ static int long_size; | |||
50 | 50 | ||
51 | static unsigned long page_size; | 51 | static unsigned long page_size; |
52 | 52 | ||
53 | static ssize_t calc_data_size; | ||
54 | |||
55 | static int do_read(int fd, void *buf, int size) | ||
56 | { | ||
57 | int rsize = size; | ||
58 | |||
59 | while (size) { | ||
60 | int ret = read(fd, buf, size); | ||
61 | |||
62 | if (ret <= 0) | ||
63 | return -1; | ||
64 | |||
65 | size -= ret; | ||
66 | buf += ret; | ||
67 | } | ||
68 | |||
69 | return rsize; | ||
70 | } | ||
71 | |||
53 | static int read_or_die(void *data, int size) | 72 | static int read_or_die(void *data, int size) |
54 | { | 73 | { |
55 | int r; | 74 | int r; |
56 | 75 | ||
57 | r = read(input_fd, data, size); | 76 | r = do_read(input_fd, data, size); |
58 | if (r != size) | 77 | if (r <= 0) |
59 | die("reading input file (size expected=%d received=%d)", | 78 | die("reading input file (size expected=%d received=%d)", |
60 | size, r); | 79 | size, r); |
80 | |||
81 | if (calc_data_size) | ||
82 | calc_data_size += r; | ||
83 | |||
61 | return r; | 84 | return r; |
62 | } | 85 | } |
63 | 86 | ||
@@ -82,56 +105,28 @@ static char *read_string(void) | |||
82 | char buf[BUFSIZ]; | 105 | char buf[BUFSIZ]; |
83 | char *str = NULL; | 106 | char *str = NULL; |
84 | int size = 0; | 107 | int size = 0; |
85 | int i; | ||
86 | off_t r; | 108 | off_t r; |
109 | char c; | ||
87 | 110 | ||
88 | for (;;) { | 111 | for (;;) { |
89 | r = read(input_fd, buf, BUFSIZ); | 112 | r = read(input_fd, &c, 1); |
90 | if (r < 0) | 113 | if (r < 0) |
91 | die("reading input file"); | 114 | die("reading input file"); |
92 | 115 | ||
93 | if (!r) | 116 | if (!r) |
94 | die("no data"); | 117 | die("no data"); |
95 | 118 | ||
96 | for (i = 0; i < r; i++) { | 119 | buf[size++] = c; |
97 | if (!buf[i]) | ||
98 | break; | ||
99 | } | ||
100 | if (i < r) | ||
101 | break; | ||
102 | 120 | ||
103 | if (str) { | 121 | if (!c) |
104 | size += BUFSIZ; | 122 | break; |
105 | str = realloc(str, size); | ||
106 | if (!str) | ||
107 | die("malloc of size %d", size); | ||
108 | memcpy(str + (size - BUFSIZ), buf, BUFSIZ); | ||
109 | } else { | ||
110 | size = BUFSIZ; | ||
111 | str = malloc_or_die(size); | ||
112 | memcpy(str, buf, size); | ||
113 | } | ||
114 | } | 123 | } |
115 | 124 | ||
116 | /* trailing \0: */ | 125 | if (calc_data_size) |
117 | i++; | 126 | calc_data_size += size; |
118 | 127 | ||
119 | /* move the file descriptor to the end of the string */ | 128 | str = malloc_or_die(size); |
120 | r = lseek(input_fd, -(r - i), SEEK_CUR); | 129 | memcpy(str, buf, size); |
121 | if (r == (off_t)-1) | ||
122 | die("lseek"); | ||
123 | |||
124 | if (str) { | ||
125 | size += i; | ||
126 | str = realloc(str, size); | ||
127 | if (!str) | ||
128 | die("malloc of size %d", size); | ||
129 | memcpy(str + (size - i), buf, i); | ||
130 | } else { | ||
131 | size = i; | ||
132 | str = malloc_or_die(i); | ||
133 | memcpy(str, buf, i); | ||
134 | } | ||
135 | 130 | ||
136 | return str; | 131 | return str; |
137 | } | 132 | } |
@@ -459,7 +454,7 @@ struct record *trace_read_data(int cpu) | |||
459 | return data; | 454 | return data; |
460 | } | 455 | } |
461 | 456 | ||
462 | void trace_report(int fd) | 457 | ssize_t trace_report(int fd) |
463 | { | 458 | { |
464 | char buf[BUFSIZ]; | 459 | char buf[BUFSIZ]; |
465 | char test[] = { 23, 8, 68 }; | 460 | char test[] = { 23, 8, 68 }; |
@@ -467,6 +462,9 @@ void trace_report(int fd) | |||
467 | int show_version = 0; | 462 | int show_version = 0; |
468 | int show_funcs = 0; | 463 | int show_funcs = 0; |
469 | int show_printk = 0; | 464 | int show_printk = 0; |
465 | ssize_t size; | ||
466 | |||
467 | calc_data_size = 1; | ||
470 | 468 | ||
471 | input_fd = fd; | 469 | input_fd = fd; |
472 | 470 | ||
@@ -499,14 +497,17 @@ void trace_report(int fd) | |||
499 | read_proc_kallsyms(); | 497 | read_proc_kallsyms(); |
500 | read_ftrace_printk(); | 498 | read_ftrace_printk(); |
501 | 499 | ||
500 | size = calc_data_size - 1; | ||
501 | calc_data_size = 0; | ||
502 | |||
502 | if (show_funcs) { | 503 | if (show_funcs) { |
503 | print_funcs(); | 504 | print_funcs(); |
504 | return; | 505 | return size; |
505 | } | 506 | } |
506 | if (show_printk) { | 507 | if (show_printk) { |
507 | print_printk(); | 508 | print_printk(); |
508 | return; | 509 | return size; |
509 | } | 510 | } |
510 | 511 | ||
511 | return; | 512 | return size; |
512 | } | 513 | } |
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 81f2fd20a0ea..1f45d468fd9a 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -163,7 +163,7 @@ struct record *trace_read_data(int cpu); | |||
163 | 163 | ||
164 | void parse_set_info(int nr_cpus, int long_sz); | 164 | void parse_set_info(int nr_cpus, int long_sz); |
165 | 165 | ||
166 | void trace_report(int fd); | 166 | ssize_t trace_report(int fd); |
167 | 167 | ||
168 | void *malloc_or_die(unsigned int size); | 168 | void *malloc_or_die(unsigned int size); |
169 | 169 | ||
@@ -259,6 +259,8 @@ void *raw_field_ptr(struct event *event, const char *name, void *data); | |||
259 | unsigned long long eval_flag(const char *flag); | 259 | unsigned long long eval_flag(const char *flag); |
260 | 260 | ||
261 | int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events); | 261 | int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events); |
262 | ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs, | ||
263 | int nb_events); | ||
262 | 264 | ||
263 | /* taken from kernel/trace/trace.h */ | 265 | /* taken from kernel/trace/trace.h */ |
264 | enum trace_flag_type { | 266 | enum trace_flag_type { |