1#ifndef __PERF_CALLCHAIN_H
2#define __PERF_CALLCHAIN_H
3
4#include "../perf.h"
5#include <linux/list.h>
6#include <linux/rbtree.h>
7#include "event.h"
8#include "symbol.h"
9
10enum perf_call_graph_mode {
11	CALLCHAIN_NONE,
12	CALLCHAIN_FP,
13	CALLCHAIN_DWARF,
14	CALLCHAIN_LBR,
15	CALLCHAIN_MAX
16};
17
18enum chain_mode {
19	CHAIN_NONE,
20	CHAIN_FLAT,
21	CHAIN_GRAPH_ABS,
22	CHAIN_GRAPH_REL
23};
24
25enum chain_order {
26	ORDER_CALLER,
27	ORDER_CALLEE
28};
29
30struct callchain_node {
31	struct callchain_node	*parent;
32	struct list_head	val;
33	struct rb_node		rb_node_in; /* to insert nodes in an rbtree */
34	struct rb_node		rb_node;    /* to sort nodes in an output tree */
35	struct rb_root		rb_root_in; /* input tree of children */
36	struct rb_root		rb_root;    /* sorted output tree of children */
37	unsigned int		val_nr;
38	u64			hit;
39	u64			children_hit;
40};
41
42struct callchain_root {
43	u64			max_depth;
44	struct callchain_node	node;
45};
46
47struct callchain_param;
48
49typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
50				 u64, struct callchain_param *);
51
52enum chain_key {
53	CCKEY_FUNCTION,
54	CCKEY_ADDRESS
55};
56
57struct callchain_param {
58	bool			enabled;
59	enum perf_call_graph_mode record_mode;
60	u32			dump_size;
61	enum chain_mode 	mode;
62	u32			print_limit;
63	double			min_percent;
64	sort_chain_func_t	sort;
65	enum chain_order	order;
66	enum chain_key		key;
67	bool			branch_callstack;
68};
69
70extern struct callchain_param callchain_param;
71
72struct callchain_list {
73	u64			ip;
74	struct map_symbol	ms;
75	char		       *srcline;
76	struct list_head	list;
77};
78
79/*
80 * A callchain cursor is a single linked list that
81 * let one feed a callchain progressively.
82 * It keeps persistent allocated entries to minimize
83 * allocations.
84 */
85struct callchain_cursor_node {
86	u64				ip;
87	struct map			*map;
88	struct symbol			*sym;
89	struct callchain_cursor_node	*next;
90};
91
92struct callchain_cursor {
93	u64				nr;
94	struct callchain_cursor_node	*first;
95	struct callchain_cursor_node	**last;
96	u64				pos;
97	struct callchain_cursor_node	*curr;
98};
99
100extern __thread struct callchain_cursor callchain_cursor;
101
102static inline void callchain_init(struct callchain_root *root)
103{
104	INIT_LIST_HEAD(&root->node.val);
105
106	root->node.parent = NULL;
107	root->node.hit = 0;
108	root->node.children_hit = 0;
109	root->node.rb_root_in = RB_ROOT;
110	root->max_depth = 0;
111}
112
113static inline u64 callchain_cumul_hits(struct callchain_node *node)
114{
115	return node->hit + node->children_hit;
116}
117
118int callchain_register_param(struct callchain_param *param);
119int callchain_append(struct callchain_root *root,
120		     struct callchain_cursor *cursor,
121		     u64 period);
122
123int callchain_merge(struct callchain_cursor *cursor,
124		    struct callchain_root *dst, struct callchain_root *src);
125
126/*
127 * Initialize a cursor before adding entries inside, but keep
128 * the previously allocated entries as a cache.
129 */
130static inline void callchain_cursor_reset(struct callchain_cursor *cursor)
131{
132	cursor->nr = 0;
133	cursor->last = &cursor->first;
134}
135
136int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip,
137			    struct map *map, struct symbol *sym);
138
139/* Close a cursor writing session. Initialize for the reader */
140static inline void callchain_cursor_commit(struct callchain_cursor *cursor)
141{
142	cursor->curr = cursor->first;
143	cursor->pos = 0;
144}
145
146/* Cursor reading iteration helpers */
147static inline struct callchain_cursor_node *
148callchain_cursor_current(struct callchain_cursor *cursor)
149{
150	if (cursor->pos == cursor->nr)
151		return NULL;
152
153	return cursor->curr;
154}
155
156static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
157{
158	cursor->curr = cursor->curr->next;
159	cursor->pos++;
160}
161
162struct option;
163struct hist_entry;
164
165int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
166int record_callchain_opt(const struct option *opt, const char *arg, int unset);
167
168int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent,
169			      struct perf_evsel *evsel, struct addr_location *al,
170			      int max_stack);
171int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample);
172int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
173			bool hide_unresolved);
174
175extern const char record_callchain_help[];
176int parse_callchain_record_opt(const char *arg);
177int parse_callchain_report_opt(const char *arg);
178int perf_callchain_config(const char *var, const char *value);
179
180static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
181					     struct callchain_cursor *src)
182{
183	*dest = *src;
184
185	dest->first = src->curr;
186	dest->nr -= src->pos;
187}
188
189#ifdef HAVE_SKIP_CALLCHAIN_IDX
190extern int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain);
191#else
192static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused,
193			struct ip_callchain *chain __maybe_unused)
194{
195	return -1;
196}
197#endif
198
199char *callchain_list__sym_name(struct callchain_list *cl,
200			       char *bf, size_t bfsize, bool show_dso);
201
202void free_callchain(struct callchain_root *root);
203
204#endif	/* __PERF_CALLCHAIN_H */
205