Commit 26e77924 authored by Namhyung Kim's avatar Namhyung Kim Committed by Arnaldo Carvalho de Melo

perf report: Support folded callchain mode on --stdio

Add new call chain option (-g) 'folded' to print callchains in a line.
The callchains are separated by semicolons, and preceded by (absolute)
percent values and a space.

For example, the following 20 lines can be printed in 3 lines with the
folded output mode:

  $ perf report -g flat --no-children | grep -v ^# | head -20
      60.48%  swapper  [kernel.vmlinux]  [k] intel_idle
              54.60%
                 intel_idle
                 cpuidle_enter_state
                 cpuidle_enter
                 call_cpuidle
                 cpu_startup_entry
                 start_secondary

              5.88%
                 intel_idle
                 cpuidle_enter_state
                 cpuidle_enter
                 call_cpuidle
                 cpu_startup_entry
                 rest_init
                 start_kernel
                 x86_64_start_reservations
                 x86_64_start_kernel

  $ perf report -g folded --no-children | grep -v ^# | head -3
      60.48%  swapper  [kernel.vmlinux]  [k] intel_idle
  54.60% intel_idle;cpuidle_enter_state;cpuidle_enter;call_cpuidle;cpu_startup_entry;start_secondary
  5.88% intel_idle;cpuidle_enter_state;cpuidle_enter;call_cpuidle;cpu_startup_entry;rest_init;start_kernel;x86_64_start_reservations;x86_64_start_kernel

This mode is supported only for --stdio now and intended to be used by
some scripts like in FlameGraphs[1].  Support for other UI might be
added later.

[1] http://www.brendangregg.com/FlameGraphs/cpuflamegraphs.htmlRequested-and-Tested-by: default avatarBrendan Gregg <brendan.d.gregg@gmail.com>
Signed-off-by: default avatarNamhyung Kim <namhyung@kernel.org>
Tested-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1447047946-1691-2-git-send-email-namhyung@kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 566c69c3
...@@ -181,6 +181,7 @@ OPTIONS ...@@ -181,6 +181,7 @@ OPTIONS
- graph: use a graph tree, displaying absolute overhead rates. (default) - graph: use a graph tree, displaying absolute overhead rates. (default)
- fractal: like graph, but displays relative rates. Each branch of - fractal: like graph, but displays relative rates. Each branch of
the tree is considered as a new profiled object. the tree is considered as a new profiled object.
- folded: call chains are displayed in a line, separated by semicolons
- none: disable call chain display. - none: disable call chain display.
threshold is a percentage value which specifies a minimum percent to be threshold is a percentage value which specifies a minimum percent to be
......
...@@ -260,6 +260,58 @@ static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree, ...@@ -260,6 +260,58 @@ static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
return ret; return ret;
} }
static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
{
const char *sep = symbol_conf.field_sep ?: ";";
struct callchain_list *chain;
size_t ret = 0;
char bf[1024];
bool first;
if (!node)
return 0;
ret += __callchain__fprintf_folded(fp, node->parent);
first = (ret == 0);
list_for_each_entry(chain, &node->val, list) {
if (chain->ip >= PERF_CONTEXT_MAX)
continue;
ret += fprintf(fp, "%s%s", first ? "" : sep,
callchain_list__sym_name(chain,
bf, sizeof(bf), false));
first = false;
}
return ret;
}
static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree,
u64 total_samples)
{
size_t ret = 0;
u32 entries_printed = 0;
struct callchain_node *chain;
struct rb_node *rb_node = rb_first(tree);
while (rb_node) {
double percent;
chain = rb_entry(rb_node, struct callchain_node, rb_node);
percent = chain->hit * 100.0 / total_samples;
ret += fprintf(fp, "%.2f%% ", percent);
ret += __callchain__fprintf_folded(fp, chain);
ret += fprintf(fp, "\n");
if (++entries_printed == callchain_param.print_limit)
break;
rb_node = rb_next(rb_node);
}
return ret;
}
static size_t hist_entry_callchain__fprintf(struct hist_entry *he, static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
u64 total_samples, int left_margin, u64 total_samples, int left_margin,
FILE *fp) FILE *fp)
...@@ -278,6 +330,9 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he, ...@@ -278,6 +330,9 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
case CHAIN_FLAT: case CHAIN_FLAT:
return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples); return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
break; break;
case CHAIN_FOLDED:
return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples);
break;
case CHAIN_NONE: case CHAIN_NONE:
break; break;
default: default:
......
...@@ -44,6 +44,10 @@ static int parse_callchain_mode(const char *value) ...@@ -44,6 +44,10 @@ static int parse_callchain_mode(const char *value)
callchain_param.mode = CHAIN_GRAPH_REL; callchain_param.mode = CHAIN_GRAPH_REL;
return 0; return 0;
} }
if (!strncmp(value, "folded", strlen(value))) {
callchain_param.mode = CHAIN_FOLDED;
return 0;
}
return -1; return -1;
} }
...@@ -218,6 +222,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, ...@@ -218,6 +222,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
switch (mode) { switch (mode) {
case CHAIN_FLAT: case CHAIN_FLAT:
case CHAIN_FOLDED:
if (rnode->hit < chain->hit) if (rnode->hit < chain->hit)
p = &(*p)->rb_left; p = &(*p)->rb_left;
else else
...@@ -338,6 +343,7 @@ int callchain_register_param(struct callchain_param *param) ...@@ -338,6 +343,7 @@ int callchain_register_param(struct callchain_param *param)
param->sort = sort_chain_graph_rel; param->sort = sort_chain_graph_rel;
break; break;
case CHAIN_FLAT: case CHAIN_FLAT:
case CHAIN_FOLDED:
param->sort = sort_chain_flat; param->sort = sort_chain_flat;
break; break;
case CHAIN_NONE: case CHAIN_NONE:
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#define CALLCHAIN_RECORD_HELP CALLCHAIN_HELP RECORD_MODE_HELP RECORD_SIZE_HELP #define CALLCHAIN_RECORD_HELP CALLCHAIN_HELP RECORD_MODE_HELP RECORD_SIZE_HELP
#define CALLCHAIN_REPORT_HELP \ #define CALLCHAIN_REPORT_HELP \
HELP_PAD "print_type:\tcall graph printing style (graph|flat|fractal|none)\n" \ HELP_PAD "print_type:\tcall graph printing style (graph|flat|fractal|folded|none)\n" \
HELP_PAD "threshold:\tminimum call graph inclusion threshold (<percent>)\n" \ HELP_PAD "threshold:\tminimum call graph inclusion threshold (<percent>)\n" \
HELP_PAD "print_limit:\tmaximum number of call graph entry (<number>)\n" \ HELP_PAD "print_limit:\tmaximum number of call graph entry (<number>)\n" \
HELP_PAD "order:\t\tcall graph order (caller|callee)\n" \ HELP_PAD "order:\t\tcall graph order (caller|callee)\n" \
...@@ -43,7 +43,8 @@ enum chain_mode { ...@@ -43,7 +43,8 @@ enum chain_mode {
CHAIN_NONE, CHAIN_NONE,
CHAIN_FLAT, CHAIN_FLAT,
CHAIN_GRAPH_ABS, CHAIN_GRAPH_ABS,
CHAIN_GRAPH_REL CHAIN_GRAPH_REL,
CHAIN_FOLDED,
}; };
enum chain_order { enum chain_order {
......
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