callchain.c 18.9 KB
Newer Older
1
/*
2
 * Copyright (C) 2009-2011, Frederic Weisbecker <fweisbec@gmail.com>
3 4 5 6
 *
 * Handle the callchains from the stream in an ad-hoc radix tree and then
 * sort them in an rbtree.
 *
7 8 9
 * Using a radix for code path provides a fast retrieval and factorizes
 * memory use. Also that lets us use the paths in a hierarchical graph view.
 *
10 11 12 13 14 15
 */

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
16
#include <math.h>
17

18 19
#include "asm/bug.h"

20
#include "hist.h"
21
#include "util.h"
22 23
#include "sort.h"
#include "machine.h"
24 25
#include "callchain.h"

26 27
__thread struct callchain_cursor callchain_cursor;

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
#ifdef HAVE_DWARF_UNWIND_SUPPORT
static int get_stack_size(const char *str, unsigned long *_size)
{
	char *endptr;
	unsigned long size;
	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));

	size = strtoul(str, &endptr, 0);

	do {
		if (*endptr)
			break;

		size = round_up(size, sizeof(u64));
		if (!size || size > max_size)
			break;

		*_size = size;
		return 0;

	} while (0);

	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
	       max_size, str);
	return -1;
}
#endif /* HAVE_DWARF_UNWIND_SUPPORT */

int parse_callchain_record_opt(const char *arg)
{
	char *tok, *name, *saveptr = NULL;
	char *buf;
	int ret = -1;

	/* We need buffer that we know we can write to. */
	buf = malloc(strlen(arg) + 1);
	if (!buf)
		return -ENOMEM;

	strcpy(buf, arg);

	tok = strtok_r((char *)buf, ",", &saveptr);
	name = tok ? : (char *)buf;

	do {
		/* Framepointer style */
		if (!strncmp(name, "fp", sizeof("fp"))) {
			if (!strtok_r(NULL, ",", &saveptr)) {
				callchain_param.record_mode = CALLCHAIN_FP;
				ret = 0;
			} else
				pr_err("callchain: No more arguments "
				       "needed for -g fp\n");
			break;

#ifdef HAVE_DWARF_UNWIND_SUPPORT
		/* Dwarf style */
		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
			const unsigned long default_stack_dump_size = 8192;

			ret = 0;
			callchain_param.record_mode = CALLCHAIN_DWARF;
			callchain_param.dump_size = default_stack_dump_size;

			tok = strtok_r(NULL, ",", &saveptr);
			if (tok) {
				unsigned long size = 0;

				ret = get_stack_size(tok, &size);
				callchain_param.dump_size = size;
			}
#endif /* HAVE_DWARF_UNWIND_SUPPORT */
		} else {
			pr_err("callchain: Unknown --call-graph option "
			       "value: %s\n", arg);
			break;
		}

	} while (0);

	free(buf);
	return ret;
}

112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
static int parse_callchain_mode(const char *value)
{
	if (!strncmp(value, "graph", strlen(value))) {
		callchain_param.mode = CHAIN_GRAPH_ABS;
		return 0;
	}
	if (!strncmp(value, "flat", strlen(value))) {
		callchain_param.mode = CHAIN_FLAT;
		return 0;
	}
	if (!strncmp(value, "fractal", strlen(value))) {
		callchain_param.mode = CHAIN_GRAPH_REL;
		return 0;
	}
	return -1;
}

static int parse_callchain_order(const char *value)
{
	if (!strncmp(value, "caller", strlen(value))) {
		callchain_param.order = ORDER_CALLER;
		return 0;
	}
	if (!strncmp(value, "callee", strlen(value))) {
		callchain_param.order = ORDER_CALLEE;
		return 0;
	}
	return -1;
}

static int parse_callchain_sort_key(const char *value)
{
	if (!strncmp(value, "function", strlen(value))) {
		callchain_param.key = CCKEY_FUNCTION;
		return 0;
	}
	if (!strncmp(value, "address", strlen(value))) {
		callchain_param.key = CCKEY_ADDRESS;
		return 0;
	}
152 153 154 155
	if (!strncmp(value, "branch", strlen(value))) {
		callchain_param.branch_callstack = 1;
		return 0;
	}
156 157 158
	return -1;
}

