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