lib: remove librte_ prefix from directory names
[dpdk.git] / lib / eal / common / eal_common_trace_ctf.c
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         if (str)
56                 free(str);
57         return -ENOMEM;
58 }
59
60 static int
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }