aboutsummaryrefslogtreecommitdiffstats
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
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>
-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;