Commit 4802138d authored by Jin Yao's avatar Jin Yao Committed by Arnaldo Carvalho de Melo

perf diff: Support --time filter option

To improve 'perf diff', implement a --time filter option to diff the
samples within given time window.

It supports time percent with multiple time ranges. The time string
format is 'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.

For example:

Select the second 10% time slice to diff:

  perf diff --time 10%/2

Select from 0% to 10% time slice to diff:

  perf diff --time 0%-10%

Select the first and the second 10% time slices to diff:

  perf diff --time 10%/1,10%/2

Select from 0% to 10% and 30% to 40% slices to diff:

  perf diff --time 0%-10%,30%-40%

It also supports analysing samples within a given time window
<start>,<stop>.

Times have the format seconds.microseconds.

If 'start' is not given (i.e., time string is ',x.y') then analysis starts at
the beginning of the file.

If the stop time is not given (i.e, time string is 'x.y,') then analysis
goes to end of file.

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.

  perf script -i perf.data.old

    mgen 13940 [000]  3946.361400: ...

  perf script -i perf.data

    mgen 13940 [000]  3971.150589 ...

  perf diff --time 3946.361400,:3971.150589,

It analyzes the perf.data.old from the timestamp 3946.361400 to the end of
perf.data.old and analyzes the perf.data from the timestamp 3971.150589 to the
end of perf.data.

 v4:
 ---
 Update abstime_str_dup(), let it return error if strdup
 is failed, and update __cmd_diff() accordingly.
