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
metadata_printf(char ** str,const char * fmt,...)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
meta_copy(char ** meta,int * offset,char * str,int rc)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
meta_data_type_emit(char ** meta,int * offset)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
is_be(void)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
meta_header_emit(char ** meta,int * offset)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
meta_env_emit(char ** meta,int * offset)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
meta_clock_pass1_emit(char ** meta,int * offset)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
meta_clock_pass2_emit(char ** meta,int * offset)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
meta_clock_pass3_emit(char ** meta,int * offset)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
meta_clock_pass4_emit(char ** meta,int * offset)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
meta_stream_emit(char ** meta,int * offset)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
meta_event_emit(char ** meta,int * offset,struct trace_point * tp)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
trace_metadata_create(void)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
trace_metadata_destroy(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
meta_fix_freq(struct trace * trace,char * meta)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
meta_fix_freq_offset(struct trace * trace,char * meta)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
meta_fixup(struct trace * trace,char * meta)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
rte_trace_metadata_dump(FILE * f)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
trace_metadata_fixup_field(const char * field)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