callchain.c 19.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
int parse_callchain_record_opt(const char *arg, struct callchain_param *param)
29
{
30
	return parse_callchain_record(arg, param);
31 32
}

33 34 35 36 37 38 39 40 41 42 43 44 45 46
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;
	}
47 48 49 50
	if (!strncmp(value, "folded", strlen(value))) {
		callchain_param.mode = CHAIN_FOLDED;
		return 0;
	}
51 52 53 54 55 56 57
	return -1;
}

static int parse_callchain_order(const char *value)
{
	if (!strncmp(value, "caller", strlen(value))) {
		callchain_param.order = ORDER_CALLER;
58
		callchain_param.order_set = true;
59 60 61 62
		return 0;
	}
	if (!strncmp(value, "callee", strlen(value))) {
		callchain_param.order = ORDER_CALLEE;
63
		callchain_param.order_set = true;
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
		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;
	}
79 80 81 82
	if (!strncmp(value, "branch", strlen(value))) {
		callchain_param.branch_callstack = 1;
		return 0;
	}
83 84 85
	return -1;
}

86 87
static int
__parse_callchain_report_opt(const char *arg, bool allow_record_opt)
88
{
89
	char *tok;
90
	char *endptr;
91
	bool minpcnt_set = false;
92 93
	bool record_opt_set = false;
	bool try_stack_size = false;
94 95 96 97 98 99

	symbol_conf.use_callchain = true;

	if (!arg)
		return 0;

100 101 102 103 104 105 106
	while ((tok = strtok((char *)arg, ",")) != NULL) {
		if (!strncmp(tok, "none", strlen(tok))) {
			callchain_param.mode = CHAIN_NONE;
			symbol_conf.use_callchain = false;
			return 0;
		}

107 108 109 110
		if (!parse_callchain_mode(tok) ||
		    !parse_callchain_order(tok) ||
		    !parse_callchain_sort_key(tok)) {
			/* parsing ok - move on to the next */
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
			try_stack_size = false;
			goto next;
		} else if (allow_record_opt && !record_opt_set) {
			if (parse_callchain_record(tok, &callchain_param))
				goto try_numbers;

			/* assume that number followed by 'dwarf' is stack size */
			if (callchain_param.record_mode == CALLCHAIN_DWARF)
				try_stack_size = true;

			record_opt_set = true;
			goto next;
		}

try_numbers:
		if (try_stack_size) {
			unsigned long size = 0;

			if (get_stack_size(tok, &size) < 0)
				return -1;
			callchain_param.dump_size = size;
			try_stack_size = false;
133 134
		} else if (!minpcnt_set) {
			/* try to get the min percent */
135 136 137 138 139 140 141 142 143 144
			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;
		}
145
next:
146
		arg = NULL;
147 148 149 150 151 152 153 154 155
	}

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

156 157 158 159 160 161 162 163 164 165
int parse_callchain_report_opt(const char *arg)
{
	return __parse_callchain_report_opt(arg, false);
}

int parse_callchain_top_opt(const char *arg)
{
	return __parse_callchain_report_opt(arg, true);
}

166 167 168 169 170 171 172 173 174
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"))
175
		return parse_callchain_record_opt(value, &callchain_param);
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
#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;
}

207
static void
208 209
rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
		    enum chain_mode mode)
210 211 212 213
{
	struct rb_node **p = &root->rb_node;
	struct rb_node *parent = NULL;
	struct callchain_node *rnode;
214
	u64 chain_cumul = callchain_cumul_hits(chain);
215 216

	while (*p) {
217 218
		u64 rnode_cumul;

219 220
		parent = *p;
		rnode = rb_entry(parent, struct callchain_node, rb_node);
221
		rnode_cumul = callchain_cumul_hits(rnode);
222

223
		switch (mode) {
224
		case CHAIN_FLAT:
225
		case CHAIN_FOLDED:
226 227 228 229 230
			if (rnode->hit < chain->hit)
				p = &(*p)->rb_left;
			else
				p = &(*p)->rb_right;
			break;
231 232
		case CHAIN_GRAPH_ABS: /* Falldown */
		case CHAIN_GRAPH_REL:
233
			if (rnode_cumul < chain_cumul)
234 235 236 237
				p = &(*p)->rb_left;
			else
				p = &(*p)->rb_right;
			break;
238
		case CHAIN_NONE:
239 240 241
		default:
			break;
		}
242 243 244 245 246 247
	}

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

248 249 250 251
static void
__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
		  u64 min_hit)
{
252
	struct rb_node *n;
253 254
	struct callchain_node *child;

255 256 257 258 259
	n = rb_first(&node->rb_root_in);
	while (n) {
		child = rb_entry(n, struct callchain_node, rb_node_in);
		n = rb_next(n);

260
		__sort_chain_flat(rb_root, child, min_hit);
261
	}
262 263 264 265 266

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

267 268 269 270
/*
 * Once we get every callchains from the stream, we can now
 * sort them by hit
 */
271
static void
272
sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
273
		u64 min_hit, struct callchain_param *param __maybe_unused)
