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