aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/hist.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/hist.c')
-rw-r--r--tools/perf/util/hist.c187
1 files changed, 102 insertions, 85 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index f38590d7561b..b262b44b7a65 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -225,14 +225,18 @@ static void he_stat__decay(struct he_stat *he_stat)
225static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 225static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
226{ 226{
227 u64 prev_period = he->stat.period; 227 u64 prev_period = he->stat.period;
228 u64 diff;
228 229
229 if (prev_period == 0) 230 if (prev_period == 0)
230 return true; 231 return true;
231 232
232 he_stat__decay(&he->stat); 233 he_stat__decay(&he->stat);
233 234
235 diff = prev_period - he->stat.period;
236
237 hists->stats.total_period -= diff;
234 if (!he->filtered) 238 if (!he->filtered)
235 hists->stats.total_period -= prev_period - he->stat.period; 239 hists->stats.total_non_filtered_period -= diff;
236 240
237 return he->stat.period == 0; 241 return he->stat.period == 0;
238} 242}
@@ -259,8 +263,11 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
259 if (sort__need_collapse) 263 if (sort__need_collapse)
260 rb_erase(&n->rb_node_in, &hists->entries_collapsed); 264 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
261 265
262 hist_entry__free(n);
263 --hists->nr_entries; 266 --hists->nr_entries;
267 if (!n->filtered)
268 --hists->nr_non_filtered_entries;
269
270 hist_entry__free(n);
264 } 271 }
265 } 272 }
266} 273}
@@ -317,15 +324,6 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
317 return he; 324 return he;
318} 325}
319 326
320void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
321{
322 if (!h->filtered) {
323 hists__calc_col_len(hists, h);
324 ++hists->nr_entries;
325 hists->stats.total_period += h->stat.period;
326 }
327}
328
329static u8 symbol__parent_filter(const struct symbol *parent) 327static u8 symbol__parent_filter(const struct symbol *parent)
330{ 328{
331 if (symbol_conf.exclude_other && parent == NULL) 329 if (symbol_conf.exclude_other && parent == NULL)
@@ -391,7 +389,6 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
391 if (!he) 389 if (!he)
392 return NULL; 390 return NULL;
393 391
394 hists->nr_entries++;
395 rb_link_node(&he->rb_node_in, parent, p); 392 rb_link_node(&he->rb_node_in, parent, p);
396 rb_insert_color(&he->rb_node_in, hists->entries_in); 393 rb_insert_color(&he->rb_node_in, hists->entries_in);
397out: 394out:
@@ -435,11 +432,14 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
435int64_t 432int64_t
436hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 433hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
437{ 434{
438 struct sort_entry *se; 435 struct perf_hpp_fmt *fmt;
439 int64_t cmp = 0; 436 int64_t cmp = 0;
440 437
441 list_for_each_entry(se, &hist_entry__sort_list, list) { 438 perf_hpp__for_each_sort_list(fmt) {
442 cmp = se->se_cmp(left, right); 439 if (perf_hpp__should_skip(fmt))
440 continue;
441
442 cmp = fmt->cmp(left, right);
443 if (cmp) 443 if (cmp)
444 break; 444 break;
445 } 445 }
@@ -450,15 +450,14 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
450int64_t 450int64_t
451hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) 451hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
452{ 452{
453 struct sort_entry *se; 453 struct perf_hpp_fmt *fmt;
454 int64_t cmp = 0; 454 int64_t cmp = 0;
455 455
456 list_for_each_entry(se, &hist_entry__sort_list, list) { 456 perf_hpp__for_each_sort_list(fmt) {
457 int64_t (*f)(struct hist_entry *, struct hist_entry *); 457 if (perf_hpp__should_skip(fmt))
458 458 continue;
459 f = se->se_collapse ?: se->se_cmp;
460 459
461 cmp = f(left, right); 460 cmp = fmt->collapse(left, right);
462 if (cmp) 461 if (cmp)
463 break; 462 break;
464 } 463 }
@@ -571,64 +570,50 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
571 } 570 }
572} 571}
573 572
574/* 573static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
575 * reverse the map, sort on period.
576 */
577
578static int period_cmp(u64 period_a, u64 period_b)
579{ 574{
580 if (period_a > period_b) 575 struct perf_hpp_fmt *fmt;
581 return 1; 576 int64_t cmp = 0;
582 if (period_a < period_b)
583 return -1;
584 return 0;
585}
586
587static int hist_entry__sort_on_period(struct hist_entry *a,
588 struct hist_entry *b)
589{
590 int ret;
591 int i, nr_members;
592 struct perf_evsel *evsel;
593 struct hist_entry *pair;
594 u64 *periods_a, *periods_b;
595 577
596 ret = period_cmp(a->stat.period, b->stat.period); 578 perf_hpp__for_each_sort_list(fmt) {
597 if (ret || !symbol_conf.event_group) 579 if (perf_hpp__should_skip(fmt))
598 return ret; 580 continue;
599 581
600 evsel = hists_to_evsel(a->hists); 582 cmp = fmt->sort(a, b);
601 nr_members = evsel->nr_members; 583 if (cmp)
602 if (nr_members <= 1) 584 break;
603 return ret; 585 }
604 586
605 periods_a = zalloc(sizeof(periods_a) * nr_members); 587 return cmp;
606 periods_b = zalloc(sizeof(periods_b) * nr_members); 588}
607 589
608 if (!periods_a || !periods_b) 590static void hists__reset_filter_stats(struct hists *hists)
609 goto out; 591{
592 hists->nr_non_filtered_entries = 0;
593 hists->stats.total_non_filtered_period = 0;
594}
610 595
611 list_for_each_entry(pair, &a->pairs.head, pairs.node) { 596void hists__reset_stats(struct hists *hists)
612 evsel = hists_to_evsel(pair->hists); 597{
613 periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period; 598 hists->nr_entries = 0;
614 } 599 hists->stats.total_period = 0;
615 600
616 list_for_each_entry(pair, &b->pairs.head, pairs.node) { 601 hists__reset_filter_stats(hists);
617 evsel = hists_to_evsel(pair->hists); 602}
618 periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period;
619 }
620 603
621 for (i = 1; i < nr_members; i++) { 604static void hists__inc_filter_stats(struct hists *hists, struct hist_entry *h)
622 ret = period_cmp(periods_a[i], periods_b[i]); 605{
623 if (ret) 606 hists->nr_non_filtered_entries++;
624 break; 607 hists->stats.total_non_filtered_period += h->stat.period;
625 } 608}
626 609
627out: 610void hists__inc_stats(struct hists *hists, struct hist_entry *h)
628 free(periods_a); 611{
629 free(periods_b); 612 if (!h->filtered)
613 hists__inc_filter_stats(hists, h);
630 614
631 return ret; 615 hists->nr_entries++;
616 hists->stats.total_period += h->stat.period;
632} 617}
633 618
634static void __hists__insert_output_entry(struct rb_root *entries, 619static void __hists__insert_output_entry(struct rb_root *entries,
@@ -647,7 +632,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
647 parent = *p; 632 parent = *p;
648 iter = rb_entry(parent, struct hist_entry, rb_node); 633 iter = rb_entry(parent, struct hist_entry, rb_node);
649 634
650 if (hist_entry__sort_on_period(he, iter) > 0) 635 if (hist_entry__sort(he, iter) > 0)
651 p = &(*p)->rb_left; 636 p = &(*p)->rb_left;
652 else 637 else
653 p = &(*p)->rb_right; 638 p = &(*p)->rb_right;
@@ -674,8 +659,7 @@ void hists__output_resort(struct hists *hists)
674 next = rb_first(root); 659 next = rb_first(root);
675 hists->entries = RB_ROOT; 660 hists->entries = RB_ROOT;
676 661
677 hists->nr_entries = 0; 662 hists__reset_stats(hists);
678 hists->stats.total_period = 0;
679 hists__reset_col_len(hists); 663 hists__reset_col_len(hists);
680 664
681 while (next) { 665 while (next) {
@@ -683,7 +667,10 @@ void hists__output_resort(struct hists *hists)
683 next = rb_next(&n->rb_node_in); 667 next = rb_next(&n->rb_node_in);
684 668
685 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits); 669 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
686 hists__inc_nr_entries(hists, n); 670 hists__inc_stats(hists, n);
671
672 if (!n->filtered)
673 hists__calc_col_len(hists, n);
687 } 674 }
688} 675}
689 676
@@ -694,13 +681,13 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
694 if (h->filtered) 681 if (h->filtered)
695 return; 682 return;
696 683
697 ++hists->nr_entries; 684 /* force fold unfiltered entry for simplicity */
698 if (h->ms.unfolded) 685 h->ms.unfolded = false;
699 hists->nr_entries += h->nr_rows;
700 h->row_offset = 0; 686 h->row_offset = 0;
701 hists->stats.total_period += h->stat.period;
702 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events;
703 687
688 hists->stats.nr_non_filtered_samples += h->stat.nr_events;
689
690 hists__inc_filter_stats(hists, h);
704 hists__calc_col_len(hists, h); 691 hists__calc_col_len(hists, h);
705} 692}
706 693
@@ -721,8 +708,9 @@ void hists__filter_by_dso(struct hists *hists)
721{ 708{
722 struct rb_node *nd; 709 struct rb_node *nd;
723 710
724 hists->nr_entries = hists->stats.total_period = 0; 711 hists->stats.nr_non_filtered_samples = 0;
725 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 712
713 hists__reset_filter_stats(hists);
726 hists__reset_col_len(hists); 714 hists__reset_col_len(hists);
727 715
728 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 716 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -754,8 +742,9 @@ void hists__filter_by_thread(struct hists *hists)
754{ 742{
755 struct rb_node *nd; 743 struct rb_node *nd;
756 744
757 hists->nr_entries = hists->stats.total_period = 0; 745 hists->stats.nr_non_filtered_samples = 0;
758 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 746
747 hists__reset_filter_stats(hists);
759 hists__reset_col_len(hists); 748 hists__reset_col_len(hists);
760 749
761 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 750 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -785,8 +774,9 @@ void hists__filter_by_symbol(struct hists *hists)
785{ 774{
786 struct rb_node *nd; 775 struct rb_node *nd;
787 776
788 hists->nr_entries = hists->stats.total_period = 0; 777 hists->stats.nr_non_filtered_samples = 0;
789 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 778
779 hists__reset_filter_stats(hists);
790 hists__reset_col_len(hists); 780 hists__reset_col_len(hists);
791 781
792 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 782 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -847,7 +837,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
847 he->hists = hists; 837 he->hists = hists;
848 rb_link_node(&he->rb_node_in, parent, p); 838 rb_link_node(&he->rb_node_in, parent, p);
849 rb_insert_color(&he->rb_node_in, root); 839 rb_insert_color(&he->rb_node_in, root);
850 hists__inc_nr_entries(hists, he); 840 hists__inc_stats(hists, he);
851 he->dummy = true; 841 he->dummy = true;
852 } 842 }
853out: 843out:
@@ -931,3 +921,30 @@ int hists__link(struct hists *leader, struct hists *other)
931 921
932 return 0; 922 return 0;
933} 923}
924
925u64 hists__total_period(struct hists *hists)
926{
927 return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period :
928 hists->stats.total_period;
929}
930
931int parse_filter_percentage(const struct option *opt __maybe_unused,
932 const char *arg, int unset __maybe_unused)
933{
934 if (!strcmp(arg, "relative"))
935 symbol_conf.filter_relative = true;
936 else if (!strcmp(arg, "absolute"))
937 symbol_conf.filter_relative = false;
938 else
939 return -1;
940
941 return 0;
942}
943
944int perf_hist_config(const char *var, const char *value)
945{
946 if (!strcmp(var, "hist.percentage"))
947 return parse_filter_percentage(NULL, value, 0);
948
949 return 0;
950}