hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/tools/perf/util/time-utils.c
....@@ -1,16 +1,19 @@
11 // SPDX-License-Identifier: GPL-2.0
22 #include <stdlib.h>
33 #include <string.h>
4
+#include <linux/string.h>
45 #include <sys/time.h>
56 #include <linux/time64.h>
67 #include <time.h>
78 #include <errno.h>
89 #include <inttypes.h>
910 #include <math.h>
11
+#include <linux/ctype.h>
1012
11
-#include "perf.h"
1213 #include "debug.h"
1314 #include "time-utils.h"
15
+#include "session.h"
16
+#include "evlist.h"
1417
1518 int parse_nsec_time(const char *str, u64 *ptime)
1619 {
....@@ -114,6 +117,66 @@
114117 return rc;
115118 }
116119
120
+static int perf_time__parse_strs(struct perf_time_interval *ptime,
121
+ const char *ostr, int size)
122
+{
123
+ const char *cp;
124
+ char *str, *arg, *p;
125
+ int i, num = 0, rc = 0;
126
+
127
+ /* Count the commas */
128
+ for (cp = ostr; *cp; cp++)
129
+ num += !!(*cp == ',');
130
+
131
+ if (!num)
132
+ return -EINVAL;
133
+
134
+ BUG_ON(num > size);
135
+
136
+ str = strdup(ostr);
137
+ if (!str)
138
+ return -ENOMEM;
139
+
140
+ /* Split the string and parse each piece, except the last */
141
+ for (i = 0, p = str; i < num - 1; i++) {
142
+ arg = p;
143
+ /* Find next comma, there must be one */
144
+ p = skip_spaces(strchr(p, ',') + 1);
145
+ /* Skip the value, must not contain space or comma */
146
+ while (*p && !isspace(*p)) {
147
+ if (*p++ == ',') {
148
+ rc = -EINVAL;
149
+ goto out;
150
+ }
151
+ }
152
+ /* Split and parse */
153
+ if (*p)
154
+ *p++ = 0;
155
+ rc = perf_time__parse_str(ptime + i, arg);
156
+ if (rc < 0)
157
+ goto out;
158
+ }
159
+
160
+ /* Parse the last piece */
161
+ rc = perf_time__parse_str(ptime + i, p);
162
+ if (rc < 0)
163
+ goto out;
164
+
165
+ /* Check there is no overlap */
166
+ for (i = 0; i < num - 1; i++) {
167
+ if (ptime[i].end >= ptime[i + 1].start) {
168
+ rc = -EINVAL;
169
+ goto out;
170
+ }
171
+ }
172
+
173
+ rc = num;
174
+out:
175
+ free(str);
176
+
177
+ return rc;
178
+}
179
+
117180 static int parse_percent(double *pcnt, char *str)
118181 {
119182 char *c, *endptr;
....@@ -133,12 +196,30 @@
133196 return 0;
134197 }
135198
199
+static int set_percent_time(struct perf_time_interval *ptime, double start_pcnt,
200
+ double end_pcnt, u64 start, u64 end)
201
+{
202
+ u64 total = end - start;
203
+
204
+ if (start_pcnt < 0.0 || start_pcnt > 1.0 ||
205
+ end_pcnt < 0.0 || end_pcnt > 1.0) {
206
+ return -1;
207
+ }
208
+
209
+ ptime->start = start + round(start_pcnt * total);
210
+ ptime->end = start + round(end_pcnt * total);
211
+
212
+ if (ptime->end > ptime->start && ptime->end != end)
213
+ ptime->end -= 1;
214
+
215
+ return 0;
216
+}
217
+
136218 static int percent_slash_split(char *str, struct perf_time_interval *ptime,
137219 u64 start, u64 end)
138220 {
139221 char *p, *end_str;
140222 double pcnt, start_pcnt, end_pcnt;
141
- u64 total = end - start;
142223 int i;
143224
144225 /*
....@@ -166,15 +247,7 @@
166247 start_pcnt = pcnt * (i - 1);
167248 end_pcnt = pcnt * i;
168249
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;
250
+ return set_percent_time(ptime, start_pcnt, end_pcnt, start, end);
178251 }
179252
180253 static int percent_dash_split(char *str, struct perf_time_interval *ptime,
....@@ -182,7 +255,6 @@
182255 {
183256 char *start_str = NULL, *end_str;
184257 double start_pcnt, end_pcnt;
185
- u64 total = end - start;
186258 int ret;
187259
188260 /*
....@@ -201,16 +273,7 @@
201273
202274 free(start_str);
203275
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;
276
+ return set_percent_time(ptime, start_pcnt, end_pcnt, start, end);
214277 }
215278
216279 typedef int (*time_pecent_split)(char *, struct perf_time_interval *,
....@@ -374,7 +437,7 @@
374437 struct perf_time_interval *ptime;
375438 int i;
376439
377
- if ((timestamp == 0) || (num == 0))
440
+ if ((!ptime_buf) || (timestamp == 0) || (num == 0))
378441 return false;
379442
380443 if (num == 1)
....@@ -387,13 +450,79 @@
387450 ptime = &ptime_buf[i];
388451
389452 if (timestamp >= ptime->start &&
390
- ((timestamp < ptime->end && i < num - 1) ||
391
- (timestamp <= ptime->end && i == num - 1))) {
392
- break;
453
+ (timestamp <= ptime->end || !ptime->end)) {
454
+ return false;
393455 }
394456 }
395457
396
- return (i == num) ? true : false;
458
+ return true;
459
+}
460
+
461
+int perf_time__parse_for_ranges_reltime(const char *time_str,
462
+ struct perf_session *session,
463
+ struct perf_time_interval **ranges,
464
+ int *range_size, int *range_num,
465
+ bool reltime)
466
+{
467
+ bool has_percent = strchr(time_str, '%');
468
+ struct perf_time_interval *ptime_range;
469
+ int size, num, ret = -EINVAL;
470
+
471
+ ptime_range = perf_time__range_alloc(time_str, &size);
472
+ if (!ptime_range)
473
+ return -ENOMEM;
474
+
475
+ if (has_percent || reltime) {
476
+ if (session->evlist->first_sample_time == 0 &&
477
+ session->evlist->last_sample_time == 0) {
478
+ pr_err("HINT: no first/last sample time found in perf data.\n"
479
+ "Please use latest perf binary to execute 'perf record'\n"
480
+ "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n");
481
+ goto error;
482
+ }
483
+ }
484
+
485
+ if (has_percent) {
486
+ num = perf_time__percent_parse_str(
487
+ ptime_range, size,
488
+ time_str,
489
+ session->evlist->first_sample_time,
490
+ session->evlist->last_sample_time);
491
+ } else {
492
+ num = perf_time__parse_strs(ptime_range, time_str, size);
493
+ }
494
+
495
+ if (num < 0)
496
+ goto error_invalid;
497
+
498
+ if (reltime) {
499
+ int i;
500
+
501
+ for (i = 0; i < num; i++) {
502
+ ptime_range[i].start += session->evlist->first_sample_time;
503
+ ptime_range[i].end += session->evlist->first_sample_time;
504
+ }
505
+ }
506
+
507
+ *range_size = size;
508
+ *range_num = num;
509
+ *ranges = ptime_range;
510
+ return 0;
511
+
512
+error_invalid:
513
+ pr_err("Invalid time string\n");
514
+error:
515
+ free(ptime_range);
516
+ return ret;
517
+}
518
+
519
+int perf_time__parse_for_ranges(const char *time_str,
520
+ struct perf_session *session,
521
+ struct perf_time_interval **ranges,
522
+ int *range_size, int *range_num)
523
+{
524
+ return perf_time__parse_for_ranges_reltime(time_str, session, ranges,
525
+ range_size, range_num, false);
397526 }
398527
399528 int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz)
....@@ -404,6 +533,14 @@
404533 return scnprintf(buf, sz, "%"PRIu64".%06"PRIu64, sec, usec);
405534 }
406535
536
+int timestamp__scnprintf_nsec(u64 timestamp, char *buf, size_t sz)
537
+{
538
+ u64 sec = timestamp / NSEC_PER_SEC,
539
+ nsec = timestamp % NSEC_PER_SEC;
540
+
541
+ return scnprintf(buf, sz, "%" PRIu64 ".%09" PRIu64, sec, nsec);
542
+}
543
+
407544 int fetch_current_timestamp(char *buf, size_t sz)
408545 {
409546 struct timeval tv;