Callchains have markers inside their capture to tell we enter a context (kernel, user, ...). Those are not displayed in the callchains but they are incidentally an active part of the radix tree where callchains are stored, just like any other address. If we have the two following callchains: addr1 -> addr2 -> user context -> addr3 addr1 -> addr2 -> user context -> addr4 addr1 -> addr2 -> addr 5 This is pretty common if addr1 and addr2 are part of an interrupt path, addr3 and addr4 are user addresses and addr5 is a kernel non interrupt path. This will be stored as follows in the tree: addr1 addr2 / \ / addr5 user context / \ addr3 addr4 But we ignore the context markers in the report, hence the addr3 and addr4 will appear as orphan branches: |--28.30%-- hrtimer_interrupt | smp_apic_timer_interrupt | apic_timer_interrupt | | <------------- here, no parent! | | | | | |--11.11%-- 0x7fae7bccb875 | | | | | |--11.11%-- 0xffffffffff60013b | | | | | |--11.11%-- __pthread_mutex_lock_internal | | | | | |--11.11%-- __errno_location Fix this by removing the context markers when we process the callchains to the tree. Reported-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> LKML-Reference: <1269274173-20328-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
61 lines
1.3 KiB
C
61 lines
1.3 KiB
C
#ifndef __PERF_CALLCHAIN_H
|
|
#define __PERF_CALLCHAIN_H
|
|
|
|
#include "../perf.h"
|
|
#include <linux/list.h>
|
|
#include <linux/rbtree.h>
|
|
#include "util.h"
|
|
#include "symbol.h"
|
|
|
|
enum chain_mode {
|
|
CHAIN_NONE,
|
|
CHAIN_FLAT,
|
|
CHAIN_GRAPH_ABS,
|
|
CHAIN_GRAPH_REL
|
|
};
|
|
|
|
struct callchain_node {
|
|
struct callchain_node *parent;
|
|
struct list_head brothers;
|
|
struct list_head children;
|
|
struct list_head val;
|
|
struct rb_node rb_node; /* to sort nodes in an rbtree */
|
|
struct rb_root rb_root; /* sorted tree of children */
|
|
unsigned int val_nr;
|
|
u64 hit;
|
|
u64 children_hit;
|
|
};
|
|
|
|
struct callchain_param;
|
|
|
|
typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *,
|
|
u64, struct callchain_param *);
|
|
|
|
struct callchain_param {
|
|
enum chain_mode mode;
|
|
double min_percent;
|
|
sort_chain_func_t sort;
|
|
};
|
|
|
|
struct callchain_list {
|
|
u64 ip;
|
|
struct symbol *sym;
|
|
struct list_head list;
|
|
};
|
|
|
|
static inline void callchain_init(struct callchain_node *node)
|
|
{
|
|
INIT_LIST_HEAD(&node->brothers);
|
|
INIT_LIST_HEAD(&node->children);
|
|
INIT_LIST_HEAD(&node->val);
|
|
}
|
|
|
|
static inline u64 cumul_hits(struct callchain_node *node)
|
|
{
|
|
return node->hit + node->children_hit;
|
|
}
|
|
|
|
int register_callchain_param(struct callchain_param *param);
|
|
int append_chain(struct callchain_node *root, struct ip_callchain *chain,
|
|
struct symbol **syms);
|
|
#endif /* __PERF_CALLCHAIN_H */
|