xref: /linux/tools/perf/util/data-convert-bt.c (revision d4ae42139289cbe38d5b84fa1558161d330d6e54)
1edbe9817SJiri Olsa /*
2edbe9817SJiri Olsa  * CTF writing support via babeltrace.
3edbe9817SJiri Olsa  *
4edbe9817SJiri Olsa  * Copyright (C) 2014, Jiri Olsa <jolsa@redhat.com>
5edbe9817SJiri Olsa  * Copyright (C) 2014, Sebastian Andrzej Siewior <bigeasy@linutronix.de>
6edbe9817SJiri Olsa  *
7edbe9817SJiri Olsa  * Released under the GPL v2. (and only v2, not any later version)
8edbe9817SJiri Olsa  */
9edbe9817SJiri Olsa 
10edbe9817SJiri Olsa #include <linux/compiler.h>
11edbe9817SJiri Olsa #include <babeltrace/ctf-writer/writer.h>
12edbe9817SJiri Olsa #include <babeltrace/ctf-writer/clock.h>
13edbe9817SJiri Olsa #include <babeltrace/ctf-writer/stream.h>
14edbe9817SJiri Olsa #include <babeltrace/ctf-writer/event.h>
15edbe9817SJiri Olsa #include <babeltrace/ctf-writer/event-types.h>
16edbe9817SJiri Olsa #include <babeltrace/ctf-writer/event-fields.h>
17e0a7cce5SWang Nan #include <babeltrace/ctf-ir/utils.h>
18edbe9817SJiri Olsa #include <babeltrace/ctf/events.h>
19edbe9817SJiri Olsa #include <traceevent/event-parse.h>
20edbe9817SJiri Olsa #include "asm/bug.h"
21edbe9817SJiri Olsa #include "data-convert-bt.h"
22edbe9817SJiri Olsa #include "session.h"
23edbe9817SJiri Olsa #include "util.h"
24edbe9817SJiri Olsa #include "debug.h"
25edbe9817SJiri Olsa #include "tool.h"
26edbe9817SJiri Olsa #include "evlist.h"
27edbe9817SJiri Olsa #include "evsel.h"
28edbe9817SJiri Olsa #include "machine.h"
29edbe9817SJiri Olsa 
30edbe9817SJiri Olsa #define pr_N(n, fmt, ...) \
31edbe9817SJiri Olsa 	eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__)
32edbe9817SJiri Olsa 
33edbe9817SJiri Olsa #define pr(fmt, ...)  pr_N(1, pr_fmt(fmt), ##__VA_ARGS__)
34edbe9817SJiri Olsa #define pr2(fmt, ...) pr_N(2, pr_fmt(fmt), ##__VA_ARGS__)
35edbe9817SJiri Olsa 
36edbe9817SJiri Olsa #define pr_time2(t, fmt, ...) pr_time_N(2, debug_data_convert, t, pr_fmt(fmt), ##__VA_ARGS__)
37edbe9817SJiri Olsa 
38edbe9817SJiri Olsa struct evsel_priv {
39edbe9817SJiri Olsa 	struct bt_ctf_event_class *event_class;
40edbe9817SJiri Olsa };
41edbe9817SJiri Olsa 
4290e129ffSSebastian Andrzej Siewior #define MAX_CPUS	4096
4390e129ffSSebastian Andrzej Siewior 
4490e129ffSSebastian Andrzej Siewior struct ctf_stream {
4590e129ffSSebastian Andrzej Siewior 	struct bt_ctf_stream *stream;
4690e129ffSSebastian Andrzej Siewior 	int cpu;
4789e5fa88SJiri Olsa 	u32 count;
4890e129ffSSebastian Andrzej Siewior };
4990e129ffSSebastian Andrzej Siewior 
50edbe9817SJiri Olsa struct ctf_writer {
51edbe9817SJiri Olsa 	/* writer primitives */
52edbe9817SJiri Olsa 	struct bt_ctf_writer		 *writer;
5390e129ffSSebastian Andrzej Siewior 	struct ctf_stream		**stream;
5490e129ffSSebastian Andrzej Siewior 	int				  stream_cnt;
55edbe9817SJiri Olsa 	struct bt_ctf_stream_class	 *stream_class;
56edbe9817SJiri Olsa 	struct bt_ctf_clock		 *clock;
57edbe9817SJiri Olsa 
58edbe9817SJiri Olsa 	/* data types */
59edbe9817SJiri Olsa 	union {
60edbe9817SJiri Olsa 		struct {
61edbe9817SJiri Olsa 			struct bt_ctf_field_type	*s64;
62edbe9817SJiri Olsa 			struct bt_ctf_field_type	*u64;
63edbe9817SJiri Olsa 			struct bt_ctf_field_type	*s32;
64edbe9817SJiri Olsa 			struct bt_ctf_field_type	*u32;
65edbe9817SJiri Olsa 			struct bt_ctf_field_type	*string;
66edbe9817SJiri Olsa 			struct bt_ctf_field_type	*u64_hex;
67edbe9817SJiri Olsa 		};
68edbe9817SJiri Olsa 		struct bt_ctf_field_type *array[6];
69edbe9817SJiri Olsa 	} data;
70edbe9817SJiri Olsa };
71edbe9817SJiri Olsa 
72edbe9817SJiri Olsa struct convert {
73edbe9817SJiri Olsa 	struct perf_tool	tool;
74edbe9817SJiri Olsa 	struct ctf_writer	writer;
75edbe9817SJiri Olsa 
76edbe9817SJiri Olsa 	u64			events_size;
77edbe9817SJiri Olsa 	u64			events_count;
788fa46753SJiri Olsa 
798fa46753SJiri Olsa 	/* Ordered events configured queue size. */
808fa46753SJiri Olsa 	u64			queue_size;
81edbe9817SJiri Olsa };
82edbe9817SJiri Olsa 
83edbe9817SJiri Olsa static int value_set(struct bt_ctf_field_type *type,
84edbe9817SJiri Olsa 		     struct bt_ctf_event *event,
85edbe9817SJiri Olsa 		     const char *name, u64 val)
86edbe9817SJiri Olsa {
87edbe9817SJiri Olsa 	struct bt_ctf_field *field;
88edbe9817SJiri Olsa 	bool sign = bt_ctf_field_type_integer_get_signed(type);
89edbe9817SJiri Olsa 	int ret;
90edbe9817SJiri Olsa 
91edbe9817SJiri Olsa 	field = bt_ctf_field_create(type);
92edbe9817SJiri Olsa 	if (!field) {
93edbe9817SJiri Olsa 		pr_err("failed to create a field %s\n", name);
94edbe9817SJiri Olsa 		return -1;
95edbe9817SJiri Olsa 	}
96edbe9817SJiri Olsa 
97edbe9817SJiri Olsa 	if (sign) {
98edbe9817SJiri Olsa 		ret = bt_ctf_field_signed_integer_set_value(field, val);
99edbe9817SJiri Olsa 		if (ret) {
100edbe9817SJiri Olsa 			pr_err("failed to set field value %s\n", name);
101edbe9817SJiri Olsa 			goto err;
102edbe9817SJiri Olsa 		}
103edbe9817SJiri Olsa 	} else {
104edbe9817SJiri Olsa 		ret = bt_ctf_field_unsigned_integer_set_value(field, val);
105edbe9817SJiri Olsa 		if (ret) {
106edbe9817SJiri Olsa 			pr_err("failed to set field value %s\n", name);
107edbe9817SJiri Olsa 			goto err;
108edbe9817SJiri Olsa 		}
109edbe9817SJiri Olsa 	}
110edbe9817SJiri Olsa 
111edbe9817SJiri Olsa 	ret = bt_ctf_event_set_payload(event, name, field);
112edbe9817SJiri Olsa 	if (ret) {
113edbe9817SJiri Olsa 		pr_err("failed to set payload %s\n", name);
114edbe9817SJiri Olsa 		goto err;
115edbe9817SJiri Olsa 	}
116edbe9817SJiri Olsa 
117edbe9817SJiri Olsa 	pr2("  SET [%s = %" PRIu64 "]\n", name, val);
118edbe9817SJiri Olsa 
119edbe9817SJiri Olsa err:
120edbe9817SJiri Olsa 	bt_ctf_field_put(field);
121edbe9817SJiri Olsa 	return ret;
122edbe9817SJiri Olsa }
123edbe9817SJiri Olsa 
124edbe9817SJiri Olsa #define __FUNC_VALUE_SET(_name, _val_type)				\
125edbe9817SJiri Olsa static __maybe_unused int value_set_##_name(struct ctf_writer *cw,	\
126edbe9817SJiri Olsa 			     struct bt_ctf_event *event,		\
127edbe9817SJiri Olsa 			     const char *name,				\
128edbe9817SJiri Olsa 			     _val_type val)				\
129edbe9817SJiri Olsa {									\
130edbe9817SJiri Olsa 	struct bt_ctf_field_type *type = cw->data._name;		\
131edbe9817SJiri Olsa 	return value_set(type, event, name, (u64) val);			\
132edbe9817SJiri Olsa }
133edbe9817SJiri Olsa 
134edbe9817SJiri Olsa #define FUNC_VALUE_SET(_name) __FUNC_VALUE_SET(_name, _name)
135edbe9817SJiri Olsa 
136edbe9817SJiri Olsa FUNC_VALUE_SET(s32)
137edbe9817SJiri Olsa FUNC_VALUE_SET(u32)
138edbe9817SJiri Olsa FUNC_VALUE_SET(s64)
139edbe9817SJiri Olsa FUNC_VALUE_SET(u64)
140edbe9817SJiri Olsa __FUNC_VALUE_SET(u64_hex, u64)
141edbe9817SJiri Olsa 
14269364727SSebastian Andrzej Siewior static struct bt_ctf_field_type*
14369364727SSebastian Andrzej Siewior get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field)
14469364727SSebastian Andrzej Siewior {
14569364727SSebastian Andrzej Siewior 	unsigned long flags = field->flags;
14669364727SSebastian Andrzej Siewior 
14769364727SSebastian Andrzej Siewior 	if (flags & FIELD_IS_STRING)
14869364727SSebastian Andrzej Siewior 		return cw->data.string;
14969364727SSebastian Andrzej Siewior 
15069364727SSebastian Andrzej Siewior 	if (!(flags & FIELD_IS_SIGNED)) {
15169364727SSebastian Andrzej Siewior 		/* unsigned long are mostly pointers */
15269364727SSebastian Andrzej Siewior 		if (flags & FIELD_IS_LONG || flags & FIELD_IS_POINTER)
15369364727SSebastian Andrzej Siewior 			return cw->data.u64_hex;
15469364727SSebastian Andrzej Siewior 	}
15569364727SSebastian Andrzej Siewior 
15669364727SSebastian Andrzej Siewior 	if (flags & FIELD_IS_SIGNED) {
15769364727SSebastian Andrzej Siewior 		if (field->size == 8)
15869364727SSebastian Andrzej Siewior 			return cw->data.s64;
15969364727SSebastian Andrzej Siewior 		else
16069364727SSebastian Andrzej Siewior 			return cw->data.s32;
16169364727SSebastian Andrzej Siewior 	}
16269364727SSebastian Andrzej Siewior 
16369364727SSebastian Andrzej Siewior 	if (field->size == 8)
16469364727SSebastian Andrzej Siewior 		return cw->data.u64;
16569364727SSebastian Andrzej Siewior 	else
16669364727SSebastian Andrzej Siewior 		return cw->data.u32;
16769364727SSebastian Andrzej Siewior }
16869364727SSebastian Andrzej Siewior 
169*d4ae4213SWang Nan static unsigned long long adjust_signedness(unsigned long long value_int, int size)
170*d4ae4213SWang Nan {
171*d4ae4213SWang Nan 	unsigned long long value_mask;
172*d4ae4213SWang Nan 
173*d4ae4213SWang Nan 	/*
174*d4ae4213SWang Nan 	 * value_mask = (1 << (size * 8 - 1)) - 1.
175*d4ae4213SWang Nan 	 * Directly set value_mask for code readers.
176*d4ae4213SWang Nan 	 */
177*d4ae4213SWang Nan 	switch (size) {
178*d4ae4213SWang Nan 	case 1:
179*d4ae4213SWang Nan 		value_mask = 0x7fULL;
180*d4ae4213SWang Nan 		break;
181*d4ae4213SWang Nan 	case 2:
182*d4ae4213SWang Nan 		value_mask = 0x7fffULL;
183*d4ae4213SWang Nan 		break;
184*d4ae4213SWang Nan 	case 4:
185*d4ae4213SWang Nan 		value_mask = 0x7fffffffULL;
186*d4ae4213SWang Nan 		break;
187*d4ae4213SWang Nan 	case 8:
188*d4ae4213SWang Nan 		/*
189*d4ae4213SWang Nan 		 * For 64 bit value, return it self. There is no need
190*d4ae4213SWang Nan 		 * to fill high bit.
191*d4ae4213SWang Nan 		 */
192*d4ae4213SWang Nan 		/* Fall through */
193*d4ae4213SWang Nan 	default:
194*d4ae4213SWang Nan 		/* BUG! */
195*d4ae4213SWang Nan 		return value_int;
196*d4ae4213SWang Nan 	}
197*d4ae4213SWang Nan 
198*d4ae4213SWang Nan 	/* If it is a positive value, don't adjust. */
199*d4ae4213SWang Nan 	if ((value_int & (~0ULL - value_mask)) == 0)
200*d4ae4213SWang Nan 		return value_int;
201*d4ae4213SWang Nan 
202*d4ae4213SWang Nan 	/* Fill upper part of value_int with 1 to make it a negative long long. */
203*d4ae4213SWang Nan 	return (value_int & value_mask) | ~value_mask;
204*d4ae4213SWang Nan }
205*d4ae4213SWang Nan 
20669364727SSebastian Andrzej Siewior static int add_tracepoint_field_value(struct ctf_writer *cw,
20769364727SSebastian Andrzej Siewior 				      struct bt_ctf_event_class *event_class,
20869364727SSebastian Andrzej Siewior 				      struct bt_ctf_event *event,
20969364727SSebastian Andrzej Siewior 				      struct perf_sample *sample,
21069364727SSebastian Andrzej Siewior 				      struct format_field *fmtf)
21169364727SSebastian Andrzej Siewior {
21269364727SSebastian Andrzej Siewior 	struct bt_ctf_field_type *type;
21369364727SSebastian Andrzej Siewior 	struct bt_ctf_field *array_field;
21469364727SSebastian Andrzej Siewior 	struct bt_ctf_field *field;
21569364727SSebastian Andrzej Siewior 	const char *name = fmtf->name;
21669364727SSebastian Andrzej Siewior 	void *data = sample->raw_data;
21769364727SSebastian Andrzej Siewior 	unsigned long flags = fmtf->flags;
21869364727SSebastian Andrzej Siewior 	unsigned int n_items;
21969364727SSebastian Andrzej Siewior 	unsigned int i;
22069364727SSebastian Andrzej Siewior 	unsigned int offset;
22169364727SSebastian Andrzej Siewior 	unsigned int len;
22269364727SSebastian Andrzej Siewior 	int ret;
22369364727SSebastian Andrzej Siewior 
224e0a7cce5SWang Nan 	name = fmtf->alias;
22569364727SSebastian Andrzej Siewior 	offset = fmtf->offset;
22669364727SSebastian Andrzej Siewior 	len = fmtf->size;
22769364727SSebastian Andrzej Siewior 	if (flags & FIELD_IS_STRING)
22869364727SSebastian Andrzej Siewior 		flags &= ~FIELD_IS_ARRAY;
22969364727SSebastian Andrzej Siewior 
23069364727SSebastian Andrzej Siewior 	if (flags & FIELD_IS_DYNAMIC) {
23169364727SSebastian Andrzej Siewior 		unsigned long long tmp_val;
23269364727SSebastian Andrzej Siewior 
23369364727SSebastian Andrzej Siewior 		tmp_val = pevent_read_number(fmtf->event->pevent,
23469364727SSebastian Andrzej Siewior 				data + offset, len);
23569364727SSebastian Andrzej Siewior 		offset = tmp_val;
23669364727SSebastian Andrzej Siewior 		len = offset >> 16;
23769364727SSebastian Andrzej Siewior 		offset &= 0xffff;
23869364727SSebastian Andrzej Siewior 	}
23969364727SSebastian Andrzej Siewior 
24069364727SSebastian Andrzej Siewior 	if (flags & FIELD_IS_ARRAY) {
24169364727SSebastian Andrzej Siewior 
24269364727SSebastian Andrzej Siewior 		type = bt_ctf_event_class_get_field_by_name(
24369364727SSebastian Andrzej Siewior 				event_class, name);
24469364727SSebastian Andrzej Siewior 		array_field = bt_ctf_field_create(type);
24569364727SSebastian Andrzej Siewior 		bt_ctf_field_type_put(type);
24669364727SSebastian Andrzej Siewior 		if (!array_field) {
24769364727SSebastian Andrzej Siewior 			pr_err("Failed to create array type %s\n", name);
24869364727SSebastian Andrzej Siewior 			return -1;
24969364727SSebastian Andrzej Siewior 		}
25069364727SSebastian Andrzej Siewior 
25169364727SSebastian Andrzej Siewior 		len = fmtf->size / fmtf->arraylen;
25269364727SSebastian Andrzej Siewior 		n_items = fmtf->arraylen;
25369364727SSebastian Andrzej Siewior 	} else {
25469364727SSebastian Andrzej Siewior 		n_items = 1;
25569364727SSebastian Andrzej Siewior 		array_field = NULL;
25669364727SSebastian Andrzej Siewior 	}
25769364727SSebastian Andrzej Siewior 
25869364727SSebastian Andrzej Siewior 	type = get_tracepoint_field_type(cw, fmtf);
25969364727SSebastian Andrzej Siewior 
26069364727SSebastian Andrzej Siewior 	for (i = 0; i < n_items; i++) {
26169364727SSebastian Andrzej Siewior 		if (flags & FIELD_IS_ARRAY)
26269364727SSebastian Andrzej Siewior 			field = bt_ctf_field_array_get_field(array_field, i);
26369364727SSebastian Andrzej Siewior 		else
26469364727SSebastian Andrzej Siewior 			field = bt_ctf_field_create(type);
26569364727SSebastian Andrzej Siewior 
26669364727SSebastian Andrzej Siewior 		if (!field) {
26769364727SSebastian Andrzej Siewior 			pr_err("failed to create a field %s\n", name);
26869364727SSebastian Andrzej Siewior 			return -1;
26969364727SSebastian Andrzej Siewior 		}
27069364727SSebastian Andrzej Siewior 
27169364727SSebastian Andrzej Siewior 		if (flags & FIELD_IS_STRING)
27269364727SSebastian Andrzej Siewior 			ret = bt_ctf_field_string_set_value(field,
27369364727SSebastian Andrzej Siewior 					data + offset + i * len);
274*d4ae4213SWang Nan 		else {
275*d4ae4213SWang Nan 			unsigned long long value_int;
276*d4ae4213SWang Nan 
277*d4ae4213SWang Nan 			value_int = pevent_read_number(
278*d4ae4213SWang Nan 					fmtf->event->pevent,
279*d4ae4213SWang Nan 					data + offset + i * len, len);
280*d4ae4213SWang Nan 
281*d4ae4213SWang Nan 			if (!(flags & FIELD_IS_SIGNED))
28269364727SSebastian Andrzej Siewior 				ret = bt_ctf_field_unsigned_integer_set_value(
28369364727SSebastian Andrzej Siewior 						field, value_int);
28469364727SSebastian Andrzej Siewior 			else
28569364727SSebastian Andrzej Siewior 				ret = bt_ctf_field_signed_integer_set_value(
286*d4ae4213SWang Nan 						field, adjust_signedness(value_int, len));
287*d4ae4213SWang Nan 		}
288*d4ae4213SWang Nan 
28969364727SSebastian Andrzej Siewior 		if (ret) {
29069364727SSebastian Andrzej Siewior 			pr_err("failed to set file value %s\n", name);
29169364727SSebastian Andrzej Siewior 			goto err_put_field;
29269364727SSebastian Andrzej Siewior 		}
29369364727SSebastian Andrzej Siewior 		if (!(flags & FIELD_IS_ARRAY)) {
29469364727SSebastian Andrzej Siewior 			ret = bt_ctf_event_set_payload(event, name, field);
29569364727SSebastian Andrzej Siewior 			if (ret) {
29669364727SSebastian Andrzej Siewior 				pr_err("failed to set payload %s\n", name);
29769364727SSebastian Andrzej Siewior 				goto err_put_field;
29869364727SSebastian Andrzej Siewior 			}
29969364727SSebastian Andrzej Siewior 		}
30069364727SSebastian Andrzej Siewior 		bt_ctf_field_put(field);
30169364727SSebastian Andrzej Siewior 	}
30269364727SSebastian Andrzej Siewior 	if (flags & FIELD_IS_ARRAY) {
30369364727SSebastian Andrzej Siewior 		ret = bt_ctf_event_set_payload(event, name, array_field);
30469364727SSebastian Andrzej Siewior 		if (ret) {
30569364727SSebastian Andrzej Siewior 			pr_err("Failed add payload array %s\n", name);
30669364727SSebastian Andrzej Siewior 			return -1;
30769364727SSebastian Andrzej Siewior 		}
30869364727SSebastian Andrzej Siewior 		bt_ctf_field_put(array_field);
30969364727SSebastian Andrzej Siewior 	}
31069364727SSebastian Andrzej Siewior 	return 0;
31169364727SSebastian Andrzej Siewior 
31269364727SSebastian Andrzej Siewior err_put_field:
31369364727SSebastian Andrzej Siewior 	bt_ctf_field_put(field);
31469364727SSebastian Andrzej Siewior 	return -1;
31569364727SSebastian Andrzej Siewior }
31669364727SSebastian Andrzej Siewior 
31769364727SSebastian Andrzej Siewior static int add_tracepoint_fields_values(struct ctf_writer *cw,
31869364727SSebastian Andrzej Siewior 					struct bt_ctf_event_class *event_class,
31969364727SSebastian Andrzej Siewior 					struct bt_ctf_event *event,
32069364727SSebastian Andrzej Siewior 					struct format_field *fields,
32169364727SSebastian Andrzej Siewior 					struct perf_sample *sample)
32269364727SSebastian Andrzej Siewior {
32369364727SSebastian Andrzej Siewior 	struct format_field *field;
32469364727SSebastian Andrzej Siewior 	int ret;
32569364727SSebastian Andrzej Siewior 
32669364727SSebastian Andrzej Siewior 	for (field = fields; field; field = field->next) {
32769364727SSebastian Andrzej Siewior 		ret = add_tracepoint_field_value(cw, event_class, event, sample,
32869364727SSebastian Andrzej Siewior 				field);
32969364727SSebastian Andrzej Siewior 		if (ret)
33069364727SSebastian Andrzej Siewior 			return -1;
33169364727SSebastian Andrzej Siewior 	}
33269364727SSebastian Andrzej Siewior 	return 0;
33369364727SSebastian Andrzej Siewior }
33469364727SSebastian Andrzej Siewior 
33569364727SSebastian Andrzej Siewior static int add_tracepoint_values(struct ctf_writer *cw,
33669364727SSebastian Andrzej Siewior 				 struct bt_ctf_event_class *event_class,
33769364727SSebastian Andrzej Siewior 				 struct bt_ctf_event *event,
33869364727SSebastian Andrzej Siewior 				 struct perf_evsel *evsel,
33969364727SSebastian Andrzej Siewior 				 struct perf_sample *sample)
34069364727SSebastian Andrzej Siewior {
34169364727SSebastian Andrzej Siewior 	struct format_field *common_fields = evsel->tp_format->format.common_fields;
34269364727SSebastian Andrzej Siewior 	struct format_field *fields        = evsel->tp_format->format.fields;
34369364727SSebastian Andrzej Siewior 	int ret;
34469364727SSebastian Andrzej Siewior 
34569364727SSebastian Andrzej Siewior 	ret = add_tracepoint_fields_values(cw, event_class, event,
34669364727SSebastian Andrzej Siewior 					   common_fields, sample);
34769364727SSebastian Andrzej Siewior 	if (!ret)
34869364727SSebastian Andrzej Siewior 		ret = add_tracepoint_fields_values(cw, event_class, event,
34969364727SSebastian Andrzej Siewior 						   fields, sample);
35069364727SSebastian Andrzej Siewior 
35169364727SSebastian Andrzej Siewior 	return ret;
35269364727SSebastian Andrzej Siewior }
35369364727SSebastian Andrzej Siewior 
354edbe9817SJiri Olsa static int add_generic_values(struct ctf_writer *cw,
355edbe9817SJiri Olsa 			      struct bt_ctf_event *event,
356edbe9817SJiri Olsa 			      struct perf_evsel *evsel,
357edbe9817SJiri Olsa 			      struct perf_sample *sample)
358edbe9817SJiri Olsa {
359edbe9817SJiri Olsa 	u64 type = evsel->attr.sample_type;
360edbe9817SJiri Olsa 	int ret;
361edbe9817SJiri Olsa 
362edbe9817SJiri Olsa 	/*
363edbe9817SJiri Olsa 	 * missing:
364edbe9817SJiri Olsa 	 *   PERF_SAMPLE_TIME         - not needed as we have it in
365edbe9817SJiri Olsa 	 *                              ctf event header
366edbe9817SJiri Olsa 	 *   PERF_SAMPLE_READ         - TODO
367edbe9817SJiri Olsa 	 *   PERF_SAMPLE_CALLCHAIN    - TODO
368edbe9817SJiri Olsa 	 *   PERF_SAMPLE_RAW          - tracepoint fields are handled separately
369edbe9817SJiri Olsa 	 *   PERF_SAMPLE_BRANCH_STACK - TODO
370edbe9817SJiri Olsa 	 *   PERF_SAMPLE_REGS_USER    - TODO
371edbe9817SJiri Olsa 	 *   PERF_SAMPLE_STACK_USER   - TODO
372edbe9817SJiri Olsa 	 */
373edbe9817SJiri Olsa 
374edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_IP) {
37554cf776aSSebastian Andrzej Siewior 		ret = value_set_u64_hex(cw, event, "perf_ip", sample->ip);
376edbe9817SJiri Olsa 		if (ret)
377edbe9817SJiri Olsa 			return -1;
378edbe9817SJiri Olsa 	}
379edbe9817SJiri Olsa 
380edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_TID) {
38154cf776aSSebastian Andrzej Siewior 		ret = value_set_s32(cw, event, "perf_tid", sample->tid);
382edbe9817SJiri Olsa 		if (ret)
383edbe9817SJiri Olsa 			return -1;
384edbe9817SJiri Olsa 
38554cf776aSSebastian Andrzej Siewior 		ret = value_set_s32(cw, event, "perf_pid", sample->pid);
386edbe9817SJiri Olsa 		if (ret)
387edbe9817SJiri Olsa 			return -1;
388edbe9817SJiri Olsa 	}
389edbe9817SJiri Olsa 
390edbe9817SJiri Olsa 	if ((type & PERF_SAMPLE_ID) ||
391edbe9817SJiri Olsa 	    (type & PERF_SAMPLE_IDENTIFIER)) {
39254cf776aSSebastian Andrzej Siewior 		ret = value_set_u64(cw, event, "perf_id", sample->id);
393edbe9817SJiri Olsa 		if (ret)
394edbe9817SJiri Olsa 			return -1;
395edbe9817SJiri Olsa 	}
396edbe9817SJiri Olsa 
397edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_STREAM_ID) {
39854cf776aSSebastian Andrzej Siewior 		ret = value_set_u64(cw, event, "perf_stream_id", sample->stream_id);
399edbe9817SJiri Olsa 		if (ret)
400edbe9817SJiri Olsa 			return -1;
401edbe9817SJiri Olsa 	}
402edbe9817SJiri Olsa 
403edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_PERIOD) {
40454cf776aSSebastian Andrzej Siewior 		ret = value_set_u64(cw, event, "perf_period", sample->period);
405edbe9817SJiri Olsa 		if (ret)
406edbe9817SJiri Olsa 			return -1;
407edbe9817SJiri Olsa 	}
408edbe9817SJiri Olsa 
409edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_WEIGHT) {
41054cf776aSSebastian Andrzej Siewior 		ret = value_set_u64(cw, event, "perf_weight", sample->weight);
411edbe9817SJiri Olsa 		if (ret)
412edbe9817SJiri Olsa 			return -1;
413edbe9817SJiri Olsa 	}
414edbe9817SJiri Olsa 
415edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_DATA_SRC) {
41654cf776aSSebastian Andrzej Siewior 		ret = value_set_u64(cw, event, "perf_data_src",
41754cf776aSSebastian Andrzej Siewior 				sample->data_src);
418edbe9817SJiri Olsa 		if (ret)
419edbe9817SJiri Olsa 			return -1;
420edbe9817SJiri Olsa 	}
421edbe9817SJiri Olsa 
422edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_TRANSACTION) {
42354cf776aSSebastian Andrzej Siewior 		ret = value_set_u64(cw, event, "perf_transaction",
42454cf776aSSebastian Andrzej Siewior 				sample->transaction);
425edbe9817SJiri Olsa 		if (ret)
426edbe9817SJiri Olsa 			return -1;
427edbe9817SJiri Olsa 	}
428edbe9817SJiri Olsa 
429edbe9817SJiri Olsa 	return 0;
430edbe9817SJiri Olsa }
431edbe9817SJiri Olsa 
43290e129ffSSebastian Andrzej Siewior static int ctf_stream__flush(struct ctf_stream *cs)
43390e129ffSSebastian Andrzej Siewior {
43490e129ffSSebastian Andrzej Siewior 	int err = 0;
43590e129ffSSebastian Andrzej Siewior 
43690e129ffSSebastian Andrzej Siewior 	if (cs) {
43790e129ffSSebastian Andrzej Siewior 		err = bt_ctf_stream_flush(cs->stream);
43890e129ffSSebastian Andrzej Siewior 		if (err)
43990e129ffSSebastian Andrzej Siewior 			pr_err("CTF stream %d flush failed\n", cs->cpu);
44090e129ffSSebastian Andrzej Siewior 
44189e5fa88SJiri Olsa 		pr("Flush stream for cpu %d (%u samples)\n",
44289e5fa88SJiri Olsa 		   cs->cpu, cs->count);
44389e5fa88SJiri Olsa 
44489e5fa88SJiri Olsa 		cs->count = 0;
44590e129ffSSebastian Andrzej Siewior 	}
44690e129ffSSebastian Andrzej Siewior 
44790e129ffSSebastian Andrzej Siewior 	return err;
44890e129ffSSebastian Andrzej Siewior }
44990e129ffSSebastian Andrzej Siewior 
45090e129ffSSebastian Andrzej Siewior static struct ctf_stream *ctf_stream__create(struct ctf_writer *cw, int cpu)
45190e129ffSSebastian Andrzej Siewior {
45290e129ffSSebastian Andrzej Siewior 	struct ctf_stream *cs;
45390e129ffSSebastian Andrzej Siewior 	struct bt_ctf_field *pkt_ctx   = NULL;
45490e129ffSSebastian Andrzej Siewior 	struct bt_ctf_field *cpu_field = NULL;
45590e129ffSSebastian Andrzej Siewior 	struct bt_ctf_stream *stream   = NULL;
45690e129ffSSebastian Andrzej Siewior 	int ret;
45790e129ffSSebastian Andrzej Siewior 
45890e129ffSSebastian Andrzej Siewior 	cs = zalloc(sizeof(*cs));
45990e129ffSSebastian Andrzej Siewior 	if (!cs) {
46090e129ffSSebastian Andrzej Siewior 		pr_err("Failed to allocate ctf stream\n");
46190e129ffSSebastian Andrzej Siewior 		return NULL;
46290e129ffSSebastian Andrzej Siewior 	}
46390e129ffSSebastian Andrzej Siewior 
46490e129ffSSebastian Andrzej Siewior 	stream = bt_ctf_writer_create_stream(cw->writer, cw->stream_class);
46590e129ffSSebastian Andrzej Siewior 	if (!stream) {
46690e129ffSSebastian Andrzej Siewior 		pr_err("Failed to create CTF stream\n");
46790e129ffSSebastian Andrzej Siewior 		goto out;
46890e129ffSSebastian Andrzej Siewior 	}
46990e129ffSSebastian Andrzej Siewior 
47090e129ffSSebastian Andrzej Siewior 	pkt_ctx = bt_ctf_stream_get_packet_context(stream);
47190e129ffSSebastian Andrzej Siewior 	if (!pkt_ctx) {
47290e129ffSSebastian Andrzej Siewior 		pr_err("Failed to obtain packet context\n");
47390e129ffSSebastian Andrzej Siewior 		goto out;
47490e129ffSSebastian Andrzej Siewior 	}
47590e129ffSSebastian Andrzej Siewior 
47690e129ffSSebastian Andrzej Siewior 	cpu_field = bt_ctf_field_structure_get_field(pkt_ctx, "cpu_id");
47790e129ffSSebastian Andrzej Siewior 	bt_ctf_field_put(pkt_ctx);
47890e129ffSSebastian Andrzej Siewior 	if (!cpu_field) {
47990e129ffSSebastian Andrzej Siewior 		pr_err("Failed to obtain cpu field\n");
48090e129ffSSebastian Andrzej Siewior 		goto out;
48190e129ffSSebastian Andrzej Siewior 	}
48290e129ffSSebastian Andrzej Siewior 
48390e129ffSSebastian Andrzej Siewior 	ret = bt_ctf_field_unsigned_integer_set_value(cpu_field, (u32) cpu);
48490e129ffSSebastian Andrzej Siewior 	if (ret) {
48590e129ffSSebastian Andrzej Siewior 		pr_err("Failed to update CPU number\n");
48690e129ffSSebastian Andrzej Siewior 		goto out;
48790e129ffSSebastian Andrzej Siewior 	}
48890e129ffSSebastian Andrzej Siewior 
48990e129ffSSebastian Andrzej Siewior 	bt_ctf_field_put(cpu_field);
49090e129ffSSebastian Andrzej Siewior 
49190e129ffSSebastian Andrzej Siewior 	cs->cpu    = cpu;
49290e129ffSSebastian Andrzej Siewior 	cs->stream = stream;
49390e129ffSSebastian Andrzej Siewior 	return cs;
49490e129ffSSebastian Andrzej Siewior 
49590e129ffSSebastian Andrzej Siewior out:
49690e129ffSSebastian Andrzej Siewior 	if (cpu_field)
49790e129ffSSebastian Andrzej Siewior 		bt_ctf_field_put(cpu_field);
49890e129ffSSebastian Andrzej Siewior 	if (stream)
49990e129ffSSebastian Andrzej Siewior 		bt_ctf_stream_put(stream);
50090e129ffSSebastian Andrzej Siewior 
50190e129ffSSebastian Andrzej Siewior 	free(cs);
50290e129ffSSebastian Andrzej Siewior 	return NULL;
50390e129ffSSebastian Andrzej Siewior }
50490e129ffSSebastian Andrzej Siewior 
50590e129ffSSebastian Andrzej Siewior static void ctf_stream__delete(struct ctf_stream *cs)
50690e129ffSSebastian Andrzej Siewior {
50790e129ffSSebastian Andrzej Siewior 	if (cs) {
50890e129ffSSebastian Andrzej Siewior 		bt_ctf_stream_put(cs->stream);
50990e129ffSSebastian Andrzej Siewior 		free(cs);
51090e129ffSSebastian Andrzej Siewior 	}
51190e129ffSSebastian Andrzej Siewior }
51290e129ffSSebastian Andrzej Siewior 
51390e129ffSSebastian Andrzej Siewior static struct ctf_stream *ctf_stream(struct ctf_writer *cw, int cpu)
51490e129ffSSebastian Andrzej Siewior {
51590e129ffSSebastian Andrzej Siewior 	struct ctf_stream *cs = cw->stream[cpu];
51690e129ffSSebastian Andrzej Siewior 
51790e129ffSSebastian Andrzej Siewior 	if (!cs) {
51890e129ffSSebastian Andrzej Siewior 		cs = ctf_stream__create(cw, cpu);
51990e129ffSSebastian Andrzej Siewior 		cw->stream[cpu] = cs;
52090e129ffSSebastian Andrzej Siewior 	}
52190e129ffSSebastian Andrzej Siewior 
52290e129ffSSebastian Andrzej Siewior 	return cs;
52390e129ffSSebastian Andrzej Siewior }
52490e129ffSSebastian Andrzej Siewior 
52590e129ffSSebastian Andrzej Siewior static int get_sample_cpu(struct ctf_writer *cw, struct perf_sample *sample,
52690e129ffSSebastian Andrzej Siewior 			  struct perf_evsel *evsel)
52790e129ffSSebastian Andrzej Siewior {
52890e129ffSSebastian Andrzej Siewior 	int cpu = 0;
52990e129ffSSebastian Andrzej Siewior 
53090e129ffSSebastian Andrzej Siewior 	if (evsel->attr.sample_type & PERF_SAMPLE_CPU)
53190e129ffSSebastian Andrzej Siewior 		cpu = sample->cpu;
53290e129ffSSebastian Andrzej Siewior 
53390e129ffSSebastian Andrzej Siewior 	if (cpu > cw->stream_cnt) {
53490e129ffSSebastian Andrzej Siewior 		pr_err("Event was recorded for CPU %d, limit is at %d.\n",
53590e129ffSSebastian Andrzej Siewior 			cpu, cw->stream_cnt);
53690e129ffSSebastian Andrzej Siewior 		cpu = 0;
53790e129ffSSebastian Andrzej Siewior 	}
53890e129ffSSebastian Andrzej Siewior 
53990e129ffSSebastian Andrzej Siewior 	return cpu;
54090e129ffSSebastian Andrzej Siewior }
54190e129ffSSebastian Andrzej Siewior 
54289e5fa88SJiri Olsa #define STREAM_FLUSH_COUNT 100000
54389e5fa88SJiri Olsa 
54489e5fa88SJiri Olsa /*
54589e5fa88SJiri Olsa  * Currently we have no other way to determine the
54689e5fa88SJiri Olsa  * time for the stream flush other than keep track
54789e5fa88SJiri Olsa  * of the number of events and check it against
54889e5fa88SJiri Olsa  * threshold.
54989e5fa88SJiri Olsa  */
55089e5fa88SJiri Olsa static bool is_flush_needed(struct ctf_stream *cs)
55189e5fa88SJiri Olsa {
55289e5fa88SJiri Olsa 	return cs->count >= STREAM_FLUSH_COUNT;
55389e5fa88SJiri Olsa }
55489e5fa88SJiri Olsa 
555edbe9817SJiri Olsa static int process_sample_event(struct perf_tool *tool,
556edbe9817SJiri Olsa 				union perf_event *_event __maybe_unused,
557edbe9817SJiri Olsa 				struct perf_sample *sample,
558edbe9817SJiri Olsa 				struct perf_evsel *evsel,
559edbe9817SJiri Olsa 				struct machine *machine __maybe_unused)
560edbe9817SJiri Olsa {
561edbe9817SJiri Olsa 	struct convert *c = container_of(tool, struct convert, tool);
562edbe9817SJiri Olsa 	struct evsel_priv *priv = evsel->priv;
563edbe9817SJiri Olsa 	struct ctf_writer *cw = &c->writer;
56490e129ffSSebastian Andrzej Siewior 	struct ctf_stream *cs;
565edbe9817SJiri Olsa 	struct bt_ctf_event_class *event_class;
566edbe9817SJiri Olsa 	struct bt_ctf_event *event;
567edbe9817SJiri Olsa 	int ret;
568edbe9817SJiri Olsa 
569edbe9817SJiri Olsa 	if (WARN_ONCE(!priv, "Failed to setup all events.\n"))
570edbe9817SJiri Olsa 		return 0;
571edbe9817SJiri Olsa 
572edbe9817SJiri Olsa 	event_class = priv->event_class;
573edbe9817SJiri Olsa 
574edbe9817SJiri Olsa 	/* update stats */
575edbe9817SJiri Olsa 	c->events_count++;
576edbe9817SJiri Olsa 	c->events_size += _event->header.size;
577edbe9817SJiri Olsa 
578edbe9817SJiri Olsa 	pr_time2(sample->time, "sample %" PRIu64 "\n", c->events_count);
579edbe9817SJiri Olsa 
580edbe9817SJiri Olsa 	event = bt_ctf_event_create(event_class);
581edbe9817SJiri Olsa 	if (!event) {
582edbe9817SJiri Olsa 		pr_err("Failed to create an CTF event\n");
583edbe9817SJiri Olsa 		return -1;
584edbe9817SJiri Olsa 	}
585edbe9817SJiri Olsa 
586edbe9817SJiri Olsa 	bt_ctf_clock_set_time(cw->clock, sample->time);
587edbe9817SJiri Olsa 
588edbe9817SJiri Olsa 	ret = add_generic_values(cw, event, evsel, sample);
589edbe9817SJiri Olsa 	if (ret)
590edbe9817SJiri Olsa 		return -1;
591edbe9817SJiri Olsa 
59269364727SSebastian Andrzej Siewior 	if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
59369364727SSebastian Andrzej Siewior 		ret = add_tracepoint_values(cw, event_class, event,
59469364727SSebastian Andrzej Siewior 					    evsel, sample);
59569364727SSebastian Andrzej Siewior 		if (ret)
59669364727SSebastian Andrzej Siewior 			return -1;
59769364727SSebastian Andrzej Siewior 	}
59869364727SSebastian Andrzej Siewior 
59990e129ffSSebastian Andrzej Siewior 	cs = ctf_stream(cw, get_sample_cpu(cw, sample, evsel));
60089e5fa88SJiri Olsa 	if (cs) {
60189e5fa88SJiri Olsa 		if (is_flush_needed(cs))
60289e5fa88SJiri Olsa 			ctf_stream__flush(cs);
60389e5fa88SJiri Olsa 
60489e5fa88SJiri Olsa 		cs->count++;
60590e129ffSSebastian Andrzej Siewior 		bt_ctf_stream_append_event(cs->stream, event);
60689e5fa88SJiri Olsa 	}
60790e129ffSSebastian Andrzej Siewior 
608edbe9817SJiri Olsa 	bt_ctf_event_put(event);
60990e129ffSSebastian Andrzej Siewior 	return cs ? 0 : -1;
610edbe9817SJiri Olsa }
611edbe9817SJiri Olsa 
612e0a7cce5SWang Nan /* If dup < 0, add a prefix. Else, add _dupl_X suffix. */
613e0a7cce5SWang Nan static char *change_name(char *name, char *orig_name, int dup)
614e0a7cce5SWang Nan {
615e0a7cce5SWang Nan 	char *new_name = NULL;
616e0a7cce5SWang Nan 	size_t len;
617e0a7cce5SWang Nan 
618e0a7cce5SWang Nan 	if (!name)
619e0a7cce5SWang Nan 		name = orig_name;
620e0a7cce5SWang Nan 
621e0a7cce5SWang Nan 	if (dup >= 10)
622e0a7cce5SWang Nan 		goto out;
623e0a7cce5SWang Nan 	/*
624e0a7cce5SWang Nan 	 * Add '_' prefix to potential keywork.  According to
625e0a7cce5SWang Nan 	 * Mathieu Desnoyers (https://lkml.org/lkml/2015/1/23/652),
626e0a7cce5SWang Nan 	 * futher CTF spec updating may require us to use '$'.
627e0a7cce5SWang Nan 	 */
628e0a7cce5SWang Nan 	if (dup < 0)
629e0a7cce5SWang Nan 		len = strlen(name) + sizeof("_");
630e0a7cce5SWang Nan 	else
631e0a7cce5SWang Nan 		len = strlen(orig_name) + sizeof("_dupl_X");
632e0a7cce5SWang Nan 
633e0a7cce5SWang Nan 	new_name = malloc(len);
634e0a7cce5SWang Nan 	if (!new_name)
635e0a7cce5SWang Nan 		goto out;
636e0a7cce5SWang Nan 
637e0a7cce5SWang Nan 	if (dup < 0)
638e0a7cce5SWang Nan 		snprintf(new_name, len, "_%s", name);
639e0a7cce5SWang Nan 	else
640e0a7cce5SWang Nan 		snprintf(new_name, len, "%s_dupl_%d", orig_name, dup);
641e0a7cce5SWang Nan 
642e0a7cce5SWang Nan out:
643e0a7cce5SWang Nan 	if (name != orig_name)
644e0a7cce5SWang Nan 		free(name);
645e0a7cce5SWang Nan 	return new_name;
646e0a7cce5SWang Nan }
647e0a7cce5SWang Nan 
648e0a7cce5SWang Nan static int event_class_add_field(struct bt_ctf_event_class *event_class,
649e0a7cce5SWang Nan 		struct bt_ctf_field_type *type,
650e0a7cce5SWang Nan 		struct format_field *field)
651e0a7cce5SWang Nan {
652e0a7cce5SWang Nan 	struct bt_ctf_field_type *t = NULL;
653e0a7cce5SWang Nan 	char *name;
654e0a7cce5SWang Nan 	int dup = 1;
655e0a7cce5SWang Nan 	int ret;
656e0a7cce5SWang Nan 
657e0a7cce5SWang Nan 	/* alias was already assigned */
658e0a7cce5SWang Nan 	if (field->alias != field->name)
659e0a7cce5SWang Nan 		return bt_ctf_event_class_add_field(event_class, type,
660e0a7cce5SWang Nan 				(char *)field->alias);
661e0a7cce5SWang Nan 
662e0a7cce5SWang Nan 	name = field->name;
663e0a7cce5SWang Nan 
664e0a7cce5SWang Nan 	/* If 'name' is a keywork, add prefix. */
665e0a7cce5SWang Nan 	if (bt_ctf_validate_identifier(name))
666e0a7cce5SWang Nan 		name = change_name(name, field->name, -1);
667e0a7cce5SWang Nan 
668e0a7cce5SWang Nan 	if (!name) {
669e0a7cce5SWang Nan 		pr_err("Failed to fix invalid identifier.");
670e0a7cce5SWang Nan 		return -1;
671e0a7cce5SWang Nan 	}
672e0a7cce5SWang Nan 	while ((t = bt_ctf_event_class_get_field_by_name(event_class, name))) {
673e0a7cce5SWang Nan 		bt_ctf_field_type_put(t);
674e0a7cce5SWang Nan 		name = change_name(name, field->name, dup++);
675e0a7cce5SWang Nan 		if (!name) {
676e0a7cce5SWang Nan 			pr_err("Failed to create dup name for '%s'\n", field->name);
677e0a7cce5SWang Nan 			return -1;
678e0a7cce5SWang Nan 		}
679e0a7cce5SWang Nan 	}
680e0a7cce5SWang Nan 
681e0a7cce5SWang Nan 	ret = bt_ctf_event_class_add_field(event_class, type, name);
682e0a7cce5SWang Nan 	if (!ret)
683e0a7cce5SWang Nan 		field->alias = name;
684e0a7cce5SWang Nan 
685e0a7cce5SWang Nan 	return ret;
686e0a7cce5SWang Nan }
687e0a7cce5SWang Nan 
68869364727SSebastian Andrzej Siewior static int add_tracepoint_fields_types(struct ctf_writer *cw,
68969364727SSebastian Andrzej Siewior 				       struct format_field *fields,
69069364727SSebastian Andrzej Siewior 				       struct bt_ctf_event_class *event_class)
69169364727SSebastian Andrzej Siewior {
69269364727SSebastian Andrzej Siewior 	struct format_field *field;
69369364727SSebastian Andrzej Siewior 	int ret;
69469364727SSebastian Andrzej Siewior 
69569364727SSebastian Andrzej Siewior 	for (field = fields; field; field = field->next) {
69669364727SSebastian Andrzej Siewior 		struct bt_ctf_field_type *type;
69769364727SSebastian Andrzej Siewior 		unsigned long flags = field->flags;
69869364727SSebastian Andrzej Siewior 
69969364727SSebastian Andrzej Siewior 		pr2("  field '%s'\n", field->name);
70069364727SSebastian Andrzej Siewior 
70169364727SSebastian Andrzej Siewior 		type = get_tracepoint_field_type(cw, field);
70269364727SSebastian Andrzej Siewior 		if (!type)
70369364727SSebastian Andrzej Siewior 			return -1;
70469364727SSebastian Andrzej Siewior 
70569364727SSebastian Andrzej Siewior 		/*
70669364727SSebastian Andrzej Siewior 		 * A string is an array of chars. For this we use the string
70769364727SSebastian Andrzej Siewior 		 * type and don't care that it is an array. What we don't
70869364727SSebastian Andrzej Siewior 		 * support is an array of strings.
70969364727SSebastian Andrzej Siewior 		 */
71069364727SSebastian Andrzej Siewior 		if (flags & FIELD_IS_STRING)
71169364727SSebastian Andrzej Siewior 			flags &= ~FIELD_IS_ARRAY;
71269364727SSebastian Andrzej Siewior 
71369364727SSebastian Andrzej Siewior 		if (flags & FIELD_IS_ARRAY)
71469364727SSebastian Andrzej Siewior 			type = bt_ctf_field_type_array_create(type, field->arraylen);
71569364727SSebastian Andrzej Siewior 
716e0a7cce5SWang Nan 		ret = event_class_add_field(event_class, type, field);
71769364727SSebastian Andrzej Siewior 
71869364727SSebastian Andrzej Siewior 		if (flags & FIELD_IS_ARRAY)
71969364727SSebastian Andrzej Siewior 			bt_ctf_field_type_put(type);
72069364727SSebastian Andrzej Siewior 
72169364727SSebastian Andrzej Siewior 		if (ret) {
722e0a7cce5SWang Nan 			pr_err("Failed to add field '%s': %d\n",
723e0a7cce5SWang Nan 					field->name, ret);
72469364727SSebastian Andrzej Siewior 			return -1;
72569364727SSebastian Andrzej Siewior 		}
72669364727SSebastian Andrzej Siewior 	}
72769364727SSebastian Andrzej Siewior 
72869364727SSebastian Andrzej Siewior 	return 0;
72969364727SSebastian Andrzej Siewior }
73069364727SSebastian Andrzej Siewior 
73169364727SSebastian Andrzej Siewior static int add_tracepoint_types(struct ctf_writer *cw,
73269364727SSebastian Andrzej Siewior 				struct perf_evsel *evsel,
73369364727SSebastian Andrzej Siewior 				struct bt_ctf_event_class *class)
73469364727SSebastian Andrzej Siewior {
73569364727SSebastian Andrzej Siewior 	struct format_field *common_fields = evsel->tp_format->format.common_fields;
73669364727SSebastian Andrzej Siewior 	struct format_field *fields        = evsel->tp_format->format.fields;
73769364727SSebastian Andrzej Siewior 	int ret;
73869364727SSebastian Andrzej Siewior 
73969364727SSebastian Andrzej Siewior 	ret = add_tracepoint_fields_types(cw, common_fields, class);
74069364727SSebastian Andrzej Siewior 	if (!ret)
74169364727SSebastian Andrzej Siewior 		ret = add_tracepoint_fields_types(cw, fields, class);
74269364727SSebastian Andrzej Siewior 
74369364727SSebastian Andrzej Siewior 	return ret;
74469364727SSebastian Andrzej Siewior }
74569364727SSebastian Andrzej Siewior 
746edbe9817SJiri Olsa static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
747edbe9817SJiri Olsa 			     struct bt_ctf_event_class *event_class)
748edbe9817SJiri Olsa {
749edbe9817SJiri Olsa 	u64 type = evsel->attr.sample_type;
750edbe9817SJiri Olsa 
751edbe9817SJiri Olsa 	/*
752edbe9817SJiri Olsa 	 * missing:
753edbe9817SJiri Olsa 	 *   PERF_SAMPLE_TIME         - not needed as we have it in
754edbe9817SJiri Olsa 	 *                              ctf event header
755edbe9817SJiri Olsa 	 *   PERF_SAMPLE_READ         - TODO
756edbe9817SJiri Olsa 	 *   PERF_SAMPLE_CALLCHAIN    - TODO
757edbe9817SJiri Olsa 	 *   PERF_SAMPLE_RAW          - tracepoint fields are handled separately
758edbe9817SJiri Olsa 	 *   PERF_SAMPLE_BRANCH_STACK - TODO
759edbe9817SJiri Olsa 	 *   PERF_SAMPLE_REGS_USER    - TODO
760edbe9817SJiri Olsa 	 *   PERF_SAMPLE_STACK_USER   - TODO
761edbe9817SJiri Olsa 	 */
762edbe9817SJiri Olsa 
763edbe9817SJiri Olsa #define ADD_FIELD(cl, t, n)						\
764edbe9817SJiri Olsa 	do {								\
765edbe9817SJiri Olsa 		pr2("  field '%s'\n", n);				\
766edbe9817SJiri Olsa 		if (bt_ctf_event_class_add_field(cl, t, n)) {		\
767e0a7cce5SWang Nan 			pr_err("Failed to add field '%s';\n", n);	\
768edbe9817SJiri Olsa 			return -1;					\
769edbe9817SJiri Olsa 		}							\
770edbe9817SJiri Olsa 	} while (0)
771edbe9817SJiri Olsa 
772edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_IP)
77354cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64_hex, "perf_ip");
774edbe9817SJiri Olsa 
775edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_TID) {
77654cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.s32, "perf_tid");
77754cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.s32, "perf_pid");
778edbe9817SJiri Olsa 	}
779edbe9817SJiri Olsa 
780edbe9817SJiri Olsa 	if ((type & PERF_SAMPLE_ID) ||
781edbe9817SJiri Olsa 	    (type & PERF_SAMPLE_IDENTIFIER))
78254cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64, "perf_id");
783edbe9817SJiri Olsa 
784edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_STREAM_ID)
78554cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64, "perf_stream_id");
786edbe9817SJiri Olsa 
787edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_PERIOD)
78854cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64, "perf_period");
789edbe9817SJiri Olsa 
790edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_WEIGHT)
79154cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64, "perf_weight");
792edbe9817SJiri Olsa 
793edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_DATA_SRC)
79454cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64, "perf_data_src");
795edbe9817SJiri Olsa 
796edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_TRANSACTION)
79754cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64, "perf_transaction");
798edbe9817SJiri Olsa 
799edbe9817SJiri Olsa #undef ADD_FIELD
800edbe9817SJiri Olsa 	return 0;
801edbe9817SJiri Olsa }
802edbe9817SJiri Olsa 
803edbe9817SJiri Olsa static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
804edbe9817SJiri Olsa {
805edbe9817SJiri Olsa 	struct bt_ctf_event_class *event_class;
806edbe9817SJiri Olsa 	struct evsel_priv *priv;
807edbe9817SJiri Olsa 	const char *name = perf_evsel__name(evsel);
808edbe9817SJiri Olsa 	int ret;
809edbe9817SJiri Olsa 
810edbe9817SJiri Olsa 	pr("Adding event '%s' (type %d)\n", name, evsel->attr.type);
811edbe9817SJiri Olsa 
812edbe9817SJiri Olsa 	event_class = bt_ctf_event_class_create(name);
813edbe9817SJiri Olsa 	if (!event_class)
814edbe9817SJiri Olsa 		return -1;
815edbe9817SJiri Olsa 
816edbe9817SJiri Olsa 	ret = add_generic_types(cw, evsel, event_class);
817edbe9817SJiri Olsa 	if (ret)
818edbe9817SJiri Olsa 		goto err;
819edbe9817SJiri Olsa 
82069364727SSebastian Andrzej Siewior 	if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
82169364727SSebastian Andrzej Siewior 		ret = add_tracepoint_types(cw, evsel, event_class);
82269364727SSebastian Andrzej Siewior 		if (ret)
82369364727SSebastian Andrzej Siewior 			goto err;
82469364727SSebastian Andrzej Siewior 	}
82569364727SSebastian Andrzej Siewior 
826edbe9817SJiri Olsa 	ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);
827edbe9817SJiri Olsa 	if (ret) {
828edbe9817SJiri Olsa 		pr("Failed to add event class into stream.\n");
829edbe9817SJiri Olsa 		goto err;
830edbe9817SJiri Olsa 	}
831edbe9817SJiri Olsa 
832edbe9817SJiri Olsa 	priv = malloc(sizeof(*priv));
833edbe9817SJiri Olsa 	if (!priv)
834edbe9817SJiri Olsa 		goto err;
835edbe9817SJiri Olsa 
836edbe9817SJiri Olsa 	priv->event_class = event_class;
837edbe9817SJiri Olsa 	evsel->priv       = priv;
838edbe9817SJiri Olsa 	return 0;
839edbe9817SJiri Olsa 
840edbe9817SJiri Olsa err:
841edbe9817SJiri Olsa 	bt_ctf_event_class_put(event_class);
842edbe9817SJiri Olsa 	pr_err("Failed to add event '%s'.\n", name);
843edbe9817SJiri Olsa 	return -1;
844edbe9817SJiri Olsa }
845edbe9817SJiri Olsa 
846edbe9817SJiri Olsa static int setup_events(struct ctf_writer *cw, struct perf_session *session)
847edbe9817SJiri Olsa {
848edbe9817SJiri Olsa 	struct perf_evlist *evlist = session->evlist;
849edbe9817SJiri Olsa 	struct perf_evsel *evsel;
850edbe9817SJiri Olsa 	int ret;
851edbe9817SJiri Olsa 
852edbe9817SJiri Olsa 	evlist__for_each(evlist, evsel) {
853edbe9817SJiri Olsa 		ret = add_event(cw, evsel);
854edbe9817SJiri Olsa 		if (ret)
855edbe9817SJiri Olsa 			return ret;
856edbe9817SJiri Olsa 	}
857edbe9817SJiri Olsa 	return 0;
858edbe9817SJiri Olsa }
859edbe9817SJiri Olsa 
86090e129ffSSebastian Andrzej Siewior static int setup_streams(struct ctf_writer *cw, struct perf_session *session)
86190e129ffSSebastian Andrzej Siewior {
86290e129ffSSebastian Andrzej Siewior 	struct ctf_stream **stream;
86390e129ffSSebastian Andrzej Siewior 	struct perf_header *ph = &session->header;
86490e129ffSSebastian Andrzej Siewior 	int ncpus;
86590e129ffSSebastian Andrzej Siewior 
86690e129ffSSebastian Andrzej Siewior 	/*
86790e129ffSSebastian Andrzej Siewior 	 * Try to get the number of cpus used in the data file,
86890e129ffSSebastian Andrzej Siewior 	 * if not present fallback to the MAX_CPUS.
86990e129ffSSebastian Andrzej Siewior 	 */
87090e129ffSSebastian Andrzej Siewior 	ncpus = ph->env.nr_cpus_avail ?: MAX_CPUS;
87190e129ffSSebastian Andrzej Siewior 
87290e129ffSSebastian Andrzej Siewior 	stream = zalloc(sizeof(*stream) * ncpus);
87390e129ffSSebastian Andrzej Siewior 	if (!stream) {
87490e129ffSSebastian Andrzej Siewior 		pr_err("Failed to allocate streams.\n");
87590e129ffSSebastian Andrzej Siewior 		return -ENOMEM;
87690e129ffSSebastian Andrzej Siewior 	}
87790e129ffSSebastian Andrzej Siewior 
87890e129ffSSebastian Andrzej Siewior 	cw->stream     = stream;
87990e129ffSSebastian Andrzej Siewior 	cw->stream_cnt = ncpus;
88090e129ffSSebastian Andrzej Siewior 	return 0;
88190e129ffSSebastian Andrzej Siewior }
88290e129ffSSebastian Andrzej Siewior 
88390e129ffSSebastian Andrzej Siewior static void free_streams(struct ctf_writer *cw)
88490e129ffSSebastian Andrzej Siewior {
88590e129ffSSebastian Andrzej Siewior 	int cpu;
88690e129ffSSebastian Andrzej Siewior 
88790e129ffSSebastian Andrzej Siewior 	for (cpu = 0; cpu < cw->stream_cnt; cpu++)
88890e129ffSSebastian Andrzej Siewior 		ctf_stream__delete(cw->stream[cpu]);
88990e129ffSSebastian Andrzej Siewior 
89090e129ffSSebastian Andrzej Siewior 	free(cw->stream);
89190e129ffSSebastian Andrzej Siewior }
89290e129ffSSebastian Andrzej Siewior 
893edbe9817SJiri Olsa static int ctf_writer__setup_env(struct ctf_writer *cw,
894edbe9817SJiri Olsa 				 struct perf_session *session)
895edbe9817SJiri Olsa {
896edbe9817SJiri Olsa 	struct perf_header *header = &session->header;
897edbe9817SJiri Olsa 	struct bt_ctf_writer *writer = cw->writer;
898edbe9817SJiri Olsa 
899edbe9817SJiri Olsa #define ADD(__n, __v)							\
900edbe9817SJiri Olsa do {									\
901edbe9817SJiri Olsa 	if (bt_ctf_writer_add_environment_field(writer, __n, __v))	\
902edbe9817SJiri Olsa 		return -1;						\
903edbe9817SJiri Olsa } while (0)
904edbe9817SJiri Olsa 
905edbe9817SJiri Olsa 	ADD("host",    header->env.hostname);
906edbe9817SJiri Olsa 	ADD("sysname", "Linux");
907edbe9817SJiri Olsa 	ADD("release", header->env.os_release);
908edbe9817SJiri Olsa 	ADD("version", header->env.version);
909edbe9817SJiri Olsa 	ADD("machine", header->env.arch);
910edbe9817SJiri Olsa 	ADD("domain", "kernel");
911edbe9817SJiri Olsa 	ADD("tracer_name", "perf");
912edbe9817SJiri Olsa 
913edbe9817SJiri Olsa #undef ADD
914edbe9817SJiri Olsa 	return 0;
915edbe9817SJiri Olsa }
916edbe9817SJiri Olsa 
917edbe9817SJiri Olsa static int ctf_writer__setup_clock(struct ctf_writer *cw)
918edbe9817SJiri Olsa {
919edbe9817SJiri Olsa 	struct bt_ctf_clock *clock = cw->clock;
920edbe9817SJiri Olsa 
921edbe9817SJiri Olsa 	bt_ctf_clock_set_description(clock, "perf clock");
922edbe9817SJiri Olsa 
923edbe9817SJiri Olsa #define SET(__n, __v)				\
924edbe9817SJiri Olsa do {						\
925edbe9817SJiri Olsa 	if (bt_ctf_clock_set_##__n(clock, __v))	\
926edbe9817SJiri Olsa 		return -1;			\
927edbe9817SJiri Olsa } while (0)
928edbe9817SJiri Olsa 
929edbe9817SJiri Olsa 	SET(frequency,   1000000000);
930edbe9817SJiri Olsa 	SET(offset_s,    0);
931edbe9817SJiri Olsa 	SET(offset,      0);
932edbe9817SJiri Olsa 	SET(precision,   10);
933edbe9817SJiri Olsa 	SET(is_absolute, 0);
934edbe9817SJiri Olsa 
935edbe9817SJiri Olsa #undef SET
936edbe9817SJiri Olsa 	return 0;
937edbe9817SJiri Olsa }
938edbe9817SJiri Olsa 
939edbe9817SJiri Olsa static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex)
940edbe9817SJiri Olsa {
941edbe9817SJiri Olsa 	struct bt_ctf_field_type *type;
942edbe9817SJiri Olsa 
943edbe9817SJiri Olsa 	type = bt_ctf_field_type_integer_create(size);
944edbe9817SJiri Olsa 	if (!type)
945edbe9817SJiri Olsa 		return NULL;
946edbe9817SJiri Olsa 
947edbe9817SJiri Olsa 	if (sign &&
948edbe9817SJiri Olsa 	    bt_ctf_field_type_integer_set_signed(type, 1))
949edbe9817SJiri Olsa 		goto err;
950edbe9817SJiri Olsa 
951edbe9817SJiri Olsa 	if (hex &&
952edbe9817SJiri Olsa 	    bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL))
953edbe9817SJiri Olsa 		goto err;
954edbe9817SJiri Olsa 
955edbe9817SJiri Olsa 	pr2("Created type: INTEGER %d-bit %ssigned %s\n",
956edbe9817SJiri Olsa 	    size, sign ? "un" : "", hex ? "hex" : "");
957edbe9817SJiri Olsa 	return type;
958edbe9817SJiri Olsa 
959edbe9817SJiri Olsa err:
960edbe9817SJiri Olsa 	bt_ctf_field_type_put(type);
961edbe9817SJiri Olsa 	return NULL;
962edbe9817SJiri Olsa }
963edbe9817SJiri Olsa 
964edbe9817SJiri Olsa static void ctf_writer__cleanup_data(struct ctf_writer *cw)
965edbe9817SJiri Olsa {
966edbe9817SJiri Olsa 	unsigned int i;
967edbe9817SJiri Olsa 
968edbe9817SJiri Olsa 	for (i = 0; i < ARRAY_SIZE(cw->data.array); i++)
969edbe9817SJiri Olsa 		bt_ctf_field_type_put(cw->data.array[i]);
970edbe9817SJiri Olsa }
971edbe9817SJiri Olsa 
972edbe9817SJiri Olsa static int ctf_writer__init_data(struct ctf_writer *cw)
973edbe9817SJiri Olsa {
974edbe9817SJiri Olsa #define CREATE_INT_TYPE(type, size, sign, hex)		\
975edbe9817SJiri Olsa do {							\
976edbe9817SJiri Olsa 	(type) = create_int_type(size, sign, hex);	\
977edbe9817SJiri Olsa 	if (!(type))					\
978edbe9817SJiri Olsa 		goto err;				\
979edbe9817SJiri Olsa } while (0)
980edbe9817SJiri Olsa 
981edbe9817SJiri Olsa 	CREATE_INT_TYPE(cw->data.s64, 64, true,  false);
982edbe9817SJiri Olsa 	CREATE_INT_TYPE(cw->data.u64, 64, false, false);
983edbe9817SJiri Olsa 	CREATE_INT_TYPE(cw->data.s32, 32, true,  false);
984edbe9817SJiri Olsa 	CREATE_INT_TYPE(cw->data.u32, 32, false, false);
985edbe9817SJiri Olsa 	CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true);
986edbe9817SJiri Olsa 
987edbe9817SJiri Olsa 	cw->data.string  = bt_ctf_field_type_string_create();
988edbe9817SJiri Olsa 	if (cw->data.string)
989edbe9817SJiri Olsa 		return 0;
990edbe9817SJiri Olsa 
991edbe9817SJiri Olsa err:
992edbe9817SJiri Olsa 	ctf_writer__cleanup_data(cw);
993edbe9817SJiri Olsa 	pr_err("Failed to create data types.\n");
994edbe9817SJiri Olsa 	return -1;
995edbe9817SJiri Olsa }
996edbe9817SJiri Olsa 
997edbe9817SJiri Olsa static void ctf_writer__cleanup(struct ctf_writer *cw)
998edbe9817SJiri Olsa {
999edbe9817SJiri Olsa 	ctf_writer__cleanup_data(cw);
1000edbe9817SJiri Olsa 
1001edbe9817SJiri Olsa 	bt_ctf_clock_put(cw->clock);
100290e129ffSSebastian Andrzej Siewior 	free_streams(cw);
1003edbe9817SJiri Olsa 	bt_ctf_stream_class_put(cw->stream_class);
1004edbe9817SJiri Olsa 	bt_ctf_writer_put(cw->writer);
1005edbe9817SJiri Olsa 
1006edbe9817SJiri Olsa 	/* and NULL all the pointers */
1007edbe9817SJiri Olsa 	memset(cw, 0, sizeof(*cw));
1008edbe9817SJiri Olsa }
1009edbe9817SJiri Olsa 
1010edbe9817SJiri Olsa static int ctf_writer__init(struct ctf_writer *cw, const char *path)
1011edbe9817SJiri Olsa {
1012edbe9817SJiri Olsa 	struct bt_ctf_writer		*writer;
1013edbe9817SJiri Olsa 	struct bt_ctf_stream_class	*stream_class;
1014edbe9817SJiri Olsa 	struct bt_ctf_clock		*clock;
101590e129ffSSebastian Andrzej Siewior 	struct bt_ctf_field_type	*pkt_ctx_type;
101690e129ffSSebastian Andrzej Siewior 	int				ret;
1017edbe9817SJiri Olsa 
1018edbe9817SJiri Olsa 	/* CTF writer */
1019edbe9817SJiri Olsa 	writer = bt_ctf_writer_create(path);
1020edbe9817SJiri Olsa 	if (!writer)
1021edbe9817SJiri Olsa 		goto err;
1022edbe9817SJiri Olsa 
1023edbe9817SJiri Olsa 	cw->writer = writer;
1024edbe9817SJiri Olsa 
1025edbe9817SJiri Olsa 	/* CTF clock */
1026edbe9817SJiri Olsa 	clock = bt_ctf_clock_create("perf_clock");
1027edbe9817SJiri Olsa 	if (!clock) {
1028edbe9817SJiri Olsa 		pr("Failed to create CTF clock.\n");
1029edbe9817SJiri Olsa 		goto err_cleanup;
1030edbe9817SJiri Olsa 	}
1031edbe9817SJiri Olsa 
1032edbe9817SJiri Olsa 	cw->clock = clock;
1033edbe9817SJiri Olsa 
1034edbe9817SJiri Olsa 	if (ctf_writer__setup_clock(cw)) {
1035edbe9817SJiri Olsa 		pr("Failed to setup CTF clock.\n");
1036edbe9817SJiri Olsa 		goto err_cleanup;
1037edbe9817SJiri Olsa 	}
1038edbe9817SJiri Olsa 
1039edbe9817SJiri Olsa 	/* CTF stream class */
1040edbe9817SJiri Olsa 	stream_class = bt_ctf_stream_class_create("perf_stream");
1041edbe9817SJiri Olsa 	if (!stream_class) {
1042edbe9817SJiri Olsa 		pr("Failed to create CTF stream class.\n");
1043edbe9817SJiri Olsa 		goto err_cleanup;
1044edbe9817SJiri Olsa 	}
1045edbe9817SJiri Olsa 
1046edbe9817SJiri Olsa 	cw->stream_class = stream_class;
1047edbe9817SJiri Olsa 
1048edbe9817SJiri Olsa 	/* CTF clock stream setup */
1049edbe9817SJiri Olsa 	if (bt_ctf_stream_class_set_clock(stream_class, clock)) {
1050edbe9817SJiri Olsa 		pr("Failed to assign CTF clock to stream class.\n");
1051edbe9817SJiri Olsa 		goto err_cleanup;
1052edbe9817SJiri Olsa 	}
1053edbe9817SJiri Olsa 
1054edbe9817SJiri Olsa 	if (ctf_writer__init_data(cw))
1055edbe9817SJiri Olsa 		goto err_cleanup;
1056edbe9817SJiri Olsa 
105790e129ffSSebastian Andrzej Siewior 	/* Add cpu_id for packet context */
105890e129ffSSebastian Andrzej Siewior 	pkt_ctx_type = bt_ctf_stream_class_get_packet_context_type(stream_class);
105990e129ffSSebastian Andrzej Siewior 	if (!pkt_ctx_type)
1060edbe9817SJiri Olsa 		goto err_cleanup;
1061edbe9817SJiri Olsa 
106290e129ffSSebastian Andrzej Siewior 	ret = bt_ctf_field_type_structure_add_field(pkt_ctx_type, cw->data.u32, "cpu_id");
106390e129ffSSebastian Andrzej Siewior 	bt_ctf_field_type_put(pkt_ctx_type);
106490e129ffSSebastian Andrzej Siewior 	if (ret)
106590e129ffSSebastian Andrzej Siewior 		goto err_cleanup;
1066edbe9817SJiri Olsa 
1067edbe9817SJiri Olsa 	/* CTF clock writer setup */
1068edbe9817SJiri Olsa 	if (bt_ctf_writer_add_clock(writer, clock)) {
1069edbe9817SJiri Olsa 		pr("Failed to assign CTF clock to writer.\n");
1070edbe9817SJiri Olsa 		goto err_cleanup;
1071edbe9817SJiri Olsa 	}
1072edbe9817SJiri Olsa 
1073edbe9817SJiri Olsa 	return 0;
1074edbe9817SJiri Olsa 
1075edbe9817SJiri Olsa err_cleanup:
1076edbe9817SJiri Olsa 	ctf_writer__cleanup(cw);
1077edbe9817SJiri Olsa err:
1078edbe9817SJiri Olsa 	pr_err("Failed to setup CTF writer.\n");
1079edbe9817SJiri Olsa 	return -1;
1080edbe9817SJiri Olsa }
1081edbe9817SJiri Olsa 
108290e129ffSSebastian Andrzej Siewior static int ctf_writer__flush_streams(struct ctf_writer *cw)
108390e129ffSSebastian Andrzej Siewior {
108490e129ffSSebastian Andrzej Siewior 	int cpu, ret = 0;
108590e129ffSSebastian Andrzej Siewior 
108690e129ffSSebastian Andrzej Siewior 	for (cpu = 0; cpu < cw->stream_cnt && !ret; cpu++)
108790e129ffSSebastian Andrzej Siewior 		ret = ctf_stream__flush(cw->stream[cpu]);
108890e129ffSSebastian Andrzej Siewior 
108990e129ffSSebastian Andrzej Siewior 	return ret;
109090e129ffSSebastian Andrzej Siewior }
109190e129ffSSebastian Andrzej Siewior 
10928fa46753SJiri Olsa static int convert__config(const char *var, const char *value, void *cb)
10938fa46753SJiri Olsa {
10948fa46753SJiri Olsa 	struct convert *c = cb;
10958fa46753SJiri Olsa 
10968fa46753SJiri Olsa 	if (!strcmp(var, "convert.queue-size")) {
10978fa46753SJiri Olsa 		c->queue_size = perf_config_u64(var, value);
10988fa46753SJiri Olsa 		return 0;
10998fa46753SJiri Olsa 	}
11008fa46753SJiri Olsa 
11018fa46753SJiri Olsa 	return perf_default_config(var, value, cb);
11028fa46753SJiri Olsa }
11038fa46753SJiri Olsa 
1104bd05954bSYunlong Song int bt_convert__perf2ctf(const char *input, const char *path, bool force)
1105edbe9817SJiri Olsa {
1106edbe9817SJiri Olsa 	struct perf_session *session;
1107edbe9817SJiri Olsa 	struct perf_data_file file = {
1108edbe9817SJiri Olsa 		.path = input,
1109edbe9817SJiri Olsa 		.mode = PERF_DATA_MODE_READ,
1110bd05954bSYunlong Song 		.force = force,
1111edbe9817SJiri Olsa 	};
1112edbe9817SJiri Olsa 	struct convert c = {
1113edbe9817SJiri Olsa 		.tool = {
1114edbe9817SJiri Olsa 			.sample          = process_sample_event,
1115edbe9817SJiri Olsa 			.mmap            = perf_event__process_mmap,
1116edbe9817SJiri Olsa 			.mmap2           = perf_event__process_mmap2,
1117edbe9817SJiri Olsa 			.comm            = perf_event__process_comm,
1118edbe9817SJiri Olsa 			.exit            = perf_event__process_exit,
1119edbe9817SJiri Olsa 			.fork            = perf_event__process_fork,
1120edbe9817SJiri Olsa 			.lost            = perf_event__process_lost,
1121edbe9817SJiri Olsa 			.tracing_data    = perf_event__process_tracing_data,
1122edbe9817SJiri Olsa 			.build_id        = perf_event__process_build_id,
1123edbe9817SJiri Olsa 			.ordered_events  = true,
1124edbe9817SJiri Olsa 			.ordering_requires_timestamps = true,
1125edbe9817SJiri Olsa 		},
1126edbe9817SJiri Olsa 	};
1127edbe9817SJiri Olsa 	struct ctf_writer *cw = &c.writer;
1128edbe9817SJiri Olsa 	int err = -1;
1129edbe9817SJiri Olsa 
11308fa46753SJiri Olsa 	perf_config(convert__config, &c);
11318fa46753SJiri Olsa 
1132edbe9817SJiri Olsa 	/* CTF writer */
1133edbe9817SJiri Olsa 	if (ctf_writer__init(cw, path))
1134edbe9817SJiri Olsa 		return -1;
1135edbe9817SJiri Olsa 
1136edbe9817SJiri Olsa 	/* perf.data session */
1137b7b61cbeSArnaldo Carvalho de Melo 	session = perf_session__new(&file, 0, &c.tool);
1138edbe9817SJiri Olsa 	if (!session)
1139edbe9817SJiri Olsa 		goto free_writer;
1140edbe9817SJiri Olsa 
11418fa46753SJiri Olsa 	if (c.queue_size) {
11428fa46753SJiri Olsa 		ordered_events__set_alloc_size(&session->ordered_events,
11438fa46753SJiri Olsa 					       c.queue_size);
11448fa46753SJiri Olsa 	}
11458fa46753SJiri Olsa 
1146edbe9817SJiri Olsa 	/* CTF writer env/clock setup  */
1147edbe9817SJiri Olsa 	if (ctf_writer__setup_env(cw, session))
1148edbe9817SJiri Olsa 		goto free_session;
1149edbe9817SJiri Olsa 
1150edbe9817SJiri Olsa 	/* CTF events setup */
1151edbe9817SJiri Olsa 	if (setup_events(cw, session))
1152edbe9817SJiri Olsa 		goto free_session;
1153edbe9817SJiri Olsa 
115490e129ffSSebastian Andrzej Siewior 	if (setup_streams(cw, session))
115590e129ffSSebastian Andrzej Siewior 		goto free_session;
115690e129ffSSebastian Andrzej Siewior 
1157b7b61cbeSArnaldo Carvalho de Melo 	err = perf_session__process_events(session);
1158edbe9817SJiri Olsa 	if (!err)
115990e129ffSSebastian Andrzej Siewior 		err = ctf_writer__flush_streams(cw);
1160c2141055SHe Kuang 	else
1161c2141055SHe Kuang 		pr_err("Error during conversion.\n");
1162edbe9817SJiri Olsa 
1163edbe9817SJiri Olsa 	fprintf(stderr,
1164edbe9817SJiri Olsa 		"[ perf data convert: Converted '%s' into CTF data '%s' ]\n",
1165edbe9817SJiri Olsa 		file.path, path);
1166edbe9817SJiri Olsa 
1167edbe9817SJiri Olsa 	fprintf(stderr,
1168edbe9817SJiri Olsa 		"[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples) ]\n",
1169edbe9817SJiri Olsa 		(double) c.events_size / 1024.0 / 1024.0,
1170edbe9817SJiri Olsa 		c.events_count);
1171edbe9817SJiri Olsa 
1172c2141055SHe Kuang 	perf_session__delete(session);
1173c2141055SHe Kuang 	ctf_writer__cleanup(cw);
1174c2141055SHe Kuang 
1175c2141055SHe Kuang 	return err;
1176c2141055SHe Kuang 
1177edbe9817SJiri Olsa free_session:
1178edbe9817SJiri Olsa 	perf_session__delete(session);
1179edbe9817SJiri Olsa free_writer:
1180edbe9817SJiri Olsa 	ctf_writer__cleanup(cw);
1181c2141055SHe Kuang 	pr_err("Error during conversion setup.\n");
1182edbe9817SJiri Olsa 	return err;
1183edbe9817SJiri Olsa }
1184