18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <stdlib.h>
38c2ecf20Sopenharmony_ci#include <string.h>
48c2ecf20Sopenharmony_ci#include <linux/string.h>
58c2ecf20Sopenharmony_ci#include <sys/time.h>
68c2ecf20Sopenharmony_ci#include <linux/time64.h>
78c2ecf20Sopenharmony_ci#include <time.h>
88c2ecf20Sopenharmony_ci#include <errno.h>
98c2ecf20Sopenharmony_ci#include <inttypes.h>
108c2ecf20Sopenharmony_ci#include <math.h>
118c2ecf20Sopenharmony_ci#include <linux/ctype.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include "debug.h"
148c2ecf20Sopenharmony_ci#include "time-utils.h"
158c2ecf20Sopenharmony_ci#include "session.h"
168c2ecf20Sopenharmony_ci#include "evlist.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ciint parse_nsec_time(const char *str, u64 *ptime)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	u64 time_sec, time_nsec;
218c2ecf20Sopenharmony_ci	char *end;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	time_sec = strtoul(str, &end, 10);
248c2ecf20Sopenharmony_ci	if (*end != '.' && *end != '\0')
258c2ecf20Sopenharmony_ci		return -1;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	if (*end == '.') {
288c2ecf20Sopenharmony_ci		int i;
298c2ecf20Sopenharmony_ci		char nsec_buf[10];
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci		if (strlen(++end) > 9)
328c2ecf20Sopenharmony_ci			return -1;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci		strncpy(nsec_buf, end, 9);
358c2ecf20Sopenharmony_ci		nsec_buf[9] = '\0';
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci		/* make it nsec precision */
388c2ecf20Sopenharmony_ci		for (i = strlen(nsec_buf); i < 9; i++)
398c2ecf20Sopenharmony_ci			nsec_buf[i] = '0';
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci		time_nsec = strtoul(nsec_buf, &end, 10);
428c2ecf20Sopenharmony_ci		if (*end != '\0')
438c2ecf20Sopenharmony_ci			return -1;
448c2ecf20Sopenharmony_ci	} else
458c2ecf20Sopenharmony_ci		time_nsec = 0;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	*ptime = time_sec * NSEC_PER_SEC + time_nsec;
488c2ecf20Sopenharmony_ci	return 0;
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic int parse_timestr_sec_nsec(struct perf_time_interval *ptime,
528c2ecf20Sopenharmony_ci				  char *start_str, char *end_str)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	if (start_str && (*start_str != '\0') &&
558c2ecf20Sopenharmony_ci	    (parse_nsec_time(start_str, &ptime->start) != 0)) {
568c2ecf20Sopenharmony_ci		return -1;
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	if (end_str && (*end_str != '\0') &&
608c2ecf20Sopenharmony_ci	    (parse_nsec_time(end_str, &ptime->end) != 0)) {
618c2ecf20Sopenharmony_ci		return -1;
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return 0;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int split_start_end(char **start, char **end, const char *ostr, char ch)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	char *start_str, *end_str;
708c2ecf20Sopenharmony_ci	char *d, *str;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (ostr == NULL || *ostr == '\0')
738c2ecf20Sopenharmony_ci		return 0;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/* copy original string because we need to modify it */
768c2ecf20Sopenharmony_ci	str = strdup(ostr);
778c2ecf20Sopenharmony_ci	if (str == NULL)
788c2ecf20Sopenharmony_ci		return -ENOMEM;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	start_str = str;
818c2ecf20Sopenharmony_ci	d = strchr(start_str, ch);
828c2ecf20Sopenharmony_ci	if (d) {
838c2ecf20Sopenharmony_ci		*d = '\0';
848c2ecf20Sopenharmony_ci		++d;
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci	end_str = d;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	*start = start_str;
898c2ecf20Sopenharmony_ci	*end = end_str;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	return 0;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ciint perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	char *start_str = NULL, *end_str;
978c2ecf20Sopenharmony_ci	int rc;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	rc = split_start_end(&start_str, &end_str, ostr, ',');
1008c2ecf20Sopenharmony_ci	if (rc || !start_str)
1018c2ecf20Sopenharmony_ci		return rc;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	ptime->start = 0;
1048c2ecf20Sopenharmony_ci	ptime->end = 0;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	rc = parse_timestr_sec_nsec(ptime, start_str, end_str);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	free(start_str);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	/* make sure end time is after start time if it was given */
1118c2ecf20Sopenharmony_ci	if (rc == 0 && ptime->end && ptime->end < ptime->start)
1128c2ecf20Sopenharmony_ci		return -EINVAL;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	pr_debug("start time %" PRIu64 ", ", ptime->start);
1158c2ecf20Sopenharmony_ci	pr_debug("end time %" PRIu64 "\n", ptime->end);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return rc;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int perf_time__parse_strs(struct perf_time_interval *ptime,
1218c2ecf20Sopenharmony_ci				 const char *ostr, int size)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	const char *cp;
1248c2ecf20Sopenharmony_ci	char *str, *arg, *p;
1258c2ecf20Sopenharmony_ci	int i, num = 0, rc = 0;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	/* Count the commas */
1288c2ecf20Sopenharmony_ci	for (cp = ostr; *cp; cp++)
1298c2ecf20Sopenharmony_ci		num += !!(*cp == ',');
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (!num)
1328c2ecf20Sopenharmony_ci		return -EINVAL;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	BUG_ON(num > size);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	str = strdup(ostr);
1378c2ecf20Sopenharmony_ci	if (!str)
1388c2ecf20Sopenharmony_ci		return -ENOMEM;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	/* Split the string and parse each piece, except the last */
1418c2ecf20Sopenharmony_ci	for (i = 0, p = str; i < num - 1; i++) {
1428c2ecf20Sopenharmony_ci		arg = p;
1438c2ecf20Sopenharmony_ci		/* Find next comma, there must be one */
1448c2ecf20Sopenharmony_ci		p = skip_spaces(strchr(p, ',') + 1);
1458c2ecf20Sopenharmony_ci		/* Skip the value, must not contain space or comma */
1468c2ecf20Sopenharmony_ci		while (*p && !isspace(*p)) {
1478c2ecf20Sopenharmony_ci			if (*p++ == ',') {
1488c2ecf20Sopenharmony_ci				rc = -EINVAL;
1498c2ecf20Sopenharmony_ci				goto out;
1508c2ecf20Sopenharmony_ci			}
1518c2ecf20Sopenharmony_ci		}
1528c2ecf20Sopenharmony_ci		/* Split and parse */
1538c2ecf20Sopenharmony_ci		if (*p)
1548c2ecf20Sopenharmony_ci			*p++ = 0;
1558c2ecf20Sopenharmony_ci		rc = perf_time__parse_str(ptime + i, arg);
1568c2ecf20Sopenharmony_ci		if (rc < 0)
1578c2ecf20Sopenharmony_ci			goto out;
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	/* Parse the last piece */
1618c2ecf20Sopenharmony_ci	rc = perf_time__parse_str(ptime + i, p);
1628c2ecf20Sopenharmony_ci	if (rc < 0)
1638c2ecf20Sopenharmony_ci		goto out;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/* Check there is no overlap */
1668c2ecf20Sopenharmony_ci	for (i = 0; i < num - 1; i++) {
1678c2ecf20Sopenharmony_ci		if (ptime[i].end >= ptime[i + 1].start) {
1688c2ecf20Sopenharmony_ci			rc = -EINVAL;
1698c2ecf20Sopenharmony_ci			goto out;
1708c2ecf20Sopenharmony_ci		}
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	rc = num;
1748c2ecf20Sopenharmony_ciout:
1758c2ecf20Sopenharmony_ci	free(str);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	return rc;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic int parse_percent(double *pcnt, char *str)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	char *c, *endptr;
1838c2ecf20Sopenharmony_ci	double d;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	c = strchr(str, '%');
1868c2ecf20Sopenharmony_ci	if (c)
1878c2ecf20Sopenharmony_ci		*c = '\0';
1888c2ecf20Sopenharmony_ci	else
1898c2ecf20Sopenharmony_ci		return -1;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	d = strtod(str, &endptr);
1928c2ecf20Sopenharmony_ci	if (endptr != str + strlen(str))
1938c2ecf20Sopenharmony_ci		return -1;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	*pcnt = d / 100.0;
1968c2ecf20Sopenharmony_ci	return 0;
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic int set_percent_time(struct perf_time_interval *ptime, double start_pcnt,
2008c2ecf20Sopenharmony_ci			    double end_pcnt, u64 start, u64 end)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	u64 total = end - start;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	if (start_pcnt < 0.0 || start_pcnt > 1.0 ||
2058c2ecf20Sopenharmony_ci	    end_pcnt < 0.0 || end_pcnt > 1.0) {
2068c2ecf20Sopenharmony_ci		return -1;
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	ptime->start = start + round(start_pcnt * total);
2108c2ecf20Sopenharmony_ci	ptime->end = start + round(end_pcnt * total);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if (ptime->end > ptime->start && ptime->end != end)
2138c2ecf20Sopenharmony_ci		ptime->end -= 1;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	return 0;
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic int percent_slash_split(char *str, struct perf_time_interval *ptime,
2198c2ecf20Sopenharmony_ci			       u64 start, u64 end)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	char *p, *end_str;
2228c2ecf20Sopenharmony_ci	double pcnt, start_pcnt, end_pcnt;
2238c2ecf20Sopenharmony_ci	int i;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	/*
2268c2ecf20Sopenharmony_ci	 * Example:
2278c2ecf20Sopenharmony_ci	 * 10%/2: select the second 10% slice and the third 10% slice
2288c2ecf20Sopenharmony_ci	 */
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	/* We can modify this string since the original one is copied */
2318c2ecf20Sopenharmony_ci	p = strchr(str, '/');
2328c2ecf20Sopenharmony_ci	if (!p)
2338c2ecf20Sopenharmony_ci		return -1;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	*p = '\0';
2368c2ecf20Sopenharmony_ci	if (parse_percent(&pcnt, str) < 0)
2378c2ecf20Sopenharmony_ci		return -1;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	p++;
2408c2ecf20Sopenharmony_ci	i = (int)strtol(p, &end_str, 10);
2418c2ecf20Sopenharmony_ci	if (*end_str)
2428c2ecf20Sopenharmony_ci		return -1;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (pcnt <= 0.0)
2458c2ecf20Sopenharmony_ci		return -1;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	start_pcnt = pcnt * (i - 1);
2488c2ecf20Sopenharmony_ci	end_pcnt = pcnt * i;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	return set_percent_time(ptime, start_pcnt, end_pcnt, start, end);
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic int percent_dash_split(char *str, struct perf_time_interval *ptime,
2548c2ecf20Sopenharmony_ci			      u64 start, u64 end)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	char *start_str = NULL, *end_str;
2578c2ecf20Sopenharmony_ci	double start_pcnt, end_pcnt;
2588c2ecf20Sopenharmony_ci	int ret;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	/*
2618c2ecf20Sopenharmony_ci	 * Example: 0%-10%
2628c2ecf20Sopenharmony_ci	 */
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	ret = split_start_end(&start_str, &end_str, str, '-');
2658c2ecf20Sopenharmony_ci	if (ret || !start_str)
2668c2ecf20Sopenharmony_ci		return ret;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if ((parse_percent(&start_pcnt, start_str) != 0) ||
2698c2ecf20Sopenharmony_ci	    (parse_percent(&end_pcnt, end_str) != 0)) {
2708c2ecf20Sopenharmony_ci		free(start_str);
2718c2ecf20Sopenharmony_ci		return -1;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	free(start_str);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	return set_percent_time(ptime, start_pcnt, end_pcnt, start, end);
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_citypedef int (*time_pecent_split)(char *, struct perf_time_interval *,
2808c2ecf20Sopenharmony_ci				 u64 start, u64 end);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic int percent_comma_split(struct perf_time_interval *ptime_buf, int num,
2838c2ecf20Sopenharmony_ci			       const char *ostr, u64 start, u64 end,
2848c2ecf20Sopenharmony_ci			       time_pecent_split func)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	char *str, *p1, *p2;
2878c2ecf20Sopenharmony_ci	int len, ret, i = 0;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	str = strdup(ostr);
2908c2ecf20Sopenharmony_ci	if (str == NULL)
2918c2ecf20Sopenharmony_ci		return -ENOMEM;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	len = strlen(str);
2948c2ecf20Sopenharmony_ci	p1 = str;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	while (p1 < str + len) {
2978c2ecf20Sopenharmony_ci		if (i >= num) {
2988c2ecf20Sopenharmony_ci			free(str);
2998c2ecf20Sopenharmony_ci			return -1;
3008c2ecf20Sopenharmony_ci		}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci		p2 = strchr(p1, ',');
3038c2ecf20Sopenharmony_ci		if (p2)
3048c2ecf20Sopenharmony_ci			*p2 = '\0';
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci		ret = (func)(p1, &ptime_buf[i], start, end);
3078c2ecf20Sopenharmony_ci		if (ret < 0) {
3088c2ecf20Sopenharmony_ci			free(str);
3098c2ecf20Sopenharmony_ci			return -1;
3108c2ecf20Sopenharmony_ci		}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci		pr_debug("start time %d: %" PRIu64 ", ", i, ptime_buf[i].start);
3138c2ecf20Sopenharmony_ci		pr_debug("end time %d: %" PRIu64 "\n", i, ptime_buf[i].end);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci		i++;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		if (p2)
3188c2ecf20Sopenharmony_ci			p1 = p2 + 1;
3198c2ecf20Sopenharmony_ci		else
3208c2ecf20Sopenharmony_ci			break;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	free(str);
3248c2ecf20Sopenharmony_ci	return i;
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic int one_percent_convert(struct perf_time_interval *ptime_buf,
3288c2ecf20Sopenharmony_ci			       const char *ostr, u64 start, u64 end, char *c)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	char *str;
3318c2ecf20Sopenharmony_ci	int len = strlen(ostr), ret;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	/*
3348c2ecf20Sopenharmony_ci	 * c points to '%'.
3358c2ecf20Sopenharmony_ci	 * '%' should be the last character
3368c2ecf20Sopenharmony_ci	 */
3378c2ecf20Sopenharmony_ci	if (ostr + len - 1 != c)
3388c2ecf20Sopenharmony_ci		return -1;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	/*
3418c2ecf20Sopenharmony_ci	 * Construct a string like "xx%/1"
3428c2ecf20Sopenharmony_ci	 */
3438c2ecf20Sopenharmony_ci	str = malloc(len + 3);
3448c2ecf20Sopenharmony_ci	if (str == NULL)
3458c2ecf20Sopenharmony_ci		return -ENOMEM;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	memcpy(str, ostr, len);
3488c2ecf20Sopenharmony_ci	strcpy(str + len, "/1");
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	ret = percent_slash_split(str, ptime_buf, start, end);
3518c2ecf20Sopenharmony_ci	if (ret == 0)
3528c2ecf20Sopenharmony_ci		ret = 1;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	free(str);
3558c2ecf20Sopenharmony_ci	return ret;
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ciint perf_time__percent_parse_str(struct perf_time_interval *ptime_buf, int num,
3598c2ecf20Sopenharmony_ci				 const char *ostr, u64 start, u64 end)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	char *c;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/*
3648c2ecf20Sopenharmony_ci	 * ostr example:
3658c2ecf20Sopenharmony_ci	 * 10%/2,10%/3: select the second 10% slice and the third 10% slice
3668c2ecf20Sopenharmony_ci	 * 0%-10%,30%-40%: multiple time range
3678c2ecf20Sopenharmony_ci	 * 50%: just one percent
3688c2ecf20Sopenharmony_ci	 */
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	memset(ptime_buf, 0, sizeof(*ptime_buf) * num);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	c = strchr(ostr, '/');
3738c2ecf20Sopenharmony_ci	if (c) {
3748c2ecf20Sopenharmony_ci		return percent_comma_split(ptime_buf, num, ostr, start,
3758c2ecf20Sopenharmony_ci					   end, percent_slash_split);
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	c = strchr(ostr, '-');
3798c2ecf20Sopenharmony_ci	if (c) {
3808c2ecf20Sopenharmony_ci		return percent_comma_split(ptime_buf, num, ostr, start,
3818c2ecf20Sopenharmony_ci					   end, percent_dash_split);
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	c = strchr(ostr, '%');
3858c2ecf20Sopenharmony_ci	if (c)
3868c2ecf20Sopenharmony_ci		return one_percent_convert(ptime_buf, ostr, start, end, c);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	return -1;
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistruct perf_time_interval *perf_time__range_alloc(const char *ostr, int *size)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	const char *p1, *p2;
3948c2ecf20Sopenharmony_ci	int i = 1;
3958c2ecf20Sopenharmony_ci	struct perf_time_interval *ptime;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	/*
3988c2ecf20Sopenharmony_ci	 * At least allocate one time range.
3998c2ecf20Sopenharmony_ci	 */
4008c2ecf20Sopenharmony_ci	if (!ostr)
4018c2ecf20Sopenharmony_ci		goto alloc;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	p1 = ostr;
4048c2ecf20Sopenharmony_ci	while (p1 < ostr + strlen(ostr)) {
4058c2ecf20Sopenharmony_ci		p2 = strchr(p1, ',');
4068c2ecf20Sopenharmony_ci		if (!p2)
4078c2ecf20Sopenharmony_ci			break;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci		p1 = p2 + 1;
4108c2ecf20Sopenharmony_ci		i++;
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cialloc:
4148c2ecf20Sopenharmony_ci	*size = i;
4158c2ecf20Sopenharmony_ci	ptime = calloc(i, sizeof(*ptime));
4168c2ecf20Sopenharmony_ci	return ptime;
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cibool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	/* if time is not set don't drop sample */
4228c2ecf20Sopenharmony_ci	if (timestamp == 0)
4238c2ecf20Sopenharmony_ci		return false;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	/* otherwise compare sample time to time window */
4268c2ecf20Sopenharmony_ci	if ((ptime->start && timestamp < ptime->start) ||
4278c2ecf20Sopenharmony_ci	    (ptime->end && timestamp > ptime->end)) {
4288c2ecf20Sopenharmony_ci		return true;
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	return false;
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_cibool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf,
4358c2ecf20Sopenharmony_ci				   int num, u64 timestamp)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	struct perf_time_interval *ptime;
4388c2ecf20Sopenharmony_ci	int i;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	if ((!ptime_buf) || (timestamp == 0) || (num == 0))
4418c2ecf20Sopenharmony_ci		return false;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	if (num == 1)
4448c2ecf20Sopenharmony_ci		return perf_time__skip_sample(&ptime_buf[0], timestamp);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	/*
4478c2ecf20Sopenharmony_ci	 * start/end of multiple time ranges must be valid.
4488c2ecf20Sopenharmony_ci	 */
4498c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
4508c2ecf20Sopenharmony_ci		ptime = &ptime_buf[i];
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci		if (timestamp >= ptime->start &&
4538c2ecf20Sopenharmony_ci		    (timestamp <= ptime->end || !ptime->end)) {
4548c2ecf20Sopenharmony_ci			return false;
4558c2ecf20Sopenharmony_ci		}
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	return true;
4598c2ecf20Sopenharmony_ci}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ciint perf_time__parse_for_ranges_reltime(const char *time_str,
4628c2ecf20Sopenharmony_ci				struct perf_session *session,
4638c2ecf20Sopenharmony_ci				struct perf_time_interval **ranges,
4648c2ecf20Sopenharmony_ci				int *range_size, int *range_num,
4658c2ecf20Sopenharmony_ci				bool reltime)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	bool has_percent = strchr(time_str, '%');
4688c2ecf20Sopenharmony_ci	struct perf_time_interval *ptime_range;
4698c2ecf20Sopenharmony_ci	int size, num, ret = -EINVAL;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	ptime_range = perf_time__range_alloc(time_str, &size);
4728c2ecf20Sopenharmony_ci	if (!ptime_range)
4738c2ecf20Sopenharmony_ci		return -ENOMEM;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	if (has_percent || reltime) {
4768c2ecf20Sopenharmony_ci		if (session->evlist->first_sample_time == 0 &&
4778c2ecf20Sopenharmony_ci		    session->evlist->last_sample_time == 0) {
4788c2ecf20Sopenharmony_ci			pr_err("HINT: no first/last sample time found in perf data.\n"
4798c2ecf20Sopenharmony_ci			       "Please use latest perf binary to execute 'perf record'\n"
4808c2ecf20Sopenharmony_ci			       "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n");
4818c2ecf20Sopenharmony_ci			goto error;
4828c2ecf20Sopenharmony_ci		}
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	if (has_percent) {
4868c2ecf20Sopenharmony_ci		num = perf_time__percent_parse_str(
4878c2ecf20Sopenharmony_ci				ptime_range, size,
4888c2ecf20Sopenharmony_ci				time_str,
4898c2ecf20Sopenharmony_ci				session->evlist->first_sample_time,
4908c2ecf20Sopenharmony_ci				session->evlist->last_sample_time);
4918c2ecf20Sopenharmony_ci	} else {
4928c2ecf20Sopenharmony_ci		num = perf_time__parse_strs(ptime_range, time_str, size);
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	if (num < 0)
4968c2ecf20Sopenharmony_ci		goto error_invalid;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	if (reltime) {
4998c2ecf20Sopenharmony_ci		int i;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci		for (i = 0; i < num; i++) {
5028c2ecf20Sopenharmony_ci			ptime_range[i].start += session->evlist->first_sample_time;
5038c2ecf20Sopenharmony_ci			ptime_range[i].end += session->evlist->first_sample_time;
5048c2ecf20Sopenharmony_ci		}
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	*range_size = size;
5088c2ecf20Sopenharmony_ci	*range_num = num;
5098c2ecf20Sopenharmony_ci	*ranges = ptime_range;
5108c2ecf20Sopenharmony_ci	return 0;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_cierror_invalid:
5138c2ecf20Sopenharmony_ci	pr_err("Invalid time string\n");
5148c2ecf20Sopenharmony_cierror:
5158c2ecf20Sopenharmony_ci	free(ptime_range);
5168c2ecf20Sopenharmony_ci	return ret;
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ciint perf_time__parse_for_ranges(const char *time_str,
5208c2ecf20Sopenharmony_ci				struct perf_session *session,
5218c2ecf20Sopenharmony_ci				struct perf_time_interval **ranges,
5228c2ecf20Sopenharmony_ci				int *range_size, int *range_num)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	return perf_time__parse_for_ranges_reltime(time_str, session, ranges,
5258c2ecf20Sopenharmony_ci					range_size, range_num, false);
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ciint timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	u64  sec = timestamp / NSEC_PER_SEC;
5318c2ecf20Sopenharmony_ci	u64 usec = (timestamp % NSEC_PER_SEC) / NSEC_PER_USEC;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	return scnprintf(buf, sz, "%"PRIu64".%06"PRIu64, sec, usec);
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ciint timestamp__scnprintf_nsec(u64 timestamp, char *buf, size_t sz)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	u64 sec  = timestamp / NSEC_PER_SEC,
5398c2ecf20Sopenharmony_ci	    nsec = timestamp % NSEC_PER_SEC;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	return scnprintf(buf, sz, "%" PRIu64 ".%09" PRIu64, sec, nsec);
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ciint fetch_current_timestamp(char *buf, size_t sz)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct timeval tv;
5478c2ecf20Sopenharmony_ci	struct tm tm;
5488c2ecf20Sopenharmony_ci	char dt[32];
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
5518c2ecf20Sopenharmony_ci		return -1;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
5548c2ecf20Sopenharmony_ci		return -1;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	scnprintf(buf, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	return 0;
5598c2ecf20Sopenharmony_ci}
560