159 160 161
int
parse_callchain_report_opt(const char *arg)
{
162
	char *tok;
163
	char *endptr;
164
	bool minpcnt_set = false;
165 166 167 168 169 170

	symbol_conf.use_callchain = true;

	if (!arg)
		return 0;

171 172 173 174 175 176 177
	while ((tok = strtok((char *)arg, ",")) != NULL) {
		if (!strncmp(tok, "none", strlen(tok))) {
			callchain_param.mode = CHAIN_NONE;
			symbol_conf.use_callchain = false;
			return 0;
		}

178 179 180 181 182 183
		if (!parse_callchain_mode(tok) ||
		    !parse_callchain_order(tok) ||
		    !parse_callchain_sort_key(tok)) {
			/* parsing ok - move on to the next */
		} else if (!minpcnt_set) {
			/* try to get the min percent */
184 185 186 187 188 189 190 191 192 193 194 195
			callchain_param.min_percent = strtod(tok, &endptr);
			if (tok == endptr)
				return -1;
			minpcnt_set = true;
		} else {
			/* try print limit at last */
			callchain_param.print_limit = strtoul(tok, &endptr, 0);
			if (tok == endptr)
				return -1;
		}

		arg = NULL;
196 197 198 199 200 201 202 203 204
	}

	if (callchain_register_param(&callchain_param) < 0) {
		pr_err("Can't register callchain params\n");
		return -1;
	}
	return 0;
}

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
int perf_callchain_config(const char *var, const char *value)
{
	char *endptr;

	if (prefixcmp(var, "call-graph."))
		return 0;
	var += sizeof("call-graph.") - 1;

	if (!strcmp(var, "record-mode"))
		return parse_callchain_record_opt(value);
#ifdef HAVE_DWARF_UNWIND_SUPPORT
	if (!strcmp(var, "dump-size")) {
		unsigned long size = 0;
		int ret;

		ret = get_stack_size(value, &size);
		callchain_param.dump_size = size;

		return ret;
	}
#endif
	if (!strcmp(var, "print-type"))
		return parse_callchain_mode(value);
	if (!strcmp(var, "order"))
		return parse_callchain_order(value);
	if (!strcmp(var, "sort-key"))
		return parse_callchain_sort_key(value);
	if (!strcmp(var, "threshold")) {
		callchain_param.min_percent = strtod(value, &endptr);
		if (value == endptr)
			return -1;
	}
	if (!strcmp(var, "print-limit")) {
		callchain_param.print_limit = strtod(value, &endptr);
		if (value == endptr)
			return -1;
	}

	return 0;
}

246
static void
247 248
rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
		    enum chain_mode mode)
249 250 251 252
{
	struct rb_node **p = &root->rb_node;
	struct rb_node *parent = NULL;
	struct callchain_node *rnode;
253
	u64 chain_cumul = callchain_cumul_hits(chain);
254 255

	while (*p) {
256 257
		u64 rnode_cumul;

258 259
		parent = *p;
		rnode = rb_entry(parent, struct callchain_node, rb_node);
260
		rnode_cumul = callchain_cumul_hits(rnode);
261

262
		switch (mode) {
263
		case CHAIN_FLAT:
264 265 266 267 268
			if (rnode->hit < chain->hit)
				p = &(*p)->rb_left;
			else
				p = &(*p)->rb_right;
			break;
269 270
		case CHAIN_GRAPH_ABS: /* Falldown */
		case CHAIN_GRAPH_REL:
271
			if (rnode_cumul < chain_cumul)
272 273 274 275
				p = &(*p)->rb_left;
			else
				p = &(*p)->rb_right;
			break;
276
		case CHAIN_NONE:
277 278 279
		default:
			break;
		}
280 281 282 283 284 285
	}

	rb_link_node(&chain->rb_node, parent, p);
	rb_insert_color(&chain->rb_node, root);
}

