aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@redhat.com>2012-10-05 10:44:43 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2012-10-05 13:10:42 -0400
commit81d5f95819953321a2557b0656b24ea10af9629c (patch)
tree27efd993d93ab00da7fdfebe5c3563f1eba4d7f4
parent96c47f19846742bdfa3c153c8d26ccca5945586b (diff)
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 <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-5-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/Documentation/perf-diff.txt15
-rw-r--r--tools/perf/builtin-diff.c116
-rw-r--r--tools/perf/ui/hist.c30
-rw-r--r--tools/perf/util/hist.h2
-rw-r--r--tools/perf/util/sort.h3
5 files changed, 160 insertions, 6 deletions
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index cff3d9b6e4a3..fa413ac914f5 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -78,7 +78,7 @@ OPTIONS
78 78
79-c:: 79-c::
80--compute:: 80--compute::
81 Differential computation selection - delta,ratio (default is delta). 81 Differential computation selection - delta,ratio,wdiff (default is delta).
82 If '+' is specified as a first character, the output is sorted based 82 If '+' is specified as a first character, the output is sorted based
83 on the computation results. 83 on the computation results.
84 See COMPARISON METHODS section for more info. 84 See COMPARISON METHODS section for more info.
@@ -110,6 +110,19 @@ with:
110 110
111 - period being the hist entry period value 111 - period being the hist entry period value
112 112
113wdiff
114~~~~~
115If specified the 'Weighted diff' column is displayed with value 'd' computed as:
116
117 d = B->period * WEIGHT-A - A->period * WEIGHT-B
118
119 - A/B being matching hist entry from first/second file specified
120 (or perf.data/perf.data.old) respectively.
121
122 - period being the hist entry period value
123
124 - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option
125 behind ':' separator like '-c wdiff:1,2'.
113 126
114SEE ALSO 127SEE ALSO
115-------- 128--------
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index e13cfac0b063..d78e8386e1a9 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -27,24 +27,81 @@ static bool show_displacement;
27static bool show_baseline_only; 27static bool show_baseline_only;
28static bool sort_compute; 28static bool sort_compute;
29 29
30static s64 compute_wdiff_w1;
31static s64 compute_wdiff_w2;
32
30enum { 33enum {
31 COMPUTE_DELTA, 34 COMPUTE_DELTA,
32 COMPUTE_RATIO, 35 COMPUTE_RATIO,
36 COMPUTE_WEIGHTED_DIFF,
33 COMPUTE_MAX, 37 COMPUTE_MAX,
34}; 38};
35 39
36const char *compute_names[COMPUTE_MAX] = { 40const char *compute_names[COMPUTE_MAX] = {
37 [COMPUTE_DELTA] = "delta", 41 [COMPUTE_DELTA] = "delta",
38 [COMPUTE_RATIO] = "ratio", 42 [COMPUTE_RATIO] = "ratio",
43 [COMPUTE_WEIGHTED_DIFF] = "wdiff",
39}; 44};
40 45
41static int compute; 46static int compute;
42 47
48static int setup_compute_opt_wdiff(char *opt)
49{
50 char *w1_str = opt;
51 char *w2_str;
52
53 int ret = -EINVAL;
54
55 if (!opt)
56 goto out;
57
58 w2_str = strchr(opt, ',');
59 if (!w2_str)
60 goto out;
61
62 *w2_str++ = 0x0;
63 if (!*w2_str)
64 goto out;
65
66 compute_wdiff_w1 = strtol(w1_str, NULL, 10);
67 compute_wdiff_w2 = strtol(w2_str, NULL, 10);
68
69 if (!compute_wdiff_w1 || !compute_wdiff_w2)
70 goto out;
71
72 pr_debug("compute wdiff w1(%" PRId64 ") w2(%" PRId64 ")\n",
73 compute_wdiff_w1, compute_wdiff_w2);
74
75 ret = 0;
76
77 out:
78 if (ret)
79 pr_err("Failed: wrong weight data, use 'wdiff:w1,w2'\n");
80
81 return ret;
82}
83
84static int setup_compute_opt(char *opt)
85{
86 if (compute == COMPUTE_WEIGHTED_DIFF)
87 return setup_compute_opt_wdiff(opt);
88
89 if (opt) {
90 pr_err("Failed: extra option specified '%s'", opt);
91 return -EINVAL;
92 }
93
94 return 0;
95}
96
43static int setup_compute(const struct option *opt, const char *str, 97static int setup_compute(const struct option *opt, const char *str,
44 int unset __maybe_unused) 98 int unset __maybe_unused)
45{ 99{
46 int *cp = (int *) opt->value; 100 int *cp = (int *) opt->value;
101 char *cstr = (char *) str;
102 char buf[50];
47 unsigned i; 103 unsigned i;
104 char *option;
48 105
49 if (!str) { 106 if (!str) {
50 *cp = COMPUTE_DELTA; 107 *cp = COMPUTE_DELTA;
@@ -53,19 +110,37 @@ static int setup_compute(const struct option *opt, const char *str,
53 110
54 if (*str == '+') { 111 if (*str == '+') {
55 sort_compute = true; 112 sort_compute = true;
56 str++; 113 cstr = (char *) ++str;
57 if (!*str) 114 if (!*str)
58 return 0; 115 return 0;
59 } 116 }
60 117
118 option = strchr(str, ':');
119 if (option) {
120 unsigned len = option++ - str;
121
122 /*
123 * The str data are not writeable, so we need
124 * to use another buffer.
125 */
126
127 /* No option value is longer. */
128 if (len >= sizeof(buf))
129 return -EINVAL;
130
131 strncpy(buf, str, len);
132 buf[len] = 0x0;
133 cstr = buf;
134 }
135
61 for (i = 0; i < COMPUTE_MAX; i++) 136 for (i = 0; i < COMPUTE_MAX; i++)
62 if (!strcmp(str, compute_names[i])) { 137 if (!strcmp(cstr, compute_names[i])) {
63 *cp = i; 138 *cp = i;
64 return 0; 139 return setup_compute_opt(option);
65 } 140 }
66 141
67 pr_err("Failed: '%s' is not computation method " 142 pr_err("Failed: '%s' is not computation method "
68 "(use 'delta' or 'ratio').\n", str); 143 "(use 'delta','ratio' or 'wdiff')\n", str);
69 return -EINVAL; 144 return -EINVAL;
70} 145}
71 146
@@ -97,6 +172,23 @@ double perf_diff__compute_ratio(struct hist_entry *he)
97 return he->diff.period_ratio; 172 return he->diff.period_ratio;
98} 173}
99 174
175s64 perf_diff__compute_wdiff(struct hist_entry *he)
176{
177 struct hist_entry *pair = he->pair;
178 u64 new_period = he->stat.period;
179 u64 old_period = pair ? pair->stat.period : 0;
180
181 he->diff.computed = true;
182
183 if (!pair)
184 he->diff.wdiff = 0;
185 else
186 he->diff.wdiff = new_period * compute_wdiff_w2 -
187 old_period * compute_wdiff_w1;
188
189 return he->diff.wdiff;
190}
191
100static int hists__add_entry(struct hists *self, 192static int hists__add_entry(struct hists *self,
101 struct addr_location *al, u64 period) 193 struct addr_location *al, u64 period)
102{ 194{
@@ -275,6 +367,9 @@ static void hists__precompute(struct hists *hists)
275 case COMPUTE_RATIO: 367 case COMPUTE_RATIO:
276 perf_diff__compute_ratio(he); 368 perf_diff__compute_ratio(he);
277 break; 369 break;
370 case COMPUTE_WEIGHTED_DIFF:
371 perf_diff__compute_wdiff(he);
372 break;
278 default: 373 default:
279 BUG_ON(1); 374 BUG_ON(1);
280 } 375 }
@@ -310,6 +405,13 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
310 405
311 return cmp_doubles(l, r); 406 return cmp_doubles(l, r);
312 } 407 }
408 case COMPUTE_WEIGHTED_DIFF:
409 {
410 s64 l = left->diff.wdiff;
411 s64 r = right->diff.wdiff;
412
413 return r - l;
414 }
313 default: 415 default:
314 BUG_ON(1); 416 BUG_ON(1);
315 } 417 }
@@ -434,7 +536,8 @@ static const struct option options[] = {
434 "Show position displacement relative to baseline"), 536 "Show position displacement relative to baseline"),
435 OPT_BOOLEAN('b', "baseline-only", &show_baseline_only, 537 OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
436 "Show only items with match in baseline"), 538 "Show only items with match in baseline"),
437 OPT_CALLBACK('c', "compute", &compute, "delta,ratio (default delta)", 539 OPT_CALLBACK('c', "compute", &compute,
540 "delta,ratio,wdiff:w1,w2 (default delta)",
438 "Entries differential computation selection", 541 "Entries differential computation selection",
439 setup_compute), 542 setup_compute),
440 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 543 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
@@ -475,6 +578,9 @@ static void ui_init(void)
475 case COMPUTE_RATIO: 578 case COMPUTE_RATIO:
476 perf_hpp__column_enable(PERF_HPP__RATIO, true); 579 perf_hpp__column_enable(PERF_HPP__RATIO, true);
477 break; 580 break;
581 case COMPUTE_WEIGHTED_DIFF:
582 perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF, true);
583 break;
478 default: 584 default:
479 BUG_ON(1); 585 BUG_ON(1);
480 }; 586 };
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 659f2a25e997..522b4ec051d5 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)
286 return scnprintf(hpp->buf, hpp->size, fmt, buf); 286 return scnprintf(hpp->buf, hpp->size, fmt, buf);
287} 287}
288 288
289static int hpp__header_wdiff(struct perf_hpp *hpp)
290{
291 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
292
293 return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
294}
295
296static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
297{
298 return 14;
299}
300
301static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
302{
303 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
304 char buf[32] = " ";
305 s64 wdiff;
306
307 if (he->diff.computed)
308 wdiff = he->diff.wdiff;
309 else
310 wdiff = perf_diff__compute_wdiff(he);
311
312 if (wdiff != 0)
313 scnprintf(buf, sizeof(buf), "%14ld", wdiff);
314
315 return scnprintf(hpp->buf, hpp->size, fmt, buf);
316}
317
289static int hpp__header_displ(struct perf_hpp *hpp) 318static int hpp__header_displ(struct perf_hpp *hpp)
290{ 319{
291 return scnprintf(hpp->buf, hpp->size, "Displ."); 320 return scnprintf(hpp->buf, hpp->size, "Displ.");
@@ -332,6 +361,7 @@ struct perf_hpp_fmt perf_hpp__format[] = {
332 { .cond = false, HPP__PRINT_FNS(period) }, 361 { .cond = false, HPP__PRINT_FNS(period) },
333 { .cond = false, HPP__PRINT_FNS(delta) }, 362 { .cond = false, HPP__PRINT_FNS(delta) },
334 { .cond = false, HPP__PRINT_FNS(ratio) }, 363 { .cond = false, HPP__PRINT_FNS(ratio) },
364 { .cond = false, HPP__PRINT_FNS(wdiff) },
335 { .cond = false, HPP__PRINT_FNS(displ) } 365 { .cond = false, HPP__PRINT_FNS(displ) }
336}; 366};
337 367
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index a7ea28a1d502..ce76f36aeb0a 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -142,6 +142,7 @@ enum {
142 PERF_HPP__PERIOD, 142 PERF_HPP__PERIOD,
143 PERF_HPP__DELTA, 143 PERF_HPP__DELTA,
144 PERF_HPP__RATIO, 144 PERF_HPP__RATIO,
145 PERF_HPP__WEIGHTED_DIFF,
145 PERF_HPP__DISPL, 146 PERF_HPP__DISPL,
146 147
147 PERF_HPP__MAX_INDEX 148 PERF_HPP__MAX_INDEX
@@ -207,4 +208,5 @@ unsigned int hists__sort_list_width(struct hists *self);
207 208
208double perf_diff__compute_delta(struct hist_entry *he); 209double perf_diff__compute_delta(struct hist_entry *he);
209double perf_diff__compute_ratio(struct hist_entry *he); 210double perf_diff__compute_ratio(struct hist_entry *he);
211s64 perf_diff__compute_wdiff(struct hist_entry *he);
210#endif /* __PERF_HIST_H */ 212#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 337aeefa2451..13761d83a5a0 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -63,6 +63,9 @@ struct hist_entry_diff {
63 63
64 /* PERF_HPP__RATIO */ 64 /* PERF_HPP__RATIO */
65 double period_ratio; 65 double period_ratio;
66
67 /* HISTC_WEIGHTED_DIFF */
68 s64 wdiff;
66}; 69};
67 70
68/** 71/**