trace: remove size limit on CTF event description
[dpdk.git] / lib / librte_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);
41         if (ptr == NULL)
42                 goto free_str;
43
44         memcpy(RTE_PTR_ADD(ptr, count), str, rc);
45         count += rc;
46         free(str);
47
48         *meta = ptr;
49         *offset = count;
50
51         return rc;
52
53 free_str:
54         if (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\n"
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         if (meta)
294                 free(meta);
295         return -EBADF;
296 }
297
298 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
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
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
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
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 (!rte_trace_is_enabled())
362                 return 0;
363
364         if (ctf_meta == NULL)
365                 return -EINVAL;
366
367         if (!__atomic_load_n(&trace->ctf_fixup_done, __ATOMIC_SEQ_CST) &&
368                                 rte_get_timer_hz()) {
369                 meta_fixup(trace, ctf_meta);
370                 __atomic_store_n(&trace->ctf_fixup_done, 1, __ATOMIC_SEQ_CST);
371         }
372
373         rc = fprintf(f, "%s", ctf_meta);
374         return rc < 0 ? rc : 0;
375 }
376
377 char *trace_metadata_fixup_field(const char *field)
378 {
379         const char *ctf_reserved_words[] = {
380                 "align",
381                 "event",
382         };
383         unsigned int i;
384         char *out;
385         char *p;
386
387         /* reserved keywords */
388         for (i = 0; i < RTE_DIM(ctf_reserved_words); i++) {
389                 if (strcmp(field, ctf_reserved_words[i]) != 0)
390                         continue;
391                 if (asprintf(&out, "_%s", ctf_reserved_words[i]) == -1)
392                         out = NULL;
393                 return out;
394         }
395
396         /* nothing to replace, return early */
397         if (strstr(field, ".") == NULL && strstr(field, "->") == NULL)
398                 return NULL;
399
400         out = strdup(field);
401         if (out == NULL)
402                 return NULL;
403         p = out;
404         while ((p = strstr(p, ".")) != NULL) {
405                 p[0] = '_';
406                 p++;
407         }
408         p = out;
409         while ((p = strstr(p, "->")) != NULL) {
410                 p[0] = '_';
411                 p++;
412                 memmove(p, p + 1, strlen(p));
413         }
414         return out;
415 }