aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2010-08-22 15:10:35 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2010-08-22 15:10:35 -0400
commit612d4fd7d0c4a866a531099d4cdd0424c1058321 (patch)
treeae5368c9e39e3f35e23ee3501a6dcf99f35d985c /tools
parent6cb8e56161c4103af9178ea45ba61ddbde02969a (diff)
perf: Support for callchains merge
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>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/callchain.c56
-rw-r--r--tools/perf/util/callchain.h1
-rw-r--r--tools/perf/util/hist.c2
3 files changed, 59 insertions, 0 deletions
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 59cc0e12dd40..e12d539417b2 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -28,6 +28,9 @@ bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event)
28#define chain_for_each_child(child, parent) \ 28#define chain_for_each_child(child, parent) \
29 list_for_each_entry(child, &parent->children, brothers) 29 list_for_each_entry(child, &parent->children, brothers)
30 30
31#define chain_for_each_child_safe(child, next, parent) \
32 list_for_each_entry_safe(child, next, &parent->children, brothers)
33
31static void 34static void
32rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 35rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
33 enum chain_mode mode) 36 enum chain_mode mode)
@@ -406,3 +409,56 @@ end:
406 409
407 return 0; 410 return 0;
408} 411}
412
413static int
414merge_chain_branch(struct callchain_node *dst, struct callchain_node *src,
415 struct resolved_chain *chain)
416{
417 struct callchain_node *child, *next_child;
418 struct callchain_list *list, *next_list;
419 int old_pos = chain->nr;
420 int err = 0;
421
422 list_for_each_entry_safe(list, next_list, &src->val, list) {
423 chain->ips[chain->nr].ip = list->ip;
424 chain->ips[chain->nr].ms = list->ms;
425 chain->nr++;
426 list_del(&list->list);
427 free(list);
428 }
429
430 if (src->hit)
431 append_chain_children(dst, chain, 0, src->hit);
432
433 chain_for_each_child_safe(child, next_child, src) {
434 err = merge_chain_branch(dst, child, chain);
435 if (err)
436 break;
437
438 list_del(&child->brothers);
439 free(child);
440 }
441
442 chain->nr = old_pos;
443
444 return err;
445}
446
447int callchain_merge(struct callchain_root *dst, struct callchain_root *src)
448{
449 struct resolved_chain *chain;
450 int err;
451
452 chain = malloc(sizeof(*chain) +
453 src->max_depth * sizeof(struct resolved_ip));
454 if (!chain)
455 return -ENOMEM;
456
457 chain->nr = 0;
458
459 err = merge_chain_branch(&dst->node, &src->node, chain);
460
461 free(chain);
462
463 return err;
464}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 85b50fbeae52..51a8f2b600bd 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -68,6 +68,7 @@ static inline u64 cumul_hits(struct callchain_node *node)
68int register_callchain_param(struct callchain_param *param); 68int register_callchain_param(struct callchain_param *param);
69int callchain_append(struct callchain_root *root, struct ip_callchain *chain, 69int callchain_append(struct callchain_root *root, struct ip_callchain *chain,
70 struct map_symbol *syms, u64 period); 70 struct map_symbol *syms, u64 period);
71int callchain_merge(struct callchain_root *dst, struct callchain_root *src);
71 72
72bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event); 73bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event);
73#endif /* __PERF_CALLCHAIN_H */ 74#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index e77ff772463e..2022e8740994 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -226,6 +226,8 @@ static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
226 226
227 if (!cmp) { 227 if (!cmp) {
228 iter->period += he->period; 228 iter->period += he->period;
229 if (symbol_conf.use_callchain)
230 callchain_merge(iter->callchain, he->callchain);
229 hist_entry__free(he); 231 hist_entry__free(he);
230 return false; 232 return false;
231 } 233 }