286 287 288 289
static void
__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
		  u64 min_hit)
{
290
	struct rb_node *n;
291 292
	struct callchain_node *child;

293 294 295 296 297
	n = rb_first(&node->rb_root_in);
	while (n) {
		child = rb_entry(n, struct callchain_node, rb_node_in);
		n = rb_next(n);

298
		__sort_chain_flat(rb_root, child, min_hit);
299
	}
300 301 302 303 304

	if (node->hit && node->hit >= min_hit)
		rb_insert_callchain(rb_root, node, CHAIN_FLAT);
}

305 306 307 308
/*
 * Once we get every callchains from the stream, we can now
 * sort them by hit
 */
309
static void
310
sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
311
		u64 min_hit, struct callchain_param *param __maybe_unused)
312
{
313
	__sort_chain_flat(rb_root, &root->node, min_hit);
314 315 316 317
}

static void __sort_chain_graph_abs(struct callchain_node *node,
				   u64 min_hit)
318
{
319
	struct rb_node *n;
320 321
	struct callchain_node *child;

322
	node->rb_root = RB_ROOT;
323 324 325 326 327
	n = rb_first(&node->rb_root_in);

	while (n) {
		child = rb_entry(n, struct callchain_node, rb_node_in);
		n = rb_next(n);
328

329
		__sort_chain_graph_abs(child, min_hit);
330
		if (callchain_cumul_hits(child) >= min_hit)
331 332 333 334 335 336
			rb_insert_callchain(&node->rb_root, child,
					    CHAIN_GRAPH_ABS);
	}
}

static void
337
sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
338
		     u64 min_hit, struct callchain_param *param __maybe_unused)
339
{
340 341
	__sort_chain_graph_abs(&chain_root->node, min_hit);
	rb_root->rb_node = chain_root->node.rb_root.rb_node;
342 343
}

344 345
static void __sort_chain_graph_rel(struct callchain_node *node,
				   double min_percent)
346
{
347
	struct rb_node *n;
348
	struct callchain_node *child;
349
	u64 min_hit;
350 351

	node->rb_root = RB_ROOT;
352
	min_hit = ceil(node->children_hit * min_percent);
353

354 355 356 357 358
	n = rb_first(&node->rb_root_in);
	while (n) {
		child = rb_entry(n, struct callchain_node, rb_node_in);
		n = rb_next(n);

359
		__sort_chain_graph_rel(child, min_percent);
360
		if (callchain_cumul_hits(child) >= min_hit)
361 362
			rb_insert_callchain(&node->rb_root, child,
					    CHAIN_GRAPH_REL);
363 364 365
	}
}

366
static void
367
sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
368
		     u64 min_hit __maybe_unused, struct callchain_param *param)
369
{
370 371
	__sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
	rb_root->rb_node = chain_root->node.rb_root.rb_node;
372 373
}

374
int callchain_register_param(struct callchain_param *param)
375 376 377 378 379 380 381 382 383 384 385
{
	switch (param->mode) {
	case CHAIN_GRAPH_ABS:
		param->sort = sort_chain_graph_abs;
		break;
	case CHAIN_GRAPH_REL:
		param->sort = sort_chain_graph_rel;
		break;
	case CHAIN_FLAT:
		param->sort = sort_chain_flat;
		break;
386
	case CHAIN_NONE:
387 388 389 390 391 392
	default:
		return -1;
	}
	return 0;
}

393 394 395 396 397 398
/*
 * Create a child for a parent. If inherit_children, then the new child
 * will become the new parent of it's parent children
 */
static struct callchain_node *
create_child(struct callchain_node *parent, bool inherit_children)
399 400 401
{
	struct callchain_node *new;

402
	new = zalloc(sizeof(*new));
403 404 405 406 407 408
	if (!new) {
		perror("not enough memory to create child for code path tree");
		return NULL;
	}
	new->parent = parent;
	INIT_LIST_HEAD(&new->val);
409 410

	if (inherit_children) {
411 412 413 414 415
		struct rb_node *n;
		struct callchain_node *child;

		new->rb_root_in = parent->rb_root_in;
		parent->rb_root_in = RB_ROOT;
416

417 418 419 420 421 422
		n = rb_first(&new->rb_root_in);
		while (n) {
			child = rb_entry(n, struct callchain_node, rb_node_in);
			child->parent = new;
			n = rb_next(n);
		}
423

424 425 426
		/* make it the first child */
		rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
		rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
427
	}
428 429 430 431

	return new;
}

