Skip to content

Commit

Permalink
perf: Support for callchains merge
Browse files Browse the repository at this point in the history
If we sort the histograms by comm, which is the default,
we need to merge some of them, typically different thread
histograms of a same process, or just same comm. But during
this merge, we forgot to merge callchains.

So imagine we have three threads (tids: 1000, 1001, 1002) that
belong to comm "foo".

tid 1000 got 100 events
tid 1001 got 10 events
tid 1002 got 3 events

Once we merge these histograms to get a per comm result, we'll
finally get:

"foo" got 113 events

The problem is if we merge 1000 and 1001 histograms into 1002, then
the end merge result, wrt callchains, will be only callchains that
belong to 1002.
This is because we haven't handled callchains in the merge. Only those
from one of the threads inside a common comm survive.

It means during this merge, we can lose a lot of callchains.

Fix this by implementing callchains merge and apply it on histograms
that collapse.

Reported-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
  • Loading branch information
Frederic Weisbecker committed Aug 22, 2010
1 parent 6cb8e56 commit 612d4fd
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 0 deletions.
56 changes: 56 additions & 0 deletions tools/perf/util/callchain.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event)
#define chain_for_each_child(child, parent) \
list_for_each_entry(child, &parent->children, brothers)

#define chain_for_each_child_safe(child, next, parent) \
list_for_each_entry_safe(child, next, &parent->children, brothers)

static void
rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
enum chain_mode mode)
Expand Down Expand Up @@ -406,3 +409,56 @@ int callchain_append(struct callchain_root *root, struct ip_callchain *chain,

return 0;
}

static int
merge_chain_branch(struct callchain_node *dst, struct callchain_node *src,
struct resolved_chain *chain)
{
struct callchain_node *child, *next_child;
struct callchain_list *list, *next_list;
int old_pos = chain->nr;
int err = 0;

list_for_each_entry_safe(list, next_list, &src->val, list) {
chain->ips[chain->nr].ip = list->ip;
chain->ips[chain->nr].ms = list->ms;
chain->nr++;
list_del(&list->list);
free(list);
}

if (src->hit)
append_chain_children(dst, chain, 0, src->hit);

chain_for_each_child_safe(child, next_child, src) {
err = merge_chain_branch(dst, child, chain);
if (err)
break;

list_del(&child->brothers);
free(child);
}

chain->nr = old_pos;

return err;
}

int callchain_merge(struct callchain_root *dst, struct callchain_root *src)
{
struct resolved_chain *chain;
int err;

chain = malloc(sizeof(*chain) +
src->max_depth * sizeof(struct resolved_ip));
if (!chain)
return -ENOMEM;

chain->nr = 0;

err = merge_chain_branch(&dst->node, &src->node, chain);

free(chain);

return err;
}
1 change: 1 addition & 0 deletions tools/perf/util/callchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ static inline u64 cumul_hits(struct callchain_node *node)
int register_callchain_param(struct callchain_param *param);
int callchain_append(struct callchain_root *root, struct ip_callchain *chain,
struct map_symbol *syms, u64 period);
int callchain_merge(struct callchain_root *dst, struct callchain_root *src);

bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event);
#endif /* __PERF_CALLCHAIN_H */
2 changes: 2 additions & 0 deletions tools/perf/util/hist.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)

if (!cmp) {
iter->period += he->period;
if (symbol_conf.use_callchain)
callchain_merge(iter->callchain, he->callchain);
hist_entry__free(he);
return false;
}
Expand Down

0 comments on commit 612d4fd

Please sign in to comment.