diff options
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r-- | tools/perf/builtin-trace.c | 97 |
1 files changed, 93 insertions, 4 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 407041d20de..dddf3f01b5a 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -11,6 +11,8 @@ | |||
11 | 11 | ||
12 | static char const *script_name; | 12 | static char const *script_name; |
13 | static char const *generate_script_lang; | 13 | static char const *generate_script_lang; |
14 | static bool debug_ordering; | ||
15 | static u64 last_timestamp; | ||
14 | 16 | ||
15 | static int default_start_script(const char *script __unused, | 17 | static int default_start_script(const char *script __unused, |
16 | int argc __unused, | 18 | int argc __unused, |
@@ -51,6 +53,8 @@ static void setup_scripting(void) | |||
51 | 53 | ||
52 | static int cleanup_scripting(void) | 54 | static int cleanup_scripting(void) |
53 | { | 55 | { |
56 | pr_debug("\nperf trace script stopped\n"); | ||
57 | |||
54 | return scripting_ops->stop_script(); | 58 | return scripting_ops->stop_script(); |
55 | } | 59 | } |
56 | 60 | ||
@@ -87,6 +91,14 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
87 | } | 91 | } |
88 | 92 | ||
89 | if (session->sample_type & PERF_SAMPLE_RAW) { | 93 | if (session->sample_type & PERF_SAMPLE_RAW) { |
94 | if (debug_ordering) { | ||
95 | if (data.time < last_timestamp) { | ||
96 | pr_err("Samples misordered, previous: %llu " | ||
97 | "this: %llu\n", last_timestamp, | ||
98 | data.time); | ||
99 | } | ||
100 | last_timestamp = data.time; | ||
101 | } | ||
90 | /* | 102 | /* |
91 | * FIXME: better resolve from pid from the struct trace_entry | 103 | * FIXME: better resolve from pid from the struct trace_entry |
92 | * field, although it should be the same than this perf | 104 | * field, although it should be the same than this perf |
@@ -97,17 +109,31 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
97 | data.time, thread->comm); | 109 | data.time, thread->comm); |
98 | } | 110 | } |
99 | 111 | ||
100 | session->events_stats.total += data.period; | 112 | session->hists.stats.total_period += data.period; |
101 | return 0; | 113 | return 0; |
102 | } | 114 | } |
103 | 115 | ||
104 | static struct perf_event_ops event_ops = { | 116 | static struct perf_event_ops event_ops = { |
105 | .sample = process_sample_event, | 117 | .sample = process_sample_event, |
106 | .comm = event__process_comm, | 118 | .comm = event__process_comm, |
119 | .attr = event__process_attr, | ||
120 | .event_type = event__process_event_type, | ||
121 | .tracing_data = event__process_tracing_data, | ||
122 | .build_id = event__process_build_id, | ||
123 | .ordered_samples = true, | ||
107 | }; | 124 | }; |
108 | 125 | ||
126 | extern volatile int session_done; | ||
127 | |||
128 | static void sig_handler(int sig __unused) | ||
129 | { | ||
130 | session_done = 1; | ||
131 | } | ||
132 | |||
109 | static int __cmd_trace(struct perf_session *session) | 133 | static int __cmd_trace(struct perf_session *session) |
110 | { | 134 | { |
135 | signal(SIGINT, sig_handler); | ||
136 | |||
111 | return perf_session__process_events(session, &event_ops); | 137 | return perf_session__process_events(session, &event_ops); |
112 | } | 138 | } |
113 | 139 | ||
@@ -505,7 +531,7 @@ static const char * const trace_usage[] = { | |||
505 | static const struct option options[] = { | 531 | static const struct option options[] = { |
506 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 532 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
507 | "dump raw trace in ASCII"), | 533 | "dump raw trace in ASCII"), |
508 | OPT_BOOLEAN('v', "verbose", &verbose, | 534 | OPT_INCR('v', "verbose", &verbose, |
509 | "be more verbose (show symbol address, etc)"), | 535 | "be more verbose (show symbol address, etc)"), |
510 | OPT_BOOLEAN('L', "Latency", &latency_format, | 536 | OPT_BOOLEAN('L', "Latency", &latency_format, |
511 | "show latency attributes (irqs/preemption disabled, etc)"), | 537 | "show latency attributes (irqs/preemption disabled, etc)"), |
@@ -518,6 +544,8 @@ static const struct option options[] = { | |||
518 | "generate perf-trace.xx script in specified language"), | 544 | "generate perf-trace.xx script in specified language"), |
519 | OPT_STRING('i', "input", &input_name, "file", | 545 | OPT_STRING('i', "input", &input_name, "file", |
520 | "input file name"), | 546 | "input file name"), |
547 | OPT_BOOLEAN('d', "debug-ordering", &debug_ordering, | ||
548 | "check that samples time ordering is monotonic"), | ||
521 | 549 | ||
522 | OPT_END() | 550 | OPT_END() |
523 | }; | 551 | }; |
@@ -548,6 +576,65 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
548 | suffix = REPORT_SUFFIX; | 576 | suffix = REPORT_SUFFIX; |
549 | } | 577 | } |
550 | 578 | ||
579 | if (!suffix && argc >= 2 && strncmp(argv[1], "-", strlen("-")) != 0) { | ||
580 | char *record_script_path, *report_script_path; | ||
581 | int live_pipe[2]; | ||
582 | pid_t pid; | ||
583 | |||
584 | record_script_path = get_script_path(argv[1], RECORD_SUFFIX); | ||
585 | if (!record_script_path) { | ||
586 | fprintf(stderr, "record script not found\n"); | ||
587 | return -1; | ||
588 | } | ||
589 | |||
590 | report_script_path = get_script_path(argv[1], REPORT_SUFFIX); | ||
591 | if (!report_script_path) { | ||
592 | fprintf(stderr, "report script not found\n"); | ||
593 | return -1; | ||
594 | } | ||
595 | |||
596 | if (pipe(live_pipe) < 0) { | ||
597 | perror("failed to create pipe"); | ||
598 | exit(-1); | ||
599 | } | ||
600 | |||
601 | pid = fork(); | ||
602 | if (pid < 0) { | ||
603 | perror("failed to fork"); | ||
604 | exit(-1); | ||
605 | } | ||
606 | |||
607 | if (!pid) { | ||
608 | dup2(live_pipe[1], 1); | ||
609 | close(live_pipe[0]); | ||
610 | |||
611 | __argv = malloc(5 * sizeof(const char *)); | ||
612 | __argv[0] = "/bin/sh"; | ||
613 | __argv[1] = record_script_path; | ||
614 | __argv[2] = "-o"; | ||
615 | __argv[3] = "-"; | ||
616 | __argv[4] = NULL; | ||
617 | |||
618 | execvp("/bin/sh", (char **)__argv); | ||
619 | exit(-1); | ||
620 | } | ||
621 | |||
622 | dup2(live_pipe[0], 0); | ||
623 | close(live_pipe[1]); | ||
624 | |||
625 | __argv = malloc((argc + 3) * sizeof(const char *)); | ||
626 | __argv[0] = "/bin/sh"; | ||
627 | __argv[1] = report_script_path; | ||
628 | for (i = 2; i < argc; i++) | ||
629 | __argv[i] = argv[i]; | ||
630 | __argv[i++] = "-i"; | ||
631 | __argv[i++] = "-"; | ||
632 | __argv[i++] = NULL; | ||
633 | |||
634 | execvp("/bin/sh", (char **)__argv); | ||
635 | exit(-1); | ||
636 | } | ||
637 | |||
551 | if (suffix) { | 638 | if (suffix) { |
552 | script_path = get_script_path(argv[2], suffix); | 639 | script_path = get_script_path(argv[2], suffix); |
553 | if (!script_path) { | 640 | if (!script_path) { |
@@ -576,11 +663,12 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
576 | if (!script_name) | 663 | if (!script_name) |
577 | setup_pager(); | 664 | setup_pager(); |
578 | 665 | ||
579 | session = perf_session__new(input_name, O_RDONLY, 0); | 666 | session = perf_session__new(input_name, O_RDONLY, 0, false); |
580 | if (session == NULL) | 667 | if (session == NULL) |
581 | return -ENOMEM; | 668 | return -ENOMEM; |
582 | 669 | ||
583 | if (!perf_session__has_traces(session, "record -R")) | 670 | if (strcmp(input_name, "-") && |
671 | !perf_session__has_traces(session, "record -R")) | ||
584 | return -EINVAL; | 672 | return -EINVAL; |
585 | 673 | ||
586 | if (generate_script_lang) { | 674 | if (generate_script_lang) { |
@@ -617,6 +705,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
617 | err = scripting_ops->start_script(script_name, argc, argv); | 705 | err = scripting_ops->start_script(script_name, argc, argv); |
618 | if (err) | 706 | if (err) |
619 | goto out; | 707 | goto out; |
708 | pr_debug("perf trace started with script %s\n\n", script_name); | ||
620 | } | 709 | } |
621 | 710 | ||
622 | err = __cmd_trace(session); | 711 | err = __cmd_trace(session); |