trace: save bootup timestamp
[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 static bool
18 trace_entry_compare(const char *name)
19 {
20         struct trace_point_head *tp_list = trace_list_head_get();
21         struct trace_point *tp;
22         int count = 0;
23
24         STAILQ_FOREACH(tp, tp_list, next) {
25                 if (strncmp(tp->name, name, TRACE_POINT_NAME_SIZE) == 0)
26                         count++;
27                 if (count > 1) {
28                         trace_err("found duplicate entry %s", name);
29                         rte_errno = EEXIST;
30                         return true;
31                 }
32         }
33         return false;
34 }
35
36 bool
37 trace_has_duplicate_entry(void)
38 {
39         struct trace_point_head *tp_list = trace_list_head_get();
40         struct trace_point *tp;
41
42         /* Is duplicate trace name registered */
43         STAILQ_FOREACH(tp, tp_list, next)
44                 if (trace_entry_compare(tp->name))
45                         return true;
46
47         return false;
48 }
49
50 void
51 trace_uuid_generate(void)
52 {
53         struct trace_point_head *tp_list = trace_list_head_get();
54         struct trace *trace = trace_obj_get();
55         struct trace_point *tp;
56         uint64_t sz_total = 0;
57
58         /* Go over the registered trace points to get total size of events */
59         STAILQ_FOREACH(tp, tp_list, next) {
60                 const uint16_t sz = *tp->handle & __RTE_TRACE_FIELD_SIZE_MASK;
61                 sz_total += sz;
62         }
63
64         rte_uuid_t uuid = RTE_UUID_INIT(sz_total, trace->nb_trace_points,
65                 0x4370, 0x8f50, 0x222ddd514176ULL);
66         rte_uuid_copy(trace->uuid, uuid);
67 }
68
69 static int
70 trace_session_name_generate(char *trace_dir)
71 {
72         struct tm *tm_result;
73         time_t tm;
74         int rc;
75
76         tm = time(NULL);
77         if ((int)tm == -1)
78                 goto fail;
79
80         tm_result = localtime(&tm);
81         if (tm_result == NULL)
82                 goto fail;
83
84         rc = rte_strscpy(trace_dir, eal_get_hugefile_prefix(),
85                         TRACE_PREFIX_LEN);
86         if (rc == -E2BIG)
87                 rc = TRACE_PREFIX_LEN;
88         trace_dir[rc++] = '-';
89
90         rc = strftime(trace_dir + rc, TRACE_DIR_STR_LEN - rc,
91                         "%Y-%m-%d-%p-%I-%M-%S", tm_result);
92         if (rc == 0)
93                 goto fail;
94
95         return rc;
96 fail:
97         rte_errno = errno;
98         return -rte_errno;
99 }
100
101 int
102 trace_epoch_time_save(void)
103 {
104         struct trace *trace = trace_obj_get();
105         struct timespec epoch = { 0, 0 };
106         uint64_t avg, start, end;
107
108         start = rte_get_tsc_cycles();
109         if (clock_gettime(CLOCK_REALTIME, &epoch) < 0) {
110                 trace_err("failed to get the epoch time");
111                 return -1;
112         }
113         end = rte_get_tsc_cycles();
114         avg = (start + end) >> 1;
115
116         trace->epoch_sec = (uint64_t) epoch.tv_sec;
117         trace->epoch_nsec = (uint64_t) epoch.tv_nsec;
118         trace->uptime_ticks = avg;
119
120         return 0;
121 }
122
123 static int
124 trace_dir_default_path_get(char *dir_path)
125 {
126         struct trace *trace = trace_obj_get();
127         uint32_t size = sizeof(trace->dir);
128         struct passwd *pwd;
129         char *home_dir;
130
131         /* First check for shell environment variable */
132         home_dir = getenv("HOME");
133         if (home_dir == NULL) {
134                 /* Fallback to password file entry */
135                 pwd = getpwuid(getuid());
136                 if (pwd == NULL)
137                         return -EINVAL;
138
139                 home_dir = pwd->pw_dir;
140         }
141
142         /* Append dpdk-traces to directory */
143         if (snprintf(dir_path, size, "%s/dpdk-traces/", home_dir) < 0)
144                 return -ENAMETOOLONG;
145
146         return 0;
147 }
148
149 int
150 trace_mkdir(void)
151 {
152         struct trace *trace = trace_obj_get();
153         char session[TRACE_DIR_STR_LEN];
154         char *dir_path;
155         int rc;
156
157         if (!trace->dir_offset) {
158                 dir_path = calloc(1, sizeof(trace->dir));
159                 if (dir_path == NULL) {
160                         trace_err("fail to allocate memory");
161                         return -ENOMEM;
162                 }
163
164                 rc = trace_dir_default_path_get(dir_path);
165                 if (rc < 0) {
166                         trace_err("fail to get default path");
167                         free(dir_path);
168                         return rc;
169                 }
170
171         }
172
173         /* Create the path if it t exist, no "mkdir -p" available here */
174         rc = mkdir(trace->dir, 0700);
175         if (rc < 0 && errno != EEXIST) {
176                 trace_err("mkdir %s failed [%s]", trace->dir, strerror(errno));
177                 rte_errno = errno;
178                 return -rte_errno;
179         }
180
181         rc = trace_session_name_generate(session);
182         if (rc < 0)
183                 return rc;
184
185         rc = mkdir(trace->dir, 0700);
186         if (rc < 0) {
187                 trace_err("mkdir %s failed [%s]", trace->dir, strerror(errno));
188                 rte_errno = errno;
189                 return -rte_errno;
190         }
191
192         RTE_LOG(INFO, EAL, "Trace dir: %s\n", trace->dir);
193         return 0;
194 }
195