Commit 8c430a34 authored by Namhyung Kim's avatar Namhyung Kim Committed by Arnaldo Carvalho de Melo

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: default avatarNamhyung Kim <namhyung@kernel.org>
Tested-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: default avatarBrendan 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.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 4b3a3212
...@@ -207,6 +207,11 @@ static int callchain_node__count_flat_rows(struct callchain_node *node) ...@@ -207,6 +207,11 @@ static int callchain_node__count_flat_rows(struct callchain_node *node)
return n; 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) static int callchain_node__count_rows(struct callchain_node *node)
{ {
struct callchain_list *chain; struct callchain_list *chain;
...@@ -215,6 +220,8 @@ static int callchain_node__count_rows(struct callchain_node *node) ...@@ -215,6 +220,8 @@ static int callchain_node__count_rows(struct callchain_node *node)
if (callchain_param.mode == CHAIN_FLAT) if (callchain_param.mode == CHAIN_FLAT)
return callchain_node__count_flat_rows(node); 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, &node->val, list) { list_for_each_entry(chain, &node->val, list) {
++n; ++n;
...@@ -311,7 +318,8 @@ static void callchain__init_have_children(struct rb_root *root) ...@@ -311,7 +318,8 @@ static void callchain__init_have_children(struct rb_root *root)
for (nd = rb_first(root); nd; nd = rb_next(nd)) { for (nd = rb_first(root); nd; nd = rb_next(nd)) {
struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
callchain_node__init_have_children(node, has_sibling); 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); callchain_node__make_parent_list(node);
} }
} }
...@@ -723,6 +731,116 @@ static int hist_browser__show_callchain_flat(struct hist_browser *browser, ...@@ -723,6 +731,116 @@ static int hist_browser__show_callchain_flat(struct hist_browser *browser,
return row - first_row; 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(&new, "%s%s%s", old_str,
symbol_conf.field_sep ?: ";", str) < 0)
new = NULL;
} else {
if (value_str) {
if (asprintf(&new, "%s %s", value_str, str) < 0)
new = NULL;
} else {
if (asprintf(&new, "%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];
callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
if (asprintf(&value_str, "%s", buf) < 0) {
value_str = (char *)"<...>";
goto do_print;
}
value_str_alloc = value_str;
}
list_for_each_entry(chain, &child->parent_val, list) {
chain_str = hist_browser__folded_callchain_str(browser,
chain, value_str, chain_str);
if (first) {
first = false;
first_chain = chain;
}
if (chain_str == NULL) {
chain_str = (char *)"Not enough memory!";
goto do_print;
}
chain_str_alloc = chain_str;
}
list_for_each_entry(chain, &child->val, list) {
chain_str = hist_browser__folded_callchain_str(browser,
chain, value_str, chain_str);
if (first) {
first = false;
first_chain = chain;
}
if (chain_str == NULL) {
chain_str = (char *)"Not enough memory!";
goto do_print;
}
chain_str_alloc = chain_str;
}
do_print:
print(browser, first_chain, chain_str, offset, row++, arg);
free(value_str_alloc);
free(chain_str_alloc);
next:
if (is_output_full(browser, row))
break;
node = next;
}
return row - first_row;
}
static int hist_browser__show_callchain(struct hist_browser *browser, static int hist_browser__show_callchain(struct hist_browser *browser,
struct rb_root *root, int level, struct rb_root *root, int level,
unsigned short row, u64 total, unsigned short row, u64 total,
...@@ -980,6 +1098,11 @@ static int hist_browser__show_entry(struct hist_browser *browser, ...@@ -980,6 +1098,11 @@ static int hist_browser__show_entry(struct hist_browser *browser,
&entry->sorted_chain, row, total, &entry->sorted_chain, row, total,
hist_browser__show_callchain_entry, &arg, hist_browser__show_callchain_entry, &arg,
hist_browser__check_output_full); hist_browser__check_output_full);
} else if (callchain_param.mode == CHAIN_FOLDED) {
printed += hist_browser__show_callchain_folded(browser,
&entry->sorted_chain, row, total,
hist_browser__show_callchain_entry, &arg,
hist_browser__check_output_full);
} else { } else {
printed += hist_browser__show_callchain(browser, printed += hist_browser__show_callchain(browser,
&entry->sorted_chain, 1, row, total, &entry->sorted_chain, 1, row, total,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment