Skip to content

Commit

Permalink
perf tools: Fix display of first level of callchains
Browse files Browse the repository at this point in the history
The callchain stdio mode display was written using a sorted by symbol
report. In this mode we have only one callchain root per hist so we
forgot to handle cases where we have multiple callchain root, as in per
dso sorting for example.

Fix this by handling these roots like any other branch, with the hist as
the parent.

Before:

     1.97%  libpthread-2.12.1.so
            |
            --- __libc_write
                create_worker
                bench_sched_messaging
                cmd_bench
                run_builtin
                main
                __libc_start_main

            |
            --- __libc_read
                create_worker
                bench_sched_messaging
                cmd_bench
                run_builtin
                main
                __libc_start_main

After:

     1.97%  libpthread-2.12.1.so
            |
            |--36.97%-- __libc_write
            |          create_worker
            |          bench_sched_messaging
            |          cmd_bench
            |          run_builtin
            |          main
            |          __libc_start_main
            |
            |--31.47%-- __libc_read
            |          create_worker
            |          bench_sched_messaging
            |          cmd_bench
            |          run_builtin
            |          main
            |          __libc_start_main
           ...

Single roots keep their entry without percentage because they have
the same overhead than the hist they refer to. ie: 100% in fractal
mode and the percentage of the hist in graph mode:

     0.00%  [k] reschedule_interrupt
            |
            --- default_idle
                amd_e400_idle
                cpu_idle
                start_secondary

Reported-by: Benjamin Herrenschmidt <[email protected]>
Signed-off-by: Frederic Weisbecker <[email protected]>
Cc: Benjamin Herrenschmidt <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
  • Loading branch information
fweisbec authored and acmel committed Mar 26, 2012
1 parent b01c3a0 commit 6d4818c
Showing 1 changed file with 93 additions and 64 deletions.
157 changes: 93 additions & 64 deletions tools/perf/util/hist.c
Original file line number Diff line number Diff line change
Expand Up @@ -607,29 +607,24 @@ static void init_rem_hits(void)
rem_hits.ms.sym = rem_sq_bracket;
}

static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
u64 total_samples, int depth,
int depth_mask, int left_margin)
{
struct rb_node *node, *next;
struct callchain_node *child;
struct callchain_list *chain;
int new_depth_mask = depth_mask;
u64 new_total;
u64 remaining;
size_t ret = 0;
int i;
uint entries_printed = 0;

if (callchain_param.mode == CHAIN_GRAPH_REL)
new_total = self->children_hit;
else
new_total = total_samples;

remaining = new_total;
remaining = total_samples;

node = rb_first(&self->rb_root);
node = rb_first(root);
while (node) {
u64 new_total;
u64 cumul;

child = rb_entry(node, struct callchain_node, rb_node);
Expand Down Expand Up @@ -657,11 +652,17 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
list_for_each_entry(chain, &child->val, list) {
ret += ipchain__fprintf_graph(fp, chain, depth,
new_depth_mask, i++,
new_total,
total_samples,
cumul,
left_margin);
}
ret += __callchain__fprintf_graph(fp, child, new_total,

if (callchain_param.mode == CHAIN_GRAPH_REL)
new_total = child->children_hit;
else
new_total = total_samples;

ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
depth + 1,
new_depth_mask | (1 << depth),
left_margin);
Expand All @@ -671,69 +672,83 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
}

if (callchain_param.mode == CHAIN_GRAPH_REL &&
remaining && remaining != new_total) {
remaining && remaining != total_samples) {

if (!rem_sq_bracket)
return ret;

new_depth_mask &= ~(1 << (depth - 1));

ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
new_depth_mask, 0, new_total,
new_depth_mask, 0, total_samples,
remaining, left_margin);
}

return ret;
}

