aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@kernel.org>2015-02-20 17:17:00 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-02-25 14:13:12 -0500
commitedbe9817aeb540aa1494aa20276a2bfc7f4ab816 (patch)
tree83c9cfedfafc6c0f4b36ea20e04afa2451a2cb8b
parent2245bf1410d2d719f3bfce729b07ab83fe6142f7 (diff)
perf data: Add perf data to CTF conversion support
Adding 'perf data convert' to convert perf data file into different format. This patch adds support for CTF format conversion. To convert perf.data into CTF run: $ perf data convert --to-ctf=./ctf-data/ [ perf data convert: Converted 'perf.data' into CTF data './ctf-data/' ] [ perf data convert: Converted and wrote 11.268 MB (100230 samples) ] The command will create CTF metadata out of perf.data file (or one specified via -i option) and then convert all sample events into single CTF stream. Each sample_type bit is translated into separated CTF event field apart from following exceptions: PERF_SAMPLE_RAW - added in next patch PERF_SAMPLE_READ - TODO PERF_SAMPLE_CALLCHAIN - TODO PERF_SAMPLE_BRANCH_STACK - TODO PERF_SAMPLE_REGS_USER - TODO PERF_SAMPLE_STACK_USER - TODO $ perf --debug=data-convert=2 data convert ... The converted CTF data could be analyzed by CTF tools, like babletrace or tracecompass [1]. $ babeltrace ./ctf-data/ [03:19:13.962125533] (+?.?????????) cycles: { }, { ip = 0xFFFFFFFF8105443A, tid = 20714, pid = 20714, period = 1 } [03:19:13.962130001] (+0.000004468) cycles: { }, { ip = 0xFFFFFFFF8105443A, tid = 20714, pid = 20714, period = 1 } [03:19:13.962131936] (+0.000001935) cycles: { }, { ip = 0xFFFFFFFF8105443A, tid = 20714, pid = 20714, period = 8 } [03:19:13.962133732] (+0.000001796) cycles: { }, { ip = 0xFFFFFFFF8105443A, tid = 20714, pid = 20714, period = 114 } [03:19:13.962135557] (+0.000001825) cycles: { }, { ip = 0xFFFFFFFF8105443A, tid = 20714, pid = 20714, period = 2087 } [03:19:13.962137627] (+0.000002070) cycles: { }, { ip = 0xFFFFFFFF81361938, tid = 20714, pid = 20714, period = 37582 } [03:19:13.962161091] (+0.000023464) cycles: { }, { ip = 0xFFFFFFFF8124218F, tid = 20714, pid = 20714, period = 600246 } [03:19:13.962517569] (+0.000356478) cycles: { }, { ip = 0xFFFFFFFF811A75DB, tid = 20714, pid = 20714, period = 1325731 } [03:19:13.969518008] (+0.007000439) cycles: { }, { ip = 0x34080917B2, tid = 20714, pid = 20714, period = 1144298 } The following members to the ctf-environment were decided to be added to distinguish and specify perf CTF data: - domain It says "kernel" because it contains a kernel trace (not to be confused with a user space like lttng-ust does) - tracer_name It says perf. This can be used to distinguish between lttng and perf CTF based trace. - version The kernel version from stream. In addition to release, this is what it looks like on a Debian kernel: release = "3.14-1-amd64"; version = "3.14.0"; [1] http://projects.eclipse.org/projects/tools.tracecompass Signed-off-by: Jiri Olsa <jolsa@kernel.org> Acked-by: Namhyung Kim <namhyung@kernel.org> Reviewed-by: David Ahern <dsahern@gmail.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jeremie Galarneau <jgalar@efficios.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Wang Nan <wangnan0@huawei.com> Link: http://lkml.kernel.org/r/1424470628-5969-4-git-send-email-jolsa@kernel.org Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/Documentation/perf-data.txt25
-rw-r--r--tools/perf/Documentation/perf.txt7
-rw-r--r--tools/perf/builtin-data.c44
-rw-r--r--tools/perf/config/Makefile1
-rw-r--r--tools/perf/util/Build2
-rw-r--r--tools/perf/util/data-convert-bt.c612
-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
9 files changed, 701 insertions, 1 deletions
diff --git a/tools/perf/Documentation/perf-data.txt b/tools/perf/Documentation/perf-data.txt
index b8c83947715c..be8fa1a0a97e 100644
--- a/tools/perf/Documentation/perf-data.txt
+++ b/tools/perf/Documentation/perf-data.txt
@@ -13,3 +13,28 @@ SYNOPSIS
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15Data file related processing. 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.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/builtin-data.c b/tools/perf/builtin-data.c
index 1eee97d020fa..9705ba7e4c16 100644
--- a/tools/perf/builtin-data.c
+++ b/tools/perf/builtin-data.c
@@ -3,6 +3,7 @@
3#include "perf.h" 3#include "perf.h"
4#include "debug.h" 4#include "debug.h"
5#include "parse-options.h" 5#include "parse-options.h"
6#include "data-convert-bt.h"
6 7
7typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix); 8typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix);
8 9
@@ -41,7 +42,50 @@ static void print_usage(void)
41 printf("\n"); 42 printf("\n");
42} 43}
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
44static struct data_cmd data_cmds[] = { 87static struct data_cmd data_cmds[] = {
88 { "convert", "converts data file between formats", cmd_data_convert },
45 { NULL }, 89 { NULL },
46}; 90};
47 91
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 6f129b0a9c64..c3570b5f3bf3 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -713,6 +713,7 @@ ifndef NO_LIBBABELTRACE
713 CFLAGS += -DHAVE_LIBBABELTRACE_SUPPORT $(LIBBABELTRACE_CFLAGS) 713 CFLAGS += -DHAVE_LIBBABELTRACE_SUPPORT $(LIBBABELTRACE_CFLAGS)
714 LDFLAGS += $(LIBBABELTRACE_LDFLAGS) 714 LDFLAGS += $(LIBBABELTRACE_LDFLAGS)
715 EXTLIBS += -lbabeltrace-ctf 715 EXTLIBS += -lbabeltrace-ctf
716 $(call detected,CONFIG_LIBBABELTRACE)
716 endif 717 endif
717endif 718endif
718 719
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..ff4826c1745f
--- /dev/null
+++ b/tools/perf/util/data-convert-bt.c
@@ -0,0 +1,612 @@
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, "ip", sample->ip);
151 if (ret)
152 return -1;
153 }
154
155 if (type & PERF_SAMPLE_TID) {
156 ret = value_set_s32(cw, event, "tid", sample->tid);
157 if (ret)
158 return -1;
159
160 ret = value_set_s32(cw, event, "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, "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, "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, "cpu", sample->cpu);
180 if (ret)
181 return -1;
182 }
183
184 if (type & PERF_SAMPLE_PERIOD) {
185 ret = value_set_u64(cw, event, "period", sample->period);
186 if (ret)
187 return -1;
188 }
189
190 if (type & PERF_SAMPLE_WEIGHT) {
191 ret = value_set_u64(cw, event, "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, "data_src", sample->data_src);
198 if (ret)
199 return -1;
200 }
201
202 if (type & PERF_SAMPLE_TRANSACTION) {
203 ret = value_set_u64(cw, event, "transaction", sample->transaction);
204 if (ret)
205 return -1;
206 }
207
208 return 0;
209}
210
211static int process_sample_event(struct perf_tool *tool,
212 union perf_event *_event __maybe_unused,
213 struct perf_sample *sample,
214 struct perf_evsel *evsel,
215 struct machine *machine __maybe_unused)
216{
217 struct convert *c = container_of(tool, struct convert, tool);
218 struct evsel_priv *priv = evsel->priv;
219 struct ctf_writer *cw = &c->writer;
220 struct bt_ctf_event_class *event_class;
221 struct bt_ctf_event *event;
222 int ret;
223
224 if (WARN_ONCE(!priv, "Failed to setup all events.\n"))
225 return 0;
226
227 event_class = priv->event_class;
228
229 /* update stats */
230 c->events_count++;
231 c->events_size += _event->header.size;
232
233 pr_time2(sample->time, "sample %" PRIu64 "\n", c->events_count);
234
235 event = bt_ctf_event_create(event_class);
236 if (!event) {
237 pr_err("Failed to create an CTF event\n");
238 return -1;
239 }
240
241 bt_ctf_clock_set_time(cw->clock, sample->time);
242
243 ret = add_generic_values(cw, event, evsel, sample);
244 if (ret)
245 return -1;
246
247 bt_ctf_stream_append_event(cw->stream, event);
248 bt_ctf_event_put(event);
249 return 0;
250}
251
252static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
253 struct bt_ctf_event_class *event_class)
254{
255 u64 type = evsel->attr.sample_type;
256
257 /*
258 * missing:
259 * PERF_SAMPLE_TIME - not needed as we have it in
260 * ctf event header
261 * PERF_SAMPLE_READ - TODO
262 * PERF_SAMPLE_CALLCHAIN - TODO
263 * PERF_SAMPLE_RAW - tracepoint fields are handled separately
264 * PERF_SAMPLE_BRANCH_STACK - TODO
265 * PERF_SAMPLE_REGS_USER - TODO
266 * PERF_SAMPLE_STACK_USER - TODO
267 */
268
269#define ADD_FIELD(cl, t, n) \
270 do { \
271 pr2(" field '%s'\n", n); \
272 if (bt_ctf_event_class_add_field(cl, t, n)) { \
273 pr_err("Failed to add field '%s;\n", n); \
274 return -1; \
275 } \
276 } while (0)
277
278 if (type & PERF_SAMPLE_IP)
279 ADD_FIELD(event_class, cw->data.u64_hex, "ip");
280
281 if (type & PERF_SAMPLE_TID) {
282 ADD_FIELD(event_class, cw->data.s32, "tid");
283 ADD_FIELD(event_class, cw->data.s32, "pid");
284 }
285
286 if ((type & PERF_SAMPLE_ID) ||
287 (type & PERF_SAMPLE_IDENTIFIER))
288 ADD_FIELD(event_class, cw->data.u64, "id");
289
290 if (type & PERF_SAMPLE_STREAM_ID)
291 ADD_FIELD(event_class, cw->data.u64, "stream_id");
292
293 if (type & PERF_SAMPLE_CPU)
294 ADD_FIELD(event_class, cw->data.u32, "cpu");
295
296 if (type & PERF_SAMPLE_PERIOD)
297 ADD_FIELD(event_class, cw->data.u64, "period");
298
299 if (type & PERF_SAMPLE_WEIGHT)
300 ADD_FIELD(event_class, cw->data.u64, "weight");
301
302 if (type & PERF_SAMPLE_DATA_SRC)
303 ADD_FIELD(event_class, cw->data.u64, "data_src");
304
305 if (type & PERF_SAMPLE_TRANSACTION)
306 ADD_FIELD(event_class, cw->data.u64, "transaction");
307
308#undef ADD_FIELD
309 return 0;
310}
311
312static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
313{
314 struct bt_ctf_event_class *event_class;
315 struct evsel_priv *priv;
316 const char *name = perf_evsel__name(evsel);
317 int ret;
318
319 pr("Adding event '%s' (type %d)\n", name, evsel->attr.type);
320
321 event_class = bt_ctf_event_class_create(name);
322 if (!event_class)
323 return -1;
324
325 ret = add_generic_types(cw, evsel, event_class);
326 if (ret)
327 goto err;
328
329 ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);
330 if (ret) {
331 pr("Failed to add event class into stream.\n");
332 goto err;
333 }
334
335 priv = malloc(sizeof(*priv));
336 if (!priv)
337 goto err;
338
339 priv->event_class = event_class;
340 evsel->priv = priv;
341 return 0;
342
343err:
344 bt_ctf_event_class_put(event_class);
345 pr_err("Failed to add event '%s'.\n", name);
346 return -1;
347}
348
349static int setup_events(struct ctf_writer *cw, struct perf_session *session)
350{
351 struct perf_evlist *evlist = session->evlist;
352 struct perf_evsel *evsel;
353 int ret;
354
355 evlist__for_each(evlist, evsel) {
356 ret = add_event(cw, evsel);
357 if (ret)
358 return ret;
359 }
360 return 0;
361}
362
363static int ctf_writer__setup_env(struct ctf_writer *cw,
364 struct perf_session *session)
365{
366 struct perf_header *header = &session->header;
367 struct bt_ctf_writer *writer = cw->writer;
368
369#define ADD(__n, __v) \
370do { \
371 if (bt_ctf_writer_add_environment_field(writer, __n, __v)) \
372 return -1; \
373} while (0)
374
375 ADD("host", header->env.hostname);
376 ADD("sysname", "Linux");
377 ADD("release", header->env.os_release);
378 ADD("version", header->env.version);
379 ADD("machine", header->env.arch);
380 ADD("domain", "kernel");
381 ADD("tracer_name", "perf");
382
383#undef ADD
384 return 0;
385}
386
387static int ctf_writer__setup_clock(struct ctf_writer *cw)
388{
389 struct bt_ctf_clock *clock = cw->clock;
390
391 bt_ctf_clock_set_description(clock, "perf clock");
392
393#define SET(__n, __v) \
394do { \
395 if (bt_ctf_clock_set_##__n(clock, __v)) \
396 return -1; \
397} while (0)
398
399 SET(frequency, 1000000000);
400 SET(offset_s, 0);
401 SET(offset, 0);
402 SET(precision, 10);
403 SET(is_absolute, 0);
404
405#undef SET
406 return 0;
407}
408
409static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex)
410{
411 struct bt_ctf_field_type *type;
412
413 type = bt_ctf_field_type_integer_create(size);
414 if (!type)
415 return NULL;
416
417 if (sign &&
418 bt_ctf_field_type_integer_set_signed(type, 1))
419 goto err;
420
421 if (hex &&
422 bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL))
423 goto err;
424
425 pr2("Created type: INTEGER %d-bit %ssigned %s\n",
426 size, sign ? "un" : "", hex ? "hex" : "");
427 return type;
428
429err:
430 bt_ctf_field_type_put(type);
431 return NULL;
432}
433
434static void ctf_writer__cleanup_data(struct ctf_writer *cw)
435{
436 unsigned int i;
437
438 for (i = 0; i < ARRAY_SIZE(cw->data.array); i++)
439 bt_ctf_field_type_put(cw->data.array[i]);
440}
441
442static int ctf_writer__init_data(struct ctf_writer *cw)
443{
444#define CREATE_INT_TYPE(type, size, sign, hex) \
445do { \
446 (type) = create_int_type(size, sign, hex); \
447 if (!(type)) \
448 goto err; \
449} while (0)
450
451 CREATE_INT_TYPE(cw->data.s64, 64, true, false);
452 CREATE_INT_TYPE(cw->data.u64, 64, false, false);
453 CREATE_INT_TYPE(cw->data.s32, 32, true, false);
454 CREATE_INT_TYPE(cw->data.u32, 32, false, false);
455 CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true);
456
457 cw->data.string = bt_ctf_field_type_string_create();
458 if (cw->data.string)
459 return 0;
460
461err:
462 ctf_writer__cleanup_data(cw);
463 pr_err("Failed to create data types.\n");
464 return -1;
465}
466
467static void ctf_writer__cleanup(struct ctf_writer *cw)
468{
469 ctf_writer__cleanup_data(cw);
470
471 bt_ctf_clock_put(cw->clock);
472 bt_ctf_stream_put(cw->stream);
473 bt_ctf_stream_class_put(cw->stream_class);
474 bt_ctf_writer_put(cw->writer);
475
476 /* and NULL all the pointers */
477 memset(cw, 0, sizeof(*cw));
478}
479
480static int ctf_writer__init(struct ctf_writer *cw, const char *path)
481{
482 struct bt_ctf_writer *writer;
483 struct bt_ctf_stream_class *stream_class;
484 struct bt_ctf_stream *stream;
485 struct bt_ctf_clock *clock;
486
487 /* CTF writer */
488 writer = bt_ctf_writer_create(path);
489 if (!writer)
490 goto err;
491
492 cw->writer = writer;
493
494 /* CTF clock */
495 clock = bt_ctf_clock_create("perf_clock");
496 if (!clock) {
497 pr("Failed to create CTF clock.\n");
498 goto err_cleanup;
499 }
500
501 cw->clock = clock;
502
503 if (ctf_writer__setup_clock(cw)) {
504 pr("Failed to setup CTF clock.\n");
505 goto err_cleanup;
506 }
507
508 /* CTF stream class */
509 stream_class = bt_ctf_stream_class_create("perf_stream");
510 if (!stream_class) {
511 pr("Failed to create CTF stream class.\n");
512 goto err_cleanup;
513 }
514
515 cw->stream_class = stream_class;
516
517 /* CTF clock stream setup */
518 if (bt_ctf_stream_class_set_clock(stream_class, clock)) {
519 pr("Failed to assign CTF clock to stream class.\n");
520 goto err_cleanup;
521 }
522
523 if (ctf_writer__init_data(cw))
524 goto err_cleanup;
525
526 /* CTF stream instance */
527 stream = bt_ctf_writer_create_stream(writer, stream_class);
528 if (!stream) {
529 pr("Failed to create CTF stream.\n");
530 goto err_cleanup;
531 }
532
533 cw->stream = stream;
534
535 /* CTF clock writer setup */
536 if (bt_ctf_writer_add_clock(writer, clock)) {
537 pr("Failed to assign CTF clock to writer.\n");
538 goto err_cleanup;
539 }
540
541 return 0;
542
543err_cleanup:
544 ctf_writer__cleanup(cw);
545err:
546 pr_err("Failed to setup CTF writer.\n");
547 return -1;
548}
549
550int bt_convert__perf2ctf(const char *input, const char *path)
551{
552 struct perf_session *session;
553 struct perf_data_file file = {
554 .path = input,
555 .mode = PERF_DATA_MODE_READ,
556 };
557 struct convert c = {
558 .tool = {
559 .sample = process_sample_event,
560 .mmap = perf_event__process_mmap,
561 .mmap2 = perf_event__process_mmap2,
562 .comm = perf_event__process_comm,
563 .exit = perf_event__process_exit,
564 .fork = perf_event__process_fork,
565 .lost = perf_event__process_lost,
566 .tracing_data = perf_event__process_tracing_data,
567 .build_id = perf_event__process_build_id,
568 .ordered_events = true,
569 .ordering_requires_timestamps = true,
570 },
571 };
572 struct ctf_writer *cw = &c.writer;
573 int err = -1;
574
575 /* CTF writer */
576 if (ctf_writer__init(cw, path))
577 return -1;
578
579 /* perf.data session */
580 session = perf_session__new(&file, 0, NULL);
581 if (!session)
582 goto free_writer;
583
584 /* CTF writer env/clock setup */
585 if (ctf_writer__setup_env(cw, session))
586 goto free_session;
587
588 /* CTF events setup */
589 if (setup_events(cw, session))
590 goto free_session;
591
592 err = perf_session__process_events(session, &c.tool);
593 if (!err)
594 err = bt_ctf_stream_flush(cw->stream);
595
596 fprintf(stderr,
597 "[ perf data convert: Converted '%s' into CTF data '%s' ]\n",
598 file.path, path);
599
600 fprintf(stderr,
601 "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples) ]\n",
602 (double) c.events_size / 1024.0 / 1024.0,
603 c.events_count);
604
605 /* its all good */
606free_session:
607 perf_session__delete(session);
608
609free_writer:
610 ctf_writer__cleanup(cw);
611 return err;
612}
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