xref: /openbmc/linux/tools/perf/util/callchain.c (revision 161f4089)
1 /*
2  * Copyright (C) 2009-2011, Frederic Weisbecker <fweisbec@gmail.com>
3  *
4  * Handle the callchains from the stream in an ad-hoc radix tree and then
5  * sort them in an rbtree.
6  *
7  * Using a radix for code path provides a fast retrieval and factorizes
8  * memory use. Also that lets us use the paths in a hierarchical graph view.
9  *
10  */
11 
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <stdbool.h>
15 #include <errno.h>
16 #include <math.h>
17 
18 #include "hist.h"
19 #include "util.h"
20 #include "callchain.h"
21 
22 __thread struct callchain_cursor callchain_cursor;
23 
24 static void
25 rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
26 		    enum chain_mode mode)
27 {
28 	struct rb_node **p = &root->rb_node;
29 	struct rb_node *parent = NULL;
30 	struct callchain_node *rnode;
31 	u64 chain_cumul = callchain_cumul_hits(chain);
32 
33 	while (*p) {
34 		u64 rnode_cumul;
35 
36 		parent = *p;
37 		rnode = rb_entry(parent, struct callchain_node, rb_node);
38 		rnode_cumul = callchain_cumul_hits(rnode);
39 
40 		switch (mode) {
41 		case CHAIN_FLAT:
42 			if (rnode->hit < chain->hit)
43 				p = &(*p)->rb_left;
44 			else
45 				p = &(*p)->rb_right;
46 			break;
47 		case CHAIN_GRAPH_ABS: /* Falldown */
48 		case CHAIN_GRAPH_REL:
49 			if (rnode_cumul < chain_cumul)
50 				p = &(*p)->rb_left;
51 			else
52 				p = &(*p)->rb_right;
53 			break;
54 		case CHAIN_NONE:
55 		default:
56 			break;
57 		}
58 	}
59 
60 	rb_link_node(&chain->rb_node, parent, p);
61 	rb_insert_color(&chain->rb_node, root);
62 }
63 
64 static void
65 __sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
66 		  u64 min_hit)
67 {
68 	struct rb_node *n;
69 	struct callchain_node *child;
70 
71 	n = rb_first(&node->rb_root_in);
72 	while (n) {
73 		child = rb_entry(n, struct callchain_node, rb_node_in);
74 		n = rb_next(n);
75 
76 		__sort_chain_flat(rb_root, child, min_hit);
77 	}
78 
79 	if (node->hit && node->hit >= min_hit)
80 		rb_insert_callchain(rb_root, node, CHAIN_FLAT);
81 }
82 
83 /*
84  * Once we get every callchains from the stream, we can now
85  * sort them by hit
86  */
87 static void
88 sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
89 		u64 min_hit, struct callchain_param *param __maybe_unused)
90 {
91 	__sort_chain_flat(rb_root, &root->node, min_hit);
92 }
93 
94 static void __sort_chain_graph_abs(struct callchain_node *node,
95 				   u64 min_hit)
96 {
97 	struct rb_node *n;
98 	struct callchain_node *child;
99 
100 	node->rb_root = RB_ROOT;
101 	n = rb_first(&node->rb_root_in);
102 
103 	while (n) {
104 		child = rb_entry(n, struct callchain_node, rb_node_in);
105 		n = rb_next(n);
106 
107 		__sort_chain_graph_abs(child, min_hit);
108 		if (callchain_cumul_hits(child) >= min_hit)
109 			rb_insert_callchain(&node->rb_root, child,
110 					    CHAIN_GRAPH_ABS);
111 	}
112 }
113 
114 static void
115 sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
116 		     u64 min_hit, struct callchain_param *param __maybe_unused)
117 {
118 	__sort_chain_graph_abs(&chain_root->node, min_hit);
119 	rb_root->rb_node = chain_root->node.rb_root.rb_node;
120 }
121 
122 static void __sort_chain_graph_rel(struct callchain_node *node,
123 				   double min_percent)
124 {
125 	struct rb_node *n;
126 	struct callchain_node *child;
127 	u64 min_hit;
128 
129 	node->rb_root = RB_ROOT;
130 	min_hit = ceil(node->children_hit * min_percent);
131 
132 	n = rb_first(&node->rb_root_in);
133 	while (n) {
134 		child = rb_entry(n, struct callchain_node, rb_node_in);
135 		n = rb_next(n);
136 
137 		__sort_chain_graph_rel(child, min_percent);
138 		if (callchain_cumul_hits(child) >= min_hit)
139 			rb_insert_callchain(&node->rb_root, child,
140 					    CHAIN_GRAPH_REL);
141 	}
142 }
143 
144 static void
145 sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
146 		     u64 min_hit __maybe_unused, struct callchain_param *param)
147 {
148 	__sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
149 	rb_root->rb_node = chain_root->node.rb_root.rb_node;
150 }
151 
152 int callchain_register_param(struct callchain_param *param)
153 {
154 	switch (param->mode) {
155 	case CHAIN_GRAPH_ABS:
156 		param->sort = sort_chain_graph_abs;
157 		break;
158 	case CHAIN_GRAPH_REL:
159 		param->sort = sort_chain_graph_rel;
160 		break;
161 	case CHAIN_FLAT:
162 		param->sort = sort_chain_flat;
163 		break;
164 	case CHAIN_NONE:
165 	default:
166 		return -1;
167 	}
168 	return 0;
169 }
170 
171 /*
172  * Create a child for a parent. If inherit_children, then the new child
173  * will become the new parent of it's parent children
174  */
175 static struct callchain_node *
176 create_child(struct callchain_node *parent, bool inherit_children)
177 {
178 	struct callchain_node *new;
179 
180 	new = zalloc(sizeof(*new));
181 	if (!new) {
182 		perror("not enough memory to create child for code path tree");
183 		return NULL;
184 	}
185 	new->parent = parent;
186 	INIT_LIST_HEAD(&new->val);
187 
188 	if (inherit_children) {
189 		struct rb_node *n;
190 		struct callchain_node *child;
191 
192 		new->rb_root_in = parent->rb_root_in;
193 		parent->rb_root_in = RB_ROOT;
194 
195 		n = rb_first(&new->rb_root_in);
196 		while (n) {
197 			child = rb_entry(n, struct callchain_node, rb_node_in);
198 			child->parent = new;
199 			n = rb_next(n);
200 		}
201 
202 		/* make it the first child */
203 		rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
204 		rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
205 	}
206 
207 	return new;
208 }
209 
210 
211 /*
212  * Fill the node with callchain values
213  */
214 static void
215 fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
216 {
217 	struct callchain_cursor_node *cursor_node;
218 
219 	node->val_nr = cursor->nr - cursor->pos;
220 	if (!node->val_nr)
221 		pr_warning("Warning: empty node in callchain tree\n");
222 
223 	cursor_node = callchain_cursor_current(cursor);
224 
225 	while (cursor_node) {
226 		struct callchain_list *call;
227 
228 		call = zalloc(sizeof(*call));
229 		if (!call) {
230 			perror("not enough memory for the code path tree");
231 			return;
232 		}
233 		call->ip = cursor_node->ip;
234 		call->ms.sym = cursor_node->sym;
235 		call->ms.map = cursor_node->map;
236 		list_add_tail(&call->list, &node->val);
237 
238 		callchain_cursor_advance(cursor);
239 		cursor_node = callchain_cursor_current(cursor);
240 	}
241 }
242 
243 static struct callchain_node *
244 add_child(struct callchain_node *parent,
245 	  struct callchain_cursor *cursor,
246 	  u64 period)
247 {
248 	struct callchain_node *new;
249 
250 	new = create_child(parent, false);
251 	fill_node(new, cursor);
252 
253 	new->children_hit = 0;
254 	new->hit = period;
255 	return new;
256 }
257 
258 static s64 match_chain(struct callchain_cursor_node *node,
259 		      struct callchain_list *cnode)
260 {
261 	struct symbol *sym = node->sym;
262 
263 	if (cnode->ms.sym && sym &&
264 	    callchain_param.key == CCKEY_FUNCTION)
265 		return cnode->ms.sym->start - sym->start;
266 	else
267 		return cnode->ip - node->ip;
268 }
269 
270 /*
271  * Split the parent in two parts (a new child is created) and
272  * give a part of its callchain to the created child.
273  * Then create another child to host the given callchain of new branch
274  */
275 static void
276 split_add_child(struct callchain_node *parent,
277 		struct callchain_cursor *cursor,
278 		struct callchain_list *to_split,
279 		u64 idx_parents, u64 idx_local, u64 period)
280 {
281 	struct callchain_node *new;
282 	struct list_head *old_tail;
283 	unsigned int idx_total = idx_parents + idx_local;
284 
285 	/* split */
286 	new = create_child(parent, true);
287 
288 	/* split the callchain and move a part to the new child */
289 	old_tail = parent->val.prev;
290 	list_del_range(&to_split->list, old_tail);
291 	new->val.next = &to_split->list;
292 	new->val.prev = old_tail;
293 	to_split->list.prev = &new->val;
294 	old_tail->next = &new->val;
295 
296 	/* split the hits */
297 	new->hit = parent->hit;
298 	new->children_hit = parent->children_hit;
299 	parent->children_hit = callchain_cumul_hits(new);
300 	new->val_nr = parent->val_nr - idx_local;
301 	parent->val_nr = idx_local;
302 
303 	/* create a new child for the new branch if any */
304 	if (idx_total < cursor->nr) {
305 		struct callchain_node *first;
306 		struct callchain_list *cnode;
307 		struct callchain_cursor_node *node;
308 		struct rb_node *p, **pp;
309 
310 		parent->hit = 0;
311 		parent->children_hit += period;
312 
313 		node = callchain_cursor_current(cursor);
314 		new = add_child(parent, cursor, period);
315 
316 		/*
317 		 * This is second child since we moved parent's children
318 		 * to new (first) child above.
319 		 */
320 		p = parent->rb_root_in.rb_node;
321 		first = rb_entry(p, struct callchain_node, rb_node_in);
322 		cnode = list_first_entry(&first->val, struct callchain_list,
323 					 list);
324 
325 		if (match_chain(node, cnode) < 0)
326 			pp = &p->rb_left;
327 		else
328 			pp = &p->rb_right;
329 
330 		rb_link_node(&new->rb_node_in, p, pp);
331 		rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
332 	} else {
333 		parent->hit = period;
334 	}
335 }
336 
337 static int
338 append_chain(struct callchain_node *root,
339 	     struct callchain_cursor *cursor,
340 	     u64 period);
341 
342 static void
343 append_chain_children(struct callchain_node *root,
344 		      struct callchain_cursor *cursor,
345 		      u64 period)
346 {
347 	struct callchain_node *rnode;
348 	struct callchain_cursor_node *node;
349 	struct rb_node **p = &root->rb_root_in.rb_node;
350 	struct rb_node *parent = NULL;
351 
352 	node = callchain_cursor_current(cursor);
353 	if (!node)
354 		return;
355 
356 	/* lookup in childrens */
357 	while (*p) {
358 		s64 ret;
359 		struct callchain_list *cnode;
360 
361 		parent = *p;
362 		rnode = rb_entry(parent, struct callchain_node, rb_node_in);
363 		cnode = list_first_entry(&rnode->val, struct callchain_list,
364 					 list);
365 
366 		/* just check first entry */
367 		ret = match_chain(node, cnode);
368 		if (ret == 0) {
369 			append_chain(rnode, cursor, period);
370 			goto inc_children_hit;
371 		}
372 
373 		if (ret < 0)
374 			p = &parent->rb_left;
375 		else
376 			p = &parent->rb_right;
377 	}
378 	/* nothing in children, add to the current node */
379 	rnode = add_child(root, cursor, period);
380 	rb_link_node(&rnode->rb_node_in, parent, p);
381 	rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
382 
383 inc_children_hit:
384 	root->children_hit += period;
385 }
386 
387 static int
388 append_chain(struct callchain_node *root,
389 	     struct callchain_cursor *cursor,
390 	     u64 period)
391 {
392 	struct callchain_cursor_node *curr_snap = cursor->curr;
393 	struct callchain_list *cnode;
394 	u64 start = cursor->pos;
395 	bool found = false;
396 	u64 matches;
397 
398 	/*
399 	 * Lookup in the current node
400 	 * If we have a symbol, then compare the start to match
401 	 * anywhere inside a function, unless function
402 	 * mode is disabled.
403 	 */
404 	list_for_each_entry(cnode, &root->val, list) {
405 		struct callchain_cursor_node *node;
406 
407 		node = callchain_cursor_current(cursor);
408 		if (!node)
409 			break;
410 
411 		if (match_chain(node, cnode) != 0)
412 			break;
413 
414 		found = true;
415 
416 		callchain_cursor_advance(cursor);
417 	}
418 
419 	/* matches not, relay no the parent */
420 	if (!found) {
421 		cursor->curr = curr_snap;
422 		cursor->pos = start;
423 		return -1;
424 	}
425 
426 	matches = cursor->pos - start;
427 
428 	/* we match only a part of the node. Split it and add the new chain */
429 	if (matches < root->val_nr) {
430 		split_add_child(root, cursor, cnode, start, matches, period);
431 		return 0;
432 	}
433 
434 	/* we match 100% of the path, increment the hit */
435 	if (matches == root->val_nr && cursor->pos == cursor->nr) {
436 		root->hit += period;
437 		return 0;
438 	}
439 
440 	/* We match the node and still have a part remaining */
441 	append_chain_children(root, cursor, period);
442 
443 	return 0;
444 }
445 
446 int callchain_append(struct callchain_root *root,
447 		     struct callchain_cursor *cursor,
448 		     u64 period)
449 {
450 	if (!cursor->nr)
451 		return 0;
452 
453 	callchain_cursor_commit(cursor);
454 
455 	append_chain_children(&root->node, cursor, period);
456 
457 	if (cursor->nr > root->max_depth)
458 		root->max_depth = cursor->nr;
459 
460 	return 0;
461 }
462 
463 static int
464 merge_chain_branch(struct callchain_cursor *cursor,
465 		   struct callchain_node *dst, struct callchain_node *src)
466 {
467 	struct callchain_cursor_node **old_last = cursor->last;
468 	struct callchain_node *child;
469 	struct callchain_list *list, *next_list;
470 	struct rb_node *n;
471 	int old_pos = cursor->nr;
472 	int err = 0;
473 
474 	list_for_each_entry_safe(list, next_list, &src->val, list) {
475 		callchain_cursor_append(cursor, list->ip,
476 					list->ms.map, list->ms.sym);
477 		list_del(&list->list);
478 		free(list);
479 	}
480 
481 	if (src->hit) {
482 		callchain_cursor_commit(cursor);
483 		append_chain_children(dst, cursor, src->hit);
484 	}
485 
486 	n = rb_first(&src->rb_root_in);
487 	while (n) {
488 		child = container_of(n, struct callchain_node, rb_node_in);
489 		n = rb_next(n);
490 		rb_erase(&child->rb_node_in, &src->rb_root_in);
491 
492 		err = merge_chain_branch(cursor, dst, child);
493 		if (err)
494 			break;
495 
496 		free(child);
497 	}
498 
499 	cursor->nr = old_pos;
500 	cursor->last = old_last;
501 
502 	return err;
503 }
504 
505 int callchain_merge(struct callchain_cursor *cursor,
506 		    struct callchain_root *dst, struct callchain_root *src)
507 {
508 	return merge_chain_branch(cursor, &dst->node, &src->node);
509 }
510 
511 int callchain_cursor_append(struct callchain_cursor *cursor,
512 			    u64 ip, struct map *map, struct symbol *sym)
513 {
514 	struct callchain_cursor_node *node = *cursor->last;
515 
516 	if (!node) {
517 		node = calloc(1, sizeof(*node));
518 		if (!node)
519 			return -ENOMEM;
520 
521 		*cursor->last = node;
522 	}
523 
524 	node->ip = ip;
525 	node->map = map;
526 	node->sym = sym;
527 
528 	cursor->nr++;
529 
530 	cursor->last = &node->next;
531 
532 	return 0;
533 }
534