f5b8d4ec7107cf3fcfaca62ce0bf6fa9d9209296
[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 *optarg)
139 {
140         struct trace *trace = trace_obj_get();
141         char *trace_args;
142         uint8_t nb_args;
143
144         nb_args = trace->args.nb_args;
145
146         if (nb_args >= TRACE_MAX_ARGS) {
147                 trace_err("ignoring trace %s as limit exceeds", optarg);
148                 return 0;
149         }
150
151         trace_args = calloc(1, (strlen(optarg) + 1));
152         if (trace_args == NULL) {
153                 trace_err("fail to allocate memory for %s", optarg);
154                 return -ENOMEM;
155         }
156
157         memcpy(trace_args, optarg, strlen(optarg));
158         trace->args.args[nb_args++] = trace_args;
159         trace->args.nb_args = nb_args;
160         return 0;
161 }
162
163 void
164 eal_trace_args_free(void)
165 {
166         struct trace *trace = trace_obj_get();
167         int i;
168
169         for (i = 0; i < trace->args.nb_args; i++) {
170                 if (trace->args.args[i]) {
171                         free((void *)trace->args.args[i]);
172                         trace->args.args[i] = NULL;
173                 }
174         }
175 }
176
177 int
178 trace_args_apply(const char *arg)
179 {
180         char *str;
181
182         str = strdup(arg);
183         if (str == NULL)
184                 return -1;
185
186         if (rte_trace_regexp(str, true) < 0) {
187                 trace_err("cannot enable trace for %s", str);
188                 free(str);
189                 return -1;
190         }
191
192         free(str);
193         return 0;
194 }
195
196 int
197 eal_trace_dir_args_save(char const *optarg)
198 {
199         struct trace *trace = trace_obj_get();
200         uint32_t size = sizeof(trace->dir);
201         char *dir_path = NULL;
202         int rc;
203
204         if (optarg == NULL) {
205                 trace_err("no optarg is passed");
206                 return -EINVAL;
207         }
208
209         if (strlen(optarg) >= size) {
210                 trace_err("input string is too big");
211                 return -ENAMETOOLONG;
212         }
213
214         dir_path = (char *)calloc(1, size);
215         if (dir_path == NULL) {
216                 trace_err("fail to allocate memory");
217                 return -ENOMEM;
218         }
219
220         sprintf(dir_path, "%s/", optarg);
221         rc = trace_dir_update(dir_path);
222
223         free(dir_path);
224         return rc;
225 }
226
227 int
228 trace_epoch_time_save(void)
229 {
230         struct trace *trace = trace_obj_get();
231         struct timespec epoch = { 0, 0 };
232         uint64_t avg, start, end;
233
234         start = rte_get_tsc_cycles();
235         if (clock_gettime(CLOCK_REALTIME, &epoch) < 0) {
236                 trace_err("failed to get the epoch time");
237                 return -1;
238         }
239         end = rte_get_tsc_cycles();
240         avg = (start + end) >> 1;
241
242         trace->epoch_sec = (uint64_t) epoch.tv_sec;
243         trace->epoch_nsec = (uint64_t) epoch.tv_nsec;
244         trace->uptime_ticks = avg;
245
246         return 0;
247 }
248
249 static int
250 trace_dir_default_path_get(char *dir_path)
251 {
252         struct trace *trace = trace_obj_get();
253         uint32_t size = sizeof(trace->dir);
254         struct passwd *pwd;
255         char *home_dir;
256
257         /* First check for shell environment variable */
258         home_dir = getenv("HOME");
259         if (home_dir == NULL) {
260                 /* Fallback to password file entry */
261                 pwd = getpwuid(getuid());
262                 if (pwd == NULL)
263                         return -EINVAL;
264
265                 home_dir = pwd->pw_dir;
266         }
267
268         /* Append dpdk-traces to directory */
269         if (snprintf(dir_path, size, "%s/dpdk-traces/", home_dir) < 0)
270                 return -ENAMETOOLONG;
271
272         return 0;
273 }
274
275 int
276 trace_mkdir(void)
277 {
278         struct trace *trace = trace_obj_get();
279         char session[TRACE_DIR_STR_LEN];
280         char *dir_path;
281         int rc;
282
283         if (!trace->dir_offset) {
284                 dir_path = calloc(1, sizeof(trace->dir));
285                 if (dir_path == NULL) {
286                         trace_err("fail to allocate memory");
287                         return -ENOMEM;
288                 }
289
290                 rc = trace_dir_default_path_get(dir_path);
291                 if (rc < 0) {
292                         trace_err("fail to get default path");
293                         free(dir_path);
294                         return rc;
295                 }
296
297                 rc = trace_dir_update(dir_path);
298                 free(dir_path);
299                 if (rc < 0)
300                         return rc;
301         }
302
303         /* Create the path if it t exist, no "mkdir -p" available here */
304         rc = mkdir(trace->dir, 0700);
305         if (rc < 0 && errno != EEXIST) {
306                 trace_err("mkdir %s failed [%s]", trace->dir, strerror(errno));
307                 rte_errno = errno;
308                 return -rte_errno;
309         }
310
311         rc = trace_session_name_generate(session);
312         if (rc < 0)
313                 return rc;
314         rc = trace_dir_update(session);
315         if (rc < 0)
316                 return rc;
317
318         rc = mkdir(trace->dir, 0700);
319         if (rc < 0) {
320                 trace_err("mkdir %s failed [%s]", trace->dir, strerror(errno));
321                 rte_errno = errno;
322                 return -rte_errno;
323         }
324
325         RTE_LOG(INFO, EAL, "Trace dir: %s\n", trace->dir);
326         return 0;
327 }
328
329 static int
330 trace_meta_save(struct trace *trace)
331 {
332         char file_name[PATH_MAX];
333         FILE *f;
334         int rc;
335
336         rc = snprintf(file_name, PATH_MAX, "%s/metadata", trace->dir);
337         if (rc < 0)
338                 return rc;
339
340         f = fopen(file_name, "w");
341         if (f == NULL)
342                 return -errno;
343
344         rc = rte_trace_metadata_dump(f);
345
346         if (fclose(f))
347                 rc = -errno;
348
349         return rc;
350 }
351
352
353 static inline int
354 trace_file_sz(struct __rte_trace_header *hdr)
355 {
356         return sizeof(struct __rte_trace_stream_header) + hdr->offset;
357 }
358
359 static int
360 trace_mem_save(struct trace *trace, struct __rte_trace_header *hdr,
361                 uint32_t cnt)
362 {
363         char file_name[PATH_MAX];
364         FILE *f;
365         int rc;
366
367         rc = snprintf(file_name, PATH_MAX, "%s/channel0_%d", trace->dir, cnt);
368         if (rc < 0)
369                 return rc;
370
371         f = fopen(file_name, "w");
372         if (f == NULL)
373                 return -errno;
374
375         rc = fwrite(&hdr->stream_header, trace_file_sz(hdr), 1, f);
376         rc = (rc == 1) ?  0 : -EACCES;
377
378         if (fclose(f))
379                 rc = -errno;
380
381         return rc;
382 }
383
384 int
385 rte_trace_save(void)
386 {
387         struct trace *trace = trace_obj_get();
388         struct __rte_trace_header *header;
389         uint32_t count;
390         int rc = 0;
391
392         if (trace->nb_trace_mem_list == 0)
393                 return rc;
394
395         rc = trace_meta_save(trace);
396         if (rc)
397                 return rc;
398
399         rte_spinlock_lock(&trace->lock);
400         for (count = 0; count < trace->nb_trace_mem_list; count++) {
401                 header = trace->lcore_meta[count].mem;
402                 rc =  trace_mem_save(trace, header, count);
403                 if (rc)
404                         break;
405         }
406         rte_spinlock_unlock(&trace->lock);
407         return rc;
408 }