|
@@ -44,6 +44,7 @@ struct data__file {
|
|
|
struct perf_session *session;
|
|
|
const char *file;
|
|
|
int idx;
|
|
|
+ struct hists *hists;
|
|
|
struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
|
|
|
};
|
|
|
|
|
@@ -56,6 +57,7 @@ static int data__files_cnt;
|
|
|
i++, d = &data__files[i])
|
|
|
|
|
|
#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
|
|
|
+#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
|
|
|
|
|
|
static char diff__default_sort_order[] = "dso,symbol";
|
|
|
static bool force;
|
|
@@ -525,23 +527,19 @@ static void hists__compute_resort(struct hists *hists)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void hists__process(struct hists *base, struct hists *new)
|
|
|
+static void hists__process(struct hists *hists)
|
|
|
{
|
|
|
- hists__match(base, new);
|
|
|
-
|
|
|
if (show_baseline_only)
|
|
|
- hists__baseline_only(base);
|
|
|
- else
|
|
|
- hists__link(base, new);
|
|
|
+ hists__baseline_only(hists);
|
|
|
|
|
|
if (sort_compute) {
|
|
|
- hists__precompute(base);
|
|
|
- hists__compute_resort(base);
|
|
|
+ hists__precompute(hists);
|
|
|
+ hists__compute_resort(hists);
|
|
|
} else {
|
|
|
- hists__output_resort(base);
|
|
|
+ hists__output_resort(hists);
|
|
|
}
|
|
|
|
|
|
- hists__fprintf(base, true, 0, 0, 0, stdout);
|
|
|
+ hists__fprintf(hists, true, 0, 0, 0, stdout);
|
|
|
}
|
|
|
|
|
|
static void data__fprintf(void)
|
|
@@ -561,27 +559,40 @@ static void data__fprintf(void)
|
|
|
|
|
|
static void data_process(void)
|
|
|
{
|
|
|
- struct perf_evlist *evlist_old = data__files[0].session->evlist;
|
|
|
- struct perf_evlist *evlist_new = data__files[1].session->evlist;
|
|
|
- struct perf_evsel *evsel_old;
|
|
|
+ struct perf_evlist *evlist_base = data__files[0].session->evlist;
|
|
|
+ struct perf_evsel *evsel_base;
|
|
|
bool first = true;
|
|
|
|
|
|
- list_for_each_entry(evsel_old, &evlist_old->entries, node) {
|
|
|
- struct perf_evsel *evsel_new;
|
|
|
+ list_for_each_entry(evsel_base, &evlist_base->entries, node) {
|
|
|
+ struct data__file *d;
|
|
|
+ int i;
|
|
|
|
|
|
- evsel_new = evsel_match(evsel_old, evlist_new);
|
|
|
- if (!evsel_new)
|
|
|
- continue;
|
|
|
+ data__for_each_file_new(i, d) {
|
|
|
+ struct perf_evlist *evlist = d->session->evlist;
|
|
|
+ struct perf_evsel *evsel;
|
|
|
+
|
|
|
+ evsel = evsel_match(evsel_base, evlist);
|
|
|
+ if (!evsel)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ d->hists = &evsel->hists;
|
|
|
+
|
|
|
+ hists__match(&evsel_base->hists, &evsel->hists);
|
|
|
+
|
|
|
+ if (!show_baseline_only)
|
|
|
+ hists__link(&evsel_base->hists,
|
|
|
+ &evsel->hists);
|
|
|
+ }
|
|
|
|
|
|
fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
|
|
|
- perf_evsel__name(evsel_old));
|
|
|
+ perf_evsel__name(evsel_base));
|
|
|
|
|
|
first = false;
|
|
|
|
|
|
- if (verbose)
|
|
|
+ if (verbose || data__files_cnt > 2)
|
|
|
data__fprintf();
|
|
|
|
|
|
- hists__process(&evsel_old->hists, &evsel_new->hists);
|
|
|
+ hists__process(&evsel_base->hists);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -780,10 +791,29 @@ hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+static struct hist_entry *get_pair(struct hist_entry *he,
|
|
|
+ struct diff_hpp_fmt *dfmt)
|
|
|
+{
|
|
|
+ void *ptr = dfmt - dfmt->idx;
|
|
|
+ struct data__file *d = container_of(ptr, struct data__file, fmt);
|
|
|
+
|
|
|
+ if (hist_entry__has_pairs(he)) {
|
|
|
+ struct hist_entry *pair;
|
|
|
+
|
|
|
+ list_for_each_entry(pair, &he->pairs.head, pairs.node)
|
|
|
+ if (pair->hists == d->hists)
|
|
|
+ return pair;
|
|
|
+ }
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
-__hpp__entry_global(struct hist_entry *he, int idx, char *buf, size_t size)
|
|
|
+__hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt,
|
|
|
+ char *buf, size_t size)
|
|
|
{
|
|
|
- struct hist_entry *pair = hist_entry__next_pair(he);
|
|
|
+ struct hist_entry *pair = get_pair(he, dfmt);
|
|
|
+ int idx = dfmt->idx;
|
|
|
|
|
|
/* baseline is special */
|
|
|
if (idx == PERF_HPP_DIFF__BASELINE)
|
|
@@ -803,7 +833,7 @@ static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
|
|
|
container_of(_fmt, struct diff_hpp_fmt, fmt);
|
|
|
char buf[MAX_COL_WIDTH] = " ";
|
|
|
|
|
|
- __hpp__entry_global(he, dfmt->idx, buf, MAX_COL_WIDTH);
|
|
|
+ __hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH);
|
|
|
|
|
|
if (symbol_conf.field_sep)
|
|
|
return scnprintf(hpp->buf, hpp->size, "%s", buf);
|
|
@@ -832,7 +862,7 @@ static int hpp__width(struct perf_hpp_fmt *fmt,
|
|
|
return dfmt->header_width;
|
|
|
}
|
|
|
|
|
|
-static void init_header(struct diff_hpp_fmt *dfmt)
|
|
|
+static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt)
|
|
|
{
|
|
|
#define MAX_HEADER_NAME 100
|
|
|
char buf_indent[MAX_HEADER_NAME];
|
|
@@ -847,6 +877,9 @@ static void init_header(struct diff_hpp_fmt *dfmt)
|
|
|
/* Only our defined HPP fmts should appear here. */
|
|
|
BUG_ON(!header);
|
|
|
|
|
|
+ if (data__files_cnt > 2)
|
|
|
+ scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx);
|
|
|
+
|
|
|
#define NAME (data__files_cnt > 2 ? buf : header)
|
|
|
dfmt->header_width = width;
|
|
|
width = (int) strlen(NAME);
|
|
@@ -876,7 +909,7 @@ static void data__hpp_register(struct data__file *d, int idx)
|
|
|
if (idx == PERF_HPP_DIFF__BASELINE)
|
|
|
fmt->color = hpp__color_baseline;
|
|
|
|
|
|
- init_header(dfmt);
|
|
|
+ init_header(d, dfmt);
|
|
|
perf_hpp__column_register(fmt);
|
|
|
}
|
|
|
|
|
@@ -921,18 +954,18 @@ static int data_init(int argc, const char **argv)
|
|
|
"perf.data.old",
|
|
|
"perf.data",
|
|
|
};
|
|
|
+ bool use_default = true;
|
|
|
int i;
|
|
|
|
|
|
data__files_cnt = 2;
|
|
|
|
|
|
if (argc) {
|
|
|
- if (argc > 2)
|
|
|
- usage_with_options(diff_usage, options);
|
|
|
- if (argc == 2) {
|
|
|
- defaults[0] = argv[0];
|
|
|
- defaults[1] = argv[1];
|
|
|
- } else
|
|
|
+ if (argc == 1)
|
|
|
defaults[1] = argv[0];
|
|
|
+ else {
|
|
|
+ data__files_cnt = argc;
|
|
|
+ use_default = false;
|
|
|
+ }
|
|
|
} else if (symbol_conf.default_guest_vmlinux_name ||
|
|
|
symbol_conf.default_guest_kallsyms) {
|
|
|
defaults[0] = "perf.data.host";
|
|
@@ -944,7 +977,7 @@ static int data_init(int argc, const char **argv)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
data__for_each_file(i, d) {
|
|
|
- d->file = defaults[i];
|
|
|
+ d->file = use_default ? defaults[i] : argv[i];
|
|
|
d->idx = i;
|
|
|
}
|
|
|
|