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