net/cnxk: remove restriction on VF for PFC config
[dpdk.git] / lib / 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 - 1;
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                 errno = ENOSPC;
114                 goto fail;
115         }
116
117         return rc;
118 fail:
119         rte_errno = errno;
120         return -rte_errno;
121 }
122
123 static int
124 trace_dir_update(const char *str)
125 {
126         struct trace *trace = trace_obj_get();
127         int rc, remaining;
128
129         remaining = sizeof(trace->dir) - trace->dir_offset;
130         rc = rte_strscpy(&trace->dir[0] + trace->dir_offset, str, remaining);
131         if (rc < 0)
132                 goto fail;
133
134         trace->dir_offset += rc;
135 fail:
136         return rc;
137 }
138
139 int
140 eal_trace_args_save(const char *val)
141 {
142         struct trace *trace = trace_obj_get();
143         struct trace_arg *arg = malloc(sizeof(*arg));
144
145         if (arg == NULL) {
146                 trace_err("failed to allocate memory for %s", val);
147                 return -ENOMEM;
148         }
149
150         arg->val = strdup(val);
151         if (arg->val == NULL) {
152                 trace_err("failed to allocate memory for %s", val);
153                 free(arg);
154                 return -ENOMEM;
155         }
156
157         STAILQ_INSERT_TAIL(&trace->args, arg, next);
158         return 0;
159 }
160
161 void
162 eal_trace_args_free(void)
163 {
164         struct trace *trace = trace_obj_get();
165         struct trace_arg *arg;
166
167         while (!STAILQ_EMPTY(&trace->args)) {
168                 arg = STAILQ_FIRST(&trace->args);
169                 STAILQ_REMOVE_HEAD(&trace->args, next);
170                 free(arg->val);
171                 free(arg);
172         }
173 }
174
175 int
176 trace_args_apply(const char *arg)
177 {
178         if (rte_trace_regexp(arg, true) < 0) {
179                 trace_err("cannot enable trace for %s", arg);
180                 return -1;
181         }
182
183         return 0;
184 }
185
186 int
187 eal_trace_bufsz_args_save(char const *val)
188 {
189         struct trace *trace = trace_obj_get();
190         uint64_t bufsz;
191
192         bufsz = rte_str_to_size(val);
193         if (bufsz == 0) {
194                 trace_err("buffer size cannot be zero");
195                 return -EINVAL;
196         }
197
198         trace->buff_len = bufsz;
199         return 0;
200 }
201
202 void
203 trace_bufsz_args_apply(void)
204 {
205         struct trace *trace = trace_obj_get();
206
207         if (trace->buff_len == 0)
208                 trace->buff_len = 1024 * 1024; /* 1MB */
209 }
210
211 int
212 eal_trace_mode_args_save(const char *val)
213 {
214         struct trace *trace = trace_obj_get();
215         size_t len = strlen(val);
216         unsigned long tmp;
217         char *pattern;
218
219         if (len == 0) {
220                 trace_err("value is not provided with option");
221                 return -EINVAL;
222         }
223
224         pattern = (char *)calloc(1, len + 2);
225         if (pattern == NULL) {
226                 trace_err("fail to allocate memory");
227                 return -ENOMEM;
228         }
229
230         sprintf(pattern, "%s*", val);
231
232         if (fnmatch(pattern, "overwrite", 0) == 0)
233                 tmp = RTE_TRACE_MODE_OVERWRITE;
234         else if (fnmatch(pattern, "discard", 0) == 0)
235                 tmp = RTE_TRACE_MODE_DISCARD;
236         else {
237                 free(pattern);
238                 return -EINVAL;
239         }
240
241         trace->mode = tmp;
242         free(pattern);
243         return 0;
244 }
245
246 int
247 eal_trace_dir_args_save(char const *val)
248 {
249         struct trace *trace = trace_obj_get();
250         char *dir_path;
251         int rc;
252
253         if (strlen(val) >= sizeof(trace->dir) - 1) {
254                 trace_err("input string is too big");
255                 return -ENAMETOOLONG;
256         }
257
258         if (asprintf(&dir_path, "%s/", val) == -1) {
259                 trace_err("failed to copy directory: %s", strerror(errno));
260                 return -ENOMEM;
261         }
262
263         rc = trace_dir_update(dir_path);
264
265         free(dir_path);
266         return rc;
267 }
268
269 int
270 trace_epoch_time_save(void)
271 {
272         struct trace *trace = trace_obj_get();
273         struct timespec epoch = { 0, 0 };
274         uint64_t avg, start, end;
275
276         start = rte_get_tsc_cycles();
277         if (clock_gettime(CLOCK_REALTIME, &epoch) < 0) {
278                 trace_err("failed to get the epoch time");
279                 return -1;
280         }
281         end = rte_get_tsc_cycles();
282         avg = (start + end) >> 1;
283
284         trace->epoch_sec = (uint64_t) epoch.tv_sec;
285         trace->epoch_nsec = (uint64_t) epoch.tv_nsec;
286         trace->uptime_ticks = avg;
287
288         return 0;
289 }
290
291 static int
292 trace_dir_default_path_get(char *dir_path)
293 {
294         struct trace *trace = trace_obj_get();
295         uint32_t size = sizeof(trace->dir);
296         struct passwd *pwd;
297         char *home_dir;
298
299         /* First check for shell environment variable */
300         home_dir = getenv("HOME");
301         if (home_dir == NULL) {
302                 /* Fallback to password file entry */
303                 pwd = getpwuid(getuid());
304                 if (pwd == NULL)
305                         return -EINVAL;
306
307                 home_dir = pwd->pw_dir;
308         }
309
310         /* Append dpdk-traces to directory */
311         if (snprintf(dir_path, size, "%s/dpdk-traces/", home_dir) < 0)
312                 return -ENAMETOOLONG;
313
314         return 0;
315 }
316
317 int
318 trace_mkdir(void)
319 {
320         struct trace *trace = trace_obj_get();
321         char session[TRACE_DIR_STR_LEN];
322         char *dir_path;
323         int rc;
324
325         if (!trace->dir_offset) {
326                 dir_path = calloc(1, sizeof(trace->dir));
327                 if (dir_path == NULL) {
328                         trace_err("fail to allocate memory");
329                         return -ENOMEM;
330                 }
331
332                 rc = trace_dir_default_path_get(dir_path);
333                 if (rc < 0) {
334                         trace_err("fail to get default path");
335                         free(dir_path);
336                         return rc;
337                 }
338
339                 rc = trace_dir_update(dir_path);
340                 free(dir_path);
341                 if (rc < 0)
342                         return rc;
343         }
344
345         /* Create the path if it t exist, no "mkdir -p" available here */
346         rc = mkdir(trace->dir, 0700);
347         if (rc < 0 && errno != EEXIST) {
348                 trace_err("mkdir %s failed [%s]", trace->dir, strerror(errno));
349                 rte_errno = errno;
350                 return -rte_errno;
351         }
352
353         rc = trace_session_name_generate(session);
354         if (rc < 0)
355                 return rc;
356         rc = trace_dir_update(session);
357         if (rc < 0)
358                 return rc;
359
360         rc = mkdir(trace->dir, 0700);
361         if (rc < 0) {
362                 trace_err("mkdir %s failed [%s]", trace->dir, strerror(errno));
363                 rte_errno = errno;
364                 return -rte_errno;
365         }
366
367         RTE_LOG(INFO, EAL, "Trace dir: %s\n", trace->dir);
368         return 0;
369 }
370
371 static int
372 trace_meta_save(struct trace *trace)
373 {
374         char file_name[PATH_MAX];
375         FILE *f;
376         int rc;
377
378         rc = snprintf(file_name, PATH_MAX, "%s/metadata", trace->dir);
379         if (rc < 0)
380                 return rc;
381
382         f = fopen(file_name, "w");
383         if (f == NULL)
384                 return -errno;
385
386         rc = rte_trace_metadata_dump(f);
387
388         if (fclose(f))
389                 rc = -errno;
390
391         return rc;
392 }
393
394
395 static inline int
396 trace_file_sz(struct __rte_trace_header *hdr)
397 {
398         return sizeof(struct __rte_trace_stream_header) + hdr->offset;
399 }
400
401 static int
402 trace_mem_save(struct trace *trace, struct __rte_trace_header *hdr,
403                 uint32_t cnt)
404 {
405         char file_name[PATH_MAX];
406         FILE *f;
407         int rc;
408
409         rc = snprintf(file_name, PATH_MAX, "%s/channel0_%d", trace->dir, cnt);
410         if (rc < 0)
411                 return rc;
412
413         f = fopen(file_name, "w");
414         if (f == NULL)
415                 return -errno;
416
417         rc = fwrite(&hdr->stream_header, trace_file_sz(hdr), 1, f);
418         rc = (rc == 1) ?  0 : -EACCES;
419
420         if (fclose(f))
421                 rc = -errno;
422
423         return rc;
424 }
425
426 int
427 rte_trace_save(void)
428 {
429         struct trace *trace = trace_obj_get();
430         struct __rte_trace_header *header;
431         uint32_t count;
432         int rc = 0;
433
434         if (trace->nb_trace_mem_list == 0)
435                 return rc;
436
437         rc = trace_meta_save(trace);
438         if (rc)
439                 return rc;
440
441         rte_spinlock_lock(&trace->lock);
442         for (count = 0; count < trace->nb_trace_mem_list; count++) {
443                 header = trace->lcore_meta[count].mem;
444                 rc =  trace_mem_save(trace, header, count);
445                 if (rc)
446                         break;
447         }
448         rte_spinlock_unlock(&trace->lock);
449         return rc;
450 }