diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/util/callchain.c | 56 | ||||
-rw-r--r-- | tools/perf/util/callchain.h | 1 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 2 |
3 files changed, 59 insertions, 0 deletions
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 59cc0e12dd4..e12d539417b 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 | |||
31 | static void | 34 | static void |
32 | rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, | 35 | rb_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 | |||
413 | static int | ||
414 | merge_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 | |||
447 | int 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 85b50fbeae5..51a8f2b600b 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) | |||
68 | int register_callchain_param(struct callchain_param *param); | 68 | int register_callchain_param(struct callchain_param *param); |
69 | int callchain_append(struct callchain_root *root, struct ip_callchain *chain, | 69 | int callchain_append(struct callchain_root *root, struct ip_callchain *chain, |
70 | struct map_symbol *syms, u64 period); | 70 | struct map_symbol *syms, u64 period); |
71 | int callchain_merge(struct callchain_root *dst, struct callchain_root *src); | ||
71 | 72 | ||
72 | bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event); | 73 | bool 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 e77ff772463..2022e874099 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 | } |