perf time-utils: Add support for multiple explicit time intervals
authorAdrian Hunter <adrian.hunter@intel.com>
Tue, 4 Jun 2019 13:00:17 +0000 (16:00 +0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 10 Jun 2019 19:20:13 +0000 (16:20 -0300)
Currently only a single explicit time range is accepted. Add support for
multiple ranges separated by spaces, which requires the string to be
quoted. Update the time utils test accordingly.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/20190604130017.31207-20-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/Documentation/perf-diff.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-script.txt
tools/perf/tests/time-utils-test.c
tools/perf/util/time-utils.c

index 5732f69..facd91e 100644 (file)
@@ -145,9 +145,11 @@ OPTIONS
        <start>,<stop>. Times have the format seconds.nanoseconds. If 'start'
        is not given (i.e. time string is ',x.y') then analysis starts at
        the beginning of the file. If stop time is not given (i.e. time
-       string is 'x.y,') then analysis goes to the end of the file. Time string is
-       'a1.b1,c1.d1:a2.b2,c2.d2'. Use ':' to separate timestamps for different
-       perf.data files.
+       string is 'x.y,') then analysis goes to the end of the file.
+       Multiple ranges can be separated by spaces, which requires the argument
+       to be quoted e.g. --time "1234.567,1234.789 1235,"
+       Time string is'a1.b1,c1.d1:a2.b2,c2.d2'. Use ':' to separate timestamps
+       for different perf.data files.
 
        For example, we get the timestamp information from 'perf script'.
 
index 3de029f..8c43728 100644 (file)
@@ -415,7 +415,8 @@ OPTIONS
        have the format seconds.nanoseconds. If start is not given (i.e. time
        string is ',x.y') then analysis starts at the beginning of the file. If
        stop time is not given (i.e. time string is 'x.y,') then analysis goes
-       to end of file.
+       to end of file. Multiple ranges can be separated by spaces, which
+       requires the argument to be quoted e.g. --time "1234.567,1234.789 1235,"
 
        Also support time percent with multiple time ranges. Time string is
        'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.
index 878349c..d4e2e18 100644 (file)
@@ -364,7 +364,8 @@ include::itrace.txt[]
        have the format seconds.nanoseconds. If start is not given (i.e. time
        string is ',x.y') then analysis starts at the beginning of the file. If
        stop time is not given (i.e. time string is 'x.y,') then analysis goes
-       to end of file.
+       to end of file. Multiple ranges can be separated by spaces, which
+       requires the argument to be quoted e.g. --time "1234.567,1234.789 1235,"
 
        Also support time percent with multiple time ranges. Time string is
        'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.
index 7504046..4f53006 100644 (file)
@@ -168,6 +168,23 @@ int test__time_utils(struct test *t __maybe_unused, int subtest __maybe_unused)
                pass &= test__perf_time__parse_for_ranges(&d);
        }
 
+       {
+               u64 b = 1234567123456789ULL;
+               u64 c = 7654321987654321ULL;
+               u64 e = 8000000000000000ULL;
+               struct test_data d = {
+                       .str   = "1234567.123456789,1234567.123456790 "
+                                "7654321.987654321,7654321.987654444 "
+                                "8000000,8000000.000000005",
+                       .ptime = { {b, b + 1}, {c, c + 123}, {e, e + 5}, },
+                       .num = 3,
+                       .skip = { b - 1, b + 2, c - 1, c + 124, e - 1, e + 6 },
+                       .noskip = { b, b + 1, c, c + 123, e, e + 5 },
+               };
+
+               pass &= test__perf_time__parse_for_ranges(&d);
+       }
+
        {
                u64 b = 7654321ULL * NSEC_PER_SEC;
                struct test_data d = {
index d942840..2b48816 100644 (file)
@@ -7,6 +7,7 @@
 #include <errno.h>
 #include <inttypes.h>
 #include <math.h>
+#include <ctype.h>
 
 #include "perf.h"
 #include "debug.h"
@@ -116,6 +117,69 @@ int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr)
        return rc;
 }
 
+static int perf_time__parse_strs(struct perf_time_interval *ptime,
+                                const char *ostr, int size)
+{
+       const char *cp;
+       char *str, *arg, *p;
+       int i, num = 0, rc = 0;
+
+       /* Count the commas */
+       for (cp = ostr; *cp; cp++)
+               num += !!(*cp == ',');
+
+       if (!num)
+               return -EINVAL;
+
+       BUG_ON(num > size);
+
+       str = strdup(ostr);
+       if (!str)
+               return -ENOMEM;
+
+       /* Split the string and parse each piece, except the last */
+       for (i = 0, p = str; i < num - 1; i++) {
+               arg = p;
+               /* Find next comma, there must be one */
+               p = strchr(p, ',') + 1;
+               /* Skip white space */
+               while (isspace(*p))
+                       p++;
+               /* Skip the value, must not contain space or comma */
+               while (*p && !isspace(*p)) {
+                       if (*p++ == ',') {
+                               rc = -EINVAL;
+                               goto out;
+                       }
+               }
+               /* Split and parse */
+               if (*p)
+                       *p++ = 0;
+               rc = perf_time__parse_str(ptime + i, arg);
+               if (rc < 0)
+                       goto out;
+       }
+
+       /* Parse the last piece */
+       rc = perf_time__parse_str(ptime + i, p);
+       if (rc < 0)
+               goto out;
+
+       /* Check there is no overlap */
+       for (i = 0; i < num - 1; i++) {
+               if (ptime[i].end >= ptime[i + 1].start) {
+                       rc = -EINVAL;
+                       goto out;
+               }
+       }
+
+       rc = num;
+out:
+       free(str);
+
+       return rc;
+}
+
 static int parse_percent(double *pcnt, char *str)
 {
        char *c, *endptr;
@@ -424,15 +488,13 @@ int perf_time__parse_for_ranges(const char *time_str,
                                time_str,
                                session->evlist->first_sample_time,
                                session->evlist->last_sample_time);
-
-               if (num < 0)
-                       goto error_invalid;
        } else {
-               if (perf_time__parse_str(ptime_range, time_str))
-                       goto error_invalid;
-               num = 1;
+               num = perf_time__parse_strs(ptime_range, time_str, size);
        }
 
+       if (num < 0)
+               goto error_invalid;
+
        *range_size = size;
        *range_num = num;
        *ranges = ptime_range;