• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "asm/bug.h"
19 
20 #include "hist.h"
21 #include "util.h"
22 #include "sort.h"
23 #include "machine.h"
24 #include "callchain.h"
25 
26 __thread struct callchain_cursor callchain_cursor;
27 
28 #ifdef HAVE_DWARF_UNWIND_SUPPORT
get_stack_size(const char * str,unsigned long * _size)29 static int get_stack_size(const char *str, unsigned long *_size)
30 {
31 	char *endptr;
32 	unsigned long size;
33 	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
34 
35 	size = strtoul(str, &endptr, 0);
36 
37 	do {
38 		if (*endptr)
39 			break;
40 
41 		size = round_up(size, sizeof(u64));
42 		if (!size || size > max_size)
43 			break;
44 
45 		*_size = size;
46 		return 0;
47 
48 	} while (0);
49 
50 	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
51 	       max_size, str);
52 	return -1;
53 }
54 #endif /* HAVE_DWARF_UNWIND_SUPPORT */
55 
parse_callchain_record_opt(const char * arg)56 int parse_callchain_record_opt(const char *arg)
57 {
58 	char *tok, *name, *saveptr = NULL;
59 	char *buf;
60 	int ret = -1;
61 
62 	/* We need buffer that we know we can write to. */
63 	buf = malloc(strlen(arg) + 1);
64 	if (!buf)
65 		return -ENOMEM;
66 
67 	strcpy(buf, arg);
68 
69 	tok = strtok_r((char *)buf, ",", &saveptr);
70 	name = tok ? : (char *)buf;
71 
72 	do {
73 		/* Framepointer style */
74 		if (!strncmp(name, "fp", sizeof("fp"))) {
75 			if (!strtok_r(NULL, ",", &saveptr)) {
76 				callchain_param.record_mode = CALLCHAIN_FP;
77 				ret = 0;
78 			} else
79 				pr_err("callchain: No more arguments "
80 				       "needed for -g fp\n");
81 			break;
82 
83 #ifdef HAVE_DWARF_UNWIND_SUPPORT
84 		/* Dwarf style */
85 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
86 			const unsigned long default_stack_dump_size = 8192;
87 
88 			ret = 0;
89 			callchain_param.record_mode = CALLCHAIN_DWARF;
90 			callchain_param.dump_size = default_stack_dump_size;
91 
92 			tok = strtok_r(NULL, ",", &saveptr);
93 			if (tok) {
94 				unsigned long size = 0;
95 
96 				ret = get_stack_size(tok, &size);
97 				callchain_param.dump_size = size;
98 			}
99 #endif /* HAVE_DWARF_UNWIND_SUPPORT */
100 		} else {
101 			pr_err("callchain: Unknown --call-graph option "
102 			       "value: %s\n", arg);
103 			break;
104 		}
105 
106 	} while (0);
107 
108 	free(buf);
109 	return ret;
110 }
111 
parse_callchain_mode(const char * value)112 static int parse_callchain_mode(const char *value)
113 {
114 	if (!strncmp(value, "graph", strlen(value))) {
115 		callchain_param.mode = CHAIN_GRAPH_ABS;
116 		return 0;
117 	}
118 	if (!strncmp(value, "flat", strlen(value))) {
119 		callchain_param.mode = CHAIN_FLAT;
120 		return 0;
121 	}
122 	if (!strncmp(value, "fractal", strlen(value))) {
123 		callchain_param.mode = CHAIN_GRAPH_REL;
124 		return 0;
125 	}
126 	return -1;
127 }
128 
parse_callchain_order(const char * value)129 static int parse_callchain_order(const char *value)
130 {
131 	if (!strncmp(value, "caller", strlen(value))) {
132 		callchain_param.order = ORDER_CALLER;
133 		return 0;
134 	}
135 	if (!strncmp(value, "callee", strlen(value))) {
136 		callchain_param.order = ORDER_CALLEE;
137 		return 0;
138 	}
139 	return -1;
140 }
141 
parse_callchain_sort_key(const char * value)142 static int parse_callchain_sort_key(const char *value)
143 {
144 	if (!strncmp(value, "function", strlen(value))) {
145 		callchain_param.key = CCKEY_FUNCTION;
146 		return 0;
147 	}
148 	if (!strncmp(value, "address", strlen(value))) {
149 		callchain_param.key = CCKEY_ADDRESS;
150 		return 0;
151 	}
152 	return -1;
153 }
154 
155 int
parse_callchain_report_opt(const char * arg)156 parse_callchain_report_opt(const char *arg)
157 {
158 	char *tok;
159 	char *endptr;
160 	bool minpcnt_set = false;
161 
162 	symbol_conf.use_callchain = true;
163 
164 	if (!arg)
165 		return 0;
166 
167 	while ((tok = strtok((char *)arg, ",")) != NULL) {
168 		if (!strncmp(tok, "none", strlen(tok))) {
169 			callchain_param.mode = CHAIN_NONE;
170 			symbol_conf.use_callchain = false;
171 			return 0;
172 		}
173 
174 		if (!parse_callchain_mode(tok) ||
175 		    !parse_callchain_order(tok) ||
176 		    !parse_callchain_sort_key(tok)) {
177 			/* parsing ok - move on to the next */
178 		} else if (!minpcnt_set) {
179 			/* try to get the min percent */
180 			callchain_param.min_percent = strtod(tok, &endptr);
181 			if (tok == endptr)
182 				return -1;
183 			minpcnt_set = true;
184 		} else {
185 			/* try print limit at last */
186 			callchain_param.print_limit = strtoul(tok, &endptr, 0);
187 			if (tok == endptr)
188 				return -1;
189 		}
190 
191 		arg = NULL;
192 	}
193 
194 	if (callchain_register_param(&callchain_param) < 0) {
195 		pr_err("Can't register callchain params\n");
196 		return -1;
197 	}
198 	return 0;
199 }
200 
perf_callchain_config(const char * var,const char * value)201 int perf_callchain_config(const char *var, const char *value)
202 {
203 	char *endptr;
204 
205 	if (prefixcmp(var, "call-graph."))
206 		return 0;
207 	var += sizeof("call-graph.") - 1;
208 
209 	if (!strcmp(var, "record-mode"))
210 		return parse_callchain_record_opt(value);
211 #ifdef HAVE_DWARF_UNWIND_SUPPORT
212 	if (!strcmp(var, "dump-size")) {
213 		unsigned long size = 0;
214 		int ret;
215 
216 		ret = get_stack_size(value, &size);
217 		callchain_param.dump_size = size;
218 
219 		return ret;
220 	}
221 #endif
222 	if (!strcmp(var, "print-type"))
223 		return parse_callchain_mode(value);
224 	if (!strcmp(var, "order"))
225 		return parse_callchain_order(value);
226 	if (!strcmp(var, "sort-key"))
227 		return parse_callchain_sort_key(value);
228 	if (!strcmp(var, "threshold")) {
229 		callchain_param.min_percent = strtod(value, &endptr);
230 		if (value == endptr)
231 			return -1;
232 	}
233 	if (!strcmp(var, "print-limit")) {
234 		callchain_param.print_limit = strtod(value, &endptr);
235 		if (value == endptr)
236 			return -1;
237 	}
238 
239 	return 0;
240 }
241 
242 static void
rb_insert_callchain(struct rb_root * root,struct callchain_node * chain,enum chain_mode mode)243 rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
244 		    enum chain_mode mode)
245 {
246 	struct rb_node **p = &root->rb_node;
247 	struct rb_node *parent = NULL;
248 	struct callchain_node *rnode;
249 	u64 chain_cumul = callchain_cumul_hits(chain);
250 
251 	while (*p) {
252 		u64 rnode_cumul;
253 
254 		parent = *p;
255 		rnode = rb_entry(parent, struct callchain_node, rb_node);
256 		rnode_cumul = callchain_cumul_hits(rnode);
257 
258 		switch (mode) {
259 		case CHAIN_FLAT:
260 			if (rnode->hit < chain->hit)
261 				p = &(*p)->rb_left;
262 			else
263 				p = &(*p)->rb_right;
264 			break;
265 		case CHAIN_GRAPH_ABS: /* Falldown */
266 		case CHAIN_GRAPH_REL:
267 			if (rnode_cumul < chain_cumul)
268 				p = &(*p)->rb_left;
269 			else
270 				p = &(*p)->rb_right;
271 			break;
272 		case CHAIN_NONE:
273 		default:
274 			break;
275 		}
276 	}
277 
278 	rb_link_node(&chain->rb_node, parent, p);
279 	rb_insert_color(&chain->rb_node, root);
280 }
281 
282 static void
__sort_chain_flat(struct rb_root * rb_root,struct callchain_node * node,u64 min_hit)283 __sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
284 		  u64 min_hit)
285 {
286 	struct rb_node *n;
287 	struct callchain_node *child;
288 
289 	n = rb_first(&node->rb_root_in);
290 	while (n) {
291 		child = rb_entry(n, struct callchain_node, rb_node_in);
292 		n = rb_next(n);
293 
294 		__sort_chain_flat(rb_root, child, min_hit);
295 	}
296 
297 	if (node->hit && node->hit >= min_hit)
298 		rb_insert_callchain(rb_root, node, CHAIN_FLAT);
299 }
300 
301 /*
302  * Once we get every callchains from the stream, we can now
303  * sort them by hit
304  */
305 static void
sort_chain_flat(struct rb_root * rb_root,struct callchain_root * root,u64 min_hit,struct callchain_param * param __maybe_unused)306 sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
307 		u64 min_hit, struct callchain_param *param __maybe_unused)
308 {
309 	__sort_chain_flat(rb_root, &root->node, min_hit);
310 }
311 
__sort_chain_graph_abs(struct callchain_node * node,u64 min_hit)312 static void __sort_chain_graph_abs(struct callchain_node *node,
313 				   u64 min_hit)
314 {
315 	struct rb_node *n;
316 	struct callchain_node *child;
317 
318 	node->rb_root = RB_ROOT;
319 	n = rb_first(&node->rb_root_in);
320 
321 	while (n) {
322 		child = rb_entry(n, struct callchain_node, rb_node_in);
323 		n = rb_next(n);
324 
325 		__sort_chain_graph_abs(child, min_hit);
326 		if (callchain_cumul_hits(child) >= min_hit)
327 			rb_insert_callchain(&node->rb_root, child,
328 					    CHAIN_GRAPH_ABS);
329 	}
330 }
331 
332 static void
sort_chain_graph_abs(struct rb_root * rb_root,struct callchain_root * chain_root,u64 min_hit,struct callchain_param * param __maybe_unused)333 sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
334 		     u64 min_hit, struct callchain_param *param __maybe_unused)
335 {
336 	__sort_chain_graph_abs(&chain_root->node, min_hit);
337 	rb_root->rb_node = chain_root->node.rb_root.rb_node;
338 }
339 
__sort_chain_graph_rel(struct callchain_node * node,double min_percent)340 static void __sort_chain_graph_rel(struct callchain_node *node,
341 				   double min_percent)
342 {
343 	struct rb_node *n;
344 	struct callchain_node *child;
345 	u64 min_hit;
346 
347 	node->rb_root = RB_ROOT;
348 	min_hit = ceil(node->children_hit * min_percent);
349 
350 	n = rb_first(&node->rb_root_in);
351 	while (n) {
352 		child = rb_entry(n, struct callchain_node, rb_node_in);
353 		n = rb_next(n);
354 
355 		__sort_chain_graph_rel(child, min_percent);
356 		if (callchain_cumul_hits(child) >= min_hit)
357 			rb_insert_callchain(&node->rb_root, child,
358 					    CHAIN_GRAPH_REL);
359 	}
360 }
361 
362 static void
sort_chain_graph_rel(struct rb_root * rb_root,struct callchain_root * chain_root,u64 min_hit __maybe_unused,struct callchain_param * param)363 sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
364 		     u64 min_hit __maybe_unused, struct callchain_param *param)
365 {
366 	__sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
367 	rb_root->rb_node = chain_root->node.rb_root.rb_node;
368 }
369 
callchain_register_param(struct callchain_param * param)370 int callchain_register_param(struct callchain_param *param)
371 {
372 	switch (param->mode) {
373 	case CHAIN_GRAPH_ABS:
374 		param->sort = sort_chain_graph_abs;
375 		break;
376 	case CHAIN_GRAPH_REL:
377 		param->sort = sort_chain_graph_rel;
378 		break;
379 	case CHAIN_FLAT:
380 		param->sort = sort_chain_flat;
381 		break;
382 	case CHAIN_NONE:
383 	default:
384 		return -1;
385 	}
386 	return 0;
387 }
388 
389 /*
390  * Create a child for a parent. If inherit_children, then the new child
391  * will become the new parent of it's parent children
392  */
393 static struct callchain_node *
create_child(struct callchain_node * parent,bool inherit_children)394 create_child(struct callchain_node *parent, bool inherit_children)
395 {
396 	struct callchain_node *new;
397 
398 	new = zalloc(sizeof(*new));
399 	if (!new) {
400 		perror("not enough memory to create child for code path tree");
401 		return NULL;
402 	}
403 	new->parent = parent;
404 	INIT_LIST_HEAD(&new->val);
405 
406 	if (inherit_children) {
407 		struct rb_node *n;
408 		struct callchain_node *child;
409 
410 		new->rb_root_in = parent->rb_root_in;
411 		parent->rb_root_in = RB_ROOT;
412 
413 		n = rb_first(&new->rb_root_in);
414 		while (n) {
415 			child = rb_entry(n, struct callchain_node, rb_node_in);
416 			child->parent = new;
417 			n = rb_next(n);
418 		}
419 
420 		/* make it the first child */
421 		rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
422 		rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
423 	}
424 
425 	return new;
426 }
427 
428 
429 /*
430  * Fill the node with callchain values
431  */
432 static void
fill_node(struct callchain_node * node,struct callchain_cursor * cursor)433 fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
434 {
435 	struct callchain_cursor_node *cursor_node;
436 
437 	node->val_nr = cursor->nr - cursor->pos;
438 	if (!node->val_nr)
439 		pr_warning("Warning: empty node in callchain tree\n");
440 
441 	cursor_node = callchain_cursor_current(cursor);
442 
443 	while (cursor_node) {
444 		struct callchain_list *call;
445 
446 		call = zalloc(sizeof(*call));
447 		if (!call) {
448 			perror("not enough memory for the code path tree");
449 			return;
450 		}
451 		call->ip = cursor_node->ip;
452 		call->ms.sym = cursor_node->sym;
453 		call->ms.map = cursor_node->map;
454 		list_add_tail(&call->list, &node->val);
455 
456 		callchain_cursor_advance(cursor);
457 		cursor_node = callchain_cursor_current(cursor);
458 	}
459 }
460 
461 static struct callchain_node *
add_child(struct callchain_node * parent,struct callchain_cursor * cursor,u64 period)462 add_child(struct callchain_node *parent,
463 	  struct callchain_cursor *cursor,
464 	  u64 period)
465 {
466 	struct callchain_node *new;
467 
468 	new = create_child(parent, false);
469 	fill_node(new, cursor);
470 
471 	new->children_hit = 0;
472 	new->hit = period;
473 	return new;
474 }
475 
match_chain(struct callchain_cursor_node * node,struct callchain_list * cnode)476 static s64 match_chain(struct callchain_cursor_node *node,
477 		      struct callchain_list *cnode)
478 {
479 	struct symbol *sym = node->sym;
480 
481 	if (cnode->ms.sym && sym &&
482 	    callchain_param.key == CCKEY_FUNCTION)
483 		return cnode->ms.sym->start - sym->start;
484 	else
485 		return cnode->ip - node->ip;
486 }
487 
488 /*
489  * Split the parent in two parts (a new child is created) and
490  * give a part of its callchain to the created child.
491  * Then create another child to host the given callchain of new branch
492  */
493 static void
split_add_child(struct callchain_node * parent,struct callchain_cursor * cursor,struct callchain_list * to_split,u64 idx_parents,u64 idx_local,u64 period)494 split_add_child(struct callchain_node *parent,
495 		struct callchain_cursor *cursor,
496 		struct callchain_list *to_split,
497 		u64 idx_parents, u64 idx_local, u64 period)
498 {
499 	struct callchain_node *new;
500 	struct list_head *old_tail;
501 	unsigned int idx_total = idx_parents + idx_local;
502 
503 	/* split */
504 	new = create_child(parent, true);
505 
506 	/* split the callchain and move a part to the new child */
507 	old_tail = parent->val.prev;
508 	list_del_range(&to_split->list, old_tail);
509 	new->val.next = &to_split->list;
510 	new->val.prev = old_tail;
511 	to_split->list.prev = &new->val;
512 	old_tail->next = &new->val;
513 
514 	/* split the hits */
515 	new->hit = parent->hit;
516 	new->children_hit = parent->children_hit;
517 	parent->children_hit = callchain_cumul_hits(new);
518 	new->val_nr = parent->val_nr - idx_local;
519 	parent->val_nr = idx_local;
520 
521 	/* create a new child for the new branch if any */
522 	if (idx_total < cursor->nr) {
523 		struct callchain_node *first;
524 		struct callchain_list *cnode;
525 		struct callchain_cursor_node *node;
526 		struct rb_node *p, **pp;
527 
528 		parent->hit = 0;
529 		parent->children_hit += period;
530 
531 		node = callchain_cursor_current(cursor);
532 		new = add_child(parent, cursor, period);
533 
534 		/*
535 		 * This is second child since we moved parent's children
536 		 * to new (first) child above.
537 		 */
538 		p = parent->rb_root_in.rb_node;
539 		first = rb_entry(p, struct callchain_node, rb_node_in);
540 		cnode = list_first_entry(&first->val, struct callchain_list,
541 					 list);
542 
543 		if (match_chain(node, cnode) < 0)
544 			pp = &p->rb_left;
545 		else
546 			pp = &p->rb_right;
547 
548 		rb_link_node(&new->rb_node_in, p, pp);
549 		rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
550 	} else {
551 		parent->hit = period;
552 	}
553 }
554 
555 static int
556 append_chain(struct callchain_node *root,
557 	     struct callchain_cursor *cursor,
558 	     u64 period);
559 
560 static void
append_chain_children(struct callchain_node * root,struct callchain_cursor * cursor,u64 period)561 append_chain_children(struct callchain_node *root,
562 		      struct callchain_cursor *cursor,
563 		      u64 period)
564 {
565 	struct callchain_node *rnode;
566 	struct callchain_cursor_node *node;
567 	struct rb_node **p = &root->rb_root_in.rb_node;
568 	struct rb_node *parent = NULL;
569 
570 	node = callchain_cursor_current(cursor);
571 	if (!node)
572 		return;
573 
574 	/* lookup in childrens */
575 	while (*p) {
576 		s64 ret;
577 
578 		parent = *p;
579 		rnode = rb_entry(parent, struct callchain_node, rb_node_in);
580 
581 		/* If at least first entry matches, rely to children */
582 		ret = append_chain(rnode, cursor, period);
583 		if (ret == 0)
584 			goto inc_children_hit;
585 
586 		if (ret < 0)
587 			p = &parent->rb_left;
588 		else
589 			p = &parent->rb_right;
590 	}
591 	/* nothing in children, add to the current node */
592 	rnode = add_child(root, cursor, period);
593 	rb_link_node(&rnode->rb_node_in, parent, p);
594 	rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
595 
596 inc_children_hit:
597 	root->children_hit += period;
598 }
599 
600 static int
append_chain(struct callchain_node * root,struct callchain_cursor * cursor,u64 period)601 append_chain(struct callchain_node *root,
602 	     struct callchain_cursor *cursor,
603 	     u64 period)
604 {
605 	struct callchain_list *cnode;
606 	u64 start = cursor->pos;
607 	bool found = false;
608 	u64 matches;
609 	int cmp = 0;
610 
611 	/*
612 	 * Lookup in the current node
613 	 * If we have a symbol, then compare the start to match
614 	 * anywhere inside a function, unless function
615 	 * mode is disabled.
616 	 */
617 	list_for_each_entry(cnode, &root->val, list) {
618 		struct callchain_cursor_node *node;
619 
620 		node = callchain_cursor_current(cursor);
621 		if (!node)
622 			break;
623 
624 		cmp = match_chain(node, cnode);
625 		if (cmp)
626 			break;
627 
628 		found = true;
629 
630 		callchain_cursor_advance(cursor);
631 	}
632 
633 	/* matches not, relay no the parent */
634 	if (!found) {
635 		WARN_ONCE(!cmp, "Chain comparison error\n");
636 		return cmp;
637 	}
638 
639 	matches = cursor->pos - start;
640 
641 	/* we match only a part of the node. Split it and add the new chain */
642 	if (matches < root->val_nr) {
643 		split_add_child(root, cursor, cnode, start, matches, period);
644 		return 0;
645 	}
646 
647 	/* we match 100% of the path, increment the hit */
648 	if (matches == root->val_nr && cursor->pos == cursor->nr) {
649 		root->hit += period;
650 		return 0;
651 	}
652 
653 	/* We match the node and still have a part remaining */
654 	append_chain_children(root, cursor, period);
655 
656 	return 0;
657 }
658 
callchain_append(struct callchain_root * root,struct callchain_cursor * cursor,u64 period)659 int callchain_append(struct callchain_root *root,
660 		     struct callchain_cursor *cursor,
661 		     u64 period)
662 {
663 	if (!cursor->nr)
664 		return 0;
665 
666 	callchain_cursor_commit(cursor);
667 
668 	append_chain_children(&root->node, cursor, period);
669 
670 	if (cursor->nr > root->max_depth)
671 		root->max_depth = cursor->nr;
672 
673 	return 0;
674 }
675 
676 static int
merge_chain_branch(struct callchain_cursor * cursor,struct callchain_node * dst,struct callchain_node * src)677 merge_chain_branch(struct callchain_cursor *cursor,
678 		   struct callchain_node *dst, struct callchain_node *src)
679 {
680 	struct callchain_cursor_node **old_last = cursor->last;
681 	struct callchain_node *child;
682 	struct callchain_list *list, *next_list;
683 	struct rb_node *n;
684 	int old_pos = cursor->nr;
685 	int err = 0;
686 
687 	list_for_each_entry_safe(list, next_list, &src->val, list) {
688 		callchain_cursor_append(cursor, list->ip,
689 					list->ms.map, list->ms.sym);
690 		list_del(&list->list);
691 		free(list);
692 	}
693 
694 	if (src->hit) {
695 		callchain_cursor_commit(cursor);
696 		append_chain_children(dst, cursor, src->hit);
697 	}
698 
699 	n = rb_first(&src->rb_root_in);
700 	while (n) {
701 		child = container_of(n, struct callchain_node, rb_node_in);
702 		n = rb_next(n);
703 		rb_erase(&child->rb_node_in, &src->rb_root_in);
704 
705 		err = merge_chain_branch(cursor, dst, child);
706 		if (err)
707 			break;
708 
709 		free(child);
710 	}
711 
712 	cursor->nr = old_pos;
713 	cursor->last = old_last;
714 
715 	return err;
716 }
717 
callchain_merge(struct callchain_cursor * cursor,struct callchain_root * dst,struct callchain_root * src)718 int callchain_merge(struct callchain_cursor *cursor,
719 		    struct callchain_root *dst, struct callchain_root *src)
720 {
721 	return merge_chain_branch(cursor, &dst->node, &src->node);
722 }
723 
callchain_cursor_append(struct callchain_cursor * cursor,u64 ip,struct map * map,struct symbol * sym)724 int callchain_cursor_append(struct callchain_cursor *cursor,
725 			    u64 ip, struct map *map, struct symbol *sym)
726 {
727 	struct callchain_cursor_node *node = *cursor->last;
728 
729 	if (!node) {
730 		node = calloc(1, sizeof(*node));
731 		if (!node)
732 			return -ENOMEM;
733 
734 		*cursor->last = node;
735 	}
736 
737 	node->ip = ip;
738 	node->map = map;
739 	node->sym = sym;
740 
741 	cursor->nr++;
742 
743 	cursor->last = &node->next;
744 
745 	return 0;
746 }
747 
sample__resolve_callchain(struct perf_sample * sample,struct symbol ** parent,struct perf_evsel * evsel,struct addr_location * al,int max_stack)748 int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent,
749 			      struct perf_evsel *evsel, struct addr_location *al,
750 			      int max_stack)
751 {
752 	if (sample->callchain == NULL)
753 		return 0;
754 
755 	if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
756 	    sort__has_parent) {
757 		return machine__resolve_callchain(al->machine, evsel, al->thread,
758 						  sample, parent, al, max_stack);
759 	}
760 	return 0;
761 }
762 
hist_entry__append_callchain(struct hist_entry * he,struct perf_sample * sample)763 int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
764 {
765 	if (!symbol_conf.use_callchain || sample->callchain == NULL)
766 		return 0;
767 	return callchain_append(he->callchain, &callchain_cursor, sample->period);
768 }
769 
fill_callchain_info(struct addr_location * al,struct callchain_cursor_node * node,bool hide_unresolved)770 int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
771 			bool hide_unresolved)
772 {
773 	al->map = node->map;
774 	al->sym = node->sym;
775 	if (node->map)
776 		al->addr = node->map->map_ip(node->map, node->ip);
777 	else
778 		al->addr = node->ip;
779 
780 	if (al->sym == NULL) {
781 		if (hide_unresolved)
782 			return 0;
783 		if (al->map == NULL)
784 			goto out;
785 	}
786 
787 	if (al->map->groups == &al->machine->kmaps) {
788 		if (machine__is_host(al->machine)) {
789 			al->cpumode = PERF_RECORD_MISC_KERNEL;
790 			al->level = 'k';
791 		} else {
792 			al->cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
793 			al->level = 'g';
794 		}
795 	} else {
796 		if (machine__is_host(al->machine)) {
797 			al->cpumode = PERF_RECORD_MISC_USER;
798 			al->level = '.';
799 		} else if (perf_guest) {
800 			al->cpumode = PERF_RECORD_MISC_GUEST_USER;
801 			al->level = 'u';
802 		} else {
803 			al->cpumode = PERF_RECORD_MISC_HYPERVISOR;
804 			al->level = 'H';
805 		}
806 	}
807 
808 out:
809 	return 1;
810 }
811