274
{
275
	__sort_chain_flat(rb_root, &root->node, min_hit);
276 277 278 279
}

static void __sort_chain_graph_abs(struct callchain_node *node,
				   u64 min_hit)
280
{
281
	struct rb_node *n;
282 283
	struct callchain_node *child;

284
	node->rb_root = RB_ROOT;
285 286 287 288 289
	n = rb_first(&node->rb_root_in);

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

291
		__sort_chain_graph_abs(child, min_hit);
292
		if (callchain_cumul_hits(child) >= min_hit)
293 294 295 296 297 298
			rb_insert_callchain(&node->rb_root, child,
					    CHAIN_GRAPH_ABS);
	}
}

static void
299
sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
300
		     u64 min_hit, struct callchain_param *param __maybe_unused)
301
{
302 303
	__sort_chain_graph_abs(&chain_root->node, min_hit);
	rb_root->rb_node = chain_root->node.rb_root.rb_node;
304 305
}

306 307
static void __sort_chain_graph_rel(struct callchain_node *node,
				   double min_percent)
308
{
309
	struct rb_node *n;
310
	struct callchain_node *child;
311
	u64 min_hit;
312 313

	node->rb_root = RB_ROOT;
314
	min_hit = ceil(node->children_hit * min_percent);
315

316 317 318 319 320
	n = rb_first(&node->rb_root_in);
	while (n) {
		child = rb_entry(n, struct callchain_node, rb_node_in);
		n = rb_next(n);

321
		__sort_chain_graph_rel(child, min_percent);
322
		if (callchain_cumul_hits(child) >= min_hit)
323 324
			rb_insert_callchain(&node->rb_root, child,
					    CHAIN_GRAPH_REL);
325 326 327
	}
}

328
static void
329
sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
330
		     u64 min_hit __maybe_unused, struct callchain_param *param)
331
{
332 333
	__sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
	rb_root->rb_node = chain_root->node.rb_root.rb_node;
334 335
}

336
int callchain_register_param(struct callchain_param *param)
337 338 339 340 341 342 343 344 345
{
	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:
346
	case CHAIN_FOLDED:
347 348
		param->sort = sort_chain_flat;
		break;
349
	case CHAIN_NONE:
350 351 352 353 354 355
	default:
		return -1;
	}
	return 0;
}

356 357 358 359 360 361
/*
 * 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)
362 363 364
{
	struct callchain_node *new;

365
	new = zalloc(sizeof(*new));
366 367 368 369 370 371
	if (!new) {
		perror("not enough memory to create child for code path tree");
		return NULL;
	}
	new->parent = parent;
	INIT_LIST_HEAD(&new->val);
372 373

	if (inherit_children) {
374 375 376 377 378
		struct rb_node *n;
		struct callchain_node *child;

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

380 381 382 383 384 385
		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);
		}
386

387 388 389
		/* 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);
390
	}
391 392 393 394

	return new;
}

395

396 397 398
/*
 * Fill the node with callchain values
 */
399
static void
400
fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
401
{
402 403 404 405 406
	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");
407

408 409 410
	cursor_node = callchain_cursor_current(cursor);

	while (cursor_node) {
411 412
		struct callchain_list *call;

413
		call = zalloc(sizeof(*call));
414 415 416 417
		if (!call) {
			perror("not enough memory for the code path tree");
			return;
		}
418 419 420
		call->ip = cursor_node->ip;
		call->ms.sym = cursor_node->sym;
		call->ms.map = cursor_node->map;
421
		list_add_tail(&call->list, &node->val);
422 423 424

		callchain_cursor_advance(cursor);
		cursor_node = callchain_cursor_current(cursor);
425 426 427
	}
}

