Skip to content

Commit

Permalink
perf: Sync callchains with period based hits
Browse files Browse the repository at this point in the history
Hists have their hits increased by the event period. And this
period based counting is the foundation of all the stats in
perf report.

But callchains still use the raw number of hits, without taking
the period into account. So when we compute the percentage,
absolute based percentages are totally broken, and relative ones
too in the first parent level. Because we pass the number of events
muliplied by their period as the total number of hits to the
callchain filtering, while callchains expect this number to be
the number of raw hits.

perf report -g graph was simply not working, showing no graph unless
the min percent was zero. And even there the percentage of the
branches was always 0. And may be fractal filtering was broken on
the first branch level too.

flat also was broken, but it was hidden because of other breakages.

Anyway fix this by counting using periods on callchains.

Signed-off-by: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Paul Mackerras <[email protected]>
  • Loading branch information
fweisbec committed Jul 8, 2010
1 parent 97aa105 commit 108553e
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 19 deletions.
2 changes: 1 addition & 1 deletion tools/perf/builtin-report.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
goto out_free_syms;
err = 0;
if (symbol_conf.use_callchain) {
err = append_chain(he->callchain, data->callchain, syms);
err = append_chain(he->callchain, data->callchain, syms, data->period);
if (err)
goto out_free_syms;
}
Expand Down
35 changes: 18 additions & 17 deletions tools/perf/util/callchain.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,15 +230,15 @@ fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)

static void
add_child(struct callchain_node *parent, struct resolved_chain *chain,
int start)
int start, u64 period)
{
struct callchain_node *new;

new = create_child(parent, false);
fill_node(new, chain, start);

new->children_hit = 0;
new->hit = 1;
new->hit = period;
}

/*
Expand All @@ -248,7 +248,8 @@ add_child(struct callchain_node *parent, struct resolved_chain *chain,
*/
static void
split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
struct callchain_list *to_split, int idx_parents, int idx_local)
struct callchain_list *to_split, int idx_parents, int idx_local,
u64 period)
{
struct callchain_node *new;
struct list_head *old_tail;
Expand All @@ -275,41 +276,41 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
/* create a new child for the new branch if any */
if (idx_total < chain->nr) {
parent->hit = 0;
add_child(parent, chain, idx_total);
parent->children_hit++;
add_child(parent, chain, idx_total, period);
parent->children_hit += period;
} else {
parent->hit = 1;
parent->hit = period;
}
}

static int
__append_chain(struct callchain_node *root, struct resolved_chain *chain,
unsigned int start);
unsigned int start, u64 period);

static void
__append_chain_children(struct callchain_node *root,
struct resolved_chain *chain,
unsigned int start)
unsigned int start, u64 period)
{
struct callchain_node *rnode;

/* lookup in childrens */
chain_for_each_child(rnode, root) {
unsigned int ret = __append_chain(rnode, chain, start);
unsigned int ret = __append_chain(rnode, chain, start, period);

if (!ret)
goto inc_children_hit;
}
/* nothing in children, add to the current node */
add_child(root, chain, start);
add_child(root, chain, start, period);

inc_children_hit:
root->children_hit++;
root->children_hit += period;
}

static int
__append_chain(struct callchain_node *root, struct resolved_chain *chain,
unsigned int start)
unsigned int start, u64 period)
{
struct callchain_list *cnode;
unsigned int i = start;
Expand Down Expand Up @@ -345,18 +346,18 @@ __append_chain(struct callchain_node *root, struct resolved_chain *chain,

/* we match only a part of the node. Split it and add the new chain */
if (i - start < root->val_nr) {
split_add_child(root, chain, cnode, start, i - start);
split_add_child(root, chain, cnode, start, i - start, period);
return 0;
}

/* we match 100% of the path, increment the hit */
if (i - start == root->val_nr && i == chain->nr) {
root->hit++;
root->hit += period;
return 0;
}

/* We match the node and still have a part remaining */
__append_chain_children(root, chain, i);
__append_chain_children(root, chain, i, period);

return 0;
}
Expand All @@ -380,7 +381,7 @@ static void filter_context(struct ip_callchain *old, struct resolved_chain *new,


int append_chain(struct callchain_node *root, struct ip_callchain *chain,
struct map_symbol *syms)
struct map_symbol *syms, u64 period)
{
struct resolved_chain *filtered;

Expand All @@ -397,7 +398,7 @@ int append_chain(struct callchain_node *root, struct ip_callchain *chain,
if (!filtered->nr)
goto end;

__append_chain_children(root, filtered, 0);
__append_chain_children(root, filtered, 0, period);
end:
free(filtered);

Expand Down
2 changes: 1 addition & 1 deletion tools/perf/util/callchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ static inline u64 cumul_hits(struct callchain_node *node)

int register_callchain_param(struct callchain_param *param);
int append_chain(struct callchain_node *root, struct ip_callchain *chain,
struct map_symbol *syms);
struct map_symbol *syms, u64 period);

bool ip_callchain__valid(struct ip_callchain *chain, event_t *event);
#endif /* __PERF_CALLCHAIN_H */

0 comments on commit 108553e

Please sign in to comment.