mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-20 01:24:39 +08:00
612d4fd7d0
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>
75 lines
1.7 KiB
C
75 lines
1.7 KiB
C
#ifndef __PERF_CALLCHAIN_H
|
|
#define __PERF_CALLCHAIN_H
|
|
|
|
#include "../perf.h"
|
|
#include <linux/list.h>
|
|
#include <linux/rbtree.h>
|
|
#include "event.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_root {
|
|
u64 max_depth;
|
|
struct callchain_node node;
|
|
};
|
|
|
|
struct callchain_param;
|
|
|
|
typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
|
|
u64, struct callchain_param *);
|
|
|
|
struct callchain_param {
|
|
enum chain_mode mode;
|
|
u32 print_limit;
|
|
double min_percent;
|
|
sort_chain_func_t sort;
|
|
};
|
|
|
|
struct callchain_list {
|
|
u64 ip;
|
|
struct map_symbol ms;
|
|
struct list_head list;
|
|
};
|
|
|
|
static inline void callchain_init(struct callchain_root *root)
|
|
{
|
|
INIT_LIST_HEAD(&root->node.brothers);
|
|
INIT_LIST_HEAD(&root->node.children);
|
|
INIT_LIST_HEAD(&root->node.val);
|
|
|
|
root->node.parent = NULL;
|
|
root->node.hit = 0;
|
|
root->max_depth = 0;
|
|
}
|
|
|
|
static inline u64 cumul_hits(struct callchain_node *node)
|
|
{
|
|
return node->hit + node->children_hit;
|
|
}
|
|
|
|
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 */
|