diff options
author | David Ahern <dsahern@gmail.com> | 2013-08-29 00:29:52 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2013-08-29 16:42:34 -0400 |
commit | 6810fc915f7a89d8134edb3996dbbf8eac386c26 (patch) | |
tree | 879213959ccf0ddc0c3d4d49d957dc9fc811b4cb | |
parent | a2f2804a7142b043dafd39f21b86777840e1a78c (diff) |
perf trace: Add option to analyze events in a file versus live
Allows capture of raw_syscall:* events and analyzed at a later time.
v2: change -i option from inherit to input name for consistency with
other perf commands
Signed-off-by: David Ahern <dsahern@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1377750593-48046-3-git-send-email-dsahern@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/Documentation/perf-trace.txt | 4 | ||||
-rw-r--r-- | tools/perf/builtin-trace.c | 98 |
2 files changed, 100 insertions, 2 deletions
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index fe19811faf90..daccd2c0a48f 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt | |||
@@ -74,6 +74,10 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. | |||
74 | --sched: | 74 | --sched: |
75 | Accrue thread runtime and provide a summary at the end of the session. | 75 | Accrue thread runtime and provide a summary at the end of the session. |
76 | 76 | ||
77 | -i | ||
78 | --input | ||
79 | Process events from a given perf data file. | ||
80 | |||
77 | SEE ALSO | 81 | SEE ALSO |
78 | -------- | 82 | -------- |
79 | linkperf:perf-record[1], linkperf:perf-script[1] | 83 | linkperf:perf-record[1], linkperf:perf-script[1] |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 88387c565687..2a6ebe184802 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "util/debug.h" | 4 | #include "util/debug.h" |
5 | #include "util/evlist.h" | 5 | #include "util/evlist.h" |
6 | #include "util/machine.h" | 6 | #include "util/machine.h" |
7 | #include "util/session.h" | ||
7 | #include "util/thread.h" | 8 | #include "util/thread.h" |
8 | #include "util/parse-options.h" | 9 | #include "util/parse-options.h" |
9 | #include "util/strlist.h" | 10 | #include "util/strlist.h" |
@@ -652,6 +653,36 @@ out_dump: | |||
652 | return 0; | 653 | return 0; |
653 | } | 654 | } |
654 | 655 | ||
656 | static int trace__process_sample(struct perf_tool *tool, | ||
657 | union perf_event *event __maybe_unused, | ||
658 | struct perf_sample *sample, | ||
659 | struct perf_evsel *evsel, | ||
660 | struct machine *machine __maybe_unused) | ||
661 | { | ||
662 | struct trace *trace = container_of(tool, struct trace, tool); | ||
663 | int err = 0; | ||
664 | |||
665 | tracepoint_handler handler = evsel->handler.func; | ||
666 | |||
667 | if (trace->base_time == 0) | ||
668 | trace->base_time = sample->time; | ||
669 | |||
670 | if (handler) | ||
671 | handler(trace, evsel, sample); | ||
672 | |||
673 | return err; | ||
674 | } | ||
675 | |||
676 | static bool | ||
677 | perf_session__has_tp(struct perf_session *session, const char *name) | ||
678 | { | ||
679 | struct perf_evsel *evsel; | ||
680 | |||
681 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name); | ||
682 | |||
683 | return evsel != NULL; | ||
684 | } | ||
685 | |||
655 | static int trace__run(struct trace *trace, int argc, const char **argv) | 686 | static int trace__run(struct trace *trace, int argc, const char **argv) |
656 | { | 687 | { |
657 | struct perf_evlist *evlist = perf_evlist__new(); | 688 | struct perf_evlist *evlist = perf_evlist__new(); |
@@ -791,6 +822,65 @@ out: | |||
791 | return err; | 822 | return err; |
792 | } | 823 | } |
793 | 824 | ||
825 | static int trace__replay(struct trace *trace) | ||
826 | { | ||
827 | const struct perf_evsel_str_handler handlers[] = { | ||
828 | { "raw_syscalls:sys_enter", trace__sys_enter, }, | ||
829 | { "raw_syscalls:sys_exit", trace__sys_exit, }, | ||
830 | }; | ||
831 | |||
832 | struct perf_session *session; | ||
833 | int err = -1; | ||
834 | |||
835 | trace->tool.sample = trace__process_sample; | ||
836 | trace->tool.mmap = perf_event__process_mmap; | ||
837 | trace->tool.comm = perf_event__process_comm; | ||
838 | trace->tool.exit = perf_event__process_exit; | ||
839 | trace->tool.fork = perf_event__process_fork; | ||
840 | trace->tool.attr = perf_event__process_attr; | ||
841 | trace->tool.tracing_data = perf_event__process_tracing_data; | ||
842 | trace->tool.build_id = perf_event__process_build_id; | ||
843 | |||
844 | trace->tool.ordered_samples = true; | ||
845 | trace->tool.ordering_requires_timestamps = true; | ||
846 | |||
847 | /* add tid to output */ | ||
848 | trace->multiple_threads = true; | ||
849 | |||
850 | if (symbol__init() < 0) | ||
851 | return -1; | ||
852 | |||
853 | session = perf_session__new(input_name, O_RDONLY, 0, false, | ||
854 | &trace->tool); | ||
855 | if (session == NULL) | ||
856 | return -ENOMEM; | ||
857 | |||
858 | err = perf_session__set_tracepoints_handlers(session, handlers); | ||
859 | if (err) | ||
860 | goto out; | ||
861 | |||
862 | if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) { | ||
863 | pr_err("Data file does not have raw_syscalls:sys_enter events\n"); | ||
864 | goto out; | ||
865 | } | ||
866 | |||
867 | if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) { | ||
868 | pr_err("Data file does not have raw_syscalls:sys_exit events\n"); | ||
869 | goto out; | ||
870 | } | ||
871 | |||
872 | setup_pager(); | ||
873 | |||
874 | err = perf_session__process_events(session, &trace->tool); | ||
875 | if (err) | ||
876 | pr_err("Failed to process events, error %d", err); | ||
877 | |||
878 | out: | ||
879 | perf_session__delete(session); | ||
880 | |||
881 | return err; | ||
882 | } | ||
883 | |||
794 | static size_t trace__fprintf_threads_header(FILE *fp) | 884 | static size_t trace__fprintf_threads_header(FILE *fp) |
795 | { | 885 | { |
796 | size_t printed; | 886 | size_t printed; |
@@ -892,6 +982,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
892 | OPT_STRING('e', "expr", &ev_qualifier_str, "expr", | 982 | OPT_STRING('e', "expr", &ev_qualifier_str, "expr", |
893 | "list of events to trace"), | 983 | "list of events to trace"), |
894 | OPT_STRING('o', "output", &output_name, "file", "output file name"), | 984 | OPT_STRING('o', "output", &output_name, "file", "output file name"), |
985 | OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"), | ||
895 | OPT_STRING('p', "pid", &trace.opts.target.pid, "pid", | 986 | OPT_STRING('p', "pid", &trace.opts.target.pid, "pid", |
896 | "trace events on existing process id"), | 987 | "trace events on existing process id"), |
897 | OPT_STRING('t', "tid", &trace.opts.target.tid, "tid", | 988 | OPT_STRING('t', "tid", &trace.opts.target.tid, "tid", |
@@ -900,7 +991,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
900 | "system-wide collection from all CPUs"), | 991 | "system-wide collection from all CPUs"), |
901 | OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu", | 992 | OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu", |
902 | "list of cpus to monitor"), | 993 | "list of cpus to monitor"), |
903 | OPT_BOOLEAN('i', "no-inherit", &trace.opts.no_inherit, | 994 | OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit, |
904 | "child tasks do not inherit counters"), | 995 | "child tasks do not inherit counters"), |
905 | OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages, | 996 | OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages, |
906 | "number of mmap data pages"), | 997 | "number of mmap data pages"), |
@@ -958,7 +1049,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
958 | if (!argc && perf_target__none(&trace.opts.target)) | 1049 | if (!argc && perf_target__none(&trace.opts.target)) |
959 | trace.opts.target.system_wide = true; | 1050 | trace.opts.target.system_wide = true; |
960 | 1051 | ||
961 | err = trace__run(&trace, argc, argv); | 1052 | if (input_name) |
1053 | err = trace__replay(&trace); | ||
1054 | else | ||
1055 | err = trace__run(&trace, argc, argv); | ||
962 | 1056 | ||
963 | if (trace.sched && !err) | 1057 | if (trace.sched && !err) |
964 | trace__fprintf_thread_summary(&trace, trace.output); | 1058 | trace__fprintf_thread_summary(&trace, trace.output); |