428
static struct callchain_node *
429 430 431
add_child(struct callchain_node *parent,
	  struct callchain_cursor *cursor,
	  u64 period)
432 433 434
{
	struct callchain_node *new;

435
	new = create_child(parent, false);
436
	fill_node(new, cursor);
437

438
	new->children_hit = 0;
439
	new->hit = period;
440 441
	new->children_count = 0;
	new->count = 1;
442 443 444 445 446 447 448 449 450 451 452 453 454
	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;
455 456
}

457 458 459 460 461
/*
 * 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
 */
462
static void
463 464 465 466
split_add_child(struct callchain_node *parent,
		struct callchain_cursor *cursor,
		struct callchain_list *to_split,
		u64 idx_parents, u64 idx_local, u64 period)
467 468
{
	struct callchain_node *new;
469
	struct list_head *old_tail;
470
	unsigned int idx_total = idx_parents + idx_local;
471 472

	/* split */
473 474 475 476 477 478 479 480 481
	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;
482

483 484
	/* split the hits */
	new->hit = parent->hit;
485
	new->children_hit = parent->children_hit;
486
	parent->children_hit = callchain_cumul_hits(new);
487 488
	new->val_nr = parent->val_nr - idx_local;
	parent->val_nr = idx_local;
489 490 491
	new->count = parent->count;
	new->children_count = parent->children_count;
	parent->children_count = callchain_cumul_counts(new);
492 493

	/* create a new child for the new branch if any */
494
	if (idx_total < cursor->nr) {
495 496 497 498 499
		struct callchain_node *first;
		struct callchain_list *cnode;
		struct callchain_cursor_node *node;
		struct rb_node *p, **pp;

500
		parent->hit = 0;
501
		parent->children_hit += period;
502 503
		parent->count = 0;
		parent->children_count += 1;
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523

		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);
524
	} else {
525
		parent->hit = period;
526
		parent->count = 1;
527
	}
528 529 530
}

static int
531 532 533
append_chain(struct callchain_node *root,
	     struct callchain_cursor *cursor,
	     u64 period);
534

535
static void
536 537 538
append_chain_children(struct callchain_node *root,
		      struct callchain_cursor *cursor,
		      u64 period)
539 540
{
	struct callchain_node *rnode;
541 542 543 544 545 546 547
	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;
548 549

	/* lookup in childrens */
550 551
	while (*p) {
		s64 ret;
552

553 554 555
		parent = *p;
		rnode = rb_entry(parent, struct callchain_node, rb_node_in);

556 557 558
		/* If at least first entry matches, rely to children */
		ret = append_chain(rnode, cursor, period);
		if (ret == 0)
559
			goto inc_children_hit;
560 561 562 563 564

		if (ret < 0)
			p = &parent->rb_left;
		else
			p = &parent->rb_right;
565
	}
566
	/* nothing in children, add to the current node */
567 568 569
	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);
570

571
inc_children_hit:
572
	root->children_hit += period;
573
	root->children_count++;
574 575 576
}

static int
577 578 579
append_chain(struct callchain_node *root,
	     struct callchain_cursor *cursor,
	     u64 period)
580 581
{
	struct callchain_list *cnode;
582
	u64 start = cursor->pos;
583
	bool found = false;
584
	u64 matches;
585
	int cmp = 0;
586

587 588 589
	/*
	 * Lookup in the current node
	 * If we have a symbol, then compare the start to match
590 591
	 * anywhere inside a function, unless function
	 * mode is disabled.
592
	 */
593
	list_for_each_entry(cnode, &root->val, list) {
594
		struct callchain_cursor_node *node;
595

596 597
		node = callchain_cursor_current(cursor);
		if (!node)
598
			break;
599

600 601
		cmp = match_chain(node, cnode);
		if (cmp)
602
			break;
603

604
		found = true;
605 606

		callchain_cursor_advance(cursor);
607 608
	}

609
	/* matches not, relay no the parent */
610
	if (!found) {
611 612
		WARN_ONCE(!cmp, "Chain comparison error\n");
		return cmp;
613 614 615
	}

	matches = cursor->pos - start;
616 617

	/* we match only a part of the node. Split it and add the new chain */
618 619
	if (matches < root->val_nr) {
		split_add_child(root, cursor, cnode, start, matches, period);
620 621 622 623
		return 0;
	}

	/* we match 100% of the path, increment the hit */
624
	if (matches == root->val_nr && cursor->pos == cursor->nr) {
625
		root->hit += period;
626
		root->count++;
627 628 629
		return 0;
	}

630
	/* We match the node and still have a part remaining */
631
	append_chain_children(root, cursor, period);
632 633

	return 0;
634 635
}

