1 #ifndef __PERF_CALLCHAIN_H
2 #define __PERF_CALLCHAIN_H
3
4 #include "../perf.h"
5 /* ANDROID_CHANGE_BEGIN */
6 #if 0
7 #include <linux/list.h>
8 #include <linux/rbtree.h>
9 #else
10 #include "include/linux/list.h"
11 #include "include/linux/rbtree.h"
12 #endif
13 /* ANDROID_CHANGE_END */
14 #include "event.h"
15 #include "symbol.h"
16
17 enum chain_mode {
18 CHAIN_NONE,
19 CHAIN_FLAT,
20 CHAIN_GRAPH_ABS,
21 CHAIN_GRAPH_REL
22 };
23
24 struct callchain_node {
25 struct callchain_node *parent;
26 struct list_head siblings;
27 struct list_head children;
28 struct list_head val;
29 struct rb_node rb_node; /* to sort nodes in an rbtree */
30 struct rb_root rb_root; /* sorted tree of children */
31 unsigned int val_nr;
32 u64 hit;
33 u64 children_hit;
34 };
35
36 struct callchain_root {
37 u64 max_depth;
38 struct callchain_node node;
39 };
40
41 struct callchain_param;
42
43 typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
44 u64, struct callchain_param *);
45
46 struct callchain_param {
47 enum chain_mode mode;
48 u32 print_limit;
49 double min_percent;
50 sort_chain_func_t sort;
51 };
52
53 struct callchain_list {
54 u64 ip;
55 struct map_symbol ms;
56 struct list_head list;
57 };
58
59 /*
60 * A callchain cursor is a single linked list that
61 * let one feed a callchain progressively.
62 * It keeps persitent allocated entries to minimize
63 * allocations.
64 */
65 struct callchain_cursor_node {
66 u64 ip;
67 struct map *map;
68 struct symbol *sym;
69 struct callchain_cursor_node *next;
70 };
71
72 struct callchain_cursor {
73 u64 nr;
74 struct callchain_cursor_node *first;
75 struct callchain_cursor_node **last;
76 u64 pos;
77 struct callchain_cursor_node *curr;
78 };
79
callchain_init(struct callchain_root * root)80 static inline void callchain_init(struct callchain_root *root)
81 {
82 INIT_LIST_HEAD(&root->node.siblings);
83 INIT_LIST_HEAD(&root->node.children);
84 INIT_LIST_HEAD(&root->node.val);
85
86 root->node.parent = NULL;
87 root->node.hit = 0;
88 root->node.children_hit = 0;
89 root->max_depth = 0;
90 }
91
callchain_cumul_hits(struct callchain_node * node)92 static inline u64 callchain_cumul_hits(struct callchain_node *node)
93 {
94 return node->hit + node->children_hit;
95 }
96
97 int callchain_register_param(struct callchain_param *param);
98 int callchain_append(struct callchain_root *root,
99 struct callchain_cursor *cursor,
100 u64 period);
101
102 int callchain_merge(struct callchain_cursor *cursor,
103 struct callchain_root *dst, struct callchain_root *src);
104
105 bool ip_callchain__valid(struct ip_callchain *chain,
106 const union perf_event *event);
107 /*
108 * Initialize a cursor before adding entries inside, but keep
109 * the previously allocated entries as a cache.
110 */
callchain_cursor_reset(struct callchain_cursor * cursor)111 static inline void callchain_cursor_reset(struct callchain_cursor *cursor)
112 {
113 cursor->nr = 0;
114 cursor->last = &cursor->first;
115 }
116
117 int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip,
118 struct map *map, struct symbol *sym);
119
120 /* Close a cursor writing session. Initialize for the reader */
callchain_cursor_commit(struct callchain_cursor * cursor)121 static inline void callchain_cursor_commit(struct callchain_cursor *cursor)
122 {
123 cursor->curr = cursor->first;
124 cursor->pos = 0;
125 }
126
127 /* Cursor reading iteration helpers */
128 static inline struct callchain_cursor_node *
callchain_cursor_current(struct callchain_cursor * cursor)129 callchain_cursor_current(struct callchain_cursor *cursor)
130 {
131 if (cursor->pos == cursor->nr)
132 return NULL;
133
134 return cursor->curr;
135 }
136
callchain_cursor_advance(struct callchain_cursor * cursor)137 static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
138 {
139 cursor->curr = cursor->curr->next;
140 cursor->pos++;
141 }
142 #endif /* __PERF_CALLCHAIN_H */
143