Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2020 Marvell International Ltd.
3 : : */
4 : :
5 : : #include <stdlib.h>
6 : : #include <fnmatch.h>
7 : : #include <pthread.h>
8 : : #include <sys/queue.h>
9 : : #include <regex.h>
10 : :
11 : : #include <rte_common.h>
12 : : #include <rte_errno.h>
13 : : #include <rte_lcore.h>
14 : : #include <rte_per_lcore.h>
15 : : #include <rte_string_fns.h>
16 : :
17 : : #include "eal_trace.h"
18 : :
19 : : RTE_DEFINE_PER_LCORE(volatile int, trace_point_sz);
20 : : RTE_DEFINE_PER_LCORE(void *, trace_mem);
21 : : static RTE_DEFINE_PER_LCORE(char *, ctf_field);
22 : :
23 : : static struct trace_point_head tp_list = STAILQ_HEAD_INITIALIZER(tp_list);
24 : : static struct trace trace = { .args = STAILQ_HEAD_INITIALIZER(trace.args), };
25 : :
26 : : struct trace *
27 : 2937 : trace_obj_get(void)
28 : : {
29 : 2937 : return &trace;
30 : : }
31 : :
32 : : struct trace_point_head *
33 : 103556 : trace_list_head_get(void)
34 : : {
35 : 103556 : return &tp_list;
36 : : }
37 : :
38 : : int
39 : 198 : eal_trace_init(void)
40 : : {
41 : : struct trace_arg *arg;
42 : :
43 : : /* Trace memory should start with 8B aligned for natural alignment */
44 : : RTE_BUILD_BUG_ON((offsetof(struct __rte_trace_header, mem) % 8) != 0);
45 : :
46 : : /* One of the trace point registration failed */
47 [ - + ]: 198 : if (trace.register_errno) {
48 : 0 : rte_errno = trace.register_errno;
49 : 0 : goto fail;
50 : : }
51 : :
52 : : rte_spinlock_init(&trace.lock);
53 : :
54 : : /* Is duplicate trace name registered */
55 [ - + ]: 198 : if (trace_has_duplicate_entry())
56 : 0 : goto fail;
57 : :
58 : : /* Generate UUID ver 4 with total size of events and number of
59 : : * events
60 : : */
61 : 198 : trace_uuid_generate();
62 : :
63 : : /* Apply buffer size configuration for trace output */
64 : 198 : trace_bufsz_args_apply();
65 : :
66 : : /* Generate CTF TDSL metadata */
67 [ - + ]: 198 : if (trace_metadata_create() < 0)
68 : 0 : goto fail;
69 : :
70 : : /* Save current epoch timestamp for future use */
71 [ - + ]: 198 : if (trace_epoch_time_save() < 0)
72 : 0 : goto free_meta;
73 : :
74 : : /* Apply global configurations */
75 [ + + ]: 199 : STAILQ_FOREACH(arg, &trace.args, next)
76 : 1 : trace_args_apply(arg->val);
77 : :
78 : 198 : rte_trace_mode_set(trace.mode);
79 : :
80 : 198 : return 0;
81 : :
82 : : free_meta:
83 : 0 : trace_metadata_destroy();
84 : 0 : fail:
85 : 0 : trace_err("failed to initialize trace [%s]", rte_strerror(rte_errno));
86 : 0 : return -rte_errno;
87 : : }
88 : :
89 : : void
90 : 251 : eal_trace_fini(void)
91 : : {
92 : 251 : trace_mem_free();
93 : 251 : trace_metadata_destroy();
94 : 251 : eal_trace_args_free();
95 : 251 : }
96 : :
97 : : bool
98 : 801 : rte_trace_is_enabled(void)
99 : : {
100 : 801 : return rte_atomic_load_explicit(&trace.status, rte_memory_order_acquire) != 0;
101 : : }
102 : :
103 : : static void
104 : 236600 : trace_mode_set(rte_trace_point_t *t, enum rte_trace_mode mode)
105 : : {
106 [ + + ]: 236600 : if (mode == RTE_TRACE_MODE_OVERWRITE)
107 : 235560 : rte_atomic_fetch_and_explicit(t, ~__RTE_TRACE_FIELD_ENABLE_DISCARD,
108 : : rte_memory_order_release);
109 : : else
110 : 1040 : rte_atomic_fetch_or_explicit(t, __RTE_TRACE_FIELD_ENABLE_DISCARD,
111 : : rte_memory_order_release);
112 : 236600 : }
113 : :
114 : : void
115 : 204 : rte_trace_mode_set(enum rte_trace_mode mode)
116 : : {
117 : : struct trace_point *tp;
118 : :
119 [ + + ]: 106284 : STAILQ_FOREACH(tp, &tp_list, next)
120 : 106080 : trace_mode_set(tp->handle, mode);
121 : :
122 : 204 : trace.mode = mode;
123 : 204 : }
124 : :
125 : : enum
126 : 8 : rte_trace_mode rte_trace_mode_get(void)
127 : : {
128 : 8 : return trace.mode;
129 : : }
130 : :
131 : : static bool
132 : : trace_point_is_invalid(rte_trace_point_t *t)
133 : : {
134 [ - + - + : 1592 : return (t == NULL) || (trace_id_get(t) >= trace.nb_trace_points);
- + ]
135 : : }
136 : :
137 : : bool
138 [ + - ]: 1052 : rte_trace_point_is_enabled(rte_trace_point_t *t)
139 : : {
140 : : uint64_t val;
141 : :
142 [ + - ]: 1052 : if (trace_point_is_invalid(t))
143 : : return false;
144 : :
145 : 1052 : val = rte_atomic_load_explicit(t, rte_memory_order_acquire);
146 : 1052 : return (val & __RTE_TRACE_FIELD_ENABLE_MASK) != 0;
147 : : }
148 : :
149 : : int
150 [ + - ]: 530 : rte_trace_point_enable(rte_trace_point_t *t)
151 : : {
152 : : uint64_t prev;
153 : :
154 [ + - ]: 530 : if (trace_point_is_invalid(t))
155 : : return -ERANGE;
156 : :
157 : 530 : prev = rte_atomic_fetch_or_explicit(t, __RTE_TRACE_FIELD_ENABLE_MASK,
158 : : rte_memory_order_release);
159 [ + - ]: 530 : if ((prev & __RTE_TRACE_FIELD_ENABLE_MASK) == 0)
160 : 530 : rte_atomic_fetch_add_explicit(&trace.status, 1, rte_memory_order_release);
161 : : return 0;
162 : : }
163 : :
164 : : int
165 [ + - ]: 10 : rte_trace_point_disable(rte_trace_point_t *t)
166 : : {
167 : : uint64_t prev;
168 : :
169 [ + - ]: 10 : if (trace_point_is_invalid(t))
170 : : return -ERANGE;
171 : :
172 : 10 : prev = rte_atomic_fetch_and_explicit(t, ~__RTE_TRACE_FIELD_ENABLE_MASK,
173 : : rte_memory_order_release);
174 [ + + ]: 10 : if ((prev & __RTE_TRACE_FIELD_ENABLE_MASK) != 0)
175 : 8 : rte_atomic_fetch_sub_explicit(&trace.status, 1, rte_memory_order_release);
176 : : return 0;
177 : : }
178 : :
179 : : int
180 : 6 : rte_trace_pattern(const char *pattern, bool enable)
181 : : {
182 : : struct trace_point *tp;
183 : : int rc = 0, found = 0;
184 : :
185 [ + + ]: 3126 : STAILQ_FOREACH(tp, &tp_list, next) {
186 [ + + ]: 3120 : if (fnmatch(pattern, tp->name, 0) != 0)
187 : 3112 : continue;
188 : :
189 [ + + ]: 8 : if (enable)
190 : 4 : rc = rte_trace_point_enable(tp->handle);
191 : : else
192 : 4 : rc = rte_trace_point_disable(tp->handle);
193 [ + - ]: 8 : if (rc < 0) {
194 : : found = 0;
195 : : break;
196 : : }
197 : : found = 1;
198 : : }
199 : :
200 : 6 : return rc | found;
201 : : }
202 : :
203 : : int
204 : 7 : rte_trace_regexp(const char *regex, bool enable)
205 : : {
206 : : struct trace_point *tp;
207 : : int rc = 0, found = 0;
208 : : regex_t r;
209 : :
210 [ + - ]: 7 : if (regcomp(&r, regex, 0) != 0)
211 : : return -EINVAL;
212 : :
213 [ + + ]: 3647 : STAILQ_FOREACH(tp, &tp_list, next) {
214 [ + + ]: 3640 : if (regexec(&r, tp->name, 0, NULL, 0) != 0)
215 : 3112 : continue;
216 : :
217 [ + + ]: 528 : if (enable)
218 : 524 : rc = rte_trace_point_enable(tp->handle);
219 : : else
220 : 4 : rc = rte_trace_point_disable(tp->handle);
221 [ + - ]: 528 : if (rc < 0) {
222 : : found = 0;
223 : : break;
224 : : }
225 : : found = 1;
226 : : }
227 : 7 : regfree(&r);
228 : :
229 : 7 : return rc | found;
230 : : }
231 : :
232 : : rte_trace_point_t *
233 : 4 : rte_trace_point_lookup(const char *name)
234 : : {
235 : : struct trace_point *tp;
236 : :
237 [ + - ]: 4 : if (name == NULL)
238 : : return NULL;
239 : :
240 [ + + ]: 1044 : STAILQ_FOREACH(tp, &tp_list, next)
241 [ + + ]: 1042 : if (strcmp(tp->name, name) == 0)
242 : 2 : return tp->handle;
243 : :
244 : : return NULL;
245 : : }
246 : :
247 : : static void
248 : 1040 : trace_point_dump(FILE *f, struct trace_point *tp)
249 : : {
250 : 1040 : rte_trace_point_t *handle = tp->handle;
251 : :
252 [ + + ]: 1040 : fprintf(f, "\tid %d, %s, size is %d, %s\n",
253 : : trace_id_get(handle), tp->name,
254 : 1040 : (uint16_t)(*handle & __RTE_TRACE_FIELD_SIZE_MASK),
255 : 1040 : rte_trace_point_is_enabled(handle) ? "enabled" : "disabled");
256 : 1040 : }
257 : :
258 : : static void
259 : 2 : trace_lcore_mem_dump(FILE *f)
260 : : {
261 : 2 : struct trace *trace = trace_obj_get();
262 : : struct __rte_trace_header *header;
263 : : uint32_t count;
264 : :
265 : 2 : rte_spinlock_lock(&trace->lock);
266 [ - + ]: 2 : if (trace->nb_trace_mem_list == 0)
267 : 0 : goto out;
268 : : fprintf(f, "nb_trace_mem_list = %d\n", trace->nb_trace_mem_list);
269 : : fprintf(f, "\nTrace mem info\n--------------\n");
270 [ + + ]: 7 : for (count = 0; count < trace->nb_trace_mem_list; count++) {
271 : 5 : header = trace->lcore_meta[count].mem;
272 : 5 : fprintf(f, "\tid %d, mem=%p, area=%s, lcore_id=%d, name=%s\n",
273 : : count, header,
274 : : trace_area_to_string(trace->lcore_meta[count].area),
275 : : header->stream_header.lcore_id,
276 : 5 : header->stream_header.thread_name);
277 : : }
278 : 2 : out:
279 : : rte_spinlock_unlock(&trace->lock);
280 : 2 : }
281 : :
282 : : void
283 : 2 : rte_trace_dump(FILE *f)
284 : : {
285 : 2 : struct trace_point_head *tp_list = trace_list_head_get();
286 : 2 : struct trace *trace = trace_obj_get();
287 : : struct trace_point *tp;
288 : :
289 : : fprintf(f, "\nGlobal info\n-----------\n");
290 [ - + ]: 2 : fprintf(f, "status = %s\n",
291 : 2 : rte_trace_is_enabled() ? "enabled" : "disabled");
292 : 2 : fprintf(f, "mode = %s\n",
293 : : trace_mode_to_string(rte_trace_mode_get()));
294 : 2 : fprintf(f, "dir = %s\n", trace->dir);
295 : 2 : fprintf(f, "buffer len = %d\n", trace->buff_len);
296 : 2 : fprintf(f, "number of trace points = %d\n", trace->nb_trace_points);
297 : :
298 : 2 : trace_lcore_mem_dump(f);
299 : : fprintf(f, "\nTrace point info\n----------------\n");
300 [ + + ]: 1042 : STAILQ_FOREACH(tp, tp_list, next)
301 : 1040 : trace_point_dump(f, tp);
302 : 2 : }
303 : :
304 : : static void
305 : : thread_get_name(rte_thread_t id, char *name, size_t len)
306 : : {
307 : : #if defined(RTE_EXEC_ENV_LINUX) && defined(__GLIBC__) && defined(__GLIBC_PREREQ)
308 : : #if __GLIBC_PREREQ(2, 12)
309 : 5 : pthread_getname_np((pthread_t)id.opaque_id, name, len);
310 : : #endif
311 : : #endif
312 : : RTE_SET_USED(id);
313 : : RTE_SET_USED(name);
314 : : RTE_SET_USED(len);
315 : : }
316 : :
317 : : void
318 : 799 : __rte_trace_mem_per_thread_alloc(void)
319 : : {
320 : 799 : struct trace *trace = trace_obj_get();
321 : : struct __rte_trace_header *header;
322 : : uint32_t count;
323 : :
324 [ + + ]: 799 : if (!rte_trace_is_enabled())
325 : : return;
326 : :
327 [ + - ]: 5 : if (RTE_PER_LCORE(trace_mem))
328 : : return;
329 : :
330 : 5 : rte_spinlock_lock(&trace->lock);
331 : :
332 : 5 : count = trace->nb_trace_mem_list;
333 : :
334 : : /* Allocate room for storing the thread trace mem meta */
335 : 5 : trace->lcore_meta = realloc(trace->lcore_meta,
336 : 5 : sizeof(trace->lcore_meta[0]) * (count + 1));
337 : :
338 : : /* Provide dummy space for fast path to consume */
339 [ - + ]: 5 : if (trace->lcore_meta == NULL) {
340 : 0 : trace_crit("trace mem meta memory realloc failed");
341 : : header = NULL;
342 : 0 : goto fail;
343 : : }
344 : :
345 : : /* First attempt from huge page */
346 : 5 : header = eal_malloc_no_trace(NULL, trace_mem_sz(trace->buff_len), 8);
347 [ + + ]: 5 : if (header) {
348 : 3 : trace->lcore_meta[count].area = TRACE_AREA_HUGEPAGE;
349 : 3 : goto found;
350 : : }
351 : :
352 : : /* Second attempt from heap */
353 [ - + ]: 2 : header = malloc(trace_mem_sz(trace->buff_len));
354 [ - + ]: 2 : if (header == NULL) {
355 : 0 : trace_crit("trace mem malloc attempt failed");
356 : : header = NULL;
357 : 0 : goto fail;
358 : :
359 : : }
360 : :
361 : : /* Second attempt from heap is success */
362 : 2 : trace->lcore_meta[count].area = TRACE_AREA_HEAP;
363 : :
364 : : /* Initialize the trace header */
365 : 5 : found:
366 : 5 : header->offset = 0;
367 : 5 : header->len = trace->buff_len;
368 : 5 : header->stream_header.magic = TRACE_CTF_MAGIC;
369 : 5 : rte_uuid_copy(header->stream_header.uuid, trace->uuid);
370 : 5 : header->stream_header.lcore_id = rte_lcore_id();
371 : :
372 : : /* Store the thread name */
373 : 5 : char *name = header->stream_header.thread_name;
374 : : memset(name, 0, __RTE_TRACE_EMIT_STRING_LEN_MAX);
375 : 5 : thread_get_name(rte_thread_self(), name,
376 : : __RTE_TRACE_EMIT_STRING_LEN_MAX);
377 : :
378 : 5 : trace->lcore_meta[count].mem = header;
379 : 5 : trace->nb_trace_mem_list++;
380 : 5 : fail:
381 : 5 : RTE_PER_LCORE(trace_mem) = header;
382 : : rte_spinlock_unlock(&trace->lock);
383 : : }
384 : :
385 : : static void
386 : 5 : trace_mem_per_thread_free_unlocked(struct thread_mem_meta *meta)
387 : : {
388 [ + + ]: 5 : if (meta->area == TRACE_AREA_HUGEPAGE)
389 : 3 : eal_free_no_trace(meta->mem);
390 [ + - ]: 2 : else if (meta->area == TRACE_AREA_HEAP)
391 : 2 : free(meta->mem);
392 : 5 : }
393 : :
394 : : void
395 : 129 : trace_mem_per_thread_free(void)
396 : : {
397 : 129 : struct trace *trace = trace_obj_get();
398 : : struct __rte_trace_header *header;
399 : : uint32_t count;
400 : :
401 : 129 : header = RTE_PER_LCORE(trace_mem);
402 [ - + ]: 129 : if (header == NULL)
403 : : return;
404 : :
405 : 0 : rte_spinlock_lock(&trace->lock);
406 [ # # ]: 0 : for (count = 0; count < trace->nb_trace_mem_list; count++) {
407 [ # # ]: 0 : if (trace->lcore_meta[count].mem == header)
408 : : break;
409 : : }
410 [ # # ]: 0 : if (count != trace->nb_trace_mem_list) {
411 : 0 : struct thread_mem_meta *meta = &trace->lcore_meta[count];
412 : :
413 : 0 : trace_mem_per_thread_free_unlocked(meta);
414 [ # # ]: 0 : if (count != trace->nb_trace_mem_list - 1) {
415 : 0 : memmove(meta, meta + 1,
416 : : sizeof(*meta) *
417 : 0 : (trace->nb_trace_mem_list - count - 1));
418 : : }
419 : 0 : trace->nb_trace_mem_list--;
420 : : }
421 : : rte_spinlock_unlock(&trace->lock);
422 : : }
423 : :
424 : : void
425 : 251 : trace_mem_free(void)
426 : : {
427 : 251 : struct trace *trace = trace_obj_get();
428 : : uint32_t count;
429 : :
430 : 251 : rte_spinlock_lock(&trace->lock);
431 [ + + ]: 256 : for (count = 0; count < trace->nb_trace_mem_list; count++) {
432 : 5 : trace_mem_per_thread_free_unlocked(&trace->lcore_meta[count]);
433 : : }
434 : 251 : trace->nb_trace_mem_list = 0;
435 : : rte_spinlock_unlock(&trace->lock);
436 : 251 : }
437 : :
438 : : void
439 : 488948 : __rte_trace_point_emit_field(size_t sz, const char *in, const char *datatype)
440 : : {
441 : : char *field;
442 : : char *fixup;
443 : : int rc;
444 : :
445 : 488948 : fixup = trace_metadata_fixup_field(in);
446 [ + + ]: 488948 : if (fixup != NULL)
447 : : in = fixup;
448 : 488948 : rc = asprintf(&field, "%s %s %s;\n",
449 [ + + ]: 488948 : RTE_PER_LCORE(ctf_field) != NULL ?
450 : : RTE_PER_LCORE(ctf_field) : "",
451 : : datatype, in);
452 : 488948 : free(RTE_PER_LCORE(ctf_field));
453 : 488948 : free(fixup);
454 [ - + ]: 488948 : if (rc == -1) {
455 : 0 : RTE_PER_LCORE(trace_point_sz) = 0;
456 : 0 : RTE_PER_LCORE(ctf_field) = NULL;
457 : 0 : trace_crit("could not allocate CTF field");
458 : 0 : return;
459 : : }
460 : 488948 : RTE_PER_LCORE(trace_point_sz) += sz;
461 : 488948 : RTE_PER_LCORE(ctf_field) = field;
462 : : }
463 : :
464 : : int
465 : 130520 : __rte_trace_point_register(rte_trace_point_t *handle, const char *name,
466 : : void (*register_fn)(void))
467 : : {
468 : : struct trace_point *tp;
469 : : uint16_t sz;
470 : :
471 : : /* Sanity checks of arguments */
472 [ + - - + ]: 130520 : if (name == NULL || register_fn == NULL || handle == NULL) {
473 : 0 : trace_err("invalid arguments");
474 : 0 : rte_errno = EINVAL;
475 : 0 : goto fail;
476 : : }
477 : :
478 : : /* Check the size of the trace point object */
479 : 130520 : RTE_PER_LCORE(trace_point_sz) = 0;
480 : 130520 : register_fn();
481 [ - + ]: 130520 : if (RTE_PER_LCORE(trace_point_sz) == 0) {
482 : 0 : trace_err("missing rte_trace_emit_header() in register fn");
483 : 0 : rte_errno = EBADF;
484 : 0 : goto fail;
485 : : }
486 : :
487 : : /* Is size overflowed */
488 [ - + ]: 130520 : if (RTE_PER_LCORE(trace_point_sz) > UINT16_MAX) {
489 : 0 : trace_err("trace point size overflowed");
490 : 0 : rte_errno = ENOSPC;
491 : 0 : goto fail;
492 : : }
493 : :
494 : : /* Are we running out of space to store trace points? */
495 [ - + ]: 130520 : if (trace.nb_trace_points > UINT16_MAX) {
496 : 0 : trace_err("trace point exceeds the max count");
497 : 0 : rte_errno = ENOSPC;
498 : 0 : goto fail;
499 : : }
500 : :
501 : : /* Get the size of the trace point */
502 : 130520 : sz = RTE_PER_LCORE(trace_point_sz);
503 : 130520 : tp = calloc(1, sizeof(struct trace_point));
504 [ - + ]: 130520 : if (tp == NULL) {
505 : 0 : trace_err("fail to allocate trace point memory");
506 : 0 : rte_errno = ENOMEM;
507 : 0 : goto fail;
508 : : }
509 : :
510 : : /* Initialize the trace point */
511 : 130520 : tp->name = name;
512 : :
513 : : /* Copy the accumulated fields description and clear it for the next
514 : : * trace point.
515 : : */
516 : 130520 : tp->ctf_field = RTE_PER_LCORE(ctf_field);
517 : 130520 : RTE_PER_LCORE(ctf_field) = NULL;
518 : :
519 : : /* Form the trace handle */
520 : 130520 : *handle = sz;
521 : 130520 : *handle |= trace.nb_trace_points << __RTE_TRACE_FIELD_ID_SHIFT;
522 : 130520 : trace_mode_set(handle, trace.mode);
523 : :
524 : 130520 : trace.nb_trace_points++;
525 : 130520 : tp->handle = handle;
526 : :
527 : : /* Add the trace point at tail */
528 : 130520 : STAILQ_INSERT_TAIL(&tp_list, tp, next);
529 : : rte_atomic_thread_fence(rte_memory_order_release);
530 : :
531 : : /* All Good !!! */
532 : 130520 : return 0;
533 : :
534 : 0 : fail:
535 [ # # ]: 0 : if (trace.register_errno == 0)
536 : 0 : trace.register_errno = rte_errno;
537 : :
538 : 0 : return -rte_errno;
539 : : }
|