diff options
| -rw-r--r-- | tools/perf/util/hist.c | 157 |
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 | ||
| 610 | static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, | 610 | static 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 | ||
| 689 | static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self, | 689 | static 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 | ||
| 727 | static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self, | 741 | static 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; | ||
