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.c157
1 files changed, 93 insertions, 64 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index c61235f81260..2ec4b60aff6c 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -607,7 +607,7 @@ static void init_rem_hits(void)
607 rem_hits.ms.sym = rem_sq_bracket; 607 rem_hits.ms.sym = rem_sq_bracket;
608} 608}
609 609
610static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 610static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
611 u64 total_samples, int depth, 611 u64 total_samples, int depth,
612 int depth_mask, int left_margin) 612 int depth_mask, int left_margin)
613{ 613{
@@ -615,21 +615,16 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
615 struct callchain_node *child; 615 struct callchain_node *child;
616 struct callchain_list *chain; 616 struct callchain_list *chain;
617 int new_depth_mask = depth_mask; 617 int new_depth_mask = depth_mask;
618 u64 new_total;
619 u64 remaining; 618 u64 remaining;
620 size_t ret = 0; 619 size_t ret = 0;
621 int i; 620 int i;
622 uint entries_printed = 0; 621 uint entries_printed = 0;
623 622
624 if (callchain_param.mode == CHAIN_GRAPH_REL) 623 remaining = total_samples;
625 new_total = self->children_hit;
626 else
627 new_total = total_samples;
628
629 remaining = new_total;
630 624
631 node = rb_first(&self->rb_root); 625 node = rb_first(root);
632 while (node) { 626 while (node) {
627 u64 new_total;
633 u64 cumul; 628 u64 cumul;
634 629
635 child = rb_entry(node, struct callchain_node, rb_node); 630 child = rb_entry(node, struct callchain_node, rb_node);
@@ -657,11 +652,17 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
657 list_for_each_entry(chain, &child->val, list) { 652 list_for_each_entry(chain, &child->val, list) {
658 ret += ipchain__fprintf_graph(fp, chain, depth, 653 ret += ipchain__fprintf_graph(fp, chain, depth,
659 new_depth_mask, i++, 654 new_depth_mask, i++,
660 new_total, 655 total_samples,
661 cumul, 656 cumul,
662 left_margin); 657 left_margin);
663 } 658 }
664 ret += __callchain__fprintf_graph(fp, child, new_total, 659
660 if (callchain_param.mode == CHAIN_GRAPH_REL)
661 new_total = child->children_hit;
662 else
663 new_total = total_samples;
664
665 ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
665 depth + 1, 666 depth + 1,
666 new_depth_mask | (1 << depth), 667 new_depth_mask | (1 << depth),
667 left_margin); 668 left_margin);
@@ -671,61 +672,75 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
671 } 672 }
672 673
673 if (callchain_param.mode == CHAIN_GRAPH_REL && 674 if (callchain_param.mode == CHAIN_GRAPH_REL &&
674 remaining && remaining != new_total) { 675 remaining && remaining != total_samples) {
675 676
676 if (!rem_sq_bracket) 677 if (!rem_sq_bracket)
677 return ret; 678 return ret;
678 679
679 new_depth_mask &= ~(1 << (depth - 1)); 680 new_depth_mask &= ~(1 << (depth - 1));
680
681 ret += ipchain__fprintf_graph(fp, &rem_hits, depth, 681 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
682 new_depth_mask, 0, new_total, 682 new_depth_mask, 0, total_samples,
683 remaining, left_margin); 683 remaining, left_margin);
684 } 684 }
685 685
686 return ret; 686 return ret;
687} 687}
688 688
689static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 689static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
690 u64 total_samples, int left_margin) 690 u64 total_samples, int left_margin)
691{ 691{
692 struct callchain_node *cnode;
692 struct callchain_list *chain; 693 struct callchain_list *chain;
694 u32 entries_printed = 0;
693 bool printed = false; 695 bool printed = false;
696 struct rb_node *node;
694 int i = 0; 697 int i = 0;
695 int ret = 0; 698 int ret;
696 u32 entries_printed = 0;
697
698 list_for_each_entry(chain, &self->val, list) {
699 if (!i++ && sort__first_dimension == SORT_SYM)
700 continue;
701
702 if (!printed) {
703 ret += callchain__fprintf_left_margin(fp, left_margin);
704 ret += fprintf(fp, "|\n");
705 ret += callchain__fprintf_left_margin(fp, left_margin);
706 ret += fprintf(fp, "---");
707
708 left_margin += 3;
709 printed = true;
710 } else
711 ret += callchain__fprintf_left_margin(fp, left_margin);
712 699
713 if (chain->ms.sym) 700 /*
714 ret += fprintf(fp, " %s\n", chain->ms.sym->name); 701 * If have one single callchain root, don't bother printing
715 else 702 * its percentage (100 % in fractal mode and the same percentage
716 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip); 703 * than the hist in graph mode). This also avoid one level of column.
704 */
705 node = rb_first(root);
706 if (node && !rb_next(node)) {
707 cnode = rb_entry(node, struct callchain_node, rb_node);
708 list_for_each_entry(chain, &cnode->val, list) {
709 /*
710 * If we sort by symbol, the first entry is the same than
711 * the symbol. No need to print it otherwise it appears as
712 * displayed twice.
713 */
714 if (!i++ && sort__first_dimension == SORT_SYM)
715 continue;
716 if (!printed) {
717 ret += callchain__fprintf_left_margin(fp, left_margin);
718 ret += fprintf(fp, "|\n");
719 ret += callchain__fprintf_left_margin(fp, left_margin);
720 ret += fprintf(fp, "---");
721 left_margin += 3;
722 printed = true;
723 } else
724 ret += callchain__fprintf_left_margin(fp, left_margin);
725
726 if (chain->ms.sym)
727 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
728 else
729 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
717 730
718 if (++entries_printed == callchain_param.print_limit) 731 if (++entries_printed == callchain_param.print_limit)
719 break; 732 break;
733 }
734 root = &cnode->rb_root;
720 } 735 }
721 736
722 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin); 737 return __callchain__fprintf_graph(fp, root, total_samples,
723 738 1, 1, left_margin);
724 return ret;
725} 739}
726 740
727static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self, 741static size_t __callchain__fprintf_flat(FILE *fp,
728 u64 total_samples) 742 struct callchain_node *self,
743 u64 total_samples)
729{ 744{
730 struct callchain_list *chain; 745 struct callchain_list *chain;
731 size_t ret = 0; 746 size_t ret = 0;
@@ -733,7 +748,7 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
733 if (!self) 748 if (!self)
734 return 0; 749 return 0;
735 750
736 ret += callchain__fprintf_flat(fp, self->parent, total_samples); 751 ret += __callchain__fprintf_flat(fp, self->parent, total_samples);
737 752
738 753
739 list_for_each_entry(chain, &self->val, list) { 754 list_for_each_entry(chain, &self->val, list) {
@@ -749,44 +764,58 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
749 return ret; 764 return ret;
750} 765}
751 766
752static size_t hist_entry_callchain__fprintf(struct hist_entry *he, 767static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self,
753 u64 total_samples, int left_margin, 768 u64 total_samples)
754 FILE *fp)
755{ 769{
756 struct rb_node *rb_node;
757 struct callchain_node *chain;
758 size_t ret = 0; 770 size_t ret = 0;
759 u32 entries_printed = 0; 771 u32 entries_printed = 0;
772 struct rb_node *rb_node;
773 struct callchain_node *chain;
760 774
761 rb_node = rb_first(&he->sorted_chain); 775 rb_node = rb_first(self);
762 while (rb_node) { 776 while (rb_node) {
763 double percent; 777 double percent;
764 778
765 chain = rb_entry(rb_node, struct callchain_node, rb_node); 779 chain = rb_entry(rb_node, struct callchain_node, rb_node);
766 percent = chain->hit * 100.0 / total_samples; 780 percent = chain->hit * 100.0 / total_samples;
767 switch (callchain_param.mode) { 781
768 case CHAIN_FLAT: 782 ret = percent_color_fprintf(fp, " %6.2f%%\n", percent);
769 ret += percent_color_fprintf(fp, " %6.2f%%\n", 783 ret += __callchain__fprintf_flat(fp, chain, total_samples);
770 percent);
771 ret += callchain__fprintf_flat(fp, chain, total_samples);
772 break;
773 case CHAIN_GRAPH_ABS: /* Falldown */
774 case CHAIN_GRAPH_REL:
775 ret += callchain__fprintf_graph(fp, chain, total_samples,
776 left_margin);
777 case CHAIN_NONE:
778 default:
779 break;
780 }
781 ret += fprintf(fp, "\n"); 784 ret += fprintf(fp, "\n");
782 if (++entries_printed == callchain_param.print_limit) 785 if (++entries_printed == callchain_param.print_limit)
783 break; 786 break;
787
784 rb_node = rb_next(rb_node); 788 rb_node = rb_next(rb_node);
785 } 789 }
786 790
787 return ret; 791 return ret;
788} 792}
789 793
794static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
795 u64 total_samples, int left_margin,
796 FILE *fp)
797{
798 switch (callchain_param.mode) {
799 case CHAIN_GRAPH_REL:
800 return callchain__fprintf_graph(fp, &he->sorted_chain, he->period,
801 left_margin);
802 break;
803 case CHAIN_GRAPH_ABS:
804 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
805 left_margin);
806 break;
807 case CHAIN_FLAT:
808 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
809 break;
810 case CHAIN_NONE:
811 break;
812 default:
813 pr_err("Bad callchain mode\n");
814 }
815
816 return 0;
817}
818
790void hists__output_recalc_col_len(struct hists *hists, int max_rows) 819void hists__output_recalc_col_len(struct hists *hists, int max_rows)
791{ 820{
792 struct rb_node *next = rb_first(&hists->entries); 821 struct rb_node *next = rb_first(&hists->entries);