aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNamhyung Kim <namhyung@kernel.org>2015-11-09 00:45:44 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-11-19 11:19:25 -0500
commit8c430a34869946f1f5852f02d910ceef80040be5 (patch)
treed7255091acd8abec98ed884d67423ad81d7bca6e
parent4b3a3212233a042f48b7b8fedc64933e1ccd8643 (diff)
perf hists browser: Support folded callchains
The folded callchain mode prints all chains in a single line. Currently perf report --tui doesn't support folded callchains. Like flat callchains, only leaf nodes are added to the final rbtree so it should show entries in parent nodes. To do that, add flat_val list to struct callchain_node and show them along with the (normal) val list. For example, folded callchain looks like below: $ perf report -g folded --tui Samples: 234 of event 'cycles:pp', Event count (approx.): 32605268 Overhead Command Shared Object Symbol - 39.93% swapper [kernel.vmlinux] [k] intel_idle + 28.63% intel_idle; cpuidle_enter_state; cpuidle_enter; ... + 11.30% intel_idle; cpuidle_enter_state; cpuidle_enter; ... Signed-off-by: Namhyung Kim <namhyung@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Tested-by: Brendan Gregg <brendan.d.gregg@gmail.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Kan Liang <kan.liang@intel.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1447047946-1691-9-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/ui/browsers/hists.c125
1 files changed, 124 insertions, 1 deletions
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index c44af461a68f..a211b7b6a81e 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -207,6 +207,11 @@ static int callchain_node__count_flat_rows(struct callchain_node *node)
207 return n; 207 return n;
208} 208}
209 209
210static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
211{
212 return 1;
213}
214
210static int callchain_node__count_rows(struct callchain_node *node) 215static int callchain_node__count_rows(struct callchain_node *node)
211{ 216{
212 struct callchain_list *chain; 217 struct callchain_list *chain;
@@ -215,6 +220,8 @@ static int callchain_node__count_rows(struct callchain_node *node)
215 220
216 if (callchain_param.mode == CHAIN_FLAT) 221 if (callchain_param.mode == CHAIN_FLAT)
217 return callchain_node__count_flat_rows(node); 222 return callchain_node__count_flat_rows(node);
223 else if (callchain_param.mode == CHAIN_FOLDED)
224 return callchain_node__count_folded_rows(node);
218 225
219 list_for_each_entry(chain, &node->val, list) { 226 list_for_each_entry(chain, &node->val, list) {
220 ++n; 227 ++n;
@@ -311,7 +318,8 @@ static void callchain__init_have_children(struct rb_root *root)
311 for (nd = rb_first(root); nd; nd = rb_next(nd)) { 318 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
312 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 319 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
313 callchain_node__init_have_children(node, has_sibling); 320 callchain_node__init_have_children(node, has_sibling);
314 if (callchain_param.mode == CHAIN_FLAT) 321 if (callchain_param.mode == CHAIN_FLAT ||
322 callchain_param.mode == CHAIN_FOLDED)
315 callchain_node__make_parent_list(node); 323 callchain_node__make_parent_list(node);
316 } 324 }
317} 325}
@@ -723,6 +731,116 @@ out:
723 return row - first_row; 731 return row - first_row;
724} 732}
725 733
734static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
735 struct callchain_list *chain,
736 char *value_str, char *old_str)
737{
738 char bf[1024];
739 const char *str;
740 char *new;
741
742 str = callchain_list__sym_name(chain, bf, sizeof(bf),
743 browser->show_dso);
744 if (old_str) {
745 if (asprintf(&new, "%s%s%s", old_str,
746 symbol_conf.field_sep ?: ";", str) < 0)
747 new = NULL;
748 } else {
749 if (value_str) {
750 if (asprintf(&new, "%s %s", value_str, str) < 0)
751 new = NULL;
752 } else {
753 if (asprintf(&new, "%s", str) < 0)
754 new = NULL;
755 }
756 }
757 return new;
758}
759
760static int hist_browser__show_callchain_folded(struct hist_browser *browser,
761 struct rb_root *root,
762 unsigned short row, u64 total,
763 print_callchain_entry_fn print,
764 struct callchain_print_arg *arg,
765 check_output_full_fn is_output_full)
766{
767 struct rb_node *node;
768 int first_row = row, offset = LEVEL_OFFSET_STEP;
769 bool need_percent;
770
771 node = rb_first(root);
772 need_percent = node && rb_next(node);
773
774 while (node) {
775 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
776 struct rb_node *next = rb_next(node);
777 struct callchain_list *chain, *first_chain = NULL;
778 int first = true;
779 char *value_str = NULL, *value_str_alloc = NULL;
780 char *chain_str = NULL, *chain_str_alloc = NULL;
781
782 if (arg->row_offset != 0) {
783 arg->row_offset--;
784 goto next;
785 }
786
787 if (need_percent) {
788 char buf[64];
789
790 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
791 if (asprintf(&value_str, "%s", buf) < 0) {
792 value_str = (char *)"<...>";
793 goto do_print;
794 }
795 value_str_alloc = value_str;
796 }
797
798 list_for_each_entry(chain, &child->parent_val, list) {
799 chain_str = hist_browser__folded_callchain_str(browser,
800 chain, value_str, chain_str);
801 if (first) {
802 first = false;
803 first_chain = chain;
804 }
805
806 if (chain_str == NULL) {
807 chain_str = (char *)"Not enough memory!";
808 goto do_print;
809 }
810
811 chain_str_alloc = chain_str;
812 }
813
814 list_for_each_entry(chain, &child->val, list) {
815 chain_str = hist_browser__folded_callchain_str(browser,
816 chain, value_str, chain_str);
817 if (first) {
818 first = false;
819 first_chain = chain;
820 }
821
822 if (chain_str == NULL) {
823 chain_str = (char *)"Not enough memory!";
824 goto do_print;
825 }
826
827 chain_str_alloc = chain_str;
828 }
829
830do_print:
831 print(browser, first_chain, chain_str, offset, row++, arg);
832 free(value_str_alloc);
833 free(chain_str_alloc);
834
835next:
836 if (is_output_full(browser, row))
837 break;
838 node = next;
839 }
840
841 return row - first_row;
842}
843
726static int hist_browser__show_callchain(struct hist_browser *browser, 844static int hist_browser__show_callchain(struct hist_browser *browser,
727 struct rb_root *root, int level, 845 struct rb_root *root, int level,
728 unsigned short row, u64 total, 846 unsigned short row, u64 total,
@@ -980,6 +1098,11 @@ static int hist_browser__show_entry(struct hist_browser *browser,
980 &entry->sorted_chain, row, total, 1098 &entry->sorted_chain, row, total,
981 hist_browser__show_callchain_entry, &arg, 1099 hist_browser__show_callchain_entry, &arg,
982 hist_browser__check_output_full); 1100 hist_browser__check_output_full);
1101 } else if (callchain_param.mode == CHAIN_FOLDED) {
1102 printed += hist_browser__show_callchain_folded(browser,
1103 &entry->sorted_chain, row, total,
1104 hist_browser__show_callchain_entry, &arg,
1105 hist_browser__check_output_full);
983 } else { 1106 } else {
984 printed += hist_browser__show_callchain(browser, 1107 printed += hist_browser__show_callchain(browser,
985 &entry->sorted_chain, 1, row, total, 1108 &entry->sorted_chain, 1, row, total,