162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <stdlib.h>
362306a36Sopenharmony_ci#include <string.h>
462306a36Sopenharmony_ci#include <linux/string.h>
562306a36Sopenharmony_ci#include <sys/time.h>
662306a36Sopenharmony_ci#include <linux/time64.h>
762306a36Sopenharmony_ci#include <time.h>
862306a36Sopenharmony_ci#include <errno.h>
962306a36Sopenharmony_ci#include <inttypes.h>
1062306a36Sopenharmony_ci#include <math.h>
1162306a36Sopenharmony_ci#include <linux/ctype.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "debug.h"
1462306a36Sopenharmony_ci#include "time-utils.h"
1562306a36Sopenharmony_ci#include "session.h"
1662306a36Sopenharmony_ci#include "evlist.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciint parse_nsec_time(const char *str, u64 *ptime)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	u64 time_sec, time_nsec;
2162306a36Sopenharmony_ci	char *end;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	time_sec = strtoul(str, &end, 10);
2462306a36Sopenharmony_ci	if (*end != '.' && *end != '\0')
2562306a36Sopenharmony_ci		return -1;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (*end == '.') {
2862306a36Sopenharmony_ci		int i;
2962306a36Sopenharmony_ci		char nsec_buf[10];
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci		if (strlen(++end) > 9)
3262306a36Sopenharmony_ci			return -1;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci		strncpy(nsec_buf, end, 9);
3562306a36Sopenharmony_ci		nsec_buf[9] = '\0';
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci		/* make it nsec precision */
3862306a36Sopenharmony_ci		for (i = strlen(nsec_buf); i < 9; i++)
3962306a36Sopenharmony_ci			nsec_buf[i] = '0';
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci		time_nsec = strtoul(nsec_buf, &end, 10);
4262306a36Sopenharmony_ci		if (*end != '\0')
4362306a36Sopenharmony_ci			return -1;
4462306a36Sopenharmony_ci	} else
4562306a36Sopenharmony_ci		time_nsec = 0;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	*ptime = time_sec * NSEC_PER_SEC + time_nsec;
4862306a36Sopenharmony_ci	return 0;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int parse_timestr_sec_nsec(struct perf_time_interval *ptime,
5262306a36Sopenharmony_ci				  char *start_str, char *end_str)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	if (start_str && (*start_str != '\0') &&
5562306a36Sopenharmony_ci	    (parse_nsec_time(start_str, &ptime->start) != 0)) {
5662306a36Sopenharmony_ci		return -1;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (end_str && (*end_str != '\0') &&
6062306a36Sopenharmony_ci	    (parse_nsec_time(end_str, &ptime->end) != 0)) {
6162306a36Sopenharmony_ci		return -1;
6262306a36Sopenharmony_ci	}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	return 0;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int split_start_end(char **start, char **end, const char *ostr, char ch)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	char *start_str, *end_str;
7062306a36Sopenharmony_ci	char *d, *str;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (ostr == NULL || *ostr == '\0')
7362306a36Sopenharmony_ci		return 0;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* copy original string because we need to modify it */
7662306a36Sopenharmony_ci	str = strdup(ostr);
7762306a36Sopenharmony_ci	if (str == NULL)
7862306a36Sopenharmony_ci		return -ENOMEM;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	start_str = str;
8162306a36Sopenharmony_ci	d = strchr(start_str, ch);
8262306a36Sopenharmony_ci	if (d) {
8362306a36Sopenharmony_ci		*d = '\0';
8462306a36Sopenharmony_ci		++d;
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci	end_str = d;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	*start = start_str;
8962306a36Sopenharmony_ci	*end = end_str;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return 0;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ciint perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	char *start_str = NULL, *end_str;
9762306a36Sopenharmony_ci	int rc;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	rc = split_start_end(&start_str, &end_str, ostr, ',');
10062306a36Sopenharmony_ci	if (rc || !start_str)
10162306a36Sopenharmony_ci		return rc;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	ptime->start = 0;
10462306a36Sopenharmony_ci	ptime->end = 0;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	rc = parse_timestr_sec_nsec(ptime, start_str, end_str);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	free(start_str);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* make sure end time is after start time if it was given */
11162306a36Sopenharmony_ci	if (rc == 0 && ptime->end && ptime->end < ptime->start)
11262306a36Sopenharmony_ci		return -EINVAL;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	pr_debug("start time %" PRIu64 ", ", ptime->start);
11562306a36Sopenharmony_ci	pr_debug("end time %" PRIu64 "\n", ptime->end);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	return rc;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic int perf_time__parse_strs(struct perf_time_interval *ptime,
12162306a36Sopenharmony_ci				 const char *ostr, int size)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	const char *cp;
12462306a36Sopenharmony_ci	char *str, *arg, *p;
12562306a36Sopenharmony_ci	int i, num = 0, rc = 0;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* Count the commas */
12862306a36Sopenharmony_ci	for (cp = ostr; *cp; cp++)
12962306a36Sopenharmony_ci		num += !!(*cp == ',');
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	if (!num)
13262306a36Sopenharmony_ci		return -EINVAL;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	BUG_ON(num > size);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	str = strdup(ostr);
13762306a36Sopenharmony_ci	if (!str)
13862306a36Sopenharmony_ci		return -ENOMEM;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/* Split the string and parse each piece, except the last */
14162306a36Sopenharmony_ci	for (i = 0, p = str; i < num - 1; i++) {
14262306a36Sopenharmony_ci		arg = p;
14362306a36Sopenharmony_ci		/* Find next comma, there must be one */
14462306a36Sopenharmony_ci		p = skip_spaces(strchr(p, ',') + 1);
14562306a36Sopenharmony_ci		/* Skip the value, must not contain space or comma */
14662306a36Sopenharmony_ci		while (*p && !isspace(*p)) {
14762306a36Sopenharmony_ci			if (*p++ == ',') {
14862306a36Sopenharmony_ci				rc = -EINVAL;
14962306a36Sopenharmony_ci				goto out;
15062306a36Sopenharmony_ci			}
15162306a36Sopenharmony_ci		}
15262306a36Sopenharmony_ci		/* Split and parse */
15362306a36Sopenharmony_ci		if (*p)
15462306a36Sopenharmony_ci			*p++ = 0;
15562306a36Sopenharmony_ci		rc = perf_time__parse_str(ptime + i, arg);
15662306a36Sopenharmony_ci		if (rc < 0)
15762306a36Sopenharmony_ci			goto out;
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/* Parse the last piece */
16162306a36Sopenharmony_ci	rc = perf_time__parse_str(ptime + i, p);
16262306a36Sopenharmony_ci	if (rc < 0)
16362306a36Sopenharmony_ci		goto out;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/* Check there is no overlap */
16662306a36Sopenharmony_ci	for (i = 0; i < num - 1; i++) {
16762306a36Sopenharmony_ci		if (ptime[i].end >= ptime[i + 1].start) {
16862306a36Sopenharmony_ci			rc = -EINVAL;
16962306a36Sopenharmony_ci			goto out;
17062306a36Sopenharmony_ci		}
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	rc = num;
17462306a36Sopenharmony_ciout:
17562306a36Sopenharmony_ci	free(str);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	return rc;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic int parse_percent(double *pcnt, char *str)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	char *c, *endptr;
18362306a36Sopenharmony_ci	double d;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	c = strchr(str, '%');
18662306a36Sopenharmony_ci	if (c)
18762306a36Sopenharmony_ci		*c = '\0';
18862306a36Sopenharmony_ci	else
18962306a36Sopenharmony_ci		return -1;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	d = strtod(str, &endptr);
19262306a36Sopenharmony_ci	if (endptr != str + strlen(str))
19362306a36Sopenharmony_ci		return -1;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	*pcnt = d / 100.0;
19662306a36Sopenharmony_ci	return 0;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic int set_percent_time(struct perf_time_interval *ptime, double start_pcnt,
20062306a36Sopenharmony_ci			    double end_pcnt, u64 start, u64 end)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	u64 total = end - start;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (start_pcnt < 0.0 || start_pcnt > 1.0 ||
20562306a36Sopenharmony_ci	    end_pcnt < 0.0 || end_pcnt > 1.0) {
20662306a36Sopenharmony_ci		return -1;
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	ptime->start = start + round(start_pcnt * total);
21062306a36Sopenharmony_ci	ptime->end = start + round(end_pcnt * total);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (ptime->end > ptime->start && ptime->end != end)
21362306a36Sopenharmony_ci		ptime->end -= 1;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	return 0;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic int percent_slash_split(char *str, struct perf_time_interval *ptime,
21962306a36Sopenharmony_ci			       u64 start, u64 end)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	char *p, *end_str;
22262306a36Sopenharmony_ci	double pcnt, start_pcnt, end_pcnt;
22362306a36Sopenharmony_ci	int i;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/*
22662306a36Sopenharmony_ci	 * Example:
22762306a36Sopenharmony_ci	 * 10%/2: select the second 10% slice and the third 10% slice
22862306a36Sopenharmony_ci	 */
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	/* We can modify this string since the original one is copied */
23162306a36Sopenharmony_ci	p = strchr(str, '/');
23262306a36Sopenharmony_ci	if (!p)
23362306a36Sopenharmony_ci		return -1;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	*p = '\0';
23662306a36Sopenharmony_ci	if (parse_percent(&pcnt, str) < 0)
23762306a36Sopenharmony_ci		return -1;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	p++;
24062306a36Sopenharmony_ci	i = (int)strtol(p, &end_str, 10);
24162306a36Sopenharmony_ci	if (*end_str)
24262306a36Sopenharmony_ci		return -1;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (pcnt <= 0.0)
24562306a36Sopenharmony_ci		return -1;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	start_pcnt = pcnt * (i - 1);
24862306a36Sopenharmony_ci	end_pcnt = pcnt * i;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	return set_percent_time(ptime, start_pcnt, end_pcnt, start, end);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic int percent_dash_split(char *str, struct perf_time_interval *ptime,
25462306a36Sopenharmony_ci			      u64 start, u64 end)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	char *start_str = NULL, *end_str;
25762306a36Sopenharmony_ci	double start_pcnt, end_pcnt;
25862306a36Sopenharmony_ci	int ret;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/*
26162306a36Sopenharmony_ci	 * Example: 0%-10%
26262306a36Sopenharmony_ci	 */
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	ret = split_start_end(&start_str, &end_str, str, '-');
26562306a36Sopenharmony_ci	if (ret || !start_str)
26662306a36Sopenharmony_ci		return ret;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if ((parse_percent(&start_pcnt, start_str) != 0) ||
26962306a36Sopenharmony_ci	    (parse_percent(&end_pcnt, end_str) != 0)) {
27062306a36Sopenharmony_ci		free(start_str);
27162306a36Sopenharmony_ci		return -1;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	free(start_str);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	return set_percent_time(ptime, start_pcnt, end_pcnt, start, end);
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_citypedef int (*time_pecent_split)(char *, struct perf_time_interval *,
28062306a36Sopenharmony_ci				 u64 start, u64 end);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int percent_comma_split(struct perf_time_interval *ptime_buf, int num,
28362306a36Sopenharmony_ci			       const char *ostr, u64 start, u64 end,
28462306a36Sopenharmony_ci			       time_pecent_split func)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	char *str, *p1, *p2;
28762306a36Sopenharmony_ci	int len, ret, i = 0;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	str = strdup(ostr);
29062306a36Sopenharmony_ci	if (str == NULL)
29162306a36Sopenharmony_ci		return -ENOMEM;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	len = strlen(str);
29462306a36Sopenharmony_ci	p1 = str;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	while (p1 < str + len) {
29762306a36Sopenharmony_ci		if (i >= num) {
29862306a36Sopenharmony_ci			free(str);
29962306a36Sopenharmony_ci			return -1;
30062306a36Sopenharmony_ci		}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		p2 = strchr(p1, ',');
30362306a36Sopenharmony_ci		if (p2)
30462306a36Sopenharmony_ci			*p2 = '\0';
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci		ret = (func)(p1, &ptime_buf[i], start, end);
30762306a36Sopenharmony_ci		if (ret < 0) {
30862306a36Sopenharmony_ci			free(str);
30962306a36Sopenharmony_ci			return -1;
31062306a36Sopenharmony_ci		}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		pr_debug("start time %d: %" PRIu64 ", ", i, ptime_buf[i].start);
31362306a36Sopenharmony_ci		pr_debug("end time %d: %" PRIu64 "\n", i, ptime_buf[i].end);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		i++;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		if (p2)
31862306a36Sopenharmony_ci			p1 = p2 + 1;
31962306a36Sopenharmony_ci		else
32062306a36Sopenharmony_ci			break;
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	free(str);
32462306a36Sopenharmony_ci	return i;
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic int one_percent_convert(struct perf_time_interval *ptime_buf,
32862306a36Sopenharmony_ci			       const char *ostr, u64 start, u64 end, char *c)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	char *str;
33162306a36Sopenharmony_ci	int len = strlen(ostr), ret;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/*
33462306a36Sopenharmony_ci	 * c points to '%'.
33562306a36Sopenharmony_ci	 * '%' should be the last character
33662306a36Sopenharmony_ci	 */
33762306a36Sopenharmony_ci	if (ostr + len - 1 != c)
33862306a36Sopenharmony_ci		return -1;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/*
34162306a36Sopenharmony_ci	 * Construct a string like "xx%/1"
34262306a36Sopenharmony_ci	 */
34362306a36Sopenharmony_ci	str = malloc(len + 3);
34462306a36Sopenharmony_ci	if (str == NULL)
34562306a36Sopenharmony_ci		return -ENOMEM;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	memcpy(str, ostr, len);
34862306a36Sopenharmony_ci	strcpy(str + len, "/1");
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	ret = percent_slash_split(str, ptime_buf, start, end);
35162306a36Sopenharmony_ci	if (ret == 0)
35262306a36Sopenharmony_ci		ret = 1;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	free(str);
35562306a36Sopenharmony_ci	return ret;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ciint perf_time__percent_parse_str(struct perf_time_interval *ptime_buf, int num,
35962306a36Sopenharmony_ci				 const char *ostr, u64 start, u64 end)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	char *c;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	/*
36462306a36Sopenharmony_ci	 * ostr example:
36562306a36Sopenharmony_ci	 * 10%/2,10%/3: select the second 10% slice and the third 10% slice
36662306a36Sopenharmony_ci	 * 0%-10%,30%-40%: multiple time range
36762306a36Sopenharmony_ci	 * 50%: just one percent
36862306a36Sopenharmony_ci	 */
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	memset(ptime_buf, 0, sizeof(*ptime_buf) * num);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	c = strchr(ostr, '/');
37362306a36Sopenharmony_ci	if (c) {
37462306a36Sopenharmony_ci		return percent_comma_split(ptime_buf, num, ostr, start,
37562306a36Sopenharmony_ci					   end, percent_slash_split);
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	c = strchr(ostr, '-');
37962306a36Sopenharmony_ci	if (c) {
38062306a36Sopenharmony_ci		return percent_comma_split(ptime_buf, num, ostr, start,
38162306a36Sopenharmony_ci					   end, percent_dash_split);
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	c = strchr(ostr, '%');
38562306a36Sopenharmony_ci	if (c)
38662306a36Sopenharmony_ci		return one_percent_convert(ptime_buf, ostr, start, end, c);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	return -1;
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistruct perf_time_interval *perf_time__range_alloc(const char *ostr, int *size)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	const char *p1, *p2;
39462306a36Sopenharmony_ci	int i = 1;
39562306a36Sopenharmony_ci	struct perf_time_interval *ptime;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/*
39862306a36Sopenharmony_ci	 * At least allocate one time range.
39962306a36Sopenharmony_ci	 */
40062306a36Sopenharmony_ci	if (!ostr)
40162306a36Sopenharmony_ci		goto alloc;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	p1 = ostr;
40462306a36Sopenharmony_ci	while (p1 < ostr + strlen(ostr)) {
40562306a36Sopenharmony_ci		p2 = strchr(p1, ',');
40662306a36Sopenharmony_ci		if (!p2)
40762306a36Sopenharmony_ci			break;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci		p1 = p2 + 1;
41062306a36Sopenharmony_ci		i++;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cialloc:
41462306a36Sopenharmony_ci	*size = i;
41562306a36Sopenharmony_ci	ptime = calloc(i, sizeof(*ptime));
41662306a36Sopenharmony_ci	return ptime;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cibool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	/* if time is not set don't drop sample */
42262306a36Sopenharmony_ci	if (timestamp == 0)
42362306a36Sopenharmony_ci		return false;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	/* otherwise compare sample time to time window */
42662306a36Sopenharmony_ci	if ((ptime->start && timestamp < ptime->start) ||
42762306a36Sopenharmony_ci	    (ptime->end && timestamp > ptime->end)) {
42862306a36Sopenharmony_ci		return true;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	return false;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cibool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf,
43562306a36Sopenharmony_ci				   int num, u64 timestamp)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	struct perf_time_interval *ptime;
43862306a36Sopenharmony_ci	int i;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if ((!ptime_buf) || (timestamp == 0) || (num == 0))
44162306a36Sopenharmony_ci		return false;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (num == 1)
44462306a36Sopenharmony_ci		return perf_time__skip_sample(&ptime_buf[0], timestamp);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	/*
44762306a36Sopenharmony_ci	 * start/end of multiple time ranges must be valid.
44862306a36Sopenharmony_ci	 */
44962306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
45062306a36Sopenharmony_ci		ptime = &ptime_buf[i];
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci		if (timestamp >= ptime->start &&
45362306a36Sopenharmony_ci		    (timestamp <= ptime->end || !ptime->end)) {
45462306a36Sopenharmony_ci			return false;
45562306a36Sopenharmony_ci		}
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	return true;
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ciint perf_time__parse_for_ranges_reltime(const char *time_str,
46262306a36Sopenharmony_ci				struct perf_session *session,
46362306a36Sopenharmony_ci				struct perf_time_interval **ranges,
46462306a36Sopenharmony_ci				int *range_size, int *range_num,
46562306a36Sopenharmony_ci				bool reltime)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	bool has_percent = strchr(time_str, '%');
46862306a36Sopenharmony_ci	struct perf_time_interval *ptime_range;
46962306a36Sopenharmony_ci	int size, num, ret = -EINVAL;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	ptime_range = perf_time__range_alloc(time_str, &size);
47262306a36Sopenharmony_ci	if (!ptime_range)
47362306a36Sopenharmony_ci		return -ENOMEM;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	if (has_percent || reltime) {
47662306a36Sopenharmony_ci		if (session->evlist->first_sample_time == 0 &&
47762306a36Sopenharmony_ci		    session->evlist->last_sample_time == 0) {
47862306a36Sopenharmony_ci			pr_err("HINT: no first/last sample time found in perf data.\n"
47962306a36Sopenharmony_ci			       "Please use latest perf binary to execute 'perf record'\n"
48062306a36Sopenharmony_ci			       "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n");
48162306a36Sopenharmony_ci			goto error;
48262306a36Sopenharmony_ci		}
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (has_percent) {
48662306a36Sopenharmony_ci		num = perf_time__percent_parse_str(
48762306a36Sopenharmony_ci				ptime_range, size,
48862306a36Sopenharmony_ci				time_str,
48962306a36Sopenharmony_ci				session->evlist->first_sample_time,
49062306a36Sopenharmony_ci				session->evlist->last_sample_time);
49162306a36Sopenharmony_ci	} else {
49262306a36Sopenharmony_ci		num = perf_time__parse_strs(ptime_range, time_str, size);
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	if (num < 0)
49662306a36Sopenharmony_ci		goto error_invalid;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (reltime) {
49962306a36Sopenharmony_ci		int i;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci		for (i = 0; i < num; i++) {
50262306a36Sopenharmony_ci			ptime_range[i].start += session->evlist->first_sample_time;
50362306a36Sopenharmony_ci			ptime_range[i].end += session->evlist->first_sample_time;
50462306a36Sopenharmony_ci		}
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	*range_size = size;
50862306a36Sopenharmony_ci	*range_num = num;
50962306a36Sopenharmony_ci	*ranges = ptime_range;
51062306a36Sopenharmony_ci	return 0;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cierror_invalid:
51362306a36Sopenharmony_ci	pr_err("Invalid time string\n");
51462306a36Sopenharmony_cierror:
51562306a36Sopenharmony_ci	free(ptime_range);
51662306a36Sopenharmony_ci	return ret;
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ciint perf_time__parse_for_ranges(const char *time_str,
52062306a36Sopenharmony_ci				struct perf_session *session,
52162306a36Sopenharmony_ci				struct perf_time_interval **ranges,
52262306a36Sopenharmony_ci				int *range_size, int *range_num)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	return perf_time__parse_for_ranges_reltime(time_str, session, ranges,
52562306a36Sopenharmony_ci					range_size, range_num, false);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ciint timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	u64  sec = timestamp / NSEC_PER_SEC;
53162306a36Sopenharmony_ci	u64 usec = (timestamp % NSEC_PER_SEC) / NSEC_PER_USEC;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	return scnprintf(buf, sz, "%"PRIu64".%06"PRIu64, sec, usec);
53462306a36Sopenharmony_ci}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ciint timestamp__scnprintf_nsec(u64 timestamp, char *buf, size_t sz)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	u64 sec  = timestamp / NSEC_PER_SEC,
53962306a36Sopenharmony_ci	    nsec = timestamp % NSEC_PER_SEC;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	return scnprintf(buf, sz, "%" PRIu64 ".%09" PRIu64, sec, nsec);
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ciint fetch_current_timestamp(char *buf, size_t sz)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	struct timeval tv;
54762306a36Sopenharmony_ci	struct tm tm;
54862306a36Sopenharmony_ci	char dt[32];
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
55162306a36Sopenharmony_ci		return -1;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
55462306a36Sopenharmony_ci		return -1;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	scnprintf(buf, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	return 0;
55962306a36Sopenharmony_ci}
560