diff options
Diffstat (limited to 'tools/perf/builtin-diff.c')
-rw-r--r-- | tools/perf/builtin-diff.c | 148 |
1 files changed, 134 insertions, 14 deletions
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 58fe0e88215c..17cd898074c8 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -19,12 +19,21 @@ #include "util/util.h" #include "util/data.h" #include "util/config.h" +#include "util/time-utils.h" #include <errno.h> #include <inttypes.h> #include <stdlib.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. */ enum { PERF_HPP_DIFF__BASELINE, @@ -323,16 +332,22 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair, 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, struct perf_sample *sample, struct perf_evsel *evsel, struct machine *machine) { + struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool); struct addr_location al; struct hists *hists = evsel__hists(evsel); 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) { pr_warning("problem processing %d event, skipping it.\n", event->header.type); @@ -359,17 +374,19 @@ out_put: return ret; } -static struct perf_tool tool = { - .sample = diff__process_sample_event, - .mmap = perf_event__process_mmap, - .mmap2 = perf_event__process_mmap2, - .comm = perf_event__process_comm, - .exit = perf_event__process_exit, - .fork = perf_event__process_fork, - .lost = perf_event__process_lost, - .namespaces = perf_event__process_namespaces, - .ordered_events = true, - .ordering_requires_timestamps = true, +static struct perf_diff pdiff = { + .tool = { + .sample = diff__process_sample_event, + .mmap = perf_event__process_mmap, + .mmap2 = perf_event__process_mmap2, + .comm = perf_event__process_comm, + .exit = perf_event__process_exit, + .fork = perf_event__process_fork, + .lost = perf_event__process_lost, + .namespaces = perf_event__process_namespaces, + .ordered_events = true, + .ordering_requires_timestamps = true, + }, }; static struct perf_evsel *evsel_match(struct perf_evsel *evsel, @@ -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) { 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) { - d->session = perf_session__new(&d->data, false, &tool); + d->session = perf_session__new(&d->data, false, &pdiff.tool); if (!d->session) { pr_err("Failed to open %s\n", d->data.path); ret = -1; 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); if (ret) { pr_err("Failed to process %s\n", d->data.path); @@ -791,6 +899,9 @@ static int __cmd_diff(void) } perf_evlist__collapse_resort(d->session->evlist); + + if (pdiff.ptime_range) + zfree(&pdiff.ptime_range); } data_process(); @@ -802,6 +913,13 @@ static int __cmd_diff(void) } free(data__files); + + if (pdiff.ptime_range) + zfree(&pdiff.ptime_range); + + if (abstime_ostr) + free(abstime_ostr); + return ret; } @@ -849,6 +967,8 @@ static const struct option options[] = { OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", "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() }; |