perf data: Switch to multiple cpu stream files
[deliverable/linux.git] / tools / perf / util / data-convert-bt.c
CommitLineData
edbe9817
JO
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
90e129ff
SAS
41#define MAX_CPUS 4096
42
43struct ctf_stream {
44 struct bt_ctf_stream *stream;
45 int cpu;
46};
47
edbe9817
JO
48struct ctf_writer {
49 /* writer primitives */
90e129ff
SAS
50 struct bt_ctf_writer *writer;
51 struct ctf_stream **stream;
52 int stream_cnt;
53 struct bt_ctf_stream_class *stream_class;
54 struct bt_ctf_clock *clock;
edbe9817
JO
55
56 /* data types */
57 union {
58 struct {
59 struct bt_ctf_field_type *s64;
60 struct bt_ctf_field_type *u64;
61 struct bt_ctf_field_type *s32;
62 struct bt_ctf_field_type *u32;
63 struct bt_ctf_field_type *string;
64 struct bt_ctf_field_type *u64_hex;
65 };
66 struct bt_ctf_field_type *array[6];
67 } data;
68};
69
70struct convert {
71 struct perf_tool tool;
72 struct ctf_writer writer;
73
74 u64 events_size;
75 u64 events_count;
76};
77
78static int value_set(struct bt_ctf_field_type *type,
79 struct bt_ctf_event *event,
80 const char *name, u64 val)
81{
82 struct bt_ctf_field *field;
83 bool sign = bt_ctf_field_type_integer_get_signed(type);
84 int ret;
85
86 field = bt_ctf_field_create(type);
87 if (!field) {
88 pr_err("failed to create a field %s\n", name);
89 return -1;
90 }
91
92 if (sign) {
93 ret = bt_ctf_field_signed_integer_set_value(field, val);
94 if (ret) {
95 pr_err("failed to set field value %s\n", name);
96 goto err;
97 }
98 } else {
99 ret = bt_ctf_field_unsigned_integer_set_value(field, val);
100 if (ret) {
101 pr_err("failed to set field value %s\n", name);
102 goto err;
103 }
104 }
105
106 ret = bt_ctf_event_set_payload(event, name, field);
107 if (ret) {
108 pr_err("failed to set payload %s\n", name);
109 goto err;
110 }
111
112 pr2(" SET [%s = %" PRIu64 "]\n", name, val);
113
114err:
115 bt_ctf_field_put(field);
116 return ret;
117}
118
119#define __FUNC_VALUE_SET(_name, _val_type) \
120static __maybe_unused int value_set_##_name(struct ctf_writer *cw, \
121 struct bt_ctf_event *event, \
122 const char *name, \
123 _val_type val) \
124{ \
125 struct bt_ctf_field_type *type = cw->data._name; \
126 return value_set(type, event, name, (u64) val); \
127}
128
129#define FUNC_VALUE_SET(_name) __FUNC_VALUE_SET(_name, _name)
130
131FUNC_VALUE_SET(s32)
132FUNC_VALUE_SET(u32)
133FUNC_VALUE_SET(s64)
134FUNC_VALUE_SET(u64)
135__FUNC_VALUE_SET(u64_hex, u64)
136
69364727
SAS
137static struct bt_ctf_field_type*
138get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field)
139{
140 unsigned long flags = field->flags;
141
142 if (flags & FIELD_IS_STRING)
143 return cw->data.string;
144
145 if (!(flags & FIELD_IS_SIGNED)) {
146 /* unsigned long are mostly pointers */
147 if (flags & FIELD_IS_LONG || flags & FIELD_IS_POINTER)
148 return cw->data.u64_hex;
149 }
150
151 if (flags & FIELD_IS_SIGNED) {
152 if (field->size == 8)
153 return cw->data.s64;
154 else
155 return cw->data.s32;
156 }
157
158 if (field->size == 8)
159 return cw->data.u64;
160 else
161 return cw->data.u32;
162}
163
164static int add_tracepoint_field_value(struct ctf_writer *cw,
165 struct bt_ctf_event_class *event_class,
166 struct bt_ctf_event *event,
167 struct perf_sample *sample,
168 struct format_field *fmtf)
169{
170 struct bt_ctf_field_type *type;
171 struct bt_ctf_field *array_field;
172 struct bt_ctf_field *field;
173 const char *name = fmtf->name;
174 void *data = sample->raw_data;
175 unsigned long long value_int;
176 unsigned long flags = fmtf->flags;
177 unsigned int n_items;
178 unsigned int i;
179 unsigned int offset;
180 unsigned int len;
181 int ret;
182
183 offset = fmtf->offset;
184 len = fmtf->size;
185 if (flags & FIELD_IS_STRING)
186 flags &= ~FIELD_IS_ARRAY;
187
188 if (flags & FIELD_IS_DYNAMIC) {
189 unsigned long long tmp_val;
190
191 tmp_val = pevent_read_number(fmtf->event->pevent,
192 data + offset, len);
193 offset = tmp_val;
194 len = offset >> 16;
195 offset &= 0xffff;
196 }
197
198 if (flags & FIELD_IS_ARRAY) {
199
200 type = bt_ctf_event_class_get_field_by_name(
201 event_class, name);
202 array_field = bt_ctf_field_create(type);
203 bt_ctf_field_type_put(type);
204 if (!array_field) {
205 pr_err("Failed to create array type %s\n", name);
206 return -1;
207 }
208
209 len = fmtf->size / fmtf->arraylen;
210 n_items = fmtf->arraylen;
211 } else {
212 n_items = 1;
213 array_field = NULL;
214 }
215
216 type = get_tracepoint_field_type(cw, fmtf);
217
218 for (i = 0; i < n_items; i++) {
219 if (!(flags & FIELD_IS_STRING))
220 value_int = pevent_read_number(
221 fmtf->event->pevent,
222 data + offset + i * len, len);
223
224 if (flags & FIELD_IS_ARRAY)
225 field = bt_ctf_field_array_get_field(array_field, i);
226 else
227 field = bt_ctf_field_create(type);
228
229 if (!field) {
230 pr_err("failed to create a field %s\n", name);
231 return -1;
232 }
233
234 if (flags & FIELD_IS_STRING)
235 ret = bt_ctf_field_string_set_value(field,
236 data + offset + i * len);
237 else if (!(flags & FIELD_IS_SIGNED))
238 ret = bt_ctf_field_unsigned_integer_set_value(
239 field, value_int);
240 else
241 ret = bt_ctf_field_signed_integer_set_value(
242 field, value_int);
243 if (ret) {
244 pr_err("failed to set file value %s\n", name);
245 goto err_put_field;
246 }
247 if (!(flags & FIELD_IS_ARRAY)) {
248 ret = bt_ctf_event_set_payload(event, name, field);
249 if (ret) {
250 pr_err("failed to set payload %s\n", name);
251 goto err_put_field;
252 }
253 }
254 bt_ctf_field_put(field);
255 }
256 if (flags & FIELD_IS_ARRAY) {
257 ret = bt_ctf_event_set_payload(event, name, array_field);
258 if (ret) {
259 pr_err("Failed add payload array %s\n", name);
260 return -1;
261 }
262 bt_ctf_field_put(array_field);
263 }
264 return 0;
265
266err_put_field:
267 bt_ctf_field_put(field);
268 return -1;
269}
270
271static int add_tracepoint_fields_values(struct ctf_writer *cw,
272 struct bt_ctf_event_class *event_class,
273 struct bt_ctf_event *event,
274 struct format_field *fields,
275 struct perf_sample *sample)
276{
277 struct format_field *field;
278 int ret;
279
280 for (field = fields; field; field = field->next) {
281 ret = add_tracepoint_field_value(cw, event_class, event, sample,
282 field);
283 if (ret)
284 return -1;
285 }
286 return 0;
287}
288
289static int add_tracepoint_values(struct ctf_writer *cw,
290 struct bt_ctf_event_class *event_class,
291 struct bt_ctf_event *event,
292 struct perf_evsel *evsel,
293 struct perf_sample *sample)
294{
295 struct format_field *common_fields = evsel->tp_format->format.common_fields;
296 struct format_field *fields = evsel->tp_format->format.fields;
297 int ret;
298
299 ret = add_tracepoint_fields_values(cw, event_class, event,
300 common_fields, sample);
301 if (!ret)
302 ret = add_tracepoint_fields_values(cw, event_class, event,
303 fields, sample);
304
305 return ret;
306}
307
edbe9817
JO
308static int add_generic_values(struct ctf_writer *cw,
309 struct bt_ctf_event *event,
310 struct perf_evsel *evsel,
311 struct perf_sample *sample)
312{
313 u64 type = evsel->attr.sample_type;
314 int ret;
315
316 /*
317 * missing:
318 * PERF_SAMPLE_TIME - not needed as we have it in
319 * ctf event header
320 * PERF_SAMPLE_READ - TODO
321 * PERF_SAMPLE_CALLCHAIN - TODO
322 * PERF_SAMPLE_RAW - tracepoint fields are handled separately
323 * PERF_SAMPLE_BRANCH_STACK - TODO
324 * PERF_SAMPLE_REGS_USER - TODO
325 * PERF_SAMPLE_STACK_USER - TODO
326 */
327
328 if (type & PERF_SAMPLE_IP) {
54cf776a 329 ret = value_set_u64_hex(cw, event, "perf_ip", sample->ip);
edbe9817
JO
330 if (ret)
331 return -1;
332 }
333
334 if (type & PERF_SAMPLE_TID) {
54cf776a 335 ret = value_set_s32(cw, event, "perf_tid", sample->tid);
edbe9817
JO
336 if (ret)
337 return -1;
338
54cf776a 339 ret = value_set_s32(cw, event, "perf_pid", sample->pid);
edbe9817
JO
340 if (ret)
341 return -1;
342 }
343
344 if ((type & PERF_SAMPLE_ID) ||
345 (type & PERF_SAMPLE_IDENTIFIER)) {
54cf776a 346 ret = value_set_u64(cw, event, "perf_id", sample->id);
edbe9817
JO
347 if (ret)
348 return -1;
349 }
350
351 if (type & PERF_SAMPLE_STREAM_ID) {
54cf776a 352 ret = value_set_u64(cw, event, "perf_stream_id", sample->stream_id);
edbe9817
JO
353 if (ret)
354 return -1;
355 }
356
edbe9817 357 if (type & PERF_SAMPLE_PERIOD) {
54cf776a 358 ret = value_set_u64(cw, event, "perf_period", sample->period);
edbe9817
JO
359 if (ret)
360 return -1;
361 }
362
363 if (type & PERF_SAMPLE_WEIGHT) {
54cf776a 364 ret = value_set_u64(cw, event, "perf_weight", sample->weight);
edbe9817
JO
365 if (ret)
366 return -1;
367 }
368
369 if (type & PERF_SAMPLE_DATA_SRC) {
54cf776a
SAS
370 ret = value_set_u64(cw, event, "perf_data_src",
371 sample->data_src);
edbe9817
JO
372 if (ret)
373 return -1;
374 }
375
376 if (type & PERF_SAMPLE_TRANSACTION) {
54cf776a
SAS
377 ret = value_set_u64(cw, event, "perf_transaction",
378 sample->transaction);
edbe9817
JO
379 if (ret)
380 return -1;
381 }
382
383 return 0;
384}
385
90e129ff
SAS
386static int ctf_stream__flush(struct ctf_stream *cs)
387{
388 int err = 0;
389
390 if (cs) {
391 err = bt_ctf_stream_flush(cs->stream);
392 if (err)
393 pr_err("CTF stream %d flush failed\n", cs->cpu);
394
395 pr("Flush stream for cpu %d\n", cs->cpu);
396 }
397
398 return err;
399}
400
401static struct ctf_stream *ctf_stream__create(struct ctf_writer *cw, int cpu)
402{
403 struct ctf_stream *cs;
404 struct bt_ctf_field *pkt_ctx = NULL;
405 struct bt_ctf_field *cpu_field = NULL;
406 struct bt_ctf_stream *stream = NULL;
407 int ret;
408
409 cs = zalloc(sizeof(*cs));
410 if (!cs) {
411 pr_err("Failed to allocate ctf stream\n");
412 return NULL;
413 }
414
415 stream = bt_ctf_writer_create_stream(cw->writer, cw->stream_class);
416 if (!stream) {
417 pr_err("Failed to create CTF stream\n");
418 goto out;
419 }
420
421 pkt_ctx = bt_ctf_stream_get_packet_context(stream);
422 if (!pkt_ctx) {
423 pr_err("Failed to obtain packet context\n");
424 goto out;
425 }
426
427 cpu_field = bt_ctf_field_structure_get_field(pkt_ctx, "cpu_id");
428 bt_ctf_field_put(pkt_ctx);
429 if (!cpu_field) {
430 pr_err("Failed to obtain cpu field\n");
431 goto out;
432 }
433
434 ret = bt_ctf_field_unsigned_integer_set_value(cpu_field, (u32) cpu);
435 if (ret) {
436 pr_err("Failed to update CPU number\n");
437 goto out;
438 }
439
440 bt_ctf_field_put(cpu_field);
441
442 cs->cpu = cpu;
443 cs->stream = stream;
444 return cs;
445
446out:
447 if (cpu_field)
448 bt_ctf_field_put(cpu_field);
449 if (stream)
450 bt_ctf_stream_put(stream);
451
452 free(cs);
453 return NULL;
454}
455
456static void ctf_stream__delete(struct ctf_stream *cs)
457{
458 if (cs) {
459 bt_ctf_stream_put(cs->stream);
460 free(cs);
461 }
462}
463
464static struct ctf_stream *ctf_stream(struct ctf_writer *cw, int cpu)
465{
466 struct ctf_stream *cs = cw->stream[cpu];
467
468 if (!cs) {
469 cs = ctf_stream__create(cw, cpu);
470 cw->stream[cpu] = cs;
471 }
472
473 return cs;
474}
475
476static int get_sample_cpu(struct ctf_writer *cw, struct perf_sample *sample,
477 struct perf_evsel *evsel)
478{
479 int cpu = 0;
480
481 if (evsel->attr.sample_type & PERF_SAMPLE_CPU)
482 cpu = sample->cpu;
483
484 if (cpu > cw->stream_cnt) {
485 pr_err("Event was recorded for CPU %d, limit is at %d.\n",
486 cpu, cw->stream_cnt);
487 cpu = 0;
488 }
489
490 return cpu;
491}
492
edbe9817
JO
493static int process_sample_event(struct perf_tool *tool,
494 union perf_event *_event __maybe_unused,
495 struct perf_sample *sample,
496 struct perf_evsel *evsel,
497 struct machine *machine __maybe_unused)
498{
499 struct convert *c = container_of(tool, struct convert, tool);
500 struct evsel_priv *priv = evsel->priv;
501 struct ctf_writer *cw = &c->writer;
90e129ff 502 struct ctf_stream *cs;
edbe9817
JO
503 struct bt_ctf_event_class *event_class;
504 struct bt_ctf_event *event;
505 int ret;
506
507 if (WARN_ONCE(!priv, "Failed to setup all events.\n"))
508 return 0;
509
510 event_class = priv->event_class;
511
512 /* update stats */
513 c->events_count++;
514 c->events_size += _event->header.size;
515
516 pr_time2(sample->time, "sample %" PRIu64 "\n", c->events_count);
517
518 event = bt_ctf_event_create(event_class);
519 if (!event) {
520 pr_err("Failed to create an CTF event\n");
521 return -1;
522 }
523
524 bt_ctf_clock_set_time(cw->clock, sample->time);
525
526 ret = add_generic_values(cw, event, evsel, sample);
527 if (ret)
528 return -1;
529
69364727
SAS
530 if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
531 ret = add_tracepoint_values(cw, event_class, event,
532 evsel, sample);
533 if (ret)
534 return -1;
535 }
536
90e129ff
SAS
537 cs = ctf_stream(cw, get_sample_cpu(cw, sample, evsel));
538 if (cs)
539 bt_ctf_stream_append_event(cs->stream, event);
540
edbe9817 541 bt_ctf_event_put(event);
90e129ff 542 return cs ? 0 : -1;
edbe9817
JO
543}
544
69364727
SAS
545static int add_tracepoint_fields_types(struct ctf_writer *cw,
546 struct format_field *fields,
547 struct bt_ctf_event_class *event_class)
548{
549 struct format_field *field;
550 int ret;
551
552 for (field = fields; field; field = field->next) {
553 struct bt_ctf_field_type *type;
554 unsigned long flags = field->flags;
555
556 pr2(" field '%s'\n", field->name);
557
558 type = get_tracepoint_field_type(cw, field);
559 if (!type)
560 return -1;
561
562 /*
563 * A string is an array of chars. For this we use the string
564 * type and don't care that it is an array. What we don't
565 * support is an array of strings.
566 */
567 if (flags & FIELD_IS_STRING)
568 flags &= ~FIELD_IS_ARRAY;
569
570 if (flags & FIELD_IS_ARRAY)
571 type = bt_ctf_field_type_array_create(type, field->arraylen);
572
573 ret = bt_ctf_event_class_add_field(event_class, type,
574 field->name);
575
576 if (flags & FIELD_IS_ARRAY)
577 bt_ctf_field_type_put(type);
578
579 if (ret) {
580 pr_err("Failed to add field '%s\n", field->name);
581 return -1;
582 }
583 }
584
585 return 0;
586}
587
588static int add_tracepoint_types(struct ctf_writer *cw,
589 struct perf_evsel *evsel,
590 struct bt_ctf_event_class *class)
591{
592 struct format_field *common_fields = evsel->tp_format->format.common_fields;
593 struct format_field *fields = evsel->tp_format->format.fields;
594 int ret;
595
596 ret = add_tracepoint_fields_types(cw, common_fields, class);
597 if (!ret)
598 ret = add_tracepoint_fields_types(cw, fields, class);
599
600 return ret;
601}
602
edbe9817
JO
603static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
604 struct bt_ctf_event_class *event_class)
605{
606 u64 type = evsel->attr.sample_type;
607
608 /*
609 * missing:
610 * PERF_SAMPLE_TIME - not needed as we have it in
611 * ctf event header
612 * PERF_SAMPLE_READ - TODO
613 * PERF_SAMPLE_CALLCHAIN - TODO
614 * PERF_SAMPLE_RAW - tracepoint fields are handled separately
615 * PERF_SAMPLE_BRANCH_STACK - TODO
616 * PERF_SAMPLE_REGS_USER - TODO
617 * PERF_SAMPLE_STACK_USER - TODO
618 */
619
620#define ADD_FIELD(cl, t, n) \
621 do { \
622 pr2(" field '%s'\n", n); \
623 if (bt_ctf_event_class_add_field(cl, t, n)) { \
624 pr_err("Failed to add field '%s;\n", n); \
625 return -1; \
626 } \
627 } while (0)
628
629 if (type & PERF_SAMPLE_IP)
54cf776a 630 ADD_FIELD(event_class, cw->data.u64_hex, "perf_ip");
edbe9817
JO
631
632 if (type & PERF_SAMPLE_TID) {
54cf776a
SAS
633 ADD_FIELD(event_class, cw->data.s32, "perf_tid");
634 ADD_FIELD(event_class, cw->data.s32, "perf_pid");
edbe9817
JO
635 }
636
637 if ((type & PERF_SAMPLE_ID) ||
638 (type & PERF_SAMPLE_IDENTIFIER))
54cf776a 639 ADD_FIELD(event_class, cw->data.u64, "perf_id");
edbe9817
JO
640
641 if (type & PERF_SAMPLE_STREAM_ID)
54cf776a 642 ADD_FIELD(event_class, cw->data.u64, "perf_stream_id");
edbe9817 643
edbe9817 644 if (type & PERF_SAMPLE_PERIOD)
54cf776a 645 ADD_FIELD(event_class, cw->data.u64, "perf_period");
edbe9817
JO
646
647 if (type & PERF_SAMPLE_WEIGHT)
54cf776a 648 ADD_FIELD(event_class, cw->data.u64, "perf_weight");
edbe9817
JO
649
650 if (type & PERF_SAMPLE_DATA_SRC)
54cf776a 651 ADD_FIELD(event_class, cw->data.u64, "perf_data_src");
edbe9817
JO
652
653 if (type & PERF_SAMPLE_TRANSACTION)
54cf776a 654 ADD_FIELD(event_class, cw->data.u64, "perf_transaction");
edbe9817
JO
655
656#undef ADD_FIELD
657 return 0;
658}
659
660static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
661{
662 struct bt_ctf_event_class *event_class;
663 struct evsel_priv *priv;
664 const char *name = perf_evsel__name(evsel);
665 int ret;
666
667 pr("Adding event '%s' (type %d)\n", name, evsel->attr.type);
668
669 event_class = bt_ctf_event_class_create(name);
670 if (!event_class)
671 return -1;
672
673 ret = add_generic_types(cw, evsel, event_class);
674 if (ret)
675 goto err;
676
69364727
SAS
677 if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
678 ret = add_tracepoint_types(cw, evsel, event_class);
679 if (ret)
680 goto err;
681 }
682
edbe9817
JO
683 ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);
684 if (ret) {
685 pr("Failed to add event class into stream.\n");
686 goto err;
687 }
688
689 priv = malloc(sizeof(*priv));
690 if (!priv)
691 goto err;
692
693 priv->event_class = event_class;
694 evsel->priv = priv;
695 return 0;
696
697err:
698 bt_ctf_event_class_put(event_class);
699 pr_err("Failed to add event '%s'.\n", name);
700 return -1;
701}
702
703static int setup_events(struct ctf_writer *cw, struct perf_session *session)
704{
705 struct perf_evlist *evlist = session->evlist;
706 struct perf_evsel *evsel;
707 int ret;
708
709 evlist__for_each(evlist, evsel) {
710 ret = add_event(cw, evsel);
711 if (ret)
712 return ret;
713 }
714 return 0;
715}
716
90e129ff
SAS
717static int setup_streams(struct ctf_writer *cw, struct perf_session *session)
718{
719 struct ctf_stream **stream;
720 struct perf_header *ph = &session->header;
721 int ncpus;
722
723 /*
724 * Try to get the number of cpus used in the data file,
725 * if not present fallback to the MAX_CPUS.
726 */
727 ncpus = ph->env.nr_cpus_avail ?: MAX_CPUS;
728
729 stream = zalloc(sizeof(*stream) * ncpus);
730 if (!stream) {
731 pr_err("Failed to allocate streams.\n");
732 return -ENOMEM;
733 }
734
735 cw->stream = stream;
736 cw->stream_cnt = ncpus;
737 return 0;
738}
739
740static void free_streams(struct ctf_writer *cw)
741{
742 int cpu;
743
744 for (cpu = 0; cpu < cw->stream_cnt; cpu++)
745 ctf_stream__delete(cw->stream[cpu]);
746
747 free(cw->stream);
748}
749
edbe9817
JO
750static int ctf_writer__setup_env(struct ctf_writer *cw,
751 struct perf_session *session)
752{
753 struct perf_header *header = &session->header;
754 struct bt_ctf_writer *writer = cw->writer;
755
756#define ADD(__n, __v) \
757do { \
758 if (bt_ctf_writer_add_environment_field(writer, __n, __v)) \
759 return -1; \
760} while (0)
761
762 ADD("host", header->env.hostname);
763 ADD("sysname", "Linux");
764 ADD("release", header->env.os_release);
765 ADD("version", header->env.version);
766 ADD("machine", header->env.arch);
767 ADD("domain", "kernel");
768 ADD("tracer_name", "perf");
769
770#undef ADD
771 return 0;
772}
773
774static int ctf_writer__setup_clock(struct ctf_writer *cw)
775{
776 struct bt_ctf_clock *clock = cw->clock;
777
778 bt_ctf_clock_set_description(clock, "perf clock");
779
780#define SET(__n, __v) \
781do { \
782 if (bt_ctf_clock_set_##__n(clock, __v)) \
783 return -1; \
784} while (0)
785
786 SET(frequency, 1000000000);
787 SET(offset_s, 0);
788 SET(offset, 0);
789 SET(precision, 10);
790 SET(is_absolute, 0);
791
792#undef SET
793 return 0;
794}
795
796static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex)
797{
798 struct bt_ctf_field_type *type;
799
800 type = bt_ctf_field_type_integer_create(size);
801 if (!type)
802 return NULL;
803
804 if (sign &&
805 bt_ctf_field_type_integer_set_signed(type, 1))
806 goto err;
807
808 if (hex &&
809 bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL))
810 goto err;
811
812 pr2("Created type: INTEGER %d-bit %ssigned %s\n",
813 size, sign ? "un" : "", hex ? "hex" : "");
814 return type;
815
816err:
817 bt_ctf_field_type_put(type);
818 return NULL;
819}
820
821static void ctf_writer__cleanup_data(struct ctf_writer *cw)
822{
823 unsigned int i;
824
825 for (i = 0; i < ARRAY_SIZE(cw->data.array); i++)
826 bt_ctf_field_type_put(cw->data.array[i]);
827}
828
829static int ctf_writer__init_data(struct ctf_writer *cw)
830{
831#define CREATE_INT_TYPE(type, size, sign, hex) \
832do { \
833 (type) = create_int_type(size, sign, hex); \
834 if (!(type)) \
835 goto err; \
836} while (0)
837
838 CREATE_INT_TYPE(cw->data.s64, 64, true, false);
839 CREATE_INT_TYPE(cw->data.u64, 64, false, false);
840 CREATE_INT_TYPE(cw->data.s32, 32, true, false);
841 CREATE_INT_TYPE(cw->data.u32, 32, false, false);
842 CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true);
843
844 cw->data.string = bt_ctf_field_type_string_create();
845 if (cw->data.string)
846 return 0;
847
848err:
849 ctf_writer__cleanup_data(cw);
850 pr_err("Failed to create data types.\n");
851 return -1;
852}
853
854static void ctf_writer__cleanup(struct ctf_writer *cw)
855{
856 ctf_writer__cleanup_data(cw);
857
858 bt_ctf_clock_put(cw->clock);
90e129ff 859 free_streams(cw);
edbe9817
JO
860 bt_ctf_stream_class_put(cw->stream_class);
861 bt_ctf_writer_put(cw->writer);
862
863 /* and NULL all the pointers */
864 memset(cw, 0, sizeof(*cw));
865}
866
867static int ctf_writer__init(struct ctf_writer *cw, const char *path)
868{
869 struct bt_ctf_writer *writer;
870 struct bt_ctf_stream_class *stream_class;
edbe9817 871 struct bt_ctf_clock *clock;
90e129ff
SAS
872 struct bt_ctf_field_type *pkt_ctx_type;
873 int ret;
edbe9817
JO
874
875 /* CTF writer */
876 writer = bt_ctf_writer_create(path);
877 if (!writer)
878 goto err;
879
880 cw->writer = writer;
881
882 /* CTF clock */
883 clock = bt_ctf_clock_create("perf_clock");
884 if (!clock) {
885 pr("Failed to create CTF clock.\n");
886 goto err_cleanup;
887 }
888
889 cw->clock = clock;
890
891 if (ctf_writer__setup_clock(cw)) {
892 pr("Failed to setup CTF clock.\n");
893 goto err_cleanup;
894 }
895
896 /* CTF stream class */
897 stream_class = bt_ctf_stream_class_create("perf_stream");
898 if (!stream_class) {
899 pr("Failed to create CTF stream class.\n");
900 goto err_cleanup;
901 }
902
903 cw->stream_class = stream_class;
904
905 /* CTF clock stream setup */
906 if (bt_ctf_stream_class_set_clock(stream_class, clock)) {
907 pr("Failed to assign CTF clock to stream class.\n");
908 goto err_cleanup;
909 }
910
911 if (ctf_writer__init_data(cw))
912 goto err_cleanup;
913
90e129ff
SAS
914 /* Add cpu_id for packet context */
915 pkt_ctx_type = bt_ctf_stream_class_get_packet_context_type(stream_class);
916 if (!pkt_ctx_type)
edbe9817 917 goto err_cleanup;
edbe9817 918
90e129ff
SAS
919 ret = bt_ctf_field_type_structure_add_field(pkt_ctx_type, cw->data.u32, "cpu_id");
920 bt_ctf_field_type_put(pkt_ctx_type);
921 if (ret)
922 goto err_cleanup;
edbe9817
JO
923
924 /* CTF clock writer setup */
925 if (bt_ctf_writer_add_clock(writer, clock)) {
926 pr("Failed to assign CTF clock to writer.\n");
927 goto err_cleanup;
928 }
929
930 return 0;
931
932err_cleanup:
933 ctf_writer__cleanup(cw);
934err:
935 pr_err("Failed to setup CTF writer.\n");
936 return -1;
937}
938
90e129ff
SAS
939static int ctf_writer__flush_streams(struct ctf_writer *cw)
940{
941 int cpu, ret = 0;
942
943 for (cpu = 0; cpu < cw->stream_cnt && !ret; cpu++)
944 ret = ctf_stream__flush(cw->stream[cpu]);
945
946 return ret;
947}
948
bd05954b 949int bt_convert__perf2ctf(const char *input, const char *path, bool force)
edbe9817
JO
950{
951 struct perf_session *session;
952 struct perf_data_file file = {
953 .path = input,
954 .mode = PERF_DATA_MODE_READ,
bd05954b 955 .force = force,
edbe9817
JO
956 };
957 struct convert c = {
958 .tool = {
959 .sample = process_sample_event,
960 .mmap = perf_event__process_mmap,
961 .mmap2 = perf_event__process_mmap2,
962 .comm = perf_event__process_comm,
963 .exit = perf_event__process_exit,
964 .fork = perf_event__process_fork,
965 .lost = perf_event__process_lost,
966 .tracing_data = perf_event__process_tracing_data,
967 .build_id = perf_event__process_build_id,
968 .ordered_events = true,
969 .ordering_requires_timestamps = true,
970 },
971 };
972 struct ctf_writer *cw = &c.writer;
973 int err = -1;
974
975 /* CTF writer */
976 if (ctf_writer__init(cw, path))
977 return -1;
978
979 /* perf.data session */
b7b61cbe 980 session = perf_session__new(&file, 0, &c.tool);
edbe9817
JO
981 if (!session)
982 goto free_writer;
983
984 /* CTF writer env/clock setup */
985 if (ctf_writer__setup_env(cw, session))
986 goto free_session;
987
988 /* CTF events setup */
989 if (setup_events(cw, session))
990 goto free_session;
991
90e129ff
SAS
992 if (setup_streams(cw, session))
993 goto free_session;
994
b7b61cbe 995 err = perf_session__process_events(session);
edbe9817 996 if (!err)
90e129ff 997 err = ctf_writer__flush_streams(cw);
c2141055
HK
998 else
999 pr_err("Error during conversion.\n");
edbe9817
JO
1000
1001 fprintf(stderr,
1002 "[ perf data convert: Converted '%s' into CTF data '%s' ]\n",
1003 file.path, path);
1004
1005 fprintf(stderr,
1006 "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples) ]\n",
1007 (double) c.events_size / 1024.0 / 1024.0,
1008 c.events_count);
1009
edbe9817 1010 perf_session__delete(session);
c2141055 1011 ctf_writer__cleanup(cw);
edbe9817 1012
c2141055
HK
1013 return err;
1014
1015free_session:
1016 perf_session__delete(session);
edbe9817
JO
1017free_writer:
1018 ctf_writer__cleanup(cw);
c2141055 1019 pr_err("Error during conversion setup.\n");
edbe9817
JO
1020 return err;
1021}
This page took 0.066891 seconds and 5 git commands to generate.