432

433 434 435
/*
 * Fill the node with callchain values
 */
436
static void
437
fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
438
{
439 440 441 442 443
	struct callchain_cursor_node *cursor_node;

	node->val_nr = cursor->nr - cursor->pos;
	if (!node->val_nr)
		pr_warning("Warning: empty node in callchain tree\n");
444

445 446 447
	cursor_node = callchain_cursor_current(cursor);

	while (cursor_node) {
448 449
		struct callchain_list *call;

450
		call = zalloc(sizeof(*call));
451 452 453 454
		if (!call) {
			perror("not enough memory for the code path tree");
			return;
		}
455 456 457
		call->ip = cursor_node->ip;
		call->ms.sym = cursor_node->sym;
		call->ms.map = cursor_node->map;
458
		list_add_tail(&call->list, &node->val);
459 460 461

		callchain_cursor_advance(cursor);
		cursor_node = callchain_cursor_current(cursor);
462 463 464
	}
}

465
static struct callchain_node *
466 467 468
add_child(struct callchain_node *parent,
	  struct callchain_cursor *cursor,
	  u64 period)
469 470 471
{
	struct callchain_node *new;

472
	new = create_child(parent, false);
473
	fill_node(new, cursor);
474

475
	new->children_hit = 0;
476
	new->hit = period;
477 478 479 480 481 482 483 484 485 486 487 488 489
	return new;
}

static s64 match_chain(struct callchain_cursor_node *node,
		      struct callchain_list *cnode)
{
	struct symbol *sym = node->sym;

	if (cnode->ms.sym && sym &&
	    callchain_param.key == CCKEY_FUNCTION)
		return cnode->ms.sym->start - sym->start;
	else
		return cnode->ip - node->ip;
490 491
}

492 493 494 495 496
/*
 * Split the parent in two parts (a new child is created) and
 * give a part of its callchain to the created child.
 * Then create another child to host the given callchain of new branch
 */
497
static void
498 499 500 501
split_add_child(struct callchain_node *parent,
		struct callchain_cursor *cursor,
		struct callchain_list *to_split,
		u64 idx_parents, u64 idx_local, u64 period)
502 503
{
	struct callchain_node *new;
504
	struct list_head *old_tail;
505
	unsigned int idx_total = idx_parents + idx_local;
506 507

	/* split */
508 509 510 511 512 513 514 515 516
	new = create_child(parent, true);

	/* split the callchain and move a part to the new child */
	old_tail = parent->val.prev;
	list_del_range(&to_split->list, old_tail);
	new->val.next = &to_split->list;
	new->val.prev = old_tail;
	to_split->list.prev = &new->val;
	old_tail->next = &new->val;
517

518 519
	/* split the hits */
	new->hit = parent->hit;
520
	new->children_hit = parent->children_hit;
521
	parent->children_hit = callchain_cumul_hits(new);
522 523 524 525
	new->val_nr = parent->val_nr - idx_local;
	parent->val_nr = idx_local;

	/* create a new child for the new branch if any */
526
	if (idx_total < cursor->nr) {
527 528 529 530 531
		struct callchain_node *first;
		struct callchain_list *cnode;
		struct callchain_cursor_node *node;
		struct rb_node *p, **pp;

532
		parent->hit = 0;
533
		parent->children_hit += period;
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553

		node = callchain_cursor_current(cursor);
		new = add_child(parent, cursor, period);

		/*
		 * This is second child since we moved parent's children
		 * to new (first) child above.
		 */
		p = parent->rb_root_in.rb_node;
		first = rb_entry(p, struct callchain_node, rb_node_in);
		cnode = list_first_entry(&first->val, struct callchain_list,
					 list);

		if (match_chain(node, cnode) < 0)
			pp = &p->rb_left;
		else
			pp = &p->rb_right;

		rb_link_node(&new->rb_node_in, p, pp);
		rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
554
	} else {
555
		parent->hit = period;
556
	}
557 558 559
}

