perf time-utils: Add support for multiple explicit time intervals

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>
This commit is contained in:
Adrian Hunter 2019-06-04 16:00:17 +03:00 committed by Arnaldo Carvalho de Melo
parent e39a12cbd2
commit a77a05e233
5 changed files with 94 additions and 11 deletions

View File

@ -145,9 +145,11 @@ OPTIONS
<start>,<stop>. Times have the format seconds.nanoseconds. If 'start' <start>,<stop>. Times have the format seconds.nanoseconds. If 'start'
is not given (i.e. time string is ',x.y') then analysis starts at 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 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 string is 'x.y,') then analysis goes to the end of the file.
'a1.b1,c1.d1:a2.b2,c2.d2'. Use ':' to separate timestamps for different Multiple ranges can be separated by spaces, which requires the argument
perf.data files. 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'. For example, we get the timestamp information from 'perf script'.

View File

@ -415,7 +415,8 @@ OPTIONS
have the format seconds.nanoseconds. If start is not given (i.e. time 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 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 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 Also support time percent with multiple time ranges. Time string is
'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'. 'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.

View File

@ -364,7 +364,8 @@ include::itrace.txt[]
have the format seconds.nanoseconds. If start is not given (i.e. time 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 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 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 Also support time percent with multiple time ranges. Time string is
'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'. 'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.

View 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); 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; u64 b = 7654321ULL * NSEC_PER_SEC;
struct test_data d = { struct test_data d = {

View File

@ -7,6 +7,7 @@
#include <errno.h> #include <errno.h>
#include <inttypes.h> #include <inttypes.h>
#include <math.h> #include <math.h>
#include <ctype.h>
#include "perf.h" #include "perf.h"
#include "debug.h" #include "debug.h"
@ -116,6 +117,69 @@ int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr)
return rc; 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) static int parse_percent(double *pcnt, char *str)
{ {
char *c, *endptr; char *c, *endptr;
@ -424,15 +488,13 @@ int perf_time__parse_for_ranges(const char *time_str,
time_str, time_str,
session->evlist->first_sample_time, session->evlist->first_sample_time,
session->evlist->last_sample_time); session->evlist->last_sample_time);
if (num < 0)
goto error_invalid;
} else { } else {
if (perf_time__parse_str(ptime_range, time_str)) num = perf_time__parse_strs(ptime_range, time_str, size);
goto error_invalid;
num = 1;
} }
if (num < 0)
goto error_invalid;
*range_size = size; *range_size = size;
*range_num = num; *range_num = num;
*ranges = ptime_range; *ranges = ptime_range;