Commit 96c47f19 authored by Jiri Olsa's avatar Jiri Olsa Committed by Arnaldo Carvalho de Melo

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: default avatarJiri Olsa <jolsa@redhat.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1349448287-18919-4-git-send-email-jolsa@redhat.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 7aaf6b35
...@@ -79,6 +79,8 @@ OPTIONS ...@@ -79,6 +79,8 @@ OPTIONS
-c:: -c::
--compute:: --compute::
Differential computation selection - delta,ratio (default is delta). 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. See COMPARISON METHODS section for more info.
COMPARISON METHODS COMPARISON METHODS
......
...@@ -25,6 +25,7 @@ static char diff__default_sort_order[] = "dso,symbol"; ...@@ -25,6 +25,7 @@ static char diff__default_sort_order[] = "dso,symbol";
static bool force; static bool force;
static bool show_displacement; static bool show_displacement;
static bool show_baseline_only; static bool show_baseline_only;
static bool sort_compute;
enum { enum {
COMPUTE_DELTA, COMPUTE_DELTA,
...@@ -50,6 +51,13 @@ static int setup_compute(const struct option *opt, const char *str, ...@@ -50,6 +51,13 @@ static int setup_compute(const struct option *opt, const char *str,
return 0; return 0;
} }
if (*str == '+') {
sort_compute = true;
str++;
if (!*str)
return 0;
}
for (i = 0; i < COMPUTE_MAX; i++) for (i = 0; i < COMPUTE_MAX; i++)
if (!strcmp(str, compute_names[i])) { if (!strcmp(str, compute_names[i])) {
*cp = i; *cp = i;
...@@ -61,6 +69,34 @@ static int setup_compute(const struct option *opt, const char *str, ...@@ -61,6 +69,34 @@ static int setup_compute(const struct option *opt, const char *str,
return -EINVAL; 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, static int hists__add_entry(struct hists *self,
struct addr_location *al, u64 period) struct addr_location *al, u64 period)
{ {
...@@ -223,6 +259,102 @@ static void hists__baseline_only(struct hists *hists) ...@@ -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) static void hists__process(struct hists *old, struct hists *new)
{ {
hists__match(old, new); hists__match(old, new);
...@@ -230,6 +362,11 @@ static void hists__process(struct hists *old, struct hists *new) ...@@ -230,6 +362,11 @@ static void hists__process(struct hists *old, struct hists *new)
if (show_baseline_only) if (show_baseline_only)
hists__baseline_only(new); hists__baseline_only(new);
if (sort_compute) {
hists__precompute(new);
hists__compute_resort(new);
}
hists__fprintf(new, true, 0, 0, stdout); hists__fprintf(new, true, 0, 0, stdout);
} }
......
...@@ -242,24 +242,15 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) ...@@ -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) 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"; const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
char buf[32] = " "; char buf[32] = " ";
double diff;
old_total = pair_hists ? pair_hists->stats.total_period : 0; if (he->diff.computed)
if (old_total > 0 && pair) diff = he->diff.period_ratio_delta;
old_percent = 100.0 * pair->stat.period / old_total; else
diff = perf_diff__compute_delta(he);
new_total = hists->stats.total_period;
if (new_total > 0)
new_percent = 100.0 * he->stat.period / new_total;
diff = new_percent - old_percent;
if (fabs(diff) >= 0.01) if (fabs(diff) >= 0.01)
scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
...@@ -280,12 +271,14 @@ static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused) ...@@ -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) 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"; const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
char buf[32] = " "; 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) if (ratio > 0.0)
scnprintf(buf, sizeof(buf), "%+14.6F", ratio); scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
......
...@@ -205,4 +205,6 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, ...@@ -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); 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 */ #endif /* __PERF_HIST_H */
...@@ -52,6 +52,19 @@ struct he_stat { ...@@ -52,6 +52,19 @@ struct he_stat {
u32 nr_events; 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 * struct hist_entry - histogram entry
* *
...@@ -67,6 +80,8 @@ struct hist_entry { ...@@ -67,6 +80,8 @@ struct hist_entry {
u64 ip; u64 ip;
s32 cpu; s32 cpu;
struct hist_entry_diff diff;
/* XXX These two should move to some tree widget lib */ /* XXX These two should move to some tree widget lib */
u16 row_offset; u16 row_offset;
u16 nr_rows; u16 nr_rows;
......
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