162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2009-2011, Frederic Weisbecker <fweisbec@gmail.com>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Handle the callchains from the stream in an ad-hoc radix tree and then
662306a36Sopenharmony_ci * sort them in an rbtree.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Using a radix for code path provides a fast retrieval and factorizes
962306a36Sopenharmony_ci * memory use. Also that lets us use the paths in a hierarchical graph view.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <inttypes.h>
1462306a36Sopenharmony_ci#include <stdlib.h>
1562306a36Sopenharmony_ci#include <stdio.h>
1662306a36Sopenharmony_ci#include <stdbool.h>
1762306a36Sopenharmony_ci#include <errno.h>
1862306a36Sopenharmony_ci#include <math.h>
1962306a36Sopenharmony_ci#include <linux/string.h>
2062306a36Sopenharmony_ci#include <linux/zalloc.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "asm/bug.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "debug.h"
2562306a36Sopenharmony_ci#include "dso.h"
2662306a36Sopenharmony_ci#include "event.h"
2762306a36Sopenharmony_ci#include "hist.h"
2862306a36Sopenharmony_ci#include "sort.h"
2962306a36Sopenharmony_ci#include "machine.h"
3062306a36Sopenharmony_ci#include "map.h"
3162306a36Sopenharmony_ci#include "callchain.h"
3262306a36Sopenharmony_ci#include "branch.h"
3362306a36Sopenharmony_ci#include "symbol.h"
3462306a36Sopenharmony_ci#include "util.h"
3562306a36Sopenharmony_ci#include "../perf.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define CALLCHAIN_PARAM_DEFAULT			\
3862306a36Sopenharmony_ci	.mode		= CHAIN_GRAPH_ABS,	\
3962306a36Sopenharmony_ci	.min_percent	= 0.5,			\
4062306a36Sopenharmony_ci	.order		= ORDER_CALLEE,		\
4162306a36Sopenharmony_ci	.key		= CCKEY_FUNCTION,	\
4262306a36Sopenharmony_ci	.value		= CCVAL_PERCENT,	\
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistruct callchain_param callchain_param = {
4562306a36Sopenharmony_ci	CALLCHAIN_PARAM_DEFAULT
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/*
4962306a36Sopenharmony_ci * Are there any events usind DWARF callchains?
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * I.e.
5262306a36Sopenharmony_ci *
5362306a36Sopenharmony_ci * -e cycles/call-graph=dwarf/
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_cibool dwarf_callchain_users;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistruct callchain_param callchain_param_default = {
5862306a36Sopenharmony_ci	CALLCHAIN_PARAM_DEFAULT
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* Used for thread-local struct callchain_cursor. */
6262306a36Sopenharmony_cistatic pthread_key_t callchain_cursor;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ciint parse_callchain_record_opt(const char *arg, struct callchain_param *param)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	return parse_callchain_record(arg, param);
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic int parse_callchain_mode(const char *value)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	if (!strncmp(value, "graph", strlen(value))) {
7262306a36Sopenharmony_ci		callchain_param.mode = CHAIN_GRAPH_ABS;
7362306a36Sopenharmony_ci		return 0;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci	if (!strncmp(value, "flat", strlen(value))) {
7662306a36Sopenharmony_ci		callchain_param.mode = CHAIN_FLAT;
7762306a36Sopenharmony_ci		return 0;
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci	if (!strncmp(value, "fractal", strlen(value))) {
8062306a36Sopenharmony_ci		callchain_param.mode = CHAIN_GRAPH_REL;
8162306a36Sopenharmony_ci		return 0;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci	if (!strncmp(value, "folded", strlen(value))) {
8462306a36Sopenharmony_ci		callchain_param.mode = CHAIN_FOLDED;
8562306a36Sopenharmony_ci		return 0;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci	return -1;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic int parse_callchain_order(const char *value)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	if (!strncmp(value, "caller", strlen(value))) {
9362306a36Sopenharmony_ci		callchain_param.order = ORDER_CALLER;
9462306a36Sopenharmony_ci		callchain_param.order_set = true;
9562306a36Sopenharmony_ci		return 0;
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci	if (!strncmp(value, "callee", strlen(value))) {
9862306a36Sopenharmony_ci		callchain_param.order = ORDER_CALLEE;
9962306a36Sopenharmony_ci		callchain_param.order_set = true;
10062306a36Sopenharmony_ci		return 0;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci	return -1;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic int parse_callchain_sort_key(const char *value)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	if (!strncmp(value, "function", strlen(value))) {
10862306a36Sopenharmony_ci		callchain_param.key = CCKEY_FUNCTION;
10962306a36Sopenharmony_ci		return 0;
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci	if (!strncmp(value, "address", strlen(value))) {
11262306a36Sopenharmony_ci		callchain_param.key = CCKEY_ADDRESS;
11362306a36Sopenharmony_ci		return 0;
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci	if (!strncmp(value, "srcline", strlen(value))) {
11662306a36Sopenharmony_ci		callchain_param.key = CCKEY_SRCLINE;
11762306a36Sopenharmony_ci		return 0;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci	if (!strncmp(value, "branch", strlen(value))) {
12062306a36Sopenharmony_ci		callchain_param.branch_callstack = 1;
12162306a36Sopenharmony_ci		return 0;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci	return -1;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic int parse_callchain_value(const char *value)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	if (!strncmp(value, "percent", strlen(value))) {
12962306a36Sopenharmony_ci		callchain_param.value = CCVAL_PERCENT;
13062306a36Sopenharmony_ci		return 0;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci	if (!strncmp(value, "period", strlen(value))) {
13362306a36Sopenharmony_ci		callchain_param.value = CCVAL_PERIOD;
13462306a36Sopenharmony_ci		return 0;
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci	if (!strncmp(value, "count", strlen(value))) {
13762306a36Sopenharmony_ci		callchain_param.value = CCVAL_COUNT;
13862306a36Sopenharmony_ci		return 0;
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci	return -1;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int get_stack_size(const char *str, unsigned long *_size)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	char *endptr;
14662306a36Sopenharmony_ci	unsigned long size;
14762306a36Sopenharmony_ci	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	size = strtoul(str, &endptr, 0);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	do {
15262306a36Sopenharmony_ci		if (*endptr)
15362306a36Sopenharmony_ci			break;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		size = round_up(size, sizeof(u64));
15662306a36Sopenharmony_ci		if (!size || size > max_size)
15762306a36Sopenharmony_ci			break;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci		*_size = size;
16062306a36Sopenharmony_ci		return 0;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	} while (0);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
16562306a36Sopenharmony_ci	       max_size, str);
16662306a36Sopenharmony_ci	return -1;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic int
17062306a36Sopenharmony_ci__parse_callchain_report_opt(const char *arg, bool allow_record_opt)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	char *tok;
17362306a36Sopenharmony_ci	char *endptr, *saveptr = NULL;
17462306a36Sopenharmony_ci	bool minpcnt_set = false;
17562306a36Sopenharmony_ci	bool record_opt_set = false;
17662306a36Sopenharmony_ci	bool try_stack_size = false;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	callchain_param.enabled = true;
17962306a36Sopenharmony_ci	symbol_conf.use_callchain = true;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (!arg)
18262306a36Sopenharmony_ci		return 0;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	while ((tok = strtok_r((char *)arg, ",", &saveptr)) != NULL) {
18562306a36Sopenharmony_ci		if (!strncmp(tok, "none", strlen(tok))) {
18662306a36Sopenharmony_ci			callchain_param.mode = CHAIN_NONE;
18762306a36Sopenharmony_ci			callchain_param.enabled = false;
18862306a36Sopenharmony_ci			symbol_conf.use_callchain = false;
18962306a36Sopenharmony_ci			return 0;
19062306a36Sopenharmony_ci		}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		if (!parse_callchain_mode(tok) ||
19362306a36Sopenharmony_ci		    !parse_callchain_order(tok) ||
19462306a36Sopenharmony_ci		    !parse_callchain_sort_key(tok) ||
19562306a36Sopenharmony_ci		    !parse_callchain_value(tok)) {
19662306a36Sopenharmony_ci			/* parsing ok - move on to the next */
19762306a36Sopenharmony_ci			try_stack_size = false;
19862306a36Sopenharmony_ci			goto next;
19962306a36Sopenharmony_ci		} else if (allow_record_opt && !record_opt_set) {
20062306a36Sopenharmony_ci			if (parse_callchain_record(tok, &callchain_param))
20162306a36Sopenharmony_ci				goto try_numbers;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci			/* assume that number followed by 'dwarf' is stack size */
20462306a36Sopenharmony_ci			if (callchain_param.record_mode == CALLCHAIN_DWARF)
20562306a36Sopenharmony_ci				try_stack_size = true;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci			record_opt_set = true;
20862306a36Sopenharmony_ci			goto next;
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_citry_numbers:
21262306a36Sopenharmony_ci		if (try_stack_size) {
21362306a36Sopenharmony_ci			unsigned long size = 0;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci			if (get_stack_size(tok, &size) < 0)
21662306a36Sopenharmony_ci				return -1;
21762306a36Sopenharmony_ci			callchain_param.dump_size = size;
21862306a36Sopenharmony_ci			try_stack_size = false;
21962306a36Sopenharmony_ci		} else if (!minpcnt_set) {
22062306a36Sopenharmony_ci			/* try to get the min percent */
22162306a36Sopenharmony_ci			callchain_param.min_percent = strtod(tok, &endptr);
22262306a36Sopenharmony_ci			if (tok == endptr)
22362306a36Sopenharmony_ci				return -1;
22462306a36Sopenharmony_ci			minpcnt_set = true;
22562306a36Sopenharmony_ci		} else {
22662306a36Sopenharmony_ci			/* try print limit at last */
22762306a36Sopenharmony_ci			callchain_param.print_limit = strtoul(tok, &endptr, 0);
22862306a36Sopenharmony_ci			if (tok == endptr)
22962306a36Sopenharmony_ci				return -1;
23062306a36Sopenharmony_ci		}
23162306a36Sopenharmony_cinext:
23262306a36Sopenharmony_ci		arg = NULL;
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (callchain_register_param(&callchain_param) < 0) {
23662306a36Sopenharmony_ci		pr_err("Can't register callchain params\n");
23762306a36Sopenharmony_ci		return -1;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci	return 0;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ciint parse_callchain_report_opt(const char *arg)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	return __parse_callchain_report_opt(arg, false);
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ciint parse_callchain_top_opt(const char *arg)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	return __parse_callchain_report_opt(arg, true);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ciint parse_callchain_record(const char *arg, struct callchain_param *param)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	char *tok, *name, *saveptr = NULL;
25562306a36Sopenharmony_ci	char *buf;
25662306a36Sopenharmony_ci	int ret = -1;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	/* We need buffer that we know we can write to. */
25962306a36Sopenharmony_ci	buf = malloc(strlen(arg) + 1);
26062306a36Sopenharmony_ci	if (!buf)
26162306a36Sopenharmony_ci		return -ENOMEM;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	strcpy(buf, arg);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	tok = strtok_r((char *)buf, ",", &saveptr);
26662306a36Sopenharmony_ci	name = tok ? : (char *)buf;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	do {
26962306a36Sopenharmony_ci		/* Framepointer style */
27062306a36Sopenharmony_ci		if (!strncmp(name, "fp", sizeof("fp"))) {
27162306a36Sopenharmony_ci			ret = 0;
27262306a36Sopenharmony_ci			param->record_mode = CALLCHAIN_FP;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci			tok = strtok_r(NULL, ",", &saveptr);
27562306a36Sopenharmony_ci			if (tok) {
27662306a36Sopenharmony_ci				unsigned long size;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci				size = strtoul(tok, &name, 0);
27962306a36Sopenharmony_ci				if (size < (unsigned) sysctl__max_stack())
28062306a36Sopenharmony_ci					param->max_stack = size;
28162306a36Sopenharmony_ci			}
28262306a36Sopenharmony_ci			break;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		/* Dwarf style */
28562306a36Sopenharmony_ci		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
28662306a36Sopenharmony_ci			const unsigned long default_stack_dump_size = 8192;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci			ret = 0;
28962306a36Sopenharmony_ci			param->record_mode = CALLCHAIN_DWARF;
29062306a36Sopenharmony_ci			param->dump_size = default_stack_dump_size;
29162306a36Sopenharmony_ci			dwarf_callchain_users = true;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci			tok = strtok_r(NULL, ",", &saveptr);
29462306a36Sopenharmony_ci			if (tok) {
29562306a36Sopenharmony_ci				unsigned long size = 0;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci				ret = get_stack_size(tok, &size);
29862306a36Sopenharmony_ci				param->dump_size = size;
29962306a36Sopenharmony_ci			}
30062306a36Sopenharmony_ci		} else if (!strncmp(name, "lbr", sizeof("lbr"))) {
30162306a36Sopenharmony_ci			if (!strtok_r(NULL, ",", &saveptr)) {
30262306a36Sopenharmony_ci				param->record_mode = CALLCHAIN_LBR;
30362306a36Sopenharmony_ci				ret = 0;
30462306a36Sopenharmony_ci			} else
30562306a36Sopenharmony_ci				pr_err("callchain: No more arguments "
30662306a36Sopenharmony_ci					"needed for --call-graph lbr\n");
30762306a36Sopenharmony_ci			break;
30862306a36Sopenharmony_ci		} else {
30962306a36Sopenharmony_ci			pr_err("callchain: Unknown --call-graph option "
31062306a36Sopenharmony_ci			       "value: %s\n", arg);
31162306a36Sopenharmony_ci			break;
31262306a36Sopenharmony_ci		}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	} while (0);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	free(buf);
31762306a36Sopenharmony_ci	return ret;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ciint perf_callchain_config(const char *var, const char *value)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	char *endptr;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (!strstarts(var, "call-graph."))
32562306a36Sopenharmony_ci		return 0;
32662306a36Sopenharmony_ci	var += sizeof("call-graph.") - 1;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (!strcmp(var, "record-mode"))
32962306a36Sopenharmony_ci		return parse_callchain_record_opt(value, &callchain_param);
33062306a36Sopenharmony_ci	if (!strcmp(var, "dump-size")) {
33162306a36Sopenharmony_ci		unsigned long size = 0;
33262306a36Sopenharmony_ci		int ret;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		ret = get_stack_size(value, &size);
33562306a36Sopenharmony_ci		callchain_param.dump_size = size;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci		return ret;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci	if (!strcmp(var, "print-type")){
34062306a36Sopenharmony_ci		int ret;
34162306a36Sopenharmony_ci		ret = parse_callchain_mode(value);
34262306a36Sopenharmony_ci		if (ret == -1)
34362306a36Sopenharmony_ci			pr_err("Invalid callchain mode: %s\n", value);
34462306a36Sopenharmony_ci		return ret;
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci	if (!strcmp(var, "order")){
34762306a36Sopenharmony_ci		int ret;
34862306a36Sopenharmony_ci		ret = parse_callchain_order(value);
34962306a36Sopenharmony_ci		if (ret == -1)
35062306a36Sopenharmony_ci			pr_err("Invalid callchain order: %s\n", value);
35162306a36Sopenharmony_ci		return ret;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci	if (!strcmp(var, "sort-key")){
35462306a36Sopenharmony_ci		int ret;
35562306a36Sopenharmony_ci		ret = parse_callchain_sort_key(value);
35662306a36Sopenharmony_ci		if (ret == -1)
35762306a36Sopenharmony_ci			pr_err("Invalid callchain sort key: %s\n", value);
35862306a36Sopenharmony_ci		return ret;
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci	if (!strcmp(var, "threshold")) {
36162306a36Sopenharmony_ci		callchain_param.min_percent = strtod(value, &endptr);
36262306a36Sopenharmony_ci		if (value == endptr) {
36362306a36Sopenharmony_ci			pr_err("Invalid callchain threshold: %s\n", value);
36462306a36Sopenharmony_ci			return -1;
36562306a36Sopenharmony_ci		}
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci	if (!strcmp(var, "print-limit")) {
36862306a36Sopenharmony_ci		callchain_param.print_limit = strtod(value, &endptr);
36962306a36Sopenharmony_ci		if (value == endptr) {
37062306a36Sopenharmony_ci			pr_err("Invalid callchain print limit: %s\n", value);
37162306a36Sopenharmony_ci			return -1;
37262306a36Sopenharmony_ci		}
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	return 0;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic void
37962306a36Sopenharmony_cirb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
38062306a36Sopenharmony_ci		    enum chain_mode mode)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct rb_node **p = &root->rb_node;
38362306a36Sopenharmony_ci	struct rb_node *parent = NULL;
38462306a36Sopenharmony_ci	struct callchain_node *rnode;
38562306a36Sopenharmony_ci	u64 chain_cumul = callchain_cumul_hits(chain);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	while (*p) {
38862306a36Sopenharmony_ci		u64 rnode_cumul;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		parent = *p;
39162306a36Sopenharmony_ci		rnode = rb_entry(parent, struct callchain_node, rb_node);
39262306a36Sopenharmony_ci		rnode_cumul = callchain_cumul_hits(rnode);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		switch (mode) {
39562306a36Sopenharmony_ci		case CHAIN_FLAT:
39662306a36Sopenharmony_ci		case CHAIN_FOLDED:
39762306a36Sopenharmony_ci			if (rnode->hit < chain->hit)
39862306a36Sopenharmony_ci				p = &(*p)->rb_left;
39962306a36Sopenharmony_ci			else
40062306a36Sopenharmony_ci				p = &(*p)->rb_right;
40162306a36Sopenharmony_ci			break;
40262306a36Sopenharmony_ci		case CHAIN_GRAPH_ABS: /* Falldown */
40362306a36Sopenharmony_ci		case CHAIN_GRAPH_REL:
40462306a36Sopenharmony_ci			if (rnode_cumul < chain_cumul)
40562306a36Sopenharmony_ci				p = &(*p)->rb_left;
40662306a36Sopenharmony_ci			else
40762306a36Sopenharmony_ci				p = &(*p)->rb_right;
40862306a36Sopenharmony_ci			break;
40962306a36Sopenharmony_ci		case CHAIN_NONE:
41062306a36Sopenharmony_ci		default:
41162306a36Sopenharmony_ci			break;
41262306a36Sopenharmony_ci		}
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	rb_link_node(&chain->rb_node, parent, p);
41662306a36Sopenharmony_ci	rb_insert_color(&chain->rb_node, root);
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic void
42062306a36Sopenharmony_ci__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
42162306a36Sopenharmony_ci		  u64 min_hit)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	struct rb_node *n;
42462306a36Sopenharmony_ci	struct callchain_node *child;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	n = rb_first(&node->rb_root_in);
42762306a36Sopenharmony_ci	while (n) {
42862306a36Sopenharmony_ci		child = rb_entry(n, struct callchain_node, rb_node_in);
42962306a36Sopenharmony_ci		n = rb_next(n);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		__sort_chain_flat(rb_root, child, min_hit);
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (node->hit && node->hit >= min_hit)
43562306a36Sopenharmony_ci		rb_insert_callchain(rb_root, node, CHAIN_FLAT);
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci/*
43962306a36Sopenharmony_ci * Once we get every callchains from the stream, we can now
44062306a36Sopenharmony_ci * sort them by hit
44162306a36Sopenharmony_ci */
44262306a36Sopenharmony_cistatic void
44362306a36Sopenharmony_cisort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
44462306a36Sopenharmony_ci		u64 min_hit, struct callchain_param *param __maybe_unused)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	*rb_root = RB_ROOT;
44762306a36Sopenharmony_ci	__sort_chain_flat(rb_root, &root->node, min_hit);
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic void __sort_chain_graph_abs(struct callchain_node *node,
45162306a36Sopenharmony_ci				   u64 min_hit)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct rb_node *n;
45462306a36Sopenharmony_ci	struct callchain_node *child;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	node->rb_root = RB_ROOT;
45762306a36Sopenharmony_ci	n = rb_first(&node->rb_root_in);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	while (n) {
46062306a36Sopenharmony_ci		child = rb_entry(n, struct callchain_node, rb_node_in);
46162306a36Sopenharmony_ci		n = rb_next(n);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci		__sort_chain_graph_abs(child, min_hit);
46462306a36Sopenharmony_ci		if (callchain_cumul_hits(child) >= min_hit)
46562306a36Sopenharmony_ci			rb_insert_callchain(&node->rb_root, child,
46662306a36Sopenharmony_ci					    CHAIN_GRAPH_ABS);
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic void
47162306a36Sopenharmony_cisort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
47262306a36Sopenharmony_ci		     u64 min_hit, struct callchain_param *param __maybe_unused)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	__sort_chain_graph_abs(&chain_root->node, min_hit);
47562306a36Sopenharmony_ci	rb_root->rb_node = chain_root->node.rb_root.rb_node;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic void __sort_chain_graph_rel(struct callchain_node *node,
47962306a36Sopenharmony_ci				   double min_percent)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	struct rb_node *n;
48262306a36Sopenharmony_ci	struct callchain_node *child;
48362306a36Sopenharmony_ci	u64 min_hit;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	node->rb_root = RB_ROOT;
48662306a36Sopenharmony_ci	min_hit = ceil(node->children_hit * min_percent);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	n = rb_first(&node->rb_root_in);
48962306a36Sopenharmony_ci	while (n) {
49062306a36Sopenharmony_ci		child = rb_entry(n, struct callchain_node, rb_node_in);
49162306a36Sopenharmony_ci		n = rb_next(n);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci		__sort_chain_graph_rel(child, min_percent);
49462306a36Sopenharmony_ci		if (callchain_cumul_hits(child) >= min_hit)
49562306a36Sopenharmony_ci			rb_insert_callchain(&node->rb_root, child,
49662306a36Sopenharmony_ci					    CHAIN_GRAPH_REL);
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic void
50162306a36Sopenharmony_cisort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
50262306a36Sopenharmony_ci		     u64 min_hit __maybe_unused, struct callchain_param *param)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	__sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
50562306a36Sopenharmony_ci	rb_root->rb_node = chain_root->node.rb_root.rb_node;
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ciint callchain_register_param(struct callchain_param *param)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	switch (param->mode) {
51162306a36Sopenharmony_ci	case CHAIN_GRAPH_ABS:
51262306a36Sopenharmony_ci		param->sort = sort_chain_graph_abs;
51362306a36Sopenharmony_ci		break;
51462306a36Sopenharmony_ci	case CHAIN_GRAPH_REL:
51562306a36Sopenharmony_ci		param->sort = sort_chain_graph_rel;
51662306a36Sopenharmony_ci		break;
51762306a36Sopenharmony_ci	case CHAIN_FLAT:
51862306a36Sopenharmony_ci	case CHAIN_FOLDED:
51962306a36Sopenharmony_ci		param->sort = sort_chain_flat;
52062306a36Sopenharmony_ci		break;
52162306a36Sopenharmony_ci	case CHAIN_NONE:
52262306a36Sopenharmony_ci	default:
52362306a36Sopenharmony_ci		return -1;
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci	return 0;
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci/*
52962306a36Sopenharmony_ci * Create a child for a parent. If inherit_children, then the new child
53062306a36Sopenharmony_ci * will become the new parent of it's parent children
53162306a36Sopenharmony_ci */
53262306a36Sopenharmony_cistatic struct callchain_node *
53362306a36Sopenharmony_cicreate_child(struct callchain_node *parent, bool inherit_children)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	struct callchain_node *new;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	new = zalloc(sizeof(*new));
53862306a36Sopenharmony_ci	if (!new) {
53962306a36Sopenharmony_ci		perror("not enough memory to create child for code path tree");
54062306a36Sopenharmony_ci		return NULL;
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci	new->parent = parent;
54362306a36Sopenharmony_ci	INIT_LIST_HEAD(&new->val);
54462306a36Sopenharmony_ci	INIT_LIST_HEAD(&new->parent_val);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	if (inherit_children) {
54762306a36Sopenharmony_ci		struct rb_node *n;
54862306a36Sopenharmony_ci		struct callchain_node *child;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		new->rb_root_in = parent->rb_root_in;
55162306a36Sopenharmony_ci		parent->rb_root_in = RB_ROOT;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci		n = rb_first(&new->rb_root_in);
55462306a36Sopenharmony_ci		while (n) {
55562306a36Sopenharmony_ci			child = rb_entry(n, struct callchain_node, rb_node_in);
55662306a36Sopenharmony_ci			child->parent = new;
55762306a36Sopenharmony_ci			n = rb_next(n);
55862306a36Sopenharmony_ci		}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci		/* make it the first child */
56162306a36Sopenharmony_ci		rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
56262306a36Sopenharmony_ci		rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	return new;
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci/*
57062306a36Sopenharmony_ci * Fill the node with callchain values
57162306a36Sopenharmony_ci */
57262306a36Sopenharmony_cistatic int
57362306a36Sopenharmony_cifill_node(struct callchain_node *node, struct callchain_cursor *cursor)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	struct callchain_cursor_node *cursor_node;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	node->val_nr = cursor->nr - cursor->pos;
57862306a36Sopenharmony_ci	if (!node->val_nr)
57962306a36Sopenharmony_ci		pr_warning("Warning: empty node in callchain tree\n");
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	cursor_node = callchain_cursor_current(cursor);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	while (cursor_node) {
58462306a36Sopenharmony_ci		struct callchain_list *call;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci		call = zalloc(sizeof(*call));
58762306a36Sopenharmony_ci		if (!call) {
58862306a36Sopenharmony_ci			perror("not enough memory for the code path tree");
58962306a36Sopenharmony_ci			return -1;
59062306a36Sopenharmony_ci		}
59162306a36Sopenharmony_ci		call->ip = cursor_node->ip;
59262306a36Sopenharmony_ci		call->ms = cursor_node->ms;
59362306a36Sopenharmony_ci		call->ms.map = map__get(call->ms.map);
59462306a36Sopenharmony_ci		call->ms.maps = maps__get(call->ms.maps);
59562306a36Sopenharmony_ci		call->srcline = cursor_node->srcline;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		if (cursor_node->branch) {
59862306a36Sopenharmony_ci			call->branch_count = 1;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci			if (cursor_node->branch_from) {
60162306a36Sopenharmony_ci				/*
60262306a36Sopenharmony_ci				 * branch_from is set with value somewhere else
60362306a36Sopenharmony_ci				 * to imply it's "to" of a branch.
60462306a36Sopenharmony_ci				 */
60562306a36Sopenharmony_ci				call->brtype_stat.branch_to = true;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci				if (cursor_node->branch_flags.predicted)
60862306a36Sopenharmony_ci					call->predicted_count = 1;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci				if (cursor_node->branch_flags.abort)
61162306a36Sopenharmony_ci					call->abort_count = 1;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci				branch_type_count(&call->brtype_stat,
61462306a36Sopenharmony_ci						  &cursor_node->branch_flags,
61562306a36Sopenharmony_ci						  cursor_node->branch_from,
61662306a36Sopenharmony_ci						  cursor_node->ip);
61762306a36Sopenharmony_ci			} else {
61862306a36Sopenharmony_ci				/*
61962306a36Sopenharmony_ci				 * It's "from" of a branch
62062306a36Sopenharmony_ci				 */
62162306a36Sopenharmony_ci				call->brtype_stat.branch_to = false;
62262306a36Sopenharmony_ci				call->cycles_count =
62362306a36Sopenharmony_ci					cursor_node->branch_flags.cycles;
62462306a36Sopenharmony_ci				call->iter_count = cursor_node->nr_loop_iter;
62562306a36Sopenharmony_ci				call->iter_cycles = cursor_node->iter_cycles;
62662306a36Sopenharmony_ci			}
62762306a36Sopenharmony_ci		}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci		list_add_tail(&call->list, &node->val);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci		callchain_cursor_advance(cursor);
63262306a36Sopenharmony_ci		cursor_node = callchain_cursor_current(cursor);
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci	return 0;
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic struct callchain_node *
63862306a36Sopenharmony_ciadd_child(struct callchain_node *parent,
63962306a36Sopenharmony_ci	  struct callchain_cursor *cursor,
64062306a36Sopenharmony_ci	  u64 period)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	struct callchain_node *new;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	new = create_child(parent, false);
64562306a36Sopenharmony_ci	if (new == NULL)
64662306a36Sopenharmony_ci		return NULL;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	if (fill_node(new, cursor) < 0) {
64962306a36Sopenharmony_ci		struct callchain_list *call, *tmp;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		list_for_each_entry_safe(call, tmp, &new->val, list) {
65262306a36Sopenharmony_ci			list_del_init(&call->list);
65362306a36Sopenharmony_ci			map__zput(call->ms.map);
65462306a36Sopenharmony_ci			maps__zput(call->ms.maps);
65562306a36Sopenharmony_ci			free(call);
65662306a36Sopenharmony_ci		}
65762306a36Sopenharmony_ci		free(new);
65862306a36Sopenharmony_ci		return NULL;
65962306a36Sopenharmony_ci	}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	new->children_hit = 0;
66262306a36Sopenharmony_ci	new->hit = period;
66362306a36Sopenharmony_ci	new->children_count = 0;
66462306a36Sopenharmony_ci	new->count = 1;
66562306a36Sopenharmony_ci	return new;
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cienum match_result {
66962306a36Sopenharmony_ci	MATCH_ERROR  = -1,
67062306a36Sopenharmony_ci	MATCH_EQ,
67162306a36Sopenharmony_ci	MATCH_LT,
67262306a36Sopenharmony_ci	MATCH_GT,
67362306a36Sopenharmony_ci};
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cistatic enum match_result match_chain_strings(const char *left,
67662306a36Sopenharmony_ci					     const char *right)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	enum match_result ret = MATCH_EQ;
67962306a36Sopenharmony_ci	int cmp;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (left && right)
68262306a36Sopenharmony_ci		cmp = strcmp(left, right);
68362306a36Sopenharmony_ci	else if (!left && right)
68462306a36Sopenharmony_ci		cmp = 1;
68562306a36Sopenharmony_ci	else if (left && !right)
68662306a36Sopenharmony_ci		cmp = -1;
68762306a36Sopenharmony_ci	else
68862306a36Sopenharmony_ci		return MATCH_ERROR;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	if (cmp != 0)
69162306a36Sopenharmony_ci		ret = cmp < 0 ? MATCH_LT : MATCH_GT;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	return ret;
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci/*
69762306a36Sopenharmony_ci * We need to always use relative addresses because we're aggregating
69862306a36Sopenharmony_ci * callchains from multiple threads, i.e. different address spaces, so
69962306a36Sopenharmony_ci * comparing absolute addresses make no sense as a symbol in a DSO may end up
70062306a36Sopenharmony_ci * in a different address when used in a different binary or even the same
70162306a36Sopenharmony_ci * binary but with some sort of address randomization technique, thus we need
70262306a36Sopenharmony_ci * to compare just relative addresses. -acme
70362306a36Sopenharmony_ci */
70462306a36Sopenharmony_cistatic enum match_result match_chain_dso_addresses(struct map *left_map, u64 left_ip,
70562306a36Sopenharmony_ci						   struct map *right_map, u64 right_ip)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	struct dso *left_dso = left_map ? map__dso(left_map) : NULL;
70862306a36Sopenharmony_ci	struct dso *right_dso = right_map ? map__dso(right_map) : NULL;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	if (left_dso != right_dso)
71162306a36Sopenharmony_ci		return left_dso < right_dso ? MATCH_LT : MATCH_GT;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	if (left_ip != right_ip)
71462306a36Sopenharmony_ci 		return left_ip < right_ip ? MATCH_LT : MATCH_GT;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	return MATCH_EQ;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cistatic enum match_result match_chain(struct callchain_cursor_node *node,
72062306a36Sopenharmony_ci				     struct callchain_list *cnode)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	enum match_result match = MATCH_ERROR;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	switch (callchain_param.key) {
72562306a36Sopenharmony_ci	case CCKEY_SRCLINE:
72662306a36Sopenharmony_ci		match = match_chain_strings(cnode->srcline, node->srcline);
72762306a36Sopenharmony_ci		if (match != MATCH_ERROR)
72862306a36Sopenharmony_ci			break;
72962306a36Sopenharmony_ci		/* otherwise fall-back to symbol-based comparison below */
73062306a36Sopenharmony_ci		fallthrough;
73162306a36Sopenharmony_ci	case CCKEY_FUNCTION:
73262306a36Sopenharmony_ci		if (node->ms.sym && cnode->ms.sym) {
73362306a36Sopenharmony_ci			/*
73462306a36Sopenharmony_ci			 * Compare inlined frames based on their symbol name
73562306a36Sopenharmony_ci			 * because different inlined frames will have the same
73662306a36Sopenharmony_ci			 * symbol start. Otherwise do a faster comparison based
73762306a36Sopenharmony_ci			 * on the symbol start address.
73862306a36Sopenharmony_ci			 */
73962306a36Sopenharmony_ci			if (cnode->ms.sym->inlined || node->ms.sym->inlined) {
74062306a36Sopenharmony_ci				match = match_chain_strings(cnode->ms.sym->name,
74162306a36Sopenharmony_ci							    node->ms.sym->name);
74262306a36Sopenharmony_ci				if (match != MATCH_ERROR)
74362306a36Sopenharmony_ci					break;
74462306a36Sopenharmony_ci			} else {
74562306a36Sopenharmony_ci				match = match_chain_dso_addresses(cnode->ms.map, cnode->ms.sym->start,
74662306a36Sopenharmony_ci								  node->ms.map, node->ms.sym->start);
74762306a36Sopenharmony_ci				break;
74862306a36Sopenharmony_ci			}
74962306a36Sopenharmony_ci		}
75062306a36Sopenharmony_ci		/* otherwise fall-back to IP-based comparison below */
75162306a36Sopenharmony_ci		fallthrough;
75262306a36Sopenharmony_ci	case CCKEY_ADDRESS:
75362306a36Sopenharmony_ci	default:
75462306a36Sopenharmony_ci		match = match_chain_dso_addresses(cnode->ms.map, cnode->ip, node->ms.map, node->ip);
75562306a36Sopenharmony_ci		break;
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	if (match == MATCH_EQ && node->branch) {
75962306a36Sopenharmony_ci		cnode->branch_count++;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci		if (node->branch_from) {
76262306a36Sopenharmony_ci			/*
76362306a36Sopenharmony_ci			 * It's "to" of a branch
76462306a36Sopenharmony_ci			 */
76562306a36Sopenharmony_ci			cnode->brtype_stat.branch_to = true;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci			if (node->branch_flags.predicted)
76862306a36Sopenharmony_ci				cnode->predicted_count++;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci			if (node->branch_flags.abort)
77162306a36Sopenharmony_ci				cnode->abort_count++;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci			branch_type_count(&cnode->brtype_stat,
77462306a36Sopenharmony_ci					  &node->branch_flags,
77562306a36Sopenharmony_ci					  node->branch_from,
77662306a36Sopenharmony_ci					  node->ip);
77762306a36Sopenharmony_ci		} else {
77862306a36Sopenharmony_ci			/*
77962306a36Sopenharmony_ci			 * It's "from" of a branch
78062306a36Sopenharmony_ci			 */
78162306a36Sopenharmony_ci			cnode->brtype_stat.branch_to = false;
78262306a36Sopenharmony_ci			cnode->cycles_count += node->branch_flags.cycles;
78362306a36Sopenharmony_ci			cnode->iter_count += node->nr_loop_iter;
78462306a36Sopenharmony_ci			cnode->iter_cycles += node->iter_cycles;
78562306a36Sopenharmony_ci			cnode->from_count++;
78662306a36Sopenharmony_ci		}
78762306a36Sopenharmony_ci	}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	return match;
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci/*
79362306a36Sopenharmony_ci * Split the parent in two parts (a new child is created) and
79462306a36Sopenharmony_ci * give a part of its callchain to the created child.
79562306a36Sopenharmony_ci * Then create another child to host the given callchain of new branch
79662306a36Sopenharmony_ci */
79762306a36Sopenharmony_cistatic int
79862306a36Sopenharmony_cisplit_add_child(struct callchain_node *parent,
79962306a36Sopenharmony_ci		struct callchain_cursor *cursor,
80062306a36Sopenharmony_ci		struct callchain_list *to_split,
80162306a36Sopenharmony_ci		u64 idx_parents, u64 idx_local, u64 period)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct callchain_node *new;
80462306a36Sopenharmony_ci	struct list_head *old_tail;
80562306a36Sopenharmony_ci	unsigned int idx_total = idx_parents + idx_local;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	/* split */
80862306a36Sopenharmony_ci	new = create_child(parent, true);
80962306a36Sopenharmony_ci	if (new == NULL)
81062306a36Sopenharmony_ci		return -1;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	/* split the callchain and move a part to the new child */
81362306a36Sopenharmony_ci	old_tail = parent->val.prev;
81462306a36Sopenharmony_ci	list_del_range(&to_split->list, old_tail);
81562306a36Sopenharmony_ci	new->val.next = &to_split->list;
81662306a36Sopenharmony_ci	new->val.prev = old_tail;
81762306a36Sopenharmony_ci	to_split->list.prev = &new->val;
81862306a36Sopenharmony_ci	old_tail->next = &new->val;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	/* split the hits */
82162306a36Sopenharmony_ci	new->hit = parent->hit;
82262306a36Sopenharmony_ci	new->children_hit = parent->children_hit;
82362306a36Sopenharmony_ci	parent->children_hit = callchain_cumul_hits(new);
82462306a36Sopenharmony_ci	new->val_nr = parent->val_nr - idx_local;
82562306a36Sopenharmony_ci	parent->val_nr = idx_local;
82662306a36Sopenharmony_ci	new->count = parent->count;
82762306a36Sopenharmony_ci	new->children_count = parent->children_count;
82862306a36Sopenharmony_ci	parent->children_count = callchain_cumul_counts(new);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	/* create a new child for the new branch if any */
83162306a36Sopenharmony_ci	if (idx_total < cursor->nr) {
83262306a36Sopenharmony_ci		struct callchain_node *first;
83362306a36Sopenharmony_ci		struct callchain_list *cnode;
83462306a36Sopenharmony_ci		struct callchain_cursor_node *node;
83562306a36Sopenharmony_ci		struct rb_node *p, **pp;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci		parent->hit = 0;
83862306a36Sopenharmony_ci		parent->children_hit += period;
83962306a36Sopenharmony_ci		parent->count = 0;
84062306a36Sopenharmony_ci		parent->children_count += 1;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci		node = callchain_cursor_current(cursor);
84362306a36Sopenharmony_ci		new = add_child(parent, cursor, period);
84462306a36Sopenharmony_ci		if (new == NULL)
84562306a36Sopenharmony_ci			return -1;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci		/*
84862306a36Sopenharmony_ci		 * This is second child since we moved parent's children
84962306a36Sopenharmony_ci		 * to new (first) child above.
85062306a36Sopenharmony_ci		 */
85162306a36Sopenharmony_ci		p = parent->rb_root_in.rb_node;
85262306a36Sopenharmony_ci		first = rb_entry(p, struct callchain_node, rb_node_in);
85362306a36Sopenharmony_ci		cnode = list_first_entry(&first->val, struct callchain_list,
85462306a36Sopenharmony_ci					 list);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci		if (match_chain(node, cnode) == MATCH_LT)
85762306a36Sopenharmony_ci			pp = &p->rb_left;
85862306a36Sopenharmony_ci		else
85962306a36Sopenharmony_ci			pp = &p->rb_right;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci		rb_link_node(&new->rb_node_in, p, pp);
86262306a36Sopenharmony_ci		rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
86362306a36Sopenharmony_ci	} else {
86462306a36Sopenharmony_ci		parent->hit = period;
86562306a36Sopenharmony_ci		parent->count = 1;
86662306a36Sopenharmony_ci	}
86762306a36Sopenharmony_ci	return 0;
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_cistatic enum match_result
87162306a36Sopenharmony_ciappend_chain(struct callchain_node *root,
87262306a36Sopenharmony_ci	     struct callchain_cursor *cursor,
87362306a36Sopenharmony_ci	     u64 period);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_cistatic int
87662306a36Sopenharmony_ciappend_chain_children(struct callchain_node *root,
87762306a36Sopenharmony_ci		      struct callchain_cursor *cursor,
87862306a36Sopenharmony_ci		      u64 period)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	struct callchain_node *rnode;
88162306a36Sopenharmony_ci	struct callchain_cursor_node *node;
88262306a36Sopenharmony_ci	struct rb_node **p = &root->rb_root_in.rb_node;
88362306a36Sopenharmony_ci	struct rb_node *parent = NULL;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	node = callchain_cursor_current(cursor);
88662306a36Sopenharmony_ci	if (!node)
88762306a36Sopenharmony_ci		return -1;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	/* lookup in children */
89062306a36Sopenharmony_ci	while (*p) {
89162306a36Sopenharmony_ci		enum match_result ret;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci		parent = *p;
89462306a36Sopenharmony_ci		rnode = rb_entry(parent, struct callchain_node, rb_node_in);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		/* If at least first entry matches, rely to children */
89762306a36Sopenharmony_ci		ret = append_chain(rnode, cursor, period);
89862306a36Sopenharmony_ci		if (ret == MATCH_EQ)
89962306a36Sopenharmony_ci			goto inc_children_hit;
90062306a36Sopenharmony_ci		if (ret == MATCH_ERROR)
90162306a36Sopenharmony_ci			return -1;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci		if (ret == MATCH_LT)
90462306a36Sopenharmony_ci			p = &parent->rb_left;
90562306a36Sopenharmony_ci		else
90662306a36Sopenharmony_ci			p = &parent->rb_right;
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci	/* nothing in children, add to the current node */
90962306a36Sopenharmony_ci	rnode = add_child(root, cursor, period);
91062306a36Sopenharmony_ci	if (rnode == NULL)
91162306a36Sopenharmony_ci		return -1;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	rb_link_node(&rnode->rb_node_in, parent, p);
91462306a36Sopenharmony_ci	rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ciinc_children_hit:
91762306a36Sopenharmony_ci	root->children_hit += period;
91862306a36Sopenharmony_ci	root->children_count++;
91962306a36Sopenharmony_ci	return 0;
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic enum match_result
92362306a36Sopenharmony_ciappend_chain(struct callchain_node *root,
92462306a36Sopenharmony_ci	     struct callchain_cursor *cursor,
92562306a36Sopenharmony_ci	     u64 period)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	struct callchain_list *cnode;
92862306a36Sopenharmony_ci	u64 start = cursor->pos;
92962306a36Sopenharmony_ci	bool found = false;
93062306a36Sopenharmony_ci	u64 matches;
93162306a36Sopenharmony_ci	enum match_result cmp = MATCH_ERROR;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	/*
93462306a36Sopenharmony_ci	 * Lookup in the current node
93562306a36Sopenharmony_ci	 * If we have a symbol, then compare the start to match
93662306a36Sopenharmony_ci	 * anywhere inside a function, unless function
93762306a36Sopenharmony_ci	 * mode is disabled.
93862306a36Sopenharmony_ci	 */
93962306a36Sopenharmony_ci	list_for_each_entry(cnode, &root->val, list) {
94062306a36Sopenharmony_ci		struct callchain_cursor_node *node;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci		node = callchain_cursor_current(cursor);
94362306a36Sopenharmony_ci		if (!node)
94462306a36Sopenharmony_ci			break;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci		cmp = match_chain(node, cnode);
94762306a36Sopenharmony_ci		if (cmp != MATCH_EQ)
94862306a36Sopenharmony_ci			break;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		found = true;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci		callchain_cursor_advance(cursor);
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	/* matches not, relay no the parent */
95662306a36Sopenharmony_ci	if (!found) {
95762306a36Sopenharmony_ci		WARN_ONCE(cmp == MATCH_ERROR, "Chain comparison error\n");
95862306a36Sopenharmony_ci		return cmp;
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	matches = cursor->pos - start;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	/* we match only a part of the node. Split it and add the new chain */
96462306a36Sopenharmony_ci	if (matches < root->val_nr) {
96562306a36Sopenharmony_ci		if (split_add_child(root, cursor, cnode, start, matches,
96662306a36Sopenharmony_ci				    period) < 0)
96762306a36Sopenharmony_ci			return MATCH_ERROR;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci		return MATCH_EQ;
97062306a36Sopenharmony_ci	}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	/* we match 100% of the path, increment the hit */
97362306a36Sopenharmony_ci	if (matches == root->val_nr && cursor->pos == cursor->nr) {
97462306a36Sopenharmony_ci		root->hit += period;
97562306a36Sopenharmony_ci		root->count++;
97662306a36Sopenharmony_ci		return MATCH_EQ;
97762306a36Sopenharmony_ci	}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	/* We match the node and still have a part remaining */
98062306a36Sopenharmony_ci	if (append_chain_children(root, cursor, period) < 0)
98162306a36Sopenharmony_ci		return MATCH_ERROR;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	return MATCH_EQ;
98462306a36Sopenharmony_ci}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ciint callchain_append(struct callchain_root *root,
98762306a36Sopenharmony_ci		     struct callchain_cursor *cursor,
98862306a36Sopenharmony_ci		     u64 period)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	if (cursor == NULL)
99162306a36Sopenharmony_ci		return -1;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	if (!cursor->nr)
99462306a36Sopenharmony_ci		return 0;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	callchain_cursor_commit(cursor);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	if (append_chain_children(&root->node, cursor, period) < 0)
99962306a36Sopenharmony_ci		return -1;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	if (cursor->nr > root->max_depth)
100262306a36Sopenharmony_ci		root->max_depth = cursor->nr;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	return 0;
100562306a36Sopenharmony_ci}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_cistatic int
100862306a36Sopenharmony_cimerge_chain_branch(struct callchain_cursor *cursor,
100962306a36Sopenharmony_ci		   struct callchain_node *dst, struct callchain_node *src)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	struct callchain_cursor_node **old_last = cursor->last;
101262306a36Sopenharmony_ci	struct callchain_node *child;
101362306a36Sopenharmony_ci	struct callchain_list *list, *next_list;
101462306a36Sopenharmony_ci	struct rb_node *n;
101562306a36Sopenharmony_ci	int old_pos = cursor->nr;
101662306a36Sopenharmony_ci	int err = 0;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	list_for_each_entry_safe(list, next_list, &src->val, list) {
101962306a36Sopenharmony_ci		struct map_symbol ms = {
102062306a36Sopenharmony_ci			.maps = maps__get(list->ms.maps),
102162306a36Sopenharmony_ci			.map = map__get(list->ms.map),
102262306a36Sopenharmony_ci		};
102362306a36Sopenharmony_ci		callchain_cursor_append(cursor, list->ip, &ms, false, NULL, 0, 0, 0, list->srcline);
102462306a36Sopenharmony_ci		list_del_init(&list->list);
102562306a36Sopenharmony_ci		map__zput(ms.map);
102662306a36Sopenharmony_ci		maps__zput(ms.maps);
102762306a36Sopenharmony_ci		map__zput(list->ms.map);
102862306a36Sopenharmony_ci		maps__zput(list->ms.maps);
102962306a36Sopenharmony_ci		free(list);
103062306a36Sopenharmony_ci	}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	if (src->hit) {
103362306a36Sopenharmony_ci		callchain_cursor_commit(cursor);
103462306a36Sopenharmony_ci		if (append_chain_children(dst, cursor, src->hit) < 0)
103562306a36Sopenharmony_ci			return -1;
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	n = rb_first(&src->rb_root_in);
103962306a36Sopenharmony_ci	while (n) {
104062306a36Sopenharmony_ci		child = container_of(n, struct callchain_node, rb_node_in);
104162306a36Sopenharmony_ci		n = rb_next(n);
104262306a36Sopenharmony_ci		rb_erase(&child->rb_node_in, &src->rb_root_in);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci		err = merge_chain_branch(cursor, dst, child);
104562306a36Sopenharmony_ci		if (err)
104662306a36Sopenharmony_ci			break;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci		free(child);
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	cursor->nr = old_pos;
105262306a36Sopenharmony_ci	cursor->last = old_last;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	return err;
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ciint callchain_merge(struct callchain_cursor *cursor,
105862306a36Sopenharmony_ci		    struct callchain_root *dst, struct callchain_root *src)
105962306a36Sopenharmony_ci{
106062306a36Sopenharmony_ci	return merge_chain_branch(cursor, &dst->node, &src->node);
106162306a36Sopenharmony_ci}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ciint callchain_cursor_append(struct callchain_cursor *cursor,
106462306a36Sopenharmony_ci			    u64 ip, struct map_symbol *ms,
106562306a36Sopenharmony_ci			    bool branch, struct branch_flags *flags,
106662306a36Sopenharmony_ci			    int nr_loop_iter, u64 iter_cycles, u64 branch_from,
106762306a36Sopenharmony_ci			    const char *srcline)
106862306a36Sopenharmony_ci{
106962306a36Sopenharmony_ci	struct callchain_cursor_node *node = *cursor->last;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	if (!node) {
107262306a36Sopenharmony_ci		node = calloc(1, sizeof(*node));
107362306a36Sopenharmony_ci		if (!node)
107462306a36Sopenharmony_ci			return -ENOMEM;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci		*cursor->last = node;
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	node->ip = ip;
108062306a36Sopenharmony_ci	maps__zput(node->ms.maps);
108162306a36Sopenharmony_ci	map__zput(node->ms.map);
108262306a36Sopenharmony_ci	node->ms = *ms;
108362306a36Sopenharmony_ci	node->ms.maps = maps__get(ms->maps);
108462306a36Sopenharmony_ci	node->ms.map = map__get(ms->map);
108562306a36Sopenharmony_ci	node->branch = branch;
108662306a36Sopenharmony_ci	node->nr_loop_iter = nr_loop_iter;
108762306a36Sopenharmony_ci	node->iter_cycles = iter_cycles;
108862306a36Sopenharmony_ci	node->srcline = srcline;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	if (flags)
109162306a36Sopenharmony_ci		memcpy(&node->branch_flags, flags,
109262306a36Sopenharmony_ci			sizeof(struct branch_flags));
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	node->branch_from = branch_from;
109562306a36Sopenharmony_ci	cursor->nr++;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	cursor->last = &node->next;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	return 0;
110062306a36Sopenharmony_ci}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ciint sample__resolve_callchain(struct perf_sample *sample,
110362306a36Sopenharmony_ci			      struct callchain_cursor *cursor, struct symbol **parent,
110462306a36Sopenharmony_ci			      struct evsel *evsel, struct addr_location *al,
110562306a36Sopenharmony_ci			      int max_stack)
110662306a36Sopenharmony_ci{
110762306a36Sopenharmony_ci	if (sample->callchain == NULL && !symbol_conf.show_branchflag_count)
110862306a36Sopenharmony_ci		return 0;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
111162306a36Sopenharmony_ci	    perf_hpp_list.parent || symbol_conf.show_branchflag_count) {
111262306a36Sopenharmony_ci		return thread__resolve_callchain(al->thread, cursor, evsel, sample,
111362306a36Sopenharmony_ci						 parent, al, max_stack);
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci	return 0;
111662306a36Sopenharmony_ci}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ciint hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
111962306a36Sopenharmony_ci{
112062306a36Sopenharmony_ci	if ((!symbol_conf.use_callchain || sample->callchain == NULL) &&
112162306a36Sopenharmony_ci		!symbol_conf.show_branchflag_count)
112262306a36Sopenharmony_ci		return 0;
112362306a36Sopenharmony_ci	return callchain_append(he->callchain, get_tls_callchain_cursor(), sample->period);
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ciint fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
112762306a36Sopenharmony_ci			bool hide_unresolved)
112862306a36Sopenharmony_ci{
112962306a36Sopenharmony_ci	struct machine *machine = maps__machine(node->ms.maps);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	maps__put(al->maps);
113262306a36Sopenharmony_ci	al->maps = maps__get(node->ms.maps);
113362306a36Sopenharmony_ci	map__put(al->map);
113462306a36Sopenharmony_ci	al->map = map__get(node->ms.map);
113562306a36Sopenharmony_ci	al->sym = node->ms.sym;
113662306a36Sopenharmony_ci	al->srcline = node->srcline;
113762306a36Sopenharmony_ci	al->addr = node->ip;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	if (al->sym == NULL) {
114062306a36Sopenharmony_ci		if (hide_unresolved)
114162306a36Sopenharmony_ci			return 0;
114262306a36Sopenharmony_ci		if (al->map == NULL)
114362306a36Sopenharmony_ci			goto out;
114462306a36Sopenharmony_ci	}
114562306a36Sopenharmony_ci	if (RC_CHK_ACCESS(al->maps) == RC_CHK_ACCESS(machine__kernel_maps(machine))) {
114662306a36Sopenharmony_ci		if (machine__is_host(machine)) {
114762306a36Sopenharmony_ci			al->cpumode = PERF_RECORD_MISC_KERNEL;
114862306a36Sopenharmony_ci			al->level = 'k';
114962306a36Sopenharmony_ci		} else {
115062306a36Sopenharmony_ci			al->cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
115162306a36Sopenharmony_ci			al->level = 'g';
115262306a36Sopenharmony_ci		}
115362306a36Sopenharmony_ci	} else {
115462306a36Sopenharmony_ci		if (machine__is_host(machine)) {
115562306a36Sopenharmony_ci			al->cpumode = PERF_RECORD_MISC_USER;
115662306a36Sopenharmony_ci			al->level = '.';
115762306a36Sopenharmony_ci		} else if (perf_guest) {
115862306a36Sopenharmony_ci			al->cpumode = PERF_RECORD_MISC_GUEST_USER;
115962306a36Sopenharmony_ci			al->level = 'u';
116062306a36Sopenharmony_ci		} else {
116162306a36Sopenharmony_ci			al->cpumode = PERF_RECORD_MISC_HYPERVISOR;
116262306a36Sopenharmony_ci			al->level = 'H';
116362306a36Sopenharmony_ci		}
116462306a36Sopenharmony_ci	}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ciout:
116762306a36Sopenharmony_ci	return 1;
116862306a36Sopenharmony_ci}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_cichar *callchain_list__sym_name(struct callchain_list *cl,
117162306a36Sopenharmony_ci			       char *bf, size_t bfsize, bool show_dso)
117262306a36Sopenharmony_ci{
117362306a36Sopenharmony_ci	bool show_addr = callchain_param.key == CCKEY_ADDRESS;
117462306a36Sopenharmony_ci	bool show_srcline = show_addr || callchain_param.key == CCKEY_SRCLINE;
117562306a36Sopenharmony_ci	int printed;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	if (cl->ms.sym) {
117862306a36Sopenharmony_ci		const char *inlined = cl->ms.sym->inlined ? " (inlined)" : "";
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci		if (show_srcline && cl->srcline)
118162306a36Sopenharmony_ci			printed = scnprintf(bf, bfsize, "%s %s%s",
118262306a36Sopenharmony_ci					    cl->ms.sym->name, cl->srcline,
118362306a36Sopenharmony_ci					    inlined);
118462306a36Sopenharmony_ci		else
118562306a36Sopenharmony_ci			printed = scnprintf(bf, bfsize, "%s%s",
118662306a36Sopenharmony_ci					    cl->ms.sym->name, inlined);
118762306a36Sopenharmony_ci	} else
118862306a36Sopenharmony_ci		printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	if (show_dso)
119162306a36Sopenharmony_ci		scnprintf(bf + printed, bfsize - printed, " %s",
119262306a36Sopenharmony_ci			  cl->ms.map ?
119362306a36Sopenharmony_ci			  map__dso(cl->ms.map)->short_name :
119462306a36Sopenharmony_ci			  "unknown");
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	return bf;
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cichar *callchain_node__scnprintf_value(struct callchain_node *node,
120062306a36Sopenharmony_ci				      char *bf, size_t bfsize, u64 total)
120162306a36Sopenharmony_ci{
120262306a36Sopenharmony_ci	double percent = 0.0;
120362306a36Sopenharmony_ci	u64 period = callchain_cumul_hits(node);
120462306a36Sopenharmony_ci	unsigned count = callchain_cumul_counts(node);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	if (callchain_param.mode == CHAIN_FOLDED) {
120762306a36Sopenharmony_ci		period = node->hit;
120862306a36Sopenharmony_ci		count = node->count;
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	switch (callchain_param.value) {
121262306a36Sopenharmony_ci	case CCVAL_PERIOD:
121362306a36Sopenharmony_ci		scnprintf(bf, bfsize, "%"PRIu64, period);
121462306a36Sopenharmony_ci		break;
121562306a36Sopenharmony_ci	case CCVAL_COUNT:
121662306a36Sopenharmony_ci		scnprintf(bf, bfsize, "%u", count);
121762306a36Sopenharmony_ci		break;
121862306a36Sopenharmony_ci	case CCVAL_PERCENT:
121962306a36Sopenharmony_ci	default:
122062306a36Sopenharmony_ci		if (total)
122162306a36Sopenharmony_ci			percent = period * 100.0 / total;
122262306a36Sopenharmony_ci		scnprintf(bf, bfsize, "%.2f%%", percent);
122362306a36Sopenharmony_ci		break;
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci	return bf;
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ciint callchain_node__fprintf_value(struct callchain_node *node,
122962306a36Sopenharmony_ci				 FILE *fp, u64 total)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	double percent = 0.0;
123262306a36Sopenharmony_ci	u64 period = callchain_cumul_hits(node);
123362306a36Sopenharmony_ci	unsigned count = callchain_cumul_counts(node);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	if (callchain_param.mode == CHAIN_FOLDED) {
123662306a36Sopenharmony_ci		period = node->hit;
123762306a36Sopenharmony_ci		count = node->count;
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	switch (callchain_param.value) {
124162306a36Sopenharmony_ci	case CCVAL_PERIOD:
124262306a36Sopenharmony_ci		return fprintf(fp, "%"PRIu64, period);
124362306a36Sopenharmony_ci	case CCVAL_COUNT:
124462306a36Sopenharmony_ci		return fprintf(fp, "%u", count);
124562306a36Sopenharmony_ci	case CCVAL_PERCENT:
124662306a36Sopenharmony_ci	default:
124762306a36Sopenharmony_ci		if (total)
124862306a36Sopenharmony_ci			percent = period * 100.0 / total;
124962306a36Sopenharmony_ci		return percent_color_fprintf(fp, "%.2f%%", percent);
125062306a36Sopenharmony_ci	}
125162306a36Sopenharmony_ci	return 0;
125262306a36Sopenharmony_ci}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_cistatic void callchain_counts_value(struct callchain_node *node,
125562306a36Sopenharmony_ci				   u64 *branch_count, u64 *predicted_count,
125662306a36Sopenharmony_ci				   u64 *abort_count, u64 *cycles_count)
125762306a36Sopenharmony_ci{
125862306a36Sopenharmony_ci	struct callchain_list *clist;
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	list_for_each_entry(clist, &node->val, list) {
126162306a36Sopenharmony_ci		if (branch_count)
126262306a36Sopenharmony_ci			*branch_count += clist->branch_count;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci		if (predicted_count)
126562306a36Sopenharmony_ci			*predicted_count += clist->predicted_count;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci		if (abort_count)
126862306a36Sopenharmony_ci			*abort_count += clist->abort_count;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci		if (cycles_count)
127162306a36Sopenharmony_ci			*cycles_count += clist->cycles_count;
127262306a36Sopenharmony_ci	}
127362306a36Sopenharmony_ci}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_cistatic int callchain_node_branch_counts_cumul(struct callchain_node *node,
127662306a36Sopenharmony_ci					      u64 *branch_count,
127762306a36Sopenharmony_ci					      u64 *predicted_count,
127862306a36Sopenharmony_ci					      u64 *abort_count,
127962306a36Sopenharmony_ci					      u64 *cycles_count)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	struct callchain_node *child;
128262306a36Sopenharmony_ci	struct rb_node *n;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	n = rb_first(&node->rb_root_in);
128562306a36Sopenharmony_ci	while (n) {
128662306a36Sopenharmony_ci		child = rb_entry(n, struct callchain_node, rb_node_in);
128762306a36Sopenharmony_ci		n = rb_next(n);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci		callchain_node_branch_counts_cumul(child, branch_count,
129062306a36Sopenharmony_ci						   predicted_count,
129162306a36Sopenharmony_ci						   abort_count,
129262306a36Sopenharmony_ci						   cycles_count);
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci		callchain_counts_value(child, branch_count,
129562306a36Sopenharmony_ci				       predicted_count, abort_count,
129662306a36Sopenharmony_ci				       cycles_count);
129762306a36Sopenharmony_ci	}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	return 0;
130062306a36Sopenharmony_ci}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ciint callchain_branch_counts(struct callchain_root *root,
130362306a36Sopenharmony_ci			    u64 *branch_count, u64 *predicted_count,
130462306a36Sopenharmony_ci			    u64 *abort_count, u64 *cycles_count)
130562306a36Sopenharmony_ci{
130662306a36Sopenharmony_ci	if (branch_count)
130762306a36Sopenharmony_ci		*branch_count = 0;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	if (predicted_count)
131062306a36Sopenharmony_ci		*predicted_count = 0;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	if (abort_count)
131362306a36Sopenharmony_ci		*abort_count = 0;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	if (cycles_count)
131662306a36Sopenharmony_ci		*cycles_count = 0;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	return callchain_node_branch_counts_cumul(&root->node,
131962306a36Sopenharmony_ci						  branch_count,
132062306a36Sopenharmony_ci						  predicted_count,
132162306a36Sopenharmony_ci						  abort_count,
132262306a36Sopenharmony_ci						  cycles_count);
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_cistatic int count_pri64_printf(int idx, const char *str, u64 value, char *bf, int bfsize)
132662306a36Sopenharmony_ci{
132762306a36Sopenharmony_ci	return scnprintf(bf, bfsize, "%s%s:%" PRId64 "", (idx) ? " " : " (", str, value);
132862306a36Sopenharmony_ci}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_cistatic int count_float_printf(int idx, const char *str, float value,
133162306a36Sopenharmony_ci			      char *bf, int bfsize, float threshold)
133262306a36Sopenharmony_ci{
133362306a36Sopenharmony_ci	if (threshold != 0.0 && value < threshold)
133462306a36Sopenharmony_ci		return 0;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	return scnprintf(bf, bfsize, "%s%s:%.1f%%", (idx) ? " " : " (", str, value);
133762306a36Sopenharmony_ci}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_cistatic int branch_to_str(char *bf, int bfsize,
134062306a36Sopenharmony_ci			 u64 branch_count, u64 predicted_count,
134162306a36Sopenharmony_ci			 u64 abort_count,
134262306a36Sopenharmony_ci			 struct branch_type_stat *brtype_stat)
134362306a36Sopenharmony_ci{
134462306a36Sopenharmony_ci	int printed, i = 0;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	printed = branch_type_str(brtype_stat, bf, bfsize);
134762306a36Sopenharmony_ci	if (printed)
134862306a36Sopenharmony_ci		i++;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	if (predicted_count < branch_count) {
135162306a36Sopenharmony_ci		printed += count_float_printf(i++, "predicted",
135262306a36Sopenharmony_ci				predicted_count * 100.0 / branch_count,
135362306a36Sopenharmony_ci				bf + printed, bfsize - printed, 0.0);
135462306a36Sopenharmony_ci	}
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	if (abort_count) {
135762306a36Sopenharmony_ci		printed += count_float_printf(i++, "abort",
135862306a36Sopenharmony_ci				abort_count * 100.0 / branch_count,
135962306a36Sopenharmony_ci				bf + printed, bfsize - printed, 0.1);
136062306a36Sopenharmony_ci	}
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	if (i)
136362306a36Sopenharmony_ci		printed += scnprintf(bf + printed, bfsize - printed, ")");
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	return printed;
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic int branch_from_str(char *bf, int bfsize,
136962306a36Sopenharmony_ci			   u64 branch_count,
137062306a36Sopenharmony_ci			   u64 cycles_count, u64 iter_count,
137162306a36Sopenharmony_ci			   u64 iter_cycles, u64 from_count)
137262306a36Sopenharmony_ci{
137362306a36Sopenharmony_ci	int printed = 0, i = 0;
137462306a36Sopenharmony_ci	u64 cycles, v = 0;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	cycles = cycles_count / branch_count;
137762306a36Sopenharmony_ci	if (cycles) {
137862306a36Sopenharmony_ci		printed += count_pri64_printf(i++, "cycles",
137962306a36Sopenharmony_ci				cycles,
138062306a36Sopenharmony_ci				bf + printed, bfsize - printed);
138162306a36Sopenharmony_ci	}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	if (iter_count && from_count) {
138462306a36Sopenharmony_ci		v = iter_count / from_count;
138562306a36Sopenharmony_ci		if (v) {
138662306a36Sopenharmony_ci			printed += count_pri64_printf(i++, "iter",
138762306a36Sopenharmony_ci					v, bf + printed, bfsize - printed);
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci			printed += count_pri64_printf(i++, "avg_cycles",
139062306a36Sopenharmony_ci					iter_cycles / iter_count,
139162306a36Sopenharmony_ci					bf + printed, bfsize - printed);
139262306a36Sopenharmony_ci		}
139362306a36Sopenharmony_ci	}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	if (i)
139662306a36Sopenharmony_ci		printed += scnprintf(bf + printed, bfsize - printed, ")");
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	return printed;
139962306a36Sopenharmony_ci}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_cistatic int counts_str_build(char *bf, int bfsize,
140262306a36Sopenharmony_ci			     u64 branch_count, u64 predicted_count,
140362306a36Sopenharmony_ci			     u64 abort_count, u64 cycles_count,
140462306a36Sopenharmony_ci			     u64 iter_count, u64 iter_cycles,
140562306a36Sopenharmony_ci			     u64 from_count,
140662306a36Sopenharmony_ci			     struct branch_type_stat *brtype_stat)
140762306a36Sopenharmony_ci{
140862306a36Sopenharmony_ci	int printed;
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	if (branch_count == 0)
141162306a36Sopenharmony_ci		return scnprintf(bf, bfsize, " (calltrace)");
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	if (brtype_stat->branch_to) {
141462306a36Sopenharmony_ci		printed = branch_to_str(bf, bfsize, branch_count,
141562306a36Sopenharmony_ci				predicted_count, abort_count, brtype_stat);
141662306a36Sopenharmony_ci	} else {
141762306a36Sopenharmony_ci		printed = branch_from_str(bf, bfsize, branch_count,
141862306a36Sopenharmony_ci				cycles_count, iter_count, iter_cycles,
141962306a36Sopenharmony_ci				from_count);
142062306a36Sopenharmony_ci	}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	if (!printed)
142362306a36Sopenharmony_ci		bf[0] = 0;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	return printed;
142662306a36Sopenharmony_ci}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_cistatic int callchain_counts_printf(FILE *fp, char *bf, int bfsize,
142962306a36Sopenharmony_ci				   u64 branch_count, u64 predicted_count,
143062306a36Sopenharmony_ci				   u64 abort_count, u64 cycles_count,
143162306a36Sopenharmony_ci				   u64 iter_count, u64 iter_cycles,
143262306a36Sopenharmony_ci				   u64 from_count,
143362306a36Sopenharmony_ci				   struct branch_type_stat *brtype_stat)
143462306a36Sopenharmony_ci{
143562306a36Sopenharmony_ci	char str[256];
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	counts_str_build(str, sizeof(str), branch_count,
143862306a36Sopenharmony_ci			 predicted_count, abort_count, cycles_count,
143962306a36Sopenharmony_ci			 iter_count, iter_cycles, from_count, brtype_stat);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	if (fp)
144262306a36Sopenharmony_ci		return fprintf(fp, "%s", str);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	return scnprintf(bf, bfsize, "%s", str);
144562306a36Sopenharmony_ci}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ciint callchain_list_counts__printf_value(struct callchain_list *clist,
144862306a36Sopenharmony_ci					FILE *fp, char *bf, int bfsize)
144962306a36Sopenharmony_ci{
145062306a36Sopenharmony_ci	u64 branch_count, predicted_count;
145162306a36Sopenharmony_ci	u64 abort_count, cycles_count;
145262306a36Sopenharmony_ci	u64 iter_count, iter_cycles;
145362306a36Sopenharmony_ci	u64 from_count;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	branch_count = clist->branch_count;
145662306a36Sopenharmony_ci	predicted_count = clist->predicted_count;
145762306a36Sopenharmony_ci	abort_count = clist->abort_count;
145862306a36Sopenharmony_ci	cycles_count = clist->cycles_count;
145962306a36Sopenharmony_ci	iter_count = clist->iter_count;
146062306a36Sopenharmony_ci	iter_cycles = clist->iter_cycles;
146162306a36Sopenharmony_ci	from_count = clist->from_count;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	return callchain_counts_printf(fp, bf, bfsize, branch_count,
146462306a36Sopenharmony_ci				       predicted_count, abort_count,
146562306a36Sopenharmony_ci				       cycles_count, iter_count, iter_cycles,
146662306a36Sopenharmony_ci				       from_count, &clist->brtype_stat);
146762306a36Sopenharmony_ci}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_cistatic void free_callchain_node(struct callchain_node *node)
147062306a36Sopenharmony_ci{
147162306a36Sopenharmony_ci	struct callchain_list *list, *tmp;
147262306a36Sopenharmony_ci	struct callchain_node *child;
147362306a36Sopenharmony_ci	struct rb_node *n;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	list_for_each_entry_safe(list, tmp, &node->parent_val, list) {
147662306a36Sopenharmony_ci		list_del_init(&list->list);
147762306a36Sopenharmony_ci		map__zput(list->ms.map);
147862306a36Sopenharmony_ci		maps__zput(list->ms.maps);
147962306a36Sopenharmony_ci		free(list);
148062306a36Sopenharmony_ci	}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	list_for_each_entry_safe(list, tmp, &node->val, list) {
148362306a36Sopenharmony_ci		list_del_init(&list->list);
148462306a36Sopenharmony_ci		map__zput(list->ms.map);
148562306a36Sopenharmony_ci		maps__zput(list->ms.maps);
148662306a36Sopenharmony_ci		free(list);
148762306a36Sopenharmony_ci	}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	n = rb_first(&node->rb_root_in);
149062306a36Sopenharmony_ci	while (n) {
149162306a36Sopenharmony_ci		child = container_of(n, struct callchain_node, rb_node_in);
149262306a36Sopenharmony_ci		n = rb_next(n);
149362306a36Sopenharmony_ci		rb_erase(&child->rb_node_in, &node->rb_root_in);
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci		free_callchain_node(child);
149662306a36Sopenharmony_ci		free(child);
149762306a36Sopenharmony_ci	}
149862306a36Sopenharmony_ci}
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_civoid free_callchain(struct callchain_root *root)
150162306a36Sopenharmony_ci{
150262306a36Sopenharmony_ci	if (!symbol_conf.use_callchain)
150362306a36Sopenharmony_ci		return;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	free_callchain_node(&root->node);
150662306a36Sopenharmony_ci}
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_cistatic u64 decay_callchain_node(struct callchain_node *node)
150962306a36Sopenharmony_ci{
151062306a36Sopenharmony_ci	struct callchain_node *child;
151162306a36Sopenharmony_ci	struct rb_node *n;
151262306a36Sopenharmony_ci	u64 child_hits = 0;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	n = rb_first(&node->rb_root_in);
151562306a36Sopenharmony_ci	while (n) {
151662306a36Sopenharmony_ci		child = container_of(n, struct callchain_node, rb_node_in);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci		child_hits += decay_callchain_node(child);
151962306a36Sopenharmony_ci		n = rb_next(n);
152062306a36Sopenharmony_ci	}
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	node->hit = (node->hit * 7) / 8;
152362306a36Sopenharmony_ci	node->children_hit = child_hits;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	return node->hit;
152662306a36Sopenharmony_ci}
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_civoid decay_callchain(struct callchain_root *root)
152962306a36Sopenharmony_ci{
153062306a36Sopenharmony_ci	if (!symbol_conf.use_callchain)
153162306a36Sopenharmony_ci		return;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	decay_callchain_node(&root->node);
153462306a36Sopenharmony_ci}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ciint callchain_node__make_parent_list(struct callchain_node *node)
153762306a36Sopenharmony_ci{
153862306a36Sopenharmony_ci	struct callchain_node *parent = node->parent;
153962306a36Sopenharmony_ci	struct callchain_list *chain, *new;
154062306a36Sopenharmony_ci	LIST_HEAD(head);
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	while (parent) {
154362306a36Sopenharmony_ci		list_for_each_entry_reverse(chain, &parent->val, list) {
154462306a36Sopenharmony_ci			new = malloc(sizeof(*new));
154562306a36Sopenharmony_ci			if (new == NULL)
154662306a36Sopenharmony_ci				goto out;
154762306a36Sopenharmony_ci			*new = *chain;
154862306a36Sopenharmony_ci			new->has_children = false;
154962306a36Sopenharmony_ci			new->ms.map = map__get(new->ms.map);
155062306a36Sopenharmony_ci			list_add_tail(&new->list, &head);
155162306a36Sopenharmony_ci		}
155262306a36Sopenharmony_ci		parent = parent->parent;
155362306a36Sopenharmony_ci	}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	list_for_each_entry_safe_reverse(chain, new, &head, list)
155662306a36Sopenharmony_ci		list_move_tail(&chain->list, &node->parent_val);
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	if (!list_empty(&node->parent_val)) {
155962306a36Sopenharmony_ci		chain = list_first_entry(&node->parent_val, struct callchain_list, list);
156062306a36Sopenharmony_ci		chain->has_children = rb_prev(&node->rb_node) || rb_next(&node->rb_node);
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci		chain = list_first_entry(&node->val, struct callchain_list, list);
156362306a36Sopenharmony_ci		chain->has_children = false;
156462306a36Sopenharmony_ci	}
156562306a36Sopenharmony_ci	return 0;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ciout:
156862306a36Sopenharmony_ci	list_for_each_entry_safe(chain, new, &head, list) {
156962306a36Sopenharmony_ci		list_del_init(&chain->list);
157062306a36Sopenharmony_ci		map__zput(chain->ms.map);
157162306a36Sopenharmony_ci		maps__zput(chain->ms.maps);
157262306a36Sopenharmony_ci		free(chain);
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci	return -ENOMEM;
157562306a36Sopenharmony_ci}
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_cistatic void callchain_cursor__delete(void *vcursor)
157862306a36Sopenharmony_ci{
157962306a36Sopenharmony_ci	struct callchain_cursor *cursor = vcursor;
158062306a36Sopenharmony_ci	struct callchain_cursor_node *node, *next;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	callchain_cursor_reset(cursor);
158362306a36Sopenharmony_ci	for (node = cursor->first; node != NULL; node = next) {
158462306a36Sopenharmony_ci		next = node->next;
158562306a36Sopenharmony_ci		free(node);
158662306a36Sopenharmony_ci	}
158762306a36Sopenharmony_ci	free(cursor);
158862306a36Sopenharmony_ci}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_cistatic void init_callchain_cursor_key(void)
159162306a36Sopenharmony_ci{
159262306a36Sopenharmony_ci	if (pthread_key_create(&callchain_cursor, callchain_cursor__delete)) {
159362306a36Sopenharmony_ci		pr_err("callchain cursor creation failed");
159462306a36Sopenharmony_ci		abort();
159562306a36Sopenharmony_ci	}
159662306a36Sopenharmony_ci}
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_cistruct callchain_cursor *get_tls_callchain_cursor(void)
159962306a36Sopenharmony_ci{
160062306a36Sopenharmony_ci	static pthread_once_t once_control = PTHREAD_ONCE_INIT;
160162306a36Sopenharmony_ci	struct callchain_cursor *cursor;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	pthread_once(&once_control, init_callchain_cursor_key);
160462306a36Sopenharmony_ci	cursor = pthread_getspecific(callchain_cursor);
160562306a36Sopenharmony_ci	if (!cursor) {
160662306a36Sopenharmony_ci		cursor = zalloc(sizeof(*cursor));
160762306a36Sopenharmony_ci		if (!cursor)
160862306a36Sopenharmony_ci			pr_debug3("%s: not enough memory\n", __func__);
160962306a36Sopenharmony_ci		pthread_setspecific(callchain_cursor, cursor);
161062306a36Sopenharmony_ci	}
161162306a36Sopenharmony_ci	return cursor;
161262306a36Sopenharmony_ci}
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ciint callchain_cursor__copy(struct callchain_cursor *dst,
161562306a36Sopenharmony_ci			   struct callchain_cursor *src)
161662306a36Sopenharmony_ci{
161762306a36Sopenharmony_ci	int rc = 0;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	callchain_cursor_reset(dst);
162062306a36Sopenharmony_ci	callchain_cursor_commit(src);
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	while (true) {
162362306a36Sopenharmony_ci		struct callchain_cursor_node *node;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci		node = callchain_cursor_current(src);
162662306a36Sopenharmony_ci		if (node == NULL)
162762306a36Sopenharmony_ci			break;
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci		rc = callchain_cursor_append(dst, node->ip, &node->ms,
163062306a36Sopenharmony_ci					     node->branch, &node->branch_flags,
163162306a36Sopenharmony_ci					     node->nr_loop_iter,
163262306a36Sopenharmony_ci					     node->iter_cycles,
163362306a36Sopenharmony_ci					     node->branch_from, node->srcline);
163462306a36Sopenharmony_ci		if (rc)
163562306a36Sopenharmony_ci			break;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci		callchain_cursor_advance(src);
163862306a36Sopenharmony_ci	}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	return rc;
164162306a36Sopenharmony_ci}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci/*
164462306a36Sopenharmony_ci * Initialize a cursor before adding entries inside, but keep
164562306a36Sopenharmony_ci * the previously allocated entries as a cache.
164662306a36Sopenharmony_ci */
164762306a36Sopenharmony_civoid callchain_cursor_reset(struct callchain_cursor *cursor)
164862306a36Sopenharmony_ci{
164962306a36Sopenharmony_ci	struct callchain_cursor_node *node;
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	cursor->nr = 0;
165262306a36Sopenharmony_ci	cursor->last = &cursor->first;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	for (node = cursor->first; node != NULL; node = node->next) {
165562306a36Sopenharmony_ci		map__zput(node->ms.map);
165662306a36Sopenharmony_ci		maps__zput(node->ms.maps);
165762306a36Sopenharmony_ci	}
165862306a36Sopenharmony_ci}
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_civoid callchain_param_setup(u64 sample_type, const char *arch)
166162306a36Sopenharmony_ci{
166262306a36Sopenharmony_ci	if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {
166362306a36Sopenharmony_ci		if ((sample_type & PERF_SAMPLE_REGS_USER) &&
166462306a36Sopenharmony_ci		    (sample_type & PERF_SAMPLE_STACK_USER)) {
166562306a36Sopenharmony_ci			callchain_param.record_mode = CALLCHAIN_DWARF;
166662306a36Sopenharmony_ci			dwarf_callchain_users = true;
166762306a36Sopenharmony_ci		} else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
166862306a36Sopenharmony_ci			callchain_param.record_mode = CALLCHAIN_LBR;
166962306a36Sopenharmony_ci		else
167062306a36Sopenharmony_ci			callchain_param.record_mode = CALLCHAIN_FP;
167162306a36Sopenharmony_ci	}
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	/*
167462306a36Sopenharmony_ci	 * It's necessary to use libunwind to reliably determine the caller of
167562306a36Sopenharmony_ci	 * a leaf function on aarch64, as otherwise we cannot know whether to
167662306a36Sopenharmony_ci	 * start from the LR or FP.
167762306a36Sopenharmony_ci	 *
167862306a36Sopenharmony_ci	 * Always starting from the LR can result in duplicate or entirely
167962306a36Sopenharmony_ci	 * erroneous entries. Always skipping the LR and starting from the FP
168062306a36Sopenharmony_ci	 * can result in missing entries.
168162306a36Sopenharmony_ci	 */
168262306a36Sopenharmony_ci	if (callchain_param.record_mode == CALLCHAIN_FP && !strcmp(arch, "arm64"))
168362306a36Sopenharmony_ci		dwarf_callchain_users = true;
168462306a36Sopenharmony_ci}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_cistatic bool chain_match(struct callchain_list *base_chain,
168762306a36Sopenharmony_ci			struct callchain_list *pair_chain)
168862306a36Sopenharmony_ci{
168962306a36Sopenharmony_ci	enum match_result match;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	match = match_chain_strings(base_chain->srcline,
169262306a36Sopenharmony_ci				    pair_chain->srcline);
169362306a36Sopenharmony_ci	if (match != MATCH_ERROR)
169462306a36Sopenharmony_ci		return match == MATCH_EQ;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	match = match_chain_dso_addresses(base_chain->ms.map,
169762306a36Sopenharmony_ci					  base_chain->ip,
169862306a36Sopenharmony_ci					  pair_chain->ms.map,
169962306a36Sopenharmony_ci					  pair_chain->ip);
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	return match == MATCH_EQ;
170262306a36Sopenharmony_ci}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_cibool callchain_cnode_matched(struct callchain_node *base_cnode,
170562306a36Sopenharmony_ci			     struct callchain_node *pair_cnode)
170662306a36Sopenharmony_ci{
170762306a36Sopenharmony_ci	struct callchain_list *base_chain, *pair_chain;
170862306a36Sopenharmony_ci	bool match = false;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	pair_chain = list_first_entry(&pair_cnode->val,
171162306a36Sopenharmony_ci				      struct callchain_list,
171262306a36Sopenharmony_ci				      list);
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	list_for_each_entry(base_chain, &base_cnode->val, list) {
171562306a36Sopenharmony_ci		if (&pair_chain->list == &pair_cnode->val)
171662306a36Sopenharmony_ci			return false;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci		if (!base_chain->srcline || !pair_chain->srcline) {
171962306a36Sopenharmony_ci			pair_chain = list_next_entry(pair_chain, list);
172062306a36Sopenharmony_ci			continue;
172162306a36Sopenharmony_ci		}
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci		match = chain_match(base_chain, pair_chain);
172462306a36Sopenharmony_ci		if (!match)
172562306a36Sopenharmony_ci			return false;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci		pair_chain = list_next_entry(pair_chain, list);
172862306a36Sopenharmony_ci	}
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	/*
173162306a36Sopenharmony_ci	 * Say chain1 is ABC, chain2 is ABCD, we consider they are
173262306a36Sopenharmony_ci	 * not fully matched.
173362306a36Sopenharmony_ci	 */
173462306a36Sopenharmony_ci	if (pair_chain && (&pair_chain->list != &pair_cnode->val))
173562306a36Sopenharmony_ci		return false;
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	return match;
173862306a36Sopenharmony_ci}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_cistatic u64 count_callchain_hits(struct hist_entry *he)
174162306a36Sopenharmony_ci{
174262306a36Sopenharmony_ci	struct rb_root *root = &he->sorted_chain;
174362306a36Sopenharmony_ci	struct rb_node *rb_node = rb_first(root);
174462306a36Sopenharmony_ci	struct callchain_node *node;
174562306a36Sopenharmony_ci	u64 chain_hits = 0;
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	while (rb_node) {
174862306a36Sopenharmony_ci		node = rb_entry(rb_node, struct callchain_node, rb_node);
174962306a36Sopenharmony_ci		chain_hits += node->hit;
175062306a36Sopenharmony_ci		rb_node = rb_next(rb_node);
175162306a36Sopenharmony_ci	}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	return chain_hits;
175462306a36Sopenharmony_ci}
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ciu64 callchain_total_hits(struct hists *hists)
175762306a36Sopenharmony_ci{
175862306a36Sopenharmony_ci	struct rb_node *next = rb_first_cached(&hists->entries);
175962306a36Sopenharmony_ci	u64 chain_hits = 0;
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	while (next) {
176262306a36Sopenharmony_ci		struct hist_entry *he = rb_entry(next, struct hist_entry,
176362306a36Sopenharmony_ci						 rb_node);
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci		chain_hits += count_callchain_hits(he);
176662306a36Sopenharmony_ci		next = rb_next(&he->rb_node);
176762306a36Sopenharmony_ci	}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	return chain_hits;
177062306a36Sopenharmony_ci}
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_cis64 callchain_avg_cycles(struct callchain_node *cnode)
177362306a36Sopenharmony_ci{
177462306a36Sopenharmony_ci	struct callchain_list *chain;
177562306a36Sopenharmony_ci	s64 cycles = 0;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	list_for_each_entry(chain, &cnode->val, list) {
177862306a36Sopenharmony_ci		if (chain->srcline && chain->branch_count)
177962306a36Sopenharmony_ci			cycles += chain->cycles_count / chain->branch_count;
178062306a36Sopenharmony_ci	}
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	return cycles;
178362306a36Sopenharmony_ci}
1784