aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2012-03-23 14:06:50 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2012-03-26 14:14:40 -0400
commit6d4818c5245fe00bee2c3bfb45edde178f302703 (patch)
treeefceca0975d71d413f0dc9c990afb1893b707934 /tools/perf
parentb01c3a0010aabadf745f3e7fdb9cab682e0a28a2 (diff)
perf tools: Fix display of first level of callchains
The callchain stdio mode display was written using a sorted by symbol report. In this mode we have only one callchain root per hist so we forgot to handle cases where we have multiple callchain root, as in per dso sorting for example. Fix this by handling these roots like any other branch, with the hist as the parent. Before: 1.97% libpthread-2.12.1.so | --- __libc_write create_worker bench_sched_messaging cmd_bench run_builtin main __libc_start_main | --- __libc_read create_worker bench_sched_messaging cmd_bench run_builtin main __libc_start_main After: 1.97% libpthread-2.12.1.so | |--36.97%-- __libc_write | create_worker | bench_sched_messaging | cmd_bench | run_builtin | main | __libc_start_main | |--31.47%-- __libc_read | create_worker | bench_sched_messaging | cmd_bench | run_builtin | main | __libc_start_main ... Single roots keep their entry without percentage because they have the same overhead than the hist they refer to. ie: 100% in fractal mode and the percentage of the hist in graph mode: 0.00% [k] reschedule_interrupt | --- default_idle amd_e400_idle cpu_idle start_secondary Reported-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: David Ahern <dsahern@gmail.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/r/1332526010-15400-1-git-send-email-fweisbec@gmail.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-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);