[PATCH 35/37] perf hists browser: Support folded callchains

2015-11-19 Thread Arnaldo Carvalho de Melo
From: Namhyung Kim 

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 
Tested-by: Arnaldo Carvalho de Melo 
Tested-by: Brendan Gregg 
Cc: Andi Kleen 
Cc: David Ahern 
Cc: Frederic Weisbecker 
Cc: Jiri Olsa 
Cc: Kan Liang 
Cc: Peter Zijlstra 
Link: 
http://lkml.kernel.org/r/1447047946-1691-9-git-send-email-namhy...@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo 
---
 tools/perf/ui/browsers/hists.c | 125 -
 1 file changed, 124 insertions(+), 1 deletion(-)

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)
return n;
 }
 
+static int callchain_node__count_folded_rows(struct callchain_node *node 
__maybe_unused)
+{
+   return 1;
+}
+
 static int callchain_node__count_rows(struct callchain_node *node)
 {
struct callchain_list *chain;
@@ -215,6 +220,8 @@ static int callchain_node__count_rows(struct callchain_node 
*node)
 
if (callchain_param.mode == CHAIN_FLAT)
return callchain_node__count_flat_rows(node);
+   else if (callchain_param.mode == CHAIN_FOLDED)
+   return callchain_node__count_folded_rows(node);
 
list_for_each_entry(chain, >val, list) {
++n;
@@ -311,7 +318,8 @@ static void callchain__init_have_children(struct rb_root 
*root)
for (nd = rb_first(root); nd; nd = rb_next(nd)) {
struct callchain_node *node = rb_entry(nd, struct 
callchain_node, rb_node);
callchain_node__init_have_children(node, has_sibling);
-   if (callchain_param.mode == CHAIN_FLAT)
+   if (callchain_param.mode == CHAIN_FLAT ||
+   callchain_param.mode == CHAIN_FOLDED)
callchain_node__make_parent_list(node);
}
 }
@@ -723,6 +731,116 @@ out:
return row - first_row;
 }
 
+static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
+   struct callchain_list *chain,
+   char *value_str, char *old_str)
+{
+   char bf[1024];
+   const char *str;
+   char *new;
+
+   str = callchain_list__sym_name(chain, bf, sizeof(bf),
+  browser->show_dso);
+   if (old_str) {
+   if (asprintf(, "%s%s%s", old_str,
+symbol_conf.field_sep ?: ";", str) < 0)
+   new = NULL;
+   } else {
+   if (value_str) {
+   if (asprintf(, "%s %s", value_str, str) < 0)
+   new = NULL;
+   } else {
+   if (asprintf(, "%s", str) < 0)
+   new = NULL;
+   }
+   }
+   return new;
+}
+
+static int hist_browser__show_callchain_folded(struct hist_browser *browser,
+  struct rb_root *root,
+  unsigned short row, u64 total,
+  print_callchain_entry_fn print,
+  struct callchain_print_arg *arg,
+  check_output_full_fn 
is_output_full)
+{
+   struct rb_node *node;
+   int first_row = row, offset = LEVEL_OFFSET_STEP;
+   bool need_percent;
+
+   node = rb_first(root);
+   need_percent = node && rb_next(node);
+
+   while (node) {
+   struct callchain_node *child = rb_entry(node, struct 
callchain_node, rb_node);
+   struct rb_node *next = rb_next(node);
+   struct callchain_list *chain, *first_chain = NULL;
+   int first = true;
+   char *value_str = NULL, *value_str_alloc = NULL;
+   char *chain_str = NULL, *chain_str_alloc = NULL;
+
+   if (arg->row_offset != 0) {
+   arg->row_offset--;
+   goto next;
+   }
+
+   if (need_percent) {
+   char buf[64];
+
+ 

[PATCH 35/37] perf hists browser: Support folded callchains

2015-11-19 Thread Arnaldo Carvalho de Melo
From: Namhyung Kim 

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 
Tested-by: Arnaldo Carvalho de Melo 
Tested-by: Brendan Gregg 
Cc: Andi Kleen 
Cc: David Ahern 
Cc: Frederic Weisbecker 
Cc: Jiri Olsa 
Cc: Kan Liang 
Cc: Peter Zijlstra 
Link: 
http://lkml.kernel.org/r/1447047946-1691-9-git-send-email-namhy...@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo 
---
 tools/perf/ui/browsers/hists.c | 125 -
 1 file changed, 124 insertions(+), 1 deletion(-)

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)
return n;
 }
 
+static int callchain_node__count_folded_rows(struct callchain_node *node 
__maybe_unused)
+{
+   return 1;
+}
+
 static int callchain_node__count_rows(struct callchain_node *node)
 {
struct callchain_list *chain;
@@ -215,6 +220,8 @@ static int callchain_node__count_rows(struct callchain_node 
*node)
 
if (callchain_param.mode == CHAIN_FLAT)
return callchain_node__count_flat_rows(node);
+   else if (callchain_param.mode == CHAIN_FOLDED)
+   return callchain_node__count_folded_rows(node);
 
list_for_each_entry(chain, >val, list) {
++n;
@@ -311,7 +318,8 @@ static void callchain__init_have_children(struct rb_root 
*root)
for (nd = rb_first(root); nd; nd = rb_next(nd)) {
struct callchain_node *node = rb_entry(nd, struct 
callchain_node, rb_node);
callchain_node__init_have_children(node, has_sibling);
-   if (callchain_param.mode == CHAIN_FLAT)
+   if (callchain_param.mode == CHAIN_FLAT ||
+   callchain_param.mode == CHAIN_FOLDED)
callchain_node__make_parent_list(node);
}
 }
@@ -723,6 +731,116 @@ out:
return row - first_row;
 }
 
+static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
+   struct callchain_list *chain,
+   char *value_str, char *old_str)
+{
+   char bf[1024];
+   const char *str;
+   char *new;
+
+   str = callchain_list__sym_name(chain, bf, sizeof(bf),
+  browser->show_dso);
+   if (old_str) {
+   if (asprintf(, "%s%s%s", old_str,
+symbol_conf.field_sep ?: ";", str) < 0)
+   new = NULL;
+   } else {
+   if (value_str) {
+   if (asprintf(, "%s %s", value_str, str) < 0)
+   new = NULL;
+   } else {
+   if (asprintf(, "%s", str) < 0)
+   new = NULL;
+   }
+   }
+   return new;
+}
+
+static int hist_browser__show_callchain_folded(struct hist_browser *browser,
+  struct rb_root *root,
+  unsigned short row, u64 total,
+  print_callchain_entry_fn print,
+  struct callchain_print_arg *arg,
+  check_output_full_fn 
is_output_full)
+{
+   struct rb_node *node;
+   int first_row = row, offset = LEVEL_OFFSET_STEP;
+   bool need_percent;
+
+   node = rb_first(root);
+   need_percent = node && rb_next(node);
+
+   while (node) {
+   struct callchain_node *child = rb_entry(node, struct 
callchain_node, rb_node);
+   struct rb_node *next = rb_next(node);
+   struct callchain_list *chain, *first_chain = NULL;
+   int first = true;
+   char *value_str = NULL, *value_str_alloc = NULL;
+   char *chain_str = NULL, *chain_str_alloc =