From a06d143e7cfaa10626f3ad0127a9b9169f900add Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 5 Oct 2012 16:44:40 +0200 Subject: perf diff: Add -b option for perf diff to display paired entries only Adding -b option to perf diff command to display only entries with match in the baseline. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1349448287-18919-2-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index a0b531c14b9..1063c31e507 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -24,6 +24,7 @@ static char const *input_old = "perf.data.old", static char diff__default_sort_order[] = "dso,symbol"; static bool force; static bool show_displacement; +static bool show_baseline_only; static int hists__add_entry(struct hists *self, struct addr_location *al, u64 period) @@ -172,6 +173,31 @@ static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) } } +static void hists__baseline_only(struct hists *hists) +{ + struct rb_node *next = rb_first(&hists->entries); + + while (next != NULL) { + struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); + + next = rb_next(&he->rb_node); + if (!he->pair) { + rb_erase(&he->rb_node, &hists->entries); + hist_entry__free(he); + } + } +} + +static void hists__process(struct hists *old, struct hists *new) +{ + hists__match(old, new); + + if (show_baseline_only) + hists__baseline_only(new); + + hists__fprintf(new, true, 0, 0, stdout); +} + static int __cmd_diff(void) { int ret, i; @@ -213,8 +239,7 @@ static int __cmd_diff(void) first = false; - hists__match(&evsel_old->hists, &evsel->hists); - hists__fprintf(&evsel->hists, true, 0, 0, stdout); + hists__process(&evsel_old->hists, &evsel->hists); } out_delete: @@ -235,6 +260,8 @@ static const struct option options[] = { "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('M', "displacement", &show_displacement, "Show position displacement relative to baseline"), + OPT_BOOLEAN('b', "baseline-only", &show_baseline_only, + "Show only items with match in baseline"), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), -- cgit v1.2.3-70-g09d2 From 7aaf6b35512382329c5b2dd46b42f2bf12a5fff0 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 5 Oct 2012 16:44:41 +0200 Subject: perf diff: Add ratio computation way to compare hist entries Adding -c option to select computation method with the current 'Delta' computation as default. Current possible values are of this option are: 'delta' and 'ratio'. Adding 'ratio' as new computation way to compare hist entries. If specified the 'Ratio' column is displayed with value 'r' computed as: r = A->period / B->period with: - A/B being matching hist entry from first/second file specified (or perf.data/perf.data.old) respectively. - period being the hist entry period value Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1349448287-18919-3-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-diff.txt | 33 +++++++++++++++++++++ tools/perf/builtin-diff.c | 52 ++++++++++++++++++++++++++++++++-- tools/perf/ui/hist.c | 28 ++++++++++++++++++ tools/perf/util/hist.h | 1 + 4 files changed, 112 insertions(+), 2 deletions(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 6ce95858cd4..8fff0618c59 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt @@ -76,6 +76,39 @@ OPTIONS --baseline-only:: Show only items with match in baseline. +-c:: +--compute:: + Differential computation selection - delta,ratio (default is delta). + See COMPARISON METHODS section for more info. + +COMPARISON METHODS +------------------ +delta +~~~~~ +If specified the 'Delta' column is displayed with value 'd' computed as: + + d = A->period_percent - B->period_percent + +with: + - A/B being matching hist entry from first/second file specified + (or perf.data/perf.data.old) respectively. + + - period_percent being the % of the hist entry period value within + single data file + +ratio +~~~~~ +If specified the 'Ratio' column is displayed with value 'r' computed as: + + r = A->period / B->period + +with: + - A/B being matching hist entry from first/second file specified + (or perf.data/perf.data.old) respectively. + + - period being the hist entry period value + + SEE ALSO -------- linkperf:perf-record[1] diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 1063c31e507..e90c06aea4d 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -26,6 +26,41 @@ static bool force; static bool show_displacement; static bool show_baseline_only; +enum { + COMPUTE_DELTA, + COMPUTE_RATIO, + COMPUTE_MAX, +}; + +const char *compute_names[COMPUTE_MAX] = { + [COMPUTE_DELTA] = "delta", + [COMPUTE_RATIO] = "ratio", +}; + +static int compute; + +static int setup_compute(const struct option *opt, const char *str, + int unset __maybe_unused) +{ + int *cp = (int *) opt->value; + unsigned i; + + if (!str) { + *cp = COMPUTE_DELTA; + return 0; + } + + for (i = 0; i < COMPUTE_MAX; i++) + if (!strcmp(str, compute_names[i])) { + *cp = i; + return 0; + } + + pr_err("Failed: '%s' is not computation method " + "(use 'delta' or 'ratio').\n", str); + return -EINVAL; +} + static int hists__add_entry(struct hists *self, struct addr_location *al, u64 period) { @@ -262,6 +297,9 @@ static const struct option options[] = { "Show position displacement relative to baseline"), OPT_BOOLEAN('b', "baseline-only", &show_baseline_only, "Show only items with match in baseline"), + OPT_CALLBACK('c', "compute", &compute, "delta,ratio (default delta)", + "Entries differential computation selection", + setup_compute), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), @@ -290,9 +328,19 @@ static void ui_init(void) /* No overhead column. */ perf_hpp__column_enable(PERF_HPP__OVERHEAD, false); - /* Display baseline/delta/displacement columns. */ + /* Display baseline/delta/ratio/displacement columns. */ perf_hpp__column_enable(PERF_HPP__BASELINE, true); - perf_hpp__column_enable(PERF_HPP__DELTA, true); + + switch (compute) { + case COMPUTE_DELTA: + perf_hpp__column_enable(PERF_HPP__DELTA, true); + break; + case COMPUTE_RATIO: + perf_hpp__column_enable(PERF_HPP__RATIO, true); + break; + default: + BUG_ON(1); + }; if (show_displacement) perf_hpp__column_enable(PERF_HPP__DISPL, true); diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index f5a1e4f6526..1b633a4b5c4 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -266,6 +266,33 @@ static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) return scnprintf(hpp->buf, hpp->size, fmt, buf); } +static int hpp__header_ratio(struct perf_hpp *hpp) +{ + const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; + + return scnprintf(hpp->buf, hpp->size, fmt, "Ratio"); +} + +static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused) +{ + return 14; +} + +static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) +{ + struct hist_entry *pair = he->pair; + double new_period = he->stat.period; + double old_period = pair ? pair->stat.period : 0; + double ratio = pair ? new_period / old_period : 0; + const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; + char buf[32] = " "; + + if (ratio > 0.0) + scnprintf(buf, sizeof(buf), "%+14.6F", ratio); + + return scnprintf(hpp->buf, hpp->size, fmt, buf); +} + static int hpp__header_displ(struct perf_hpp *hpp) { return scnprintf(hpp->buf, hpp->size, "Displ."); @@ -311,6 +338,7 @@ struct perf_hpp_fmt perf_hpp__format[] = { { .cond = false, HPP__PRINT_FNS(samples) }, { .cond = false, HPP__PRINT_FNS(period) }, { .cond = false, HPP__PRINT_FNS(delta) }, + { .cond = false, HPP__PRINT_FNS(ratio) }, { .cond = false, HPP__PRINT_FNS(displ) } }; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 66cb31fe81d..7e4d4c26221 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -141,6 +141,7 @@ enum { PERF_HPP__SAMPLES, PERF_HPP__PERIOD, PERF_HPP__DELTA, + PERF_HPP__RATIO, PERF_HPP__DISPL, PERF_HPP__MAX_INDEX -- cgit v1.2.3-70-g09d2 From 96c47f19846742bdfa3c153c8d26ccca5945586b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 5 Oct 2012 16:44:42 +0200 Subject: perf diff: Add option to sort entries based on diff computation Adding support to sort hist entries based on the outcome of selected computation. It's now possible to specify '+' as a first character of '-c' option value to make such sort. Example: $ perf diff -c ratio -b # Event 'cache-misses' # # Baseline Ratio Shared Object Symbol # ........ .............. ................. ................................ # 19.64% 0.69 [kernel.kallsyms] [k] clear_page 0.30% 0.17 [kernel.kallsyms] [k] mm_alloc 0.04% 0.20 [kernel.kallsyms] [k] kmem_cache_alloc $ perf diff -c +ratio -b # Event 'cache-misses' # # Baseline Ratio Shared Object Symbol # ........ .............. ................. ................................ # 19.64% 0.69 [kernel.kallsyms] [k] clear_page 0.04% 0.20 [kernel.kallsyms] [k] kmem_cache_alloc 0.30% 0.17 [kernel.kallsyms] [k] mm_alloc Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1349448287-18919-4-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-diff.txt | 2 + tools/perf/builtin-diff.c | 137 +++++++++++++++++++++++++++++++++ tools/perf/ui/hist.c | 29 +++---- tools/perf/util/hist.h | 2 + tools/perf/util/sort.h | 15 ++++ 5 files changed, 167 insertions(+), 18 deletions(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 8fff0618c59..cff3d9b6e4a 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt @@ -79,6 +79,8 @@ OPTIONS -c:: --compute:: Differential computation selection - delta,ratio (default is delta). + If '+' is specified as a first character, the output is sorted based + on the computation results. See COMPARISON METHODS section for more info. COMPARISON METHODS diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index e90c06aea4d..e13cfac0b06 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -25,6 +25,7 @@ static char diff__default_sort_order[] = "dso,symbol"; static bool force; static bool show_displacement; static bool show_baseline_only; +static bool sort_compute; enum { COMPUTE_DELTA, @@ -50,6 +51,13 @@ static int setup_compute(const struct option *opt, const char *str, return 0; } + if (*str == '+') { + sort_compute = true; + str++; + if (!*str) + return 0; + } + for (i = 0; i < COMPUTE_MAX; i++) if (!strcmp(str, compute_names[i])) { *cp = i; @@ -61,6 +69,34 @@ static int setup_compute(const struct option *opt, const char *str, return -EINVAL; } +static double get_period_percent(struct hist_entry *he, u64 period) +{ + u64 total = he->hists->stats.total_period; + return (period * 100.0) / total; +} + +double perf_diff__compute_delta(struct hist_entry *he) +{ + struct hist_entry *pair = he->pair; + double new_percent = get_period_percent(he, he->stat.period); + double old_percent = pair ? get_period_percent(pair, pair->stat.period) : 0.0; + + he->diff.period_ratio_delta = new_percent - old_percent; + he->diff.computed = true; + return he->diff.period_ratio_delta; +} + +double perf_diff__compute_ratio(struct hist_entry *he) +{ + struct hist_entry *pair = he->pair; + double new_period = he->stat.period; + double old_period = pair ? pair->stat.period : 0; + + he->diff.computed = true; + he->diff.period_ratio = pair ? (new_period / old_period) : 0; + return he->diff.period_ratio; +} + static int hists__add_entry(struct hists *self, struct addr_location *al, u64 period) { @@ -223,6 +259,102 @@ static void hists__baseline_only(struct hists *hists) } } +static void hists__precompute(struct hists *hists) +{ + struct rb_node *next = rb_first(&hists->entries); + + while (next != NULL) { + struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); + + next = rb_next(&he->rb_node); + + switch (compute) { + case COMPUTE_DELTA: + perf_diff__compute_delta(he); + break; + case COMPUTE_RATIO: + perf_diff__compute_ratio(he); + break; + default: + BUG_ON(1); + } + } +} + +static int64_t cmp_doubles(double l, double r) +{ + if (l > r) + return -1; + else if (l < r) + return 1; + else + return 0; +} + +static int64_t +hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, + int c) +{ + switch (c) { + case COMPUTE_DELTA: + { + double l = left->diff.period_ratio_delta; + double r = right->diff.period_ratio_delta; + + return cmp_doubles(l, r); + } + case COMPUTE_RATIO: + { + double l = left->diff.period_ratio; + double r = right->diff.period_ratio; + + return cmp_doubles(l, r); + } + default: + BUG_ON(1); + } + + return 0; +} + +static void insert_hist_entry_by_compute(struct rb_root *root, + struct hist_entry *he, + int c) +{ + struct rb_node **p = &root->rb_node; + struct rb_node *parent = NULL; + struct hist_entry *iter; + + while (*p != NULL) { + parent = *p; + iter = rb_entry(parent, struct hist_entry, rb_node); + if (hist_entry__cmp_compute(he, iter, c) < 0) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&he->rb_node, parent, p); + rb_insert_color(&he->rb_node, root); +} + +static void hists__compute_resort(struct hists *hists) +{ + struct rb_root tmp = RB_ROOT; + struct rb_node *next = rb_first(&hists->entries); + + while (next != NULL) { + struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); + + next = rb_next(&he->rb_node); + + rb_erase(&he->rb_node, &hists->entries); + insert_hist_entry_by_compute(&tmp, he, compute); + } + + hists->entries = tmp; +} + static void hists__process(struct hists *old, struct hists *new) { hists__match(old, new); @@ -230,6 +362,11 @@ static void hists__process(struct hists *old, struct hists *new) if (show_baseline_only) hists__baseline_only(new); + if (sort_compute) { + hists__precompute(new); + hists__compute_resort(new); + } + hists__fprintf(new, true, 0, 0, stdout); } diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 1b633a4b5c4..659f2a25e99 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -242,24 +242,15 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) { - struct hist_entry *pair = he->pair; - struct hists *pair_hists = pair ? pair->hists : NULL; - struct hists *hists = he->hists; - u64 old_total, new_total; - double old_percent = 0, new_percent = 0; - double diff; const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; char buf[32] = " "; + double diff; - old_total = pair_hists ? pair_hists->stats.total_period : 0; - if (old_total > 0 && pair) - old_percent = 100.0 * pair->stat.period / old_total; - - new_total = hists->stats.total_period; - if (new_total > 0) - new_percent = 100.0 * he->stat.period / new_total; + if (he->diff.computed) + diff = he->diff.period_ratio_delta; + else + diff = perf_diff__compute_delta(he); - diff = new_percent - old_percent; if (fabs(diff) >= 0.01) scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); @@ -280,12 +271,14 @@ static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused) static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) { - struct hist_entry *pair = he->pair; - double new_period = he->stat.period; - double old_period = pair ? pair->stat.period : 0; - double ratio = pair ? new_period / old_period : 0; const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; char buf[32] = " "; + double ratio; + + if (he->diff.computed) + ratio = he->diff.period_ratio; + else + ratio = perf_diff__compute_ratio(he); if (ratio > 0.0) scnprintf(buf, sizeof(buf), "%+14.6F", ratio); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 7e4d4c26221..a7ea28a1d50 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -205,4 +205,6 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, unsigned int hists__sort_list_width(struct hists *self); +double perf_diff__compute_delta(struct hist_entry *he); +double perf_diff__compute_ratio(struct hist_entry *he); #endif /* __PERF_HIST_H */ diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 5786f323b59..337aeefa245 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -52,6 +52,19 @@ struct he_stat { u32 nr_events; }; +struct hist_entry_diff { + bool computed; + + /* PERF_HPP__DISPL */ + int displacement; + + /* PERF_HPP__DELTA */ + double period_ratio_delta; + + /* PERF_HPP__RATIO */ + double period_ratio; +}; + /** * struct hist_entry - histogram entry * @@ -67,6 +80,8 @@ struct hist_entry { u64 ip; s32 cpu; + struct hist_entry_diff diff; + /* XXX These two should move to some tree widget lib */ u16 row_offset; u16 nr_rows; -- cgit v1.2.3-70-g09d2 From 81d5f95819953321a2557b0656b24ea10af9629c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 5 Oct 2012 16:44:43 +0200 Subject: perf diff: Add weighted diff computation way to compare hist entries Adding 'wdiff' as new computation way to compare hist entries. If specified the 'Weighted diff' column is displayed with value 'd' computed as: d = B->period * WEIGHT-A - A->period * WEIGHT-B - A/B being matching hist entry from first/second file specified (or perf.data/perf.data.old) respectively. - period being the hist entry period value - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option behind ':' separator like '-c wdiff:1,2'. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1349448287-18919-5-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-diff.txt | 15 ++++- tools/perf/builtin-diff.c | 116 +++++++++++++++++++++++++++++++-- tools/perf/ui/hist.c | 30 +++++++++ tools/perf/util/hist.h | 2 + tools/perf/util/sort.h | 3 + 5 files changed, 160 insertions(+), 6 deletions(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index cff3d9b6e4a..fa413ac914f 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt @@ -78,7 +78,7 @@ OPTIONS -c:: --compute:: - Differential computation selection - delta,ratio (default is delta). + Differential computation selection - delta,ratio,wdiff (default is delta). If '+' is specified as a first character, the output is sorted based on the computation results. See COMPARISON METHODS section for more info. @@ -110,6 +110,19 @@ with: - period being the hist entry period value +wdiff +~~~~~ +If specified the 'Weighted diff' column is displayed with value 'd' computed as: + + d = B->period * WEIGHT-A - A->period * WEIGHT-B + + - A/B being matching hist entry from first/second file specified + (or perf.data/perf.data.old) respectively. + + - period being the hist entry period value + + - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option + behind ':' separator like '-c wdiff:1,2'. SEE ALSO -------- diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index e13cfac0b06..d78e8386e1a 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -27,24 +27,81 @@ static bool show_displacement; static bool show_baseline_only; static bool sort_compute; +static s64 compute_wdiff_w1; +static s64 compute_wdiff_w2; + enum { COMPUTE_DELTA, COMPUTE_RATIO, + COMPUTE_WEIGHTED_DIFF, COMPUTE_MAX, }; const char *compute_names[COMPUTE_MAX] = { [COMPUTE_DELTA] = "delta", [COMPUTE_RATIO] = "ratio", + [COMPUTE_WEIGHTED_DIFF] = "wdiff", }; static int compute; +static int setup_compute_opt_wdiff(char *opt) +{ + char *w1_str = opt; + char *w2_str; + + int ret = -EINVAL; + + if (!opt) + goto out; + + w2_str = strchr(opt, ','); + if (!w2_str) + goto out; + + *w2_str++ = 0x0; + if (!*w2_str) + goto out; + + compute_wdiff_w1 = strtol(w1_str, NULL, 10); + compute_wdiff_w2 = strtol(w2_str, NULL, 10); + + if (!compute_wdiff_w1 || !compute_wdiff_w2) + goto out; + + pr_debug("compute wdiff w1(%" PRId64 ") w2(%" PRId64 ")\n", + compute_wdiff_w1, compute_wdiff_w2); + + ret = 0; + + out: + if (ret) + pr_err("Failed: wrong weight data, use 'wdiff:w1,w2'\n"); + + return ret; +} + +static int setup_compute_opt(char *opt) +{ + if (compute == COMPUTE_WEIGHTED_DIFF) + return setup_compute_opt_wdiff(opt); + + if (opt) { + pr_err("Failed: extra option specified '%s'", opt); + return -EINVAL; + } + + return 0; +} + static int setup_compute(const struct option *opt, const char *str, int unset __maybe_unused) { int *cp = (int *) opt->value; + char *cstr = (char *) str; + char buf[50]; unsigned i; + char *option; if (!str) { *cp = COMPUTE_DELTA; @@ -53,19 +110,37 @@ static int setup_compute(const struct option *opt, const char *str, if (*str == '+') { sort_compute = true; - str++; + cstr = (char *) ++str; if (!*str) return 0; } + option = strchr(str, ':'); + if (option) { + unsigned len = option++ - str; + + /* + * The str data are not writeable, so we need + * to use another buffer. + */ + + /* No option value is longer. */ + if (len >= sizeof(buf)) + return -EINVAL; + + strncpy(buf, str, len); + buf[len] = 0x0; + cstr = buf; + } + for (i = 0; i < COMPUTE_MAX; i++) - if (!strcmp(str, compute_names[i])) { + if (!strcmp(cstr, compute_names[i])) { *cp = i; - return 0; + return setup_compute_opt(option); } pr_err("Failed: '%s' is not computation method " - "(use 'delta' or 'ratio').\n", str); + "(use 'delta','ratio' or 'wdiff')\n", str); return -EINVAL; } @@ -97,6 +172,23 @@ double perf_diff__compute_ratio(struct hist_entry *he) return he->diff.period_ratio; } +s64 perf_diff__compute_wdiff(struct hist_entry *he) +{ + struct hist_entry *pair = he->pair; + u64 new_period = he->stat.period; + u64 old_period = pair ? pair->stat.period : 0; + + he->diff.computed = true; + + if (!pair) + he->diff.wdiff = 0; + else + he->diff.wdiff = new_period * compute_wdiff_w2 - + old_period * compute_wdiff_w1; + + return he->diff.wdiff; +} + static int hists__add_entry(struct hists *self, struct addr_location *al, u64 period) { @@ -275,6 +367,9 @@ static void hists__precompute(struct hists *hists) case COMPUTE_RATIO: perf_diff__compute_ratio(he); break; + case COMPUTE_WEIGHTED_DIFF: + perf_diff__compute_wdiff(he); + break; default: BUG_ON(1); } @@ -310,6 +405,13 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, return cmp_doubles(l, r); } + case COMPUTE_WEIGHTED_DIFF: + { + s64 l = left->diff.wdiff; + s64 r = right->diff.wdiff; + + return r - l; + } default: BUG_ON(1); } @@ -434,7 +536,8 @@ static const struct option options[] = { "Show position displacement relative to baseline"), OPT_BOOLEAN('b', "baseline-only", &show_baseline_only, "Show only items with match in baseline"), - OPT_CALLBACK('c', "compute", &compute, "delta,ratio (default delta)", + OPT_CALLBACK('c', "compute", &compute, + "delta,ratio,wdiff:w1,w2 (default delta)", "Entries differential computation selection", setup_compute), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, @@ -475,6 +578,9 @@ static void ui_init(void) case COMPUTE_RATIO: perf_hpp__column_enable(PERF_HPP__RATIO, true); break; + case COMPUTE_WEIGHTED_DIFF: + perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF, true); + break; default: BUG_ON(1); }; diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 659f2a25e99..522b4ec051d 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -286,6 +286,35 @@ static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) return scnprintf(hpp->buf, hpp->size, fmt, buf); } +static int hpp__header_wdiff(struct perf_hpp *hpp) +{ + const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; + + return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff"); +} + +static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused) +{ + return 14; +} + +static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) +{ + const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; + char buf[32] = " "; + s64 wdiff; + + if (he->diff.computed) + wdiff = he->diff.wdiff; + else + wdiff = perf_diff__compute_wdiff(he); + + if (wdiff != 0) + scnprintf(buf, sizeof(buf), "%14ld", wdiff); + + return scnprintf(hpp->buf, hpp->size, fmt, buf); +} + static int hpp__header_displ(struct perf_hpp *hpp) { return scnprintf(hpp->buf, hpp->size, "Displ."); @@ -332,6 +361,7 @@ struct perf_hpp_fmt perf_hpp__format[] = { { .cond = false, HPP__PRINT_FNS(period) }, { .cond = false, HPP__PRINT_FNS(delta) }, { .cond = false, HPP__PRINT_FNS(ratio) }, + { .cond = false, HPP__PRINT_FNS(wdiff) }, { .cond = false, HPP__PRINT_FNS(displ) } }; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index a7ea28a1d50..ce76f36aeb0 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -142,6 +142,7 @@ enum { PERF_HPP__PERIOD, PERF_HPP__DELTA, PERF_HPP__RATIO, + PERF_HPP__WEIGHTED_DIFF, PERF_HPP__DISPL, PERF_HPP__MAX_INDEX @@ -207,4 +208,5 @@ unsigned int hists__sort_list_width(struct hists *self); double perf_diff__compute_delta(struct hist_entry *he); double perf_diff__compute_ratio(struct hist_entry *he); +s64 perf_diff__compute_wdiff(struct hist_entry *he); #endif /* __PERF_HIST_H */ diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 337aeefa245..13761d83a5a 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -63,6 +63,9 @@ struct hist_entry_diff { /* PERF_HPP__RATIO */ double period_ratio; + + /* HISTC_WEIGHTED_DIFF */ + s64 wdiff; }; /** -- cgit v1.2.3-70-g09d2 From 61949b212e7f6f8f31891236ba24033f9b7af8c3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 5 Oct 2012 16:44:44 +0200 Subject: perf diff: Add -p option to display period values for hist entries Adding -p option to show period values for both compared hist entries. Showing hist column PERF_HPP__PERIOD and newly added hist column PERF_HPP__PERIOD_BASELINE. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1349448287-18919-6-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-diff.txt | 4 ++++ tools/perf/builtin-diff.c | 10 +++++++++- tools/perf/ui/hist.c | 21 +++++++++++++++++++++ tools/perf/util/hist.h | 1 + 4 files changed, 35 insertions(+), 1 deletion(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index fa413ac914f..21cc2ef7756 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt @@ -83,6 +83,10 @@ OPTIONS on the computation results. See COMPARISON METHODS section for more info. +-p:: +--period:: + Show period values for both compared hist entries. + COMPARISON METHODS ------------------ delta diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index d78e8386e1a..2411dd18c55 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -24,6 +24,7 @@ static char const *input_old = "perf.data.old", static char diff__default_sort_order[] = "dso,symbol"; static bool force; static bool show_displacement; +static bool show_period; static bool show_baseline_only; static bool sort_compute; @@ -540,6 +541,8 @@ static const struct option options[] = { "delta,ratio,wdiff:w1,w2 (default delta)", "Entries differential computation selection", setup_compute), + OPT_BOOLEAN('p', "period", &show_period, + "Show period values."), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), @@ -568,7 +571,7 @@ static void ui_init(void) /* No overhead column. */ perf_hpp__column_enable(PERF_HPP__OVERHEAD, false); - /* Display baseline/delta/ratio/displacement columns. */ + /* Display baseline/delta/ratio/displacement/periods columns. */ perf_hpp__column_enable(PERF_HPP__BASELINE, true); switch (compute) { @@ -587,6 +590,11 @@ static void ui_init(void) if (show_displacement) perf_hpp__column_enable(PERF_HPP__DISPL, true); + + if (show_period) { + perf_hpp__column_enable(PERF_HPP__PERIOD, true); + perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE, true); + } } int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 522b4ec051d..2fadaff6312 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -228,6 +228,26 @@ static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he) return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period); } +static int hpp__header_period_baseline(struct perf_hpp *hpp) +{ + const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; + + return scnprintf(hpp->buf, hpp->size, fmt, "Period Base"); +} + +static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused) +{ + return 12; +} + +static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he) +{ + struct hist_entry *pair = he->pair; + u64 period = pair ? pair->stat.period : 0; + const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; + + return scnprintf(hpp->buf, hpp->size, fmt, period); +} static int hpp__header_delta(struct perf_hpp *hpp) { const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; @@ -359,6 +379,7 @@ struct perf_hpp_fmt perf_hpp__format[] = { { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) }, { .cond = false, HPP__PRINT_FNS(samples) }, { .cond = false, HPP__PRINT_FNS(period) }, + { .cond = false, HPP__PRINT_FNS(period_baseline) }, { .cond = false, HPP__PRINT_FNS(delta) }, { .cond = false, HPP__PRINT_FNS(ratio) }, { .cond = false, HPP__PRINT_FNS(wdiff) }, diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ce76f36aeb0..5604791e5ed 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -140,6 +140,7 @@ enum { PERF_HPP__OVERHEAD_GUEST_US, PERF_HPP__SAMPLES, PERF_HPP__PERIOD, + PERF_HPP__PERIOD_BASELINE, PERF_HPP__DELTA, PERF_HPP__RATIO, PERF_HPP__WEIGHTED_DIFF, -- cgit v1.2.3-70-g09d2 From ed279da2fc9774b4c0dc9fd513fa89a11cae3f56 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 5 Oct 2012 16:44:45 +0200 Subject: perf diff: Add -F option to display formula for computation Adding -F option to display the formula for specified computation. This is mainly to facilitate debugging, but can be useful anyway. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1349448287-18919-7-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-diff.txt | 4 ++ tools/perf/builtin-diff.c | 67 +++++++++++++++++++++++++++++++++- tools/perf/ui/hist.c | 24 +++++++++++- tools/perf/ui/stdio/hist.c | 2 +- tools/perf/util/hist.h | 2 + 5 files changed, 96 insertions(+), 3 deletions(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 21cc2ef7756..194f37d635d 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt @@ -87,6 +87,10 @@ OPTIONS --period:: Show period values for both compared hist entries. +-F:: +--formula:: + Show formula for given computation. + COMPARISON METHODS ------------------ delta diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 2411dd18c55..dd9c064514f 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -25,6 +25,7 @@ static char diff__default_sort_order[] = "dso,symbol"; static bool force; static bool show_displacement; static bool show_period; +static bool show_formula; static bool show_baseline_only; static bool sort_compute; @@ -190,6 +191,62 @@ s64 perf_diff__compute_wdiff(struct hist_entry *he) return he->diff.wdiff; } +static int formula_delta(struct hist_entry *he, char *buf, size_t size) +{ + struct hist_entry *pair = he->pair; + + if (!pair) + return -1; + + return scnprintf(buf, size, + "(%" PRIu64 " * 100 / %" PRIu64 ") - " + "(%" PRIu64 " * 100 / %" PRIu64 ")", + he->stat.period, he->hists->stats.total_period, + pair->stat.period, pair->hists->stats.total_period); +} + +static int formula_ratio(struct hist_entry *he, char *buf, size_t size) +{ + struct hist_entry *pair = he->pair; + double new_period = he->stat.period; + double old_period = pair ? pair->stat.period : 0; + + if (!pair) + return -1; + + return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); +} + +static int formula_wdiff(struct hist_entry *he, char *buf, size_t size) +{ + struct hist_entry *pair = he->pair; + u64 new_period = he->stat.period; + u64 old_period = pair ? pair->stat.period : 0; + + if (!pair) + return -1; + + return scnprintf(buf, size, + "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", + new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); +} + +int perf_diff__formula(char *buf, size_t size, struct hist_entry *he) +{ + switch (compute) { + case COMPUTE_DELTA: + return formula_delta(he, buf, size); + case COMPUTE_RATIO: + return formula_ratio(he, buf, size); + case COMPUTE_WEIGHTED_DIFF: + return formula_wdiff(he, buf, size); + default: + BUG_ON(1); + } + + return -1; +} + static int hists__add_entry(struct hists *self, struct addr_location *al, u64 period) { @@ -543,6 +600,8 @@ static const struct option options[] = { setup_compute), OPT_BOOLEAN('p', "period", &show_period, "Show period values."), + OPT_BOOLEAN('F', "formula", &show_formula, + "Show formula."), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), @@ -571,7 +630,10 @@ static void ui_init(void) /* No overhead column. */ perf_hpp__column_enable(PERF_HPP__OVERHEAD, false); - /* Display baseline/delta/ratio/displacement/periods columns. */ + /* + * Display baseline/delta/ratio/displacement/ + * formula/periods columns. + */ perf_hpp__column_enable(PERF_HPP__BASELINE, true); switch (compute) { @@ -591,6 +653,9 @@ static void ui_init(void) if (show_displacement) perf_hpp__column_enable(PERF_HPP__DISPL, true); + if (show_formula) + perf_hpp__column_enable(PERF_HPP__FORMULA, true); + if (show_period) { perf_hpp__column_enable(PERF_HPP__PERIOD, true); perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE, true); diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 2fadaff6312..305eb79f4af 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -359,6 +359,27 @@ static int hpp__entry_displ(struct perf_hpp *hpp, return scnprintf(hpp->buf, hpp->size, fmt, buf); } +static int hpp__header_formula(struct perf_hpp *hpp) +{ + const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; + + return scnprintf(hpp->buf, hpp->size, fmt, "Formula"); +} + +static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused) +{ + return 70; +} + +static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) +{ + const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; + char buf[96] = " "; + + perf_diff__formula(buf, sizeof(buf), he); + return scnprintf(hpp->buf, hpp->size, fmt, buf); +} + #define HPP__COLOR_PRINT_FNS(_name) \ .header = hpp__header_ ## _name, \ .width = hpp__width_ ## _name, \ @@ -383,7 +404,8 @@ struct perf_hpp_fmt perf_hpp__format[] = { { .cond = false, HPP__PRINT_FNS(delta) }, { .cond = false, HPP__PRINT_FNS(ratio) }, { .cond = false, HPP__PRINT_FNS(wdiff) }, - { .cond = false, HPP__PRINT_FNS(displ) } + { .cond = false, HPP__PRINT_FNS(displ) }, + { .cond = false, HPP__PRINT_FNS(formula) } }; #undef HPP__COLOR_PRINT_FNS diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index fbd4e32d074..f0ee204f99b 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -342,7 +342,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, const char *sep = symbol_conf.field_sep; const char *col_width = symbol_conf.col_width_list_str; int idx, nr_rows = 0; - char bf[64]; + char bf[96]; struct perf_hpp dummy_hpp = { .buf = bf, .size = sizeof(bf), diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 5604791e5ed..c751624d415 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -145,6 +145,7 @@ enum { PERF_HPP__RATIO, PERF_HPP__WEIGHTED_DIFF, PERF_HPP__DISPL, + PERF_HPP__FORMULA, PERF_HPP__MAX_INDEX }; @@ -210,4 +211,5 @@ unsigned int hists__sort_list_width(struct hists *self); double perf_diff__compute_delta(struct hist_entry *he); double perf_diff__compute_ratio(struct hist_entry *he); s64 perf_diff__compute_wdiff(struct hist_entry *he); +int perf_diff__formula(char *buf, size_t size, struct hist_entry *he); #endif /* __PERF_HIST_H */ -- cgit v1.2.3-70-g09d2 From d88c48f9b5bfcbd2e296b2d240e8cb0aec99f042 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 5 Oct 2012 16:44:46 +0200 Subject: perf diff: Include samples without symbol in overall stats Currently we omit samples without symbols. This way we get different and confusing numbers for samples than from report command. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1349448287-18919-8-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index dd9c064514f..b4db5137519 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -269,7 +269,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, return -1; } - if (al.filtered || al.sym == NULL) + if (al.filtered) return 0; if (hists__add_entry(&evsel->hists, &al, sample->period)) { -- cgit v1.2.3-70-g09d2 From f62d3f0f4596f983ec00495d91c8ddb30268d878 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 6 Oct 2012 15:44:59 -0300 Subject: perf event: No need to create a thread when handling PERF_RECORD_EXIT When we were processing a PERF_RECORD_EXIT event we first used machine__findnew_thread for both the thread exiting and for its parent, only to use just the thread struct associated with the one exiting, and to just delete it. If it existed, i.e. not created at this very moment in machine__findnew_thread, it will be moved to the machine->dead_threads linked list, because we may have hist_entries pointing to it, but if it was created just do be deleted, it will just sit there with no references at all. Use the new machine__find_thread() method so that if it is not there, we don't create it. As a bonus the parent thread will also not be created at this point. Create process_fork() and process_exit() helpers to use this and make the builtins use it instead of the generic process_task(), ditched by this patch. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-z7n2y98ebjyrvmytaope4vdl@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-diff.c | 4 ++-- tools/perf/builtin-inject.c | 6 +++--- tools/perf/builtin-report.c | 4 ++-- tools/perf/builtin-sched.c | 2 +- tools/perf/builtin-script.c | 4 ++-- tools/perf/util/build-id.c | 2 +- tools/perf/util/event.c | 30 ++++++++++++++++++++++-------- tools/perf/util/event.h | 6 +++++- 9 files changed, 39 insertions(+), 21 deletions(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 9ea38540b87..cca2fb5c436 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -246,7 +246,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) .sample = process_sample_event, .mmap = perf_event__process_mmap, .comm = perf_event__process_comm, - .fork = perf_event__process_task, + .fork = perf_event__process_fork, .ordered_samples = true, .ordering_requires_timestamps = true, }, diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index b4db5137519..380683de1df 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -285,8 +285,8 @@ static struct perf_tool tool = { .sample = diff__process_sample_event, .mmap = perf_event__process_mmap, .comm = perf_event__process_comm, - .exit = perf_event__process_task, - .fork = perf_event__process_task, + .exit = perf_event__process_exit, + .fork = perf_event__process_fork, .lost = perf_event__process_lost, .ordered_samples = true, .ordering_requires_timestamps = true, diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 4688bea95c1..386a5c0013f 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -102,14 +102,14 @@ static int perf_event__repipe_mmap(struct perf_tool *tool, return err; } -static int perf_event__repipe_task(struct perf_tool *tool, +static int perf_event__repipe_fork(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) { int err; - err = perf_event__process_task(tool, event, sample, machine); + err = perf_event__process_fork(tool, event, sample, machine); perf_event__repipe(tool, event, sample, machine); return err; @@ -227,7 +227,7 @@ static int __cmd_inject(struct perf_inject *inject) if (inject->build_ids) { inject->tool.sample = perf_event__inject_buildid; inject->tool.mmap = perf_event__repipe_mmap; - inject->tool.fork = perf_event__repipe_task; + inject->tool.fork = perf_event__repipe_fork; inject->tool.tracing_data = perf_event__repipe_tracing_data; } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index a61725d89d3..5104a40af56 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -556,8 +556,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) .sample = process_sample_event, .mmap = perf_event__process_mmap, .comm = perf_event__process_comm, - .exit = perf_event__process_task, - .fork = perf_event__process_task, + .exit = perf_event__process_exit, + .fork = perf_event__process_fork, .lost = perf_event__process_lost, .read = process_read_event, .attr = perf_event__process_attr, diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 3488ead3b60..3a25cd83b56 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1672,7 +1672,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) .sample = perf_sched__process_tracepoint_sample, .comm = perf_event__process_comm, .lost = perf_event__process_lost, - .fork = perf_event__process_task, + .fork = perf_event__process_fork, .ordered_samples = true, }, .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index fb9625083a2..04ceb0779d3 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -520,8 +520,8 @@ static struct perf_tool perf_script = { .sample = process_sample_event, .mmap = perf_event__process_mmap, .comm = perf_event__process_comm, - .exit = perf_event__process_task, - .fork = perf_event__process_task, + .exit = perf_event__process_exit, + .fork = perf_event__process_fork, .attr = perf_event__process_attr, .event_type = perf_event__process_event_type, .tracing_data = perf_event__process_tracing_data, diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 8e3a740ddbd..6a6399955ef 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -64,7 +64,7 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, struct perf_tool build_id__mark_dso_hit_ops = { .sample = build_id__mark_dso_hit, .mmap = perf_event__process_mmap, - .fork = perf_event__process_task, + .fork = perf_event__process_fork, .exit = perf_event__exit_del_thread, .attr = perf_event__process_attr, .build_id = perf_event__process_build_id, diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 6715b193872..eaaee22628e 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -1,6 +1,7 @@ #include #include "event.h" #include "debug.h" +#include "machine.h" #include "sort.h" #include "string.h" #include "strlist.h" @@ -702,10 +703,10 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) event->fork.ppid, event->fork.ptid); } -int perf_event__process_task(struct perf_tool *tool __maybe_unused, +int perf_event__process_fork(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample __maybe_unused, - struct machine *machine) + struct machine *machine) { struct thread *thread = machine__findnew_thread(machine, event->fork.tid); struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); @@ -713,11 +714,6 @@ int perf_event__process_task(struct perf_tool *tool __maybe_unused, if (dump_trace) perf_event__fprintf_task(event, stdout); - if (event->header.type == PERF_RECORD_EXIT) { - machine__remove_thread(machine, thread); - return 0; - } - if (thread == NULL || parent == NULL || thread__fork(thread, parent) < 0) { dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); @@ -727,6 +723,22 @@ int perf_event__process_task(struct perf_tool *tool __maybe_unused, return 0; } +int perf_event__process_exit(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine) +{ + struct thread *thread = machine__find_thread(machine, event->fork.tid); + + if (dump_trace) + perf_event__fprintf_task(event, stdout); + + if (thread != NULL) + machine__remove_thread(machine, thread); + + return 0; +} + size_t perf_event__fprintf(union perf_event *event, FILE *fp) { size_t ret = fprintf(fp, "PERF_RECORD_%s", @@ -761,8 +773,10 @@ int perf_event__process(struct perf_tool *tool, union perf_event *event, perf_event__process_mmap(tool, event, sample, machine); break; case PERF_RECORD_FORK: + perf_event__process_fork(tool, event, sample, machine); + break; case PERF_RECORD_EXIT: - perf_event__process_task(tool, event, sample, machine); + perf_event__process_exit(tool, event, sample, machine); break; case PERF_RECORD_LOST: perf_event__process_lost(tool, event, sample, machine); diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 21b99e741a8..da97aff5bd7 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -191,7 +191,11 @@ int perf_event__process_mmap(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); -int perf_event__process_task(struct perf_tool *tool, +int perf_event__process_fork(struct perf_tool *tool, + union perf_event *event, + struct perf_sample *sample, + struct machine *machine); +int perf_event__process_exit(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); -- cgit v1.2.3-70-g09d2 From b821c7325354c589ccc9611cf9e6b0d7490ed6a6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 25 Oct 2012 14:42:45 -0200 Subject: perf diff: Start moving to support matching more than two hists We want to match more than two hists, so that we can match more than two perf.data files and moreover, match hist_entries (buckets) in multiple events in a group. So the "baseline"/"leader" will instead of a ->pair pointer, use a list_head, that will link to the pairs and hists__match use it. Following that perf_evlist__link will link the hists in its evsel groups. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-2kbmzepoi544ygj9godseqpv@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 21 ++++++++++++--------- tools/perf/ui/hist.c | 10 +++++----- tools/perf/util/hist.c | 2 ++ tools/perf/util/sort.h | 27 +++++++++++++++++++++++---- 4 files changed, 42 insertions(+), 18 deletions(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 380683de1df..8a9db38e562 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -154,7 +154,7 @@ static double get_period_percent(struct hist_entry *he, u64 period) double perf_diff__compute_delta(struct hist_entry *he) { - struct hist_entry *pair = he->pair; + struct hist_entry *pair = hist_entry__next_pair(he); double new_percent = get_period_percent(he, he->stat.period); double old_percent = pair ? get_period_percent(pair, pair->stat.period) : 0.0; @@ -165,7 +165,7 @@ double perf_diff__compute_delta(struct hist_entry *he) double perf_diff__compute_ratio(struct hist_entry *he) { - struct hist_entry *pair = he->pair; + struct hist_entry *pair = hist_entry__next_pair(he); double new_period = he->stat.period; double old_period = pair ? pair->stat.period : 0; @@ -176,7 +176,7 @@ double perf_diff__compute_ratio(struct hist_entry *he) s64 perf_diff__compute_wdiff(struct hist_entry *he) { - struct hist_entry *pair = he->pair; + struct hist_entry *pair = hist_entry__next_pair(he); u64 new_period = he->stat.period; u64 old_period = pair ? pair->stat.period : 0; @@ -193,7 +193,7 @@ s64 perf_diff__compute_wdiff(struct hist_entry *he) static int formula_delta(struct hist_entry *he, char *buf, size_t size) { - struct hist_entry *pair = he->pair; + struct hist_entry *pair = hist_entry__next_pair(he); if (!pair) return -1; @@ -207,7 +207,7 @@ static int formula_delta(struct hist_entry *he, char *buf, size_t size) static int formula_ratio(struct hist_entry *he, char *buf, size_t size) { - struct hist_entry *pair = he->pair; + struct hist_entry *pair = hist_entry__next_pair(he); double new_period = he->stat.period; double old_period = pair ? pair->stat.period : 0; @@ -219,7 +219,7 @@ static int formula_ratio(struct hist_entry *he, char *buf, size_t size) static int formula_wdiff(struct hist_entry *he, char *buf, size_t size) { - struct hist_entry *pair = he->pair; + struct hist_entry *pair = hist_entry__next_pair(he); u64 new_period = he->stat.period; u64 old_period = pair ? pair->stat.period : 0; @@ -359,8 +359,11 @@ static void hists__match(struct hists *older, struct hists *newer) struct rb_node *nd; for (nd = rb_first(&newer->entries); nd; nd = rb_next(nd)) { - struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node); - pos->pair = hists__find_entry(older, pos); + struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node), + *pair = hists__find_entry(older, pos); + + if (pair) + hist__entry_add_pair(pos, pair); } } @@ -402,7 +405,7 @@ static void hists__baseline_only(struct hists *hists) struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); next = rb_next(&he->rb_node); - if (!he->pair) { + if (!hist_entry__next_pair(he)) { rb_erase(&he->rb_node, &hists->entries); hist_entry__free(he); } diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 4f5f4756faa..aa84130024d 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -161,7 +161,7 @@ static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused) static double baseline_percent(struct hist_entry *he) { - struct hist_entry *pair = he->pair; + struct hist_entry *pair = hist_entry__next_pair(he); struct hists *pair_hists = pair ? pair->hists : NULL; double percent = 0.0; @@ -179,7 +179,7 @@ static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he) { double percent = baseline_percent(he); - if (he->pair) + if (hist_entry__has_pairs(he)) return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); else return scnprintf(hpp->buf, hpp->size, " "); @@ -190,7 +190,7 @@ static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) double percent = baseline_percent(he); const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; - if (he->pair || symbol_conf.field_sep) + if (hist_entry__has_pairs(he) || symbol_conf.field_sep) return scnprintf(hpp->buf, hpp->size, fmt, percent); else return scnprintf(hpp->buf, hpp->size, " "); @@ -248,7 +248,7 @@ static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused) static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he) { - struct hist_entry *pair = he->pair; + struct hist_entry *pair = hist_entry__next_pair(he); u64 period = pair ? pair->stat.period : 0; const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; @@ -354,7 +354,7 @@ static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused) static int hpp__entry_displ(struct perf_hpp *hpp, struct hist_entry *he) { - struct hist_entry *pair = he->pair; + struct hist_entry *pair = hist_entry__next_pair(he); long displacement = pair ? pair->position - he->position : 0; const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s"; char buf[32] = " "; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index a1b823f8c17..f42de79d2e6 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -244,6 +244,8 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) he->ms.map->referenced = true; if (symbol_conf.use_callchain) callchain_init(he->callchain); + + INIT_LIST_HEAD(&he->pairs.node); } return he; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 13761d83a5a..b4e8c3ba559 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -77,6 +77,10 @@ struct hist_entry_diff { struct hist_entry { struct rb_node rb_node_in; struct rb_node rb_node; + union { + struct list_head node; + struct list_head head; + } pairs; struct he_stat stat; struct map_symbol ms; struct thread *thread; @@ -96,15 +100,30 @@ struct hist_entry { char *srcline; struct symbol *parent; unsigned long position; - union { - struct hist_entry *pair; - struct rb_root sorted_chain; - }; + struct rb_root sorted_chain; struct branch_info *branch_info; struct hists *hists; struct callchain_root callchain[0]; }; +static inline bool hist_entry__has_pairs(struct hist_entry *he) +{ + return !list_empty(&he->pairs.node); +} + +static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he) +{ + if (hist_entry__has_pairs(he)) + return list_entry(he->pairs.node.next, struct hist_entry, pairs.node); + return NULL; +} + +static inline void hist__entry_add_pair(struct hist_entry *he, + struct hist_entry *pair) +{ + list_add_tail(&he->pairs.head, &pair->pairs.node); +} + enum sort_type { SORT_PID, SORT_COMM, -- cgit v1.2.3-70-g09d2 From 95529be47855be6350dfd0b9cd09ea863ca7421f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 8 Nov 2012 17:54:33 -0300 Subject: perf diff: Move hists__match to the hists lib Its not 'diff' specific and will be useful for other use cases, like bucketizing multiple events in a single session. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-o35urjgxfxxm70aw1wa81s4w@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 35 +---------------------------------- tools/perf/util/hist.c | 37 +++++++++++++++++++++++++++++++++++++ tools/perf/util/hist.h | 2 ++ 3 files changed, 40 insertions(+), 34 deletions(-) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 8a9db38e562..e99fb3bc1c2 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -334,39 +334,6 @@ static void hists__name_resort(struct hists *self, bool sort) self->entries = tmp; } -static struct hist_entry *hists__find_entry(struct hists *self, - struct hist_entry *he) -{ - struct rb_node *n = self->entries.rb_node; - - while (n) { - struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); - int64_t cmp = hist_entry__cmp(he, iter); - - if (cmp < 0) - n = n->rb_left; - else if (cmp > 0) - n = n->rb_right; - else - return iter; - } - - return NULL; -} - -static void hists__match(struct hists *older, struct hists *newer) -{ - struct rb_node *nd; - - for (nd = rb_first(&newer->entries); nd; nd = rb_next(nd)) { - struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node), - *pair = hists__find_entry(older, pos); - - if (pair) - hist__entry_add_pair(pos, pair); - } -} - static struct perf_evsel *evsel_match(struct perf_evsel *evsel, struct perf_evlist *evlist) { @@ -520,7 +487,7 @@ static void hists__compute_resort(struct hists *hists) static void hists__process(struct hists *old, struct hists *new) { - hists__match(old, new); + hists__match(new, old); if (show_baseline_only) hists__baseline_only(new); diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index f42de79d2e6..c1de3b05fe0 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -716,3 +716,40 @@ void hists__inc_nr_events(struct hists *hists, u32 type) ++hists->stats.nr_events[0]; ++hists->stats.nr_events[type]; } + +static struct hist_entry *hists__find_entry(struct hists *hists, + struct hist_entry *he) +{ + struct rb_node *n = hists->entries.rb_node; + + while (n) { + struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); + int64_t cmp = hist_entry__cmp(he, iter); + + if (cmp < 0) + n = n->rb_left; + else if (cmp > 0) + n = n->rb_right; + else + return iter; + } + + return NULL; +} + +/* + * Look for pairs to link to the leader buckets (hist_entries): + */ +void hists__match(struct hists *leader, struct hists *other) +{ + struct rb_node *nd; + struct hist_entry *pos, *pair; + + for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) { + pos = rb_entry(nd, struct hist_entry, rb_node); + pair = hists__find_entry(other, pos); + + if (pair) + hist__entry_add_pair(pos, pair); + } +} diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index a4f45dd0469..ff1c3963e04 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -115,6 +115,8 @@ bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); void hists__reset_col_len(struct hists *hists); void hists__calc_col_len(struct hists *hists, struct hist_entry *he); +void hists__match(struct hists *leader, struct hists *other); + struct perf_hpp { char *buf; size_t size; -- cgit v1.2.3-70-g09d2 From bfaef4b46b17ff053dc38f979cec364b0715cabb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 8 Nov 2012 18:08:26 -0300 Subject: perf diff: Use hists__link when not pairing just with baseline Previously there were blind spots because we were not looking at symbols that didn't ocurred in the latest run: # perf record usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.018 MB perf.data (~801 samples) ] # perf record usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.018 MB perf.data (~801 samples) ] Before: # perf diff # Event 'cycles' # # Baseline Delta Shared Object Symbol # ........ ....... ................. ............................. # +10.38% [kernel.kallsyms] [k] get_empty_filp +9.51% [kernel.kallsyms] [k] update_sd_lb_stats +9.41% libpopt.so.0.0.0 [.] _init +9.29% [kernel.kallsyms] [k] vma_interval_tree_insert 9.05% +0.12% [kernel.kallsyms] [k] do_sys_open +9.14% [kernel.kallsyms] [k] kfree +8.98% [kernel.kallsyms] [k] free_pages_and_swap_cache +8.78% [kernel.kallsyms] [k] unmap_page_range 9.36% -0.90% [kernel.kallsyms] [k] zap_pte_range 7.60% +0.09% [kernel.kallsyms] [k] find_next_bit +4.37% [kernel.kallsyms] [k] place_entity +3.38% [kernel.kallsyms] [k] __do_page_fault +0.80% [kernel.kallsyms] [k] native_apic_mem_write 0.21% +0.43% [kernel.kallsyms] [k] native_write_msr_safe # So 9.05 + 9.36 + 7.60 + 0.21 != 100% Now using the recently introduced hists__link we can see the whole picture: # perf diff # Event 'cycles' # # Baseline Delta Shared Object Symbol # ........ ....... ................. ............................. # 8.44% -8.44% [kernel.kallsyms] [k] _raw_spin_lock 9.05% -9.05% [kernel.kallsyms] [k] sha_transform 10.55% -10.55% [kernel.kallsyms] [k] __d_lookup_rcu +10.38% [kernel.kallsyms] [k] get_empty_filp 17.70% -17.70% [kernel.kallsyms] [k] kmem_cache_free +9.51% [kernel.kallsyms] [k] update_sd_lb_stats +9.41% libpopt.so.0.0.0 [.] _init +9.29% [kernel.kallsyms] [k] vma_interval_tree_insert 9.05% +0.12% [kernel.kallsyms] [k] do_sys_open +9.14% [kernel.kallsyms] [k] kfree +8.98% [kernel.kallsyms] [k] free_pages_and_swap_cache +8.78% [kernel.kallsyms] [k] unmap_page_range 9.36% -0.90% [kernel.kallsyms] [k] zap_pte_range 7.60% +0.09% [kernel.kallsyms] [k] find_next_bit +4.37% [kernel.kallsyms] [k] place_entity +3.38% [kernel.kallsyms] [k] __do_page_fault 4.01% -4.01% [kernel.kallsyms] [k] handle_pte_fault 9.27% -9.27% [kernel.kallsyms] [k] find_get_page 0.78% -0.78% [kernel.kallsyms] [k] rcu_irq_enter 0.57% -0.57% [kernel.kallsyms] [k] finish_task_switch 4.25% -4.25% [kernel.kallsyms] [k] run_timer_softirq +0.80% [kernel.kallsyms] [k] native_apic_mem_write 0.21% +0.43% [kernel.kallsyms] [k] native_write_msr_safe 9.16% -9.16% ld-2.12.so [.] close # Now: 8.44 + 9.05 + 10.55 + 17.70 + 9.05 + 9.36 + 7.60 + 4.01 + 9.27 + 0.78 + 0.57 + 4.25 + 0.21 + 9.16 == 100% Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-jeq55qdgby1745bs8r9sscdh@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-diff.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/perf/builtin-diff.c') diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index e99fb3bc1c2..93b852f8a5d 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -491,6 +491,8 @@ static void hists__process(struct hists *old, struct hists *new) if (show_baseline_only) hists__baseline_only(new); + else + hists__link(new, old); if (sort_compute) { hists__precompute(new); -- cgit v1.2.3-70-g09d2