1 // SPDX-License-Identifier: GPL-2.0 2 #include <stdlib.h> 3 #include <string.h> 4 #include <sys/time.h> 5 #include <linux/time64.h> 6 #include <time.h> 7 #include <errno.h> 8 #include <inttypes.h> 9 10 #include "perf.h" 11 #include "debug.h" 12 #include "time-utils.h" 13 14 int parse_nsec_time(const char *str, u64 *ptime) 15 { 16 u64 time_sec, time_nsec; 17 char *end; 18 19 time_sec = strtoul(str, &end, 10); 20 if (*end != '.' && *end != '\0') 21 return -1; 22 23 if (*end == '.') { 24 int i; 25 char nsec_buf[10]; 26 27 if (strlen(++end) > 9) 28 return -1; 29 30 strncpy(nsec_buf, end, 9); 31 nsec_buf[9] = '\0'; 32 33 /* make it nsec precision */ 34 for (i = strlen(nsec_buf); i < 9; i++) 35 nsec_buf[i] = '0'; 36 37 time_nsec = strtoul(nsec_buf, &end, 10); 38 if (*end != '\0') 39 return -1; 40 } else 41 time_nsec = 0; 42 43 *ptime = time_sec * NSEC_PER_SEC + time_nsec; 44 return 0; 45 } 46 47 static int parse_timestr_sec_nsec(struct perf_time_interval *ptime, 48 char *start_str, char *end_str) 49 { 50 if (start_str && (*start_str != '\0') && 51 (parse_nsec_time(start_str, &ptime->start) != 0)) { 52 return -1; 53 } 54 55 if (end_str && (*end_str != '\0') && 56 (parse_nsec_time(end_str, &ptime->end) != 0)) { 57 return -1; 58 } 59 60 return 0; 61 } 62 63 int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr) 64 { 65 char *start_str, *end_str; 66 char *d, *str; 67 int rc = 0; 68 69 if (ostr == NULL || *ostr == '\0') 70 return 0; 71 72 /* copy original string because we need to modify it */ 73 str = strdup(ostr); 74 if (str == NULL) 75 return -ENOMEM; 76 77 ptime->start = 0; 78 ptime->end = 0; 79 80 /* str has the format: <start>,<stop> 81 * variations: <start>, 82 * ,<stop> 83 * , 84 */ 85 start_str = str; 86 d = strchr(start_str, ','); 87 if (d) { 88 *d = '\0'; 89 ++d; 90 } 91 end_str = d; 92 93 rc = parse_timestr_sec_nsec(ptime, start_str, end_str); 94 95 free(str); 96 97 /* make sure end time is after start time if it was given */ 98 if (rc == 0 && ptime->end && ptime->end < ptime->start) 99 return -EINVAL; 100 101 pr_debug("start time %" PRIu64 ", ", ptime->start); 102 pr_debug("end time %" PRIu64 "\n", ptime->end); 103 104 return rc; 105 } 106 107 bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp) 108 { 109 /* if time is not set don't drop sample */ 110 if (timestamp == 0) 111 return false; 112 113 /* otherwise compare sample time to time window */ 114 if ((ptime->start && timestamp < ptime->start) || 115 (ptime->end && timestamp > ptime->end)) { 116 return true; 117 } 118 119 return false; 120 } 121 122 int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz) 123 { 124 u64 sec = timestamp / NSEC_PER_SEC; 125 u64 usec = (timestamp % NSEC_PER_SEC) / NSEC_PER_USEC; 126 127 return scnprintf(buf, sz, "%"PRIu64".%06"PRIu64, sec, usec); 128 } 129 130 int fetch_current_timestamp(char *buf, size_t sz) 131 { 132 struct timeval tv; 133 struct tm tm; 134 char dt[32]; 135 136 if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm)) 137 return -1; 138 139 if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm)) 140 return -1; 141 142 scnprintf(buf, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000); 143 144 return 0; 145 } 146