diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-02-26 06:25:20 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-02-26 06:25:20 -0500 |
commit | 0afb1704010f60e7ae85aef0f93fc10f2d99761e (patch) | |
tree | 62e8dff37b9c4fb6fbc45618aef73c35fb86f57a /tools | |
parent | e9e4e44309f866b115d08ab4a54834008c50a8a4 (diff) | |
parent | 54cf776a9c5c2e6a91de31954bba4d3bad6c657c (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
New user selectable features:
- Support recording running/enabled time in 'perf record' (Andi Kleen)
- New tool: 'perf data' for converting perf.data to other formats,
initially for the CTF (Common Trace Format) from LTTng (Jiri Olsa, Sebastian Siewior)
User visible changes:
- Only insert blank duration bracket when tracing syscalls in 'perf trace' (Arnaldo Carvalho de Melo)
- Filter out the trace pid when no threads are specified in 'perf trace' (Arnaldo Carvalho de Melo)
- Add 'perf trace' man page entry for --event (Arnaldo Carvalho de Melo)
- Dump stack on segfaults in 'perf trace' (Arnaldo Carvalho de Melo)
Infrastructure changes:
- Introduce set_filter_pid and set_filter_pids methods in the evlist class (Arnaldo Carvalho de Melo)
- Some perf_session untanglement patches, removing the need to pass a
perf_session instance for things that are related to evlists, so that
tools that don't deal with perf.data files like trace in live mode can
make use of the ordered_events class (Arnaldo Carvalho de Melo)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
33 files changed, 1063 insertions, 99 deletions
diff --git a/tools/perf/Build b/tools/perf/Build index 976e03849f6d..b77370ef7005 100644 --- a/tools/perf/Build +++ b/tools/perf/Build | |||
@@ -18,6 +18,7 @@ perf-y += builtin-lock.o | |||
18 | perf-y += builtin-kvm.o | 18 | perf-y += builtin-kvm.o |
19 | perf-y += builtin-inject.o | 19 | perf-y += builtin-inject.o |
20 | perf-y += builtin-mem.o | 20 | perf-y += builtin-mem.o |
21 | perf-y += builtin-data.o | ||
21 | 22 | ||
22 | perf-$(CONFIG_AUDIT) += builtin-trace.o | 23 | perf-$(CONFIG_AUDIT) += builtin-trace.o |
23 | perf-$(CONFIG_LIBELF) += builtin-probe.o | 24 | perf-$(CONFIG_LIBELF) += builtin-probe.o |
diff --git a/tools/perf/Documentation/perf-data.txt b/tools/perf/Documentation/perf-data.txt new file mode 100644 index 000000000000..be8fa1a0a97e --- /dev/null +++ b/tools/perf/Documentation/perf-data.txt | |||
@@ -0,0 +1,40 @@ | |||
1 | perf-data(1) | ||
2 | ============== | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | perf-data - Data file related processing | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | [verse] | ||
11 | 'perf data' [<common options>] <command> [<options>]", | ||
12 | |||
13 | DESCRIPTION | ||
14 | ----------- | ||
15 | Data file related processing. | ||
16 | |||
17 | COMMANDS | ||
18 | -------- | ||
19 | convert:: | ||
20 | Converts perf data file into another format (only CTF [1] format is support by now). | ||
21 | It's possible to set data-convert debug variable to get debug messages from conversion, | ||
22 | like: | ||
23 | perf --debug data-convert data convert ... | ||
24 | |||
25 | OPTIONS for 'convert' | ||
26 | --------------------- | ||
27 | --to-ctf:: | ||
28 | Triggers the CTF conversion, specify the path of CTF data directory. | ||
29 | |||
30 | -i:: | ||
31 | Specify input perf data file path. | ||
32 | |||
33 | -v:: | ||
34 | --verbose:: | ||
35 | Be more verbose (show counter open errors, etc). | ||
36 | |||
37 | SEE ALSO | ||
38 | -------- | ||
39 | linkperf:perf[1] | ||
40 | [1] Common Trace Format - http://www.efficios.com/ctf | ||
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 1c7e50f62b1f..cae75c11120f 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -241,6 +241,9 @@ Capture machine state (registers) at interrupt, i.e., on counter overflows for | |||
241 | each sample. List of captured registers depends on the architecture. This option | 241 | each sample. List of captured registers depends on the architecture. This option |
242 | is off by default. | 242 | is off by default. |
243 | 243 | ||
244 | --running-time:: | ||
245 | Record running and enabled time for read events (:S) | ||
246 | |||
244 | SEE ALSO | 247 | SEE ALSO |
245 | -------- | 248 | -------- |
246 | linkperf:perf-stat[1], linkperf:perf-list[1] | 249 | linkperf:perf-stat[1], linkperf:perf-list[1] |
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index 7e1b1f2bb83c..ba03fd5d1a54 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt | |||
@@ -55,6 +55,9 @@ OPTIONS | |||
55 | --uid=:: | 55 | --uid=:: |
56 | Record events in threads owned by uid. Name or number. | 56 | Record events in threads owned by uid. Name or number. |
57 | 57 | ||
58 | --filter-pids=:: | ||
59 | Filter out events for these pids and for 'trace' itself (comma separated list). | ||
60 | |||
58 | -v:: | 61 | -v:: |
59 | --verbose=:: | 62 | --verbose=:: |
60 | Verbosity level. | 63 | Verbosity level. |
@@ -115,6 +118,9 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. | |||
115 | --syscalls:: | 118 | --syscalls:: |
116 | Trace system calls. This options is enabled by default. | 119 | Trace system calls. This options is enabled by default. |
117 | 120 | ||
121 | --event:: | ||
122 | Trace other events, see 'perf list' for a complete list. | ||
123 | |||
118 | PAGEFAULTS | 124 | PAGEFAULTS |
119 | ---------- | 125 | ---------- |
120 | 126 | ||
diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt index 1e8e400b4493..2b131776363e 100644 --- a/tools/perf/Documentation/perf.txt +++ b/tools/perf/Documentation/perf.txt | |||
@@ -13,11 +13,16 @@ SYNOPSIS | |||
13 | OPTIONS | 13 | OPTIONS |
14 | ------- | 14 | ------- |
15 | --debug:: | 15 | --debug:: |
16 | Setup debug variable (just verbose for now) in value | 16 | Setup debug variable (see list below) in value |
17 | range (0, 10). Use like: | 17 | range (0, 10). Use like: |
18 | --debug verbose # sets verbose = 1 | 18 | --debug verbose # sets verbose = 1 |
19 | --debug verbose=2 # sets verbose = 2 | 19 | --debug verbose=2 # sets verbose = 2 |
20 | 20 | ||
21 | List of debug variables allowed to set: | ||
22 | verbose - general debug messages | ||
23 | ordered-events - ordered events object debug messages | ||
24 | data-convert - data convert command debug messages | ||
25 | |||
21 | --buildid-dir:: | 26 | --buildid-dir:: |
22 | Setup buildid cache directory. It has higher priority than | 27 | Setup buildid cache directory. It has higher priority than |
23 | buildid.dir config file option. | 28 | buildid.dir config file option. |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index efc5158738f4..ec4c063ed9f3 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -68,7 +68,9 @@ include config/utilities.mak | |||
68 | # for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode | 68 | # for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode |
69 | # | 69 | # |
70 | # Define NO_ZLIB if you do not want to support compressed kernel modules | 70 | # Define NO_ZLIB if you do not want to support compressed kernel modules |
71 | 71 | # | |
72 | # Define NO_LIBBABELTRACE if you do not want libbabeltrace support | ||
73 | # for CTF data format. | ||
72 | 74 | ||
73 | ifeq ($(srctree),) | 75 | ifeq ($(srctree),) |
74 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | 76 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) |
diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c new file mode 100644 index 000000000000..9705ba7e4c16 --- /dev/null +++ b/tools/perf/builtin-data.c | |||
@@ -0,0 +1,119 @@ | |||
1 | #include <linux/compiler.h> | ||
2 | #include "builtin.h" | ||
3 | #include "perf.h" | ||
4 | #include "debug.h" | ||
5 | #include "parse-options.h" | ||
6 | #include "data-convert-bt.h" | ||
7 | |||
8 | typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix); | ||
9 | |||
10 | struct data_cmd { | ||
11 | const char *name; | ||
12 | const char *summary; | ||
13 | data_cmd_fn_t fn; | ||
14 | }; | ||
15 | |||
16 | static struct data_cmd data_cmds[]; | ||
17 | |||
18 | #define for_each_cmd(cmd) \ | ||
19 | for (cmd = data_cmds; cmd && cmd->name; cmd++) | ||
20 | |||
21 | static const struct option data_options[] = { | ||
22 | OPT_END() | ||
23 | }; | ||
24 | |||
25 | static const char * const data_usage[] = { | ||
26 | "perf data [<common options>] <command> [<options>]", | ||
27 | NULL | ||
28 | }; | ||
29 | |||
30 | static void print_usage(void) | ||
31 | { | ||
32 | struct data_cmd *cmd; | ||
33 | |||
34 | printf("Usage:\n"); | ||
35 | printf("\t%s\n\n", data_usage[0]); | ||
36 | printf("\tAvailable commands:\n"); | ||
37 | |||
38 | for_each_cmd(cmd) { | ||
39 | printf("\t %s\t- %s\n", cmd->name, cmd->summary); | ||
40 | } | ||
41 | |||
42 | printf("\n"); | ||
43 | } | ||
44 | |||
45 | static const char * const data_convert_usage[] = { | ||
46 | "perf data convert [<options>]", | ||
47 | NULL | ||
48 | }; | ||
49 | |||
50 | static int cmd_data_convert(int argc, const char **argv, | ||
51 | const char *prefix __maybe_unused) | ||
52 | { | ||
53 | const char *to_ctf = NULL; | ||
54 | const struct option options[] = { | ||
55 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), | ||
56 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | ||
57 | #ifdef HAVE_LIBBABELTRACE_SUPPORT | ||
58 | OPT_STRING(0, "to-ctf", &to_ctf, NULL, "Convert to CTF format"), | ||
59 | #endif | ||
60 | OPT_END() | ||
61 | }; | ||
62 | |||
63 | #ifndef HAVE_LIBBABELTRACE_SUPPORT | ||
64 | pr_err("No conversion support compiled in.\n"); | ||
65 | return -1; | ||
66 | #endif | ||
67 | |||
68 | argc = parse_options(argc, argv, options, | ||
69 | data_convert_usage, 0); | ||
70 | if (argc) { | ||
71 | usage_with_options(data_convert_usage, options); | ||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | if (to_ctf) { | ||
76 | #ifdef HAVE_LIBBABELTRACE_SUPPORT | ||
77 | return bt_convert__perf2ctf(input_name, to_ctf); | ||
78 | #else | ||
79 | pr_err("The libbabeltrace support is not compiled in.\n"); | ||
80 | return -1; | ||
81 | #endif | ||
82 | } | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static struct data_cmd data_cmds[] = { | ||
88 | { "convert", "converts data file between formats", cmd_data_convert }, | ||
89 | { NULL }, | ||
90 | }; | ||
91 | |||
92 | int cmd_data(int argc, const char **argv, const char *prefix) | ||
93 | { | ||
94 | struct data_cmd *cmd; | ||
95 | const char *cmdstr; | ||
96 | |||
97 | /* No command specified. */ | ||
98 | if (argc < 2) | ||
99 | goto usage; | ||
100 | |||
101 | argc = parse_options(argc, argv, data_options, data_usage, | ||
102 | PARSE_OPT_STOP_AT_NON_OPTION); | ||
103 | if (argc < 1) | ||
104 | goto usage; | ||
105 | |||
106 | cmdstr = argv[0]; | ||
107 | |||
108 | for_each_cmd(cmd) { | ||
109 | if (strcmp(cmd->name, cmdstr)) | ||
110 | continue; | ||
111 | |||
112 | return cmd->fn(argc, argv, prefix); | ||
113 | } | ||
114 | |||
115 | pr_err("Unknown command: %s\n", cmdstr); | ||
116 | usage: | ||
117 | print_usage(); | ||
118 | return -1; | ||
119 | } | ||
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d0d02a811ecd..4fdad06d37db 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -839,6 +839,8 @@ struct option __record_options[] = { | |||
839 | "use per-thread mmaps"), | 839 | "use per-thread mmaps"), |
840 | OPT_BOOLEAN('I', "intr-regs", &record.opts.sample_intr_regs, | 840 | OPT_BOOLEAN('I', "intr-regs", &record.opts.sample_intr_regs, |
841 | "Sample machine registers on interrupt"), | 841 | "Sample machine registers on interrupt"), |
842 | OPT_BOOLEAN(0, "running-time", &record.opts.running_time, | ||
843 | "Record running/enabled time of read (:S) events"), | ||
842 | OPT_END() | 844 | OPT_END() |
843 | }; | 845 | }; |
844 | 846 | ||
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 891c3930080e..7ce296618717 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -1473,9 +1473,9 @@ static int perf_sched__read_events(struct perf_sched *sched, | |||
1473 | goto out_delete; | 1473 | goto out_delete; |
1474 | } | 1474 | } |
1475 | 1475 | ||
1476 | sched->nr_events = session->stats.nr_events[0]; | 1476 | sched->nr_events = session->evlist->stats.nr_events[0]; |
1477 | sched->nr_lost_events = session->stats.total_lost; | 1477 | sched->nr_lost_events = session->evlist->stats.total_lost; |
1478 | sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST]; | 1478 | sched->nr_lost_chunks = session->evlist->stats.nr_events[PERF_RECORD_LOST]; |
1479 | } | 1479 | } |
1480 | 1480 | ||
1481 | if (psession) | 1481 | if (psession) |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c4c7eac69de4..5fb8723c7128 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -716,7 +716,7 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
716 | 716 | ||
717 | if (!machine) { | 717 | if (!machine) { |
718 | pr_err("%u unprocessable samples recorded.\r", | 718 | pr_err("%u unprocessable samples recorded.\r", |
719 | top->session->stats.nr_unprocessable_samples++); | 719 | top->session->evlist->stats.nr_unprocessable_samples++); |
720 | return; | 720 | return; |
721 | } | 721 | } |
722 | 722 | ||
@@ -856,7 +856,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
856 | hists__inc_nr_events(evsel__hists(evsel), event->header.type); | 856 | hists__inc_nr_events(evsel__hists(evsel), event->header.type); |
857 | machine__process_event(machine, event, &sample); | 857 | machine__process_event(machine, event, &sample); |
858 | } else | 858 | } else |
859 | ++session->stats.nr_unknown_events; | 859 | ++session->evlist->stats.nr_unknown_events; |
860 | next_event: | 860 | next_event: |
861 | perf_evlist__mmap_consume(top->evlist, idx); | 861 | perf_evlist__mmap_consume(top->evlist, idx); |
862 | } | 862 | } |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index b1c1df9bfb26..5cd8497445fe 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -1229,6 +1229,10 @@ struct trace { | |||
1229 | const char *last_vfs_getname; | 1229 | const char *last_vfs_getname; |
1230 | struct intlist *tid_list; | 1230 | struct intlist *tid_list; |
1231 | struct intlist *pid_list; | 1231 | struct intlist *pid_list; |
1232 | struct { | ||
1233 | size_t nr; | ||
1234 | pid_t *entries; | ||
1235 | } filter_pids; | ||
1232 | double duration_filter; | 1236 | double duration_filter; |
1233 | double runtime_ms; | 1237 | double runtime_ms; |
1234 | struct { | 1238 | struct { |
@@ -1840,7 +1844,11 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, | |||
1840 | { | 1844 | { |
1841 | trace__printf_interrupted_entry(trace, sample); | 1845 | trace__printf_interrupted_entry(trace, sample); |
1842 | trace__fprintf_tstamp(trace, sample->time, trace->output); | 1846 | trace__fprintf_tstamp(trace, sample->time, trace->output); |
1843 | fprintf(trace->output, "(%9.9s): %s:", " ", evsel->name); | 1847 | |
1848 | if (trace->trace_syscalls) | ||
1849 | fprintf(trace->output, "( ): "); | ||
1850 | |||
1851 | fprintf(trace->output, "%s:", evsel->name); | ||
1844 | 1852 | ||
1845 | if (evsel->tp_format) { | 1853 | if (evsel->tp_format) { |
1846 | event_format__fprintf(evsel->tp_format, sample->cpu, | 1854 | event_format__fprintf(evsel->tp_format, sample->cpu, |
@@ -2084,10 +2092,39 @@ static int perf_evlist__add_pgfault(struct perf_evlist *evlist, | |||
2084 | return 0; | 2092 | return 0; |
2085 | } | 2093 | } |
2086 | 2094 | ||
2095 | static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample) | ||
2096 | { | ||
2097 | const u32 type = event->header.type; | ||
2098 | struct perf_evsel *evsel; | ||
2099 | |||
2100 | if (!trace->full_time && trace->base_time == 0) | ||
2101 | trace->base_time = sample->time; | ||
2102 | |||
2103 | if (type != PERF_RECORD_SAMPLE) { | ||
2104 | trace__process_event(trace, trace->host, event, sample); | ||
2105 | return; | ||
2106 | } | ||
2107 | |||
2108 | evsel = perf_evlist__id2evsel(trace->evlist, sample->id); | ||
2109 | if (evsel == NULL) { | ||
2110 | fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id); | ||
2111 | return; | ||
2112 | } | ||
2113 | |||
2114 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && | ||
2115 | sample->raw_data == NULL) { | ||
2116 | fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", | ||
2117 | perf_evsel__name(evsel), sample->tid, | ||
2118 | sample->cpu, sample->raw_size); | ||
2119 | } else { | ||
2120 | tracepoint_handler handler = evsel->handler; | ||
2121 | handler(trace, evsel, event, sample); | ||
2122 | } | ||
2123 | } | ||
2124 | |||
2087 | static int trace__run(struct trace *trace, int argc, const char **argv) | 2125 | static int trace__run(struct trace *trace, int argc, const char **argv) |
2088 | { | 2126 | { |
2089 | struct perf_evlist *evlist = trace->evlist; | 2127 | struct perf_evlist *evlist = trace->evlist; |
2090 | struct perf_evsel *evsel; | ||
2091 | int err = -1, i; | 2128 | int err = -1, i; |
2092 | unsigned long before; | 2129 | unsigned long before; |
2093 | const bool forks = argc > 0; | 2130 | const bool forks = argc > 0; |
@@ -2147,6 +2184,22 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
2147 | if (err < 0) | 2184 | if (err < 0) |
2148 | goto out_error_open; | 2185 | goto out_error_open; |
2149 | 2186 | ||
2187 | /* | ||
2188 | * Better not use !target__has_task() here because we need to cover the | ||
2189 | * case where no threads were specified in the command line, but a | ||
2190 | * workload was, and in that case we will fill in the thread_map when | ||
2191 | * we fork the workload in perf_evlist__prepare_workload. | ||
2192 | */ | ||
2193 | if (trace->filter_pids.nr > 0) | ||
2194 | err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries); | ||
2195 | else if (evlist->threads->map[0] == -1) | ||
2196 | err = perf_evlist__set_filter_pid(evlist, getpid()); | ||
2197 | |||
2198 | if (err < 0) { | ||
2199 | printf("err=%d,%s\n", -err, strerror(-err)); | ||
2200 | exit(1); | ||
2201 | } | ||
2202 | |||
2150 | err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false); | 2203 | err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false); |
2151 | if (err < 0) | 2204 | if (err < 0) |
2152 | goto out_error_mmap; | 2205 | goto out_error_mmap; |
@@ -2166,8 +2219,6 @@ again: | |||
2166 | union perf_event *event; | 2219 | union perf_event *event; |
2167 | 2220 | ||
2168 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { | 2221 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { |
2169 | const u32 type = event->header.type; | ||
2170 | tracepoint_handler handler; | ||
2171 | struct perf_sample sample; | 2222 | struct perf_sample sample; |
2172 | 2223 | ||
2173 | ++trace->nr_events; | 2224 | ++trace->nr_events; |
@@ -2178,30 +2229,7 @@ again: | |||
2178 | goto next_event; | 2229 | goto next_event; |
2179 | } | 2230 | } |
2180 | 2231 | ||
2181 | if (!trace->full_time && trace->base_time == 0) | 2232 | trace__handle_event(trace, event, &sample); |
2182 | trace->base_time = sample.time; | ||
2183 | |||
2184 | if (type != PERF_RECORD_SAMPLE) { | ||
2185 | trace__process_event(trace, trace->host, event, &sample); | ||
2186 | continue; | ||
2187 | } | ||
2188 | |||
2189 | evsel = perf_evlist__id2evsel(evlist, sample.id); | ||
2190 | if (evsel == NULL) { | ||
2191 | fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id); | ||
2192 | goto next_event; | ||
2193 | } | ||
2194 | |||
2195 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && | ||
2196 | sample.raw_data == NULL) { | ||
2197 | fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", | ||
2198 | perf_evsel__name(evsel), sample.tid, | ||
2199 | sample.cpu, sample.raw_size); | ||
2200 | goto next_event; | ||
2201 | } | ||
2202 | |||
2203 | handler = evsel->handler; | ||
2204 | handler(trace, evsel, event, &sample); | ||
2205 | next_event: | 2233 | next_event: |
2206 | perf_evlist__mmap_consume(evlist, i); | 2234 | perf_evlist__mmap_consume(evlist, i); |
2207 | 2235 | ||
@@ -2478,6 +2506,38 @@ static int trace__set_duration(const struct option *opt, const char *str, | |||
2478 | return 0; | 2506 | return 0; |
2479 | } | 2507 | } |
2480 | 2508 | ||
2509 | static int trace__set_filter_pids(const struct option *opt, const char *str, | ||
2510 | int unset __maybe_unused) | ||
2511 | { | ||
2512 | int ret = -1; | ||
2513 | size_t i; | ||
2514 | struct trace *trace = opt->value; | ||
2515 | /* | ||
2516 | * FIXME: introduce a intarray class, plain parse csv and create a | ||
2517 | * { int nr, int entries[] } struct... | ||
2518 | */ | ||
2519 | struct intlist *list = intlist__new(str); | ||
2520 | |||
2521 | if (list == NULL) | ||
2522 | return -1; | ||
2523 | |||
2524 | i = trace->filter_pids.nr = intlist__nr_entries(list) + 1; | ||
2525 | trace->filter_pids.entries = calloc(i, sizeof(pid_t)); | ||
2526 | |||
2527 | if (trace->filter_pids.entries == NULL) | ||
2528 | goto out; | ||
2529 | |||
2530 | trace->filter_pids.entries[0] = getpid(); | ||
2531 | |||
2532 | for (i = 1; i < trace->filter_pids.nr; ++i) | ||
2533 | trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i; | ||
2534 | |||
2535 | intlist__delete(list); | ||
2536 | ret = 0; | ||
2537 | out: | ||
2538 | return ret; | ||
2539 | } | ||
2540 | |||
2481 | static int trace__open_output(struct trace *trace, const char *filename) | 2541 | static int trace__open_output(struct trace *trace, const char *filename) |
2482 | { | 2542 | { |
2483 | struct stat st; | 2543 | struct stat st; |
@@ -2568,6 +2628,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
2568 | "trace events on existing process id"), | 2628 | "trace events on existing process id"), |
2569 | OPT_STRING('t', "tid", &trace.opts.target.tid, "tid", | 2629 | OPT_STRING('t', "tid", &trace.opts.target.tid, "tid", |
2570 | "trace events on existing thread id"), | 2630 | "trace events on existing thread id"), |
2631 | OPT_CALLBACK(0, "filter-pids", &trace, "float", | ||
2632 | "show only events with duration > N.M ms", trace__set_filter_pids), | ||
2571 | OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide, | 2633 | OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide, |
2572 | "system-wide collection from all CPUs"), | 2634 | "system-wide collection from all CPUs"), |
2573 | OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu", | 2635 | OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu", |
@@ -2598,6 +2660,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
2598 | int err; | 2660 | int err; |
2599 | char bf[BUFSIZ]; | 2661 | char bf[BUFSIZ]; |
2600 | 2662 | ||
2663 | signal(SIGSEGV, sighandler_dump_stack); | ||
2664 | signal(SIGFPE, sighandler_dump_stack); | ||
2665 | |||
2601 | trace.evlist = perf_evlist__new(); | 2666 | trace.evlist = perf_evlist__new(); |
2602 | if (trace.evlist == NULL) | 2667 | if (trace.evlist == NULL) |
2603 | return -ENOMEM; | 2668 | return -ENOMEM; |
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index b210d62907e4..3688ad29085f 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h | |||
@@ -37,6 +37,7 @@ extern int cmd_test(int argc, const char **argv, const char *prefix); | |||
37 | extern int cmd_trace(int argc, const char **argv, const char *prefix); | 37 | extern int cmd_trace(int argc, const char **argv, const char *prefix); |
38 | extern int cmd_inject(int argc, const char **argv, const char *prefix); | 38 | extern int cmd_inject(int argc, const char **argv, const char *prefix); |
39 | extern int cmd_mem(int argc, const char **argv, const char *prefix); | 39 | extern int cmd_mem(int argc, const char **argv, const char *prefix); |
40 | extern int cmd_data(int argc, const char **argv, const char *prefix); | ||
40 | 41 | ||
41 | extern int find_scripts(char **scripts_array, char **scripts_path_array); | 42 | extern int find_scripts(char **scripts_array, char **scripts_path_array); |
42 | #endif | 43 | #endif |
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index 0906fc401c52..00fcaf8a5b8d 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt | |||
@@ -7,6 +7,7 @@ perf-archive mainporcelain common | |||
7 | perf-bench mainporcelain common | 7 | perf-bench mainporcelain common |
8 | perf-buildid-cache mainporcelain common | 8 | perf-buildid-cache mainporcelain common |
9 | perf-buildid-list mainporcelain common | 9 | perf-buildid-list mainporcelain common |
10 | perf-data mainporcelain common | ||
10 | perf-diff mainporcelain common | 11 | perf-diff mainporcelain common |
11 | perf-evlist mainporcelain common | 12 | perf-evlist mainporcelain common |
12 | perf-inject mainporcelain common | 13 | perf-inject mainporcelain common |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index b97a7b903a23..c3570b5f3bf3 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -96,6 +96,17 @@ ifndef NO_LIBELF | |||
96 | FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw | 96 | FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw |
97 | endif | 97 | endif |
98 | 98 | ||
99 | ifndef NO_LIBBABELTRACE | ||
100 | # for linking with debug library, run like: | ||
101 | # make DEBUG=1 LIBBABELTRACE_DIR=/opt/libbabeltrace/ | ||
102 | ifdef LIBBABELTRACE_DIR | ||
103 | LIBBABELTRACE_CFLAGS := -I$(LIBBABELTRACE_DIR)/include | ||
104 | LIBBABELTRACE_LDFLAGS := -L$(LIBBABELTRACE_DIR)/lib | ||
105 | endif | ||
106 | FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS) | ||
107 | FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf | ||
108 | endif | ||
109 | |||
99 | # include ARCH specific config | 110 | # include ARCH specific config |
100 | -include $(src-perf)/arch/$(ARCH)/Makefile | 111 | -include $(src-perf)/arch/$(ARCH)/Makefile |
101 | 112 | ||
@@ -216,6 +227,7 @@ CORE_FEATURE_TESTS = \ | |||
216 | stackprotector-all \ | 227 | stackprotector-all \ |
217 | timerfd \ | 228 | timerfd \ |
218 | libdw-dwarf-unwind \ | 229 | libdw-dwarf-unwind \ |
230 | libbabeltrace \ | ||
219 | zlib | 231 | zlib |
220 | 232 | ||
221 | LIB_FEATURE_TESTS = \ | 233 | LIB_FEATURE_TESTS = \ |
@@ -231,6 +243,7 @@ LIB_FEATURE_TESTS = \ | |||
231 | libslang \ | 243 | libslang \ |
232 | libunwind \ | 244 | libunwind \ |
233 | libdw-dwarf-unwind \ | 245 | libdw-dwarf-unwind \ |
246 | libbabeltrace \ | ||
234 | zlib | 247 | zlib |
235 | 248 | ||
236 | VF_FEATURE_TESTS = \ | 249 | VF_FEATURE_TESTS = \ |
@@ -692,6 +705,18 @@ else | |||
692 | NO_PERF_READ_VDSOX32 := 1 | 705 | NO_PERF_READ_VDSOX32 := 1 |
693 | endif | 706 | endif |
694 | 707 | ||
708 | ifndef NO_LIBBABELTRACE | ||
709 | ifeq ($(feature-libbabeltrace), 0) | ||
710 | msg := $(warning No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-devel/libbabeltrace-ctf-dev); | ||
711 | NO_LIBBABELTRACE := 1 | ||
712 | else | ||
713 | CFLAGS += -DHAVE_LIBBABELTRACE_SUPPORT $(LIBBABELTRACE_CFLAGS) | ||
714 | LDFLAGS += $(LIBBABELTRACE_LDFLAGS) | ||
715 | EXTLIBS += -lbabeltrace-ctf | ||
716 | $(call detected,CONFIG_LIBBABELTRACE) | ||
717 | endif | ||
718 | endif | ||
719 | |||
695 | # Among the variables below, these: | 720 | # Among the variables below, these: |
696 | # perfexecdir | 721 | # perfexecdir |
697 | # template_dir | 722 | # template_dir |
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index b32ff3372514..70c9aebe9da3 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile | |||
@@ -29,6 +29,7 @@ FILES= \ | |||
29 | test-stackprotector-all.bin \ | 29 | test-stackprotector-all.bin \ |
30 | test-timerfd.bin \ | 30 | test-timerfd.bin \ |
31 | test-libdw-dwarf-unwind.bin \ | 31 | test-libdw-dwarf-unwind.bin \ |
32 | test-libbabeltrace.bin \ | ||
32 | test-compile-32.bin \ | 33 | test-compile-32.bin \ |
33 | test-compile-x32.bin \ | 34 | test-compile-x32.bin \ |
34 | test-zlib.bin | 35 | test-zlib.bin |
@@ -43,7 +44,7 @@ BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS) | |||
43 | ############################### | 44 | ############################### |
44 | 45 | ||
45 | test-all.bin: | 46 | test-all.bin: |
46 | $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz | 47 | $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -lbabeltrace |
47 | 48 | ||
48 | test-hello.bin: | 49 | test-hello.bin: |
49 | $(BUILD) | 50 | $(BUILD) |
@@ -133,7 +134,10 @@ test-timerfd.bin: | |||
133 | $(BUILD) | 134 | $(BUILD) |
134 | 135 | ||
135 | test-libdw-dwarf-unwind.bin: | 136 | test-libdw-dwarf-unwind.bin: |
136 | $(BUILD) | 137 | $(BUILD) # -ldw provided by $(FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind) |
138 | |||
139 | test-libbabeltrace.bin: | ||
140 | $(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace) | ||
137 | 141 | ||
138 | test-sync-compare-and-swap.bin: | 142 | test-sync-compare-and-swap.bin: |
139 | $(BUILD) -Werror | 143 | $(BUILD) -Werror |
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c index 6d4d09323922..1ffc3da5ca10 100644 --- a/tools/perf/config/feature-checks/test-all.c +++ b/tools/perf/config/feature-checks/test-all.c | |||
@@ -101,6 +101,10 @@ | |||
101 | # include "test-pthread_attr_setaffinity_np.c" | 101 | # include "test-pthread_attr_setaffinity_np.c" |
102 | #undef main | 102 | #undef main |
103 | 103 | ||
104 | #define main main_test_libbabeltrace | ||
105 | # include "test-libbabeltrace.c" | ||
106 | #undef main | ||
107 | |||
104 | int main(int argc, char *argv[]) | 108 | int main(int argc, char *argv[]) |
105 | { | 109 | { |
106 | main_test_libpython(); | 110 | main_test_libpython(); |
@@ -126,6 +130,7 @@ int main(int argc, char *argv[]) | |||
126 | main_test_sync_compare_and_swap(argc, argv); | 130 | main_test_sync_compare_and_swap(argc, argv); |
127 | main_test_zlib(); | 131 | main_test_zlib(); |
128 | main_test_pthread_attr_setaffinity_np(); | 132 | main_test_pthread_attr_setaffinity_np(); |
133 | main_test_libbabeltrace(); | ||
129 | 134 | ||
130 | return 0; | 135 | return 0; |
131 | } | 136 | } |
diff --git a/tools/perf/config/feature-checks/test-libbabeltrace.c b/tools/perf/config/feature-checks/test-libbabeltrace.c new file mode 100644 index 000000000000..3b7dd68a4d52 --- /dev/null +++ b/tools/perf/config/feature-checks/test-libbabeltrace.c | |||
@@ -0,0 +1,8 @@ | |||
1 | |||
2 | #include <babeltrace/ctf-writer/writer.h> | ||
3 | |||
4 | int main(void) | ||
5 | { | ||
6 | bt_ctf_stream_class_get_packet_context_type((void *) 0); | ||
7 | return 0; | ||
8 | } | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 3700a7faca6c..f3c66b81c6be 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -62,6 +62,7 @@ static struct cmd_struct commands[] = { | |||
62 | #endif | 62 | #endif |
63 | { "inject", cmd_inject, 0 }, | 63 | { "inject", cmd_inject, 0 }, |
64 | { "mem", cmd_mem, 0 }, | 64 | { "mem", cmd_mem, 0 }, |
65 | { "data", cmd_data, 0 }, | ||
65 | }; | 66 | }; |
66 | 67 | ||
67 | struct pager_config { | 68 | struct pager_config { |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 1dabb8553499..1caa70a4a9e1 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -53,6 +53,7 @@ struct record_opts { | |||
53 | bool sample_time; | 53 | bool sample_time; |
54 | bool period; | 54 | bool period; |
55 | bool sample_intr_regs; | 55 | bool sample_intr_regs; |
56 | bool running_time; | ||
56 | unsigned int freq; | 57 | unsigned int freq; |
57 | unsigned int mmap_pages; | 58 | unsigned int mmap_pages; |
58 | unsigned int user_freq; | 59 | unsigned int user_freq; |
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 32f9327b1a97..a2c8047d25f7 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
@@ -88,6 +88,8 @@ libperf-$(CONFIG_DWARF) += dwarf-aux.o | |||
88 | libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o | 88 | libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o |
89 | libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o | 89 | libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o |
90 | 90 | ||
91 | libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o | ||
92 | |||
91 | libperf-y += scripting-engines/ | 93 | libperf-y += scripting-engines/ |
92 | 94 | ||
93 | libperf-$(CONFIG_PERF_REGS) += perf_regs.o | 95 | libperf-$(CONFIG_PERF_REGS) += perf_regs.o |
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c new file mode 100644 index 000000000000..e372e03ff480 --- /dev/null +++ b/tools/perf/util/data-convert-bt.c | |||
@@ -0,0 +1,614 @@ | |||
1 | /* | ||
2 | * CTF writing support via babeltrace. | ||
3 | * | ||
4 | * Copyright (C) 2014, Jiri Olsa <jolsa@redhat.com> | ||
5 | * Copyright (C) 2014, Sebastian Andrzej Siewior <bigeasy@linutronix.de> | ||
6 | * | ||
7 | * Released under the GPL v2. (and only v2, not any later version) | ||
8 | */ | ||
9 | |||
10 | #include <linux/compiler.h> | ||
11 | #include <babeltrace/ctf-writer/writer.h> | ||
12 | #include <babeltrace/ctf-writer/clock.h> | ||
13 | #include <babeltrace/ctf-writer/stream.h> | ||
14 | #include <babeltrace/ctf-writer/event.h> | ||
15 | #include <babeltrace/ctf-writer/event-types.h> | ||
16 | #include <babeltrace/ctf-writer/event-fields.h> | ||
17 | #include <babeltrace/ctf/events.h> | ||
18 | #include <traceevent/event-parse.h> | ||
19 | #include "asm/bug.h" | ||
20 | #include "data-convert-bt.h" | ||
21 | #include "session.h" | ||
22 | #include "util.h" | ||
23 | #include "debug.h" | ||
24 | #include "tool.h" | ||
25 | #include "evlist.h" | ||
26 | #include "evsel.h" | ||
27 | #include "machine.h" | ||
28 | |||
29 | #define pr_N(n, fmt, ...) \ | ||
30 | eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__) | ||
31 | |||
32 | #define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__) | ||
33 | #define pr2(fmt, ...) pr_N(2, pr_fmt(fmt), ##__VA_ARGS__) | ||
34 | |||
35 | #define pr_time2(t, fmt, ...) pr_time_N(2, debug_data_convert, t, pr_fmt(fmt), ##__VA_ARGS__) | ||
36 | |||
37 | struct evsel_priv { | ||
38 | struct bt_ctf_event_class *event_class; | ||
39 | }; | ||
40 | |||
41 | struct ctf_writer { | ||
42 | /* writer primitives */ | ||
43 | struct bt_ctf_writer *writer; | ||
44 | struct bt_ctf_stream *stream; | ||
45 | struct bt_ctf_stream_class *stream_class; | ||
46 | struct bt_ctf_clock *clock; | ||
47 | |||
48 | /* data types */ | ||
49 | union { | ||
50 | struct { | ||
51 | struct bt_ctf_field_type *s64; | ||
52 | struct bt_ctf_field_type *u64; | ||
53 | struct bt_ctf_field_type *s32; | ||
54 | struct bt_ctf_field_type *u32; | ||
55 | struct bt_ctf_field_type *string; | ||
56 | struct bt_ctf_field_type *u64_hex; | ||
57 | }; | ||
58 | struct bt_ctf_field_type *array[6]; | ||
59 | } data; | ||
60 | }; | ||
61 | |||
62 | struct convert { | ||
63 | struct perf_tool tool; | ||
64 | struct ctf_writer writer; | ||
65 | |||
66 | u64 events_size; | ||
67 | u64 events_count; | ||
68 | }; | ||
69 | |||
70 | static int value_set(struct bt_ctf_field_type *type, | ||
71 | struct bt_ctf_event *event, | ||
72 | const char *name, u64 val) | ||
73 | { | ||
74 | struct bt_ctf_field *field; | ||
75 | bool sign = bt_ctf_field_type_integer_get_signed(type); | ||
76 | int ret; | ||
77 | |||
78 | field = bt_ctf_field_create(type); | ||
79 | if (!field) { | ||
80 | pr_err("failed to create a field %s\n", name); | ||
81 | return -1; | ||
82 | } | ||
83 | |||
84 | if (sign) { | ||
85 | ret = bt_ctf_field_signed_integer_set_value(field, val); | ||
86 | if (ret) { | ||
87 | pr_err("failed to set field value %s\n", name); | ||
88 | goto err; | ||
89 | } | ||
90 | } else { | ||
91 | ret = bt_ctf_field_unsigned_integer_set_value(field, val); | ||
92 | if (ret) { | ||
93 | pr_err("failed to set field value %s\n", name); | ||
94 | goto err; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | ret = bt_ctf_event_set_payload(event, name, field); | ||
99 | if (ret) { | ||
100 | pr_err("failed to set payload %s\n", name); | ||
101 | goto err; | ||
102 | } | ||
103 | |||
104 | pr2(" SET [%s = %" PRIu64 "]\n", name, val); | ||
105 | |||
106 | err: | ||
107 | bt_ctf_field_put(field); | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | #define __FUNC_VALUE_SET(_name, _val_type) \ | ||
112 | static __maybe_unused int value_set_##_name(struct ctf_writer *cw, \ | ||
113 | struct bt_ctf_event *event, \ | ||
114 | const char *name, \ | ||
115 | _val_type val) \ | ||
116 | { \ | ||
117 | struct bt_ctf_field_type *type = cw->data._name; \ | ||
118 | return value_set(type, event, name, (u64) val); \ | ||
119 | } | ||
120 | |||
121 | #define FUNC_VALUE_SET(_name) __FUNC_VALUE_SET(_name, _name) | ||
122 | |||
123 | FUNC_VALUE_SET(s32) | ||
124 | FUNC_VALUE_SET(u32) | ||
125 | FUNC_VALUE_SET(s64) | ||
126 | FUNC_VALUE_SET(u64) | ||
127 | __FUNC_VALUE_SET(u64_hex, u64) | ||
128 | |||
129 | static int add_generic_values(struct ctf_writer *cw, | ||
130 | struct bt_ctf_event *event, | ||
131 | struct perf_evsel *evsel, | ||
132 | struct perf_sample *sample) | ||
133 | { | ||
134 | u64 type = evsel->attr.sample_type; | ||
135 | int ret; | ||
136 | |||
137 | /* | ||
138 | * missing: | ||
139 | * PERF_SAMPLE_TIME - not needed as we have it in | ||
140 | * ctf event header | ||
141 | * PERF_SAMPLE_READ - TODO | ||
142 | * PERF_SAMPLE_CALLCHAIN - TODO | ||
143 | * PERF_SAMPLE_RAW - tracepoint fields are handled separately | ||
144 | * PERF_SAMPLE_BRANCH_STACK - TODO | ||
145 | * PERF_SAMPLE_REGS_USER - TODO | ||
146 | * PERF_SAMPLE_STACK_USER - TODO | ||
147 | */ | ||
148 | |||
149 | if (type & PERF_SAMPLE_IP) { | ||
150 | ret = value_set_u64_hex(cw, event, "perf_ip", sample->ip); | ||
151 | if (ret) | ||
152 | return -1; | ||
153 | } | ||
154 | |||
155 | if (type & PERF_SAMPLE_TID) { | ||
156 | ret = value_set_s32(cw, event, "perf_tid", sample->tid); | ||
157 | if (ret) | ||
158 | return -1; | ||
159 | |||
160 | ret = value_set_s32(cw, event, "perf_pid", sample->pid); | ||
161 | if (ret) | ||
162 | return -1; | ||
163 | } | ||
164 | |||
165 | if ((type & PERF_SAMPLE_ID) || | ||
166 | (type & PERF_SAMPLE_IDENTIFIER)) { | ||
167 | ret = value_set_u64(cw, event, "perf_id", sample->id); | ||
168 | if (ret) | ||
169 | return -1; | ||
170 | } | ||
171 | |||
172 | if (type & PERF_SAMPLE_STREAM_ID) { | ||
173 | ret = value_set_u64(cw, event, "perf_stream_id", sample->stream_id); | ||
174 | if (ret) | ||
175 | return -1; | ||
176 | } | ||
177 | |||
178 | if (type & PERF_SAMPLE_CPU) { | ||
179 | ret = value_set_u32(cw, event, "perf_cpu", sample->cpu); | ||
180 | if (ret) | ||
181 | return -1; | ||
182 | } | ||
183 | |||
184 | if (type & PERF_SAMPLE_PERIOD) { | ||
185 | ret = value_set_u64(cw, event, "perf_period", sample->period); | ||
186 | if (ret) | ||
187 | return -1; | ||
188 | } | ||
189 | |||
190 | if (type & PERF_SAMPLE_WEIGHT) { | ||
191 | ret = value_set_u64(cw, event, "perf_weight", sample->weight); | ||
192 | if (ret) | ||
193 | return -1; | ||
194 | } | ||
195 | |||
196 | if (type & PERF_SAMPLE_DATA_SRC) { | ||
197 | ret = value_set_u64(cw, event, "perf_data_src", | ||
198 | sample->data_src); | ||
199 | if (ret) | ||
200 | return -1; | ||
201 | } | ||
202 | |||
203 | if (type & PERF_SAMPLE_TRANSACTION) { | ||
204 | ret = value_set_u64(cw, event, "perf_transaction", | ||
205 | sample->transaction); | ||
206 | if (ret) | ||
207 | return -1; | ||
208 | } | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static int process_sample_event(struct perf_tool *tool, | ||
214 | union perf_event *_event __maybe_unused, | ||
215 | struct perf_sample *sample, | ||
216 | struct perf_evsel *evsel, | ||
217 | struct machine *machine __maybe_unused) | ||
218 | { | ||
219 | struct convert *c = container_of(tool, struct convert, tool); | ||
220 | struct evsel_priv *priv = evsel->priv; | ||
221 | struct ctf_writer *cw = &c->writer; | ||
222 | struct bt_ctf_event_class *event_class; | ||
223 | struct bt_ctf_event *event; | ||
224 | int ret; | ||
225 | |||
226 | if (WARN_ONCE(!priv, "Failed to setup all events.\n")) | ||
227 | return 0; | ||
228 | |||
229 | event_class = priv->event_class; | ||
230 | |||
231 | /* update stats */ | ||
232 | c->events_count++; | ||
233 | c->events_size += _event->header.size; | ||
234 | |||
235 | pr_time2(sample->time, "sample %" PRIu64 "\n", c->events_count); | ||
236 | |||
237 | event = bt_ctf_event_create(event_class); | ||
238 | if (!event) { | ||
239 | pr_err("Failed to create an CTF event\n"); | ||
240 | return -1; | ||
241 | } | ||
242 | |||
243 | bt_ctf_clock_set_time(cw->clock, sample->time); | ||
244 | |||
245 | ret = add_generic_values(cw, event, evsel, sample); | ||
246 | if (ret) | ||
247 | return -1; | ||
248 | |||
249 | bt_ctf_stream_append_event(cw->stream, event); | ||
250 | bt_ctf_event_put(event); | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, | ||
255 | struct bt_ctf_event_class *event_class) | ||
256 | { | ||
257 | u64 type = evsel->attr.sample_type; | ||
258 | |||
259 | /* | ||
260 | * missing: | ||
261 | * PERF_SAMPLE_TIME - not needed as we have it in | ||
262 | * ctf event header | ||
263 | * PERF_SAMPLE_READ - TODO | ||
264 | * PERF_SAMPLE_CALLCHAIN - TODO | ||
265 | * PERF_SAMPLE_RAW - tracepoint fields are handled separately | ||
266 | * PERF_SAMPLE_BRANCH_STACK - TODO | ||
267 | * PERF_SAMPLE_REGS_USER - TODO | ||
268 | * PERF_SAMPLE_STACK_USER - TODO | ||
269 | */ | ||
270 | |||
271 | #define ADD_FIELD(cl, t, n) \ | ||
272 | do { \ | ||
273 | pr2(" field '%s'\n", n); \ | ||
274 | if (bt_ctf_event_class_add_field(cl, t, n)) { \ | ||
275 | pr_err("Failed to add field '%s;\n", n); \ | ||
276 | return -1; \ | ||
277 | } \ | ||
278 | } while (0) | ||
279 | |||
280 | if (type & PERF_SAMPLE_IP) | ||
281 | ADD_FIELD(event_class, cw->data.u64_hex, "perf_ip"); | ||
282 | |||
283 | if (type & PERF_SAMPLE_TID) { | ||
284 | ADD_FIELD(event_class, cw->data.s32, "perf_tid"); | ||
285 | ADD_FIELD(event_class, cw->data.s32, "perf_pid"); | ||
286 | } | ||
287 | |||
288 | if ((type & PERF_SAMPLE_ID) || | ||
289 | (type & PERF_SAMPLE_IDENTIFIER)) | ||
290 | ADD_FIELD(event_class, cw->data.u64, "perf_id"); | ||
291 | |||
292 | if (type & PERF_SAMPLE_STREAM_ID) | ||
293 | ADD_FIELD(event_class, cw->data.u64, "perf_stream_id"); | ||
294 | |||
295 | if (type & PERF_SAMPLE_CPU) | ||
296 | ADD_FIELD(event_class, cw->data.u32, "perf_cpu"); | ||
297 | |||
298 | if (type & PERF_SAMPLE_PERIOD) | ||
299 | ADD_FIELD(event_class, cw->data.u64, "perf_period"); | ||
300 | |||
301 | if (type & PERF_SAMPLE_WEIGHT) | ||
302 | ADD_FIELD(event_class, cw->data.u64, "perf_weight"); | ||
303 | |||
304 | if (type & PERF_SAMPLE_DATA_SRC) | ||
305 | ADD_FIELD(event_class, cw->data.u64, "perf_data_src"); | ||
306 | |||
307 | if (type & PERF_SAMPLE_TRANSACTION) | ||
308 | ADD_FIELD(event_class, cw->data.u64, "perf_transaction"); | ||
309 | |||
310 | #undef ADD_FIELD | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel) | ||
315 | { | ||
316 | struct bt_ctf_event_class *event_class; | ||
317 | struct evsel_priv *priv; | ||
318 | const char *name = perf_evsel__name(evsel); | ||
319 | int ret; | ||
320 | |||
321 | pr("Adding event '%s' (type %d)\n", name, evsel->attr.type); | ||
322 | |||
323 | event_class = bt_ctf_event_class_create(name); | ||
324 | if (!event_class) | ||
325 | return -1; | ||
326 | |||
327 | ret = add_generic_types(cw, evsel, event_class); | ||
328 | if (ret) | ||
329 | goto err; | ||
330 | |||
331 | ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class); | ||
332 | if (ret) { | ||
333 | pr("Failed to add event class into stream.\n"); | ||
334 | goto err; | ||
335 | } | ||
336 | |||
337 | priv = malloc(sizeof(*priv)); | ||
338 | if (!priv) | ||
339 | goto err; | ||
340 | |||
341 | priv->event_class = event_class; | ||
342 | evsel->priv = priv; | ||
343 | return 0; | ||
344 | |||
345 | err: | ||
346 | bt_ctf_event_class_put(event_class); | ||
347 | pr_err("Failed to add event '%s'.\n", name); | ||
348 | return -1; | ||
349 | } | ||
350 | |||
351 | static int setup_events(struct ctf_writer *cw, struct perf_session *session) | ||
352 | { | ||
353 | struct perf_evlist *evlist = session->evlist; | ||
354 | struct perf_evsel *evsel; | ||
355 | int ret; | ||
356 | |||
357 | evlist__for_each(evlist, evsel) { | ||
358 | ret = add_event(cw, evsel); | ||
359 | if (ret) | ||
360 | return ret; | ||
361 | } | ||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | static int ctf_writer__setup_env(struct ctf_writer *cw, | ||
366 | struct perf_session *session) | ||
367 | { | ||
368 | struct perf_header *header = &session->header; | ||
369 | struct bt_ctf_writer *writer = cw->writer; | ||
370 | |||
371 | #define ADD(__n, __v) \ | ||
372 | do { \ | ||
373 | if (bt_ctf_writer_add_environment_field(writer, __n, __v)) \ | ||
374 | return -1; \ | ||
375 | } while (0) | ||
376 | |||
377 | ADD("host", header->env.hostname); | ||
378 | ADD("sysname", "Linux"); | ||
379 | ADD("release", header->env.os_release); | ||
380 | ADD("version", header->env.version); | ||
381 | ADD("machine", header->env.arch); | ||
382 | ADD("domain", "kernel"); | ||
383 | ADD("tracer_name", "perf"); | ||
384 | |||
385 | #undef ADD | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static int ctf_writer__setup_clock(struct ctf_writer *cw) | ||
390 | { | ||
391 | struct bt_ctf_clock *clock = cw->clock; | ||
392 | |||
393 | bt_ctf_clock_set_description(clock, "perf clock"); | ||
394 | |||
395 | #define SET(__n, __v) \ | ||
396 | do { \ | ||
397 | if (bt_ctf_clock_set_##__n(clock, __v)) \ | ||
398 | return -1; \ | ||
399 | } while (0) | ||
400 | |||
401 | SET(frequency, 1000000000); | ||
402 | SET(offset_s, 0); | ||
403 | SET(offset, 0); | ||
404 | SET(precision, 10); | ||
405 | SET(is_absolute, 0); | ||
406 | |||
407 | #undef SET | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex) | ||
412 | { | ||
413 | struct bt_ctf_field_type *type; | ||
414 | |||
415 | type = bt_ctf_field_type_integer_create(size); | ||
416 | if (!type) | ||
417 | return NULL; | ||
418 | |||
419 | if (sign && | ||
420 | bt_ctf_field_type_integer_set_signed(type, 1)) | ||
421 | goto err; | ||
422 | |||
423 | if (hex && | ||
424 | bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL)) | ||
425 | goto err; | ||
426 | |||
427 | pr2("Created type: INTEGER %d-bit %ssigned %s\n", | ||
428 | size, sign ? "un" : "", hex ? "hex" : ""); | ||
429 | return type; | ||
430 | |||
431 | err: | ||
432 | bt_ctf_field_type_put(type); | ||
433 | return NULL; | ||
434 | } | ||
435 | |||
436 | static void ctf_writer__cleanup_data(struct ctf_writer *cw) | ||
437 | { | ||
438 | unsigned int i; | ||
439 | |||
440 | for (i = 0; i < ARRAY_SIZE(cw->data.array); i++) | ||
441 | bt_ctf_field_type_put(cw->data.array[i]); | ||
442 | } | ||
443 | |||
444 | static int ctf_writer__init_data(struct ctf_writer *cw) | ||
445 | { | ||
446 | #define CREATE_INT_TYPE(type, size, sign, hex) \ | ||
447 | do { \ | ||
448 | (type) = create_int_type(size, sign, hex); \ | ||
449 | if (!(type)) \ | ||
450 | goto err; \ | ||
451 | } while (0) | ||
452 | |||
453 | CREATE_INT_TYPE(cw->data.s64, 64, true, false); | ||
454 | CREATE_INT_TYPE(cw->data.u64, 64, false, false); | ||
455 | CREATE_INT_TYPE(cw->data.s32, 32, true, false); | ||
456 | CREATE_INT_TYPE(cw->data.u32, 32, false, false); | ||
457 | CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true); | ||
458 | |||
459 | cw->data.string = bt_ctf_field_type_string_create(); | ||
460 | if (cw->data.string) | ||
461 | return 0; | ||
462 | |||
463 | err: | ||
464 | ctf_writer__cleanup_data(cw); | ||
465 | pr_err("Failed to create data types.\n"); | ||
466 | return -1; | ||
467 | } | ||
468 | |||
469 | static void ctf_writer__cleanup(struct ctf_writer *cw) | ||
470 | { | ||
471 | ctf_writer__cleanup_data(cw); | ||
472 | |||
473 | bt_ctf_clock_put(cw->clock); | ||
474 | bt_ctf_stream_put(cw->stream); | ||
475 | bt_ctf_stream_class_put(cw->stream_class); | ||
476 | bt_ctf_writer_put(cw->writer); | ||
477 | |||
478 | /* and NULL all the pointers */ | ||
479 | memset(cw, 0, sizeof(*cw)); | ||
480 | } | ||
481 | |||
482 | static int ctf_writer__init(struct ctf_writer *cw, const char *path) | ||
483 | { | ||
484 | struct bt_ctf_writer *writer; | ||
485 | struct bt_ctf_stream_class *stream_class; | ||
486 | struct bt_ctf_stream *stream; | ||
487 | struct bt_ctf_clock *clock; | ||
488 | |||
489 | /* CTF writer */ | ||
490 | writer = bt_ctf_writer_create(path); | ||
491 | if (!writer) | ||
492 | goto err; | ||
493 | |||
494 | cw->writer = writer; | ||
495 | |||
496 | /* CTF clock */ | ||
497 | clock = bt_ctf_clock_create("perf_clock"); | ||
498 | if (!clock) { | ||
499 | pr("Failed to create CTF clock.\n"); | ||
500 | goto err_cleanup; | ||
501 | } | ||
502 | |||
503 | cw->clock = clock; | ||
504 | |||
505 | if (ctf_writer__setup_clock(cw)) { | ||
506 | pr("Failed to setup CTF clock.\n"); | ||
507 | goto err_cleanup; | ||
508 | } | ||
509 | |||
510 | /* CTF stream class */ | ||
511 | stream_class = bt_ctf_stream_class_create("perf_stream"); | ||
512 | if (!stream_class) { | ||
513 | pr("Failed to create CTF stream class.\n"); | ||
514 | goto err_cleanup; | ||
515 | } | ||
516 | |||
517 | cw->stream_class = stream_class; | ||
518 | |||
519 | /* CTF clock stream setup */ | ||
520 | if (bt_ctf_stream_class_set_clock(stream_class, clock)) { | ||
521 | pr("Failed to assign CTF clock to stream class.\n"); | ||
522 | goto err_cleanup; | ||
523 | } | ||
524 | |||
525 | if (ctf_writer__init_data(cw)) | ||
526 | goto err_cleanup; | ||
527 | |||
528 | /* CTF stream instance */ | ||
529 | stream = bt_ctf_writer_create_stream(writer, stream_class); | ||
530 | if (!stream) { | ||
531 | pr("Failed to create CTF stream.\n"); | ||
532 | goto err_cleanup; | ||
533 | } | ||
534 | |||
535 | cw->stream = stream; | ||
536 | |||
537 | /* CTF clock writer setup */ | ||
538 | if (bt_ctf_writer_add_clock(writer, clock)) { | ||
539 | pr("Failed to assign CTF clock to writer.\n"); | ||
540 | goto err_cleanup; | ||
541 | } | ||
542 | |||
543 | return 0; | ||
544 | |||
545 | err_cleanup: | ||
546 | ctf_writer__cleanup(cw); | ||
547 | err: | ||
548 | pr_err("Failed to setup CTF writer.\n"); | ||
549 | return -1; | ||
550 | } | ||
551 | |||
552 | int bt_convert__perf2ctf(const char *input, const char *path) | ||
553 | { | ||
554 | struct perf_session *session; | ||
555 | struct perf_data_file file = { | ||
556 | .path = input, | ||
557 | .mode = PERF_DATA_MODE_READ, | ||
558 | }; | ||
559 | struct convert c = { | ||
560 | .tool = { | ||
561 | .sample = process_sample_event, | ||
562 | .mmap = perf_event__process_mmap, | ||
563 | .mmap2 = perf_event__process_mmap2, | ||
564 | .comm = perf_event__process_comm, | ||
565 | .exit = perf_event__process_exit, | ||
566 | .fork = perf_event__process_fork, | ||
567 | .lost = perf_event__process_lost, | ||
568 | .tracing_data = perf_event__process_tracing_data, | ||
569 | .build_id = perf_event__process_build_id, | ||
570 | .ordered_events = true, | ||
571 | .ordering_requires_timestamps = true, | ||
572 | }, | ||
573 | }; | ||
574 | struct ctf_writer *cw = &c.writer; | ||
575 | int err = -1; | ||
576 | |||
577 | /* CTF writer */ | ||
578 | if (ctf_writer__init(cw, path)) | ||
579 | return -1; | ||
580 | |||
581 | /* perf.data session */ | ||
582 | session = perf_session__new(&file, 0, NULL); | ||
583 | if (!session) | ||
584 | goto free_writer; | ||
585 | |||
586 | /* CTF writer env/clock setup */ | ||
587 | if (ctf_writer__setup_env(cw, session)) | ||
588 | goto free_session; | ||
589 | |||
590 | /* CTF events setup */ | ||
591 | if (setup_events(cw, session)) | ||
592 | goto free_session; | ||
593 | |||
594 | err = perf_session__process_events(session, &c.tool); | ||
595 | if (!err) | ||
596 | err = bt_ctf_stream_flush(cw->stream); | ||
597 | |||
598 | fprintf(stderr, | ||
599 | "[ perf data convert: Converted '%s' into CTF data '%s' ]\n", | ||
600 | file.path, path); | ||
601 | |||
602 | fprintf(stderr, | ||
603 | "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples) ]\n", | ||
604 | (double) c.events_size / 1024.0 / 1024.0, | ||
605 | c.events_count); | ||
606 | |||
607 | /* its all good */ | ||
608 | free_session: | ||
609 | perf_session__delete(session); | ||
610 | |||
611 | free_writer: | ||
612 | ctf_writer__cleanup(cw); | ||
613 | return err; | ||
614 | } | ||
diff --git a/tools/perf/util/data-convert-bt.h b/tools/perf/util/data-convert-bt.h new file mode 100644 index 000000000000..dda30c5d0792 --- /dev/null +++ b/tools/perf/util/data-convert-bt.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef __DATA_CONVERT_BT_H | ||
2 | #define __DATA_CONVERT_BT_H | ||
3 | #ifdef HAVE_LIBBABELTRACE_SUPPORT | ||
4 | |||
5 | int bt_convert__perf2ctf(const char *input_name, const char *to_ctf); | ||
6 | |||
7 | #endif /* HAVE_LIBBABELTRACE_SUPPORT */ | ||
8 | #endif /* __DATA_CONVERT_BT_H */ | ||
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index ad60b2f20258..2da5581ec74d 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -20,6 +20,7 @@ int verbose; | |||
20 | bool dump_trace = false, quiet = false; | 20 | bool dump_trace = false, quiet = false; |
21 | int debug_ordered_events; | 21 | int debug_ordered_events; |
22 | static int redirect_to_stderr; | 22 | static int redirect_to_stderr; |
23 | int debug_data_convert; | ||
23 | 24 | ||
24 | static int _eprintf(int level, int var, const char *fmt, va_list args) | 25 | static int _eprintf(int level, int var, const char *fmt, va_list args) |
25 | { | 26 | { |
@@ -147,6 +148,7 @@ static struct debug_variable { | |||
147 | { .name = "verbose", .ptr = &verbose }, | 148 | { .name = "verbose", .ptr = &verbose }, |
148 | { .name = "ordered-events", .ptr = &debug_ordered_events}, | 149 | { .name = "ordered-events", .ptr = &debug_ordered_events}, |
149 | { .name = "stderr", .ptr = &redirect_to_stderr}, | 150 | { .name = "stderr", .ptr = &redirect_to_stderr}, |
151 | { .name = "data-convert", .ptr = &debug_data_convert }, | ||
150 | { .name = NULL, } | 152 | { .name = NULL, } |
151 | }; | 153 | }; |
152 | 154 | ||
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index be264d6f3b30..caac2fdc6105 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -12,6 +12,7 @@ | |||
12 | extern int verbose; | 12 | extern int verbose; |
13 | extern bool quiet, dump_trace; | 13 | extern bool quiet, dump_trace; |
14 | extern int debug_ordered_events; | 14 | extern int debug_ordered_events; |
15 | extern int debug_data_convert; | ||
15 | 16 | ||
16 | #ifndef pr_fmt | 17 | #ifndef pr_fmt |
17 | #define pr_fmt(fmt) fmt | 18 | #define pr_fmt(fmt) fmt |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 6c6d044e959a..9e806d855b04 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -615,7 +615,7 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) | |||
615 | else | 615 | else |
616 | s = ""; | 616 | s = ""; |
617 | 617 | ||
618 | return fprintf(fp, "%s: %s:%d\n", s, event->comm.comm, event->comm.tid); | 618 | return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid); |
619 | } | 619 | } |
620 | 620 | ||
621 | int perf_event__process_comm(struct perf_tool *tool __maybe_unused, | 621 | int perf_event__process_comm(struct perf_tool *tool __maybe_unused, |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index a8b2c5726aba..8d0b62361129 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -1085,6 +1085,38 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter) | |||
1085 | return err; | 1085 | return err; |
1086 | } | 1086 | } |
1087 | 1087 | ||
1088 | int perf_evlist__set_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids) | ||
1089 | { | ||
1090 | char *filter; | ||
1091 | int ret = -1; | ||
1092 | size_t i; | ||
1093 | |||
1094 | for (i = 0; i < npids; ++i) { | ||
1095 | if (i == 0) { | ||
1096 | if (asprintf(&filter, "common_pid != %d", pids[i]) < 0) | ||
1097 | return -1; | ||
1098 | } else { | ||
1099 | char *tmp; | ||
1100 | |||
1101 | if (asprintf(&tmp, "%s && common_pid != %d", filter, pids[i]) < 0) | ||
1102 | goto out_free; | ||
1103 | |||
1104 | free(filter); | ||
1105 | filter = tmp; | ||
1106 | } | ||
1107 | } | ||
1108 | |||
1109 | ret = perf_evlist__set_filter(evlist, filter); | ||
1110 | out_free: | ||
1111 | free(filter); | ||
1112 | return ret; | ||
1113 | } | ||
1114 | |||
1115 | int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid) | ||
1116 | { | ||
1117 | return perf_evlist__set_filter_pids(evlist, 1, &pid); | ||
1118 | } | ||
1119 | |||
1088 | bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) | 1120 | bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) |
1089 | { | 1121 | { |
1090 | struct perf_evsel *pos; | 1122 | struct perf_evsel *pos; |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index c94a9e03ecf1..d4768a30f884 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -51,6 +51,7 @@ struct perf_evlist { | |||
51 | struct thread_map *threads; | 51 | struct thread_map *threads; |
52 | struct cpu_map *cpus; | 52 | struct cpu_map *cpus; |
53 | struct perf_evsel *selected; | 53 | struct perf_evsel *selected; |
54 | struct events_stats stats; | ||
54 | }; | 55 | }; |
55 | 56 | ||
56 | struct perf_evsel_str_handler { | 57 | struct perf_evsel_str_handler { |
@@ -77,6 +78,8 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist, | |||
77 | const char *sys, const char *name, void *handler); | 78 | const char *sys, const char *name, void *handler); |
78 | 79 | ||
79 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); | 80 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); |
81 | int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid); | ||
82 | int perf_evlist__set_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids); | ||
80 | 83 | ||
81 | struct perf_evsel * | 84 | struct perf_evsel * |
82 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); | 85 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index f93e5208c762..bb4eff28869e 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -734,6 +734,12 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
734 | if (opts->sample_transaction) | 734 | if (opts->sample_transaction) |
735 | perf_evsel__set_sample_bit(evsel, TRANSACTION); | 735 | perf_evsel__set_sample_bit(evsel, TRANSACTION); |
736 | 736 | ||
737 | if (opts->running_time) { | ||
738 | evsel->attr.read_format |= | ||
739 | PERF_FORMAT_TOTAL_TIME_ENABLED | | ||
740 | PERF_FORMAT_TOTAL_TIME_RUNNING; | ||
741 | } | ||
742 | |||
737 | /* | 743 | /* |
738 | * XXX see the function comment above | 744 | * XXX see the function comment above |
739 | * | 745 | * |
diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index fd4be94125fb..077ddd25189f 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c | |||
@@ -166,7 +166,7 @@ static int __ordered_events__flush(struct perf_session *s, | |||
166 | struct ui_progress prog; | 166 | struct ui_progress prog; |
167 | int ret; | 167 | int ret; |
168 | 168 | ||
169 | if (!tool->ordered_events || !limit) | 169 | if (!limit) |
170 | return 0; | 170 | return 0; |
171 | 171 | ||
172 | if (show_progress) | 172 | if (show_progress) |
@@ -216,6 +216,9 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, | |||
216 | }; | 216 | }; |
217 | int err; | 217 | int err; |
218 | 218 | ||
219 | if (oe->nr_events == 0) | ||
220 | return 0; | ||
221 | |||
219 | switch (how) { | 222 | switch (how) { |
220 | case OE_FLUSH__FINAL: | 223 | case OE_FLUSH__FINAL: |
221 | oe->next_flush = ULLONG_MAX; | 224 | oe->next_flush = ULLONG_MAX; |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 504b7e664e6c..e4f166981ff0 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -537,7 +537,7 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event, | |||
537 | pr_oe_time(oe->last_flush, "last flush, last_flush_type %d\n", | 537 | pr_oe_time(oe->last_flush, "last flush, last_flush_type %d\n", |
538 | oe->last_flush_type); | 538 | oe->last_flush_type); |
539 | 539 | ||
540 | s->stats.nr_unordered_events++; | 540 | s->evlist->stats.nr_unordered_events++; |
541 | } | 541 | } |
542 | 542 | ||
543 | new = ordered_events__new(oe, timestamp, event); | 543 | new = ordered_events__new(oe, timestamp, event); |
@@ -688,14 +688,14 @@ static void stack_user__printf(struct stack_dump *dump) | |||
688 | dump->size, dump->offset); | 688 | dump->size, dump->offset); |
689 | } | 689 | } |
690 | 690 | ||
691 | static void perf_session__print_tstamp(struct perf_session *session, | 691 | static void perf_evlist__print_tstamp(struct perf_evlist *evlist, |
692 | union perf_event *event, | 692 | union perf_event *event, |
693 | struct perf_sample *sample) | 693 | struct perf_sample *sample) |
694 | { | 694 | { |
695 | u64 sample_type = __perf_evlist__combined_sample_type(session->evlist); | 695 | u64 sample_type = __perf_evlist__combined_sample_type(evlist); |
696 | 696 | ||
697 | if (event->header.type != PERF_RECORD_SAMPLE && | 697 | if (event->header.type != PERF_RECORD_SAMPLE && |
698 | !perf_evlist__sample_id_all(session->evlist)) { | 698 | !perf_evlist__sample_id_all(evlist)) { |
699 | fputs("-1 -1 ", stdout); | 699 | fputs("-1 -1 ", stdout); |
700 | return; | 700 | return; |
701 | } | 701 | } |
@@ -737,7 +737,7 @@ static void sample_read__printf(struct perf_sample *sample, u64 read_format) | |||
737 | sample->read.one.id, sample->read.one.value); | 737 | sample->read.one.id, sample->read.one.value); |
738 | } | 738 | } |
739 | 739 | ||
740 | static void dump_event(struct perf_session *session, union perf_event *event, | 740 | static void dump_event(struct perf_evlist *evlist, union perf_event *event, |
741 | u64 file_offset, struct perf_sample *sample) | 741 | u64 file_offset, struct perf_sample *sample) |
742 | { | 742 | { |
743 | if (!dump_trace) | 743 | if (!dump_trace) |
@@ -749,7 +749,7 @@ static void dump_event(struct perf_session *session, union perf_event *event, | |||
749 | trace_event(event); | 749 | trace_event(event); |
750 | 750 | ||
751 | if (sample) | 751 | if (sample) |
752 | perf_session__print_tstamp(session, event, sample); | 752 | perf_evlist__print_tstamp(evlist, event, sample); |
753 | 753 | ||
754 | printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset, | 754 | printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset, |
755 | event->header.size, perf_event__name(event->header.type)); | 755 | event->header.size, perf_event__name(event->header.type)); |
@@ -797,8 +797,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, | |||
797 | sample_read__printf(sample, evsel->attr.read_format); | 797 | sample_read__printf(sample, evsel->attr.read_format); |
798 | } | 798 | } |
799 | 799 | ||
800 | static struct machine * | 800 | static struct machine *machines__find_for_cpumode(struct machines *machines, |
801 | perf_session__find_machine_for_cpumode(struct perf_session *session, | ||
802 | union perf_event *event, | 801 | union perf_event *event, |
803 | struct perf_sample *sample) | 802 | struct perf_sample *sample) |
804 | { | 803 | { |
@@ -816,26 +815,24 @@ static struct machine * | |||
816 | else | 815 | else |
817 | pid = sample->pid; | 816 | pid = sample->pid; |
818 | 817 | ||
819 | machine = perf_session__find_machine(session, pid); | 818 | machine = machines__find(machines, pid); |
820 | if (!machine) | 819 | if (!machine) |
821 | machine = perf_session__findnew_machine(session, | 820 | machine = machines__find(machines, DEFAULT_GUEST_KERNEL_ID); |
822 | DEFAULT_GUEST_KERNEL_ID); | ||
823 | return machine; | 821 | return machine; |
824 | } | 822 | } |
825 | 823 | ||
826 | return &session->machines.host; | 824 | return &machines->host; |
827 | } | 825 | } |
828 | 826 | ||
829 | static int deliver_sample_value(struct perf_session *session, | 827 | static int deliver_sample_value(struct perf_evlist *evlist, |
830 | struct perf_tool *tool, | 828 | struct perf_tool *tool, |
831 | union perf_event *event, | 829 | union perf_event *event, |
832 | struct perf_sample *sample, | 830 | struct perf_sample *sample, |
833 | struct sample_read_value *v, | 831 | struct sample_read_value *v, |
834 | struct machine *machine) | 832 | struct machine *machine) |
835 | { | 833 | { |
836 | struct perf_sample_id *sid; | 834 | struct perf_sample_id *sid = perf_evlist__id2sid(evlist, v->id); |
837 | 835 | ||
838 | sid = perf_evlist__id2sid(session->evlist, v->id); | ||
839 | if (sid) { | 836 | if (sid) { |
840 | sample->id = v->id; | 837 | sample->id = v->id; |
841 | sample->period = v->value - sid->period; | 838 | sample->period = v->value - sid->period; |
@@ -843,14 +840,14 @@ static int deliver_sample_value(struct perf_session *session, | |||
843 | } | 840 | } |
844 | 841 | ||
845 | if (!sid || sid->evsel == NULL) { | 842 | if (!sid || sid->evsel == NULL) { |
846 | ++session->stats.nr_unknown_id; | 843 | ++evlist->stats.nr_unknown_id; |
847 | return 0; | 844 | return 0; |
848 | } | 845 | } |
849 | 846 | ||
850 | return tool->sample(tool, event, sample, sid->evsel, machine); | 847 | return tool->sample(tool, event, sample, sid->evsel, machine); |
851 | } | 848 | } |
852 | 849 | ||
853 | static int deliver_sample_group(struct perf_session *session, | 850 | static int deliver_sample_group(struct perf_evlist *evlist, |
854 | struct perf_tool *tool, | 851 | struct perf_tool *tool, |
855 | union perf_event *event, | 852 | union perf_event *event, |
856 | struct perf_sample *sample, | 853 | struct perf_sample *sample, |
@@ -860,7 +857,7 @@ static int deliver_sample_group(struct perf_session *session, | |||
860 | u64 i; | 857 | u64 i; |
861 | 858 | ||
862 | for (i = 0; i < sample->read.group.nr; i++) { | 859 | for (i = 0; i < sample->read.group.nr; i++) { |
863 | ret = deliver_sample_value(session, tool, event, sample, | 860 | ret = deliver_sample_value(evlist, tool, event, sample, |
864 | &sample->read.group.values[i], | 861 | &sample->read.group.values[i], |
865 | machine); | 862 | machine); |
866 | if (ret) | 863 | if (ret) |
@@ -871,7 +868,7 @@ static int deliver_sample_group(struct perf_session *session, | |||
871 | } | 868 | } |
872 | 869 | ||
873 | static int | 870 | static int |
874 | perf_session__deliver_sample(struct perf_session *session, | 871 | perf_evlist__deliver_sample(struct perf_evlist *evlist, |
875 | struct perf_tool *tool, | 872 | struct perf_tool *tool, |
876 | union perf_event *event, | 873 | union perf_event *event, |
877 | struct perf_sample *sample, | 874 | struct perf_sample *sample, |
@@ -888,10 +885,10 @@ perf_session__deliver_sample(struct perf_session *session, | |||
888 | 885 | ||
889 | /* For PERF_SAMPLE_READ we have either single or group mode. */ | 886 | /* For PERF_SAMPLE_READ we have either single or group mode. */ |
890 | if (read_format & PERF_FORMAT_GROUP) | 887 | if (read_format & PERF_FORMAT_GROUP) |
891 | return deliver_sample_group(session, tool, event, sample, | 888 | return deliver_sample_group(evlist, tool, event, sample, |
892 | machine); | 889 | machine); |
893 | else | 890 | else |
894 | return deliver_sample_value(session, tool, event, sample, | 891 | return deliver_sample_value(evlist, tool, event, sample, |
895 | &sample->read.one, machine); | 892 | &sample->read.one, machine); |
896 | } | 893 | } |
897 | 894 | ||
@@ -900,29 +897,28 @@ int perf_session__deliver_event(struct perf_session *session, | |||
900 | struct perf_sample *sample, | 897 | struct perf_sample *sample, |
901 | struct perf_tool *tool, u64 file_offset) | 898 | struct perf_tool *tool, u64 file_offset) |
902 | { | 899 | { |
900 | struct perf_evlist *evlist = session->evlist; | ||
903 | struct perf_evsel *evsel; | 901 | struct perf_evsel *evsel; |
904 | struct machine *machine; | 902 | struct machine *machine; |
905 | 903 | ||
906 | dump_event(session, event, file_offset, sample); | 904 | dump_event(evlist, event, file_offset, sample); |
907 | 905 | ||
908 | evsel = perf_evlist__id2evsel(session->evlist, sample->id); | 906 | evsel = perf_evlist__id2evsel(evlist, sample->id); |
909 | 907 | ||
910 | machine = perf_session__find_machine_for_cpumode(session, event, | 908 | machine = machines__find_for_cpumode(&session->machines, event, sample); |
911 | sample); | ||
912 | 909 | ||
913 | switch (event->header.type) { | 910 | switch (event->header.type) { |
914 | case PERF_RECORD_SAMPLE: | 911 | case PERF_RECORD_SAMPLE: |
915 | dump_sample(evsel, event, sample); | 912 | dump_sample(evsel, event, sample); |
916 | if (evsel == NULL) { | 913 | if (evsel == NULL) { |
917 | ++session->stats.nr_unknown_id; | 914 | ++evlist->stats.nr_unknown_id; |
918 | return 0; | 915 | return 0; |
919 | } | 916 | } |
920 | if (machine == NULL) { | 917 | if (machine == NULL) { |
921 | ++session->stats.nr_unprocessable_samples; | 918 | ++evlist->stats.nr_unprocessable_samples; |
922 | return 0; | 919 | return 0; |
923 | } | 920 | } |
924 | return perf_session__deliver_sample(session, tool, event, | 921 | return perf_evlist__deliver_sample(evlist, tool, event, sample, evsel, machine); |
925 | sample, evsel, machine); | ||
926 | case PERF_RECORD_MMAP: | 922 | case PERF_RECORD_MMAP: |
927 | return tool->mmap(tool, event, sample, machine); | 923 | return tool->mmap(tool, event, sample, machine); |
928 | case PERF_RECORD_MMAP2: | 924 | case PERF_RECORD_MMAP2: |
@@ -935,7 +931,7 @@ int perf_session__deliver_event(struct perf_session *session, | |||
935 | return tool->exit(tool, event, sample, machine); | 931 | return tool->exit(tool, event, sample, machine); |
936 | case PERF_RECORD_LOST: | 932 | case PERF_RECORD_LOST: |
937 | if (tool->lost == perf_event__process_lost) | 933 | if (tool->lost == perf_event__process_lost) |
938 | session->stats.total_lost += event->lost.lost; | 934 | evlist->stats.total_lost += event->lost.lost; |
939 | return tool->lost(tool, event, sample, machine); | 935 | return tool->lost(tool, event, sample, machine); |
940 | case PERF_RECORD_READ: | 936 | case PERF_RECORD_READ: |
941 | return tool->read(tool, event, sample, evsel, machine); | 937 | return tool->read(tool, event, sample, evsel, machine); |
@@ -944,7 +940,7 @@ int perf_session__deliver_event(struct perf_session *session, | |||
944 | case PERF_RECORD_UNTHROTTLE: | 940 | case PERF_RECORD_UNTHROTTLE: |
945 | return tool->unthrottle(tool, event, sample, machine); | 941 | return tool->unthrottle(tool, event, sample, machine); |
946 | default: | 942 | default: |
947 | ++session->stats.nr_unknown_events; | 943 | ++evlist->stats.nr_unknown_events; |
948 | return -1; | 944 | return -1; |
949 | } | 945 | } |
950 | } | 946 | } |
@@ -957,7 +953,7 @@ static s64 perf_session__process_user_event(struct perf_session *session, | |||
957 | int fd = perf_data_file__fd(session->file); | 953 | int fd = perf_data_file__fd(session->file); |
958 | int err; | 954 | int err; |
959 | 955 | ||
960 | dump_event(session, event, file_offset, NULL); | 956 | dump_event(session->evlist, event, file_offset, NULL); |
961 | 957 | ||
962 | /* These events are processed right away */ | 958 | /* These events are processed right away */ |
963 | switch (event->header.type) { | 959 | switch (event->header.type) { |
@@ -994,7 +990,7 @@ int perf_session__deliver_synth_event(struct perf_session *session, | |||
994 | struct perf_sample *sample, | 990 | struct perf_sample *sample, |
995 | struct perf_tool *tool) | 991 | struct perf_tool *tool) |
996 | { | 992 | { |
997 | events_stats__inc(&session->stats, event->header.type); | 993 | events_stats__inc(&session->evlist->stats, event->header.type); |
998 | 994 | ||
999 | if (event->header.type >= PERF_RECORD_USER_TYPE_START) | 995 | if (event->header.type >= PERF_RECORD_USER_TYPE_START) |
1000 | return perf_session__process_user_event(session, event, tool, 0); | 996 | return perf_session__process_user_event(session, event, tool, 0); |
@@ -1071,16 +1067,17 @@ static s64 perf_session__process_event(struct perf_session *session, | |||
1071 | struct perf_tool *tool, | 1067 | struct perf_tool *tool, |
1072 | u64 file_offset) | 1068 | u64 file_offset) |
1073 | { | 1069 | { |
1070 | struct perf_evlist *evlist = session->evlist; | ||
1074 | struct perf_sample sample; | 1071 | struct perf_sample sample; |
1075 | int ret; | 1072 | int ret; |
1076 | 1073 | ||
1077 | if (session->header.needs_swap) | 1074 | if (session->header.needs_swap) |
1078 | event_swap(event, perf_evlist__sample_id_all(session->evlist)); | 1075 | event_swap(event, perf_evlist__sample_id_all(evlist)); |
1079 | 1076 | ||
1080 | if (event->header.type >= PERF_RECORD_HEADER_MAX) | 1077 | if (event->header.type >= PERF_RECORD_HEADER_MAX) |
1081 | return -EINVAL; | 1078 | return -EINVAL; |
1082 | 1079 | ||
1083 | events_stats__inc(&session->stats, event->header.type); | 1080 | events_stats__inc(&evlist->stats, event->header.type); |
1084 | 1081 | ||
1085 | if (event->header.type >= PERF_RECORD_USER_TYPE_START) | 1082 | if (event->header.type >= PERF_RECORD_USER_TYPE_START) |
1086 | return perf_session__process_user_event(session, event, tool, file_offset); | 1083 | return perf_session__process_user_event(session, event, tool, file_offset); |
@@ -1088,7 +1085,7 @@ static s64 perf_session__process_event(struct perf_session *session, | |||
1088 | /* | 1085 | /* |
1089 | * For all kernel events we get the sample data | 1086 | * For all kernel events we get the sample data |
1090 | */ | 1087 | */ |
1091 | ret = perf_evlist__parse_sample(session->evlist, event, &sample); | 1088 | ret = perf_evlist__parse_sample(evlist, event, &sample); |
1092 | if (ret) | 1089 | if (ret) |
1093 | return ret; | 1090 | return ret; |
1094 | 1091 | ||
@@ -1128,47 +1125,47 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se | |||
1128 | return thread; | 1125 | return thread; |
1129 | } | 1126 | } |
1130 | 1127 | ||
1131 | static void perf_session__warn_about_errors(const struct perf_session *session, | 1128 | static void perf_tool__warn_about_errors(const struct perf_tool *tool, |
1132 | const struct perf_tool *tool) | 1129 | const struct events_stats *stats) |
1133 | { | 1130 | { |
1134 | if (tool->lost == perf_event__process_lost && | 1131 | if (tool->lost == perf_event__process_lost && |
1135 | session->stats.nr_events[PERF_RECORD_LOST] != 0) { | 1132 | stats->nr_events[PERF_RECORD_LOST] != 0) { |
1136 | ui__warning("Processed %d events and lost %d chunks!\n\n" | 1133 | ui__warning("Processed %d events and lost %d chunks!\n\n" |
1137 | "Check IO/CPU overload!\n\n", | 1134 | "Check IO/CPU overload!\n\n", |
1138 | session->stats.nr_events[0], | 1135 | stats->nr_events[0], |
1139 | session->stats.nr_events[PERF_RECORD_LOST]); | 1136 | stats->nr_events[PERF_RECORD_LOST]); |
1140 | } | 1137 | } |
1141 | 1138 | ||
1142 | if (session->stats.nr_unknown_events != 0) { | 1139 | if (stats->nr_unknown_events != 0) { |
1143 | ui__warning("Found %u unknown events!\n\n" | 1140 | ui__warning("Found %u unknown events!\n\n" |
1144 | "Is this an older tool processing a perf.data " | 1141 | "Is this an older tool processing a perf.data " |
1145 | "file generated by a more recent tool?\n\n" | 1142 | "file generated by a more recent tool?\n\n" |
1146 | "If that is not the case, consider " | 1143 | "If that is not the case, consider " |
1147 | "reporting to linux-kernel@vger.kernel.org.\n\n", | 1144 | "reporting to linux-kernel@vger.kernel.org.\n\n", |
1148 | session->stats.nr_unknown_events); | 1145 | stats->nr_unknown_events); |
1149 | } | 1146 | } |
1150 | 1147 | ||
1151 | if (session->stats.nr_unknown_id != 0) { | 1148 | if (stats->nr_unknown_id != 0) { |
1152 | ui__warning("%u samples with id not present in the header\n", | 1149 | ui__warning("%u samples with id not present in the header\n", |
1153 | session->stats.nr_unknown_id); | 1150 | stats->nr_unknown_id); |
1154 | } | 1151 | } |
1155 | 1152 | ||
1156 | if (session->stats.nr_invalid_chains != 0) { | 1153 | if (stats->nr_invalid_chains != 0) { |
1157 | ui__warning("Found invalid callchains!\n\n" | 1154 | ui__warning("Found invalid callchains!\n\n" |
1158 | "%u out of %u events were discarded for this reason.\n\n" | 1155 | "%u out of %u events were discarded for this reason.\n\n" |
1159 | "Consider reporting to linux-kernel@vger.kernel.org.\n\n", | 1156 | "Consider reporting to linux-kernel@vger.kernel.org.\n\n", |
1160 | session->stats.nr_invalid_chains, | 1157 | stats->nr_invalid_chains, |
1161 | session->stats.nr_events[PERF_RECORD_SAMPLE]); | 1158 | stats->nr_events[PERF_RECORD_SAMPLE]); |
1162 | } | 1159 | } |
1163 | 1160 | ||
1164 | if (session->stats.nr_unprocessable_samples != 0) { | 1161 | if (stats->nr_unprocessable_samples != 0) { |
1165 | ui__warning("%u unprocessable samples recorded.\n" | 1162 | ui__warning("%u unprocessable samples recorded.\n" |
1166 | "Do you have a KVM guest running and not using 'perf kvm'?\n", | 1163 | "Do you have a KVM guest running and not using 'perf kvm'?\n", |
1167 | session->stats.nr_unprocessable_samples); | 1164 | stats->nr_unprocessable_samples); |
1168 | } | 1165 | } |
1169 | 1166 | ||
1170 | if (session->stats.nr_unordered_events != 0) | 1167 | if (stats->nr_unordered_events != 0) |
1171 | ui__warning("%u out of order events recorded.\n", session->stats.nr_unordered_events); | 1168 | ui__warning("%u out of order events recorded.\n", stats->nr_unordered_events); |
1172 | } | 1169 | } |
1173 | 1170 | ||
1174 | volatile int session_done; | 1171 | volatile int session_done; |
@@ -1258,7 +1255,7 @@ done: | |||
1258 | err = ordered_events__flush(session, tool, OE_FLUSH__FINAL); | 1255 | err = ordered_events__flush(session, tool, OE_FLUSH__FINAL); |
1259 | out_err: | 1256 | out_err: |
1260 | free(buf); | 1257 | free(buf); |
1261 | perf_session__warn_about_errors(session, tool); | 1258 | perf_tool__warn_about_errors(tool, &session->evlist->stats); |
1262 | ordered_events__free(&session->ordered_events); | 1259 | ordered_events__free(&session->ordered_events); |
1263 | return err; | 1260 | return err; |
1264 | } | 1261 | } |
@@ -1403,7 +1400,7 @@ out: | |||
1403 | err = ordered_events__flush(session, tool, OE_FLUSH__FINAL); | 1400 | err = ordered_events__flush(session, tool, OE_FLUSH__FINAL); |
1404 | out_err: | 1401 | out_err: |
1405 | ui_progress__finish(); | 1402 | ui_progress__finish(); |
1406 | perf_session__warn_about_errors(session, tool); | 1403 | perf_tool__warn_about_errors(tool, &session->evlist->stats); |
1407 | ordered_events__free(&session->ordered_events); | 1404 | ordered_events__free(&session->ordered_events); |
1408 | session->one_mmap = false; | 1405 | session->one_mmap = false; |
1409 | return err; | 1406 | return err; |
@@ -1488,7 +1485,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | |||
1488 | { | 1485 | { |
1489 | size_t ret = fprintf(fp, "Aggregated stats:\n"); | 1486 | size_t ret = fprintf(fp, "Aggregated stats:\n"); |
1490 | 1487 | ||
1491 | ret += events_stats__fprintf(&session->stats, fp); | 1488 | ret += events_stats__fprintf(&session->evlist->stats, fp); |
1492 | return ret; | 1489 | return ret; |
1493 | } | 1490 | } |
1494 | 1491 | ||
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 6d663dc76404..fe859f379ca7 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -20,7 +20,6 @@ struct perf_session { | |||
20 | struct machines machines; | 20 | struct machines machines; |
21 | struct perf_evlist *evlist; | 21 | struct perf_evlist *evlist; |
22 | struct trace_event tevent; | 22 | struct trace_event tevent; |
23 | struct events_stats stats; | ||
24 | bool repipe; | 23 | bool repipe; |
25 | bool one_mmap; | 24 | bool one_mmap; |
26 | void *one_mmap_addr; | 25 | void *one_mmap_addr; |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 92db3f156b63..4ee6d0d4c993 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -269,6 +269,13 @@ void dump_stack(void) | |||
269 | void dump_stack(void) {} | 269 | void dump_stack(void) {} |
270 | #endif | 270 | #endif |
271 | 271 | ||
272 | void sighandler_dump_stack(int sig) | ||
273 | { | ||
274 | psignal(sig, "perf"); | ||
275 | dump_stack(); | ||
276 | exit(sig); | ||
277 | } | ||
278 | |||
272 | void get_term_dimensions(struct winsize *ws) | 279 | void get_term_dimensions(struct winsize *ws) |
273 | { | 280 | { |
274 | char *s = getenv("LINES"); | 281 | char *s = getenv("LINES"); |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 73c2f8e557ab..fbd598afc606 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -277,6 +277,7 @@ char *ltrim(char *s); | |||
277 | char *rtrim(char *s); | 277 | char *rtrim(char *s); |
278 | 278 | ||
279 | void dump_stack(void); | 279 | void dump_stack(void); |
280 | void sighandler_dump_stack(int sig); | ||
280 | 281 | ||
281 | extern unsigned int page_size; | 282 | extern unsigned int page_size; |
282 | extern int cacheline_size; | 283 | extern int cacheline_size; |