aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2015-02-26 06:25:20 -0500
committerIngo Molnar <mingo@kernel.org>2015-02-26 06:25:20 -0500
commit0afb1704010f60e7ae85aef0f93fc10f2d99761e (patch)
tree62e8dff37b9c4fb6fbc45618aef73c35fb86f57a /tools
parente9e4e44309f866b115d08ab4a54834008c50a8a4 (diff)
parent54cf776a9c5c2e6a91de31954bba4d3bad6c657c (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')
-rw-r--r--tools/perf/Build1
-rw-r--r--tools/perf/Documentation/perf-data.txt40
-rw-r--r--tools/perf/Documentation/perf-record.txt3
-rw-r--r--tools/perf/Documentation/perf-trace.txt6
-rw-r--r--tools/perf/Documentation/perf.txt7
-rw-r--r--tools/perf/Makefile.perf4
-rw-r--r--tools/perf/builtin-data.c119
-rw-r--r--tools/perf/builtin-record.c2
-rw-r--r--tools/perf/builtin-sched.c6
-rw-r--r--tools/perf/builtin-top.c4
-rw-r--r--tools/perf/builtin-trace.c121
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/config/Makefile25
-rw-r--r--tools/perf/config/feature-checks/Makefile8
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/config/feature-checks/test-libbabeltrace.c8
-rw-r--r--tools/perf/perf.c1
-rw-r--r--tools/perf/perf.h1
-rw-r--r--tools/perf/util/Build2
-rw-r--r--tools/perf/util/data-convert-bt.c614
-rw-r--r--tools/perf/util/data-convert-bt.h8
-rw-r--r--tools/perf/util/debug.c2
-rw-r--r--tools/perf/util/debug.h1
-rw-r--r--tools/perf/util/event.c2
-rw-r--r--tools/perf/util/evlist.c32
-rw-r--r--tools/perf/util/evlist.h3
-rw-r--r--tools/perf/util/evsel.c6
-rw-r--r--tools/perf/util/ordered-events.c5
-rw-r--r--tools/perf/util/session.c115
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/util.c7
-rw-r--r--tools/perf/util/util.h1
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
18perf-y += builtin-kvm.o 18perf-y += builtin-kvm.o
19perf-y += builtin-inject.o 19perf-y += builtin-inject.o
20perf-y += builtin-mem.o 20perf-y += builtin-mem.o
21perf-y += builtin-data.o
21 22
22perf-$(CONFIG_AUDIT) += builtin-trace.o 23perf-$(CONFIG_AUDIT) += builtin-trace.o
23perf-$(CONFIG_LIBELF) += builtin-probe.o 24perf-$(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 @@
1perf-data(1)
2==============
3
4NAME
5----
6perf-data - Data file related processing
7
8SYNOPSIS
9--------
10[verse]
11'perf data' [<common options>] <command> [<options>]",
12
13DESCRIPTION
14-----------
15Data file related processing.
16
17COMMANDS
18--------
19convert::
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
25OPTIONS 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
37SEE ALSO
38--------
39linkperf: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
241each sample. List of captured registers depends on the architecture. This option 241each sample. List of captured registers depends on the architecture. This option
242is off by default. 242is off by default.
243 243
244--running-time::
245Record running and enabled time for read events (:S)
246
244SEE ALSO 247SEE ALSO
245-------- 248--------
246linkperf:perf-stat[1], linkperf:perf-list[1] 249linkperf: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
118PAGEFAULTS 124PAGEFAULTS
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
13OPTIONS 13OPTIONS
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
73ifeq ($(srctree),) 75ifeq ($(srctree),)
74srctree := $(patsubst %/,%,$(dir $(shell pwd))) 76srctree := $(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
8typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix);
9
10struct data_cmd {
11 const char *name;
12 const char *summary;
13 data_cmd_fn_t fn;
14};
15
16static struct data_cmd data_cmds[];
17
18#define for_each_cmd(cmd) \
19 for (cmd = data_cmds; cmd && cmd->name; cmd++)
20
21static const struct option data_options[] = {
22 OPT_END()
23};
24
25static const char * const data_usage[] = {
26 "perf data [<common options>] <command> [<options>]",
27 NULL
28};
29
30static 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
45static const char * const data_convert_usage[] = {
46 "perf data convert [<options>]",
47 NULL
48};
49
50static 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
87static struct data_cmd data_cmds[] = {
88 { "convert", "converts data file between formats", cmd_data_convert },
89 { NULL },
90};
91
92int 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);
116usage:
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;
860next_event: 860next_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
2095static 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
2087static int trace__run(struct trace *trace, int argc, const char **argv) 2125static 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);
2205next_event: 2233next_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
2509static 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;
2537out:
2538 return ret;
2539}
2540
2481static int trace__open_output(struct trace *trace, const char *filename) 2541static 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);
37extern int cmd_trace(int argc, const char **argv, const char *prefix); 37extern int cmd_trace(int argc, const char **argv, const char *prefix);
38extern int cmd_inject(int argc, const char **argv, const char *prefix); 38extern int cmd_inject(int argc, const char **argv, const char *prefix);
39extern int cmd_mem(int argc, const char **argv, const char *prefix); 39extern int cmd_mem(int argc, const char **argv, const char *prefix);
40extern int cmd_data(int argc, const char **argv, const char *prefix);
40 41
41extern int find_scripts(char **scripts_array, char **scripts_path_array); 42extern 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
7perf-bench mainporcelain common 7perf-bench mainporcelain common
8perf-buildid-cache mainporcelain common 8perf-buildid-cache mainporcelain common
9perf-buildid-list mainporcelain common 9perf-buildid-list mainporcelain common
10perf-data mainporcelain common
10perf-diff mainporcelain common 11perf-diff mainporcelain common
11perf-evlist mainporcelain common 12perf-evlist mainporcelain common
12perf-inject mainporcelain common 13perf-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
97endif 97endif
98 98
99ifndef 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
108endif
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
221LIB_FEATURE_TESTS = \ 233LIB_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
236VF_FEATURE_TESTS = \ 249VF_FEATURE_TESTS = \
@@ -692,6 +705,18 @@ else
692 NO_PERF_READ_VDSOX32 := 1 705 NO_PERF_READ_VDSOX32 := 1
693endif 706endif
694 707
708ifndef 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
718endif
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
45test-all.bin: 46test-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
48test-hello.bin: 49test-hello.bin:
49 $(BUILD) 50 $(BUILD)
@@ -133,7 +134,10 @@ test-timerfd.bin:
133 $(BUILD) 134 $(BUILD)
134 135
135test-libdw-dwarf-unwind.bin: 136test-libdw-dwarf-unwind.bin:
136 $(BUILD) 137 $(BUILD) # -ldw provided by $(FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind)
138
139test-libbabeltrace.bin:
140 $(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace)
137 141
138test-sync-compare-and-swap.bin: 142test-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
104int main(int argc, char *argv[]) 108int 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
4int 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
67struct pager_config { 68struct 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
88libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o 88libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
89libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o 89libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
90 90
91libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o
92
91libperf-y += scripting-engines/ 93libperf-y += scripting-engines/
92 94
93libperf-$(CONFIG_PERF_REGS) += perf_regs.o 95libperf-$(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
37struct evsel_priv {
38 struct bt_ctf_event_class *event_class;
39};
40
41struct 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
62struct convert {
63 struct perf_tool tool;
64 struct ctf_writer writer;
65
66 u64 events_size;
67 u64 events_count;
68};
69
70static 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
106err:
107 bt_ctf_field_put(field);
108 return ret;
109}
110
111#define __FUNC_VALUE_SET(_name, _val_type) \
112static __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
123FUNC_VALUE_SET(s32)
124FUNC_VALUE_SET(u32)
125FUNC_VALUE_SET(s64)
126FUNC_VALUE_SET(u64)
127__FUNC_VALUE_SET(u64_hex, u64)
128
129static 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
213static 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
254static 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
314static 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
345err:
346 bt_ctf_event_class_put(event_class);
347 pr_err("Failed to add event '%s'.\n", name);
348 return -1;
349}
350
351static 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
365static 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) \
372do { \
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
389static 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) \
396do { \
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
411static 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
431err:
432 bt_ctf_field_type_put(type);
433 return NULL;
434}
435
436static 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
444static int ctf_writer__init_data(struct ctf_writer *cw)
445{
446#define CREATE_INT_TYPE(type, size, sign, hex) \
447do { \
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
463err:
464 ctf_writer__cleanup_data(cw);
465 pr_err("Failed to create data types.\n");
466 return -1;
467}
468
469static 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
482static 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
545err_cleanup:
546 ctf_writer__cleanup(cw);
547err:
548 pr_err("Failed to setup CTF writer.\n");
549 return -1;
550}
551
552int 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 */
608free_session:
609 perf_session__delete(session);
610
611free_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
5int 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;
20bool dump_trace = false, quiet = false; 20bool dump_trace = false, quiet = false;
21int debug_ordered_events; 21int debug_ordered_events;
22static int redirect_to_stderr; 22static int redirect_to_stderr;
23int debug_data_convert;
23 24
24static int _eprintf(int level, int var, const char *fmt, va_list args) 25static 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 @@
12extern int verbose; 12extern int verbose;
13extern bool quiet, dump_trace; 13extern bool quiet, dump_trace;
14extern int debug_ordered_events; 14extern int debug_ordered_events;
15extern 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
621int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 621int 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
1088int 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);
1110out_free:
1111 free(filter);
1112 return ret;
1113}
1114
1115int 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
1088bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) 1120bool 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
56struct perf_evsel_str_handler { 57struct 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
79int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); 80int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter);
81int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid);
82int perf_evlist__set_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids);
80 83
81struct perf_evsel * 84struct perf_evsel *
82perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); 85perf_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
691static void perf_session__print_tstamp(struct perf_session *session, 691static 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
740static void dump_event(struct perf_session *session, union perf_event *event, 740static 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
800static struct machine * 800static 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
829static int deliver_sample_value(struct perf_session *session, 827static 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
853static int deliver_sample_group(struct perf_session *session, 850static 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
873static int 870static int
874perf_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
1131static void perf_session__warn_about_errors(const struct perf_session *session, 1128static 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
1174volatile int session_done; 1171volatile 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);
1259out_err: 1256out_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);
1404out_err: 1401out_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)
269void dump_stack(void) {} 269void dump_stack(void) {}
270#endif 270#endif
271 271
272void sighandler_dump_stack(int sig)
273{
274 psignal(sig, "perf");
275 dump_stack();
276 exit(sig);
277}
278
272void get_term_dimensions(struct winsize *ws) 279void 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);
277char *rtrim(char *s); 277char *rtrim(char *s);
278 278
279void dump_stack(void); 279void dump_stack(void);
280void sighandler_dump_stack(int sig);
280 281
281extern unsigned int page_size; 282extern unsigned int page_size;
282extern int cacheline_size; 283extern int cacheline_size;