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