aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@redhat.com>2012-10-05 10:44:42 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2012-10-05 13:08:54 -0400
commit96c47f19846742bdfa3c153c8d26ccca5945586b (patch)
tree209bbd497e4ddc814718fd8963abd615850e412d /tools/perf
parent7aaf6b35512382329c5b2dd46b42f2bf12a5fff0 (diff)
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 <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.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-diff.txt2
-rw-r--r--tools/perf/builtin-diff.c137
-rw-r--r--tools/perf/ui/hist.c29
-rw-r--r--tools/perf/util/hist.h2
-rw-r--r--tools/perf/util/sort.h15
5 files changed, 167 insertions, 18 deletions
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 8fff0618c597..cff3d9b6e4a3 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -79,6 +79,8 @@ OPTIONS
79-c:: 79-c::
80--compute:: 80--compute::
81 Differential computation selection - delta,ratio (default is delta). 81 Differential computation selection - delta,ratio (default is delta).
82 If '+' is specified as a first character, the output is sorted based
83 on the computation results.
82 See COMPARISON METHODS section for more info. 84 See COMPARISON METHODS section for more info.
83 85
84COMPARISON METHODS 86COMPARISON METHODS
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index e90c06aea4d4..e13cfac0b063 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";
25static bool force; 25static bool force;
26static bool show_displacement; 26static bool show_displacement;
27static bool show_baseline_only; 27static bool show_baseline_only;
28static bool sort_compute;
28 29
29enum { 30enum {
30 COMPUTE_DELTA, 31 COMPUTE_DELTA,
@@ -50,6 +51,13 @@ static int setup_compute(const struct option *opt, const char *str,
50 return 0; 51 return 0;
51 } 52 }
52 53
54 if (*str == '+') {
55 sort_compute = true;
56 str++;
57 if (!*str)
58 return 0;
59 }
60
53 for (i = 0; i < COMPUTE_MAX; i++) 61 for (i = 0; i < COMPUTE_MAX; i++)
54 if (!strcmp(str, compute_names[i])) { 62 if (!strcmp(str, compute_names[i])) {
55 *cp = i; 63 *cp = i;
@@ -61,6 +69,34 @@ static int setup_compute(const struct option *opt, const char *str,
61 return -EINVAL; 69 return -EINVAL;
62} 70}
63 71
72static double get_period_percent(struct hist_entry *he, u64 period)
73{
74 u64 total = he->hists->stats.total_period;
75 return (period * 100.0) / total;
76}
77
78double perf_diff__compute_delta(struct hist_entry *he)
79{
80 struct hist_entry *pair = he->pair;
81 double new_percent = get_period_percent(he, he->stat.period);
82 double old_percent = pair ? get_period_percent(pair, pair->stat.period) : 0.0;
83
84 he->diff.period_ratio_delta = new_percent - old_percent;
85 he->diff.computed = true;
86 return he->diff.period_ratio_delta;
87}
88
89double perf_diff__compute_ratio(struct hist_entry *he)
90{
91 struct hist_entry *pair = he->pair;
92 double new_period = he->stat.period;
93 double old_period = pair ? pair->stat.period : 0;
94
95 he->diff.computed = true;
96 he->diff.period_ratio = pair ? (new_period / old_period) : 0;
97 return he->diff.period_ratio;
98}
99
64static int hists__add_entry(struct hists *self, 100static int hists__add_entry(struct hists *self,
65 struct addr_location *al, u64 period) 101 struct addr_location *al, u64 period)
66{ 102{
@@ -223,6 +259,102 @@ static void hists__baseline_only(struct hists *hists)
223 } 259 }
224} 260}
225 261
262static void hists__precompute(struct hists *hists)
263{
264 struct rb_node *next = rb_first(&hists->entries);
265
266 while (next != NULL) {
267 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
268
269 next = rb_next(&he->rb_node);
270
271 switch (compute) {
272 case COMPUTE_DELTA:
273 perf_diff__compute_delta(he);
274 break;
275 case COMPUTE_RATIO:
276 perf_diff__compute_ratio(he);
277 break;
278 default:
279 BUG_ON(1);
280 }
281 }
282}
283
284static int64_t cmp_doubles(double l, double r)
285{
286 if (l > r)
287 return -1;
288 else if (l < r)
289 return 1;
290 else
291 return 0;
292}
293
294static int64_t
295hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
296 int c)
297{
298 switch (c) {
299 case COMPUTE_DELTA:
300 {
301 double l = left->diff.period_ratio_delta;
302 double r = right->diff.period_ratio_delta;
303
304 return cmp_doubles(l, r);
305 }
306 case COMPUTE_RATIO:
307 {
308 double l = left->diff.period_ratio;
309 double r = right->diff.period_ratio;
310
311 return cmp_doubles(l, r);
312 }
313 default:
314 BUG_ON(1);
315 }
316
317 return 0;
318}
319
320static void insert_hist_entry_by_compute(struct rb_root *root,
321 struct hist_entry *he,
322 int c)
323{
324 struct rb_node **p = &root->rb_node;
325 struct rb_node *parent = NULL;
326 struct hist_entry *iter;
327
328 while (*p != NULL) {
329 parent = *p;
330 iter = rb_entry(parent, struct hist_entry, rb_node);
331 if (hist_entry__cmp_compute(he, iter, c) < 0)
332 p = &(*p)->rb_left;
333 else
334 p = &(*p)->rb_right;
335 }
336
337 rb_link_node(&he->rb_node, parent, p);
338 rb_insert_color(&he->rb_node, root);
339}
340
341static void hists__compute_resort(struct hists *hists)
342{
343 struct rb_root tmp = RB_ROOT;
344 struct rb_node *next = rb_first(&hists->entries);
345
346 while (next != NULL) {
347 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
348
349 next = rb_next(&he->rb_node);
350
351 rb_erase(&he->rb_node, &hists->entries);
352 insert_hist_entry_by_compute(&tmp, he, compute);
353 }
354
355 hists->entries = tmp;
356}
357
226static void hists__process(struct hists *old, struct hists *new) 358static void hists__process(struct hists *old, struct hists *new)
227{ 359{
228 hists__match(old, new); 360 hists__match(old, new);
@@ -230,6 +362,11 @@ static void hists__process(struct hists *old, struct hists *new)
230 if (show_baseline_only) 362 if (show_baseline_only)
231 hists__baseline_only(new); 363 hists__baseline_only(new);
232 364
365 if (sort_compute) {
366 hists__precompute(new);
367 hists__compute_resort(new);
368 }
369
233 hists__fprintf(new, true, 0, 0, stdout); 370 hists__fprintf(new, true, 0, 0, stdout);
234} 371}
235 372
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 1b633a4b5c45..659f2a25e997 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)
242 242
243static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) 243static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
244{ 244{
245 struct hist_entry *pair = he->pair;
246 struct hists *pair_hists = pair ? pair->hists : NULL;
247 struct hists *hists = he->hists;
248 u64 old_total, new_total;
249 double old_percent = 0, new_percent = 0;
250 double diff;
251 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; 245 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
252 char buf[32] = " "; 246 char buf[32] = " ";
247 double diff;
253 248
254 old_total = pair_hists ? pair_hists->stats.total_period : 0; 249 if (he->diff.computed)
255 if (old_total > 0 && pair) 250 diff = he->diff.period_ratio_delta;
256 old_percent = 100.0 * pair->stat.period / old_total; 251 else
257 252 diff = perf_diff__compute_delta(he);
258 new_total = hists->stats.total_period;
259 if (new_total > 0)
260 new_percent = 100.0 * he->stat.period / new_total;
261 253
262 diff = new_percent - old_percent;
263 if (fabs(diff) >= 0.01) 254 if (fabs(diff) >= 0.01)
264 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); 255 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
265 256
@@ -280,12 +271,14 @@ static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
280 271
281static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) 272static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
282{ 273{
283 struct hist_entry *pair = he->pair;
284 double new_period = he->stat.period;
285 double old_period = pair ? pair->stat.period : 0;
286 double ratio = pair ? new_period / old_period : 0;
287 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; 274 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
288 char buf[32] = " "; 275 char buf[32] = " ";
276 double ratio;
277
278 if (he->diff.computed)
279 ratio = he->diff.period_ratio;
280 else
281 ratio = perf_diff__compute_ratio(he);
289 282
290 if (ratio > 0.0) 283 if (ratio > 0.0)
291 scnprintf(buf, sizeof(buf), "%+14.6F", ratio); 284 scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 7e4d4c262213..a7ea28a1d502 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,
205 205
206unsigned int hists__sort_list_width(struct hists *self); 206unsigned int hists__sort_list_width(struct hists *self);
207 207
208double perf_diff__compute_delta(struct hist_entry *he);
209double perf_diff__compute_ratio(struct hist_entry *he);
208#endif /* __PERF_HIST_H */ 210#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 5786f323b597..337aeefa2451 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -52,6 +52,19 @@ struct he_stat {
52 u32 nr_events; 52 u32 nr_events;
53}; 53};
54 54
55struct hist_entry_diff {
56 bool computed;
57
58 /* PERF_HPP__DISPL */
59 int displacement;
60
61 /* PERF_HPP__DELTA */
62 double period_ratio_delta;
63
64 /* PERF_HPP__RATIO */
65 double period_ratio;
66};
67
55/** 68/**
56 * struct hist_entry - histogram entry 69 * struct hist_entry - histogram entry
57 * 70 *
@@ -67,6 +80,8 @@ struct hist_entry {
67 u64 ip; 80 u64 ip;
68 s32 cpu; 81 s32 cpu;
69 82
83 struct hist_entry_diff diff;
84
70 /* XXX These two should move to some tree widget lib */ 85 /* XXX These two should move to some tree widget lib */
71 u16 row_offset; 86 u16 row_offset;
72 u16 nr_rows; 87 u16 nr_rows;