77ea8f78e14d9057c61552be5ecc332785267727
[dpdk.git] / lib / librte_eal / common / eal_common_trace_utils.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2020 Marvell International Ltd.
3  */
4
5 #include <fnmatch.h>
6 #include <pwd.h>
7 #include <sys/stat.h>
8 #include <time.h>
9
10 #include <rte_common.h>
11 #include <rte_errno.h>
12 #include <rte_string_fns.h>
13
14 #include "eal_filesystem.h"
15 #include "eal_trace.h"
16
17 const char *
18 trace_mode_to_string(enum rte_trace_mode mode)
19 {
20         switch (mode) {
21         case RTE_TRACE_MODE_OVERWRITE: return "overwrite";
22         case RTE_TRACE_MODE_DISCARD: return "discard";
23         default: return "unknown";
24         }
25 }
26
27 const char *
28 trace_area_to_string(enum trace_area_e area)
29 {
30         switch (area) {
31         case TRACE_AREA_HEAP: return "heap";
32         case TRACE_AREA_HUGEPAGE: return "hugepage";
33         default: return "unknown";
34         }
35 }
36
37 static bool
38 trace_entry_compare(const char *name)
39 {
40         struct trace_point_head *tp_list = trace_list_head_get();
41         struct trace_point *tp;
42         int count = 0;
43
44         STAILQ_FOREACH(tp, tp_list, next) {
45                 if (strncmp(tp->name, name, TRACE_POINT_NAME_SIZE) == 0)
46                         count++;
47                 if (count > 1) {
48                         trace_err("found duplicate entry %s", name);
49                         rte_errno = EEXIST;
50                         return true;
51                 }
52         }
53         return false;
54 }
55
56 bool
57 trace_has_duplicate_entry(void)
58 {
59         struct trace_point_head *tp_list = trace_list_head_get();
60         struct trace_point *tp;
61
62         /* Is duplicate trace name registered */
63         STAILQ_FOREACH(tp, tp_list, next)
64                 if (trace_entry_compare(tp->name))
65                         return true;
66
67         return false;
68 }
69
70 void
71 trace_uuid_generate(void)
72 {
73         struct trace_point_head *tp_list = trace_list_head_get();
74         struct trace *trace = trace_obj_get();
75         struct trace_point *tp;
76         uint64_t sz_total = 0;
77
78         /* Go over the registered trace points to get total size of events */
79         STAILQ_FOREACH(tp, tp_list, next) {
80                 const uint16_t sz = *tp->handle & __RTE_TRACE_FIELD_SIZE_MASK;
81                 sz_total += sz;
82         }
83
84         rte_uuid_t uuid = RTE_UUID_INIT(sz_total, trace->nb_trace_points,
85                 0x4370, 0x8f50, 0x222ddd514176ULL);
86         rte_uuid_copy(trace->uuid, uuid);
87 }
88
89 static int
90 trace_session_name_generate(char *trace_dir)
91 {
92         struct tm *tm_result;
93         time_t tm;
94         int rc;
95
96         tm = time(NULL);
97         if ((int)tm == -1)
98                 goto fail;
99
100         tm_result = localtime(&tm);
101         if (tm_result == NULL)
102                 goto fail;
103
104         rc = rte_strscpy(trace_dir, eal_get_hugefile_prefix(),
105                         TRACE_PREFIX_LEN);
106         if (rc == -E2BIG)
107                 rc = TRACE_PREFIX_LEN;
108         trace_dir[rc++] = '-';
109
110         rc = strftime(trace_dir + rc, TRACE_DIR_STR_LEN - rc,
111                         "%Y-%m-%d-%p-%I-%M-%S", tm_result);
112         if (rc == 0)
113                 goto fail;
114
115         return rc;
116 fail:
117         rte_errno = errno;
118         return -rte_errno;
119 }
120
121 static int
122 trace_dir_update(const char *str)
123 {
124         struct trace *trace = trace_obj_get();
125         int rc, remaining;
126
127         remaining = sizeof(trace->dir) - trace->dir_offset;
128         rc = rte_strscpy(&trace->dir[0] + trace->dir_offset, str, remaining);
129         if (rc < 0)
130                 goto fail;
131
132         trace->dir_offset += rc;
133 fail:
134         return rc;
135 }
136
137 int
138 eal_trace_args_save(const char *val)
139 {
140         struct trace *trace = trace_obj_get();
141         struct trace_arg *arg = malloc(sizeof(*arg));
142
143         if (arg == NULL) {
144                 trace_err("failed to allocate memory for %s", val);
145                 return -ENOMEM;
146         }
147
148         arg->val = strdup(val);
149         if (arg->val == NULL) {
150                 trace_err("failed to allocate memory for %s", val);
151                 free(arg);
152                 return -ENOMEM;
153         }
154
155         STAILQ_INSERT_TAIL(&trace->args, arg, next);
156         return 0;
157 }
158
159 void
160 eal_trace_args_free(void)
161 {
162         struct trace *trace = trace_obj_get();
163         struct trace_arg *arg;
164
165         while (!STAILQ_EMPTY(&trace->args)) {
166                 arg = STAILQ_FIRST(&trace->args);
167                 STAILQ_REMOVE_HEAD(&trace->args, next);
168                 free(arg->val);
169                 free(arg);
170         }
171 }
172
173 int
174 trace_args_apply(const char *arg)
175 {
176         char *str;
177
178         str = strdup(arg);
179         if (str == NULL)
180                 return -1;
181
182         if (rte_trace_regexp(str, true) < 0) {
183                 trace_err("cannot enable trace for %s", str);
184                 free(str);
185                 return -1;
186         }
187
188         free(str);
189         return 0;
190 }
191
192 int
193 eal_trace_bufsz_args_save(char const *val)
194 {
195         struct trace *trace = trace_obj_get();
196         uint64_t bufsz;
197
198         bufsz = rte_str_to_size(val);
199         if (bufsz == 0) {
200                 trace_err("buffer size cannot be zero");
201                 return -EINVAL;
202         }
203
204         trace->buff_len = bufsz;
205         return 0;
206 }
207
208 void
209 trace_bufsz_args_apply(void)
210 {
211         struct trace *trace = trace_obj_get();
212
213         if (trace->buff_len == 0)
214                 trace->buff_len = 1024 * 1024; /* 1MB */
215 }
216
217 int
218 eal_trace_mode_args_save(const char *val)
219 {
220         struct trace *trace = trace_obj_get();
221         size_t len = strlen(val);
222         unsigned long tmp;
223         char *pattern;
224
225         if (len == 0) {
226                 trace_err("value is not provided with option");
227                 return -EINVAL;
228         }
229
230         pattern = (char *)calloc(1, len + 2);
231         if (pattern == NULL) {
232                 trace_err("fail to allocate memory");
233                 return -ENOMEM;
234         }
235
236         sprintf(pattern, "%s*", val);
237
238         if (fnmatch(pattern, "overwrite", 0) == 0)
239                 tmp = RTE_TRACE_MODE_OVERWRITE;
240         else if (fnmatch(pattern, "discard", 0) == 0)
241                 tmp = RTE_TRACE_MODE_DISCARD;
242         else {
243                 free(pattern);
244                 return -EINVAL;
245         }
246
247         trace->mode = tmp;
248         free(pattern);
249         return 0;
250 }
251
252 int
253 eal_trace_dir_args_save(char const *val)
254 {
255         struct trace *trace = trace_obj_get();
256         uint32_t size = sizeof(trace->dir);
257         char *dir_path = NULL;
258         int rc;
259
260         if (strlen(val) >= size) {
261                 trace_err("input string is too big");
262                 return -ENAMETOOLONG;
263         }
264
265         dir_path = (char *)calloc(1, size);
266         if (dir_path == NULL) {
267                 trace_err("fail to allocate memory");
268                 return -ENOMEM;
269         }
270
271         sprintf(dir_path, "%s/", val);
272         rc = trace_dir_update(dir_path);
273
274         free(dir_path);
275         return rc;
276 }
277
278 int
279 trace_epoch_time_save(void)
280 {
281         struct trace *trace = trace_obj_get();
282         struct timespec epoch = { 0, 0 };
283         uint64_t avg, start, end;
284
285         start = rte_get_tsc_cycles();
286         if (clock_gettime(CLOCK_REALTIME, &epoch) < 0) {
287                 trace_err("failed to get the epoch time");
288                 return -1;
289         }
290         end = rte_get_tsc_cycles();
291         avg = (start + end) >> 1;
292
293         trace->epoch_sec = (uint64_t) epoch.tv_sec;
294         trace->epoch_nsec = (uint64_t) epoch.tv_nsec;
295         trace->uptime_ticks = avg;
296
297         return 0;
298 }
299
300 static int
301 trace_dir_default_path_get(char *dir_path)
302 {
303         struct trace *trace = trace_obj_get();
304         uint32_t size = sizeof(trace->dir);
305         struct passwd *pwd;
306         char *home_dir;
307
308         /* First check for shell environment variable */
309         home_dir = getenv("HOME");
310         if (home_dir == NULL) {
311                 /* Fallback to password file entry */
312                 pwd = getpwuid(getuid());
313                 if (pwd == NULL)
314                         return -EINVAL;
315
316                 home_dir = pwd->pw_dir;
317         }
318
319         /* Append dpdk-traces to directory */
320         if (snprintf(dir_path, size, "%s/dpdk-traces/", home_dir) < 0)
321                 return -ENAMETOOLONG;
322
323         return 0;
324 }
325
326 int
327 trace_mkdir(void)
328 {
329         struct trace *trace = trace_obj_get();
330         char session[TRACE_DIR_STR_LEN];
331         char *dir_path;
332         int rc;
333
334         if (!trace->dir_offset) {
335                 dir_path = calloc(1, sizeof(trace->dir));
336                 if (dir_path == NULL) {
337                         trace_err("fail to allocate memory");
338                         return -ENOMEM;
339                 }
340
341                 rc = trace_dir_default_path_get(dir_path);
342                 if (rc < 0) {
343                         trace_err("fail to get default path");
344                         free(dir_path);
345                         return rc;
346                 }
347
348                 rc = trace_dir_update(dir_path);
349                 free(dir_path);
350                 if (rc < 0)
351                         return rc;
352         }
353
354         /* Create the path if it t exist, no "mkdir -p" available here */
355         rc = mkdir(trace->dir, 0700);
356         if (rc < 0 && errno != EEXIST) {
357                 trace_err("mkdir %s failed [%s]", trace->dir, strerror(errno));
358                 rte_errno = errno;
359                 return -rte_errno;
360         }
361
362         rc = trace_session_name_generate(session);
363         if (rc < 0)
364                 return rc;
365         rc = trace_dir_update(session);
366         if (rc < 0)
367                 return rc;
368
369         rc = mkdir(trace->dir, 0700);
370         if (rc < 0) {
371                 trace_err("mkdir %s failed [%s]", trace->dir, strerror(errno));
372                 rte_errno = errno;
373                 return -rte_errno;
374         }
375
376         RTE_LOG(INFO, EAL, "Trace dir: %s\n", trace->dir);
377         return 0;
378 }
379
380 static int
381 trace_meta_save(struct trace *trace)
382 {
383         char file_name[PATH_MAX];
384         FILE *f;
385         int rc;
386
387         rc = snprintf(file_name, PATH_MAX, "%s/metadata", trace->dir);
388         if (rc < 0)
389                 return rc;
390
391         f = fopen(file_name, "w");
392         if (f == NULL)
393                 return -errno;
394
395         rc = rte_trace_metadata_dump(f);
396
397         if (fclose(f))
398                 rc = -errno;
399
400         return rc;
401 }
402
403
404 static inline int
405 trace_file_sz(struct __rte_trace_header *hdr)
406 {
407         return sizeof(struct __rte_trace_stream_header) + hdr->offset;
408 }
409
410 static int
411 trace_mem_save(struct trace *trace, struct __rte_trace_header *hdr,
412                 uint32_t cnt)
413 {
414         char file_name[PATH_MAX];
415         FILE *f;
416         int rc;
417
418         rc = snprintf(file_name, PATH_MAX, "%s/channel0_%d", trace->dir, cnt);
419         if (rc < 0)
420                 return rc;
421
422         f = fopen(file_name, "w");
423         if (f == NULL)
424                 return -errno;
425
426         rc = fwrite(&hdr->stream_header, trace_file_sz(hdr), 1, f);
427         rc = (rc == 1) ?  0 : -EACCES;
428
429         if (fclose(f))
430                 rc = -errno;
431
432         return rc;
433 }
434
435 int
436 rte_trace_save(void)
437 {
438         struct trace *trace = trace_obj_get();
439         struct __rte_trace_header *header;
440         uint32_t count;
441         int rc = 0;
442
443         if (trace->nb_trace_mem_list == 0)
444                 return rc;
445
446         rc = trace_meta_save(trace);
447         if (rc)
448                 return rc;
449
450         rte_spinlock_lock(&trace->lock);
451         for (count = 0; count < trace->nb_trace_mem_list; count++) {
452                 header = trace->lcore_meta[count].mem;
453                 rc =  trace_mem_save(trace, header, count);
454                 if (rc)
455                         break;
456         }
457         rte_spinlock_unlock(&trace->lock);
458         return rc;
459 }