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 if (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 if (meta)
295 free(meta);
296 return -EBADF;
297 }
298
299 void
trace_metadata_destroy(void)300 trace_metadata_destroy(void)
301 {
302 struct trace *trace = trace_obj_get();
303
304 if (trace->ctf_meta) {
305 free(trace->ctf_meta);
306 trace->ctf_meta = NULL;
307 }
308 }
309
310 static void
meta_fix_freq(struct trace * trace,char * meta)311 meta_fix_freq(struct trace *trace, char *meta)
312 {
313 char *str;
314 int rc;
315
316 str = RTE_PTR_ADD(meta, trace->ctf_meta_offset_freq);
317 rc = sprintf(str, "%20"PRIu64"", rte_get_timer_hz());
318 str[rc] = ';';
319 }
320
321 static void
meta_fix_freq_offset(struct trace * trace,char * meta)322 meta_fix_freq_offset(struct trace *trace, char *meta)
323 {
324 uint64_t uptime_tickes_floor, uptime_ticks, freq, uptime_sec;
325 uint64_t offset, offset_s;
326 char *str;
327 int rc;
328
329 uptime_ticks = trace->uptime_ticks &
330 ((1ULL << __RTE_TRACE_EVENT_HEADER_ID_SHIFT) - 1);
331 freq = rte_get_tsc_hz();
332 uptime_tickes_floor = RTE_ALIGN_MUL_FLOOR(uptime_ticks, freq);
333
334 uptime_sec = uptime_tickes_floor / freq;
335 offset_s = trace->epoch_sec - uptime_sec;
336
337 offset = uptime_ticks - uptime_tickes_floor;
338 offset += trace->epoch_nsec * (freq / NSEC_PER_SEC);
339
340 str = RTE_PTR_ADD(meta, trace->ctf_meta_offset_freq_off_s);
341 rc = sprintf(str, "%20"PRIu64"", offset_s);
342 str[rc] = ';';
343 str = RTE_PTR_ADD(meta, trace->ctf_meta_offset_freq_off);
344 rc = sprintf(str, "%20"PRIu64"", offset);
345 str[rc] = ';';
346 }
347
348 static void
meta_fixup(struct trace * trace,char * meta)349 meta_fixup(struct trace *trace, char *meta)
350 {
351 meta_fix_freq(trace, meta);
352 meta_fix_freq_offset(trace, meta);
353 }
354
355 int
rte_trace_metadata_dump(FILE * f)356 rte_trace_metadata_dump(FILE *f)
357 {
358 struct trace *trace = trace_obj_get();
359 char *ctf_meta = trace->ctf_meta;
360 int rc;
361
362 if (!rte_trace_is_enabled())
363 return 0;
364
365 if (ctf_meta == NULL)
366 return -EINVAL;
367
368 if (!__atomic_load_n(&trace->ctf_fixup_done, __ATOMIC_SEQ_CST) &&
369 rte_get_timer_hz()) {
370 meta_fixup(trace, ctf_meta);
371 __atomic_store_n(&trace->ctf_fixup_done, 1, __ATOMIC_SEQ_CST);
372 }
373
374 rc = fprintf(f, "%s", ctf_meta);
375 return rc < 0 ? rc : 0;
376 }
377
trace_metadata_fixup_field(const char * field)378 char *trace_metadata_fixup_field(const char *field)
379 {
380 const char *ctf_reserved_words[] = {
381 "align",
382 "event",
383 };
384 unsigned int i;
385 char *out;
386 char *p;
387
388 /* reserved keywords */
389 for (i = 0; i < RTE_DIM(ctf_reserved_words); i++) {
390 if (strcmp(field, ctf_reserved_words[i]) != 0)
391 continue;
392 if (asprintf(&out, "_%s", ctf_reserved_words[i]) == -1)
393 out = NULL;
394 return out;
395 }
396
397 /* nothing to replace, return early */
398 if (strstr(field, ".") == NULL && strstr(field, "->") == NULL)
399 return NULL;
400
401 out = strdup(field);
402 if (out == NULL)
403 return NULL;
404 p = out;
405 while ((p = strstr(p, ".")) != NULL) {
406 p[0] = '_';
407 p++;
408 }
409 p = out;
410 while ((p = strstr(p, "->")) != NULL) {
411 p[0] = '_';
412 p++;
413 memmove(p, p + 1, strlen(p));
414 }
415 return out;
416 }
417