static int
560 561 562
append_chain(struct callchain_node *root,
	     struct callchain_cursor *cursor,
	     u64 period);
563

564
static void
565 566 567
append_chain_children(struct callchain_node *root,
		      struct callchain_cursor *cursor,
		      u64 period)
568 569
{
	struct callchain_node *rnode;
570 571 572 573 574 575 576
	struct callchain_cursor_node *node;
	struct rb_node **p = &root->rb_root_in.rb_node;
	struct rb_node *parent = NULL;

	node = callchain_cursor_current(cursor);
	if (!node)
		return;
577 578

	/* lookup in childrens */
579 580
	while (*p) {
		s64 ret;
581

582 583 584
		parent = *p;
		rnode = rb_entry(parent, struct callchain_node, rb_node_in);

585 586 587
		/* If at least first entry matches, rely to children */
		ret = append_chain(rnode, cursor, period);
		if (ret == 0)
588
			goto inc_children_hit;
589 590 591 592 593

		if (ret < 0)
			p = &parent->rb_left;
		else
			p = &parent->rb_right;
594
	}
595
	/* nothing in children, add to the current node */
596 597 598
	rnode = add_child(root, cursor, period);
	rb_link_node(&rnode->rb_node_in, parent, p);
	rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
599

600
inc_children_hit:
601
	root->children_hit += period;
602 603 604
}

static int
605 606 607
append_chain(struct callchain_node *root,
	     struct callchain_cursor *cursor,
	     u64 period)
608 609
{
	struct callchain_list *cnode;
610
	u64 start = cursor->pos;
611
	bool found = false;
612
	u64 matches;
613
	int cmp = 0;
614

615 616 617
	/*
	 * Lookup in the current node
	 * If we have a symbol, then compare the start to match
618 619
	 * anywhere inside a function, unless function
	 * mode is disabled.
620
	 */
621
	list_for_each_entry(cnode, &root->val, list) {
622
		struct callchain_cursor_node *node;
623

624 625
		node = callchain_cursor_current(cursor);
		if (!node)
626
			break;
627

628 629
		cmp = match_chain(node, cnode);
		if (cmp)
630
			break;
631

632
		found = true;
633 634

		callchain_cursor_advance(cursor);
635 636
	}

637
	/* matches not, relay no the parent */
638
	if (!found) {
639 640
		WARN_ONCE(!cmp, "Chain comparison error\n");
		return cmp;
641 642 643
	}

	matches = cursor->pos - start;
644 645

	/* we match only a part of the node. Split it and add the new chain */
646 647
	if (matches < root->val_nr) {
		split_add_child(root, cursor, cnode, start, matches, period);
648 649 650 651
		return 0;
	}

	/* we match 100% of the path, increment the hit */
652
	if (matches == root->val_nr && cursor->pos == cursor->nr) {
653
		root->hit += period;
654 655 656
		return 0;
	}

657
	/* We match the node and still have a part remaining */
658
	append_chain_children(root, cursor, period);
659 660

	return 0;
661 662
}

663 664 665
int callchain_append(struct callchain_root *root,
		     struct callchain_cursor *cursor,
		     u64 period)
666
{
667
	if (!cursor->nr)
668 669
		return 0;

670
	callchain_cursor_commit(cursor);
671

672
	append_chain_children(&root->node, cursor, period);
673

674 675
	if (cursor->nr > root->max_depth)
		root->max_depth = cursor->nr;
676 677

	return 0;
678
}
679 680

static int
681 682
merge_chain_branch(struct callchain_cursor *cursor,
		   struct callchain_node *dst, struct callchain_node *src)