636 637 638
int callchain_append(struct callchain_root *root,
		     struct callchain_cursor *cursor,
		     u64 period)
639
{
640
	if (!cursor->nr)
641 642
		return 0;

643
	callchain_cursor_commit(cursor);
644

645
	append_chain_children(&root->node, cursor, period);
646

647 648
	if (cursor->nr > root->max_depth)
		root->max_depth = cursor->nr;
649 650

	return 0;
651
}
652 653

static int
654 655
merge_chain_branch(struct callchain_cursor *cursor,
		   struct callchain_node *dst, struct callchain_node *src)
656
{
657
	struct callchain_cursor_node **old_last = cursor->last;
658
	struct callchain_node *child;
659
	struct callchain_list *list, *next_list;
660
	struct rb_node *n;
661
	int old_pos = cursor->nr;
662 663 664
	int err = 0;

	list_for_each_entry_safe(list, next_list, &src->val, list) {
665 666
		callchain_cursor_append(cursor, list->ip,
					list->ms.map, list->ms.sym);
667 668 669 670
		list_del(&list->list);
		free(list);
	}

671 672 673 674
	if (src->hit) {
		callchain_cursor_commit(cursor);
		append_chain_children(dst, cursor, src->hit);
	}
675

676 677 678 679 680 681
	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);

682
		err = merge_chain_branch(cursor, dst, child);
683 684 685 686 687 688
		if (err)
			break;

		free(child);
	}

689 690
	cursor->nr = old_pos;
	cursor->last = old_last;
691 692 693 694

	return err;
}

695 696 697 698 699 700 701 702
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)
703
{
704
	struct callchain_cursor_node *node = *cursor->last;
705

706
	if (!node) {
707
		node = calloc(1, sizeof(*node));
708 709
		if (!node)
			return -ENOMEM;
710

711 712
		*cursor->last = node;
	}
713

714 715 716
	node->ip = ip;
	node->map = map;
	node->sym = sym;
717

718
	cursor->nr++;
719

720 721 722
	cursor->last = &node->next;

	return 0;
723
}
724 725 726 727 728 729 730 731

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;

732 733
	if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
	    sort__has_parent) {
734 735
		return thread__resolve_callchain(al->thread, evsel, sample,
						 parent, al, max_stack);
736 737 738 739 740 741
	}
	return 0;
}

int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
{
742
	if (!symbol_conf.use_callchain || sample->callchain == NULL)
743 744 745
		return 0;
	return callchain_append(he->callchain, &callchain_cursor, sample->period);
}
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787

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;
}
788 789 790 791 792 793 794

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

	if (cl->ms.sym) {
795 796 797 798
		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,
799 800
								    cl->ip),
						  cl->ms.sym, false);
801 802 803 804 805
		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);
806 807 808 809 810 811 812 813 814 815 816
	} 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;
}
817

818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
char *callchain_node__scnprintf_value(struct callchain_node *node,
				      char *bf, size_t bfsize, u64 total)
{
	double percent = 0.0;
	u64 period = callchain_cumul_hits(node);

	if (callchain_param.mode == CHAIN_FOLDED)
		period = node->hit;
	if (total)
		percent = period * 100.0 / total;

	scnprintf(bf, bfsize, "%.2f%%", percent);
	return bf;
}

int callchain_node__fprintf_value(struct callchain_node *node,
				 FILE *fp, u64 total)
{
	double percent = 0.0;
	u64 period = callchain_cumul_hits(node);

	if (callchain_param.mode == CHAIN_FOLDED)
		period = node->hit;
	if (total)
		percent = period * 100.0 / total;

	return percent_color_fprintf(fp, "%.2f%%", percent);
}

847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
static void free_callchain_node(struct callchain_node *node)
{
	struct callchain_list *list, *tmp;
	struct callchain_node *child;
	struct rb_node *n;

	list_for_each_entry_safe(list, tmp, &node->val, list) {
		list_del(&list->list);
		free(list);
	}

	n = rb_first(&node->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, &node->rb_root_in);

		free_callchain_node(child);
		free(child);
	}
}

void free_callchain(struct callchain_root *root)
{
	if (!symbol_conf.use_callchain)
		return;

	free_callchain_node(&root->node);
}