xref: /OK3568_Linux_fs/kernel/tools/perf/util/time-utils.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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