683
{
684
	struct callchain_cursor_node **old_last = cursor->last;
685
	struct callchain_node *child;
686
	struct callchain_list *list, *next_list;
687
	struct rb_node *n;
688
	int old_pos = cursor->nr;
689 690 691
	int err = 0;

	list_for_each_entry_safe(list, next_list, &src->val, list) {
692 693
		callchain_cursor_append(cursor, list->ip,
					list->ms.map, list->ms.sym);
694 695 696 697
		list_del(&list->list);
		free(list);
	}

698 699 700 701
	if (src->hit) {
		callchain_cursor_commit(cursor);
		append_chain_children(dst, cursor, src->hit);
	}
702

703 704 705 706 707 708
	n = rb_first(&src->rb_root_in);
	while (n) {
		child = container_of(n, struct callchain_node, rb_node_in);
		n = rb_next(n);
		rb_erase(&child->rb_node_in, &src->rb_root_in);

709
		err = merge_chain_branch(cursor, dst, child);
710 711 712 713 714 715
		if (err)
			break;

		free(child);
	}

716 717
	cursor->nr = old_pos;
	cursor->last = old_last;
718 719 720 721

	return err;
}

722 723 724 725 726 727 728 729
int callchain_merge(struct callchain_cursor *cursor,
		    struct callchain_root *dst, struct callchain_root *src)
{
	return merge_chain_branch(cursor, &dst->node, &src->node);
}

int callchain_cursor_append(struct callchain_cursor *cursor,
			    u64 ip, struct map *map, struct symbol *sym)
730
{
731
	struct callchain_cursor_node *node = *cursor->last;
732

733
	if (!node) {
734
		node = calloc(1, sizeof(*node));
735 736
		if (!node)
			return -ENOMEM;
737

738 739
		*cursor->last = node;
	}
740

741 742 743
	node->ip = ip;
	node->map = map;
	node->sym = sym;
744

745
	cursor->nr++;
746

747 748 749
	cursor->last = &node->next;

	return 0;
750
}
751 752 753 754 755 756 757 758

int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent,
			      struct perf_evsel *evsel, struct addr_location *al,
			      int max_stack)
{
	if (sample->callchain == NULL)
		return 0;

759 760
	if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
	    sort__has_parent) {
761 762
		return thread__resolve_callchain(al->thread, evsel, sample,
						 parent, al, max_stack);
763 764 765 766 767 768
	}
	return 0;
}

int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
{
769
	if (!symbol_conf.use_callchain || sample->callchain == NULL)
770 771 772
		return 0;
	return callchain_append(he->callchain, &callchain_cursor, sample->period);
}
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814

int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
			bool hide_unresolved)
{
	al->map = node->map;
	al->sym = node->sym;
	if (node->map)
		al->addr = node->map->map_ip(node->map, node->ip);
	else
		al->addr = node->ip;

	if (al->sym == NULL) {
		if (hide_unresolved)
			return 0;
		if (al->map == NULL)
			goto out;
	}

	if (al->map->groups == &al->machine->kmaps) {
		if (machine__is_host(al->machine)) {
			al->cpumode = PERF_RECORD_MISC_KERNEL;
			al->level = 'k';
		} else {
			al->cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
			al->level = 'g';
		}
	} else {
		if (machine__is_host(al->machine)) {
			al->cpumode = PERF_RECORD_MISC_USER;
			al->level = '.';
		} else if (perf_guest) {
			al->cpumode = PERF_RECORD_MISC_GUEST_USER;
			al->level = 'u';
		} else {
			al->cpumode = PERF_RECORD_MISC_HYPERVISOR;
			al->level = 'H';
		}
	}

out:
	return 1;
}
815 816 817 818 819 820 821

char *callchain_list__sym_name(struct callchain_list *cl,
			       char *bf, size_t bfsize, bool show_dso)
{
	int printed;

	if (cl->ms.sym) {
822 823 824 825
		if (callchain_param.key == CCKEY_ADDRESS &&
		    cl->ms.map && !cl->srcline)
			cl->srcline = get_srcline(cl->ms.map->dso,
						  map__rip_2objdump(cl->ms.map,
826 827
								    cl->ip),
						  cl->ms.sym, false);
828 829 830 831 832
		if (cl->srcline)
			printed = scnprintf(bf, bfsize, "%s %s",
					cl->ms.sym->name, cl->srcline);
		else
			printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
833 834 835 836 837 838 839 840 841 842 843
	} else
		printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);

	if (show_dso)
		scnprintf(bf + printed, bfsize - printed, " %s",
			  cl->ms.map ?
			  cl->ms.map->dso->short_name :
			  "unknown");

	return bf;
}