1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <stdlib.h>
3*4882a593Smuzhiyun #include <string.h>
4*4882a593Smuzhiyun #include <linux/string.h>
5*4882a593Smuzhiyun #include <sys/time.h>
6*4882a593Smuzhiyun #include <linux/time64.h>
7*4882a593Smuzhiyun #include <time.h>
8*4882a593Smuzhiyun #include <errno.h>
9*4882a593Smuzhiyun #include <inttypes.h>
10*4882a593Smuzhiyun #include <math.h>
11*4882a593Smuzhiyun #include <linux/ctype.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include "debug.h"
14*4882a593Smuzhiyun #include "time-utils.h"
15*4882a593Smuzhiyun #include "session.h"
16*4882a593Smuzhiyun #include "evlist.h"
17*4882a593Smuzhiyun
parse_nsec_time(const char * str,u64 * ptime)18*4882a593Smuzhiyun int parse_nsec_time(const char *str, u64 *ptime)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun u64 time_sec, time_nsec;
21*4882a593Smuzhiyun char *end;
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun time_sec = strtoul(str, &end, 10);
24*4882a593Smuzhiyun if (*end != '.' && *end != '\0')
25*4882a593Smuzhiyun return -1;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun if (*end == '.') {
28*4882a593Smuzhiyun int i;
29*4882a593Smuzhiyun char nsec_buf[10];
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun if (strlen(++end) > 9)
32*4882a593Smuzhiyun return -1;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun strncpy(nsec_buf, end, 9);
35*4882a593Smuzhiyun nsec_buf[9] = '\0';
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /* make it nsec precision */
38*4882a593Smuzhiyun for (i = strlen(nsec_buf); i < 9; i++)
39*4882a593Smuzhiyun nsec_buf[i] = '0';
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun time_nsec = strtoul(nsec_buf, &end, 10);
42*4882a593Smuzhiyun if (*end != '\0')
43*4882a593Smuzhiyun return -1;
44*4882a593Smuzhiyun } else
45*4882a593Smuzhiyun time_nsec = 0;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun *ptime = time_sec * NSEC_PER_SEC + time_nsec;
48*4882a593Smuzhiyun return 0;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
parse_timestr_sec_nsec(struct perf_time_interval * ptime,char * start_str,char * end_str)51*4882a593Smuzhiyun static int parse_timestr_sec_nsec(struct perf_time_interval *ptime,
52*4882a593Smuzhiyun char *start_str, char *end_str)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun if (start_str && (*start_str != '\0') &&
55*4882a593Smuzhiyun (parse_nsec_time(start_str, &ptime->start) != 0)) {
56*4882a593Smuzhiyun return -1;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun if (end_str && (*end_str != '\0') &&
60*4882a593Smuzhiyun (parse_nsec_time(end_str, &ptime->end) != 0)) {
61*4882a593Smuzhiyun return -1;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun return 0;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
split_start_end(char ** start,char ** end,const char * ostr,char ch)67*4882a593Smuzhiyun static int split_start_end(char **start, char **end, const char *ostr, char ch)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun char *start_str, *end_str;
70*4882a593Smuzhiyun char *d, *str;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun if (ostr == NULL || *ostr == '\0')
73*4882a593Smuzhiyun return 0;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* copy original string because we need to modify it */
76*4882a593Smuzhiyun str = strdup(ostr);
77*4882a593Smuzhiyun if (str == NULL)
78*4882a593Smuzhiyun return -ENOMEM;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun start_str = str;
81*4882a593Smuzhiyun d = strchr(start_str, ch);
82*4882a593Smuzhiyun if (d) {
83*4882a593Smuzhiyun *d = '\0';
84*4882a593Smuzhiyun ++d;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun end_str = d;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun *start = start_str;
89*4882a593Smuzhiyun *end = end_str;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun return 0;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
perf_time__parse_str(struct perf_time_interval * ptime,const char * ostr)94*4882a593Smuzhiyun int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun char *start_str = NULL, *end_str;
97*4882a593Smuzhiyun int rc;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun rc = split_start_end(&start_str, &end_str, ostr, ',');
100*4882a593Smuzhiyun if (rc || !start_str)
101*4882a593Smuzhiyun return rc;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun ptime->start = 0;
104*4882a593Smuzhiyun ptime->end = 0;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun rc = parse_timestr_sec_nsec(ptime, start_str, end_str);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun free(start_str);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun /* make sure end time is after start time if it was given */
111*4882a593Smuzhiyun if (rc == 0 && ptime->end && ptime->end < ptime->start)
112*4882a593Smuzhiyun return -EINVAL;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun pr_debug("start time %" PRIu64 ", ", ptime->start);
115*4882a593Smuzhiyun pr_debug("end time %" PRIu64 "\n", ptime->end);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun return rc;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
perf_time__parse_strs(struct perf_time_interval * ptime,const char * ostr,int size)120*4882a593Smuzhiyun static int perf_time__parse_strs(struct perf_time_interval *ptime,
121*4882a593Smuzhiyun const char *ostr, int size)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun const char *cp;
124*4882a593Smuzhiyun char *str, *arg, *p;
125*4882a593Smuzhiyun int i, num = 0, rc = 0;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* Count the commas */
128*4882a593Smuzhiyun for (cp = ostr; *cp; cp++)
129*4882a593Smuzhiyun num += !!(*cp == ',');
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun if (!num)
132*4882a593Smuzhiyun return -EINVAL;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun BUG_ON(num > size);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun str = strdup(ostr);
137*4882a593Smuzhiyun if (!str)
138*4882a593Smuzhiyun return -ENOMEM;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /* Split the string and parse each piece, except the last */
141*4882a593Smuzhiyun for (i = 0, p = str; i < num - 1; i++) {
142*4882a593Smuzhiyun arg = p;
143*4882a593Smuzhiyun /* Find next comma, there must be one */
144*4882a593Smuzhiyun p = skip_spaces(strchr(p, ',') + 1);
145*4882a593Smuzhiyun /* Skip the value, must not contain space or comma */
146*4882a593Smuzhiyun while (*p && !isspace(*p)) {
147*4882a593Smuzhiyun if (*p++ == ',') {
148*4882a593Smuzhiyun rc = -EINVAL;
149*4882a593Smuzhiyun goto out;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun /* Split and parse */
153*4882a593Smuzhiyun if (*p)
154*4882a593Smuzhiyun *p++ = 0;
155*4882a593Smuzhiyun rc = perf_time__parse_str(ptime + i, arg);
156*4882a593Smuzhiyun if (rc < 0)
157*4882a593Smuzhiyun goto out;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /* Parse the last piece */
161*4882a593Smuzhiyun rc = perf_time__parse_str(ptime + i, p);
162*4882a593Smuzhiyun if (rc < 0)
163*4882a593Smuzhiyun goto out;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /* Check there is no overlap */
166*4882a593Smuzhiyun for (i = 0; i < num - 1; i++) {
167*4882a593Smuzhiyun if (ptime[i].end >= ptime[i + 1].start) {
168*4882a593Smuzhiyun rc = -EINVAL;
169*4882a593Smuzhiyun goto out;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun rc = num;
174*4882a593Smuzhiyun out:
175*4882a593Smuzhiyun free(str);
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun return rc;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
parse_percent(double * pcnt,char * str)180*4882a593Smuzhiyun static int parse_percent(double *pcnt, char *str)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun char *c, *endptr;
183*4882a593Smuzhiyun double d;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun c = strchr(str, '%');
186*4882a593Smuzhiyun if (c)
187*4882a593Smuzhiyun *c = '\0';
188*4882a593Smuzhiyun else
189*4882a593Smuzhiyun return -1;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun d = strtod(str, &endptr);
192*4882a593Smuzhiyun if (endptr != str + strlen(str))
193*4882a593Smuzhiyun return -1;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun *pcnt = d / 100.0;
196*4882a593Smuzhiyun return 0;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
set_percent_time(struct perf_time_interval * ptime,double start_pcnt,double end_pcnt,u64 start,u64 end)199*4882a593Smuzhiyun static int set_percent_time(struct perf_time_interval *ptime, double start_pcnt,
200*4882a593Smuzhiyun double end_pcnt, u64 start, u64 end)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun u64 total = end - start;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun if (start_pcnt < 0.0 || start_pcnt > 1.0 ||
205*4882a593Smuzhiyun end_pcnt < 0.0 || end_pcnt > 1.0) {
206*4882a593Smuzhiyun return -1;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun ptime->start = start + round(start_pcnt * total);
210*4882a593Smuzhiyun ptime->end = start + round(end_pcnt * total);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun if (ptime->end > ptime->start && ptime->end != end)
213*4882a593Smuzhiyun ptime->end -= 1;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun return 0;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
percent_slash_split(char * str,struct perf_time_interval * ptime,u64 start,u64 end)218*4882a593Smuzhiyun static int percent_slash_split(char *str, struct perf_time_interval *ptime,
219*4882a593Smuzhiyun u64 start, u64 end)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun char *p, *end_str;
222*4882a593Smuzhiyun double pcnt, start_pcnt, end_pcnt;
223*4882a593Smuzhiyun int i;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun /*
226*4882a593Smuzhiyun * Example:
227*4882a593Smuzhiyun * 10%/2: select the second 10% slice and the third 10% slice
228*4882a593Smuzhiyun */
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun /* We can modify this string since the original one is copied */
231*4882a593Smuzhiyun p = strchr(str, '/');
232*4882a593Smuzhiyun if (!p)
233*4882a593Smuzhiyun return -1;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun *p = '\0';
236*4882a593Smuzhiyun if (parse_percent(&pcnt, str) < 0)
237*4882a593Smuzhiyun return -1;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun p++;
240*4882a593Smuzhiyun i = (int)strtol(p, &end_str, 10);
241*4882a593Smuzhiyun if (*end_str)
242*4882a593Smuzhiyun return -1;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun if (pcnt <= 0.0)
245*4882a593Smuzhiyun return -1;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun start_pcnt = pcnt * (i - 1);
248*4882a593Smuzhiyun end_pcnt = pcnt * i;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun return set_percent_time(ptime, start_pcnt, end_pcnt, start, end);
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
percent_dash_split(char * str,struct perf_time_interval * ptime,u64 start,u64 end)253*4882a593Smuzhiyun static int percent_dash_split(char *str, struct perf_time_interval *ptime,
254*4882a593Smuzhiyun u64 start, u64 end)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun char *start_str = NULL, *end_str;
257*4882a593Smuzhiyun double start_pcnt, end_pcnt;
258*4882a593Smuzhiyun int ret;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun /*
261*4882a593Smuzhiyun * Example: 0%-10%
262*4882a593Smuzhiyun */
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun ret = split_start_end(&start_str, &end_str, str, '-');
265*4882a593Smuzhiyun if (ret || !start_str)
266*4882a593Smuzhiyun return ret;
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun if ((parse_percent(&start_pcnt, start_str) != 0) ||
269*4882a593Smuzhiyun (parse_percent(&end_pcnt, end_str) != 0)) {
270*4882a593Smuzhiyun free(start_str);
271*4882a593Smuzhiyun return -1;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun free(start_str);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun return set_percent_time(ptime, start_pcnt, end_pcnt, start, end);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun typedef int (*time_pecent_split)(char *, struct perf_time_interval *,
280*4882a593Smuzhiyun u64 start, u64 end);
281*4882a593Smuzhiyun
percent_comma_split(struct perf_time_interval * ptime_buf,int num,const char * ostr,u64 start,u64 end,time_pecent_split func)282*4882a593Smuzhiyun static int percent_comma_split(struct perf_time_interval *ptime_buf, int num,
283*4882a593Smuzhiyun const char *ostr, u64 start, u64 end,
284*4882a593Smuzhiyun time_pecent_split func)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun char *str, *p1, *p2;
287*4882a593Smuzhiyun int len, ret, i = 0;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun str = strdup(ostr);
290*4882a593Smuzhiyun if (str == NULL)
291*4882a593Smuzhiyun return -ENOMEM;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun len = strlen(str);
294*4882a593Smuzhiyun p1 = str;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun while (p1 < str + len) {
297*4882a593Smuzhiyun if (i >= num) {
298*4882a593Smuzhiyun free(str);
299*4882a593Smuzhiyun return -1;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun p2 = strchr(p1, ',');
303*4882a593Smuzhiyun if (p2)
304*4882a593Smuzhiyun *p2 = '\0';
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun ret = (func)(p1, &ptime_buf[i], start, end);
307*4882a593Smuzhiyun if (ret < 0) {
308*4882a593Smuzhiyun free(str);
309*4882a593Smuzhiyun return -1;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun pr_debug("start time %d: %" PRIu64 ", ", i, ptime_buf[i].start);
313*4882a593Smuzhiyun pr_debug("end time %d: %" PRIu64 "\n", i, ptime_buf[i].end);
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun i++;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun if (p2)
318*4882a593Smuzhiyun p1 = p2 + 1;
319*4882a593Smuzhiyun else
320*4882a593Smuzhiyun break;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun free(str);
324*4882a593Smuzhiyun return i;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
one_percent_convert(struct perf_time_interval * ptime_buf,const char * ostr,u64 start,u64 end,char * c)327*4882a593Smuzhiyun static int one_percent_convert(struct perf_time_interval *ptime_buf,
328*4882a593Smuzhiyun const char *ostr, u64 start, u64 end, char *c)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun char *str;
331*4882a593Smuzhiyun int len = strlen(ostr), ret;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun /*
334*4882a593Smuzhiyun * c points to '%'.
335*4882a593Smuzhiyun * '%' should be the last character
336*4882a593Smuzhiyun */
337*4882a593Smuzhiyun if (ostr + len - 1 != c)
338*4882a593Smuzhiyun return -1;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /*
341*4882a593Smuzhiyun * Construct a string like "xx%/1"
342*4882a593Smuzhiyun */
343*4882a593Smuzhiyun str = malloc(len + 3);
344*4882a593Smuzhiyun if (str == NULL)
345*4882a593Smuzhiyun return -ENOMEM;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun memcpy(str, ostr, len);
348*4882a593Smuzhiyun strcpy(str + len, "/1");
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun ret = percent_slash_split(str, ptime_buf, start, end);
351*4882a593Smuzhiyun if (ret == 0)
352*4882a593Smuzhiyun ret = 1;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun free(str);
355*4882a593Smuzhiyun return ret;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
perf_time__percent_parse_str(struct perf_time_interval * ptime_buf,int num,const char * ostr,u64 start,u64 end)358*4882a593Smuzhiyun int perf_time__percent_parse_str(struct perf_time_interval *ptime_buf, int num,
359*4882a593Smuzhiyun const char *ostr, u64 start, u64 end)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun char *c;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun /*
364*4882a593Smuzhiyun * ostr example:
365*4882a593Smuzhiyun * 10%/2,10%/3: select the second 10% slice and the third 10% slice
366*4882a593Smuzhiyun * 0%-10%,30%-40%: multiple time range
367*4882a593Smuzhiyun * 50%: just one percent
368*4882a593Smuzhiyun */
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun memset(ptime_buf, 0, sizeof(*ptime_buf) * num);
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun c = strchr(ostr, '/');
373*4882a593Smuzhiyun if (c) {
374*4882a593Smuzhiyun return percent_comma_split(ptime_buf, num, ostr, start,
375*4882a593Smuzhiyun end, percent_slash_split);
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun c = strchr(ostr, '-');
379*4882a593Smuzhiyun if (c) {
380*4882a593Smuzhiyun return percent_comma_split(ptime_buf, num, ostr, start,
381*4882a593Smuzhiyun end, percent_dash_split);
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun c = strchr(ostr, '%');
385*4882a593Smuzhiyun if (c)
386*4882a593Smuzhiyun return one_percent_convert(ptime_buf, ostr, start, end, c);
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun return -1;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
perf_time__range_alloc(const char * ostr,int * size)391*4882a593Smuzhiyun struct perf_time_interval *perf_time__range_alloc(const char *ostr, int *size)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun const char *p1, *p2;
394*4882a593Smuzhiyun int i = 1;
395*4882a593Smuzhiyun struct perf_time_interval *ptime;
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun /*
398*4882a593Smuzhiyun * At least allocate one time range.
399*4882a593Smuzhiyun */
400*4882a593Smuzhiyun if (!ostr)
401*4882a593Smuzhiyun goto alloc;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun p1 = ostr;
404*4882a593Smuzhiyun while (p1 < ostr + strlen(ostr)) {
405*4882a593Smuzhiyun p2 = strchr(p1, ',');
406*4882a593Smuzhiyun if (!p2)
407*4882a593Smuzhiyun break;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun p1 = p2 + 1;
410*4882a593Smuzhiyun i++;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun alloc:
414*4882a593Smuzhiyun *size = i;
415*4882a593Smuzhiyun ptime = calloc(i, sizeof(*ptime));
416*4882a593Smuzhiyun return ptime;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
perf_time__skip_sample(struct perf_time_interval * ptime,u64 timestamp)419*4882a593Smuzhiyun bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun /* if time is not set don't drop sample */
422*4882a593Smuzhiyun if (timestamp == 0)
423*4882a593Smuzhiyun return false;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun /* otherwise compare sample time to time window */
426*4882a593Smuzhiyun if ((ptime->start && timestamp < ptime->start) ||
427*4882a593Smuzhiyun (ptime->end && timestamp > ptime->end)) {
428*4882a593Smuzhiyun return true;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun return false;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
perf_time__ranges_skip_sample(struct perf_time_interval * ptime_buf,int num,u64 timestamp)434*4882a593Smuzhiyun bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf,
435*4882a593Smuzhiyun int num, u64 timestamp)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun struct perf_time_interval *ptime;
438*4882a593Smuzhiyun int i;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun if ((!ptime_buf) || (timestamp == 0) || (num == 0))
441*4882a593Smuzhiyun return false;
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun if (num == 1)
444*4882a593Smuzhiyun return perf_time__skip_sample(&ptime_buf[0], timestamp);
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun /*
447*4882a593Smuzhiyun * start/end of multiple time ranges must be valid.
448*4882a593Smuzhiyun */
449*4882a593Smuzhiyun for (i = 0; i < num; i++) {
450*4882a593Smuzhiyun ptime = &ptime_buf[i];
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun if (timestamp >= ptime->start &&
453*4882a593Smuzhiyun (timestamp <= ptime->end || !ptime->end)) {
454*4882a593Smuzhiyun return false;
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun return true;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun
perf_time__parse_for_ranges_reltime(const char * time_str,struct perf_session * session,struct perf_time_interval ** ranges,int * range_size,int * range_num,bool reltime)461*4882a593Smuzhiyun int perf_time__parse_for_ranges_reltime(const char *time_str,
462*4882a593Smuzhiyun struct perf_session *session,
463*4882a593Smuzhiyun struct perf_time_interval **ranges,
464*4882a593Smuzhiyun int *range_size, int *range_num,
465*4882a593Smuzhiyun bool reltime)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun bool has_percent = strchr(time_str, '%');
468*4882a593Smuzhiyun struct perf_time_interval *ptime_range;
469*4882a593Smuzhiyun int size, num, ret = -EINVAL;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun ptime_range = perf_time__range_alloc(time_str, &size);
472*4882a593Smuzhiyun if (!ptime_range)
473*4882a593Smuzhiyun return -ENOMEM;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun if (has_percent || reltime) {
476*4882a593Smuzhiyun if (session->evlist->first_sample_time == 0 &&
477*4882a593Smuzhiyun session->evlist->last_sample_time == 0) {
478*4882a593Smuzhiyun pr_err("HINT: no first/last sample time found in perf data.\n"
479*4882a593Smuzhiyun "Please use latest perf binary to execute 'perf record'\n"
480*4882a593Smuzhiyun "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n");
481*4882a593Smuzhiyun goto error;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun if (has_percent) {
486*4882a593Smuzhiyun num = perf_time__percent_parse_str(
487*4882a593Smuzhiyun ptime_range, size,
488*4882a593Smuzhiyun time_str,
489*4882a593Smuzhiyun session->evlist->first_sample_time,
490*4882a593Smuzhiyun session->evlist->last_sample_time);
491*4882a593Smuzhiyun } else {
492*4882a593Smuzhiyun num = perf_time__parse_strs(ptime_range, time_str, size);
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun if (num < 0)
496*4882a593Smuzhiyun goto error_invalid;
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun if (reltime) {
499*4882a593Smuzhiyun int i;
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun for (i = 0; i < num; i++) {
502*4882a593Smuzhiyun ptime_range[i].start += session->evlist->first_sample_time;
503*4882a593Smuzhiyun ptime_range[i].end += session->evlist->first_sample_time;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun *range_size = size;
508*4882a593Smuzhiyun *range_num = num;
509*4882a593Smuzhiyun *ranges = ptime_range;
510*4882a593Smuzhiyun return 0;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun error_invalid:
513*4882a593Smuzhiyun pr_err("Invalid time string\n");
514*4882a593Smuzhiyun error:
515*4882a593Smuzhiyun free(ptime_range);
516*4882a593Smuzhiyun return ret;
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun
perf_time__parse_for_ranges(const char * time_str,struct perf_session * session,struct perf_time_interval ** ranges,int * range_size,int * range_num)519*4882a593Smuzhiyun int perf_time__parse_for_ranges(const char *time_str,
520*4882a593Smuzhiyun struct perf_session *session,
521*4882a593Smuzhiyun struct perf_time_interval **ranges,
522*4882a593Smuzhiyun int *range_size, int *range_num)
523*4882a593Smuzhiyun {
524*4882a593Smuzhiyun return perf_time__parse_for_ranges_reltime(time_str, session, ranges,
525*4882a593Smuzhiyun range_size, range_num, false);
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun
timestamp__scnprintf_usec(u64 timestamp,char * buf,size_t sz)528*4882a593Smuzhiyun int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz)
529*4882a593Smuzhiyun {
530*4882a593Smuzhiyun u64 sec = timestamp / NSEC_PER_SEC;
531*4882a593Smuzhiyun u64 usec = (timestamp % NSEC_PER_SEC) / NSEC_PER_USEC;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun return scnprintf(buf, sz, "%"PRIu64".%06"PRIu64, sec, usec);
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun
timestamp__scnprintf_nsec(u64 timestamp,char * buf,size_t sz)536*4882a593Smuzhiyun int timestamp__scnprintf_nsec(u64 timestamp, char *buf, size_t sz)
537*4882a593Smuzhiyun {
538*4882a593Smuzhiyun u64 sec = timestamp / NSEC_PER_SEC,
539*4882a593Smuzhiyun nsec = timestamp % NSEC_PER_SEC;
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun return scnprintf(buf, sz, "%" PRIu64 ".%09" PRIu64, sec, nsec);
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun
fetch_current_timestamp(char * buf,size_t sz)544*4882a593Smuzhiyun int fetch_current_timestamp(char *buf, size_t sz)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun struct timeval tv;
547*4882a593Smuzhiyun struct tm tm;
548*4882a593Smuzhiyun char dt[32];
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
551*4882a593Smuzhiyun return -1;
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
554*4882a593Smuzhiyun return -1;
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun scnprintf(buf, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun return 0;
559*4882a593Smuzhiyun }
560