diff options
author | Ingo Molnar <mingo@elte.hu> | 2010-04-15 03:13:26 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-04-15 03:13:26 -0400 |
commit | 84b13fd596522db47f9545d5124c30cc00dfdf5a (patch) | |
tree | c1f51b8fe43a59fb56ea43a18da88c0d0812dd7d | |
parent | f92128193094c288bc315db1694fafeaeb7ee1d0 (diff) | |
parent | a0cccc2e8e9fb16cbed3a117b30e3fbac3092ee3 (diff) |
Merge branch 'perf/live' into perf/core
Conflicts:
tools/perf/builtin-record.c
Merge reason: add the live tracing feature, resolve conflict.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
35 files changed, 1184 insertions, 106 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ca2affc9233f..a1b99eeac3c0 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -42,6 +42,7 @@ static unsigned int mmap_pages = 128; | |||
42 | static unsigned int user_freq = UINT_MAX; | 42 | static unsigned int user_freq = UINT_MAX; |
43 | static int freq = 1000; | 43 | static int freq = 1000; |
44 | static int output; | 44 | static int output; |
45 | static int pipe_output = 0; | ||
45 | static const char *output_name = "perf.data"; | 46 | static const char *output_name = "perf.data"; |
46 | static int group = 0; | 47 | static int group = 0; |
47 | static unsigned int realtime_prio = 0; | 48 | static unsigned int realtime_prio = 0; |
@@ -109,6 +110,11 @@ static void mmap_write_tail(struct mmap_data *md, unsigned long tail) | |||
109 | pc->data_tail = tail; | 110 | pc->data_tail = tail; |
110 | } | 111 | } |
111 | 112 | ||
113 | static void advance_output(size_t size) | ||
114 | { | ||
115 | bytes_written += size; | ||
116 | } | ||
117 | |||
112 | static void write_output(void *buf, size_t size) | 118 | static void write_output(void *buf, size_t size) |
113 | { | 119 | { |
114 | while (size) { | 120 | while (size) { |
@@ -435,10 +441,19 @@ static int process_buildids(void) | |||
435 | 441 | ||
436 | static void atexit_header(void) | 442 | static void atexit_header(void) |
437 | { | 443 | { |
438 | session->header.data_size += bytes_written; | 444 | if (!pipe_output) { |
445 | session->header.data_size += bytes_written; | ||
439 | 446 | ||
440 | process_buildids(); | 447 | process_buildids(); |
441 | perf_header__write(&session->header, output, true); | 448 | perf_header__write(&session->header, output, true); |
449 | } else { | ||
450 | int err; | ||
451 | |||
452 | err = event__synthesize_build_ids(process_synthesized_event, | ||
453 | session); | ||
454 | if (err < 0) | ||
455 | pr_err("Couldn't synthesize build ids.\n"); | ||
456 | } | ||
442 | } | 457 | } |
443 | 458 | ||
444 | static int __cmd_record(int argc, const char **argv) | 459 | static int __cmd_record(int argc, const char **argv) |
@@ -464,7 +479,9 @@ static int __cmd_record(int argc, const char **argv) | |||
464 | exit(-1); | 479 | exit(-1); |
465 | } | 480 | } |
466 | 481 | ||
467 | if (!stat(output_name, &st) && st.st_size) { | 482 | if (!strcmp(output_name, "-")) |
483 | pipe_output = 1; | ||
484 | else if (!stat(output_name, &st) && st.st_size) { | ||
468 | if (write_mode == WRITE_FORCE) { | 485 | if (write_mode == WRITE_FORCE) { |
469 | char oldname[PATH_MAX]; | 486 | char oldname[PATH_MAX]; |
470 | snprintf(oldname, sizeof(oldname), "%s.old", | 487 | snprintf(oldname, sizeof(oldname), "%s.old", |
@@ -482,7 +499,10 @@ static int __cmd_record(int argc, const char **argv) | |||
482 | else | 499 | else |
483 | flags |= O_TRUNC; | 500 | flags |= O_TRUNC; |
484 | 501 | ||
485 | 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); | ||
486 | if (output < 0) { | 506 | if (output < 0) { |
487 | perror("failed to create output file"); | 507 | perror("failed to create output file"); |
488 | exit(-1); | 508 | exit(-1); |
@@ -496,7 +516,7 @@ static int __cmd_record(int argc, const char **argv) | |||
496 | } | 516 | } |
497 | 517 | ||
498 | if (!file_new) { | 518 | if (!file_new) { |
499 | err = perf_header__read(&session->header, output); | 519 | err = perf_header__read(session, output); |
500 | if (err < 0) | 520 | if (err < 0) |
501 | return err; | 521 | return err; |
502 | } | 522 | } |
@@ -522,6 +542,8 @@ static int __cmd_record(int argc, const char **argv) | |||
522 | } | 542 | } |
523 | 543 | ||
524 | if (!child_pid) { | 544 | if (!child_pid) { |
545 | if (pipe_output) | ||
546 | dup2(2, 1); | ||
525 | close(child_ready_pipe[0]); | 547 | close(child_ready_pipe[0]); |
526 | close(go_pipe[1]); | 548 | close(go_pipe[1]); |
527 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); | 549 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); |
@@ -573,7 +595,11 @@ static int __cmd_record(int argc, const char **argv) | |||
573 | open_counters(cpumap[i]); | 595 | open_counters(cpumap[i]); |
574 | } | 596 | } |
575 | 597 | ||
576 | 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) { | ||
577 | err = perf_header__write(&session->header, output, false); | 603 | err = perf_header__write(&session->header, output, false); |
578 | if (err < 0) | 604 | if (err < 0) |
579 | return err; | 605 | return err; |
@@ -581,6 +607,34 @@ static int __cmd_record(int argc, const char **argv) | |||
581 | 607 | ||
582 | post_processing_offset = lseek(output, 0, SEEK_CUR); | 608 | post_processing_offset = lseek(output, 0, SEEK_CUR); |
583 | 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 | |||
584 | err = event__synthesize_kernel_mmap(process_synthesized_event, | 638 | err = event__synthesize_kernel_mmap(process_synthesized_event, |
585 | session, "_text"); | 639 | session, "_text"); |
586 | if (err < 0) | 640 | if (err < 0) |
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/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-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 { |