aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-diff.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-diff.c')
-rw-r--r--tools/perf/builtin-diff.c205
1 files changed, 77 insertions, 128 deletions
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 93b852f8a5d5..d207a97a2db1 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -23,7 +23,6 @@ static char const *input_old = "perf.data.old",
23 *input_new = "perf.data"; 23 *input_new = "perf.data";
24static char diff__default_sort_order[] = "dso,symbol"; 24static char diff__default_sort_order[] = "dso,symbol";
25static bool force; 25static bool force;
26static bool show_displacement;
27static bool show_period; 26static bool show_period;
28static bool show_formula; 27static bool show_formula;
29static bool show_baseline_only; 28static bool show_baseline_only;
@@ -146,58 +145,47 @@ static int setup_compute(const struct option *opt, const char *str,
146 return -EINVAL; 145 return -EINVAL;
147} 146}
148 147
149static double get_period_percent(struct hist_entry *he, u64 period) 148double perf_diff__period_percent(struct hist_entry *he, u64 period)
150{ 149{
151 u64 total = he->hists->stats.total_period; 150 u64 total = he->hists->stats.total_period;
152 return (period * 100.0) / total; 151 return (period * 100.0) / total;
153} 152}
154 153
155double perf_diff__compute_delta(struct hist_entry *he) 154double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair)
156{ 155{
157 struct hist_entry *pair = hist_entry__next_pair(he); 156 double new_percent = perf_diff__period_percent(he, he->stat.period);
158 double new_percent = get_period_percent(he, he->stat.period); 157 double old_percent = perf_diff__period_percent(pair, pair->stat.period);
159 double old_percent = pair ? get_period_percent(pair, pair->stat.period) : 0.0;
160 158
161 he->diff.period_ratio_delta = new_percent - old_percent; 159 he->diff.period_ratio_delta = new_percent - old_percent;
162 he->diff.computed = true; 160 he->diff.computed = true;
163 return he->diff.period_ratio_delta; 161 return he->diff.period_ratio_delta;
164} 162}
165 163
166double perf_diff__compute_ratio(struct hist_entry *he) 164double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair)
167{ 165{
168 struct hist_entry *pair = hist_entry__next_pair(he);
169 double new_period = he->stat.period; 166 double new_period = he->stat.period;
170 double old_period = pair ? pair->stat.period : 0; 167 double old_period = pair->stat.period;
171 168
172 he->diff.computed = true; 169 he->diff.computed = true;
173 he->diff.period_ratio = pair ? (new_period / old_period) : 0; 170 he->diff.period_ratio = new_period / old_period;
174 return he->diff.period_ratio; 171 return he->diff.period_ratio;
175} 172}
176 173
177s64 perf_diff__compute_wdiff(struct hist_entry *he) 174s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
178{ 175{
179 struct hist_entry *pair = hist_entry__next_pair(he);
180 u64 new_period = he->stat.period; 176 u64 new_period = he->stat.period;
181 u64 old_period = pair ? pair->stat.period : 0; 177 u64 old_period = pair->stat.period;
182 178
183 he->diff.computed = true; 179 he->diff.computed = true;
184 180 he->diff.wdiff = new_period * compute_wdiff_w2 -
185 if (!pair) 181 old_period * compute_wdiff_w1;
186 he->diff.wdiff = 0;
187 else
188 he->diff.wdiff = new_period * compute_wdiff_w2 -
189 old_period * compute_wdiff_w1;
190 182
191 return he->diff.wdiff; 183 return he->diff.wdiff;
192} 184}
193 185
194static int formula_delta(struct hist_entry *he, char *buf, size_t size) 186static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
187 char *buf, size_t size)
195{ 188{
196 struct hist_entry *pair = hist_entry__next_pair(he);
197
198 if (!pair)
199 return -1;
200
201 return scnprintf(buf, size, 189 return scnprintf(buf, size,
202 "(%" PRIu64 " * 100 / %" PRIu64 ") - " 190 "(%" PRIu64 " * 100 / %" PRIu64 ") - "
203 "(%" PRIu64 " * 100 / %" PRIu64 ")", 191 "(%" PRIu64 " * 100 / %" PRIu64 ")",
@@ -205,41 +193,36 @@ static int formula_delta(struct hist_entry *he, char *buf, size_t size)
205 pair->stat.period, pair->hists->stats.total_period); 193 pair->stat.period, pair->hists->stats.total_period);
206} 194}
207 195
208static int formula_ratio(struct hist_entry *he, char *buf, size_t size) 196static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
197 char *buf, size_t size)
209{ 198{
210 struct hist_entry *pair = hist_entry__next_pair(he);
211 double new_period = he->stat.period; 199 double new_period = he->stat.period;
212 double old_period = pair ? pair->stat.period : 0; 200 double old_period = pair->stat.period;
213
214 if (!pair)
215 return -1;
216 201
217 return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); 202 return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
218} 203}
219 204
220static int formula_wdiff(struct hist_entry *he, char *buf, size_t size) 205static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
206 char *buf, size_t size)
221{ 207{
222 struct hist_entry *pair = hist_entry__next_pair(he);
223 u64 new_period = he->stat.period; 208 u64 new_period = he->stat.period;
224 u64 old_period = pair ? pair->stat.period : 0; 209 u64 old_period = pair->stat.period;
225
226 if (!pair)
227 return -1;
228 210
229 return scnprintf(buf, size, 211 return scnprintf(buf, size,
230 "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", 212 "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
231 new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); 213 new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
232} 214}
233 215
234int perf_diff__formula(char *buf, size_t size, struct hist_entry *he) 216int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
217 char *buf, size_t size)
235{ 218{
236 switch (compute) { 219 switch (compute) {
237 case COMPUTE_DELTA: 220 case COMPUTE_DELTA:
238 return formula_delta(he, buf, size); 221 return formula_delta(he, pair, buf, size);
239 case COMPUTE_RATIO: 222 case COMPUTE_RATIO:
240 return formula_ratio(he, buf, size); 223 return formula_ratio(he, pair, buf, size);
241 case COMPUTE_WEIGHTED_DIFF: 224 case COMPUTE_WEIGHTED_DIFF:
242 return formula_wdiff(he, buf, size); 225 return formula_wdiff(he, pair, buf, size);
243 default: 226 default:
244 BUG_ON(1); 227 BUG_ON(1);
245 } 228 }
@@ -292,48 +275,6 @@ static struct perf_tool tool = {
292 .ordering_requires_timestamps = true, 275 .ordering_requires_timestamps = true,
293}; 276};
294 277
295static void insert_hist_entry_by_name(struct rb_root *root,
296 struct hist_entry *he)
297{
298 struct rb_node **p = &root->rb_node;
299 struct rb_node *parent = NULL;
300 struct hist_entry *iter;
301
302 while (*p != NULL) {
303 parent = *p;
304 iter = rb_entry(parent, struct hist_entry, rb_node);
305 if (hist_entry__cmp(he, iter) < 0)
306 p = &(*p)->rb_left;
307 else
308 p = &(*p)->rb_right;
309 }
310
311 rb_link_node(&he->rb_node, parent, p);
312 rb_insert_color(&he->rb_node, root);
313}
314
315static void hists__name_resort(struct hists *self, bool sort)
316{
317 unsigned long position = 1;
318 struct rb_root tmp = RB_ROOT;
319 struct rb_node *next = rb_first(&self->entries);
320
321 while (next != NULL) {
322 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
323
324 next = rb_next(&n->rb_node);
325 n->position = position++;
326
327 if (sort) {
328 rb_erase(&n->rb_node, &self->entries);
329 insert_hist_entry_by_name(&tmp, n);
330 }
331 }
332
333 if (sort)
334 self->entries = tmp;
335}
336
337static struct perf_evsel *evsel_match(struct perf_evsel *evsel, 278static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
338 struct perf_evlist *evlist) 279 struct perf_evlist *evlist)
339{ 280{
@@ -346,34 +287,34 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
346 return NULL; 287 return NULL;
347} 288}
348 289
349static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) 290static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
350{ 291{
351 struct perf_evsel *evsel; 292 struct perf_evsel *evsel;
352 293
353 list_for_each_entry(evsel, &evlist->entries, node) { 294 list_for_each_entry(evsel, &evlist->entries, node) {
354 struct hists *hists = &evsel->hists; 295 struct hists *hists = &evsel->hists;
355 296
356 hists__output_resort(hists); 297 hists__collapse_resort(hists);
357
358 /*
359 * The hists__name_resort only sets possition
360 * if name is false.
361 */
362 if (name || ((!name) && show_displacement))
363 hists__name_resort(hists, name);
364 } 298 }
365} 299}
366 300
367static void hists__baseline_only(struct hists *hists) 301static void hists__baseline_only(struct hists *hists)
368{ 302{
369 struct rb_node *next = rb_first(&hists->entries); 303 struct rb_root *root;
304 struct rb_node *next;
370 305
306 if (sort__need_collapse)
307 root = &hists->entries_collapsed;
308 else
309 root = hists->entries_in;
310
311 next = rb_first(root);
371 while (next != NULL) { 312 while (next != NULL) {
372 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); 313 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
373 314
374 next = rb_next(&he->rb_node); 315 next = rb_next(&he->rb_node_in);
375 if (!hist_entry__next_pair(he)) { 316 if (!hist_entry__next_pair(he)) {
376 rb_erase(&he->rb_node, &hists->entries); 317 rb_erase(&he->rb_node_in, root);
377 hist_entry__free(he); 318 hist_entry__free(he);
378 } 319 }
379 } 320 }
@@ -385,18 +326,21 @@ static void hists__precompute(struct hists *hists)
385 326
386 while (next != NULL) { 327 while (next != NULL) {
387 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); 328 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
329 struct hist_entry *pair = hist_entry__next_pair(he);
388 330
389 next = rb_next(&he->rb_node); 331 next = rb_next(&he->rb_node);
332 if (!pair)
333 continue;
390 334
391 switch (compute) { 335 switch (compute) {
392 case COMPUTE_DELTA: 336 case COMPUTE_DELTA:
393 perf_diff__compute_delta(he); 337 perf_diff__compute_delta(he, pair);
394 break; 338 break;
395 case COMPUTE_RATIO: 339 case COMPUTE_RATIO:
396 perf_diff__compute_ratio(he); 340 perf_diff__compute_ratio(he, pair);
397 break; 341 break;
398 case COMPUTE_WEIGHTED_DIFF: 342 case COMPUTE_WEIGHTED_DIFF:
399 perf_diff__compute_wdiff(he); 343 perf_diff__compute_wdiff(he, pair);
400 break; 344 break;
401 default: 345 default:
402 BUG_ON(1); 346 BUG_ON(1);
@@ -470,19 +414,30 @@ static void insert_hist_entry_by_compute(struct rb_root *root,
470 414
471static void hists__compute_resort(struct hists *hists) 415static void hists__compute_resort(struct hists *hists)
472{ 416{
473 struct rb_root tmp = RB_ROOT; 417 struct rb_root *root;
474 struct rb_node *next = rb_first(&hists->entries); 418 struct rb_node *next;
419
420 if (sort__need_collapse)
421 root = &hists->entries_collapsed;
422 else
423 root = hists->entries_in;
424
425 hists->entries = RB_ROOT;
426 next = rb_first(root);
427
428 hists->nr_entries = 0;
429 hists->stats.total_period = 0;
430 hists__reset_col_len(hists);
475 431
476 while (next != NULL) { 432 while (next != NULL) {
477 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); 433 struct hist_entry *he;
478 434
479 next = rb_next(&he->rb_node); 435 he = rb_entry(next, struct hist_entry, rb_node_in);
436 next = rb_next(&he->rb_node_in);
480 437
481 rb_erase(&he->rb_node, &hists->entries); 438 insert_hist_entry_by_compute(&hists->entries, he, compute);
482 insert_hist_entry_by_compute(&tmp, he, compute); 439 hists__inc_nr_entries(hists, he);
483 } 440 }
484
485 hists->entries = tmp;
486} 441}
487 442
488static void hists__process(struct hists *old, struct hists *new) 443static void hists__process(struct hists *old, struct hists *new)
@@ -497,6 +452,8 @@ static void hists__process(struct hists *old, struct hists *new)
497 if (sort_compute) { 452 if (sort_compute) {
498 hists__precompute(new); 453 hists__precompute(new);
499 hists__compute_resort(new); 454 hists__compute_resort(new);
455 } else {
456 hists__output_resort(new);
500 } 457 }
501 458
502 hists__fprintf(new, true, 0, 0, stdout); 459 hists__fprintf(new, true, 0, 0, stdout);
@@ -528,8 +485,8 @@ static int __cmd_diff(void)
528 evlist_old = older->evlist; 485 evlist_old = older->evlist;
529 evlist_new = newer->evlist; 486 evlist_new = newer->evlist;
530 487
531 perf_evlist__resort_hists(evlist_old, true); 488 perf_evlist__collapse_resort(evlist_old);
532 perf_evlist__resort_hists(evlist_new, false); 489 perf_evlist__collapse_resort(evlist_new);
533 490
534 list_for_each_entry(evsel, &evlist_new->entries, node) { 491 list_for_each_entry(evsel, &evlist_new->entries, node) {
535 struct perf_evsel *evsel_old; 492 struct perf_evsel *evsel_old;
@@ -562,8 +519,6 @@ static const char * const diff_usage[] = {
562static const struct option options[] = { 519static const struct option options[] = {
563 OPT_INCR('v', "verbose", &verbose, 520 OPT_INCR('v', "verbose", &verbose,
564 "be more verbose (show symbol address, etc)"), 521 "be more verbose (show symbol address, etc)"),
565 OPT_BOOLEAN('M', "displacement", &show_displacement,
566 "Show position displacement relative to baseline"),
567 OPT_BOOLEAN('b', "baseline-only", &show_baseline_only, 522 OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
568 "Show only items with match in baseline"), 523 "Show only items with match in baseline"),
569 OPT_CALLBACK('c', "compute", &compute, 524 OPT_CALLBACK('c', "compute", &compute,
@@ -597,40 +552,32 @@ static const struct option options[] = {
597 552
598static void ui_init(void) 553static void ui_init(void)
599{ 554{
600 perf_hpp__init();
601
602 /* No overhead column. */
603 perf_hpp__column_enable(PERF_HPP__OVERHEAD, false);
604
605 /* 555 /*
606 * Display baseline/delta/ratio/displacement/ 556 * Display baseline/delta/ratio
607 * formula/periods columns. 557 * formula/periods columns.
608 */ 558 */
609 perf_hpp__column_enable(PERF_HPP__BASELINE, true); 559 perf_hpp__column_enable(PERF_HPP__BASELINE);
610 560
611 switch (compute) { 561 switch (compute) {
612 case COMPUTE_DELTA: 562 case COMPUTE_DELTA:
613 perf_hpp__column_enable(PERF_HPP__DELTA, true); 563 perf_hpp__column_enable(PERF_HPP__DELTA);
614 break; 564 break;
615 case COMPUTE_RATIO: 565 case COMPUTE_RATIO:
616 perf_hpp__column_enable(PERF_HPP__RATIO, true); 566 perf_hpp__column_enable(PERF_HPP__RATIO);
617 break; 567 break;
618 case COMPUTE_WEIGHTED_DIFF: 568 case COMPUTE_WEIGHTED_DIFF:
619 perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF, true); 569 perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF);
620 break; 570 break;
621 default: 571 default:
622 BUG_ON(1); 572 BUG_ON(1);
623 }; 573 };
624 574
625 if (show_displacement)
626 perf_hpp__column_enable(PERF_HPP__DISPL, true);
627
628 if (show_formula) 575 if (show_formula)
629 perf_hpp__column_enable(PERF_HPP__FORMULA, true); 576 perf_hpp__column_enable(PERF_HPP__FORMULA);
630 577
631 if (show_period) { 578 if (show_period) {
632 perf_hpp__column_enable(PERF_HPP__PERIOD, true); 579 perf_hpp__column_enable(PERF_HPP__PERIOD);
633 perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE, true); 580 perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE);
634 } 581 }
635} 582}
636 583
@@ -658,7 +605,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
658 605
659 ui_init(); 606 ui_init();
660 607
661 setup_sorting(diff_usage, options); 608 if (setup_sorting() < 0)
609 usage_with_options(diff_usage, options);
610
662 setup_pager(); 611 setup_pager();
663 612
664 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); 613 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL);