summaryrefslogtreecommitdiff
path: root/tools/perf/builtin-diff.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-diff.c')
-rw-r--r--tools/perf/builtin-diff.c134
1 files changed, 115 insertions, 19 deletions
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index f28799e94f2a..a77e31246c00 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -16,6 +16,7 @@
#include "util/sort.h"
#include "util/symbol.h"
#include "util/util.h"
+#include "util/data.h"
#include <stdlib.h>
#include <math.h>
@@ -42,7 +43,7 @@ struct diff_hpp_fmt {
struct data__file {
struct perf_session *session;
- const char *file;
+ struct perf_data_file file;
int idx;
struct hists *hists;
struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
@@ -302,11 +303,12 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
return -1;
}
-static int hists__add_entry(struct hists *self,
+static int hists__add_entry(struct hists *hists,
struct addr_location *al, u64 period,
- u64 weight)
+ u64 weight, u64 transaction)
{
- if (__hists__add_entry(self, al, NULL, period, weight) != NULL)
+ if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight,
+ transaction) != NULL)
return 0;
return -ENOMEM;
}
@@ -328,7 +330,8 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
if (al.filtered)
return 0;
- if (hists__add_entry(&evsel->hists, &al, sample->period, sample->weight)) {
+ if (hists__add_entry(&evsel->hists, &al, sample->period,
+ sample->weight, sample->transaction)) {
pr_warning("problem incrementing symbol period, skipping event\n");
return -1;
}
@@ -353,9 +356,10 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
{
struct perf_evsel *e;
- list_for_each_entry(e, &evlist->entries, node)
+ evlist__for_each(evlist, e) {
if (perf_evsel__match2(evsel, e))
return e;
+ }
return NULL;
}
@@ -364,10 +368,10 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
{
struct perf_evsel *evsel;
- list_for_each_entry(evsel, &evlist->entries, node) {
+ evlist__for_each(evlist, evsel) {
struct hists *hists = &evsel->hists;
- hists__collapse_resort(hists);
+ hists__collapse_resort(hists, NULL);
}
}
@@ -599,7 +603,7 @@ static void data__fprintf(void)
data__for_each_file(i, d)
fprintf(stdout, "# [%d] %s %s\n",
- d->idx, d->file,
+ d->idx, d->file.path,
!d->idx ? "(Baseline)" : "");
fprintf(stdout, "#\n");
@@ -611,7 +615,7 @@ static void data_process(void)
struct perf_evsel *evsel_base;
bool first = true;
- list_for_each_entry(evsel_base, &evlist_base->entries, node) {
+ evlist__for_each(evlist_base, evsel_base) {
struct data__file *d;
int i;
@@ -651,7 +655,7 @@ static void data__free(struct data__file *d)
for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
struct diff_hpp_fmt *fmt = &d->fmt[col];
- free(fmt->header);
+ zfree(&fmt->header);
}
}
@@ -661,17 +665,16 @@ static int __cmd_diff(void)
int ret = -EINVAL, i;
data__for_each_file(i, d) {
- d->session = perf_session__new(d->file, O_RDONLY, force,
- false, &tool);
+ d->session = perf_session__new(&d->file, false, &tool);
if (!d->session) {
- pr_err("Failed to open %s\n", d->file);
+ pr_err("Failed to open %s\n", d->file.path);
ret = -ENOMEM;
goto out_delete;
}
ret = perf_session__process_events(d->session, &tool);
if (ret) {
- pr_err("Failed to process %s\n", d->file);
+ pr_err("Failed to process %s\n", d->file.path);
goto out_delete;
}
@@ -767,6 +770,81 @@ static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
return ret;
}
+static int __hpp__color_compare(struct perf_hpp_fmt *fmt,
+ struct perf_hpp *hpp, struct hist_entry *he,
+ int comparison_method)
+{
+ struct diff_hpp_fmt *dfmt =
+ container_of(fmt, struct diff_hpp_fmt, fmt);
+ struct hist_entry *pair = get_pair_fmt(he, dfmt);
+ double diff;
+ s64 wdiff;
+ char pfmt[20] = " ";
+
+ if (!pair)
+ goto dummy_print;
+
+ switch (comparison_method) {
+ case COMPUTE_DELTA:
+ if (pair->diff.computed)
+ diff = pair->diff.period_ratio_delta;
+ else
+ diff = compute_delta(he, pair);
+
+ if (fabs(diff) < 0.01)
+ goto dummy_print;
+ scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1);
+ return percent_color_snprintf(hpp->buf, hpp->size,
+ pfmt, diff);
+ case COMPUTE_RATIO:
+ if (he->dummy)
+ goto dummy_print;
+ if (pair->diff.computed)
+ diff = pair->diff.period_ratio;
+ else
+ diff = compute_ratio(he, pair);
+
+ scnprintf(pfmt, 20, "%%%d.6f", dfmt->header_width);
+ return value_color_snprintf(hpp->buf, hpp->size,
+ pfmt, diff);
+ case COMPUTE_WEIGHTED_DIFF:
+ if (he->dummy)
+ goto dummy_print;
+ if (pair->diff.computed)
+ wdiff = pair->diff.wdiff;
+ else
+ wdiff = compute_wdiff(he, pair);
+
+ scnprintf(pfmt, 20, "%%14ld", dfmt->header_width);
+ return color_snprintf(hpp->buf, hpp->size,
+ get_percent_color(wdiff),
+ pfmt, wdiff);
+ default:
+ BUG_ON(1);
+ }
+dummy_print:
+ return scnprintf(hpp->buf, hpp->size, "%*s",
+ dfmt->header_width, pfmt);
+}
+
+static int hpp__color_delta(struct perf_hpp_fmt *fmt,
+ struct perf_hpp *hpp, struct hist_entry *he)
+{
+ return __hpp__color_compare(fmt, hpp, he, COMPUTE_DELTA);
+}
+
+static int hpp__color_ratio(struct perf_hpp_fmt *fmt,
+ struct perf_hpp *hpp, struct hist_entry *he)
+{
+ return __hpp__color_compare(fmt, hpp, he, COMPUTE_RATIO);
+}
+
+static int hpp__color_wdiff(struct perf_hpp_fmt *fmt,
+ struct perf_hpp *hpp, struct hist_entry *he)
+{
+ return __hpp__color_compare(fmt, hpp, he, COMPUTE_WEIGHTED_DIFF);
+}
+
static void
hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
{
@@ -938,8 +1016,22 @@ static void data__hpp_register(struct data__file *d, int idx)
fmt->entry = hpp__entry_global;
/* TODO more colors */
- if (idx == PERF_HPP_DIFF__BASELINE)
+ switch (idx) {
+ case PERF_HPP_DIFF__BASELINE:
fmt->color = hpp__color_baseline;
+ break;
+ case PERF_HPP_DIFF__DELTA:
+ fmt->color = hpp__color_delta;
+ break;
+ case PERF_HPP_DIFF__RATIO:
+ fmt->color = hpp__color_ratio;
+ break;
+ case PERF_HPP_DIFF__WEIGHTED_DIFF:
+ fmt->color = hpp__color_wdiff;
+ break;
+ default:
+ break;
+ }
init_header(d, dfmt);
perf_hpp__column_register(fmt);
@@ -998,8 +1090,7 @@ static int data_init(int argc, const char **argv)
data__files_cnt = argc;
use_default = false;
}
- } else if (symbol_conf.default_guest_vmlinux_name ||
- symbol_conf.default_guest_kallsyms) {
+ } else if (perf_guest) {
defaults[0] = "perf.data.host";
defaults[1] = "perf.data.guest";
}
@@ -1014,7 +1105,12 @@ static int data_init(int argc, const char **argv)
return -ENOMEM;
data__for_each_file(i, d) {
- d->file = use_default ? defaults[i] : argv[i];
+ struct perf_data_file *file = &d->file;
+
+ file->path = use_default ? defaults[i] : argv[i];
+ file->mode = PERF_DATA_MODE_READ,
+ file->force = force,
+
d->idx = i;
}