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