xref: /dpdk/lib/eal/common/eal_common_trace_ctf.c (revision 2a7a42a5918af42dbf229d30dbba13697e68320f)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2020 Marvell International Ltd.
3  */
4 
5 #include <inttypes.h>
6 #include <stdlib.h>
7 #include <time.h>
8 
9 #include <rte_byteorder.h>
10 #include <rte_common.h>
11 #include <rte_time.h>
12 #include <rte_trace.h>
13 #include <rte_version.h>
14 
15 #include "eal_trace.h"
16 
17 __rte_format_printf(2, 0)
18 static int
metadata_printf(char ** str,const char * fmt,...)19 metadata_printf(char **str, const char *fmt, ...)
20 {
21 	va_list ap;
22 	int rc;
23 
24 	*str = NULL;
25 	va_start(ap, fmt);
26 	rc = vasprintf(str, fmt, ap);
27 	va_end(ap);
28 
29 	return rc;
30 }
31 
32 static int
meta_copy(char ** meta,int * offset,char * str,int rc)33 meta_copy(char **meta, int *offset, char *str, int rc)
34 {
35 	int count = *offset;
36 	char *ptr = *meta;
37 
38 	if (rc < 0)
39 		return rc;
40 
41 	ptr = realloc(ptr, count + rc + 1);
42 	if (ptr == NULL)
43 		goto free_str;
44 
45 	memcpy(RTE_PTR_ADD(ptr, count), str, rc);
46 	ptr[count + rc] = '\0';
47 	count += rc;
48 	free(str);
49 
50 	*meta = ptr;
51 	*offset = count;
52 
53 	return rc;
54 
55 free_str:
56 	free(str);
57 	return -ENOMEM;
58 }
59 
60 static int
meta_data_type_emit(char ** meta,int * offset)61 meta_data_type_emit(char **meta, int *offset)
62 {
63 	char *str = NULL;
64 	int rc;
65 
66 	rc = metadata_printf(&str,
67 		"/* CTF 1.8 */\n"
68 		"typealias integer {size = 8; base = x;}:= uint8_t;\n"
69 		"typealias integer {size = 16; base = x;} := uint16_t;\n"
70 		"typealias integer {size = 32; base = x;} := uint32_t;\n"
71 		"typealias integer {size = 64; base = x;} := uint64_t;\n"
72 		"typealias integer {size = 8; signed = true;}  := int8_t;\n"
73 		"typealias integer {size = 16; signed = true;} := int16_t;\n"
74 		"typealias integer {size = 32; signed = true;} := int32_t;\n"
75 		"typealias integer {size = 64; signed = true;} := int64_t;\n"
76 #ifdef RTE_ARCH_64
77 		"typealias integer {size = 64; base = x;} := uintptr_t;\n"
78 #else
79 		"typealias integer {size = 32; base = x;} := uintptr_t;\n"
80 #endif
81 #ifdef RTE_ARCH_64
82 		"typealias integer {size = 64; base = x;} := long;\n"
83 #else
84 		"typealias integer {size = 32; base = x;} := long;\n"
85 #endif
86 		"typealias integer {size = 8; signed = false; encoding = ASCII; } := string_bounded_t;\n\n"
87 #ifdef RTE_ARCH_64
88 		"typealias integer {size = 64; base = x;} := size_t;\n"
89 #else
90 		"typealias integer {size = 32; base = x;} := size_t;\n"
91 #endif
92 		"typealias floating_point {\n"
93 		"    exp_dig = 8;\n"
94 		"    mant_dig = 24;\n"
95 		"} := float;\n\n"
96 		"typealias floating_point {\n"
97 		"    exp_dig = 11;\n"
98 		"    mant_dig = 53;\n"
99 		"} := double;\n\n");
100 
101 	return meta_copy(meta, offset, str, rc);
102 }
103 
104 static int
is_be(void)105 is_be(void)
106 {
107 #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
108 	return 1;
109 #else
110 	return 0;
111 #endif
112 }
113 
114 static int
meta_header_emit(char ** meta,int * offset)115 meta_header_emit(char **meta, int *offset)
116 {
117 	struct trace *trace = trace_obj_get();
118 	char uustr[RTE_UUID_STRLEN];
119 	char *str = NULL;
120 	int rc;
121 
122 	rte_uuid_unparse(trace->uuid, uustr, RTE_UUID_STRLEN);
123 	rc = metadata_printf(&str,
124 		"trace {\n"
125 		"    major = 1;\n"
126 		"    minor = 8;\n"
127 		"    uuid = \"%s\";\n"
128 		"    byte_order = %s;\n"
129 		"    packet.header := struct {\n"
130 		"	    uint32_t magic;\n"
131 		"	    uint8_t  uuid[16];\n"
132 		"    };\n"
133 		"};\n\n", uustr, is_be() ? "be" : "le");
134 	return meta_copy(meta, offset, str, rc);
135 }
136 
137 static int
meta_env_emit(char ** meta,int * offset)138 meta_env_emit(char **meta, int *offset)
139 {
140 	char *str = NULL;
141 	int rc;
142 
143 	rc = metadata_printf(&str,
144 		"env {\n"
145 		"    dpdk_version = \"%s\";\n"
146 		"    tracer_name = \"dpdk\";\n"
147 		"};\n\n", rte_version());
148 	return meta_copy(meta, offset, str, rc);
149 }
150 
151 static int
meta_clock_pass1_emit(char ** meta,int * offset)152 meta_clock_pass1_emit(char **meta, int *offset)
153 {
154 	char *str = NULL;
155 	int rc;
156 
157 	rc = metadata_printf(&str,
158 		"clock {\n"
159 		"    name = \"dpdk\";\n"
160 		"    freq = ");
161 	return meta_copy(meta, offset, str, rc);
162 }
163 
164 static int
meta_clock_pass2_emit(char ** meta,int * offset)165 meta_clock_pass2_emit(char **meta, int *offset)
166 {
167 	char *str = NULL;
168 	int rc;
169 
170 	rc = metadata_printf(&str,
171 		"%20"PRIu64";\n"
172 		"    offset_s =", 0);
173 	return meta_copy(meta, offset, str, rc);
174 }
175 
176 static int
meta_clock_pass3_emit(char ** meta,int * offset)177 meta_clock_pass3_emit(char **meta, int *offset)
178 {
179 	char *str = NULL;
180 	int rc;
181 
182 	rc = metadata_printf(&str,
183 		"%20"PRIu64";\n"
184 		"    offset =", 0);
185 	return meta_copy(meta, offset, str, rc);
186 }
187 
188 static int
meta_clock_pass4_emit(char ** meta,int * offset)189 meta_clock_pass4_emit(char **meta, int *offset)
190 {
191 	char *str = NULL;
192 	int rc;
193 
194 	rc = metadata_printf(&str,
195 		"%20"PRIu64";\n};\n\n"
196 		"typealias integer {\n"
197 		"    size = 48; align = 1; signed = false;\n"
198 		"    map = clock.dpdk.value;\n"
199 		"} := uint48_clock_dpdk_t;\n\n", 0);
200 
201 	return meta_copy(meta, offset, str, rc);
202 }
203 
204 static int
meta_stream_emit(char ** meta,int * offset)205 meta_stream_emit(char **meta, int *offset)
206 {
207 	char *str = NULL;
208 	int rc;
209 
210 	rc = metadata_printf(&str,
211 		"stream {\n"
212 		"    packet.context := struct {\n"
213 		"         uint32_t cpu_id;\n"
214 		"         string_bounded_t name[32];\n"
215 		"    };\n"
216 		"    event.header := struct {\n"
217 		"          uint48_clock_dpdk_t timestamp;\n"
218 		"          uint16_t id;\n"
219 		"    } align(64);\n"
220 		"};\n\n");
221 	return meta_copy(meta, offset, str, rc);
222 }
223 
224 static int
meta_event_emit(char ** meta,int * offset,struct trace_point * tp)225 meta_event_emit(char **meta, int *offset, struct trace_point *tp)
226 {
227 	char *str = NULL;
228 	int rc;
229 
230 	rc = metadata_printf(&str,
231 		"event {\n"
232 		"    id = %d;\n"
233 		"    name = \"%s\";\n"
234 		"    fields := struct {\n"
235 		"%s"
236 		"    };\n"
237 		"};\n\n", trace_id_get(tp->handle), tp->name,
238 		tp->ctf_field != NULL ? tp->ctf_field : "");
239 	return meta_copy(meta, offset, str, rc);
240 }
241 
242 int
trace_metadata_create(void)243 trace_metadata_create(void)
244 {
245 	struct trace_point_head *tp_list = trace_list_head_get();
246 	struct trace *trace = trace_obj_get();
247 	struct trace_point *tp;
248 	int rc, offset = 0;
249 	char *meta = NULL;
250 
251 	rc = meta_data_type_emit(&meta, &offset);
252 	if (rc < 0)
253 		goto fail;
254 
255 	rc = meta_header_emit(&meta, &offset);
256 	if (rc < 0)
257 		goto fail;
258 
259 	rc = meta_env_emit(&meta, &offset);
260 	if (rc < 0)
261 		goto fail;
262 
263 	rc = meta_clock_pass1_emit(&meta, &offset);
264 	if (rc < 0)
265 		goto fail;
266 	trace->ctf_meta_offset_freq = offset;
267 
268 	rc = meta_clock_pass2_emit(&meta, &offset);
269 	if (rc < 0)
270 		goto fail;
271 	trace->ctf_meta_offset_freq_off_s = offset;
272 
273 	rc = meta_clock_pass3_emit(&meta, &offset);
274 	if (rc < 0)
275 		goto fail;
276 	trace->ctf_meta_offset_freq_off = offset;
277 
278 	rc = meta_clock_pass4_emit(&meta, &offset);
279 	if (rc < 0)
280 		goto fail;
281 
282 	rc = meta_stream_emit(&meta, &offset);
283 	if (rc < 0)
284 		goto fail;
285 
286 	STAILQ_FOREACH(tp, tp_list, next)
287 		if (meta_event_emit(&meta, &offset, tp) < 0)
288 			goto fail;
289 
290 	trace->ctf_meta = meta;
291 	return 0;
292 
293 fail:
294 	free(meta);
295 	return -EBADF;
296 }
297 
298 void
trace_metadata_destroy(void)299 trace_metadata_destroy(void)
300 {
301 	struct trace *trace = trace_obj_get();
302 
303 	if (trace->ctf_meta) {
304 		free(trace->ctf_meta);
305 		trace->ctf_meta = NULL;
306 	}
307 }
308 
309 static void
meta_fix_freq(struct trace * trace,char * meta)310 meta_fix_freq(struct trace *trace, char *meta)
311 {
312 	char *str;
313 	int rc;
314 
315 	str = RTE_PTR_ADD(meta, trace->ctf_meta_offset_freq);
316 	rc = sprintf(str, "%20"PRIu64"", rte_get_timer_hz());
317 	str[rc] = ';';
318 }
319 
320 static void
meta_fix_freq_offset(struct trace * trace,char * meta)321 meta_fix_freq_offset(struct trace *trace, char *meta)
322 {
323 	uint64_t uptime_tickes_floor, uptime_ticks, freq, uptime_sec;
324 	uint64_t offset, offset_s;
325 	char *str;
326 	int rc;
327 
328 	uptime_ticks = trace->uptime_ticks &
329 			((1ULL << __RTE_TRACE_EVENT_HEADER_ID_SHIFT) - 1);
330 	freq = rte_get_tsc_hz();
331 	uptime_tickes_floor = RTE_ALIGN_MUL_FLOOR(uptime_ticks, freq);
332 
333 	uptime_sec = uptime_tickes_floor / freq;
334 	offset_s = trace->epoch_sec - uptime_sec;
335 
336 	offset = uptime_ticks - uptime_tickes_floor;
337 	offset += trace->epoch_nsec * (freq / NSEC_PER_SEC);
338 
339 	str = RTE_PTR_ADD(meta, trace->ctf_meta_offset_freq_off_s);
340 	rc = sprintf(str, "%20"PRIu64"", offset_s);
341 	str[rc] = ';';
342 	str = RTE_PTR_ADD(meta, trace->ctf_meta_offset_freq_off);
343 	rc = sprintf(str, "%20"PRIu64"", offset);
344 	str[rc] = ';';
345 }
346 
347 static void
meta_fixup(struct trace * trace,char * meta)348 meta_fixup(struct trace *trace, char *meta)
349 {
350 	meta_fix_freq(trace, meta);
351 	meta_fix_freq_offset(trace, meta);
352 }
353 
354 int
rte_trace_metadata_dump(FILE * f)355 rte_trace_metadata_dump(FILE *f)
356 {
357 	struct trace *trace = trace_obj_get();
358 	char *ctf_meta = trace->ctf_meta;
359 	int rc;
360 
361 	if (ctf_meta == NULL)
362 		return -EINVAL;
363 
364 	if (!rte_atomic_load_explicit(&trace->ctf_fixup_done, rte_memory_order_seq_cst) &&
365 				rte_get_timer_hz()) {
366 		meta_fixup(trace, ctf_meta);
367 		rte_atomic_store_explicit(&trace->ctf_fixup_done, 1, rte_memory_order_seq_cst);
368 	}
369 
370 	rc = fprintf(f, "%s", ctf_meta);
371 	return rc < 0 ? rc : 0;
372 }
373 
trace_metadata_fixup_field(const char * field)374 char *trace_metadata_fixup_field(const char *field)
375 {
376 	const char *ctf_reserved_words[] = {
377 		"align",
378 		"event",
379 	};
380 	unsigned int i;
381 	char *out;
382 	char *p;
383 
384 	/* reserved keywords */
385 	for (i = 0; i < RTE_DIM(ctf_reserved_words); i++) {
386 		if (strcmp(field, ctf_reserved_words[i]) != 0)
387 			continue;
388 		if (asprintf(&out, "_%s", ctf_reserved_words[i]) == -1)
389 			out = NULL;
390 		return out;
391 	}
392 
393 	/* nothing to replace, return early */
394 	if (strstr(field, ".") == NULL && strstr(field, "->") == NULL)
395 		return NULL;
396 
397 	out = strdup(field);
398 	if (out == NULL)
399 		return NULL;
400 	p = out;
401 	while ((p = strstr(p, ".")) != NULL) {
402 		p[0] = '_';
403 		p++;
404 	}
405 	p = out;
406 	while ((p = strstr(p, "->")) != NULL) {
407 		p[0] = '_';
408 		p++;
409 		memmove(p, p + 1, strlen(p));
410 	}
411 	return out;
412 }
413