Signed-off-by: default avatarJin Yao <yao.jin@linux.intel.com>
Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Jin Yao <yao.jin@intel.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1551791143-10334-2-git-send-email-yao.jin@linux.intel.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 15325938
...@@ -118,6 +118,51 @@ OPTIONS ...@@ -118,6 +118,51 @@ OPTIONS
sum of shown entries will be always 100%. "absolute" means it retains sum of shown entries will be always 100%. "absolute" means it retains
the original value before and after the filter is applied. the original value before and after the filter is applied.
--time::
Analyze samples within given time window. It supports time
percent with multiple time ranges. Time string is 'a%/n,b%/m,...'
or 'a%-b%,c%-%d,...'.
For example:
Select the second 10% time slice to diff:
perf diff --time 10%/2
Select from 0% to 10% time slice to diff:
perf diff --time 0%-10%
Select the first and the second 10% time slices to diff:
perf diff --time 10%/1,10%/2
Select from 0% to 10% and 30% to 40% slices to diff:
perf diff --time 0%-10%,30%-40%
It also supports analyzing samples within a given time window
<start>,<stop>. Times have the format seconds.microseconds. 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.
For example, we get the timestamp information from 'perf script'.
perf script -i perf.data.old
mgen 13940 [000] 3946.361400: ...
perf script -i perf.data
mgen 13940 [000] 3971.150589 ...
perf diff --time 3946.361400,:3971.150589,
It analyzes the perf.data.old from the timestamp 3946.361400 to
the end of perf.data.old and analyzes the perf.data from the
timestamp 3971.150589 to the end of perf.data.
COMPARISON COMPARISON
---------- ----------
The comparison is governed by the baseline file. The baseline perf.data The comparison is governed by the baseline file. The baseline perf.data
......
...@@ -19,12 +19,21 @@ ...@@ -19,12 +19,21 @@
#include "util/util.h" #include "util/util.h"
#include "util/data.h" #include "util/data.h"
#include "util/config.h" #include "util/config.h"
#include "util/time-utils.h"
#include <errno.h> #include <errno.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
struct perf_diff {
struct perf_tool tool;
const char *time_str;
struct perf_time_interval *ptime_range;
int range_size;
int range_num;
};
/* Diff command specific HPP columns. */ /* Diff command specific HPP columns. */
enum { enum {
PERF_HPP_DIFF__BASELINE, PERF_HPP_DIFF__BASELINE,
...@@ -323,16 +332,22 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair, ...@@ -323,16 +332,22 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
return -1; return -1;
} }
static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, static int diff__process_sample_event(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct machine *machine) struct machine *machine)
{ {
struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool);
struct addr_location al; struct addr_location al;
struct hists *hists = evsel__hists(evsel); struct hists *hists = evsel__hists(evsel);
int ret = -1; int ret = -1;
if (perf_time__ranges_skip_sample(pdiff->ptime_range, pdiff->range_num,
sample->time)) {
return 0;
}
if (machine__resolve(machine, &al, sample) < 0) { if (machine__resolve(machine, &al, sample) < 0) {
pr_warning("problem processing %d event, skipping it.\n", pr_warning("problem processing %d event, skipping it.\n",
event->header.type); event->header.type);
...@@ -359,17 +374,19 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, ...@@ -359,17 +374,19 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
return ret; return ret;
} }
static struct perf_tool tool = { static struct perf_diff pdiff = {
.sample = diff__process_sample_event, .tool = {
.mmap = perf_event__process_mmap, .sample = diff__process_sample_event,
.mmap2 = perf_event__process_mmap2, .mmap = perf_event__process_mmap,
.comm = perf_event__process_comm, .mmap2 = perf_event__process_mmap2,
.exit = perf_event__process_exit, .comm = perf_event__process_comm,
.fork = perf_event__process_fork, .exit = perf_event__process_exit,
.lost = perf_event__process_lost, .fork = perf_event__process_fork,
.namespaces = perf_event__process_namespaces, .lost = perf_event__process_lost,
.ordered_events = true, .namespaces = perf_event__process_namespaces,
.ordering_requires_timestamps = true, .ordered_events = true,
.ordering_requires_timestamps = true,
},
}; };
static struct perf_evsel *evsel_match(struct perf_evsel *evsel, static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
...@@ -771,19 +788,110 @@ static void data__free(struct data__file *d) ...@@ -771,19 +788,110 @@ static void data__free(struct data__file *d)
} }
} }
static int abstime_str_dup(char **pstr)
{
char *str = NULL;
if (pdiff.time_str && strchr(pdiff.time_str, ':')) {
str = strdup(pdiff.time_str);
if (!str)
return -ENOMEM;
}
*pstr = str;
return 0;
}
static int parse_absolute_time(struct data__file *d, char **pstr)
{
char *p = *pstr;
int ret;
/*
* Absolute timestamp for one file has the format: a.b,c.d
* For multiple files, the format is: a.b,c.d:a.b,c.d
*/
p = strchr(*pstr, ':');
if (p) {
if (p == *pstr) {
pr_err("Invalid time string\n");
return -EINVAL;
}
*p = 0;
p++;
if (*p == 0) {
pr_err("Invalid time string\n");
return -EINVAL;
}
}
ret = perf_time__parse_for_ranges(*pstr, d->session,
&pdiff.ptime_range,
&pdiff.range_size,
&pdiff.range_num);
if (ret < 0)
return ret;
if (!p || *p == 0)
*pstr = NULL;
else
*pstr = p;
return ret;
}
static int parse_percent_time(struct data__file *d)
{
int ret;
ret = perf_time__parse_for_ranges(pdiff.time_str, d->session,
&pdiff.ptime_range,
&pdiff.range_size,
&pdiff.range_num);
return ret;
}
static int parse_time_str(struct data__file *d, char *abstime_ostr,
char **pabstime_tmp)
{
int ret = 0;
if (abstime_ostr)
ret = parse_absolute_time(d, pabstime_tmp);
else if (pdiff.time_str)
ret = parse_percent_time(d);
return ret;
}
static int __cmd_diff(void) static int __cmd_diff(void)
{ {
struct data__file *d; struct data__file *d;
int ret = -EINVAL, i; int ret, i;
char *abstime_ostr, *abstime_tmp;
ret = abstime_str_dup(&abstime_ostr);
if (ret)
return ret;
abstime_tmp = abstime_ostr;
ret = -EINVAL;
data__for_each_file(i, d) { data__for_each_file(i, d) {
d->session = perf_session__new(&d->data, false, &tool); d->session = perf_session__new(&d->data, false, &pdiff.tool);
if (!d->session) { if (!d->session) {
pr_err("Failed to open %s\n", d->data.path); pr_err("Failed to open %s\n", d->data.path);
ret = -1; ret = -1;
goto out_delete; goto out_delete;
} }
if (pdiff.time_str) {
ret = parse_time_str(d, abstime_ostr, &abstime_tmp);
if (ret < 0)
goto out_delete;
}
ret = perf_session__process_events(d->session); ret = perf_session__process_events(d->session);
if (ret) { if (ret) {
pr_err("Failed to process %s\n", d->data.path); pr_err("Failed to process %s\n", d->data.path);
...@@ -791,6 +899,9 @@ static int __cmd_diff(void) ...@@ -791,6 +899,9 @@ static int __cmd_diff(void)
} }
perf_evlist__collapse_resort(d->session->evlist); perf_evlist__collapse_resort(d->session->evlist);
if (pdiff.ptime_range)
zfree(&pdiff.ptime_range);
} }
data_process(); data_process();
...@@ -802,6 +913,13 @@ static int __cmd_diff(void) ...@@ -802,6 +913,13 @@ static int __cmd_diff(void)
} }
free(data__files); free(data__files);
if (pdiff.ptime_range)
zfree(&pdiff.ptime_range);
if (abstime_ostr)
free(abstime_ostr);
return ret; return ret;
} }
...@@ -849,6 +967,8 @@ static const struct option options[] = { ...@@ -849,6 +967,8 @@ static const struct option options[] = {
OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
"How to display percentage of filtered entries", parse_filter_percentage), "How to display percentage of filtered entries", parse_filter_percentage),
OPT_STRING(0, "time", &pdiff.time_str, "str",
"Time span (time percent or absolute timestamp)"),
OPT_END() OPT_END()
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment