Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / tools / perf / util / data-convert-bt.c
1 /*
2  * CTF writing support via babeltrace.
3  *
4  * Copyright (C) 2014, Jiri Olsa <jolsa@redhat.com>
5  * Copyright (C) 2014, Sebastian Andrzej Siewior <bigeasy@linutronix.de>
6  *
7  * Released under the GPL v2. (and only v2, not any later version)
8  */
9
10 #include <linux/compiler.h>
11 #include <babeltrace/ctf-writer/writer.h>
12 #include <babeltrace/ctf-writer/clock.h>
13 #include <babeltrace/ctf-writer/stream.h>
14 #include <babeltrace/ctf-writer/event.h>
15 #include <babeltrace/ctf-writer/event-types.h>
16 #include <babeltrace/ctf-writer/event-fields.h>
17 #include <babeltrace/ctf/events.h>
18 #include <traceevent/event-parse.h>
19 #include "asm/bug.h"
20 #include "data-convert-bt.h"
21 #include "session.h"
22 #include "util.h"
23 #include "debug.h"
24 #include "tool.h"
25 #include "evlist.h"
26 #include "evsel.h"
27 #include "machine.h"
28
29 #define pr_N(n, fmt, ...) \
30         eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__)
31
32 #define pr(fmt, ...)  pr_N(1, pr_fmt(fmt), ##__VA_ARGS__)
33 #define pr2(fmt, ...) pr_N(2, pr_fmt(fmt), ##__VA_ARGS__)
34
35 #define pr_time2(t, fmt, ...) pr_time_N(2, debug_data_convert, t, pr_fmt(fmt), ##__VA_ARGS__)
36
37 struct evsel_priv {
38         struct bt_ctf_event_class *event_class;
39 };
40
41 struct ctf_writer {
42         /* writer primitives */
43         struct bt_ctf_writer            *writer;
44         struct bt_ctf_stream            *stream;
45         struct bt_ctf_stream_class      *stream_class;
46         struct bt_ctf_clock             *clock;
47
48         /* data types */
49         union {
50                 struct {
51                         struct bt_ctf_field_type        *s64;
52                         struct bt_ctf_field_type        *u64;
53                         struct bt_ctf_field_type        *s32;
54                         struct bt_ctf_field_type        *u32;
55                         struct bt_ctf_field_type        *string;
56                         struct bt_ctf_field_type        *u64_hex;
57                 };
58                 struct bt_ctf_field_type *array[6];
59         } data;
60 };
61
62 struct convert {
63         struct perf_tool        tool;
64         struct ctf_writer       writer;
65
66         u64                     events_size;
67         u64                     events_count;
68 };
69
70 static int value_set(struct bt_ctf_field_type *type,
71                      struct bt_ctf_event *event,
72                      const char *name, u64 val)
73 {
74         struct bt_ctf_field *field;
75         bool sign = bt_ctf_field_type_integer_get_signed(type);
76         int ret;
77
78         field = bt_ctf_field_create(type);
79         if (!field) {
80                 pr_err("failed to create a field %s\n", name);
81                 return -1;
82         }
83
84         if (sign) {
85                 ret = bt_ctf_field_signed_integer_set_value(field, val);
86                 if (ret) {
87                         pr_err("failed to set field value %s\n", name);
88                         goto err;
89                 }
90         } else {
91                 ret = bt_ctf_field_unsigned_integer_set_value(field, val);
92                 if (ret) {
93                         pr_err("failed to set field value %s\n", name);
94                         goto err;
95                 }
96         }
97
98         ret = bt_ctf_event_set_payload(event, name, field);
99         if (ret) {
100                 pr_err("failed to set payload %s\n", name);
101                 goto err;
102         }
103
104         pr2("  SET [%s = %" PRIu64 "]\n", name, val);
105
106 err:
107         bt_ctf_field_put(field);
108         return ret;
109 }
110
111 #define __FUNC_VALUE_SET(_name, _val_type)                              \
112 static __maybe_unused int value_set_##_name(struct ctf_writer *cw,      \
113                              struct bt_ctf_event *event,                \
114                              const char *name,                          \
115                              _val_type val)                             \
116 {                                                                       \
117         struct bt_ctf_field_type *type = cw->data._name;                \
118         return value_set(type, event, name, (u64) val);                 \
119 }
120
121 #define FUNC_VALUE_SET(_name) __FUNC_VALUE_SET(_name, _name)
122
123 FUNC_VALUE_SET(s32)
124 FUNC_VALUE_SET(u32)
125 FUNC_VALUE_SET(s64)
126 FUNC_VALUE_SET(u64)
127 __FUNC_VALUE_SET(u64_hex, u64)
128
129 static struct bt_ctf_field_type*
130 get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field)
131 {
132         unsigned long flags = field->flags;
133
134         if (flags & FIELD_IS_STRING)
135                 return cw->data.string;
136
137         if (!(flags & FIELD_IS_SIGNED)) {
138                 /* unsigned long are mostly pointers */
139                 if (flags & FIELD_IS_LONG || flags & FIELD_IS_POINTER)
140                         return cw->data.u64_hex;
141         }
142
143         if (flags & FIELD_IS_SIGNED) {
144                 if (field->size == 8)
145                         return cw->data.s64;
146                 else
147                         return cw->data.s32;
148         }
149
150         if (field->size == 8)
151                 return cw->data.u64;
152         else
153                 return cw->data.u32;
154 }
155
156 static int add_tracepoint_field_value(struct ctf_writer *cw,
157                                       struct bt_ctf_event_class *event_class,
158                                       struct bt_ctf_event *event,
159                                       struct perf_sample *sample,
160                                       struct format_field *fmtf)
161 {
162         struct bt_ctf_field_type *type;
163         struct bt_ctf_field *array_field;
164         struct bt_ctf_field *field;
165         const char *name = fmtf->name;
166         void *data = sample->raw_data;
167         unsigned long long value_int;
168         unsigned long flags = fmtf->flags;
169         unsigned int n_items;
170         unsigned int i;
171         unsigned int offset;
172         unsigned int len;
173         int ret;
174
175         offset = fmtf->offset;
176         len = fmtf->size;
177         if (flags & FIELD_IS_STRING)
178                 flags &= ~FIELD_IS_ARRAY;
179
180         if (flags & FIELD_IS_DYNAMIC) {
181                 unsigned long long tmp_val;
182
183                 tmp_val = pevent_read_number(fmtf->event->pevent,
184                                 data + offset, len);
185                 offset = tmp_val;
186                 len = offset >> 16;
187                 offset &= 0xffff;
188         }
189
190         if (flags & FIELD_IS_ARRAY) {
191
192                 type = bt_ctf_event_class_get_field_by_name(
193                                 event_class, name);
194                 array_field = bt_ctf_field_create(type);
195                 bt_ctf_field_type_put(type);
196                 if (!array_field) {
197                         pr_err("Failed to create array type %s\n", name);
198                         return -1;
199                 }
200
201                 len = fmtf->size / fmtf->arraylen;
202                 n_items = fmtf->arraylen;
203         } else {
204                 n_items = 1;
205                 array_field = NULL;
206         }
207
208         type = get_tracepoint_field_type(cw, fmtf);
209
210         for (i = 0; i < n_items; i++) {
211                 if (!(flags & FIELD_IS_STRING))
212                         value_int = pevent_read_number(
213                                         fmtf->event->pevent,
214                                         data + offset + i * len, len);
215
216                 if (flags & FIELD_IS_ARRAY)
217                         field = bt_ctf_field_array_get_field(array_field, i);
218                 else
219                         field = bt_ctf_field_create(type);
220
221                 if (!field) {
222                         pr_err("failed to create a field %s\n", name);
223                         return -1;
224                 }
225
226                 if (flags & FIELD_IS_STRING)
227                         ret = bt_ctf_field_string_set_value(field,
228                                         data + offset + i * len);
229                 else if (!(flags & FIELD_IS_SIGNED))
230                         ret = bt_ctf_field_unsigned_integer_set_value(
231                                         field, value_int);
232                 else
233                         ret = bt_ctf_field_signed_integer_set_value(
234                                         field, value_int);
235                 if (ret) {
236                         pr_err("failed to set file value %s\n", name);
237                         goto err_put_field;
238                 }
239                 if (!(flags & FIELD_IS_ARRAY)) {
240                         ret = bt_ctf_event_set_payload(event, name, field);
241                         if (ret) {
242                                 pr_err("failed to set payload %s\n", name);
243                                 goto err_put_field;
244                         }
245                 }
246                 bt_ctf_field_put(field);
247         }
248         if (flags & FIELD_IS_ARRAY) {
249                 ret = bt_ctf_event_set_payload(event, name, array_field);
250                 if (ret) {
251                         pr_err("Failed add payload array %s\n", name);
252                         return -1;
253                 }
254                 bt_ctf_field_put(array_field);
255         }
256         return 0;
257
258 err_put_field:
259         bt_ctf_field_put(field);
260         return -1;
261 }
262
263 static int add_tracepoint_fields_values(struct ctf_writer *cw,
264                                         struct bt_ctf_event_class *event_class,
265                                         struct bt_ctf_event *event,
266                                         struct format_field *fields,
267                                         struct perf_sample *sample)
268 {
269         struct format_field *field;
270         int ret;
271
272         for (field = fields; field; field = field->next) {
273                 ret = add_tracepoint_field_value(cw, event_class, event, sample,
274                                 field);
275                 if (ret)
276                         return -1;
277         }
278         return 0;
279 }
280
281 static int add_tracepoint_values(struct ctf_writer *cw,
282                                  struct bt_ctf_event_class *event_class,
283                                  struct bt_ctf_event *event,
284                                  struct perf_evsel *evsel,
285                                  struct perf_sample *sample)
286 {
287         struct format_field *common_fields = evsel->tp_format->format.common_fields;
288         struct format_field *fields        = evsel->tp_format->format.fields;
289         int ret;
290
291         ret = add_tracepoint_fields_values(cw, event_class, event,
292                                            common_fields, sample);
293         if (!ret)
294                 ret = add_tracepoint_fields_values(cw, event_class, event,
295                                                    fields, sample);
296
297         return ret;
298 }
299
300 static int add_generic_values(struct ctf_writer *cw,
301                               struct bt_ctf_event *event,
302                               struct perf_evsel *evsel,
303                               struct perf_sample *sample)
304 {
305         u64 type = evsel->attr.sample_type;
306         int ret;
307
308         /*
309          * missing:
310          *   PERF_SAMPLE_TIME         - not needed as we have it in
311          *                              ctf event header
312          *   PERF_SAMPLE_READ         - TODO
313          *   PERF_SAMPLE_CALLCHAIN    - TODO
314          *   PERF_SAMPLE_RAW          - tracepoint fields are handled separately
315          *   PERF_SAMPLE_BRANCH_STACK - TODO
316          *   PERF_SAMPLE_REGS_USER    - TODO
317          *   PERF_SAMPLE_STACK_USER   - TODO
318          */
319
320         if (type & PERF_SAMPLE_IP) {
321                 ret = value_set_u64_hex(cw, event, "perf_ip", sample->ip);
322                 if (ret)
323                         return -1;
324         }
325
326         if (type & PERF_SAMPLE_TID) {
327                 ret = value_set_s32(cw, event, "perf_tid", sample->tid);
328                 if (ret)
329                         return -1;
330
331                 ret = value_set_s32(cw, event, "perf_pid", sample->pid);
332                 if (ret)
333                         return -1;
334         }
335
336         if ((type & PERF_SAMPLE_ID) ||
337             (type & PERF_SAMPLE_IDENTIFIER)) {
338                 ret = value_set_u64(cw, event, "perf_id", sample->id);
339                 if (ret)
340                         return -1;
341         }
342
343         if (type & PERF_SAMPLE_STREAM_ID) {
344                 ret = value_set_u64(cw, event, "perf_stream_id", sample->stream_id);
345                 if (ret)
346                         return -1;
347         }
348
349         if (type & PERF_SAMPLE_CPU) {
350                 ret = value_set_u32(cw, event, "perf_cpu", sample->cpu);
351                 if (ret)
352                         return -1;
353         }
354
355         if (type & PERF_SAMPLE_PERIOD) {
356                 ret = value_set_u64(cw, event, "perf_period", sample->period);
357                 if (ret)
358                         return -1;
359         }
360
361         if (type & PERF_SAMPLE_WEIGHT) {
362                 ret = value_set_u64(cw, event, "perf_weight", sample->weight);
363                 if (ret)
364                         return -1;
365         }
366
367         if (type & PERF_SAMPLE_DATA_SRC) {
368                 ret = value_set_u64(cw, event, "perf_data_src",
369                                 sample->data_src);
370                 if (ret)
371                         return -1;
372         }
373
374         if (type & PERF_SAMPLE_TRANSACTION) {
375                 ret = value_set_u64(cw, event, "perf_transaction",
376                                 sample->transaction);
377                 if (ret)
378                         return -1;
379         }
380
381         return 0;
382 }
383
384 static int process_sample_event(struct perf_tool *tool,
385                                 union perf_event *_event __maybe_unused,
386                                 struct perf_sample *sample,
387                                 struct perf_evsel *evsel,
388                                 struct machine *machine __maybe_unused)
389 {
390         struct convert *c = container_of(tool, struct convert, tool);
391         struct evsel_priv *priv = evsel->priv;
392         struct ctf_writer *cw = &c->writer;
393         struct bt_ctf_event_class *event_class;
394         struct bt_ctf_event *event;
395         int ret;
396
397         if (WARN_ONCE(!priv, "Failed to setup all events.\n"))
398                 return 0;
399
400         event_class = priv->event_class;
401
402         /* update stats */
403         c->events_count++;
404         c->events_size += _event->header.size;
405
406         pr_time2(sample->time, "sample %" PRIu64 "\n", c->events_count);
407
408         event = bt_ctf_event_create(event_class);
409         if (!event) {
410                 pr_err("Failed to create an CTF event\n");
411                 return -1;
412         }
413
414         bt_ctf_clock_set_time(cw->clock, sample->time);
415
416         ret = add_generic_values(cw, event, evsel, sample);
417         if (ret)
418                 return -1;
419
420         if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
421                 ret = add_tracepoint_values(cw, event_class, event,
422                                             evsel, sample);
423                 if (ret)
424                         return -1;
425         }
426
427         bt_ctf_stream_append_event(cw->stream, event);
428         bt_ctf_event_put(event);
429         return 0;
430 }
431
432 static int add_tracepoint_fields_types(struct ctf_writer *cw,
433                                        struct format_field *fields,
434                                        struct bt_ctf_event_class *event_class)
435 {
436         struct format_field *field;
437         int ret;
438
439         for (field = fields; field; field = field->next) {
440                 struct bt_ctf_field_type *type;
441                 unsigned long flags = field->flags;
442
443                 pr2("  field '%s'\n", field->name);
444
445                 type = get_tracepoint_field_type(cw, field);
446                 if (!type)
447                         return -1;
448
449                 /*
450                  * A string is an array of chars. For this we use the string
451                  * type and don't care that it is an array. What we don't
452                  * support is an array of strings.
453                  */
454                 if (flags & FIELD_IS_STRING)
455                         flags &= ~FIELD_IS_ARRAY;
456
457                 if (flags & FIELD_IS_ARRAY)
458                         type = bt_ctf_field_type_array_create(type, field->arraylen);
459
460                 ret = bt_ctf_event_class_add_field(event_class, type,
461                                 field->name);
462
463                 if (flags & FIELD_IS_ARRAY)
464                         bt_ctf_field_type_put(type);
465
466                 if (ret) {
467                         pr_err("Failed to add field '%s\n", field->name);
468                         return -1;
469                 }
470         }
471
472         return 0;
473 }
474
475 static int add_tracepoint_types(struct ctf_writer *cw,
476                                 struct perf_evsel *evsel,
477                                 struct bt_ctf_event_class *class)
478 {
479         struct format_field *common_fields = evsel->tp_format->format.common_fields;
480         struct format_field *fields        = evsel->tp_format->format.fields;
481         int ret;
482
483         ret = add_tracepoint_fields_types(cw, common_fields, class);
484         if (!ret)
485                 ret = add_tracepoint_fields_types(cw, fields, class);
486
487         return ret;
488 }
489
490 static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
491                              struct bt_ctf_event_class *event_class)
492 {
493         u64 type = evsel->attr.sample_type;
494
495         /*
496          * missing:
497          *   PERF_SAMPLE_TIME         - not needed as we have it in
498          *                              ctf event header
499          *   PERF_SAMPLE_READ         - TODO
500          *   PERF_SAMPLE_CALLCHAIN    - TODO
501          *   PERF_SAMPLE_RAW          - tracepoint fields are handled separately
502          *   PERF_SAMPLE_BRANCH_STACK - TODO
503          *   PERF_SAMPLE_REGS_USER    - TODO
504          *   PERF_SAMPLE_STACK_USER   - TODO
505          */
506
507 #define ADD_FIELD(cl, t, n)                                             \
508         do {                                                            \
509                 pr2("  field '%s'\n", n);                               \
510                 if (bt_ctf_event_class_add_field(cl, t, n)) {           \
511                         pr_err("Failed to add field '%s;\n", n);        \
512                         return -1;                                      \
513                 }                                                       \
514         } while (0)
515
516         if (type & PERF_SAMPLE_IP)
517                 ADD_FIELD(event_class, cw->data.u64_hex, "perf_ip");
518
519         if (type & PERF_SAMPLE_TID) {
520                 ADD_FIELD(event_class, cw->data.s32, "perf_tid");
521                 ADD_FIELD(event_class, cw->data.s32, "perf_pid");
522         }
523
524         if ((type & PERF_SAMPLE_ID) ||
525             (type & PERF_SAMPLE_IDENTIFIER))
526                 ADD_FIELD(event_class, cw->data.u64, "perf_id");
527
528         if (type & PERF_SAMPLE_STREAM_ID)
529                 ADD_FIELD(event_class, cw->data.u64, "perf_stream_id");
530
531         if (type & PERF_SAMPLE_CPU)
532                 ADD_FIELD(event_class, cw->data.u32, "perf_cpu");
533
534         if (type & PERF_SAMPLE_PERIOD)
535                 ADD_FIELD(event_class, cw->data.u64, "perf_period");
536
537         if (type & PERF_SAMPLE_WEIGHT)
538                 ADD_FIELD(event_class, cw->data.u64, "perf_weight");
539
540         if (type & PERF_SAMPLE_DATA_SRC)
541                 ADD_FIELD(event_class, cw->data.u64, "perf_data_src");
542
543         if (type & PERF_SAMPLE_TRANSACTION)
544                 ADD_FIELD(event_class, cw->data.u64, "perf_transaction");
545
546 #undef ADD_FIELD
547         return 0;
548 }
549
550 static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
551 {
552         struct bt_ctf_event_class *event_class;
553         struct evsel_priv *priv;
554         const char *name = perf_evsel__name(evsel);
555         int ret;
556
557         pr("Adding event '%s' (type %d)\n", name, evsel->attr.type);
558
559         event_class = bt_ctf_event_class_create(name);
560         if (!event_class)
561                 return -1;
562
563         ret = add_generic_types(cw, evsel, event_class);
564         if (ret)
565                 goto err;
566
567         if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
568                 ret = add_tracepoint_types(cw, evsel, event_class);
569                 if (ret)
570                         goto err;
571         }
572
573         ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);
574         if (ret) {
575                 pr("Failed to add event class into stream.\n");
576                 goto err;
577         }
578
579         priv = malloc(sizeof(*priv));
580         if (!priv)
581                 goto err;
582
583         priv->event_class = event_class;
584         evsel->priv       = priv;
585         return 0;
586
587 err:
588         bt_ctf_event_class_put(event_class);
589         pr_err("Failed to add event '%s'.\n", name);
590         return -1;
591 }
592
593 static int setup_events(struct ctf_writer *cw, struct perf_session *session)
594 {
595         struct perf_evlist *evlist = session->evlist;
596         struct perf_evsel *evsel;
597         int ret;
598
599         evlist__for_each(evlist, evsel) {
600                 ret = add_event(cw, evsel);
601                 if (ret)
602                         return ret;
603         }
604         return 0;
605 }
606
607 static int ctf_writer__setup_env(struct ctf_writer *cw,
608                                  struct perf_session *session)
609 {
610         struct perf_header *header = &session->header;
611         struct bt_ctf_writer *writer = cw->writer;
612
613 #define ADD(__n, __v)                                                   \
614 do {                                                                    \
615         if (bt_ctf_writer_add_environment_field(writer, __n, __v))      \
616                 return -1;                                              \
617 } while (0)
618
619         ADD("host",    header->env.hostname);
620         ADD("sysname", "Linux");
621         ADD("release", header->env.os_release);
622         ADD("version", header->env.version);
623         ADD("machine", header->env.arch);
624         ADD("domain", "kernel");
625         ADD("tracer_name", "perf");
626
627 #undef ADD
628         return 0;
629 }
630
631 static int ctf_writer__setup_clock(struct ctf_writer *cw)
632 {
633         struct bt_ctf_clock *clock = cw->clock;
634
635         bt_ctf_clock_set_description(clock, "perf clock");
636
637 #define SET(__n, __v)                           \
638 do {                                            \
639         if (bt_ctf_clock_set_##__n(clock, __v)) \
640                 return -1;                      \
641 } while (0)
642
643         SET(frequency,   1000000000);
644         SET(offset_s,    0);
645         SET(offset,      0);
646         SET(precision,   10);
647         SET(is_absolute, 0);
648
649 #undef SET
650         return 0;
651 }
652
653 static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex)
654 {
655         struct bt_ctf_field_type *type;
656
657         type = bt_ctf_field_type_integer_create(size);
658         if (!type)
659                 return NULL;
660
661         if (sign &&
662             bt_ctf_field_type_integer_set_signed(type, 1))
663                 goto err;
664
665         if (hex &&
666             bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL))
667                 goto err;
668
669         pr2("Created type: INTEGER %d-bit %ssigned %s\n",
670             size, sign ? "un" : "", hex ? "hex" : "");
671         return type;
672
673 err:
674         bt_ctf_field_type_put(type);
675         return NULL;
676 }
677
678 static void ctf_writer__cleanup_data(struct ctf_writer *cw)
679 {
680         unsigned int i;
681
682         for (i = 0; i < ARRAY_SIZE(cw->data.array); i++)
683                 bt_ctf_field_type_put(cw->data.array[i]);
684 }
685
686 static int ctf_writer__init_data(struct ctf_writer *cw)
687 {
688 #define CREATE_INT_TYPE(type, size, sign, hex)          \
689 do {                                                    \
690         (type) = create_int_type(size, sign, hex);      \
691         if (!(type))                                    \
692                 goto err;                               \
693 } while (0)
694
695         CREATE_INT_TYPE(cw->data.s64, 64, true,  false);
696         CREATE_INT_TYPE(cw->data.u64, 64, false, false);
697         CREATE_INT_TYPE(cw->data.s32, 32, true,  false);
698         CREATE_INT_TYPE(cw->data.u32, 32, false, false);
699         CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true);
700
701         cw->data.string  = bt_ctf_field_type_string_create();
702         if (cw->data.string)
703                 return 0;
704
705 err:
706         ctf_writer__cleanup_data(cw);
707         pr_err("Failed to create data types.\n");
708         return -1;
709 }
710
711 static void ctf_writer__cleanup(struct ctf_writer *cw)
712 {
713         ctf_writer__cleanup_data(cw);
714
715         bt_ctf_clock_put(cw->clock);
716         bt_ctf_stream_put(cw->stream);
717         bt_ctf_stream_class_put(cw->stream_class);
718         bt_ctf_writer_put(cw->writer);
719
720         /* and NULL all the pointers */
721         memset(cw, 0, sizeof(*cw));
722 }
723
724 static int ctf_writer__init(struct ctf_writer *cw, const char *path)
725 {
726         struct bt_ctf_writer            *writer;
727         struct bt_ctf_stream_class      *stream_class;
728         struct bt_ctf_stream            *stream;
729         struct bt_ctf_clock             *clock;
730
731         /* CTF writer */
732         writer = bt_ctf_writer_create(path);
733         if (!writer)
734                 goto err;
735
736         cw->writer = writer;
737
738         /* CTF clock */
739         clock = bt_ctf_clock_create("perf_clock");
740         if (!clock) {
741                 pr("Failed to create CTF clock.\n");
742                 goto err_cleanup;
743         }
744
745         cw->clock = clock;
746
747         if (ctf_writer__setup_clock(cw)) {
748                 pr("Failed to setup CTF clock.\n");
749                 goto err_cleanup;
750         }
751
752         /* CTF stream class */
753         stream_class = bt_ctf_stream_class_create("perf_stream");
754         if (!stream_class) {
755                 pr("Failed to create CTF stream class.\n");
756                 goto err_cleanup;
757         }
758
759         cw->stream_class = stream_class;
760
761         /* CTF clock stream setup */
762         if (bt_ctf_stream_class_set_clock(stream_class, clock)) {
763                 pr("Failed to assign CTF clock to stream class.\n");
764                 goto err_cleanup;
765         }
766
767         if (ctf_writer__init_data(cw))
768                 goto err_cleanup;
769
770         /* CTF stream instance */
771         stream = bt_ctf_writer_create_stream(writer, stream_class);
772         if (!stream) {
773                 pr("Failed to create CTF stream.\n");
774                 goto err_cleanup;
775         }
776
777         cw->stream = stream;
778
779         /* CTF clock writer setup */
780         if (bt_ctf_writer_add_clock(writer, clock)) {
781                 pr("Failed to assign CTF clock to writer.\n");
782                 goto err_cleanup;
783         }
784
785         return 0;
786
787 err_cleanup:
788         ctf_writer__cleanup(cw);
789 err:
790         pr_err("Failed to setup CTF writer.\n");
791         return -1;
792 }
793
794 int bt_convert__perf2ctf(const char *input, const char *path, bool force)
795 {
796         struct perf_session *session;
797         struct perf_data_file file = {
798                 .path = input,
799                 .mode = PERF_DATA_MODE_READ,
800                 .force = force,
801         };
802         struct convert c = {
803                 .tool = {
804                         .sample          = process_sample_event,
805                         .mmap            = perf_event__process_mmap,
806                         .mmap2           = perf_event__process_mmap2,
807                         .comm            = perf_event__process_comm,
808                         .exit            = perf_event__process_exit,
809                         .fork            = perf_event__process_fork,
810                         .lost            = perf_event__process_lost,
811                         .tracing_data    = perf_event__process_tracing_data,
812                         .build_id        = perf_event__process_build_id,
813                         .ordered_events  = true,
814                         .ordering_requires_timestamps = true,
815                 },
816         };
817         struct ctf_writer *cw = &c.writer;
818         int err = -1;
819
820         /* CTF writer */
821         if (ctf_writer__init(cw, path))
822                 return -1;
823
824         /* perf.data session */
825         session = perf_session__new(&file, 0, &c.tool);
826         if (!session)
827                 goto free_writer;
828
829         /* CTF writer env/clock setup  */
830         if (ctf_writer__setup_env(cw, session))
831                 goto free_session;
832
833         /* CTF events setup */
834         if (setup_events(cw, session))
835                 goto free_session;
836
837         err = perf_session__process_events(session);
838         if (!err)
839                 err = bt_ctf_stream_flush(cw->stream);
840
841         fprintf(stderr,
842                 "[ perf data convert: Converted '%s' into CTF data '%s' ]\n",
843                 file.path, path);
844
845         fprintf(stderr,
846                 "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples) ]\n",
847                 (double) c.events_size / 1024.0 / 1024.0,
848                 c.events_count);
849
850         /* its all good */
851 free_session:
852         perf_session__delete(session);
853
854 free_writer:
855         ctf_writer__cleanup(cw);
856         return err;
857 }