static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
u64 total_samples, int left_margin)
{
struct callchain_node *cnode;
struct callchain_list *chain;
u32 entries_printed = 0;
bool printed = false;
struct rb_node *node;
int i = 0;
int ret = 0;
u32 entries_printed = 0;

list_for_each_entry(chain, &self->val, list) {
if (!i++ && sort__first_dimension == SORT_SYM)
continue;

if (!printed) {
ret += callchain__fprintf_left_margin(fp, left_margin);
ret += fprintf(fp, "|\n");
ret += callchain__fprintf_left_margin(fp, left_margin);
ret += fprintf(fp, "---");

left_margin += 3;
printed = true;
} else
ret += callchain__fprintf_left_margin(fp, left_margin);
int ret;

if (chain->ms.sym)
ret += fprintf(fp, " %s\n", chain->ms.sym->name);
else
ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
/*
* If have one single callchain root, don't bother printing
* its percentage (100 % in fractal mode and the same percentage
* than the hist in graph mode). This also avoid one level of column.
*/
node = rb_first(root);
if (node && !rb_next(node)) {
cnode = rb_entry(node, struct callchain_node, rb_node);
list_for_each_entry(chain, &cnode->val, list) {
/*
* If we sort by symbol, the first entry is the same than
* the symbol. No need to print it otherwise it appears as
* displayed twice.
*/
if (!i++ && sort__first_dimension == SORT_SYM)
continue;
if (!printed) {
ret += callchain__fprintf_left_margin(fp, left_margin);
ret += fprintf(fp, "|\n");
ret += callchain__fprintf_left_margin(fp, left_margin);
ret += fprintf(fp, "---");
left_margin += 3;
printed = true;
} else
ret += callchain__fprintf_left_margin(fp, left_margin);

if (chain->ms.sym)
ret += fprintf(fp, " %s\n", chain->ms.sym->name);
else
ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);

if (++entries_printed == callchain_param.print_limit)
break;
if (++entries_printed == callchain_param.print_limit)
break;
}
root = &cnode->rb_root;
}

ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);

return ret;
return __callchain__fprintf_graph(fp, root, total_samples,
1, 1, left_margin);
}

static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
u64 total_samples)
static size_t __callchain__fprintf_flat(FILE *fp,
struct callchain_node *self,
u64 total_samples)
{
struct callchain_list *chain;
size_t ret = 0;

if (!self)
return 0;

ret += callchain__fprintf_flat(fp, self->parent, total_samples);
ret += __callchain__fprintf_flat(fp, self->parent, total_samples);


list_for_each_entry(chain, &self->val, list) {
Expand All @@ -749,44 +764,58 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
return ret;
}

static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
u64 total_samples, int left_margin,
FILE *fp)
static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self,
u64 total_samples)
{
struct rb_node *rb_node;
struct callchain_node *chain;
size_t ret = 0;
u32 entries_printed = 0;
struct rb_node *rb_node;
struct callchain_node *chain;

rb_node = rb_first(&he->sorted_chain);
rb_node = rb_first(self);
while (rb_node) {
double percent;

chain = rb_entry(rb_node, struct callchain_node, rb_node);
percent = chain->hit * 100.0 / total_samples;
switch (callchain_param.mode) {
case CHAIN_FLAT:
ret += percent_color_fprintf(fp, " %6.2f%%\n",
percent);
ret += callchain__fprintf_flat(fp, chain, total_samples);
break;
case CHAIN_GRAPH_ABS: /* Falldown */
case CHAIN_GRAPH_REL:
ret += callchain__fprintf_graph(fp, chain, total_samples,
left_margin);
case CHAIN_NONE:
default:
break;
}

ret = percent_color_fprintf(fp, " %6.2f%%\n", percent);
ret += __callchain__fprintf_flat(fp, chain, total_samples);
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,
u64 total_samples, int left_margin,
FILE *fp)
{
switch (callchain_param.mode) {
case CHAIN_GRAPH_REL:
return callchain__fprintf_graph(fp, &he->sorted_chain, he->period,
left_margin);
break;
case CHAIN_GRAPH_ABS:
return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
left_margin);
break;
case CHAIN_FLAT:
return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
break;
case CHAIN_NONE:
break;
default:
pr_err("Bad callchain mode\n");
}

return 0;
}

void hists__output_recalc_col_len(struct hists *hists, int max_rows)
{
struct rb_node *next = rb_first(&hists->entries);
Expand Down

0 comments on commit 6d4818c

Please sign in to comment.