2 * CTF writing support via babeltrace.
4 * Copyright (C) 2014, Jiri Olsa <jolsa@redhat.com>
5 * Copyright (C) 2014, Sebastian Andrzej Siewior <bigeasy@linutronix.de>
7 * Released under the GPL v2. (and only v2, not any later version)
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>
20 #include "data-convert-bt.h"
29 #define pr_N(n, fmt, ...) \
30 eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__)
32 #define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__)
33 #define pr2(fmt, ...) pr_N(2, pr_fmt(fmt), ##__VA_ARGS__)
35 #define pr_time2(t, fmt, ...) pr_time_N(2, debug_data_convert, t, pr_fmt(fmt), ##__VA_ARGS__)
38 struct bt_ctf_event_class *event_class;
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;
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;
58 struct bt_ctf_field_type *array[6];
63 struct perf_tool tool;
64 struct ctf_writer writer;
70 static int value_set(struct bt_ctf_field_type *type,
71 struct bt_ctf_event *event,
72 const char *name, u64 val)
74 struct bt_ctf_field *field;
75 bool sign = bt_ctf_field_type_integer_get_signed(type);
78 field = bt_ctf_field_create(type);
80 pr_err("failed to create a field %s\n", name);
85 ret = bt_ctf_field_signed_integer_set_value(field, val);
87 pr_err("failed to set field value %s\n", name);
91 ret = bt_ctf_field_unsigned_integer_set_value(field, val);
93 pr_err("failed to set field value %s\n", name);
98 ret = bt_ctf_event_set_payload(event, name, field);
100 pr_err("failed to set payload %s\n", name);
104 pr2(" SET [%s = %" PRIu64 "]\n", name, val);
107 bt_ctf_field_put(field);
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, \
117 struct bt_ctf_field_type *type = cw->data._name; \
118 return value_set(type, event, name, (u64) val); \
121 #define FUNC_VALUE_SET(_name) __FUNC_VALUE_SET(_name, _name)
127 __FUNC_VALUE_SET(u64_hex, u64)
129 static struct bt_ctf_field_type*
130 get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field)
132 unsigned long flags = field->flags;
134 if (flags & FIELD_IS_STRING)
135 return cw->data.string;
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;
143 if (flags & FIELD_IS_SIGNED) {
144 if (field->size == 8)
150 if (field->size == 8)
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)
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;
175 offset = fmtf->offset;
177 if (flags & FIELD_IS_STRING)
178 flags &= ~FIELD_IS_ARRAY;
180 if (flags & FIELD_IS_DYNAMIC) {
181 unsigned long long tmp_val;
183 tmp_val = pevent_read_number(fmtf->event->pevent,
190 if (flags & FIELD_IS_ARRAY) {
192 type = bt_ctf_event_class_get_field_by_name(
194 array_field = bt_ctf_field_create(type);
195 bt_ctf_field_type_put(type);
197 pr_err("Failed to create array type %s\n", name);
201 len = fmtf->size / fmtf->arraylen;
202 n_items = fmtf->arraylen;
208 type = get_tracepoint_field_type(cw, fmtf);
210 for (i = 0; i < n_items; i++) {
211 if (!(flags & FIELD_IS_STRING))
212 value_int = pevent_read_number(
214 data + offset + i * len, len);
216 if (flags & FIELD_IS_ARRAY)
217 field = bt_ctf_field_array_get_field(array_field, i);
219 field = bt_ctf_field_create(type);
222 pr_err("failed to create a field %s\n", name);
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(
233 ret = bt_ctf_field_signed_integer_set_value(
236 pr_err("failed to set file value %s\n", name);
239 if (!(flags & FIELD_IS_ARRAY)) {
240 ret = bt_ctf_event_set_payload(event, name, field);
242 pr_err("failed to set payload %s\n", name);
246 bt_ctf_field_put(field);
248 if (flags & FIELD_IS_ARRAY) {
249 ret = bt_ctf_event_set_payload(event, name, array_field);
251 pr_err("Failed add payload array %s\n", name);
254 bt_ctf_field_put(array_field);
259 bt_ctf_field_put(field);
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)
269 struct format_field *field;
272 for (field = fields; field; field = field->next) {
273 ret = add_tracepoint_field_value(cw, event_class, event, sample,
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)
287 struct format_field *common_fields = evsel->tp_format->format.common_fields;
288 struct format_field *fields = evsel->tp_format->format.fields;
291 ret = add_tracepoint_fields_values(cw, event_class, event,
292 common_fields, sample);
294 ret = add_tracepoint_fields_values(cw, event_class, event,
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)
305 u64 type = evsel->attr.sample_type;
310 * PERF_SAMPLE_TIME - not needed as we have it in
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
320 if (type & PERF_SAMPLE_IP) {
321 ret = value_set_u64_hex(cw, event, "perf_ip", sample->ip);
326 if (type & PERF_SAMPLE_TID) {
327 ret = value_set_s32(cw, event, "perf_tid", sample->tid);
331 ret = value_set_s32(cw, event, "perf_pid", sample->pid);
336 if ((type & PERF_SAMPLE_ID) ||
337 (type & PERF_SAMPLE_IDENTIFIER)) {
338 ret = value_set_u64(cw, event, "perf_id", sample->id);
343 if (type & PERF_SAMPLE_STREAM_ID) {
344 ret = value_set_u64(cw, event, "perf_stream_id", sample->stream_id);
349 if (type & PERF_SAMPLE_CPU) {
350 ret = value_set_u32(cw, event, "perf_cpu", sample->cpu);
355 if (type & PERF_SAMPLE_PERIOD) {
356 ret = value_set_u64(cw, event, "perf_period", sample->period);
361 if (type & PERF_SAMPLE_WEIGHT) {
362 ret = value_set_u64(cw, event, "perf_weight", sample->weight);
367 if (type & PERF_SAMPLE_DATA_SRC) {
368 ret = value_set_u64(cw, event, "perf_data_src",
374 if (type & PERF_SAMPLE_TRANSACTION) {
375 ret = value_set_u64(cw, event, "perf_transaction",
376 sample->transaction);
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)
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;
397 if (WARN_ONCE(!priv, "Failed to setup all events.\n"))
400 event_class = priv->event_class;
404 c->events_size += _event->header.size;
406 pr_time2(sample->time, "sample %" PRIu64 "\n", c->events_count);
408 event = bt_ctf_event_create(event_class);
410 pr_err("Failed to create an CTF event\n");
414 bt_ctf_clock_set_time(cw->clock, sample->time);
416 ret = add_generic_values(cw, event, evsel, sample);
420 if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
421 ret = add_tracepoint_values(cw, event_class, event,
427 bt_ctf_stream_append_event(cw->stream, event);
428 bt_ctf_event_put(event);
432 static int add_tracepoint_fields_types(struct ctf_writer *cw,
433 struct format_field *fields,
434 struct bt_ctf_event_class *event_class)
436 struct format_field *field;
439 for (field = fields; field; field = field->next) {
440 struct bt_ctf_field_type *type;
441 unsigned long flags = field->flags;
443 pr2(" field '%s'\n", field->name);
445 type = get_tracepoint_field_type(cw, field);
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.
454 if (flags & FIELD_IS_STRING)
455 flags &= ~FIELD_IS_ARRAY;
457 if (flags & FIELD_IS_ARRAY)
458 type = bt_ctf_field_type_array_create(type, field->arraylen);
460 ret = bt_ctf_event_class_add_field(event_class, type,
463 if (flags & FIELD_IS_ARRAY)
464 bt_ctf_field_type_put(type);
467 pr_err("Failed to add field '%s\n", field->name);
475 static int add_tracepoint_types(struct ctf_writer *cw,
476 struct perf_evsel *evsel,
477 struct bt_ctf_event_class *class)
479 struct format_field *common_fields = evsel->tp_format->format.common_fields;
480 struct format_field *fields = evsel->tp_format->format.fields;
483 ret = add_tracepoint_fields_types(cw, common_fields, class);
485 ret = add_tracepoint_fields_types(cw, fields, class);
490 static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
491 struct bt_ctf_event_class *event_class)
493 u64 type = evsel->attr.sample_type;
497 * PERF_SAMPLE_TIME - not needed as we have it in
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
507 #define ADD_FIELD(cl, t, n) \
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); \
516 if (type & PERF_SAMPLE_IP)
517 ADD_FIELD(event_class, cw->data.u64_hex, "perf_ip");
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");
524 if ((type & PERF_SAMPLE_ID) ||
525 (type & PERF_SAMPLE_IDENTIFIER))
526 ADD_FIELD(event_class, cw->data.u64, "perf_id");
528 if (type & PERF_SAMPLE_STREAM_ID)
529 ADD_FIELD(event_class, cw->data.u64, "perf_stream_id");
531 if (type & PERF_SAMPLE_CPU)
532 ADD_FIELD(event_class, cw->data.u32, "perf_cpu");
534 if (type & PERF_SAMPLE_PERIOD)
535 ADD_FIELD(event_class, cw->data.u64, "perf_period");
537 if (type & PERF_SAMPLE_WEIGHT)
538 ADD_FIELD(event_class, cw->data.u64, "perf_weight");
540 if (type & PERF_SAMPLE_DATA_SRC)
541 ADD_FIELD(event_class, cw->data.u64, "perf_data_src");
543 if (type & PERF_SAMPLE_TRANSACTION)
544 ADD_FIELD(event_class, cw->data.u64, "perf_transaction");
550 static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
552 struct bt_ctf_event_class *event_class;
553 struct evsel_priv *priv;
554 const char *name = perf_evsel__name(evsel);
557 pr("Adding event '%s' (type %d)\n", name, evsel->attr.type);
559 event_class = bt_ctf_event_class_create(name);
563 ret = add_generic_types(cw, evsel, event_class);
567 if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
568 ret = add_tracepoint_types(cw, evsel, event_class);
573 ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);
575 pr("Failed to add event class into stream.\n");
579 priv = malloc(sizeof(*priv));
583 priv->event_class = event_class;
588 bt_ctf_event_class_put(event_class);
589 pr_err("Failed to add event '%s'.\n", name);
593 static int setup_events(struct ctf_writer *cw, struct perf_session *session)
595 struct perf_evlist *evlist = session->evlist;
596 struct perf_evsel *evsel;
599 evlist__for_each(evlist, evsel) {
600 ret = add_event(cw, evsel);
607 static int ctf_writer__setup_env(struct ctf_writer *cw,
608 struct perf_session *session)
610 struct perf_header *header = &session->header;
611 struct bt_ctf_writer *writer = cw->writer;
613 #define ADD(__n, __v) \
615 if (bt_ctf_writer_add_environment_field(writer, __n, __v)) \
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");
631 static int ctf_writer__setup_clock(struct ctf_writer *cw)
633 struct bt_ctf_clock *clock = cw->clock;
635 bt_ctf_clock_set_description(clock, "perf clock");
637 #define SET(__n, __v) \
639 if (bt_ctf_clock_set_##__n(clock, __v)) \
643 SET(frequency, 1000000000);
653 static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex)
655 struct bt_ctf_field_type *type;
657 type = bt_ctf_field_type_integer_create(size);
662 bt_ctf_field_type_integer_set_signed(type, 1))
666 bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL))
669 pr2("Created type: INTEGER %d-bit %ssigned %s\n",
670 size, sign ? "un" : "", hex ? "hex" : "");
674 bt_ctf_field_type_put(type);
678 static void ctf_writer__cleanup_data(struct ctf_writer *cw)
682 for (i = 0; i < ARRAY_SIZE(cw->data.array); i++)
683 bt_ctf_field_type_put(cw->data.array[i]);
686 static int ctf_writer__init_data(struct ctf_writer *cw)
688 #define CREATE_INT_TYPE(type, size, sign, hex) \
690 (type) = create_int_type(size, sign, hex); \
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);
701 cw->data.string = bt_ctf_field_type_string_create();
706 ctf_writer__cleanup_data(cw);
707 pr_err("Failed to create data types.\n");
711 static void ctf_writer__cleanup(struct ctf_writer *cw)
713 ctf_writer__cleanup_data(cw);
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);
720 /* and NULL all the pointers */
721 memset(cw, 0, sizeof(*cw));
724 static int ctf_writer__init(struct ctf_writer *cw, const char *path)
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;
732 writer = bt_ctf_writer_create(path);
739 clock = bt_ctf_clock_create("perf_clock");
741 pr("Failed to create CTF clock.\n");
747 if (ctf_writer__setup_clock(cw)) {
748 pr("Failed to setup CTF clock.\n");
752 /* CTF stream class */
753 stream_class = bt_ctf_stream_class_create("perf_stream");
755 pr("Failed to create CTF stream class.\n");
759 cw->stream_class = stream_class;
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");
767 if (ctf_writer__init_data(cw))
770 /* CTF stream instance */
771 stream = bt_ctf_writer_create_stream(writer, stream_class);
773 pr("Failed to create CTF stream.\n");
779 /* CTF clock writer setup */
780 if (bt_ctf_writer_add_clock(writer, clock)) {
781 pr("Failed to assign CTF clock to writer.\n");
788 ctf_writer__cleanup(cw);
790 pr_err("Failed to setup CTF writer.\n");
794 int bt_convert__perf2ctf(const char *input, const char *path, bool force)
796 struct perf_session *session;
797 struct perf_data_file file = {
799 .mode = PERF_DATA_MODE_READ,
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,
817 struct ctf_writer *cw = &c.writer;
821 if (ctf_writer__init(cw, path))
824 /* perf.data session */
825 session = perf_session__new(&file, 0, &c.tool);
829 /* CTF writer env/clock setup */
830 if (ctf_writer__setup_env(cw, session))
833 /* CTF events setup */
834 if (setup_events(cw, session))
837 err = perf_session__process_events(session);
839 err = bt_ctf_stream_flush(cw->stream);
842 "[ perf data convert: Converted '%s' into CTF data '%s' ]\n",
846 "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples) ]\n",
847 (double) c.events_size / 1024.0 / 1024.0,
852 perf_session__delete(session);
855 ctf_writer__cleanup(cw);