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