xref: /linux/tools/perf/util/data-convert-bt.c (revision b8cbb349061edda648463b086cfa869a7ab583af)
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;
6626812d46SWang Nan 			struct bt_ctf_field_type	*u32_hex;
67edbe9817SJiri Olsa 			struct bt_ctf_field_type	*u64_hex;
68edbe9817SJiri Olsa 		};
69edbe9817SJiri Olsa 		struct bt_ctf_field_type *array[6];
70edbe9817SJiri Olsa 	} data;
71edbe9817SJiri Olsa };
72edbe9817SJiri Olsa 
73edbe9817SJiri Olsa struct convert {
74edbe9817SJiri Olsa 	struct perf_tool	tool;
75edbe9817SJiri Olsa 	struct ctf_writer	writer;
76edbe9817SJiri Olsa 
77edbe9817SJiri Olsa 	u64			events_size;
78edbe9817SJiri Olsa 	u64			events_count;
798fa46753SJiri Olsa 
808fa46753SJiri Olsa 	/* Ordered events configured queue size. */
818fa46753SJiri Olsa 	u64			queue_size;
82edbe9817SJiri Olsa };
83edbe9817SJiri Olsa 
84edbe9817SJiri Olsa static int value_set(struct bt_ctf_field_type *type,
85edbe9817SJiri Olsa 		     struct bt_ctf_event *event,
86edbe9817SJiri Olsa 		     const char *name, u64 val)
87edbe9817SJiri Olsa {
88edbe9817SJiri Olsa 	struct bt_ctf_field *field;
89edbe9817SJiri Olsa 	bool sign = bt_ctf_field_type_integer_get_signed(type);
90edbe9817SJiri Olsa 	int ret;
91edbe9817SJiri Olsa 
92edbe9817SJiri Olsa 	field = bt_ctf_field_create(type);
93edbe9817SJiri Olsa 	if (!field) {
94edbe9817SJiri Olsa 		pr_err("failed to create a field %s\n", name);
95edbe9817SJiri Olsa 		return -1;
96edbe9817SJiri Olsa 	}
97edbe9817SJiri Olsa 
98edbe9817SJiri Olsa 	if (sign) {
99edbe9817SJiri Olsa 		ret = bt_ctf_field_signed_integer_set_value(field, val);
100edbe9817SJiri Olsa 		if (ret) {
101edbe9817SJiri Olsa 			pr_err("failed to set field value %s\n", name);
102edbe9817SJiri Olsa 			goto err;
103edbe9817SJiri Olsa 		}
104edbe9817SJiri Olsa 	} else {
105edbe9817SJiri Olsa 		ret = bt_ctf_field_unsigned_integer_set_value(field, val);
106edbe9817SJiri Olsa 		if (ret) {
107edbe9817SJiri Olsa 			pr_err("failed to set field value %s\n", name);
108edbe9817SJiri Olsa 			goto err;
109edbe9817SJiri Olsa 		}
110edbe9817SJiri Olsa 	}
111edbe9817SJiri Olsa 
112edbe9817SJiri Olsa 	ret = bt_ctf_event_set_payload(event, name, field);
113edbe9817SJiri Olsa 	if (ret) {
114edbe9817SJiri Olsa 		pr_err("failed to set payload %s\n", name);
115edbe9817SJiri Olsa 		goto err;
116edbe9817SJiri Olsa 	}
117edbe9817SJiri Olsa 
118edbe9817SJiri Olsa 	pr2("  SET [%s = %" PRIu64 "]\n", name, val);
119edbe9817SJiri Olsa 
120edbe9817SJiri Olsa err:
121edbe9817SJiri Olsa 	bt_ctf_field_put(field);
122edbe9817SJiri Olsa 	return ret;
123edbe9817SJiri Olsa }
124edbe9817SJiri Olsa 
125edbe9817SJiri Olsa #define __FUNC_VALUE_SET(_name, _val_type)				\
126edbe9817SJiri Olsa static __maybe_unused int value_set_##_name(struct ctf_writer *cw,	\
127edbe9817SJiri Olsa 			     struct bt_ctf_event *event,		\
128edbe9817SJiri Olsa 			     const char *name,				\
129edbe9817SJiri Olsa 			     _val_type val)				\
130edbe9817SJiri Olsa {									\
131edbe9817SJiri Olsa 	struct bt_ctf_field_type *type = cw->data._name;		\
132edbe9817SJiri Olsa 	return value_set(type, event, name, (u64) val);			\
133edbe9817SJiri Olsa }
134edbe9817SJiri Olsa 
135edbe9817SJiri Olsa #define FUNC_VALUE_SET(_name) __FUNC_VALUE_SET(_name, _name)
136edbe9817SJiri Olsa 
137edbe9817SJiri Olsa FUNC_VALUE_SET(s32)
138edbe9817SJiri Olsa FUNC_VALUE_SET(u32)
139edbe9817SJiri Olsa FUNC_VALUE_SET(s64)
140edbe9817SJiri Olsa FUNC_VALUE_SET(u64)
141edbe9817SJiri Olsa __FUNC_VALUE_SET(u64_hex, u64)
142edbe9817SJiri Olsa 
14369364727SSebastian Andrzej Siewior static struct bt_ctf_field_type*
14469364727SSebastian Andrzej Siewior get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field)
14569364727SSebastian Andrzej Siewior {
14669364727SSebastian Andrzej Siewior 	unsigned long flags = field->flags;
14769364727SSebastian Andrzej Siewior 
14869364727SSebastian Andrzej Siewior 	if (flags & FIELD_IS_STRING)
14969364727SSebastian Andrzej Siewior 		return cw->data.string;
15069364727SSebastian Andrzej Siewior 
15169364727SSebastian Andrzej Siewior 	if (!(flags & FIELD_IS_SIGNED)) {
15269364727SSebastian Andrzej Siewior 		/* unsigned long are mostly pointers */
15369364727SSebastian Andrzej Siewior 		if (flags & FIELD_IS_LONG || flags & FIELD_IS_POINTER)
15469364727SSebastian Andrzej Siewior 			return cw->data.u64_hex;
15569364727SSebastian Andrzej Siewior 	}
15669364727SSebastian Andrzej Siewior 
15769364727SSebastian Andrzej Siewior 	if (flags & FIELD_IS_SIGNED) {
15869364727SSebastian Andrzej Siewior 		if (field->size == 8)
15969364727SSebastian Andrzej Siewior 			return cw->data.s64;
16069364727SSebastian Andrzej Siewior 		else
16169364727SSebastian Andrzej Siewior 			return cw->data.s32;
16269364727SSebastian Andrzej Siewior 	}
16369364727SSebastian Andrzej Siewior 
16469364727SSebastian Andrzej Siewior 	if (field->size == 8)
16569364727SSebastian Andrzej Siewior 		return cw->data.u64;
16669364727SSebastian Andrzej Siewior 	else
16769364727SSebastian Andrzej Siewior 		return cw->data.u32;
16869364727SSebastian Andrzej Siewior }
16969364727SSebastian Andrzej Siewior 
170d4ae4213SWang Nan static unsigned long long adjust_signedness(unsigned long long value_int, int size)
171d4ae4213SWang Nan {
172d4ae4213SWang Nan 	unsigned long long value_mask;
173d4ae4213SWang Nan 
174d4ae4213SWang Nan 	/*
175d4ae4213SWang Nan 	 * value_mask = (1 << (size * 8 - 1)) - 1.
176d4ae4213SWang Nan 	 * Directly set value_mask for code readers.
177d4ae4213SWang Nan 	 */
178d4ae4213SWang Nan 	switch (size) {
179d4ae4213SWang Nan 	case 1:
180d4ae4213SWang Nan 		value_mask = 0x7fULL;
181d4ae4213SWang Nan 		break;
182d4ae4213SWang Nan 	case 2:
183d4ae4213SWang Nan 		value_mask = 0x7fffULL;
184d4ae4213SWang Nan 		break;
185d4ae4213SWang Nan 	case 4:
186d4ae4213SWang Nan 		value_mask = 0x7fffffffULL;
187d4ae4213SWang Nan 		break;
188d4ae4213SWang Nan 	case 8:
189d4ae4213SWang Nan 		/*
190d4ae4213SWang Nan 		 * For 64 bit value, return it self. There is no need
191d4ae4213SWang Nan 		 * to fill high bit.
192d4ae4213SWang Nan 		 */
193d4ae4213SWang Nan 		/* Fall through */
194d4ae4213SWang Nan 	default:
195d4ae4213SWang Nan 		/* BUG! */
196d4ae4213SWang Nan 		return value_int;
197d4ae4213SWang Nan 	}
198d4ae4213SWang Nan 
199d4ae4213SWang Nan 	/* If it is a positive value, don't adjust. */
200d4ae4213SWang Nan 	if ((value_int & (~0ULL - value_mask)) == 0)
201d4ae4213SWang Nan 		return value_int;
202d4ae4213SWang Nan 
203d4ae4213SWang Nan 	/* Fill upper part of value_int with 1 to make it a negative long long. */
204d4ae4213SWang Nan 	return (value_int & value_mask) | ~value_mask;
205d4ae4213SWang Nan }
206d4ae4213SWang Nan 
20769364727SSebastian Andrzej Siewior static int add_tracepoint_field_value(struct ctf_writer *cw,
20869364727SSebastian Andrzej Siewior 				      struct bt_ctf_event_class *event_class,
20969364727SSebastian Andrzej Siewior 				      struct bt_ctf_event *event,
21069364727SSebastian Andrzej Siewior 				      struct perf_sample *sample,
21169364727SSebastian Andrzej Siewior 				      struct format_field *fmtf)
21269364727SSebastian Andrzej Siewior {
21369364727SSebastian Andrzej Siewior 	struct bt_ctf_field_type *type;
21469364727SSebastian Andrzej Siewior 	struct bt_ctf_field *array_field;
21569364727SSebastian Andrzej Siewior 	struct bt_ctf_field *field;
21669364727SSebastian Andrzej Siewior 	const char *name = fmtf->name;
21769364727SSebastian Andrzej Siewior 	void *data = sample->raw_data;
21869364727SSebastian Andrzej Siewior 	unsigned long flags = fmtf->flags;
21969364727SSebastian Andrzej Siewior 	unsigned int n_items;
22069364727SSebastian Andrzej Siewior 	unsigned int i;
22169364727SSebastian Andrzej Siewior 	unsigned int offset;
22269364727SSebastian Andrzej Siewior 	unsigned int len;
22369364727SSebastian Andrzej Siewior 	int ret;
22469364727SSebastian Andrzej Siewior 
225e0a7cce5SWang Nan 	name = fmtf->alias;
22669364727SSebastian Andrzej Siewior 	offset = fmtf->offset;
22769364727SSebastian Andrzej Siewior 	len = fmtf->size;
22869364727SSebastian Andrzej Siewior 	if (flags & FIELD_IS_STRING)
22969364727SSebastian Andrzej Siewior 		flags &= ~FIELD_IS_ARRAY;
23069364727SSebastian Andrzej Siewior 
23169364727SSebastian Andrzej Siewior 	if (flags & FIELD_IS_DYNAMIC) {
23269364727SSebastian Andrzej Siewior 		unsigned long long tmp_val;
23369364727SSebastian Andrzej Siewior 
23469364727SSebastian Andrzej Siewior 		tmp_val = pevent_read_number(fmtf->event->pevent,
23569364727SSebastian Andrzej Siewior 				data + offset, len);
23669364727SSebastian Andrzej Siewior 		offset = tmp_val;
23769364727SSebastian Andrzej Siewior 		len = offset >> 16;
23869364727SSebastian Andrzej Siewior 		offset &= 0xffff;
23969364727SSebastian Andrzej Siewior 	}
24069364727SSebastian Andrzej Siewior 
24169364727SSebastian Andrzej Siewior 	if (flags & FIELD_IS_ARRAY) {
24269364727SSebastian Andrzej Siewior 
24369364727SSebastian Andrzej Siewior 		type = bt_ctf_event_class_get_field_by_name(
24469364727SSebastian Andrzej Siewior 				event_class, name);
24569364727SSebastian Andrzej Siewior 		array_field = bt_ctf_field_create(type);
24669364727SSebastian Andrzej Siewior 		bt_ctf_field_type_put(type);
24769364727SSebastian Andrzej Siewior 		if (!array_field) {
24869364727SSebastian Andrzej Siewior 			pr_err("Failed to create array type %s\n", name);
24969364727SSebastian Andrzej Siewior 			return -1;
25069364727SSebastian Andrzej Siewior 		}
25169364727SSebastian Andrzej Siewior 
25269364727SSebastian Andrzej Siewior 		len = fmtf->size / fmtf->arraylen;
25369364727SSebastian Andrzej Siewior 		n_items = fmtf->arraylen;
25469364727SSebastian Andrzej Siewior 	} else {
25569364727SSebastian Andrzej Siewior 		n_items = 1;
25669364727SSebastian Andrzej Siewior 		array_field = NULL;
25769364727SSebastian Andrzej Siewior 	}
25869364727SSebastian Andrzej Siewior 
25969364727SSebastian Andrzej Siewior 	type = get_tracepoint_field_type(cw, fmtf);
26069364727SSebastian Andrzej Siewior 
26169364727SSebastian Andrzej Siewior 	for (i = 0; i < n_items; i++) {
26269364727SSebastian Andrzej Siewior 		if (flags & FIELD_IS_ARRAY)
26369364727SSebastian Andrzej Siewior 			field = bt_ctf_field_array_get_field(array_field, i);
26469364727SSebastian Andrzej Siewior 		else
26569364727SSebastian Andrzej Siewior 			field = bt_ctf_field_create(type);
26669364727SSebastian Andrzej Siewior 
26769364727SSebastian Andrzej Siewior 		if (!field) {
26869364727SSebastian Andrzej Siewior 			pr_err("failed to create a field %s\n", name);
26969364727SSebastian Andrzej Siewior 			return -1;
27069364727SSebastian Andrzej Siewior 		}
27169364727SSebastian Andrzej Siewior 
27269364727SSebastian Andrzej Siewior 		if (flags & FIELD_IS_STRING)
27369364727SSebastian Andrzej Siewior 			ret = bt_ctf_field_string_set_value(field,
27469364727SSebastian Andrzej Siewior 					data + offset + i * len);
275d4ae4213SWang Nan 		else {
276d4ae4213SWang Nan 			unsigned long long value_int;
277d4ae4213SWang Nan 
278d4ae4213SWang Nan 			value_int = pevent_read_number(
279d4ae4213SWang Nan 					fmtf->event->pevent,
280d4ae4213SWang Nan 					data + offset + i * len, len);
281d4ae4213SWang Nan 
282d4ae4213SWang Nan 			if (!(flags & FIELD_IS_SIGNED))
28369364727SSebastian Andrzej Siewior 				ret = bt_ctf_field_unsigned_integer_set_value(
28469364727SSebastian Andrzej Siewior 						field, value_int);
28569364727SSebastian Andrzej Siewior 			else
28669364727SSebastian Andrzej Siewior 				ret = bt_ctf_field_signed_integer_set_value(
287d4ae4213SWang Nan 						field, adjust_signedness(value_int, len));
288d4ae4213SWang Nan 		}
289d4ae4213SWang Nan 
29069364727SSebastian Andrzej Siewior 		if (ret) {
29169364727SSebastian Andrzej Siewior 			pr_err("failed to set file value %s\n", name);
29269364727SSebastian Andrzej Siewior 			goto err_put_field;
29369364727SSebastian Andrzej Siewior 		}
29469364727SSebastian Andrzej Siewior 		if (!(flags & FIELD_IS_ARRAY)) {
29569364727SSebastian Andrzej Siewior 			ret = bt_ctf_event_set_payload(event, name, field);
29669364727SSebastian Andrzej Siewior 			if (ret) {
29769364727SSebastian Andrzej Siewior 				pr_err("failed to set payload %s\n", name);
29869364727SSebastian Andrzej Siewior 				goto err_put_field;
29969364727SSebastian Andrzej Siewior 			}
30069364727SSebastian Andrzej Siewior 		}
30169364727SSebastian Andrzej Siewior 		bt_ctf_field_put(field);
30269364727SSebastian Andrzej Siewior 	}
30369364727SSebastian Andrzej Siewior 	if (flags & FIELD_IS_ARRAY) {
30469364727SSebastian Andrzej Siewior 		ret = bt_ctf_event_set_payload(event, name, array_field);
30569364727SSebastian Andrzej Siewior 		if (ret) {
30669364727SSebastian Andrzej Siewior 			pr_err("Failed add payload array %s\n", name);
30769364727SSebastian Andrzej Siewior 			return -1;
30869364727SSebastian Andrzej Siewior 		}
30969364727SSebastian Andrzej Siewior 		bt_ctf_field_put(array_field);
31069364727SSebastian Andrzej Siewior 	}
31169364727SSebastian Andrzej Siewior 	return 0;
31269364727SSebastian Andrzej Siewior 
31369364727SSebastian Andrzej Siewior err_put_field:
31469364727SSebastian Andrzej Siewior 	bt_ctf_field_put(field);
31569364727SSebastian Andrzej Siewior 	return -1;
31669364727SSebastian Andrzej Siewior }
31769364727SSebastian Andrzej Siewior 
31869364727SSebastian Andrzej Siewior static int add_tracepoint_fields_values(struct ctf_writer *cw,
31969364727SSebastian Andrzej Siewior 					struct bt_ctf_event_class *event_class,
32069364727SSebastian Andrzej Siewior 					struct bt_ctf_event *event,
32169364727SSebastian Andrzej Siewior 					struct format_field *fields,
32269364727SSebastian Andrzej Siewior 					struct perf_sample *sample)
32369364727SSebastian Andrzej Siewior {
32469364727SSebastian Andrzej Siewior 	struct format_field *field;
32569364727SSebastian Andrzej Siewior 	int ret;
32669364727SSebastian Andrzej Siewior 
32769364727SSebastian Andrzej Siewior 	for (field = fields; field; field = field->next) {
32869364727SSebastian Andrzej Siewior 		ret = add_tracepoint_field_value(cw, event_class, event, sample,
32969364727SSebastian Andrzej Siewior 				field);
33069364727SSebastian Andrzej Siewior 		if (ret)
33169364727SSebastian Andrzej Siewior 			return -1;
33269364727SSebastian Andrzej Siewior 	}
33369364727SSebastian Andrzej Siewior 	return 0;
33469364727SSebastian Andrzej Siewior }
33569364727SSebastian Andrzej Siewior 
33669364727SSebastian Andrzej Siewior static int add_tracepoint_values(struct ctf_writer *cw,
33769364727SSebastian Andrzej Siewior 				 struct bt_ctf_event_class *event_class,
33869364727SSebastian Andrzej Siewior 				 struct bt_ctf_event *event,
33969364727SSebastian Andrzej Siewior 				 struct perf_evsel *evsel,
34069364727SSebastian Andrzej Siewior 				 struct perf_sample *sample)
34169364727SSebastian Andrzej Siewior {
34269364727SSebastian Andrzej Siewior 	struct format_field *common_fields = evsel->tp_format->format.common_fields;
34369364727SSebastian Andrzej Siewior 	struct format_field *fields        = evsel->tp_format->format.fields;
34469364727SSebastian Andrzej Siewior 	int ret;
34569364727SSebastian Andrzej Siewior 
34669364727SSebastian Andrzej Siewior 	ret = add_tracepoint_fields_values(cw, event_class, event,
34769364727SSebastian Andrzej Siewior 					   common_fields, sample);
34869364727SSebastian Andrzej Siewior 	if (!ret)
34969364727SSebastian Andrzej Siewior 		ret = add_tracepoint_fields_values(cw, event_class, event,
35069364727SSebastian Andrzej Siewior 						   fields, sample);
35169364727SSebastian Andrzej Siewior 
35269364727SSebastian Andrzej Siewior 	return ret;
35369364727SSebastian Andrzej Siewior }
35469364727SSebastian Andrzej Siewior 
355edbe9817SJiri Olsa static int add_generic_values(struct ctf_writer *cw,
356edbe9817SJiri Olsa 			      struct bt_ctf_event *event,
357edbe9817SJiri Olsa 			      struct perf_evsel *evsel,
358edbe9817SJiri Olsa 			      struct perf_sample *sample)
359edbe9817SJiri Olsa {
360edbe9817SJiri Olsa 	u64 type = evsel->attr.sample_type;
361edbe9817SJiri Olsa 	int ret;
362edbe9817SJiri Olsa 
363edbe9817SJiri Olsa 	/*
364edbe9817SJiri Olsa 	 * missing:
365edbe9817SJiri Olsa 	 *   PERF_SAMPLE_TIME         - not needed as we have it in
366edbe9817SJiri Olsa 	 *                              ctf event header
367edbe9817SJiri Olsa 	 *   PERF_SAMPLE_READ         - TODO
368edbe9817SJiri Olsa 	 *   PERF_SAMPLE_CALLCHAIN    - TODO
369edbe9817SJiri Olsa 	 *   PERF_SAMPLE_RAW          - tracepoint fields are handled separately
370edbe9817SJiri Olsa 	 *   PERF_SAMPLE_BRANCH_STACK - TODO
371edbe9817SJiri Olsa 	 *   PERF_SAMPLE_REGS_USER    - TODO
372edbe9817SJiri Olsa 	 *   PERF_SAMPLE_STACK_USER   - TODO
373edbe9817SJiri Olsa 	 */
374edbe9817SJiri Olsa 
375edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_IP) {
37654cf776aSSebastian Andrzej Siewior 		ret = value_set_u64_hex(cw, event, "perf_ip", sample->ip);
377edbe9817SJiri Olsa 		if (ret)
378edbe9817SJiri Olsa 			return -1;
379edbe9817SJiri Olsa 	}
380edbe9817SJiri Olsa 
381edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_TID) {
38254cf776aSSebastian Andrzej Siewior 		ret = value_set_s32(cw, event, "perf_tid", sample->tid);
383edbe9817SJiri Olsa 		if (ret)
384edbe9817SJiri Olsa 			return -1;
385edbe9817SJiri Olsa 
38654cf776aSSebastian Andrzej Siewior 		ret = value_set_s32(cw, event, "perf_pid", sample->pid);
387edbe9817SJiri Olsa 		if (ret)
388edbe9817SJiri Olsa 			return -1;
389edbe9817SJiri Olsa 	}
390edbe9817SJiri Olsa 
391edbe9817SJiri Olsa 	if ((type & PERF_SAMPLE_ID) ||
392edbe9817SJiri Olsa 	    (type & PERF_SAMPLE_IDENTIFIER)) {
39354cf776aSSebastian Andrzej Siewior 		ret = value_set_u64(cw, event, "perf_id", sample->id);
394edbe9817SJiri Olsa 		if (ret)
395edbe9817SJiri Olsa 			return -1;
396edbe9817SJiri Olsa 	}
397edbe9817SJiri Olsa 
398edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_STREAM_ID) {
39954cf776aSSebastian Andrzej Siewior 		ret = value_set_u64(cw, event, "perf_stream_id", sample->stream_id);
400edbe9817SJiri Olsa 		if (ret)
401edbe9817SJiri Olsa 			return -1;
402edbe9817SJiri Olsa 	}
403edbe9817SJiri Olsa 
404edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_PERIOD) {
40554cf776aSSebastian Andrzej Siewior 		ret = value_set_u64(cw, event, "perf_period", sample->period);
406edbe9817SJiri Olsa 		if (ret)
407edbe9817SJiri Olsa 			return -1;
408edbe9817SJiri Olsa 	}
409edbe9817SJiri Olsa 
410edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_WEIGHT) {
41154cf776aSSebastian Andrzej Siewior 		ret = value_set_u64(cw, event, "perf_weight", sample->weight);
412edbe9817SJiri Olsa 		if (ret)
413edbe9817SJiri Olsa 			return -1;
414edbe9817SJiri Olsa 	}
415edbe9817SJiri Olsa 
416edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_DATA_SRC) {
41754cf776aSSebastian Andrzej Siewior 		ret = value_set_u64(cw, event, "perf_data_src",
41854cf776aSSebastian Andrzej Siewior 				sample->data_src);
419edbe9817SJiri Olsa 		if (ret)
420edbe9817SJiri Olsa 			return -1;
421edbe9817SJiri Olsa 	}
422edbe9817SJiri Olsa 
423edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_TRANSACTION) {
42454cf776aSSebastian Andrzej Siewior 		ret = value_set_u64(cw, event, "perf_transaction",
42554cf776aSSebastian Andrzej Siewior 				sample->transaction);
426edbe9817SJiri Olsa 		if (ret)
427edbe9817SJiri Olsa 			return -1;
428edbe9817SJiri Olsa 	}
429edbe9817SJiri Olsa 
430edbe9817SJiri Olsa 	return 0;
431edbe9817SJiri Olsa }
432edbe9817SJiri Olsa 
43390e129ffSSebastian Andrzej Siewior static int ctf_stream__flush(struct ctf_stream *cs)
43490e129ffSSebastian Andrzej Siewior {
43590e129ffSSebastian Andrzej Siewior 	int err = 0;
43690e129ffSSebastian Andrzej Siewior 
43790e129ffSSebastian Andrzej Siewior 	if (cs) {
43890e129ffSSebastian Andrzej Siewior 		err = bt_ctf_stream_flush(cs->stream);
43990e129ffSSebastian Andrzej Siewior 		if (err)
44090e129ffSSebastian Andrzej Siewior 			pr_err("CTF stream %d flush failed\n", cs->cpu);
44190e129ffSSebastian Andrzej Siewior 
44289e5fa88SJiri Olsa 		pr("Flush stream for cpu %d (%u samples)\n",
44389e5fa88SJiri Olsa 		   cs->cpu, cs->count);
44489e5fa88SJiri Olsa 
44589e5fa88SJiri Olsa 		cs->count = 0;
44690e129ffSSebastian Andrzej Siewior 	}
44790e129ffSSebastian Andrzej Siewior 
44890e129ffSSebastian Andrzej Siewior 	return err;
44990e129ffSSebastian Andrzej Siewior }
45090e129ffSSebastian Andrzej Siewior 
45190e129ffSSebastian Andrzej Siewior static struct ctf_stream *ctf_stream__create(struct ctf_writer *cw, int cpu)
45290e129ffSSebastian Andrzej Siewior {
45390e129ffSSebastian Andrzej Siewior 	struct ctf_stream *cs;
45490e129ffSSebastian Andrzej Siewior 	struct bt_ctf_field *pkt_ctx   = NULL;
45590e129ffSSebastian Andrzej Siewior 	struct bt_ctf_field *cpu_field = NULL;
45690e129ffSSebastian Andrzej Siewior 	struct bt_ctf_stream *stream   = NULL;
45790e129ffSSebastian Andrzej Siewior 	int ret;
45890e129ffSSebastian Andrzej Siewior 
45990e129ffSSebastian Andrzej Siewior 	cs = zalloc(sizeof(*cs));
46090e129ffSSebastian Andrzej Siewior 	if (!cs) {
46190e129ffSSebastian Andrzej Siewior 		pr_err("Failed to allocate ctf stream\n");
46290e129ffSSebastian Andrzej Siewior 		return NULL;
46390e129ffSSebastian Andrzej Siewior 	}
46490e129ffSSebastian Andrzej Siewior 
46590e129ffSSebastian Andrzej Siewior 	stream = bt_ctf_writer_create_stream(cw->writer, cw->stream_class);
46690e129ffSSebastian Andrzej Siewior 	if (!stream) {
46790e129ffSSebastian Andrzej Siewior 		pr_err("Failed to create CTF stream\n");
46890e129ffSSebastian Andrzej Siewior 		goto out;
46990e129ffSSebastian Andrzej Siewior 	}
47090e129ffSSebastian Andrzej Siewior 
47190e129ffSSebastian Andrzej Siewior 	pkt_ctx = bt_ctf_stream_get_packet_context(stream);
47290e129ffSSebastian Andrzej Siewior 	if (!pkt_ctx) {
47390e129ffSSebastian Andrzej Siewior 		pr_err("Failed to obtain packet context\n");
47490e129ffSSebastian Andrzej Siewior 		goto out;
47590e129ffSSebastian Andrzej Siewior 	}
47690e129ffSSebastian Andrzej Siewior 
47790e129ffSSebastian Andrzej Siewior 	cpu_field = bt_ctf_field_structure_get_field(pkt_ctx, "cpu_id");
47890e129ffSSebastian Andrzej Siewior 	bt_ctf_field_put(pkt_ctx);
47990e129ffSSebastian Andrzej Siewior 	if (!cpu_field) {
48090e129ffSSebastian Andrzej Siewior 		pr_err("Failed to obtain cpu field\n");
48190e129ffSSebastian Andrzej Siewior 		goto out;
48290e129ffSSebastian Andrzej Siewior 	}
48390e129ffSSebastian Andrzej Siewior 
48490e129ffSSebastian Andrzej Siewior 	ret = bt_ctf_field_unsigned_integer_set_value(cpu_field, (u32) cpu);
48590e129ffSSebastian Andrzej Siewior 	if (ret) {
48690e129ffSSebastian Andrzej Siewior 		pr_err("Failed to update CPU number\n");
48790e129ffSSebastian Andrzej Siewior 		goto out;
48890e129ffSSebastian Andrzej Siewior 	}
48990e129ffSSebastian Andrzej Siewior 
49090e129ffSSebastian Andrzej Siewior 	bt_ctf_field_put(cpu_field);
49190e129ffSSebastian Andrzej Siewior 
49290e129ffSSebastian Andrzej Siewior 	cs->cpu    = cpu;
49390e129ffSSebastian Andrzej Siewior 	cs->stream = stream;
49490e129ffSSebastian Andrzej Siewior 	return cs;
49590e129ffSSebastian Andrzej Siewior 
49690e129ffSSebastian Andrzej Siewior out:
49790e129ffSSebastian Andrzej Siewior 	if (cpu_field)
49890e129ffSSebastian Andrzej Siewior 		bt_ctf_field_put(cpu_field);
49990e129ffSSebastian Andrzej Siewior 	if (stream)
50090e129ffSSebastian Andrzej Siewior 		bt_ctf_stream_put(stream);
50190e129ffSSebastian Andrzej Siewior 
50290e129ffSSebastian Andrzej Siewior 	free(cs);
50390e129ffSSebastian Andrzej Siewior 	return NULL;
50490e129ffSSebastian Andrzej Siewior }
50590e129ffSSebastian Andrzej Siewior 
50690e129ffSSebastian Andrzej Siewior static void ctf_stream__delete(struct ctf_stream *cs)
50790e129ffSSebastian Andrzej Siewior {
50890e129ffSSebastian Andrzej Siewior 	if (cs) {
50990e129ffSSebastian Andrzej Siewior 		bt_ctf_stream_put(cs->stream);
51090e129ffSSebastian Andrzej Siewior 		free(cs);
51190e129ffSSebastian Andrzej Siewior 	}
51290e129ffSSebastian Andrzej Siewior }
51390e129ffSSebastian Andrzej Siewior 
51490e129ffSSebastian Andrzej Siewior static struct ctf_stream *ctf_stream(struct ctf_writer *cw, int cpu)
51590e129ffSSebastian Andrzej Siewior {
51690e129ffSSebastian Andrzej Siewior 	struct ctf_stream *cs = cw->stream[cpu];
51790e129ffSSebastian Andrzej Siewior 
51890e129ffSSebastian Andrzej Siewior 	if (!cs) {
51990e129ffSSebastian Andrzej Siewior 		cs = ctf_stream__create(cw, cpu);
52090e129ffSSebastian Andrzej Siewior 		cw->stream[cpu] = cs;
52190e129ffSSebastian Andrzej Siewior 	}
52290e129ffSSebastian Andrzej Siewior 
52390e129ffSSebastian Andrzej Siewior 	return cs;
52490e129ffSSebastian Andrzej Siewior }
52590e129ffSSebastian Andrzej Siewior 
52690e129ffSSebastian Andrzej Siewior static int get_sample_cpu(struct ctf_writer *cw, struct perf_sample *sample,
52790e129ffSSebastian Andrzej Siewior 			  struct perf_evsel *evsel)
52890e129ffSSebastian Andrzej Siewior {
52990e129ffSSebastian Andrzej Siewior 	int cpu = 0;
53090e129ffSSebastian Andrzej Siewior 
53190e129ffSSebastian Andrzej Siewior 	if (evsel->attr.sample_type & PERF_SAMPLE_CPU)
53290e129ffSSebastian Andrzej Siewior 		cpu = sample->cpu;
53390e129ffSSebastian Andrzej Siewior 
53490e129ffSSebastian Andrzej Siewior 	if (cpu > cw->stream_cnt) {
53590e129ffSSebastian Andrzej Siewior 		pr_err("Event was recorded for CPU %d, limit is at %d.\n",
53690e129ffSSebastian Andrzej Siewior 			cpu, cw->stream_cnt);
53790e129ffSSebastian Andrzej Siewior 		cpu = 0;
53890e129ffSSebastian Andrzej Siewior 	}
53990e129ffSSebastian Andrzej Siewior 
54090e129ffSSebastian Andrzej Siewior 	return cpu;
54190e129ffSSebastian Andrzej Siewior }
54290e129ffSSebastian Andrzej Siewior 
54389e5fa88SJiri Olsa #define STREAM_FLUSH_COUNT 100000
54489e5fa88SJiri Olsa 
54589e5fa88SJiri Olsa /*
54689e5fa88SJiri Olsa  * Currently we have no other way to determine the
54789e5fa88SJiri Olsa  * time for the stream flush other than keep track
54889e5fa88SJiri Olsa  * of the number of events and check it against
54989e5fa88SJiri Olsa  * threshold.
55089e5fa88SJiri Olsa  */
55189e5fa88SJiri Olsa static bool is_flush_needed(struct ctf_stream *cs)
55289e5fa88SJiri Olsa {
55389e5fa88SJiri Olsa 	return cs->count >= STREAM_FLUSH_COUNT;
55489e5fa88SJiri Olsa }
55589e5fa88SJiri Olsa 
556edbe9817SJiri Olsa static int process_sample_event(struct perf_tool *tool,
557edbe9817SJiri Olsa 				union perf_event *_event __maybe_unused,
558edbe9817SJiri Olsa 				struct perf_sample *sample,
559edbe9817SJiri Olsa 				struct perf_evsel *evsel,
560edbe9817SJiri Olsa 				struct machine *machine __maybe_unused)
561edbe9817SJiri Olsa {
562edbe9817SJiri Olsa 	struct convert *c = container_of(tool, struct convert, tool);
563edbe9817SJiri Olsa 	struct evsel_priv *priv = evsel->priv;
564edbe9817SJiri Olsa 	struct ctf_writer *cw = &c->writer;
56590e129ffSSebastian Andrzej Siewior 	struct ctf_stream *cs;
566edbe9817SJiri Olsa 	struct bt_ctf_event_class *event_class;
567edbe9817SJiri Olsa 	struct bt_ctf_event *event;
568edbe9817SJiri Olsa 	int ret;
569edbe9817SJiri Olsa 
570edbe9817SJiri Olsa 	if (WARN_ONCE(!priv, "Failed to setup all events.\n"))
571edbe9817SJiri Olsa 		return 0;
572edbe9817SJiri Olsa 
573edbe9817SJiri Olsa 	event_class = priv->event_class;
574edbe9817SJiri Olsa 
575edbe9817SJiri Olsa 	/* update stats */
576edbe9817SJiri Olsa 	c->events_count++;
577edbe9817SJiri Olsa 	c->events_size += _event->header.size;
578edbe9817SJiri Olsa 
579edbe9817SJiri Olsa 	pr_time2(sample->time, "sample %" PRIu64 "\n", c->events_count);
580edbe9817SJiri Olsa 
581edbe9817SJiri Olsa 	event = bt_ctf_event_create(event_class);
582edbe9817SJiri Olsa 	if (!event) {
583edbe9817SJiri Olsa 		pr_err("Failed to create an CTF event\n");
584edbe9817SJiri Olsa 		return -1;
585edbe9817SJiri Olsa 	}
586edbe9817SJiri Olsa 
587edbe9817SJiri Olsa 	bt_ctf_clock_set_time(cw->clock, sample->time);
588edbe9817SJiri Olsa 
589edbe9817SJiri Olsa 	ret = add_generic_values(cw, event, evsel, sample);
590edbe9817SJiri Olsa 	if (ret)
591edbe9817SJiri Olsa 		return -1;
592edbe9817SJiri Olsa 
59369364727SSebastian Andrzej Siewior 	if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
59469364727SSebastian Andrzej Siewior 		ret = add_tracepoint_values(cw, event_class, event,
59569364727SSebastian Andrzej Siewior 					    evsel, sample);
59669364727SSebastian Andrzej Siewior 		if (ret)
59769364727SSebastian Andrzej Siewior 			return -1;
59869364727SSebastian Andrzej Siewior 	}
59969364727SSebastian Andrzej Siewior 
60090e129ffSSebastian Andrzej Siewior 	cs = ctf_stream(cw, get_sample_cpu(cw, sample, evsel));
60189e5fa88SJiri Olsa 	if (cs) {
60289e5fa88SJiri Olsa 		if (is_flush_needed(cs))
60389e5fa88SJiri Olsa 			ctf_stream__flush(cs);
60489e5fa88SJiri Olsa 
60589e5fa88SJiri Olsa 		cs->count++;
60690e129ffSSebastian Andrzej Siewior 		bt_ctf_stream_append_event(cs->stream, event);
60789e5fa88SJiri Olsa 	}
60890e129ffSSebastian Andrzej Siewior 
609edbe9817SJiri Olsa 	bt_ctf_event_put(event);
61090e129ffSSebastian Andrzej Siewior 	return cs ? 0 : -1;
611edbe9817SJiri Olsa }
612edbe9817SJiri Olsa 
613e0a7cce5SWang Nan /* If dup < 0, add a prefix. Else, add _dupl_X suffix. */
614e0a7cce5SWang Nan static char *change_name(char *name, char *orig_name, int dup)
615e0a7cce5SWang Nan {
616e0a7cce5SWang Nan 	char *new_name = NULL;
617e0a7cce5SWang Nan 	size_t len;
618e0a7cce5SWang Nan 
619e0a7cce5SWang Nan 	if (!name)
620e0a7cce5SWang Nan 		name = orig_name;
621e0a7cce5SWang Nan 
622e0a7cce5SWang Nan 	if (dup >= 10)
623e0a7cce5SWang Nan 		goto out;
624e0a7cce5SWang Nan 	/*
625e0a7cce5SWang Nan 	 * Add '_' prefix to potential keywork.  According to
626e0a7cce5SWang Nan 	 * Mathieu Desnoyers (https://lkml.org/lkml/2015/1/23/652),
627e0a7cce5SWang Nan 	 * futher CTF spec updating may require us to use '$'.
628e0a7cce5SWang Nan 	 */
629e0a7cce5SWang Nan 	if (dup < 0)
630e0a7cce5SWang Nan 		len = strlen(name) + sizeof("_");
631e0a7cce5SWang Nan 	else
632e0a7cce5SWang Nan 		len = strlen(orig_name) + sizeof("_dupl_X");
633e0a7cce5SWang Nan 
634e0a7cce5SWang Nan 	new_name = malloc(len);
635e0a7cce5SWang Nan 	if (!new_name)
636e0a7cce5SWang Nan 		goto out;
637e0a7cce5SWang Nan 
638e0a7cce5SWang Nan 	if (dup < 0)
639e0a7cce5SWang Nan 		snprintf(new_name, len, "_%s", name);
640e0a7cce5SWang Nan 	else
641e0a7cce5SWang Nan 		snprintf(new_name, len, "%s_dupl_%d", orig_name, dup);
642e0a7cce5SWang Nan 
643e0a7cce5SWang Nan out:
644e0a7cce5SWang Nan 	if (name != orig_name)
645e0a7cce5SWang Nan 		free(name);
646e0a7cce5SWang Nan 	return new_name;
647e0a7cce5SWang Nan }
648e0a7cce5SWang Nan 
649e0a7cce5SWang Nan static int event_class_add_field(struct bt_ctf_event_class *event_class,
650e0a7cce5SWang Nan 		struct bt_ctf_field_type *type,
651e0a7cce5SWang Nan 		struct format_field *field)
652e0a7cce5SWang Nan {
653e0a7cce5SWang Nan 	struct bt_ctf_field_type *t = NULL;
654e0a7cce5SWang Nan 	char *name;
655e0a7cce5SWang Nan 	int dup = 1;
656e0a7cce5SWang Nan 	int ret;
657e0a7cce5SWang Nan 
658e0a7cce5SWang Nan 	/* alias was already assigned */
659e0a7cce5SWang Nan 	if (field->alias != field->name)
660e0a7cce5SWang Nan 		return bt_ctf_event_class_add_field(event_class, type,
661e0a7cce5SWang Nan 				(char *)field->alias);
662e0a7cce5SWang Nan 
663e0a7cce5SWang Nan 	name = field->name;
664e0a7cce5SWang Nan 
665e0a7cce5SWang Nan 	/* If 'name' is a keywork, add prefix. */
666e0a7cce5SWang Nan 	if (bt_ctf_validate_identifier(name))
667e0a7cce5SWang Nan 		name = change_name(name, field->name, -1);
668e0a7cce5SWang Nan 
669e0a7cce5SWang Nan 	if (!name) {
670e0a7cce5SWang Nan 		pr_err("Failed to fix invalid identifier.");
671e0a7cce5SWang Nan 		return -1;
672e0a7cce5SWang Nan 	}
673e0a7cce5SWang Nan 	while ((t = bt_ctf_event_class_get_field_by_name(event_class, name))) {
674e0a7cce5SWang Nan 		bt_ctf_field_type_put(t);
675e0a7cce5SWang Nan 		name = change_name(name, field->name, dup++);
676e0a7cce5SWang Nan 		if (!name) {
677e0a7cce5SWang Nan 			pr_err("Failed to create dup name for '%s'\n", field->name);
678e0a7cce5SWang Nan 			return -1;
679e0a7cce5SWang Nan 		}
680e0a7cce5SWang Nan 	}
681e0a7cce5SWang Nan 
682e0a7cce5SWang Nan 	ret = bt_ctf_event_class_add_field(event_class, type, name);
683e0a7cce5SWang Nan 	if (!ret)
684e0a7cce5SWang Nan 		field->alias = name;
685e0a7cce5SWang Nan 
686e0a7cce5SWang Nan 	return ret;
687e0a7cce5SWang Nan }
688e0a7cce5SWang Nan 
68969364727SSebastian Andrzej Siewior static int add_tracepoint_fields_types(struct ctf_writer *cw,
69069364727SSebastian Andrzej Siewior 				       struct format_field *fields,
69169364727SSebastian Andrzej Siewior 				       struct bt_ctf_event_class *event_class)
69269364727SSebastian Andrzej Siewior {
69369364727SSebastian Andrzej Siewior 	struct format_field *field;
69469364727SSebastian Andrzej Siewior 	int ret;
69569364727SSebastian Andrzej Siewior 
69669364727SSebastian Andrzej Siewior 	for (field = fields; field; field = field->next) {
69769364727SSebastian Andrzej Siewior 		struct bt_ctf_field_type *type;
69869364727SSebastian Andrzej Siewior 		unsigned long flags = field->flags;
69969364727SSebastian Andrzej Siewior 
70069364727SSebastian Andrzej Siewior 		pr2("  field '%s'\n", field->name);
70169364727SSebastian Andrzej Siewior 
70269364727SSebastian Andrzej Siewior 		type = get_tracepoint_field_type(cw, field);
70369364727SSebastian Andrzej Siewior 		if (!type)
70469364727SSebastian Andrzej Siewior 			return -1;
70569364727SSebastian Andrzej Siewior 
70669364727SSebastian Andrzej Siewior 		/*
70769364727SSebastian Andrzej Siewior 		 * A string is an array of chars. For this we use the string
70869364727SSebastian Andrzej Siewior 		 * type and don't care that it is an array. What we don't
70969364727SSebastian Andrzej Siewior 		 * support is an array of strings.
71069364727SSebastian Andrzej Siewior 		 */
71169364727SSebastian Andrzej Siewior 		if (flags & FIELD_IS_STRING)
71269364727SSebastian Andrzej Siewior 			flags &= ~FIELD_IS_ARRAY;
71369364727SSebastian Andrzej Siewior 
71469364727SSebastian Andrzej Siewior 		if (flags & FIELD_IS_ARRAY)
71569364727SSebastian Andrzej Siewior 			type = bt_ctf_field_type_array_create(type, field->arraylen);
71669364727SSebastian Andrzej Siewior 
717e0a7cce5SWang Nan 		ret = event_class_add_field(event_class, type, field);
71869364727SSebastian Andrzej Siewior 
71969364727SSebastian Andrzej Siewior 		if (flags & FIELD_IS_ARRAY)
72069364727SSebastian Andrzej Siewior 			bt_ctf_field_type_put(type);
72169364727SSebastian Andrzej Siewior 
72269364727SSebastian Andrzej Siewior 		if (ret) {
723e0a7cce5SWang Nan 			pr_err("Failed to add field '%s': %d\n",
724e0a7cce5SWang Nan 					field->name, ret);
72569364727SSebastian Andrzej Siewior 			return -1;
72669364727SSebastian Andrzej Siewior 		}
72769364727SSebastian Andrzej Siewior 	}
72869364727SSebastian Andrzej Siewior 
72969364727SSebastian Andrzej Siewior 	return 0;
73069364727SSebastian Andrzej Siewior }
73169364727SSebastian Andrzej Siewior 
73269364727SSebastian Andrzej Siewior static int add_tracepoint_types(struct ctf_writer *cw,
73369364727SSebastian Andrzej Siewior 				struct perf_evsel *evsel,
73469364727SSebastian Andrzej Siewior 				struct bt_ctf_event_class *class)
73569364727SSebastian Andrzej Siewior {
73669364727SSebastian Andrzej Siewior 	struct format_field *common_fields = evsel->tp_format->format.common_fields;
73769364727SSebastian Andrzej Siewior 	struct format_field *fields        = evsel->tp_format->format.fields;
73869364727SSebastian Andrzej Siewior 	int ret;
73969364727SSebastian Andrzej Siewior 
74069364727SSebastian Andrzej Siewior 	ret = add_tracepoint_fields_types(cw, common_fields, class);
74169364727SSebastian Andrzej Siewior 	if (!ret)
74269364727SSebastian Andrzej Siewior 		ret = add_tracepoint_fields_types(cw, fields, class);
74369364727SSebastian Andrzej Siewior 
74469364727SSebastian Andrzej Siewior 	return ret;
74569364727SSebastian Andrzej Siewior }
74669364727SSebastian Andrzej Siewior 
747edbe9817SJiri Olsa static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
748edbe9817SJiri Olsa 			     struct bt_ctf_event_class *event_class)
749edbe9817SJiri Olsa {
750edbe9817SJiri Olsa 	u64 type = evsel->attr.sample_type;
751edbe9817SJiri Olsa 
752edbe9817SJiri Olsa 	/*
753edbe9817SJiri Olsa 	 * missing:
754edbe9817SJiri Olsa 	 *   PERF_SAMPLE_TIME         - not needed as we have it in
755edbe9817SJiri Olsa 	 *                              ctf event header
756edbe9817SJiri Olsa 	 *   PERF_SAMPLE_READ         - TODO
757edbe9817SJiri Olsa 	 *   PERF_SAMPLE_CALLCHAIN    - TODO
758edbe9817SJiri Olsa 	 *   PERF_SAMPLE_RAW          - tracepoint fields are handled separately
759edbe9817SJiri Olsa 	 *   PERF_SAMPLE_BRANCH_STACK - TODO
760edbe9817SJiri Olsa 	 *   PERF_SAMPLE_REGS_USER    - TODO
761edbe9817SJiri Olsa 	 *   PERF_SAMPLE_STACK_USER   - TODO
762edbe9817SJiri Olsa 	 */
763edbe9817SJiri Olsa 
764edbe9817SJiri Olsa #define ADD_FIELD(cl, t, n)						\
765edbe9817SJiri Olsa 	do {								\
766edbe9817SJiri Olsa 		pr2("  field '%s'\n", n);				\
767edbe9817SJiri Olsa 		if (bt_ctf_event_class_add_field(cl, t, n)) {		\
768e0a7cce5SWang Nan 			pr_err("Failed to add field '%s';\n", n);	\
769edbe9817SJiri Olsa 			return -1;					\
770edbe9817SJiri Olsa 		}							\
771edbe9817SJiri Olsa 	} while (0)
772edbe9817SJiri Olsa 
773edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_IP)
77454cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64_hex, "perf_ip");
775edbe9817SJiri Olsa 
776edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_TID) {
77754cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.s32, "perf_tid");
77854cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.s32, "perf_pid");
779edbe9817SJiri Olsa 	}
780edbe9817SJiri Olsa 
781edbe9817SJiri Olsa 	if ((type & PERF_SAMPLE_ID) ||
782edbe9817SJiri Olsa 	    (type & PERF_SAMPLE_IDENTIFIER))
78354cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64, "perf_id");
784edbe9817SJiri Olsa 
785edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_STREAM_ID)
78654cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64, "perf_stream_id");
787edbe9817SJiri Olsa 
788edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_PERIOD)
78954cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64, "perf_period");
790edbe9817SJiri Olsa 
791edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_WEIGHT)
79254cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64, "perf_weight");
793edbe9817SJiri Olsa 
794edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_DATA_SRC)
79554cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64, "perf_data_src");
796edbe9817SJiri Olsa 
797edbe9817SJiri Olsa 	if (type & PERF_SAMPLE_TRANSACTION)
79854cf776aSSebastian Andrzej Siewior 		ADD_FIELD(event_class, cw->data.u64, "perf_transaction");
799edbe9817SJiri Olsa 
800edbe9817SJiri Olsa #undef ADD_FIELD
801edbe9817SJiri Olsa 	return 0;
802edbe9817SJiri Olsa }
803edbe9817SJiri Olsa 
804edbe9817SJiri Olsa static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
805edbe9817SJiri Olsa {
806edbe9817SJiri Olsa 	struct bt_ctf_event_class *event_class;
807edbe9817SJiri Olsa 	struct evsel_priv *priv;
808edbe9817SJiri Olsa 	const char *name = perf_evsel__name(evsel);
809edbe9817SJiri Olsa 	int ret;
810edbe9817SJiri Olsa 
811edbe9817SJiri Olsa 	pr("Adding event '%s' (type %d)\n", name, evsel->attr.type);
812edbe9817SJiri Olsa 
813edbe9817SJiri Olsa 	event_class = bt_ctf_event_class_create(name);
814edbe9817SJiri Olsa 	if (!event_class)
815edbe9817SJiri Olsa 		return -1;
816edbe9817SJiri Olsa 
817edbe9817SJiri Olsa 	ret = add_generic_types(cw, evsel, event_class);
818edbe9817SJiri Olsa 	if (ret)
819edbe9817SJiri Olsa 		goto err;
820edbe9817SJiri Olsa 
82169364727SSebastian Andrzej Siewior 	if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
82269364727SSebastian Andrzej Siewior 		ret = add_tracepoint_types(cw, evsel, event_class);
82369364727SSebastian Andrzej Siewior 		if (ret)
82469364727SSebastian Andrzej Siewior 			goto err;
82569364727SSebastian Andrzej Siewior 	}
82669364727SSebastian Andrzej Siewior 
827edbe9817SJiri Olsa 	ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);
828edbe9817SJiri Olsa 	if (ret) {
829edbe9817SJiri Olsa 		pr("Failed to add event class into stream.\n");
830edbe9817SJiri Olsa 		goto err;
831edbe9817SJiri Olsa 	}
832edbe9817SJiri Olsa 
833edbe9817SJiri Olsa 	priv = malloc(sizeof(*priv));
834edbe9817SJiri Olsa 	if (!priv)
835edbe9817SJiri Olsa 		goto err;
836edbe9817SJiri Olsa 
837edbe9817SJiri Olsa 	priv->event_class = event_class;
838edbe9817SJiri Olsa 	evsel->priv       = priv;
839edbe9817SJiri Olsa 	return 0;
840edbe9817SJiri Olsa 
841edbe9817SJiri Olsa err:
842edbe9817SJiri Olsa 	bt_ctf_event_class_put(event_class);
843edbe9817SJiri Olsa 	pr_err("Failed to add event '%s'.\n", name);
844edbe9817SJiri Olsa 	return -1;
845edbe9817SJiri Olsa }
846edbe9817SJiri Olsa 
847edbe9817SJiri Olsa static int setup_events(struct ctf_writer *cw, struct perf_session *session)
848edbe9817SJiri Olsa {
849edbe9817SJiri Olsa 	struct perf_evlist *evlist = session->evlist;
850edbe9817SJiri Olsa 	struct perf_evsel *evsel;
851edbe9817SJiri Olsa 	int ret;
852edbe9817SJiri Olsa 
853edbe9817SJiri Olsa 	evlist__for_each(evlist, evsel) {
854edbe9817SJiri Olsa 		ret = add_event(cw, evsel);
855edbe9817SJiri Olsa 		if (ret)
856edbe9817SJiri Olsa 			return ret;
857edbe9817SJiri Olsa 	}
858edbe9817SJiri Olsa 	return 0;
859edbe9817SJiri Olsa }
860edbe9817SJiri Olsa 
8615141d735SWang Nan static void cleanup_events(struct perf_session *session)
8625141d735SWang Nan {
8635141d735SWang Nan 	struct perf_evlist *evlist = session->evlist;
8645141d735SWang Nan 	struct perf_evsel *evsel;
8655141d735SWang Nan 
8665141d735SWang Nan 	evlist__for_each(evlist, evsel) {
8675141d735SWang Nan 		struct evsel_priv *priv;
8685141d735SWang Nan 
8695141d735SWang Nan 		priv = evsel->priv;
8705141d735SWang Nan 		bt_ctf_event_class_put(priv->event_class);
8715141d735SWang Nan 		zfree(&evsel->priv);
8725141d735SWang Nan 	}
8735141d735SWang Nan 
8745141d735SWang Nan 	perf_evlist__delete(evlist);
8755141d735SWang Nan 	session->evlist = NULL;
8765141d735SWang Nan }
8775141d735SWang Nan 
87890e129ffSSebastian Andrzej Siewior static int setup_streams(struct ctf_writer *cw, struct perf_session *session)
87990e129ffSSebastian Andrzej Siewior {
88090e129ffSSebastian Andrzej Siewior 	struct ctf_stream **stream;
88190e129ffSSebastian Andrzej Siewior 	struct perf_header *ph = &session->header;
88290e129ffSSebastian Andrzej Siewior 	int ncpus;
88390e129ffSSebastian Andrzej Siewior 
88490e129ffSSebastian Andrzej Siewior 	/*
88590e129ffSSebastian Andrzej Siewior 	 * Try to get the number of cpus used in the data file,
88690e129ffSSebastian Andrzej Siewior 	 * if not present fallback to the MAX_CPUS.
88790e129ffSSebastian Andrzej Siewior 	 */
88890e129ffSSebastian Andrzej Siewior 	ncpus = ph->env.nr_cpus_avail ?: MAX_CPUS;
88990e129ffSSebastian Andrzej Siewior 
89090e129ffSSebastian Andrzej Siewior 	stream = zalloc(sizeof(*stream) * ncpus);
89190e129ffSSebastian Andrzej Siewior 	if (!stream) {
89290e129ffSSebastian Andrzej Siewior 		pr_err("Failed to allocate streams.\n");
89390e129ffSSebastian Andrzej Siewior 		return -ENOMEM;
89490e129ffSSebastian Andrzej Siewior 	}
89590e129ffSSebastian Andrzej Siewior 
89690e129ffSSebastian Andrzej Siewior 	cw->stream     = stream;
89790e129ffSSebastian Andrzej Siewior 	cw->stream_cnt = ncpus;
89890e129ffSSebastian Andrzej Siewior 	return 0;
89990e129ffSSebastian Andrzej Siewior }
90090e129ffSSebastian Andrzej Siewior 
90190e129ffSSebastian Andrzej Siewior static void free_streams(struct ctf_writer *cw)
90290e129ffSSebastian Andrzej Siewior {
90390e129ffSSebastian Andrzej Siewior 	int cpu;
90490e129ffSSebastian Andrzej Siewior 
90590e129ffSSebastian Andrzej Siewior 	for (cpu = 0; cpu < cw->stream_cnt; cpu++)
90690e129ffSSebastian Andrzej Siewior 		ctf_stream__delete(cw->stream[cpu]);
90790e129ffSSebastian Andrzej Siewior 
90890e129ffSSebastian Andrzej Siewior 	free(cw->stream);
90990e129ffSSebastian Andrzej Siewior }
91090e129ffSSebastian Andrzej Siewior 
911edbe9817SJiri Olsa static int ctf_writer__setup_env(struct ctf_writer *cw,
912edbe9817SJiri Olsa 				 struct perf_session *session)
913edbe9817SJiri Olsa {
914edbe9817SJiri Olsa 	struct perf_header *header = &session->header;
915edbe9817SJiri Olsa 	struct bt_ctf_writer *writer = cw->writer;
916edbe9817SJiri Olsa 
917edbe9817SJiri Olsa #define ADD(__n, __v)							\
918edbe9817SJiri Olsa do {									\
919edbe9817SJiri Olsa 	if (bt_ctf_writer_add_environment_field(writer, __n, __v))	\
920edbe9817SJiri Olsa 		return -1;						\
921edbe9817SJiri Olsa } while (0)
922edbe9817SJiri Olsa 
923edbe9817SJiri Olsa 	ADD("host",    header->env.hostname);
924edbe9817SJiri Olsa 	ADD("sysname", "Linux");
925edbe9817SJiri Olsa 	ADD("release", header->env.os_release);
926edbe9817SJiri Olsa 	ADD("version", header->env.version);
927edbe9817SJiri Olsa 	ADD("machine", header->env.arch);
928edbe9817SJiri Olsa 	ADD("domain", "kernel");
929edbe9817SJiri Olsa 	ADD("tracer_name", "perf");
930edbe9817SJiri Olsa 
931edbe9817SJiri Olsa #undef ADD
932edbe9817SJiri Olsa 	return 0;
933edbe9817SJiri Olsa }
934edbe9817SJiri Olsa 
935edbe9817SJiri Olsa static int ctf_writer__setup_clock(struct ctf_writer *cw)
936edbe9817SJiri Olsa {
937edbe9817SJiri Olsa 	struct bt_ctf_clock *clock = cw->clock;
938edbe9817SJiri Olsa 
939edbe9817SJiri Olsa 	bt_ctf_clock_set_description(clock, "perf clock");
940edbe9817SJiri Olsa 
941edbe9817SJiri Olsa #define SET(__n, __v)				\
942edbe9817SJiri Olsa do {						\
943edbe9817SJiri Olsa 	if (bt_ctf_clock_set_##__n(clock, __v))	\
944edbe9817SJiri Olsa 		return -1;			\
945edbe9817SJiri Olsa } while (0)
946edbe9817SJiri Olsa 
947edbe9817SJiri Olsa 	SET(frequency,   1000000000);
948edbe9817SJiri Olsa 	SET(offset_s,    0);
949edbe9817SJiri Olsa 	SET(offset,      0);
950edbe9817SJiri Olsa 	SET(precision,   10);
951edbe9817SJiri Olsa 	SET(is_absolute, 0);
952edbe9817SJiri Olsa 
953edbe9817SJiri Olsa #undef SET
954edbe9817SJiri Olsa 	return 0;
955edbe9817SJiri Olsa }
956edbe9817SJiri Olsa 
957edbe9817SJiri Olsa static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex)
958edbe9817SJiri Olsa {
959edbe9817SJiri Olsa 	struct bt_ctf_field_type *type;
960edbe9817SJiri Olsa 
961edbe9817SJiri Olsa 	type = bt_ctf_field_type_integer_create(size);
962edbe9817SJiri Olsa 	if (!type)
963edbe9817SJiri Olsa 		return NULL;
964edbe9817SJiri Olsa 
965edbe9817SJiri Olsa 	if (sign &&
966edbe9817SJiri Olsa 	    bt_ctf_field_type_integer_set_signed(type, 1))
967edbe9817SJiri Olsa 		goto err;
968edbe9817SJiri Olsa 
969edbe9817SJiri Olsa 	if (hex &&
970edbe9817SJiri Olsa 	    bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL))
971edbe9817SJiri Olsa 		goto err;
972edbe9817SJiri Olsa 
973edbe9817SJiri Olsa 	pr2("Created type: INTEGER %d-bit %ssigned %s\n",
974edbe9817SJiri Olsa 	    size, sign ? "un" : "", hex ? "hex" : "");
975edbe9817SJiri Olsa 	return type;
976edbe9817SJiri Olsa 
977edbe9817SJiri Olsa err:
978edbe9817SJiri Olsa 	bt_ctf_field_type_put(type);
979edbe9817SJiri Olsa 	return NULL;
980edbe9817SJiri Olsa }
981edbe9817SJiri Olsa 
982edbe9817SJiri Olsa static void ctf_writer__cleanup_data(struct ctf_writer *cw)
983edbe9817SJiri Olsa {
984edbe9817SJiri Olsa 	unsigned int i;
985edbe9817SJiri Olsa 
986edbe9817SJiri Olsa 	for (i = 0; i < ARRAY_SIZE(cw->data.array); i++)
987edbe9817SJiri Olsa 		bt_ctf_field_type_put(cw->data.array[i]);
988edbe9817SJiri Olsa }
989edbe9817SJiri Olsa 
990edbe9817SJiri Olsa static int ctf_writer__init_data(struct ctf_writer *cw)
991edbe9817SJiri Olsa {
992edbe9817SJiri Olsa #define CREATE_INT_TYPE(type, size, sign, hex)		\
993edbe9817SJiri Olsa do {							\
994edbe9817SJiri Olsa 	(type) = create_int_type(size, sign, hex);	\
995edbe9817SJiri Olsa 	if (!(type))					\
996edbe9817SJiri Olsa 		goto err;				\
997edbe9817SJiri Olsa } while (0)
998edbe9817SJiri Olsa 
999edbe9817SJiri Olsa 	CREATE_INT_TYPE(cw->data.s64, 64, true,  false);
1000edbe9817SJiri Olsa 	CREATE_INT_TYPE(cw->data.u64, 64, false, false);
1001edbe9817SJiri Olsa 	CREATE_INT_TYPE(cw->data.s32, 32, true,  false);
1002edbe9817SJiri Olsa 	CREATE_INT_TYPE(cw->data.u32, 32, false, false);
100326812d46SWang Nan 	CREATE_INT_TYPE(cw->data.u32_hex, 32, false, true);
1004edbe9817SJiri Olsa 	CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true);
1005edbe9817SJiri Olsa 
1006edbe9817SJiri Olsa 	cw->data.string  = bt_ctf_field_type_string_create();
1007edbe9817SJiri Olsa 	if (cw->data.string)
1008edbe9817SJiri Olsa 		return 0;
1009edbe9817SJiri Olsa 
1010edbe9817SJiri Olsa err:
1011edbe9817SJiri Olsa 	ctf_writer__cleanup_data(cw);
1012edbe9817SJiri Olsa 	pr_err("Failed to create data types.\n");
1013edbe9817SJiri Olsa 	return -1;
1014edbe9817SJiri Olsa }
1015edbe9817SJiri Olsa 
1016edbe9817SJiri Olsa static void ctf_writer__cleanup(struct ctf_writer *cw)
1017edbe9817SJiri Olsa {
1018edbe9817SJiri Olsa 	ctf_writer__cleanup_data(cw);
1019edbe9817SJiri Olsa 
1020edbe9817SJiri Olsa 	bt_ctf_clock_put(cw->clock);
102190e129ffSSebastian Andrzej Siewior 	free_streams(cw);
1022edbe9817SJiri Olsa 	bt_ctf_stream_class_put(cw->stream_class);
1023edbe9817SJiri Olsa 	bt_ctf_writer_put(cw->writer);
1024edbe9817SJiri Olsa 
1025edbe9817SJiri Olsa 	/* and NULL all the pointers */
1026edbe9817SJiri Olsa 	memset(cw, 0, sizeof(*cw));
1027edbe9817SJiri Olsa }
1028edbe9817SJiri Olsa 
1029edbe9817SJiri Olsa static int ctf_writer__init(struct ctf_writer *cw, const char *path)
1030edbe9817SJiri Olsa {
1031edbe9817SJiri Olsa 	struct bt_ctf_writer		*writer;
1032edbe9817SJiri Olsa 	struct bt_ctf_stream_class	*stream_class;
1033edbe9817SJiri Olsa 	struct bt_ctf_clock		*clock;
103490e129ffSSebastian Andrzej Siewior 	struct bt_ctf_field_type	*pkt_ctx_type;
103590e129ffSSebastian Andrzej Siewior 	int				ret;
1036edbe9817SJiri Olsa 
1037edbe9817SJiri Olsa 	/* CTF writer */
1038edbe9817SJiri Olsa 	writer = bt_ctf_writer_create(path);
1039edbe9817SJiri Olsa 	if (!writer)
1040edbe9817SJiri Olsa 		goto err;
1041edbe9817SJiri Olsa 
1042edbe9817SJiri Olsa 	cw->writer = writer;
1043edbe9817SJiri Olsa 
1044edbe9817SJiri Olsa 	/* CTF clock */
1045edbe9817SJiri Olsa 	clock = bt_ctf_clock_create("perf_clock");
1046edbe9817SJiri Olsa 	if (!clock) {
1047edbe9817SJiri Olsa 		pr("Failed to create CTF clock.\n");
1048edbe9817SJiri Olsa 		goto err_cleanup;
1049edbe9817SJiri Olsa 	}
1050edbe9817SJiri Olsa 
1051edbe9817SJiri Olsa 	cw->clock = clock;
1052edbe9817SJiri Olsa 
1053edbe9817SJiri Olsa 	if (ctf_writer__setup_clock(cw)) {
1054edbe9817SJiri Olsa 		pr("Failed to setup CTF clock.\n");
1055edbe9817SJiri Olsa 		goto err_cleanup;
1056edbe9817SJiri Olsa 	}
1057edbe9817SJiri Olsa 
1058edbe9817SJiri Olsa 	/* CTF stream class */
1059edbe9817SJiri Olsa 	stream_class = bt_ctf_stream_class_create("perf_stream");
1060edbe9817SJiri Olsa 	if (!stream_class) {
1061edbe9817SJiri Olsa 		pr("Failed to create CTF stream class.\n");
1062edbe9817SJiri Olsa 		goto err_cleanup;
1063edbe9817SJiri Olsa 	}
1064edbe9817SJiri Olsa 
1065edbe9817SJiri Olsa 	cw->stream_class = stream_class;
1066edbe9817SJiri Olsa 
1067edbe9817SJiri Olsa 	/* CTF clock stream setup */
1068edbe9817SJiri Olsa 	if (bt_ctf_stream_class_set_clock(stream_class, clock)) {
1069edbe9817SJiri Olsa 		pr("Failed to assign CTF clock to stream class.\n");
1070edbe9817SJiri Olsa 		goto err_cleanup;
1071edbe9817SJiri Olsa 	}
1072edbe9817SJiri Olsa 
1073edbe9817SJiri Olsa 	if (ctf_writer__init_data(cw))
1074edbe9817SJiri Olsa 		goto err_cleanup;
1075edbe9817SJiri Olsa 
107690e129ffSSebastian Andrzej Siewior 	/* Add cpu_id for packet context */
107790e129ffSSebastian Andrzej Siewior 	pkt_ctx_type = bt_ctf_stream_class_get_packet_context_type(stream_class);
107890e129ffSSebastian Andrzej Siewior 	if (!pkt_ctx_type)
1079edbe9817SJiri Olsa 		goto err_cleanup;
1080edbe9817SJiri Olsa 
108190e129ffSSebastian Andrzej Siewior 	ret = bt_ctf_field_type_structure_add_field(pkt_ctx_type, cw->data.u32, "cpu_id");
108290e129ffSSebastian Andrzej Siewior 	bt_ctf_field_type_put(pkt_ctx_type);
108390e129ffSSebastian Andrzej Siewior 	if (ret)
108490e129ffSSebastian Andrzej Siewior 		goto err_cleanup;
1085edbe9817SJiri Olsa 
1086edbe9817SJiri Olsa 	/* CTF clock writer setup */
1087edbe9817SJiri Olsa 	if (bt_ctf_writer_add_clock(writer, clock)) {
1088edbe9817SJiri Olsa 		pr("Failed to assign CTF clock to writer.\n");
1089edbe9817SJiri Olsa 		goto err_cleanup;
1090edbe9817SJiri Olsa 	}
1091edbe9817SJiri Olsa 
1092edbe9817SJiri Olsa 	return 0;
1093edbe9817SJiri Olsa 
1094edbe9817SJiri Olsa err_cleanup:
1095edbe9817SJiri Olsa 	ctf_writer__cleanup(cw);
1096edbe9817SJiri Olsa err:
1097edbe9817SJiri Olsa 	pr_err("Failed to setup CTF writer.\n");
1098edbe9817SJiri Olsa 	return -1;
1099edbe9817SJiri Olsa }
1100edbe9817SJiri Olsa 
110190e129ffSSebastian Andrzej Siewior static int ctf_writer__flush_streams(struct ctf_writer *cw)
110290e129ffSSebastian Andrzej Siewior {
110390e129ffSSebastian Andrzej Siewior 	int cpu, ret = 0;
110490e129ffSSebastian Andrzej Siewior 
110590e129ffSSebastian Andrzej Siewior 	for (cpu = 0; cpu < cw->stream_cnt && !ret; cpu++)
110690e129ffSSebastian Andrzej Siewior 		ret = ctf_stream__flush(cw->stream[cpu]);
110790e129ffSSebastian Andrzej Siewior 
110890e129ffSSebastian Andrzej Siewior 	return ret;
110990e129ffSSebastian Andrzej Siewior }
111090e129ffSSebastian Andrzej Siewior 
11118fa46753SJiri Olsa static int convert__config(const char *var, const char *value, void *cb)
11128fa46753SJiri Olsa {
11138fa46753SJiri Olsa 	struct convert *c = cb;
11148fa46753SJiri Olsa 
11158fa46753SJiri Olsa 	if (!strcmp(var, "convert.queue-size")) {
11168fa46753SJiri Olsa 		c->queue_size = perf_config_u64(var, value);
11178fa46753SJiri Olsa 		return 0;
11188fa46753SJiri Olsa 	}
11198fa46753SJiri Olsa 
1120*b8cbb349SWang Nan 	return 0;
11218fa46753SJiri Olsa }
11228fa46753SJiri Olsa 
1123bd05954bSYunlong Song int bt_convert__perf2ctf(const char *input, const char *path, bool force)
1124edbe9817SJiri Olsa {
1125edbe9817SJiri Olsa 	struct perf_session *session;
1126edbe9817SJiri Olsa 	struct perf_data_file file = {
1127edbe9817SJiri Olsa 		.path = input,
1128edbe9817SJiri Olsa 		.mode = PERF_DATA_MODE_READ,
1129bd05954bSYunlong Song 		.force = force,
1130edbe9817SJiri Olsa 	};
1131edbe9817SJiri Olsa 	struct convert c = {
1132edbe9817SJiri Olsa 		.tool = {
1133edbe9817SJiri Olsa 			.sample          = process_sample_event,
1134edbe9817SJiri Olsa 			.mmap            = perf_event__process_mmap,
1135edbe9817SJiri Olsa 			.mmap2           = perf_event__process_mmap2,
1136edbe9817SJiri Olsa 			.comm            = perf_event__process_comm,
1137edbe9817SJiri Olsa 			.exit            = perf_event__process_exit,
1138edbe9817SJiri Olsa 			.fork            = perf_event__process_fork,
1139edbe9817SJiri Olsa 			.lost            = perf_event__process_lost,
1140edbe9817SJiri Olsa 			.tracing_data    = perf_event__process_tracing_data,
1141edbe9817SJiri Olsa 			.build_id        = perf_event__process_build_id,
1142edbe9817SJiri Olsa 			.ordered_events  = true,
1143edbe9817SJiri Olsa 			.ordering_requires_timestamps = true,
1144edbe9817SJiri Olsa 		},
1145edbe9817SJiri Olsa 	};
1146edbe9817SJiri Olsa 	struct ctf_writer *cw = &c.writer;
1147edbe9817SJiri Olsa 	int err = -1;
1148edbe9817SJiri Olsa 
11498fa46753SJiri Olsa 	perf_config(convert__config, &c);
11508fa46753SJiri Olsa 
1151edbe9817SJiri Olsa 	/* CTF writer */
1152edbe9817SJiri Olsa 	if (ctf_writer__init(cw, path))
1153edbe9817SJiri Olsa 		return -1;
1154edbe9817SJiri Olsa 
1155edbe9817SJiri Olsa 	/* perf.data session */
1156b7b61cbeSArnaldo Carvalho de Melo 	session = perf_session__new(&file, 0, &c.tool);
1157edbe9817SJiri Olsa 	if (!session)
1158edbe9817SJiri Olsa 		goto free_writer;
1159edbe9817SJiri Olsa 
11608fa46753SJiri Olsa 	if (c.queue_size) {
11618fa46753SJiri Olsa 		ordered_events__set_alloc_size(&session->ordered_events,
11628fa46753SJiri Olsa 					       c.queue_size);
11638fa46753SJiri Olsa 	}
11648fa46753SJiri Olsa 
1165edbe9817SJiri Olsa 	/* CTF writer env/clock setup  */
1166edbe9817SJiri Olsa 	if (ctf_writer__setup_env(cw, session))
1167edbe9817SJiri Olsa 		goto free_session;
1168edbe9817SJiri Olsa 
1169edbe9817SJiri Olsa 	/* CTF events setup */
1170edbe9817SJiri Olsa 	if (setup_events(cw, session))
1171edbe9817SJiri Olsa 		goto free_session;
1172edbe9817SJiri Olsa 
117390e129ffSSebastian Andrzej Siewior 	if (setup_streams(cw, session))
117490e129ffSSebastian Andrzej Siewior 		goto free_session;
117590e129ffSSebastian Andrzej Siewior 
1176b7b61cbeSArnaldo Carvalho de Melo 	err = perf_session__process_events(session);
1177edbe9817SJiri Olsa 	if (!err)
117890e129ffSSebastian Andrzej Siewior 		err = ctf_writer__flush_streams(cw);
1179c2141055SHe Kuang 	else
1180c2141055SHe Kuang 		pr_err("Error during conversion.\n");
1181edbe9817SJiri Olsa 
1182edbe9817SJiri Olsa 	fprintf(stderr,
1183edbe9817SJiri Olsa 		"[ perf data convert: Converted '%s' into CTF data '%s' ]\n",
1184edbe9817SJiri Olsa 		file.path, path);
1185edbe9817SJiri Olsa 
1186edbe9817SJiri Olsa 	fprintf(stderr,
1187edbe9817SJiri Olsa 		"[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples) ]\n",
1188edbe9817SJiri Olsa 		(double) c.events_size / 1024.0 / 1024.0,
1189edbe9817SJiri Olsa 		c.events_count);
1190edbe9817SJiri Olsa 
11915141d735SWang Nan 	cleanup_events(session);
1192c2141055SHe Kuang 	perf_session__delete(session);
1193c2141055SHe Kuang 	ctf_writer__cleanup(cw);
1194c2141055SHe Kuang 
1195c2141055SHe Kuang 	return err;
1196c2141055SHe Kuang 
1197edbe9817SJiri Olsa free_session:
1198edbe9817SJiri Olsa 	perf_session__delete(session);
1199edbe9817SJiri Olsa free_writer:
1200edbe9817SJiri Olsa 	ctf_writer__cleanup(cw);
1201c2141055SHe Kuang 	pr_err("Error during conversion setup.\n");
1202edbe9817SJiri Olsa 	return err;
1203edbe9817SJiri Olsa }
1204