503d0ab3d968927bc492747a78bf25af205a1735
[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 int
122 trace_epoch_time_save(void)
123 {
124         struct trace *trace = trace_obj_get();
125         struct timespec epoch = { 0, 0 };
126         uint64_t avg, start, end;
127
128         start = rte_get_tsc_cycles();
129         if (clock_gettime(CLOCK_REALTIME, &epoch) < 0) {
130                 trace_err("failed to get the epoch time");
131                 return -1;
132         }
133         end = rte_get_tsc_cycles();
134         avg = (start + end) >> 1;
135
136         trace->epoch_sec = (uint64_t) epoch.tv_sec;
137         trace->epoch_nsec = (uint64_t) epoch.tv_nsec;
138         trace->uptime_ticks = avg;
139
140         return 0;
141 }
142
143 static int
144 trace_dir_default_path_get(char *dir_path)
145 {
146         struct trace *trace = trace_obj_get();
147         uint32_t size = sizeof(trace->dir);
148         struct passwd *pwd;
149         char *home_dir;
150
151         /* First check for shell environment variable */
152         home_dir = getenv("HOME");
153         if (home_dir == NULL) {
154                 /* Fallback to password file entry */
155                 pwd = getpwuid(getuid());
156                 if (pwd == NULL)
157                         return -EINVAL;
158
159                 home_dir = pwd->pw_dir;
160         }
161
162         /* Append dpdk-traces to directory */
163         if (snprintf(dir_path, size, "%s/dpdk-traces/", home_dir) < 0)
164                 return -ENAMETOOLONG;
165
166         return 0;
167 }
168
169 int
170 trace_mkdir(void)
171 {
172         struct trace *trace = trace_obj_get();
173         char session[TRACE_DIR_STR_LEN];
174         char *dir_path;
175         int rc;
176
177         if (!trace->dir_offset) {
178                 dir_path = calloc(1, sizeof(trace->dir));
179                 if (dir_path == NULL) {
180                         trace_err("fail to allocate memory");
181                         return -ENOMEM;
182                 }
183
184                 rc = trace_dir_default_path_get(dir_path);
185                 if (rc < 0) {
186                         trace_err("fail to get default path");
187                         free(dir_path);
188                         return rc;
189                 }
190
191         }
192
193         /* Create the path if it t exist, no "mkdir -p" available here */
194         rc = mkdir(trace->dir, 0700);
195         if (rc < 0 && errno != EEXIST) {
196                 trace_err("mkdir %s failed [%s]", trace->dir, strerror(errno));
197                 rte_errno = errno;
198                 return -rte_errno;
199         }
200
201         rc = trace_session_name_generate(session);
202         if (rc < 0)
203                 return rc;
204
205         rc = mkdir(trace->dir, 0700);
206         if (rc < 0) {
207                 trace_err("mkdir %s failed [%s]", trace->dir, strerror(errno));
208                 rte_errno = errno;
209                 return -rte_errno;
210         }
211
212         RTE_LOG(INFO, EAL, "Trace dir: %s\n", trace->dir);
213         return 0;
214 }
215