diff options
Diffstat (limited to 'tools/perf/util/time-utils.c')
-rw-r--r-- | tools/perf/util/time-utils.c | 301 |
1 files changed, 289 insertions, 12 deletions
diff --git a/tools/perf/util/time-utils.c b/tools/perf/util/time-utils.c index 81927d027417..6193b46050a5 100644 --- a/tools/perf/util/time-utils.c +++ b/tools/perf/util/time-utils.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <time.h> | 6 | #include <time.h> |
7 | #include <errno.h> | 7 | #include <errno.h> |
8 | #include <inttypes.h> | 8 | #include <inttypes.h> |
9 | #include <math.h> | ||
9 | 10 | ||
10 | #include "perf.h" | 11 | #include "perf.h" |
11 | #include "debug.h" | 12 | #include "debug.h" |
@@ -60,11 +61,10 @@ static int parse_timestr_sec_nsec(struct perf_time_interval *ptime, | |||
60 | return 0; | 61 | return 0; |
61 | } | 62 | } |
62 | 63 | ||
63 | int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr) | 64 | static int split_start_end(char **start, char **end, const char *ostr, char ch) |
64 | { | 65 | { |
65 | char *start_str, *end_str; | 66 | char *start_str, *end_str; |
66 | char *d, *str; | 67 | char *d, *str; |
67 | int rc = 0; | ||
68 | 68 | ||
69 | if (ostr == NULL || *ostr == '\0') | 69 | if (ostr == NULL || *ostr == '\0') |
70 | return 0; | 70 | return 0; |
@@ -74,25 +74,35 @@ int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr) | |||
74 | if (str == NULL) | 74 | if (str == NULL) |
75 | return -ENOMEM; | 75 | return -ENOMEM; |
76 | 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; | 77 | start_str = str; |
86 | d = strchr(start_str, ','); | 78 | d = strchr(start_str, ch); |
87 | if (d) { | 79 | if (d) { |
88 | *d = '\0'; | 80 | *d = '\0'; |
89 | ++d; | 81 | ++d; |
90 | } | 82 | } |
91 | end_str = d; | 83 | end_str = d; |
92 | 84 | ||
85 | *start = start_str; | ||
86 | *end = end_str; | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr) | ||
92 | { | ||
93 | char *start_str = NULL, *end_str; | ||
94 | int rc; | ||
95 | |||
96 | rc = split_start_end(&start_str, &end_str, ostr, ','); | ||
97 | if (rc || !start_str) | ||
98 | return rc; | ||
99 | |||
100 | ptime->start = 0; | ||
101 | ptime->end = 0; | ||
102 | |||
93 | rc = parse_timestr_sec_nsec(ptime, start_str, end_str); | 103 | rc = parse_timestr_sec_nsec(ptime, start_str, end_str); |
94 | 104 | ||
95 | free(str); | 105 | free(start_str); |
96 | 106 | ||
97 | /* make sure end time is after start time if it was given */ | 107 | /* make sure end time is after start time if it was given */ |
98 | if (rc == 0 && ptime->end && ptime->end < ptime->start) | 108 | if (rc == 0 && ptime->end && ptime->end < ptime->start) |
@@ -104,6 +114,245 @@ int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr) | |||
104 | return rc; | 114 | return rc; |
105 | } | 115 | } |
106 | 116 | ||
117 | static int parse_percent(double *pcnt, char *str) | ||
118 | { | ||
119 | char *c, *endptr; | ||
120 | double d; | ||
121 | |||
122 | c = strchr(str, '%'); | ||
123 | if (c) | ||
124 | *c = '\0'; | ||
125 | else | ||
126 | return -1; | ||
127 | |||
128 | d = strtod(str, &endptr); | ||
129 | if (endptr != str + strlen(str)) | ||
130 | return -1; | ||
131 | |||
132 | *pcnt = d / 100.0; | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int percent_slash_split(char *str, struct perf_time_interval *ptime, | ||
137 | u64 start, u64 end) | ||
138 | { | ||
139 | char *p, *end_str; | ||
140 | double pcnt, start_pcnt, end_pcnt; | ||
141 | u64 total = end - start; | ||
142 | int i; | ||
143 | |||
144 | /* | ||
145 | * Example: | ||
146 | * 10%/2: select the second 10% slice and the third 10% slice | ||
147 | */ | ||
148 | |||
149 | /* We can modify this string since the original one is copied */ | ||
150 | p = strchr(str, '/'); | ||
151 | if (!p) | ||
152 | return -1; | ||
153 | |||
154 | *p = '\0'; | ||
155 | if (parse_percent(&pcnt, str) < 0) | ||
156 | return -1; | ||
157 | |||
158 | p++; | ||
159 | i = (int)strtol(p, &end_str, 10); | ||
160 | if (*end_str) | ||
161 | return -1; | ||
162 | |||
163 | if (pcnt <= 0.0) | ||
164 | return -1; | ||
165 | |||
166 | start_pcnt = pcnt * (i - 1); | ||
167 | end_pcnt = pcnt * i; | ||
168 | |||
169 | if (start_pcnt < 0.0 || start_pcnt > 1.0 || | ||
170 | end_pcnt < 0.0 || end_pcnt > 1.0) { | ||
171 | return -1; | ||
172 | } | ||
173 | |||
174 | ptime->start = start + round(start_pcnt * total); | ||
175 | ptime->end = start + round(end_pcnt * total); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static int percent_dash_split(char *str, struct perf_time_interval *ptime, | ||
181 | u64 start, u64 end) | ||
182 | { | ||
183 | char *start_str = NULL, *end_str; | ||
184 | double start_pcnt, end_pcnt; | ||
185 | u64 total = end - start; | ||
186 | int ret; | ||
187 | |||
188 | /* | ||
189 | * Example: 0%-10% | ||
190 | */ | ||
191 | |||
192 | ret = split_start_end(&start_str, &end_str, str, '-'); | ||
193 | if (ret || !start_str) | ||
194 | return ret; | ||
195 | |||
196 | if ((parse_percent(&start_pcnt, start_str) != 0) || | ||
197 | (parse_percent(&end_pcnt, end_str) != 0)) { | ||
198 | free(start_str); | ||
199 | return -1; | ||
200 | } | ||
201 | |||
202 | free(start_str); | ||
203 | |||
204 | if (start_pcnt < 0.0 || start_pcnt > 1.0 || | ||
205 | end_pcnt < 0.0 || end_pcnt > 1.0 || | ||
206 | start_pcnt > end_pcnt) { | ||
207 | return -1; | ||
208 | } | ||
209 | |||
210 | ptime->start = start + round(start_pcnt * total); | ||
211 | ptime->end = start + round(end_pcnt * total); | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | typedef int (*time_pecent_split)(char *, struct perf_time_interval *, | ||
217 | u64 start, u64 end); | ||
218 | |||
219 | static int percent_comma_split(struct perf_time_interval *ptime_buf, int num, | ||
220 | const char *ostr, u64 start, u64 end, | ||
221 | time_pecent_split func) | ||
222 | { | ||
223 | char *str, *p1, *p2; | ||
224 | int len, ret, i = 0; | ||
225 | |||
226 | str = strdup(ostr); | ||
227 | if (str == NULL) | ||
228 | return -ENOMEM; | ||
229 | |||
230 | len = strlen(str); | ||
231 | p1 = str; | ||
232 | |||
233 | while (p1 < str + len) { | ||
234 | if (i >= num) { | ||
235 | free(str); | ||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | p2 = strchr(p1, ','); | ||
240 | if (p2) | ||
241 | *p2 = '\0'; | ||
242 | |||
243 | ret = (func)(p1, &ptime_buf[i], start, end); | ||
244 | if (ret < 0) { | ||
245 | free(str); | ||
246 | return -1; | ||
247 | } | ||
248 | |||
249 | pr_debug("start time %d: %" PRIu64 ", ", i, ptime_buf[i].start); | ||
250 | pr_debug("end time %d: %" PRIu64 "\n", i, ptime_buf[i].end); | ||
251 | |||
252 | i++; | ||
253 | |||
254 | if (p2) | ||
255 | p1 = p2 + 1; | ||
256 | else | ||
257 | break; | ||
258 | } | ||
259 | |||
260 | free(str); | ||
261 | return i; | ||
262 | } | ||
263 | |||
264 | static int one_percent_convert(struct perf_time_interval *ptime_buf, | ||
265 | const char *ostr, u64 start, u64 end, char *c) | ||
266 | { | ||
267 | char *str; | ||
268 | int len = strlen(ostr), ret; | ||
269 | |||
270 | /* | ||
271 | * c points to '%'. | ||
272 | * '%' should be the last character | ||
273 | */ | ||
274 | if (ostr + len - 1 != c) | ||
275 | return -1; | ||
276 | |||
277 | /* | ||
278 | * Construct a string like "xx%/1" | ||
279 | */ | ||
280 | str = malloc(len + 3); | ||
281 | if (str == NULL) | ||
282 | return -ENOMEM; | ||
283 | |||
284 | memcpy(str, ostr, len); | ||
285 | strcpy(str + len, "/1"); | ||
286 | |||
287 | ret = percent_slash_split(str, ptime_buf, start, end); | ||
288 | if (ret == 0) | ||
289 | ret = 1; | ||
290 | |||
291 | free(str); | ||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | int perf_time__percent_parse_str(struct perf_time_interval *ptime_buf, int num, | ||
296 | const char *ostr, u64 start, u64 end) | ||
297 | { | ||
298 | char *c; | ||
299 | |||
300 | /* | ||
301 | * ostr example: | ||
302 | * 10%/2,10%/3: select the second 10% slice and the third 10% slice | ||
303 | * 0%-10%,30%-40%: multiple time range | ||
304 | * 50%: just one percent | ||
305 | */ | ||
306 | |||
307 | memset(ptime_buf, 0, sizeof(*ptime_buf) * num); | ||
308 | |||
309 | c = strchr(ostr, '/'); | ||
310 | if (c) { | ||
311 | return percent_comma_split(ptime_buf, num, ostr, start, | ||
312 | end, percent_slash_split); | ||
313 | } | ||
314 | |||
315 | c = strchr(ostr, '-'); | ||
316 | if (c) { | ||
317 | return percent_comma_split(ptime_buf, num, ostr, start, | ||
318 | end, percent_dash_split); | ||
319 | } | ||
320 | |||
321 | c = strchr(ostr, '%'); | ||
322 | if (c) | ||
323 | return one_percent_convert(ptime_buf, ostr, start, end, c); | ||
324 | |||
325 | return -1; | ||
326 | } | ||
327 | |||
328 | struct perf_time_interval *perf_time__range_alloc(const char *ostr, int *size) | ||
329 | { | ||
330 | const char *p1, *p2; | ||
331 | int i = 1; | ||
332 | struct perf_time_interval *ptime; | ||
333 | |||
334 | /* | ||
335 | * At least allocate one time range. | ||
336 | */ | ||
337 | if (!ostr) | ||
338 | goto alloc; | ||
339 | |||
340 | p1 = ostr; | ||
341 | while (p1 < ostr + strlen(ostr)) { | ||
342 | p2 = strchr(p1, ','); | ||
343 | if (!p2) | ||
344 | break; | ||
345 | |||
346 | p1 = p2 + 1; | ||
347 | i++; | ||
348 | } | ||
349 | |||
350 | alloc: | ||
351 | *size = i; | ||
352 | ptime = calloc(i, sizeof(*ptime)); | ||
353 | return ptime; | ||
354 | } | ||
355 | |||
107 | bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp) | 356 | bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp) |
108 | { | 357 | { |
109 | /* if time is not set don't drop sample */ | 358 | /* if time is not set don't drop sample */ |
@@ -119,6 +368,34 @@ bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp) | |||
119 | return false; | 368 | return false; |
120 | } | 369 | } |
121 | 370 | ||
371 | bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf, | ||
372 | int num, u64 timestamp) | ||
373 | { | ||
374 | struct perf_time_interval *ptime; | ||
375 | int i; | ||
376 | |||
377 | if ((timestamp == 0) || (num == 0)) | ||
378 | return false; | ||
379 | |||
380 | if (num == 1) | ||
381 | return perf_time__skip_sample(&ptime_buf[0], timestamp); | ||
382 | |||
383 | /* | ||
384 | * start/end of multiple time ranges must be valid. | ||
385 | */ | ||
386 | for (i = 0; i < num; i++) { | ||
387 | ptime = &ptime_buf[i]; | ||
388 | |||
389 | if (timestamp >= ptime->start && | ||
390 | ((timestamp < ptime->end && i < num - 1) || | ||
391 | (timestamp <= ptime->end && i == num - 1))) { | ||
392 | break; | ||
393 | } | ||
394 | } | ||
395 | |||
396 | return (i == num) ? true : false; | ||
397 | } | ||
398 | |||
122 | int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz) | 399 | int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz) |
123 | { | 400 | { |
124 | u64 sec = timestamp / NSEC_PER_SEC; | 401 | u64 sec = timestamp / NSEC_PER_SEC; |