xref: /openbmc/linux/tools/perf/util/hist.c (revision 58157004)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2b10ba7f1SArnaldo Carvalho de Melo #include "callchain.h"
3b4209025SArnaldo Carvalho de Melo #include "debug.h"
44a3cec84SArnaldo Carvalho de Melo #include "dso.h"
5598357ebSFrederic Weisbecker #include "build-id.h"
63d1d07ecSJohn Kacur #include "hist.h"
7ebf39d29SLeo Yan #include "kvm-stat.h"
89c68ae98SKrister Johansen #include "map.h"
9d3300a3cSArnaldo Carvalho de Melo #include "map_symbol.h"
10d3300a3cSArnaldo Carvalho de Melo #include "branch.h"
11d3300a3cSArnaldo Carvalho de Melo #include "mem-events.h"
124e4f06e4SArnaldo Carvalho de Melo #include "session.h"
13d890a98cSHari Bathini #include "namespaces.h"
14b629f3e9SNamhyung Kim #include "cgroup.h"
154e4f06e4SArnaldo Carvalho de Melo #include "sort.h"
1625c312dbSArnaldo Carvalho de Melo #include "units.h"
172a1731fbSArnaldo Carvalho de Melo #include "evlist.h"
1829d720edSNamhyung Kim #include "evsel.h"
1969bcb019SNamhyung Kim #include "annotate.h"
20632a5cabSArnaldo Carvalho de Melo #include "srcline.h"
21daecf9e0SArnaldo Carvalho de Melo #include "symbol.h"
22e7ff8920SArnaldo Carvalho de Melo #include "thread.h"
2360414418SJin Yao #include "block-info.h"
24740b97f9SNamhyung Kim #include "ui/progress.h"
25a43783aeSArnaldo Carvalho de Melo #include <errno.h>
269b33827dSArnaldo Carvalho de Melo #include <math.h>
2725c312dbSArnaldo Carvalho de Melo #include <inttypes.h>
28391e4206SArnaldo Carvalho de Melo #include <sys/param.h>
295c9dbe6dSArnaldo Carvalho de Melo #include <linux/rbtree.h>
308520a98dSArnaldo Carvalho de Melo #include <linux/string.h>
313723908dSAndi Kleen #include <linux/time64.h>
327f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
333d1d07ecSJohn Kacur 
3490cf1fb5SArnaldo Carvalho de Melo static bool hists__filter_entry_by_dso(struct hists *hists,
3590cf1fb5SArnaldo Carvalho de Melo 				       struct hist_entry *he);
3690cf1fb5SArnaldo Carvalho de Melo static bool hists__filter_entry_by_thread(struct hists *hists,
3790cf1fb5SArnaldo Carvalho de Melo 					  struct hist_entry *he);
38e94d53ebSNamhyung Kim static bool hists__filter_entry_by_symbol(struct hists *hists,
39e94d53ebSNamhyung Kim 					  struct hist_entry *he);
4021394d94SKan Liang static bool hists__filter_entry_by_socket(struct hists *hists,
4121394d94SKan Liang 					  struct hist_entry *he);
4290cf1fb5SArnaldo Carvalho de Melo 
hists__col_len(struct hists * hists,enum hist_column col)4342b28ac0SArnaldo Carvalho de Melo u16 hists__col_len(struct hists *hists, enum hist_column col)
448a6c5b26SArnaldo Carvalho de Melo {
4542b28ac0SArnaldo Carvalho de Melo 	return hists->col_len[col];
468a6c5b26SArnaldo Carvalho de Melo }
478a6c5b26SArnaldo Carvalho de Melo 
hists__set_col_len(struct hists * hists,enum hist_column col,u16 len)4842b28ac0SArnaldo Carvalho de Melo void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len)
498a6c5b26SArnaldo Carvalho de Melo {
5042b28ac0SArnaldo Carvalho de Melo 	hists->col_len[col] = len;
518a6c5b26SArnaldo Carvalho de Melo }
528a6c5b26SArnaldo Carvalho de Melo 
hists__new_col_len(struct hists * hists,enum hist_column col,u16 len)5342b28ac0SArnaldo Carvalho de Melo bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
548a6c5b26SArnaldo Carvalho de Melo {
5542b28ac0SArnaldo Carvalho de Melo 	if (len > hists__col_len(hists, col)) {
5642b28ac0SArnaldo Carvalho de Melo 		hists__set_col_len(hists, col, len);
578a6c5b26SArnaldo Carvalho de Melo 		return true;
588a6c5b26SArnaldo Carvalho de Melo 	}
598a6c5b26SArnaldo Carvalho de Melo 	return false;
608a6c5b26SArnaldo Carvalho de Melo }
618a6c5b26SArnaldo Carvalho de Melo 
hists__reset_col_len(struct hists * hists)627ccf4f90SNamhyung Kim void hists__reset_col_len(struct hists *hists)
638a6c5b26SArnaldo Carvalho de Melo {
648a6c5b26SArnaldo Carvalho de Melo 	enum hist_column col;
658a6c5b26SArnaldo Carvalho de Melo 
668a6c5b26SArnaldo Carvalho de Melo 	for (col = 0; col < HISTC_NR_COLS; ++col)
6742b28ac0SArnaldo Carvalho de Melo 		hists__set_col_len(hists, col, 0);
688a6c5b26SArnaldo Carvalho de Melo }
698a6c5b26SArnaldo Carvalho de Melo 
hists__set_unres_dso_col_len(struct hists * hists,int dso)70b5387528SRoberto Agostino Vitillo static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
71b5387528SRoberto Agostino Vitillo {
72b5387528SRoberto Agostino Vitillo 	const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
73b5387528SRoberto Agostino Vitillo 
74b5387528SRoberto Agostino Vitillo 	if (hists__col_len(hists, dso) < unresolved_col_width &&
75b5387528SRoberto Agostino Vitillo 	    !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
76b5387528SRoberto Agostino Vitillo 	    !symbol_conf.dso_list)
77b5387528SRoberto Agostino Vitillo 		hists__set_col_len(hists, dso, unresolved_col_width);
78b5387528SRoberto Agostino Vitillo }
79b5387528SRoberto Agostino Vitillo 
hists__calc_col_len(struct hists * hists,struct hist_entry * h)807ccf4f90SNamhyung Kim void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
818a6c5b26SArnaldo Carvalho de Melo {
82b5387528SRoberto Agostino Vitillo 	const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
8398a3b32cSStephane Eranian 	int symlen;
848a6c5b26SArnaldo Carvalho de Melo 	u16 len;
858a6c5b26SArnaldo Carvalho de Melo 
860bdf181fSJin Yao 	if (h->block_info)
870bdf181fSJin Yao 		return;
88ded19d57SNamhyung Kim 	/*
89ded19d57SNamhyung Kim 	 * +4 accounts for '[x] ' priv level info
90ded19d57SNamhyung Kim 	 * +2 accounts for 0x prefix on raw addresses
91ded19d57SNamhyung Kim 	 * +3 accounts for ' y ' symtab origin info
92ded19d57SNamhyung Kim 	 */
93ded19d57SNamhyung Kim 	if (h->ms.sym) {
94ded19d57SNamhyung Kim 		symlen = h->ms.sym->namelen + 4;
95bb963e16SNamhyung Kim 		if (verbose > 0)
96ded19d57SNamhyung Kim 			symlen += BITS_PER_LONG / 4 + 2 + 3;
97ded19d57SNamhyung Kim 		hists__new_col_len(hists, HISTC_SYMBOL, symlen);
98ded19d57SNamhyung Kim 	} else {
9998a3b32cSStephane Eranian 		symlen = unresolved_col_width + 4 + 2;
10098a3b32cSStephane Eranian 		hists__new_col_len(hists, HISTC_SYMBOL, symlen);
101b5387528SRoberto Agostino Vitillo 		hists__set_unres_dso_col_len(hists, HISTC_DSO);
10298a3b32cSStephane Eranian 	}
1038a6c5b26SArnaldo Carvalho de Melo 
1048a6c5b26SArnaldo Carvalho de Melo 	len = thread__comm_len(h->thread);
10542b28ac0SArnaldo Carvalho de Melo 	if (hists__new_col_len(hists, HISTC_COMM, len))
10689c7cb2cSJiri Olsa 		hists__set_col_len(hists, HISTC_THREAD, len + 8);
1078a6c5b26SArnaldo Carvalho de Melo 
1088a6c5b26SArnaldo Carvalho de Melo 	if (h->ms.map) {
10963df0e4bSIan Rogers 		len = dso__name_len(map__dso(h->ms.map));
11042b28ac0SArnaldo Carvalho de Melo 		hists__new_col_len(hists, HISTC_DSO, len);
1118a6c5b26SArnaldo Carvalho de Melo 	}
112b5387528SRoberto Agostino Vitillo 
113cb993744SNamhyung Kim 	if (h->parent)
114cb993744SNamhyung Kim 		hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
115cb993744SNamhyung Kim 
116b5387528SRoberto Agostino Vitillo 	if (h->branch_info) {
117d46a4cdfSArnaldo Carvalho de Melo 		if (h->branch_info->from.ms.sym) {
118d46a4cdfSArnaldo Carvalho de Melo 			symlen = (int)h->branch_info->from.ms.sym->namelen + 4;
119bb963e16SNamhyung Kim 			if (verbose > 0)
120ded19d57SNamhyung Kim 				symlen += BITS_PER_LONG / 4 + 2 + 3;
121b5387528SRoberto Agostino Vitillo 			hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
122b5387528SRoberto Agostino Vitillo 
12363df0e4bSIan Rogers 			symlen = dso__name_len(map__dso(h->branch_info->from.ms.map));
124b5387528SRoberto Agostino Vitillo 			hists__new_col_len(hists, HISTC_DSO_FROM, symlen);
125b5387528SRoberto Agostino Vitillo 		} else {
126b5387528SRoberto Agostino Vitillo 			symlen = unresolved_col_width + 4 + 2;
127b5387528SRoberto Agostino Vitillo 			hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
12805274770SStephane Eranian 			hists__new_col_len(hists, HISTC_ADDR_FROM, symlen);
129b5387528SRoberto Agostino Vitillo 			hists__set_unres_dso_col_len(hists, HISTC_DSO_FROM);
130b5387528SRoberto Agostino Vitillo 		}
131b5387528SRoberto Agostino Vitillo 
132d46a4cdfSArnaldo Carvalho de Melo 		if (h->branch_info->to.ms.sym) {
133d46a4cdfSArnaldo Carvalho de Melo 			symlen = (int)h->branch_info->to.ms.sym->namelen + 4;
134bb963e16SNamhyung Kim 			if (verbose > 0)
135ded19d57SNamhyung Kim 				symlen += BITS_PER_LONG / 4 + 2 + 3;
136b5387528SRoberto Agostino Vitillo 			hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
137b5387528SRoberto Agostino Vitillo 
13863df0e4bSIan Rogers 			symlen = dso__name_len(map__dso(h->branch_info->to.ms.map));
139b5387528SRoberto Agostino Vitillo 			hists__new_col_len(hists, HISTC_DSO_TO, symlen);
140b5387528SRoberto Agostino Vitillo 		} else {
141b5387528SRoberto Agostino Vitillo 			symlen = unresolved_col_width + 4 + 2;
142b5387528SRoberto Agostino Vitillo 			hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
14305274770SStephane Eranian 			hists__new_col_len(hists, HISTC_ADDR_TO, symlen);
144b5387528SRoberto Agostino Vitillo 			hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
145b5387528SRoberto Agostino Vitillo 		}
146508be0dfSAndi Kleen 
147508be0dfSAndi Kleen 		if (h->branch_info->srcline_from)
148508be0dfSAndi Kleen 			hists__new_col_len(hists, HISTC_SRCLINE_FROM,
149508be0dfSAndi Kleen 					strlen(h->branch_info->srcline_from));
150508be0dfSAndi Kleen 		if (h->branch_info->srcline_to)
151508be0dfSAndi Kleen 			hists__new_col_len(hists, HISTC_SRCLINE_TO,
152508be0dfSAndi Kleen 					strlen(h->branch_info->srcline_to));
153b5387528SRoberto Agostino Vitillo 	}
15498a3b32cSStephane Eranian 
15598a3b32cSStephane Eranian 	if (h->mem_info) {
156d46a4cdfSArnaldo Carvalho de Melo 		if (h->mem_info->daddr.ms.sym) {
157d46a4cdfSArnaldo Carvalho de Melo 			symlen = (int)h->mem_info->daddr.ms.sym->namelen + 4
15898a3b32cSStephane Eranian 			       + unresolved_col_width + 2;
15998a3b32cSStephane Eranian 			hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
16098a3b32cSStephane Eranian 					   symlen);
1619b32ba71SDon Zickus 			hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
1629b32ba71SDon Zickus 					   symlen + 1);
16398a3b32cSStephane Eranian 		} else {
16498a3b32cSStephane Eranian 			symlen = unresolved_col_width + 4 + 2;
16598a3b32cSStephane Eranian 			hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
16698a3b32cSStephane Eranian 					   symlen);
1670805909fSJiri Olsa 			hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
1680805909fSJiri Olsa 					   symlen);
16998a3b32cSStephane Eranian 		}
170b34b3bf0SJiri Olsa 
171d46a4cdfSArnaldo Carvalho de Melo 		if (h->mem_info->iaddr.ms.sym) {
172d46a4cdfSArnaldo Carvalho de Melo 			symlen = (int)h->mem_info->iaddr.ms.sym->namelen + 4
173b34b3bf0SJiri Olsa 			       + unresolved_col_width + 2;
174b34b3bf0SJiri Olsa 			hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL,
175b34b3bf0SJiri Olsa 					   symlen);
176b34b3bf0SJiri Olsa 		} else {
177b34b3bf0SJiri Olsa 			symlen = unresolved_col_width + 4 + 2;
178b34b3bf0SJiri Olsa 			hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL,
179b34b3bf0SJiri Olsa 					   symlen);
180b34b3bf0SJiri Olsa 		}
181b34b3bf0SJiri Olsa 
182d46a4cdfSArnaldo Carvalho de Melo 		if (h->mem_info->daddr.ms.map) {
18363df0e4bSIan Rogers 			symlen = dso__name_len(map__dso(h->mem_info->daddr.ms.map));
18498a3b32cSStephane Eranian 			hists__new_col_len(hists, HISTC_MEM_DADDR_DSO,
18598a3b32cSStephane Eranian 					   symlen);
18698a3b32cSStephane Eranian 		} else {
18798a3b32cSStephane Eranian 			symlen = unresolved_col_width + 4 + 2;
18898a3b32cSStephane Eranian 			hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
18998a3b32cSStephane Eranian 		}
1908780fb25SKan Liang 
1918780fb25SKan Liang 		hists__new_col_len(hists, HISTC_MEM_PHYS_DADDR,
1928780fb25SKan Liang 				   unresolved_col_width + 4 + 2);
1938780fb25SKan Liang 
194a50d03e3SKan Liang 		hists__new_col_len(hists, HISTC_MEM_DATA_PAGE_SIZE,
195a50d03e3SKan Liang 				   unresolved_col_width + 4 + 2);
196a50d03e3SKan Liang 
19798a3b32cSStephane Eranian 	} else {
19898a3b32cSStephane Eranian 		symlen = unresolved_col_width + 4 + 2;
19998a3b32cSStephane Eranian 		hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen);
200b34b3bf0SJiri Olsa 		hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL, symlen);
20198a3b32cSStephane Eranian 		hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
20298a3b32cSStephane Eranian 	}
20398a3b32cSStephane Eranian 
204b629f3e9SNamhyung Kim 	hists__new_col_len(hists, HISTC_CGROUP, 6);
205d890a98cSHari Bathini 	hists__new_col_len(hists, HISTC_CGROUP_ID, 20);
206a4978ecaSArnaldo Carvalho de Melo 	hists__new_col_len(hists, HISTC_CPU, 3);
2072e7ea3abSKan Liang 	hists__new_col_len(hists, HISTC_SOCKET, 6);
20898a3b32cSStephane Eranian 	hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
20998a3b32cSStephane Eranian 	hists__new_col_len(hists, HISTC_MEM_TLB, 22);
21098a3b32cSStephane Eranian 	hists__new_col_len(hists, HISTC_MEM_SNOOP, 12);
2114953c897SRavi Bangoria 	hists__new_col_len(hists, HISTC_MEM_LVL, 36 + 3);
21298a3b32cSStephane Eranian 	hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
21398a3b32cSStephane Eranian 	hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
214a054c298SKan Liang 	hists__new_col_len(hists, HISTC_MEM_BLOCKED, 10);
215590db42dSKan Liang 	hists__new_col_len(hists, HISTC_LOCAL_INS_LAT, 13);
216590db42dSKan Liang 	hists__new_col_len(hists, HISTC_GLOBAL_INS_LAT, 13);
217e3304c21SAthira Rajeev 	hists__new_col_len(hists, HISTC_LOCAL_P_STAGE_CYC, 13);
218e3304c21SAthira Rajeev 	hists__new_col_len(hists, HISTC_GLOBAL_P_STAGE_CYC, 13);
219762461f1SNamhyung Kim 	hists__new_col_len(hists, HISTC_ADDR, BITS_PER_LONG / 4 + 2);
220e3304c21SAthira Rajeev 
2213dab6ac0SAndi Kleen 	if (symbol_conf.nanosecs)
2223dab6ac0SAndi Kleen 		hists__new_col_len(hists, HISTC_TIME, 16);
2233dab6ac0SAndi Kleen 	else
2243723908dSAndi Kleen 		hists__new_col_len(hists, HISTC_TIME, 12);
2259fd74f20SStephane Eranian 	hists__new_col_len(hists, HISTC_CODE_PAGE_SIZE, 6);
226475eeab9SAndi Kleen 
227f666ac0dSJiri Olsa 	if (h->srcline) {
228f666ac0dSJiri Olsa 		len = MAX(strlen(h->srcline), strlen(sort_srcline.se_header));
229f666ac0dSJiri Olsa 		hists__new_col_len(hists, HISTC_SRCLINE, len);
230f666ac0dSJiri Olsa 	}
231e8e6d37eSArnaldo Carvalho de Melo 
23231191a85SAndi Kleen 	if (h->srcfile)
23331191a85SAndi Kleen 		hists__new_col_len(hists, HISTC_SRCFILE, strlen(h->srcfile));
23431191a85SAndi Kleen 
235475eeab9SAndi Kleen 	if (h->transaction)
236475eeab9SAndi Kleen 		hists__new_col_len(hists, HISTC_TRANSACTION,
237475eeab9SAndi Kleen 				   hist_entry__transaction_len());
2380c0af78dSNamhyung Kim 
2390c0af78dSNamhyung Kim 	if (h->trace_output)
2400c0af78dSNamhyung Kim 		hists__new_col_len(hists, HISTC_TRACE, strlen(h->trace_output));
241b629f3e9SNamhyung Kim 
242b629f3e9SNamhyung Kim 	if (h->cgroup) {
243b629f3e9SNamhyung Kim 		const char *cgrp_name = "unknown";
2445ab6d715SIan Rogers 		struct cgroup *cgrp = cgroup__find(maps__machine(h->ms.maps)->env,
245b629f3e9SNamhyung Kim 						   h->cgroup);
246b629f3e9SNamhyung Kim 		if (cgrp != NULL)
247b629f3e9SNamhyung Kim 			cgrp_name = cgrp->name;
248b629f3e9SNamhyung Kim 
249b629f3e9SNamhyung Kim 		hists__new_col_len(hists, HISTC_CGROUP, strlen(cgrp_name));
250b629f3e9SNamhyung Kim 	}
2518a6c5b26SArnaldo Carvalho de Melo }
2528a6c5b26SArnaldo Carvalho de Melo 
hists__output_recalc_col_len(struct hists * hists,int max_rows)2537ccf4f90SNamhyung Kim void hists__output_recalc_col_len(struct hists *hists, int max_rows)
2547ccf4f90SNamhyung Kim {
2552eb3d689SDavidlohr Bueso 	struct rb_node *next = rb_first_cached(&hists->entries);
2567ccf4f90SNamhyung Kim 	struct hist_entry *n;
2577ccf4f90SNamhyung Kim 	int row = 0;
2587ccf4f90SNamhyung Kim 
2597ccf4f90SNamhyung Kim 	hists__reset_col_len(hists);
2607ccf4f90SNamhyung Kim 
2617ccf4f90SNamhyung Kim 	while (next && row++ < max_rows) {
2627ccf4f90SNamhyung Kim 		n = rb_entry(next, struct hist_entry, rb_node);
2637ccf4f90SNamhyung Kim 		if (!n->filtered)
2647ccf4f90SNamhyung Kim 			hists__calc_col_len(hists, n);
2657ccf4f90SNamhyung Kim 		next = rb_next(&n->rb_node);
2667ccf4f90SNamhyung Kim 	}
2677ccf4f90SNamhyung Kim }
2687ccf4f90SNamhyung Kim 
he_stat__add_cpumode_period(struct he_stat * he_stat,unsigned int cpumode,u64 period)269f39056f9SNamhyung Kim static void he_stat__add_cpumode_period(struct he_stat *he_stat,
270c82ee828SArnaldo Carvalho de Melo 					unsigned int cpumode, u64 period)
271a1645ce1SZhang, Yanmin {
27228e2a106SArnaldo Carvalho de Melo 	switch (cpumode) {
273a1645ce1SZhang, Yanmin 	case PERF_RECORD_MISC_KERNEL:
274f39056f9SNamhyung Kim 		he_stat->period_sys += period;
275a1645ce1SZhang, Yanmin 		break;
276a1645ce1SZhang, Yanmin 	case PERF_RECORD_MISC_USER:
277f39056f9SNamhyung Kim 		he_stat->period_us += period;
278a1645ce1SZhang, Yanmin 		break;
279a1645ce1SZhang, Yanmin 	case PERF_RECORD_MISC_GUEST_KERNEL:
280f39056f9SNamhyung Kim 		he_stat->period_guest_sys += period;
281a1645ce1SZhang, Yanmin 		break;
282a1645ce1SZhang, Yanmin 	case PERF_RECORD_MISC_GUEST_USER:
283f39056f9SNamhyung Kim 		he_stat->period_guest_us += period;
284a1645ce1SZhang, Yanmin 		break;
285a1645ce1SZhang, Yanmin 	default:
286a1645ce1SZhang, Yanmin 		break;
287a1645ce1SZhang, Yanmin 	}
288a1645ce1SZhang, Yanmin }
289a1645ce1SZhang, Yanmin 
hist_time(unsigned long htime)2903723908dSAndi Kleen static long hist_time(unsigned long htime)
2913723908dSAndi Kleen {
2923723908dSAndi Kleen 	unsigned long time_quantum = symbol_conf.time_quantum;
2933723908dSAndi Kleen 	if (time_quantum)
2943723908dSAndi Kleen 		return (htime / time_quantum) * time_quantum;
2953723908dSAndi Kleen 	return htime;
2963723908dSAndi Kleen }
2973723908dSAndi Kleen 
he_stat__add_period(struct he_stat * he_stat,u64 period)298db4b2840SNamhyung Kim static void he_stat__add_period(struct he_stat *he_stat, u64 period)
299139c0815SNamhyung Kim {
300139c0815SNamhyung Kim 	he_stat->period		+= period;
301139c0815SNamhyung Kim 	he_stat->nr_events	+= 1;
302139c0815SNamhyung Kim }
303139c0815SNamhyung Kim 
he_stat__add_stat(struct he_stat * dest,struct he_stat * src)304139c0815SNamhyung Kim static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
305139c0815SNamhyung Kim {
306139c0815SNamhyung Kim 	dest->period		+= src->period;
307139c0815SNamhyung Kim 	dest->period_sys	+= src->period_sys;
308139c0815SNamhyung Kim 	dest->period_us		+= src->period_us;
309139c0815SNamhyung Kim 	dest->period_guest_sys	+= src->period_guest_sys;
310139c0815SNamhyung Kim 	dest->period_guest_us	+= src->period_guest_us;
311139c0815SNamhyung Kim 	dest->nr_events		+= src->nr_events;
312139c0815SNamhyung Kim }
313139c0815SNamhyung Kim 
he_stat__decay(struct he_stat * he_stat)314f39056f9SNamhyung Kim static void he_stat__decay(struct he_stat *he_stat)
315ab81f3fdSArnaldo Carvalho de Melo {
316f39056f9SNamhyung Kim 	he_stat->period = (he_stat->period * 7) / 8;
317f39056f9SNamhyung Kim 	he_stat->nr_events = (he_stat->nr_events * 7) / 8;
31805484298SAndi Kleen 	/* XXX need decay for weight too? */
319ab81f3fdSArnaldo Carvalho de Melo }
320ab81f3fdSArnaldo Carvalho de Melo 
3215d8200aeSNamhyung Kim static void hists__delete_entry(struct hists *hists, struct hist_entry *he);
3225d8200aeSNamhyung Kim 
hists__decay_entry(struct hists * hists,struct hist_entry * he)323ab81f3fdSArnaldo Carvalho de Melo static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
324ab81f3fdSArnaldo Carvalho de Melo {
325b24c28f7SNamhyung Kim 	u64 prev_period = he->stat.period;
3263186b681SNamhyung Kim 	u64 diff;
327c64550cfSArnaldo Carvalho de Melo 
328c64550cfSArnaldo Carvalho de Melo 	if (prev_period == 0)
329df71d95fSArnaldo Carvalho de Melo 		return true;
330c64550cfSArnaldo Carvalho de Melo 
331f39056f9SNamhyung Kim 	he_stat__decay(&he->stat);
332f8be1c8cSNamhyung Kim 	if (symbol_conf.cumulate_callchain)
333f8be1c8cSNamhyung Kim 		he_stat__decay(he->stat_acc);
33442b276a2SNamhyung Kim 	decay_callchain(he->callchain);
335c64550cfSArnaldo Carvalho de Melo 
3363186b681SNamhyung Kim 	diff = prev_period - he->stat.period;
3373186b681SNamhyung Kim 
3385d8200aeSNamhyung Kim 	if (!he->depth) {
3393186b681SNamhyung Kim 		hists->stats.total_period -= diff;
340c64550cfSArnaldo Carvalho de Melo 		if (!he->filtered)
3413186b681SNamhyung Kim 			hists->stats.total_non_filtered_period -= diff;
3425d8200aeSNamhyung Kim 	}
3435d8200aeSNamhyung Kim 
3445d8200aeSNamhyung Kim 	if (!he->leaf) {
3455d8200aeSNamhyung Kim 		struct hist_entry *child;
3462eb3d689SDavidlohr Bueso 		struct rb_node *node = rb_first_cached(&he->hroot_out);
3475d8200aeSNamhyung Kim 		while (node) {
3485d8200aeSNamhyung Kim 			child = rb_entry(node, struct hist_entry, rb_node);
3495d8200aeSNamhyung Kim 			node = rb_next(node);
3505d8200aeSNamhyung Kim 
3515d8200aeSNamhyung Kim 			if (hists__decay_entry(hists, child))
3525d8200aeSNamhyung Kim 				hists__delete_entry(hists, child);
3535d8200aeSNamhyung Kim 		}
3545d8200aeSNamhyung Kim 	}
355c64550cfSArnaldo Carvalho de Melo 
356b24c28f7SNamhyung Kim 	return he->stat.period == 0;
357ab81f3fdSArnaldo Carvalho de Melo }
358ab81f3fdSArnaldo Carvalho de Melo 
hists__delete_entry(struct hists * hists,struct hist_entry * he)359956b65e1SArnaldo Carvalho de Melo static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
360956b65e1SArnaldo Carvalho de Melo {
3612eb3d689SDavidlohr Bueso 	struct rb_root_cached *root_in;
3622eb3d689SDavidlohr Bueso 	struct rb_root_cached *root_out;
363956b65e1SArnaldo Carvalho de Melo 
3645d8200aeSNamhyung Kim 	if (he->parent_he) {
3655d8200aeSNamhyung Kim 		root_in  = &he->parent_he->hroot_in;
3665d8200aeSNamhyung Kim 		root_out = &he->parent_he->hroot_out;
3675d8200aeSNamhyung Kim 	} else {
36852225036SJiri Olsa 		if (hists__has(hists, need_collapse))
3695d8200aeSNamhyung Kim 			root_in = &hists->entries_collapsed;
37061fa0e94SNamhyung Kim 		else
3715d8200aeSNamhyung Kim 			root_in = hists->entries_in;
3725d8200aeSNamhyung Kim 		root_out = &hists->entries;
3735d8200aeSNamhyung Kim 	}
3745d8200aeSNamhyung Kim 
3752eb3d689SDavidlohr Bueso 	rb_erase_cached(&he->rb_node_in, root_in);
3762eb3d689SDavidlohr Bueso 	rb_erase_cached(&he->rb_node, root_out);
377956b65e1SArnaldo Carvalho de Melo 
378956b65e1SArnaldo Carvalho de Melo 	--hists->nr_entries;
379956b65e1SArnaldo Carvalho de Melo 	if (!he->filtered)
380956b65e1SArnaldo Carvalho de Melo 		--hists->nr_non_filtered_entries;
381956b65e1SArnaldo Carvalho de Melo 
382956b65e1SArnaldo Carvalho de Melo 	hist_entry__delete(he);
383956b65e1SArnaldo Carvalho de Melo }
384956b65e1SArnaldo Carvalho de Melo 
hists__decay_entries(struct hists * hists,bool zap_user,bool zap_kernel)3853a5714f8SNamhyung Kim void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
386ab81f3fdSArnaldo Carvalho de Melo {
3872eb3d689SDavidlohr Bueso 	struct rb_node *next = rb_first_cached(&hists->entries);
388ab81f3fdSArnaldo Carvalho de Melo 	struct hist_entry *n;
389ab81f3fdSArnaldo Carvalho de Melo 
390ab81f3fdSArnaldo Carvalho de Melo 	while (next) {
391ab81f3fdSArnaldo Carvalho de Melo 		n = rb_entry(next, struct hist_entry, rb_node);
392ab81f3fdSArnaldo Carvalho de Melo 		next = rb_next(&n->rb_node);
393b079d4e9SArnaldo Carvalho de Melo 		if (((zap_user && n->level == '.') ||
394b079d4e9SArnaldo Carvalho de Melo 		     (zap_kernel && n->level != '.') ||
3954c47f4fcSArnaldo Carvalho de Melo 		     hists__decay_entry(hists, n))) {
396956b65e1SArnaldo Carvalho de Melo 			hists__delete_entry(hists, n);
397ab81f3fdSArnaldo Carvalho de Melo 		}
398ab81f3fdSArnaldo Carvalho de Melo 	}
399ab81f3fdSArnaldo Carvalho de Melo }
400ab81f3fdSArnaldo Carvalho de Melo 
hists__delete_entries(struct hists * hists)401701937bdSNamhyung Kim void hists__delete_entries(struct hists *hists)
402701937bdSNamhyung Kim {
4032eb3d689SDavidlohr Bueso 	struct rb_node *next = rb_first_cached(&hists->entries);
404701937bdSNamhyung Kim 	struct hist_entry *n;
405701937bdSNamhyung Kim 
406701937bdSNamhyung Kim 	while (next) {
407701937bdSNamhyung Kim 		n = rb_entry(next, struct hist_entry, rb_node);
408701937bdSNamhyung Kim 		next = rb_next(&n->rb_node);
409701937bdSNamhyung Kim 
410956b65e1SArnaldo Carvalho de Melo 		hists__delete_entry(hists, n);
411701937bdSNamhyung Kim 	}
412701937bdSNamhyung Kim }
413701937bdSNamhyung Kim 
hists__get_entry(struct hists * hists,int idx)414b10c78c5SJin Yao struct hist_entry *hists__get_entry(struct hists *hists, int idx)
415b10c78c5SJin Yao {
416b10c78c5SJin Yao 	struct rb_node *next = rb_first_cached(&hists->entries);
417b10c78c5SJin Yao 	struct hist_entry *n;
418b10c78c5SJin Yao 	int i = 0;
419b10c78c5SJin Yao 
420b10c78c5SJin Yao 	while (next) {
421b10c78c5SJin Yao 		n = rb_entry(next, struct hist_entry, rb_node);
422b10c78c5SJin Yao 		if (i == idx)
423b10c78c5SJin Yao 			return n;
424b10c78c5SJin Yao 
425b10c78c5SJin Yao 		next = rb_next(&n->rb_node);
426b10c78c5SJin Yao 		i++;
427b10c78c5SJin Yao 	}
428b10c78c5SJin Yao 
429b10c78c5SJin Yao 	return NULL;
430b10c78c5SJin Yao }
431b10c78c5SJin Yao 
4323d1d07ecSJohn Kacur /*
433c82ee828SArnaldo Carvalho de Melo  * histogram, sorted on item, collects periods
4343d1d07ecSJohn Kacur  */
4353d1d07ecSJohn Kacur 
hist_entry__init(struct hist_entry * he,struct hist_entry * template,bool sample_self,size_t callchain_size)4360a269a6bSJiri Olsa static int hist_entry__init(struct hist_entry *he,
4370a269a6bSJiri Olsa 			    struct hist_entry *template,
43841477acfSArnaldo Carvalho de Melo 			    bool sample_self,
43941477acfSArnaldo Carvalho de Melo 			    size_t callchain_size)
44028e2a106SArnaldo Carvalho de Melo {
44112c14278SArnaldo Carvalho de Melo 	*he = *template;
44241477acfSArnaldo Carvalho de Melo 	he->callchain_size = callchain_size;
443c4b35351SNamhyung Kim 
444f8be1c8cSNamhyung Kim 	if (symbol_conf.cumulate_callchain) {
445f8be1c8cSNamhyung Kim 		he->stat_acc = malloc(sizeof(he->stat));
4460a269a6bSJiri Olsa 		if (he->stat_acc == NULL)
4470a269a6bSJiri Olsa 			return -ENOMEM;
448f8be1c8cSNamhyung Kim 		memcpy(he->stat_acc, &he->stat, sizeof(he->stat));
449a0b51af3SNamhyung Kim 		if (!sample_self)
450a0b51af3SNamhyung Kim 			memset(&he->stat, 0, sizeof(he->stat));
451f8be1c8cSNamhyung Kim 	}
452f8be1c8cSNamhyung Kim 
453bffb5b0cSIan Rogers 	he->ms.maps = maps__get(he->ms.maps);
454ec417ad4SIan Rogers 	he->ms.map = map__get(he->ms.map);
4553cf0cb1fSStephane Eranian 
4563cf0cb1fSStephane Eranian 	if (he->branch_info) {
45726353a61SNamhyung Kim 		/*
45826353a61SNamhyung Kim 		 * This branch info is (a part of) allocated from
459644f2df2SArnaldo Carvalho de Melo 		 * sample__resolve_bstack() and will be freed after
46026353a61SNamhyung Kim 		 * adding new entries.  So we need to save a copy.
46126353a61SNamhyung Kim 		 */
46226353a61SNamhyung Kim 		he->branch_info = malloc(sizeof(*he->branch_info));
463c5758910SJiri Olsa 		if (he->branch_info == NULL)
464c5758910SJiri Olsa 			goto err;
46526353a61SNamhyung Kim 
46626353a61SNamhyung Kim 		memcpy(he->branch_info, template->branch_info,
46726353a61SNamhyung Kim 		       sizeof(*he->branch_info));
46826353a61SNamhyung Kim 
469ec417ad4SIan Rogers 		he->branch_info->from.ms.map = map__get(he->branch_info->from.ms.map);
470ec417ad4SIan Rogers 		he->branch_info->to.ms.map = map__get(he->branch_info->to.ms.map);
4713cf0cb1fSStephane Eranian 	}
4723cf0cb1fSStephane Eranian 
47398a3b32cSStephane Eranian 	if (he->mem_info) {
474ec417ad4SIan Rogers 		he->mem_info->iaddr.ms.map = map__get(he->mem_info->iaddr.ms.map);
475ec417ad4SIan Rogers 		he->mem_info->daddr.ms.map = map__get(he->mem_info->daddr.ms.map);
47698a3b32cSStephane Eranian 	}
47798a3b32cSStephane Eranian 
478fabd37b8SArnaldo Carvalho de Melo 	if (hist_entry__has_callchains(he) && symbol_conf.use_callchain)
47912c14278SArnaldo Carvalho de Melo 		callchain_init(he->callchain);
480b821c732SArnaldo Carvalho de Melo 
48172392834SNamhyung Kim 	if (he->raw_data) {
48272392834SNamhyung Kim 		he->raw_data = memdup(he->raw_data, he->raw_size);
483c5758910SJiri Olsa 		if (he->raw_data == NULL)
484c5758910SJiri Olsa 			goto err_infos;
48572392834SNamhyung Kim 	}
48626349585SJiri Olsa 
487922db21dSArnaldo Carvalho de Melo 	if (he->srcline && he->srcline != SRCLINE_UNKNOWN) {
48826349585SJiri Olsa 		he->srcline = strdup(he->srcline);
48926349585SJiri Olsa 		if (he->srcline == NULL)
49026349585SJiri Olsa 			goto err_rawdata;
49126349585SJiri Olsa 	}
49226349585SJiri Olsa 
4934968ac8fSAndi Kleen 	if (symbol_conf.res_sample) {
4944968ac8fSAndi Kleen 		he->res_samples = calloc(sizeof(struct res_sample),
4954968ac8fSAndi Kleen 					symbol_conf.res_sample);
4964968ac8fSAndi Kleen 		if (!he->res_samples)
4974968ac8fSAndi Kleen 			goto err_srcline;
4984968ac8fSAndi Kleen 	}
4994968ac8fSAndi Kleen 
500b821c732SArnaldo Carvalho de Melo 	INIT_LIST_HEAD(&he->pairs.node);
501bffb5b0cSIan Rogers 	he->thread = thread__get(he->thread);
5022eb3d689SDavidlohr Bueso 	he->hroot_in  = RB_ROOT_CACHED;
5032eb3d689SDavidlohr Bueso 	he->hroot_out = RB_ROOT_CACHED;
504aef810ecSNamhyung Kim 
505aef810ecSNamhyung Kim 	if (!symbol_conf.report_hierarchy)
506aef810ecSNamhyung Kim 		he->leaf = true;
5070a269a6bSJiri Olsa 
5080a269a6bSJiri Olsa 	return 0;
509c5758910SJiri Olsa 
5104968ac8fSAndi Kleen err_srcline:
511d8f9da24SArnaldo Carvalho de Melo 	zfree(&he->srcline);
5124968ac8fSAndi Kleen 
51326349585SJiri Olsa err_rawdata:
514d8f9da24SArnaldo Carvalho de Melo 	zfree(&he->raw_data);
51526349585SJiri Olsa 
516c5758910SJiri Olsa err_infos:
517c5758910SJiri Olsa 	if (he->branch_info) {
518d46a4cdfSArnaldo Carvalho de Melo 		map__put(he->branch_info->from.ms.map);
519d46a4cdfSArnaldo Carvalho de Melo 		map__put(he->branch_info->to.ms.map);
520d8f9da24SArnaldo Carvalho de Melo 		zfree(&he->branch_info);
521c5758910SJiri Olsa 	}
522c5758910SJiri Olsa 	if (he->mem_info) {
523d46a4cdfSArnaldo Carvalho de Melo 		map__put(he->mem_info->iaddr.ms.map);
524d46a4cdfSArnaldo Carvalho de Melo 		map__put(he->mem_info->daddr.ms.map);
525c5758910SJiri Olsa 	}
526c5758910SJiri Olsa err:
527bffb5b0cSIan Rogers 	maps__zput(he->ms.maps);
528c5758910SJiri Olsa 	map__zput(he->ms.map);
529d8f9da24SArnaldo Carvalho de Melo 	zfree(&he->stat_acc);
530c5758910SJiri Olsa 	return -ENOMEM;
5310a269a6bSJiri Olsa }
5320a269a6bSJiri Olsa 
hist_entry__zalloc(size_t size)533f542e767SJiri Olsa static void *hist_entry__zalloc(size_t size)
534f542e767SJiri Olsa {
535f542e767SJiri Olsa 	return zalloc(size + sizeof(struct hist_entry));
536f542e767SJiri Olsa }
537f542e767SJiri Olsa 
hist_entry__free(void * ptr)538f542e767SJiri Olsa static void hist_entry__free(void *ptr)
539f542e767SJiri Olsa {
540f542e767SJiri Olsa 	free(ptr);
541f542e767SJiri Olsa }
542f542e767SJiri Olsa 
543f542e767SJiri Olsa static struct hist_entry_ops default_ops = {
544f542e767SJiri Olsa 	.new	= hist_entry__zalloc,
545f542e767SJiri Olsa 	.free	= hist_entry__free,
546f542e767SJiri Olsa };
547f542e767SJiri Olsa 
hist_entry__new(struct hist_entry * template,bool sample_self)5480a269a6bSJiri Olsa static struct hist_entry *hist_entry__new(struct hist_entry *template,
5490a269a6bSJiri Olsa 					  bool sample_self)
5500a269a6bSJiri Olsa {
551f542e767SJiri Olsa 	struct hist_entry_ops *ops = template->ops;
5520a269a6bSJiri Olsa 	size_t callchain_size = 0;
5530a269a6bSJiri Olsa 	struct hist_entry *he;
5540a269a6bSJiri Olsa 	int err = 0;
5550a269a6bSJiri Olsa 
556f542e767SJiri Olsa 	if (!ops)
557f542e767SJiri Olsa 		ops = template->ops = &default_ops;
558f542e767SJiri Olsa 
5590a269a6bSJiri Olsa 	if (symbol_conf.use_callchain)
5600a269a6bSJiri Olsa 		callchain_size = sizeof(struct callchain_root);
5610a269a6bSJiri Olsa 
562f542e767SJiri Olsa 	he = ops->new(callchain_size);
5630a269a6bSJiri Olsa 	if (he) {
56441477acfSArnaldo Carvalho de Melo 		err = hist_entry__init(he, template, sample_self, callchain_size);
565f542e767SJiri Olsa 		if (err) {
566f542e767SJiri Olsa 			ops->free(he);
567f542e767SJiri Olsa 			he = NULL;
568f542e767SJiri Olsa 		}
56928e2a106SArnaldo Carvalho de Melo 	}
57028e2a106SArnaldo Carvalho de Melo 
57112c14278SArnaldo Carvalho de Melo 	return he;
57228e2a106SArnaldo Carvalho de Melo }
57328e2a106SArnaldo Carvalho de Melo 
symbol__parent_filter(const struct symbol * parent)5747a007ca9SArnaldo Carvalho de Melo static u8 symbol__parent_filter(const struct symbol *parent)
5757a007ca9SArnaldo Carvalho de Melo {
5767a007ca9SArnaldo Carvalho de Melo 	if (symbol_conf.exclude_other && parent == NULL)
5777a007ca9SArnaldo Carvalho de Melo 		return 1 << HIST_FILTER__PARENT;
5787a007ca9SArnaldo Carvalho de Melo 	return 0;
5797a007ca9SArnaldo Carvalho de Melo }
5807a007ca9SArnaldo Carvalho de Melo 
hist_entry__add_callchain_period(struct hist_entry * he,u64 period)581467ef10cSNamhyung Kim static void hist_entry__add_callchain_period(struct hist_entry *he, u64 period)
582467ef10cSNamhyung Kim {
583fabd37b8SArnaldo Carvalho de Melo 	if (!hist_entry__has_callchains(he) || !symbol_conf.use_callchain)
584467ef10cSNamhyung Kim 		return;
585467ef10cSNamhyung Kim 
586467ef10cSNamhyung Kim 	he->hists->callchain_period += period;
587467ef10cSNamhyung Kim 	if (!he->filtered)
588467ef10cSNamhyung Kim 		he->hists->callchain_non_filtered_period += period;
589467ef10cSNamhyung Kim }
590467ef10cSNamhyung Kim 
hists__findnew_entry(struct hists * hists,struct hist_entry * entry,const struct addr_location * al,bool sample_self)591e7e0efcdSArnaldo Carvalho de Melo static struct hist_entry *hists__findnew_entry(struct hists *hists,
592b5387528SRoberto Agostino Vitillo 					       struct hist_entry *entry,
5930dd5041cSIan Rogers 					       const struct addr_location *al,
594a0b51af3SNamhyung Kim 					       bool sample_self)
5959735abf1SArnaldo Carvalho de Melo {
5961980c2ebSArnaldo Carvalho de Melo 	struct rb_node **p;
5979735abf1SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
5989735abf1SArnaldo Carvalho de Melo 	struct hist_entry *he;
599354cc40eSAndi Kleen 	int64_t cmp;
600f1cbf78dSNamhyung Kim 	u64 period = entry->stat.period;
6012eb3d689SDavidlohr Bueso 	bool leftmost = true;
6029735abf1SArnaldo Carvalho de Melo 
6032eb3d689SDavidlohr Bueso 	p = &hists->entries_in->rb_root.rb_node;
6041980c2ebSArnaldo Carvalho de Melo 
6059735abf1SArnaldo Carvalho de Melo 	while (*p != NULL) {
6069735abf1SArnaldo Carvalho de Melo 		parent = *p;
6071980c2ebSArnaldo Carvalho de Melo 		he = rb_entry(parent, struct hist_entry, rb_node_in);
6089735abf1SArnaldo Carvalho de Melo 
6099afcf930SNamhyung Kim 		/*
6109afcf930SNamhyung Kim 		 * Make sure that it receives arguments in a same order as
6119afcf930SNamhyung Kim 		 * hist_entry__collapse() so that we can use an appropriate
6129afcf930SNamhyung Kim 		 * function when searching an entry regardless which sort
6139afcf930SNamhyung Kim 		 * keys were used.
6149afcf930SNamhyung Kim 		 */
6159afcf930SNamhyung Kim 		cmp = hist_entry__cmp(he, entry);
6169735abf1SArnaldo Carvalho de Melo 		if (!cmp) {
6170f58474eSNamhyung Kim 			if (sample_self) {
618db4b2840SNamhyung Kim 				he_stat__add_period(&he->stat, period);
619467ef10cSNamhyung Kim 				hist_entry__add_callchain_period(he, period);
6200f58474eSNamhyung Kim 			}
621f8be1c8cSNamhyung Kim 			if (symbol_conf.cumulate_callchain)
622db4b2840SNamhyung Kim 				he_stat__add_period(he->stat_acc, period);
62363fa471dSDavid Miller 
624ceb2acbcSNamhyung Kim 			/*
625e80faac0SArnaldo Carvalho de Melo 			 * This mem info was allocated from sample__resolve_mem
626ceb2acbcSNamhyung Kim 			 * and will not be used anymore.
627ceb2acbcSNamhyung Kim 			 */
6289f87498fSJiri Olsa 			mem_info__zput(entry->mem_info);
629ceb2acbcSNamhyung Kim 
630fe96245cSJin Yao 			block_info__zput(entry->block_info);
631fe96245cSJin Yao 
632f1e8f259SLeo Yan 			kvm_info__zput(entry->kvm_info);
633f1e8f259SLeo Yan 
63463fa471dSDavid Miller 			/* If the map of an existing hist_entry has
63563fa471dSDavid Miller 			 * become out-of-date due to an exec() or
63663fa471dSDavid Miller 			 * similar, update it.  Otherwise we will
63763fa471dSDavid Miller 			 * mis-adjust symbol addresses when computing
63863fa471dSDavid Miller 			 * the history counter to increment.
63963fa471dSDavid Miller 			 */
64063fa471dSDavid Miller 			if (he->ms.map != entry->ms.map) {
6415c24b67aSArnaldo Carvalho de Melo 				map__put(he->ms.map);
6425c24b67aSArnaldo Carvalho de Melo 				he->ms.map = map__get(entry->ms.map);
64363fa471dSDavid Miller 			}
64428e2a106SArnaldo Carvalho de Melo 			goto out;
6459735abf1SArnaldo Carvalho de Melo 		}
6469735abf1SArnaldo Carvalho de Melo 
6479735abf1SArnaldo Carvalho de Melo 		if (cmp < 0)
6489735abf1SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
6492eb3d689SDavidlohr Bueso 		else {
6509735abf1SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
6512eb3d689SDavidlohr Bueso 			leftmost = false;
6522eb3d689SDavidlohr Bueso 		}
6539735abf1SArnaldo Carvalho de Melo 	}
6549735abf1SArnaldo Carvalho de Melo 
655a0b51af3SNamhyung Kim 	he = hist_entry__new(entry, sample_self);
6569735abf1SArnaldo Carvalho de Melo 	if (!he)
65727a0dcb7SNamhyung Kim 		return NULL;
6581980c2ebSArnaldo Carvalho de Melo 
6590f58474eSNamhyung Kim 	if (sample_self)
660467ef10cSNamhyung Kim 		hist_entry__add_callchain_period(he, period);
661590cd344SNamhyung Kim 	hists->nr_entries++;
662590cd344SNamhyung Kim 
6631980c2ebSArnaldo Carvalho de Melo 	rb_link_node(&he->rb_node_in, parent, p);
6642eb3d689SDavidlohr Bueso 	rb_insert_color_cached(&he->rb_node_in, hists->entries_in, leftmost);
66528e2a106SArnaldo Carvalho de Melo out:
666a0b51af3SNamhyung Kim 	if (sample_self)
667f39056f9SNamhyung Kim 		he_stat__add_cpumode_period(&he->stat, al->cpumode, period);
668f8be1c8cSNamhyung Kim 	if (symbol_conf.cumulate_callchain)
669f8be1c8cSNamhyung Kim 		he_stat__add_cpumode_period(he->stat_acc, al->cpumode, period);
6709735abf1SArnaldo Carvalho de Melo 	return he;
6719735abf1SArnaldo Carvalho de Melo }
6729735abf1SArnaldo Carvalho de Melo 
random_max(unsigned high)6734968ac8fSAndi Kleen static unsigned random_max(unsigned high)
6744968ac8fSAndi Kleen {
6754968ac8fSAndi Kleen 	unsigned thresh = -high % high;
6764968ac8fSAndi Kleen 	for (;;) {
6774968ac8fSAndi Kleen 		unsigned r = random();
6784968ac8fSAndi Kleen 		if (r >= thresh)
6794968ac8fSAndi Kleen 			return r % high;
6804968ac8fSAndi Kleen 	}
6814968ac8fSAndi Kleen }
6824968ac8fSAndi Kleen 
hists__res_sample(struct hist_entry * he,struct perf_sample * sample)6834968ac8fSAndi Kleen static void hists__res_sample(struct hist_entry *he, struct perf_sample *sample)
6844968ac8fSAndi Kleen {
6854968ac8fSAndi Kleen 	struct res_sample *r;
6864968ac8fSAndi Kleen 	int j;
6874968ac8fSAndi Kleen 
6884968ac8fSAndi Kleen 	if (he->num_res < symbol_conf.res_sample) {
6894968ac8fSAndi Kleen 		j = he->num_res++;
6904968ac8fSAndi Kleen 	} else {
6914968ac8fSAndi Kleen 		j = random_max(symbol_conf.res_sample);
6924968ac8fSAndi Kleen 	}
6934968ac8fSAndi Kleen 	r = &he->res_samples[j];
6944968ac8fSAndi Kleen 	r->time = sample->time;
6954968ac8fSAndi Kleen 	r->cpu = sample->cpu;
6964968ac8fSAndi Kleen 	r->tid = sample->tid;
6974968ac8fSAndi Kleen }
6984968ac8fSAndi Kleen 
699a5051979SJiri Olsa static struct hist_entry*
__hists__add_entry(struct hists * hists,struct addr_location * al,struct symbol * sym_parent,struct branch_info * bi,struct mem_info * mi,struct kvm_info * ki,struct block_info * block_info,struct perf_sample * sample,bool sample_self,struct hist_entry_ops * ops)700a5051979SJiri Olsa __hists__add_entry(struct hists *hists,
701b5387528SRoberto Agostino Vitillo 		   struct addr_location *al,
702b5387528SRoberto Agostino Vitillo 		   struct symbol *sym_parent,
703b5387528SRoberto Agostino Vitillo 		   struct branch_info *bi,
70441a4e6e2SNamhyung Kim 		   struct mem_info *mi,
705ebf39d29SLeo Yan 		   struct kvm_info *ki,
706fe96245cSJin Yao 		   struct block_info *block_info,
707fd36f3ddSNamhyung Kim 		   struct perf_sample *sample,
708a5051979SJiri Olsa 		   bool sample_self,
709a5051979SJiri Olsa 		   struct hist_entry_ops *ops)
710b5387528SRoberto Agostino Vitillo {
711d890a98cSHari Bathini 	struct namespaces *ns = thread__namespaces(al->thread);
712b5387528SRoberto Agostino Vitillo 	struct hist_entry entry = {
713b5387528SRoberto Agostino Vitillo 		.thread	= al->thread,
7144dfced35SNamhyung Kim 		.comm = thread__comm(al->thread),
715d890a98cSHari Bathini 		.cgroup_id = {
716d890a98cSHari Bathini 			.dev = ns ? ns->link_info[CGROUP_NS_INDEX].dev : 0,
717d890a98cSHari Bathini 			.ino = ns ? ns->link_info[CGROUP_NS_INDEX].ino : 0,
718d890a98cSHari Bathini 		},
719b629f3e9SNamhyung Kim 		.cgroup = sample->cgroup,
720b5387528SRoberto Agostino Vitillo 		.ms = {
721f2eaea09SArnaldo Carvalho de Melo 			.maps	= al->maps,
722b5387528SRoberto Agostino Vitillo 			.map	= al->map,
723b5387528SRoberto Agostino Vitillo 			.sym	= al->sym,
724b5387528SRoberto Agostino Vitillo 		},
72526349585SJiri Olsa 		.srcline = (char *) al->srcline,
7260c4c4debSKan Liang 		.socket	 = al->socket,
727b5387528SRoberto Agostino Vitillo 		.cpu	 = al->cpu,
7287365be55SDon Zickus 		.cpumode = al->cpumode,
729b5387528SRoberto Agostino Vitillo 		.ip	 = al->addr,
730b5387528SRoberto Agostino Vitillo 		.level	 = al->level,
7319fd74f20SStephane Eranian 		.code_page_size = sample->code_page_size,
732b24c28f7SNamhyung Kim 		.stat = {
733c4b35351SNamhyung Kim 			.nr_events = 1,
734fd36f3ddSNamhyung Kim 			.period	= sample->period,
735b24c28f7SNamhyung Kim 		},
736b5387528SRoberto Agostino Vitillo 		.parent = sym_parent,
7372c86c7caSNamhyung Kim 		.filtered = symbol__parent_filter(sym_parent) | al->filtered,
738c824c433SArnaldo Carvalho de Melo 		.hists	= hists,
73941a4e6e2SNamhyung Kim 		.branch_info = bi,
74041a4e6e2SNamhyung Kim 		.mem_info = mi,
741ebf39d29SLeo Yan 		.kvm_info = ki,
742fe96245cSJin Yao 		.block_info = block_info,
743fd36f3ddSNamhyung Kim 		.transaction = sample->transaction,
74472392834SNamhyung Kim 		.raw_data = sample->raw_data,
74572392834SNamhyung Kim 		.raw_size = sample->raw_size,
746a5051979SJiri Olsa 		.ops = ops,
7473723908dSAndi Kleen 		.time = hist_time(sample->time),
748784e8addSNamhyung Kim 		.weight = sample->weight,
7494d03c753SNamhyung Kim 		.ins_lat = sample->ins_lat,
750db4b2840SNamhyung Kim 		.p_stage_cyc = sample->p_stage_cyc,
751ea15483eSGerman Gomez 		.simd_flags = sample->simd_flags,
752c9d36628SArnaldo Carvalho de Melo 	}, *he = hists__findnew_entry(hists, &entry, al, sample_self);
753b5387528SRoberto Agostino Vitillo 
754c9d36628SArnaldo Carvalho de Melo 	if (!hists->has_callchains && he && he->callchain_size != 0)
755c9d36628SArnaldo Carvalho de Melo 		hists->has_callchains = true;
7564968ac8fSAndi Kleen 	if (he && symbol_conf.res_sample)
7574968ac8fSAndi Kleen 		hists__res_sample(he, sample);
758c9d36628SArnaldo Carvalho de Melo 	return he;
759b5387528SRoberto Agostino Vitillo }
760b5387528SRoberto Agostino Vitillo 
hists__add_entry(struct hists * hists,struct addr_location * al,struct symbol * sym_parent,struct branch_info * bi,struct mem_info * mi,struct kvm_info * ki,struct perf_sample * sample,bool sample_self)761a5051979SJiri Olsa struct hist_entry *hists__add_entry(struct hists *hists,
762a5051979SJiri Olsa 				    struct addr_location *al,
763a5051979SJiri Olsa 				    struct symbol *sym_parent,
764a5051979SJiri Olsa 				    struct branch_info *bi,
765a5051979SJiri Olsa 				    struct mem_info *mi,
766ebf39d29SLeo Yan 				    struct kvm_info *ki,
767a5051979SJiri Olsa 				    struct perf_sample *sample,
768a5051979SJiri Olsa 				    bool sample_self)
769a5051979SJiri Olsa {
770ebf39d29SLeo Yan 	return __hists__add_entry(hists, al, sym_parent, bi, mi, ki, NULL,
771a5051979SJiri Olsa 				  sample, sample_self, NULL);
772a5051979SJiri Olsa }
773a5051979SJiri Olsa 
hists__add_entry_ops(struct hists * hists,struct hist_entry_ops * ops,struct addr_location * al,struct symbol * sym_parent,struct branch_info * bi,struct mem_info * mi,struct kvm_info * ki,struct perf_sample * sample,bool sample_self)774a5051979SJiri Olsa struct hist_entry *hists__add_entry_ops(struct hists *hists,
775a5051979SJiri Olsa 					struct hist_entry_ops *ops,
776a5051979SJiri Olsa 					struct addr_location *al,
777a5051979SJiri Olsa 					struct symbol *sym_parent,
778a5051979SJiri Olsa 					struct branch_info *bi,
779a5051979SJiri Olsa 					struct mem_info *mi,
780ebf39d29SLeo Yan 					struct kvm_info *ki,
781a5051979SJiri Olsa 					struct perf_sample *sample,
782a5051979SJiri Olsa 					bool sample_self)
783a5051979SJiri Olsa {
784ebf39d29SLeo Yan 	return __hists__add_entry(hists, al, sym_parent, bi, mi, ki, NULL,
785a5051979SJiri Olsa 				  sample, sample_self, ops);
786a5051979SJiri Olsa }
787a5051979SJiri Olsa 
hists__add_entry_block(struct hists * hists,struct addr_location * al,struct block_info * block_info)788fe96245cSJin Yao struct hist_entry *hists__add_entry_block(struct hists *hists,
789fe96245cSJin Yao 					  struct addr_location *al,
790fe96245cSJin Yao 					  struct block_info *block_info)
791fe96245cSJin Yao {
792fe96245cSJin Yao 	struct hist_entry entry = {
793fe96245cSJin Yao 		.block_info = block_info,
794fe96245cSJin Yao 		.hists = hists,
795b65a7d37SJin Yao 		.ms = {
796f2eaea09SArnaldo Carvalho de Melo 			.maps = al->maps,
797b65a7d37SJin Yao 			.map = al->map,
798b65a7d37SJin Yao 			.sym = al->sym,
799b65a7d37SJin Yao 		},
800fe96245cSJin Yao 	}, *he = hists__findnew_entry(hists, &entry, al, false);
801fe96245cSJin Yao 
802fe96245cSJin Yao 	return he;
803fe96245cSJin Yao }
804fe96245cSJin Yao 
80569bcb019SNamhyung Kim static int
iter_next_nop_entry(struct hist_entry_iter * iter __maybe_unused,struct addr_location * al __maybe_unused)80669bcb019SNamhyung Kim iter_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
80769bcb019SNamhyung Kim 		    struct addr_location *al __maybe_unused)
80869bcb019SNamhyung Kim {
80969bcb019SNamhyung Kim 	return 0;
81069bcb019SNamhyung Kim }
81169bcb019SNamhyung Kim 
81269bcb019SNamhyung Kim static int
iter_add_next_nop_entry(struct hist_entry_iter * iter __maybe_unused,struct addr_location * al __maybe_unused)81369bcb019SNamhyung Kim iter_add_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
81469bcb019SNamhyung Kim 			struct addr_location *al __maybe_unused)
81569bcb019SNamhyung Kim {
81669bcb019SNamhyung Kim 	return 0;
81769bcb019SNamhyung Kim }
81869bcb019SNamhyung Kim 
81969bcb019SNamhyung Kim static int
iter_prepare_mem_entry(struct hist_entry_iter * iter,struct addr_location * al)82069bcb019SNamhyung Kim iter_prepare_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
82169bcb019SNamhyung Kim {
82269bcb019SNamhyung Kim 	struct perf_sample *sample = iter->sample;
82369bcb019SNamhyung Kim 	struct mem_info *mi;
82469bcb019SNamhyung Kim 
82569bcb019SNamhyung Kim 	mi = sample__resolve_mem(sample, al);
82669bcb019SNamhyung Kim 	if (mi == NULL)
82769bcb019SNamhyung Kim 		return -ENOMEM;
82869bcb019SNamhyung Kim 
82969bcb019SNamhyung Kim 	iter->priv = mi;
83069bcb019SNamhyung Kim 	return 0;
83169bcb019SNamhyung Kim }
83269bcb019SNamhyung Kim 
83369bcb019SNamhyung Kim static int
iter_add_single_mem_entry(struct hist_entry_iter * iter,struct addr_location * al)83469bcb019SNamhyung Kim iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
83569bcb019SNamhyung Kim {
83669bcb019SNamhyung Kim 	u64 cost;
83769bcb019SNamhyung Kim 	struct mem_info *mi = iter->priv;
8384ea062edSArnaldo Carvalho de Melo 	struct hists *hists = evsel__hists(iter->evsel);
839fd36f3ddSNamhyung Kim 	struct perf_sample *sample = iter->sample;
84069bcb019SNamhyung Kim 	struct hist_entry *he;
84169bcb019SNamhyung Kim 
84269bcb019SNamhyung Kim 	if (mi == NULL)
84369bcb019SNamhyung Kim 		return -EINVAL;
84469bcb019SNamhyung Kim 
845fd36f3ddSNamhyung Kim 	cost = sample->weight;
84669bcb019SNamhyung Kim 	if (!cost)
84769bcb019SNamhyung Kim 		cost = 1;
84869bcb019SNamhyung Kim 
84969bcb019SNamhyung Kim 	/*
85069bcb019SNamhyung Kim 	 * must pass period=weight in order to get the correct
85169bcb019SNamhyung Kim 	 * sorting from hists__collapse_resort() which is solely
85269bcb019SNamhyung Kim 	 * based on periods. We want sorting be done on nr_events * weight
85369bcb019SNamhyung Kim 	 * and this is indirectly achieved by passing period=weight here
85469bcb019SNamhyung Kim 	 * and the he_stat__add_period() function.
85569bcb019SNamhyung Kim 	 */
856fd36f3ddSNamhyung Kim 	sample->period = cost;
857fd36f3ddSNamhyung Kim 
858ebf39d29SLeo Yan 	he = hists__add_entry(hists, al, iter->parent, NULL, mi, NULL,
859fd36f3ddSNamhyung Kim 			      sample, true);
86069bcb019SNamhyung Kim 	if (!he)
86169bcb019SNamhyung Kim 		return -ENOMEM;
86269bcb019SNamhyung Kim 
86369bcb019SNamhyung Kim 	iter->he = he;
86469bcb019SNamhyung Kim 	return 0;
86569bcb019SNamhyung Kim }
86669bcb019SNamhyung Kim 
86769bcb019SNamhyung Kim static int
iter_finish_mem_entry(struct hist_entry_iter * iter,struct addr_location * al __maybe_unused)8689d3c02d7SNamhyung Kim iter_finish_mem_entry(struct hist_entry_iter *iter,
8699d3c02d7SNamhyung Kim 		      struct addr_location *al __maybe_unused)
87069bcb019SNamhyung Kim {
87132dcd021SJiri Olsa 	struct evsel *evsel = iter->evsel;
8724ea062edSArnaldo Carvalho de Melo 	struct hists *hists = evsel__hists(evsel);
87369bcb019SNamhyung Kim 	struct hist_entry *he = iter->he;
87469bcb019SNamhyung Kim 	int err = -EINVAL;
87569bcb019SNamhyung Kim 
87669bcb019SNamhyung Kim 	if (he == NULL)
87769bcb019SNamhyung Kim 		goto out;
87869bcb019SNamhyung Kim 
8794ea062edSArnaldo Carvalho de Melo 	hists__inc_nr_samples(hists, he->filtered);
88069bcb019SNamhyung Kim 
88169bcb019SNamhyung Kim 	err = hist_entry__append_callchain(he, iter->sample);
88269bcb019SNamhyung Kim 
88369bcb019SNamhyung Kim out:
88469bcb019SNamhyung Kim 	/*
885e7e0efcdSArnaldo Carvalho de Melo 	 * We don't need to free iter->priv (mem_info) here since the mem info
886e7e0efcdSArnaldo Carvalho de Melo 	 * was either already freed in hists__findnew_entry() or passed to a
887e7e0efcdSArnaldo Carvalho de Melo 	 * new hist entry by hist_entry__new().
88869bcb019SNamhyung Kim 	 */
88969bcb019SNamhyung Kim 	iter->priv = NULL;
89069bcb019SNamhyung Kim 
89169bcb019SNamhyung Kim 	iter->he = NULL;
89269bcb019SNamhyung Kim 	return err;
89369bcb019SNamhyung Kim }
89469bcb019SNamhyung Kim 
89569bcb019SNamhyung Kim static int
iter_prepare_branch_entry(struct hist_entry_iter * iter,struct addr_location * al)89669bcb019SNamhyung Kim iter_prepare_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
89769bcb019SNamhyung Kim {
89869bcb019SNamhyung Kim 	struct branch_info *bi;
89969bcb019SNamhyung Kim 	struct perf_sample *sample = iter->sample;
90069bcb019SNamhyung Kim 
90169bcb019SNamhyung Kim 	bi = sample__resolve_bstack(sample, al);
90269bcb019SNamhyung Kim 	if (!bi)
90369bcb019SNamhyung Kim 		return -ENOMEM;
90469bcb019SNamhyung Kim 
90569bcb019SNamhyung Kim 	iter->curr = 0;
90669bcb019SNamhyung Kim 	iter->total = sample->branch_stack->nr;
90769bcb019SNamhyung Kim 
90869bcb019SNamhyung Kim 	iter->priv = bi;
90969bcb019SNamhyung Kim 	return 0;
91069bcb019SNamhyung Kim }
91169bcb019SNamhyung Kim 
91269bcb019SNamhyung Kim static int
iter_add_single_branch_entry(struct hist_entry_iter * iter __maybe_unused,struct addr_location * al __maybe_unused)9132d78b189SJin Yao iter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused,
91469bcb019SNamhyung Kim 			     struct addr_location *al __maybe_unused)
91569bcb019SNamhyung Kim {
91669bcb019SNamhyung Kim 	return 0;
91769bcb019SNamhyung Kim }
91869bcb019SNamhyung Kim 
91969bcb019SNamhyung Kim static int
iter_next_branch_entry(struct hist_entry_iter * iter,struct addr_location * al)92069bcb019SNamhyung Kim iter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
92169bcb019SNamhyung Kim {
92269bcb019SNamhyung Kim 	struct branch_info *bi = iter->priv;
92369bcb019SNamhyung Kim 	int i = iter->curr;
92469bcb019SNamhyung Kim 
92569bcb019SNamhyung Kim 	if (bi == NULL)
92669bcb019SNamhyung Kim 		return 0;
92769bcb019SNamhyung Kim 
92869bcb019SNamhyung Kim 	if (iter->curr >= iter->total)
92969bcb019SNamhyung Kim 		return 0;
93069bcb019SNamhyung Kim 
9310dd5041cSIan Rogers 	maps__put(al->maps);
9320dd5041cSIan Rogers 	al->maps = maps__get(bi[i].to.ms.maps);
9330dd5041cSIan Rogers 	map__put(al->map);
9340dd5041cSIan Rogers 	al->map = map__get(bi[i].to.ms.map);
935d46a4cdfSArnaldo Carvalho de Melo 	al->sym = bi[i].to.ms.sym;
93669bcb019SNamhyung Kim 	al->addr = bi[i].to.addr;
93769bcb019SNamhyung Kim 	return 1;
93869bcb019SNamhyung Kim }
93969bcb019SNamhyung Kim 
94069bcb019SNamhyung Kim static int
iter_add_next_branch_entry(struct hist_entry_iter * iter,struct addr_location * al)94169bcb019SNamhyung Kim iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
94269bcb019SNamhyung Kim {
9439d3c02d7SNamhyung Kim 	struct branch_info *bi;
94432dcd021SJiri Olsa 	struct evsel *evsel = iter->evsel;
9454ea062edSArnaldo Carvalho de Melo 	struct hists *hists = evsel__hists(evsel);
946fd36f3ddSNamhyung Kim 	struct perf_sample *sample = iter->sample;
94769bcb019SNamhyung Kim 	struct hist_entry *he = NULL;
94869bcb019SNamhyung Kim 	int i = iter->curr;
94969bcb019SNamhyung Kim 	int err = 0;
95069bcb019SNamhyung Kim 
95169bcb019SNamhyung Kim 	bi = iter->priv;
95269bcb019SNamhyung Kim 
953d46a4cdfSArnaldo Carvalho de Melo 	if (iter->hide_unresolved && !(bi[i].from.ms.sym && bi[i].to.ms.sym))
95469bcb019SNamhyung Kim 		goto out;
95569bcb019SNamhyung Kim 
95669bcb019SNamhyung Kim 	/*
95769bcb019SNamhyung Kim 	 * The report shows the percentage of total branches captured
95869bcb019SNamhyung Kim 	 * and not events sampled. Thus we use a pseudo period of 1.
95969bcb019SNamhyung Kim 	 */
960fd36f3ddSNamhyung Kim 	sample->period = 1;
961fd36f3ddSNamhyung Kim 	sample->weight = bi->flags.cycles ? bi->flags.cycles : 1;
962fd36f3ddSNamhyung Kim 
963ebf39d29SLeo Yan 	he = hists__add_entry(hists, al, iter->parent, &bi[i], NULL, NULL,
964fd36f3ddSNamhyung Kim 			      sample, true);
96569bcb019SNamhyung Kim 	if (he == NULL)
96669bcb019SNamhyung Kim 		return -ENOMEM;
96769bcb019SNamhyung Kim 
9684ea062edSArnaldo Carvalho de Melo 	hists__inc_nr_samples(hists, he->filtered);
96969bcb019SNamhyung Kim 
97069bcb019SNamhyung Kim out:
97169bcb019SNamhyung Kim 	iter->he = he;
97269bcb019SNamhyung Kim 	iter->curr++;
97369bcb019SNamhyung Kim 	return err;
97469bcb019SNamhyung Kim }
97569bcb019SNamhyung Kim 
97669bcb019SNamhyung Kim static int
iter_finish_branch_entry(struct hist_entry_iter * iter,struct addr_location * al __maybe_unused)97769bcb019SNamhyung Kim iter_finish_branch_entry(struct hist_entry_iter *iter,
97869bcb019SNamhyung Kim 			 struct addr_location *al __maybe_unused)
97969bcb019SNamhyung Kim {
98069bcb019SNamhyung Kim 	zfree(&iter->priv);
98169bcb019SNamhyung Kim 	iter->he = NULL;
98269bcb019SNamhyung Kim 
98369bcb019SNamhyung Kim 	return iter->curr >= iter->total ? 0 : -1;
98469bcb019SNamhyung Kim }
98569bcb019SNamhyung Kim 
98669bcb019SNamhyung Kim static int
iter_prepare_normal_entry(struct hist_entry_iter * iter __maybe_unused,struct addr_location * al __maybe_unused)98769bcb019SNamhyung Kim iter_prepare_normal_entry(struct hist_entry_iter *iter __maybe_unused,
98869bcb019SNamhyung Kim 			  struct addr_location *al __maybe_unused)
98969bcb019SNamhyung Kim {
99069bcb019SNamhyung Kim 	return 0;
99169bcb019SNamhyung Kim }
99269bcb019SNamhyung Kim 
99369bcb019SNamhyung Kim static int
iter_add_single_normal_entry(struct hist_entry_iter * iter,struct addr_location * al)99469bcb019SNamhyung Kim iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location *al)
99569bcb019SNamhyung Kim {
99632dcd021SJiri Olsa 	struct evsel *evsel = iter->evsel;
99769bcb019SNamhyung Kim 	struct perf_sample *sample = iter->sample;
99869bcb019SNamhyung Kim 	struct hist_entry *he;
99969bcb019SNamhyung Kim 
10000102ef3eSJiri Olsa 	he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
1001ebf39d29SLeo Yan 			      NULL, sample, true);
100269bcb019SNamhyung Kim 	if (he == NULL)
100369bcb019SNamhyung Kim 		return -ENOMEM;
100469bcb019SNamhyung Kim 
100569bcb019SNamhyung Kim 	iter->he = he;
100669bcb019SNamhyung Kim 	return 0;
100769bcb019SNamhyung Kim }
100869bcb019SNamhyung Kim 
100969bcb019SNamhyung Kim static int
iter_finish_normal_entry(struct hist_entry_iter * iter,struct addr_location * al __maybe_unused)10109d3c02d7SNamhyung Kim iter_finish_normal_entry(struct hist_entry_iter *iter,
10119d3c02d7SNamhyung Kim 			 struct addr_location *al __maybe_unused)
101269bcb019SNamhyung Kim {
101369bcb019SNamhyung Kim 	struct hist_entry *he = iter->he;
101432dcd021SJiri Olsa 	struct evsel *evsel = iter->evsel;
101569bcb019SNamhyung Kim 	struct perf_sample *sample = iter->sample;
101669bcb019SNamhyung Kim 
101769bcb019SNamhyung Kim 	if (he == NULL)
101869bcb019SNamhyung Kim 		return 0;
101969bcb019SNamhyung Kim 
102069bcb019SNamhyung Kim 	iter->he = NULL;
102169bcb019SNamhyung Kim 
10224ea062edSArnaldo Carvalho de Melo 	hists__inc_nr_samples(evsel__hists(evsel), he->filtered);
102369bcb019SNamhyung Kim 
102469bcb019SNamhyung Kim 	return hist_entry__append_callchain(he, sample);
102569bcb019SNamhyung Kim }
102669bcb019SNamhyung Kim 
10277a13aa28SNamhyung Kim static int
iter_prepare_cumulative_entry(struct hist_entry_iter * iter,struct addr_location * al __maybe_unused)102896b40f3cSAdrian Hunter iter_prepare_cumulative_entry(struct hist_entry_iter *iter,
10297a13aa28SNamhyung Kim 			      struct addr_location *al __maybe_unused)
10307a13aa28SNamhyung Kim {
1031b4d3c8bdSNamhyung Kim 	struct hist_entry **he_cache;
10328ab12a20SIan Rogers 	struct callchain_cursor *cursor = get_tls_callchain_cursor();
1033b4d3c8bdSNamhyung Kim 
10348ab12a20SIan Rogers 	if (cursor == NULL)
10358ab12a20SIan Rogers 		return -ENOMEM;
10368ab12a20SIan Rogers 
10378ab12a20SIan Rogers 	callchain_cursor_commit(cursor);
1038b4d3c8bdSNamhyung Kim 
1039b4d3c8bdSNamhyung Kim 	/*
1040b4d3c8bdSNamhyung Kim 	 * This is for detecting cycles or recursions so that they're
1041b4d3c8bdSNamhyung Kim 	 * cumulated only one time to prevent entries more than 100%
1042b4d3c8bdSNamhyung Kim 	 * overhead.
1043b4d3c8bdSNamhyung Kim 	 */
10448ab12a20SIan Rogers 	he_cache = malloc(sizeof(*he_cache) * (cursor->nr + 1));
1045b4d3c8bdSNamhyung Kim 	if (he_cache == NULL)
1046b4d3c8bdSNamhyung Kim 		return -ENOMEM;
1047b4d3c8bdSNamhyung Kim 
1048b4d3c8bdSNamhyung Kim 	iter->priv = he_cache;
1049b4d3c8bdSNamhyung Kim 	iter->curr = 0;
1050b4d3c8bdSNamhyung Kim 
10517a13aa28SNamhyung Kim 	return 0;
10527a13aa28SNamhyung Kim }
10537a13aa28SNamhyung Kim 
10547a13aa28SNamhyung Kim static int
iter_add_single_cumulative_entry(struct hist_entry_iter * iter,struct addr_location * al)10557a13aa28SNamhyung Kim iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
10567a13aa28SNamhyung Kim 				 struct addr_location *al)
10577a13aa28SNamhyung Kim {
105832dcd021SJiri Olsa 	struct evsel *evsel = iter->evsel;
10594ea062edSArnaldo Carvalho de Melo 	struct hists *hists = evsel__hists(evsel);
10607a13aa28SNamhyung Kim 	struct perf_sample *sample = iter->sample;
1061b4d3c8bdSNamhyung Kim 	struct hist_entry **he_cache = iter->priv;
10627a13aa28SNamhyung Kim 	struct hist_entry *he;
10637a13aa28SNamhyung Kim 	int err = 0;
10647a13aa28SNamhyung Kim 
1065ebf39d29SLeo Yan 	he = hists__add_entry(hists, al, iter->parent, NULL, NULL, NULL,
1066fd36f3ddSNamhyung Kim 			      sample, true);
10677a13aa28SNamhyung Kim 	if (he == NULL)
10687a13aa28SNamhyung Kim 		return -ENOMEM;
10697a13aa28SNamhyung Kim 
10707a13aa28SNamhyung Kim 	iter->he = he;
1071b4d3c8bdSNamhyung Kim 	he_cache[iter->curr++] = he;
10727a13aa28SNamhyung Kim 
107382aa019eSNamhyung Kim 	hist_entry__append_callchain(he, sample);
1074be7f855aSNamhyung Kim 
1075be7f855aSNamhyung Kim 	/*
1076be7f855aSNamhyung Kim 	 * We need to re-initialize the cursor since callchain_append()
1077be7f855aSNamhyung Kim 	 * advanced the cursor to the end.
1078be7f855aSNamhyung Kim 	 */
10798ab12a20SIan Rogers 	callchain_cursor_commit(get_tls_callchain_cursor());
1080be7f855aSNamhyung Kim 
10814ea062edSArnaldo Carvalho de Melo 	hists__inc_nr_samples(hists, he->filtered);
10827a13aa28SNamhyung Kim 
10837a13aa28SNamhyung Kim 	return err;
10847a13aa28SNamhyung Kim }
10857a13aa28SNamhyung Kim 
10867a13aa28SNamhyung Kim static int
iter_next_cumulative_entry(struct hist_entry_iter * iter,struct addr_location * al)10877a13aa28SNamhyung Kim iter_next_cumulative_entry(struct hist_entry_iter *iter,
10887a13aa28SNamhyung Kim 			   struct addr_location *al)
10897a13aa28SNamhyung Kim {
10907a13aa28SNamhyung Kim 	struct callchain_cursor_node *node;
10917a13aa28SNamhyung Kim 
10928ab12a20SIan Rogers 	node = callchain_cursor_current(get_tls_callchain_cursor());
10937a13aa28SNamhyung Kim 	if (node == NULL)
10947a13aa28SNamhyung Kim 		return 0;
10957a13aa28SNamhyung Kim 
1096c7405d85SNamhyung Kim 	return fill_callchain_info(al, node, iter->hide_unresolved);
10977a13aa28SNamhyung Kim }
10987a13aa28SNamhyung Kim 
109912e89e65SKan Liang static bool
hist_entry__fast__sym_diff(struct hist_entry * left,struct hist_entry * right)110012e89e65SKan Liang hist_entry__fast__sym_diff(struct hist_entry *left,
110112e89e65SKan Liang 			   struct hist_entry *right)
110212e89e65SKan Liang {
110312e89e65SKan Liang 	struct symbol *sym_l = left->ms.sym;
110412e89e65SKan Liang 	struct symbol *sym_r = right->ms.sym;
110512e89e65SKan Liang 
110612e89e65SKan Liang 	if (!sym_l && !sym_r)
110712e89e65SKan Liang 		return left->ip != right->ip;
110812e89e65SKan Liang 
110912e89e65SKan Liang 	return !!_sort__sym_cmp(sym_l, sym_r);
111012e89e65SKan Liang }
111112e89e65SKan Liang 
111212e89e65SKan Liang 
11137a13aa28SNamhyung Kim static int
iter_add_next_cumulative_entry(struct hist_entry_iter * iter,struct addr_location * al)11147a13aa28SNamhyung Kim iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
11157a13aa28SNamhyung Kim 			       struct addr_location *al)
11167a13aa28SNamhyung Kim {
111732dcd021SJiri Olsa 	struct evsel *evsel = iter->evsel;
11187a13aa28SNamhyung Kim 	struct perf_sample *sample = iter->sample;
1119b4d3c8bdSNamhyung Kim 	struct hist_entry **he_cache = iter->priv;
11207a13aa28SNamhyung Kim 	struct hist_entry *he;
1121b4d3c8bdSNamhyung Kim 	struct hist_entry he_tmp = {
11225cef8976SArnaldo Carvalho de Melo 		.hists = evsel__hists(evsel),
1123b4d3c8bdSNamhyung Kim 		.cpu = al->cpu,
1124b4d3c8bdSNamhyung Kim 		.thread = al->thread,
1125b4d3c8bdSNamhyung Kim 		.comm = thread__comm(al->thread),
1126b4d3c8bdSNamhyung Kim 		.ip = al->addr,
1127b4d3c8bdSNamhyung Kim 		.ms = {
1128f2eaea09SArnaldo Carvalho de Melo 			.maps = al->maps,
1129b4d3c8bdSNamhyung Kim 			.map = al->map,
1130b4d3c8bdSNamhyung Kim 			.sym = al->sym,
1131b4d3c8bdSNamhyung Kim 		},
113226349585SJiri Olsa 		.srcline = (char *) al->srcline,
1133b4d3c8bdSNamhyung Kim 		.parent = iter->parent,
113472392834SNamhyung Kim 		.raw_data = sample->raw_data,
113572392834SNamhyung Kim 		.raw_size = sample->raw_size,
1136b4d3c8bdSNamhyung Kim 	};
1137b4d3c8bdSNamhyung Kim 	int i;
11388ab12a20SIan Rogers 	struct callchain_cursor cursor, *tls_cursor = get_tls_callchain_cursor();
113912e89e65SKan Liang 	bool fast = hists__has(he_tmp.hists, sym);
1140be7f855aSNamhyung Kim 
11418ab12a20SIan Rogers 	if (tls_cursor == NULL)
11428ab12a20SIan Rogers 		return -ENOMEM;
1143be7f855aSNamhyung Kim 
11448ab12a20SIan Rogers 	callchain_cursor_snapshot(&cursor, tls_cursor);
11458ab12a20SIan Rogers 
11468ab12a20SIan Rogers 	callchain_cursor_advance(tls_cursor);
1147b4d3c8bdSNamhyung Kim 
1148b4d3c8bdSNamhyung Kim 	/*
1149b4d3c8bdSNamhyung Kim 	 * Check if there's duplicate entries in the callchain.
1150b4d3c8bdSNamhyung Kim 	 * It's possible that it has cycles or recursive calls.
1151b4d3c8bdSNamhyung Kim 	 */
1152b4d3c8bdSNamhyung Kim 	for (i = 0; i < iter->curr; i++) {
115312e89e65SKan Liang 		/*
115412e89e65SKan Liang 		 * For most cases, there are no duplicate entries in callchain.
115512e89e65SKan Liang 		 * The symbols are usually different. Do a quick check for
115612e89e65SKan Liang 		 * symbols first.
115712e89e65SKan Liang 		 */
115812e89e65SKan Liang 		if (fast && hist_entry__fast__sym_diff(he_cache[i], &he_tmp))
115912e89e65SKan Liang 			continue;
116012e89e65SKan Liang 
11619d3c02d7SNamhyung Kim 		if (hist_entry__cmp(he_cache[i], &he_tmp) == 0) {
11629d3c02d7SNamhyung Kim 			/* to avoid calling callback function */
11639d3c02d7SNamhyung Kim 			iter->he = NULL;
1164b4d3c8bdSNamhyung Kim 			return 0;
1165b4d3c8bdSNamhyung Kim 		}
11669d3c02d7SNamhyung Kim 	}
11677a13aa28SNamhyung Kim 
11680102ef3eSJiri Olsa 	he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
1169ebf39d29SLeo Yan 			      NULL, sample, false);
11707a13aa28SNamhyung Kim 	if (he == NULL)
11717a13aa28SNamhyung Kim 		return -ENOMEM;
11727a13aa28SNamhyung Kim 
11737a13aa28SNamhyung Kim 	iter->he = he;
1174b4d3c8bdSNamhyung Kim 	he_cache[iter->curr++] = he;
11757a13aa28SNamhyung Kim 
1176fabd37b8SArnaldo Carvalho de Melo 	if (hist_entry__has_callchains(he) && symbol_conf.use_callchain)
1177be7f855aSNamhyung Kim 		callchain_append(he->callchain, &cursor, sample->period);
11787a13aa28SNamhyung Kim 	return 0;
11797a13aa28SNamhyung Kim }
11807a13aa28SNamhyung Kim 
11817a13aa28SNamhyung Kim static int
iter_finish_cumulative_entry(struct hist_entry_iter * iter,struct addr_location * al __maybe_unused)11827a13aa28SNamhyung Kim iter_finish_cumulative_entry(struct hist_entry_iter *iter,
11837a13aa28SNamhyung Kim 			     struct addr_location *al __maybe_unused)
11847a13aa28SNamhyung Kim {
1185b4d3c8bdSNamhyung Kim 	zfree(&iter->priv);
11867a13aa28SNamhyung Kim 	iter->he = NULL;
1187b4d3c8bdSNamhyung Kim 
11887a13aa28SNamhyung Kim 	return 0;
11897a13aa28SNamhyung Kim }
11907a13aa28SNamhyung Kim 
119169bcb019SNamhyung Kim const struct hist_iter_ops hist_iter_mem = {
119269bcb019SNamhyung Kim 	.prepare_entry 		= iter_prepare_mem_entry,
119369bcb019SNamhyung Kim 	.add_single_entry 	= iter_add_single_mem_entry,
119469bcb019SNamhyung Kim 	.next_entry 		= iter_next_nop_entry,
119569bcb019SNamhyung Kim 	.add_next_entry 	= iter_add_next_nop_entry,
119669bcb019SNamhyung Kim 	.finish_entry 		= iter_finish_mem_entry,
119769bcb019SNamhyung Kim };
119869bcb019SNamhyung Kim 
119969bcb019SNamhyung Kim const struct hist_iter_ops hist_iter_branch = {
120069bcb019SNamhyung Kim 	.prepare_entry 		= iter_prepare_branch_entry,
120169bcb019SNamhyung Kim 	.add_single_entry 	= iter_add_single_branch_entry,
120269bcb019SNamhyung Kim 	.next_entry 		= iter_next_branch_entry,
120369bcb019SNamhyung Kim 	.add_next_entry 	= iter_add_next_branch_entry,
120469bcb019SNamhyung Kim 	.finish_entry 		= iter_finish_branch_entry,
120569bcb019SNamhyung Kim };
120669bcb019SNamhyung Kim 
120769bcb019SNamhyung Kim const struct hist_iter_ops hist_iter_normal = {
120869bcb019SNamhyung Kim 	.prepare_entry 		= iter_prepare_normal_entry,
120969bcb019SNamhyung Kim 	.add_single_entry 	= iter_add_single_normal_entry,
121069bcb019SNamhyung Kim 	.next_entry 		= iter_next_nop_entry,
121169bcb019SNamhyung Kim 	.add_next_entry 	= iter_add_next_nop_entry,
121269bcb019SNamhyung Kim 	.finish_entry 		= iter_finish_normal_entry,
121369bcb019SNamhyung Kim };
121469bcb019SNamhyung Kim 
12157a13aa28SNamhyung Kim const struct hist_iter_ops hist_iter_cumulative = {
12167a13aa28SNamhyung Kim 	.prepare_entry 		= iter_prepare_cumulative_entry,
12177a13aa28SNamhyung Kim 	.add_single_entry 	= iter_add_single_cumulative_entry,
12187a13aa28SNamhyung Kim 	.next_entry 		= iter_next_cumulative_entry,
12197a13aa28SNamhyung Kim 	.add_next_entry 	= iter_add_next_cumulative_entry,
12207a13aa28SNamhyung Kim 	.finish_entry 		= iter_finish_cumulative_entry,
12217a13aa28SNamhyung Kim };
12227a13aa28SNamhyung Kim 
hist_entry_iter__add(struct hist_entry_iter * iter,struct addr_location * al,int max_stack_depth,void * arg)122369bcb019SNamhyung Kim int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
12249d3c02d7SNamhyung Kim 			 int max_stack_depth, void *arg)
122569bcb019SNamhyung Kim {
122669bcb019SNamhyung Kim 	int err, err2;
12279c68ae98SKrister Johansen 	struct map *alm = NULL;
12289c68ae98SKrister Johansen 
1229362379aaSArnaldo Carvalho de Melo 	if (al)
12309c68ae98SKrister Johansen 		alm = map__get(al->map);
123169bcb019SNamhyung Kim 
12328ab12a20SIan Rogers 	err = sample__resolve_callchain(iter->sample, get_tls_callchain_cursor(), &iter->parent,
1233063bd936SNamhyung Kim 					iter->evsel, al, max_stack_depth);
1234cb6186aeSChangbin Du 	if (err) {
1235cb6186aeSChangbin Du 		map__put(alm);
123669bcb019SNamhyung Kim 		return err;
1237cb6186aeSChangbin Du 	}
123869bcb019SNamhyung Kim 
123969bcb019SNamhyung Kim 	err = iter->ops->prepare_entry(iter, al);
124069bcb019SNamhyung Kim 	if (err)
124169bcb019SNamhyung Kim 		goto out;
124269bcb019SNamhyung Kim 
124369bcb019SNamhyung Kim 	err = iter->ops->add_single_entry(iter, al);
124469bcb019SNamhyung Kim 	if (err)
124569bcb019SNamhyung Kim 		goto out;
124669bcb019SNamhyung Kim 
12479d3c02d7SNamhyung Kim 	if (iter->he && iter->add_entry_cb) {
12489d3c02d7SNamhyung Kim 		err = iter->add_entry_cb(iter, al, true, arg);
12499d3c02d7SNamhyung Kim 		if (err)
12509d3c02d7SNamhyung Kim 			goto out;
12519d3c02d7SNamhyung Kim 	}
12529d3c02d7SNamhyung Kim 
125369bcb019SNamhyung Kim 	while (iter->ops->next_entry(iter, al)) {
125469bcb019SNamhyung Kim 		err = iter->ops->add_next_entry(iter, al);
125569bcb019SNamhyung Kim 		if (err)
125669bcb019SNamhyung Kim 			break;
12579d3c02d7SNamhyung Kim 
12589d3c02d7SNamhyung Kim 		if (iter->he && iter->add_entry_cb) {
12599d3c02d7SNamhyung Kim 			err = iter->add_entry_cb(iter, al, false, arg);
12609d3c02d7SNamhyung Kim 			if (err)
12619d3c02d7SNamhyung Kim 				goto out;
12629d3c02d7SNamhyung Kim 		}
126369bcb019SNamhyung Kim 	}
126469bcb019SNamhyung Kim 
126569bcb019SNamhyung Kim out:
126669bcb019SNamhyung Kim 	err2 = iter->ops->finish_entry(iter, al);
126769bcb019SNamhyung Kim 	if (!err)
126869bcb019SNamhyung Kim 		err = err2;
126969bcb019SNamhyung Kim 
12709c68ae98SKrister Johansen 	map__put(alm);
12719c68ae98SKrister Johansen 
127269bcb019SNamhyung Kim 	return err;
127369bcb019SNamhyung Kim }
127469bcb019SNamhyung Kim 
12753d1d07ecSJohn Kacur int64_t
hist_entry__cmp(struct hist_entry * left,struct hist_entry * right)12763d1d07ecSJohn Kacur hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
12773d1d07ecSJohn Kacur {
1278aa6f50afSJiri Olsa 	struct hists *hists = left->hists;
1279093f0ef3SNamhyung Kim 	struct perf_hpp_fmt *fmt;
12803d1d07ecSJohn Kacur 	int64_t cmp = 0;
12813d1d07ecSJohn Kacur 
1282aa6f50afSJiri Olsa 	hists__for_each_sort_list(hists, fmt) {
128384b6ee8eSNamhyung Kim 		if (perf_hpp__is_dynamic_entry(fmt) &&
128484b6ee8eSNamhyung Kim 		    !perf_hpp__defined_dynamic_entry(fmt, hists))
128584b6ee8eSNamhyung Kim 			continue;
128684b6ee8eSNamhyung Kim 
128787bbdf76SNamhyung Kim 		cmp = fmt->cmp(fmt, left, right);
12883d1d07ecSJohn Kacur 		if (cmp)
12893d1d07ecSJohn Kacur 			break;
12903d1d07ecSJohn Kacur 	}
12913d1d07ecSJohn Kacur 
12923d1d07ecSJohn Kacur 	return cmp;
12933d1d07ecSJohn Kacur }
12943d1d07ecSJohn Kacur 
12953d1d07ecSJohn Kacur int64_t
hist_entry__collapse(struct hist_entry * left,struct hist_entry * right)12963d1d07ecSJohn Kacur hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
12973d1d07ecSJohn Kacur {
1298aa6f50afSJiri Olsa 	struct hists *hists = left->hists;
1299093f0ef3SNamhyung Kim 	struct perf_hpp_fmt *fmt;
13003d1d07ecSJohn Kacur 	int64_t cmp = 0;
13013d1d07ecSJohn Kacur 
1302aa6f50afSJiri Olsa 	hists__for_each_sort_list(hists, fmt) {
130384b6ee8eSNamhyung Kim 		if (perf_hpp__is_dynamic_entry(fmt) &&
130484b6ee8eSNamhyung Kim 		    !perf_hpp__defined_dynamic_entry(fmt, hists))
130584b6ee8eSNamhyung Kim 			continue;
130684b6ee8eSNamhyung Kim 
130787bbdf76SNamhyung Kim 		cmp = fmt->collapse(fmt, left, right);
13083d1d07ecSJohn Kacur 		if (cmp)
13093d1d07ecSJohn Kacur 			break;
13103d1d07ecSJohn Kacur 	}
13113d1d07ecSJohn Kacur 
13123d1d07ecSJohn Kacur 	return cmp;
13133d1d07ecSJohn Kacur }
13143d1d07ecSJohn Kacur 
hist_entry__delete(struct hist_entry * he)13156733d1bfSArnaldo Carvalho de Melo void hist_entry__delete(struct hist_entry *he)
13163d1d07ecSJohn Kacur {
1317f542e767SJiri Olsa 	struct hist_entry_ops *ops = he->ops;
1318f542e767SJiri Olsa 
1319f3b623b8SArnaldo Carvalho de Melo 	thread__zput(he->thread);
1320bffb5b0cSIan Rogers 	maps__zput(he->ms.maps);
13215c24b67aSArnaldo Carvalho de Melo 	map__zput(he->ms.map);
13225c24b67aSArnaldo Carvalho de Melo 
13235c24b67aSArnaldo Carvalho de Melo 	if (he->branch_info) {
1324d46a4cdfSArnaldo Carvalho de Melo 		map__zput(he->branch_info->from.ms.map);
1325d46a4cdfSArnaldo Carvalho de Melo 		map__zput(he->branch_info->to.ms.map);
1326625db36eSIan Rogers 		zfree_srcline(&he->branch_info->srcline_from);
1327625db36eSIan Rogers 		zfree_srcline(&he->branch_info->srcline_to);
132874cf249dSArnaldo Carvalho de Melo 		zfree(&he->branch_info);
13295c24b67aSArnaldo Carvalho de Melo 	}
13305c24b67aSArnaldo Carvalho de Melo 
13315c24b67aSArnaldo Carvalho de Melo 	if (he->mem_info) {
1332d46a4cdfSArnaldo Carvalho de Melo 		map__zput(he->mem_info->iaddr.ms.map);
1333d46a4cdfSArnaldo Carvalho de Melo 		map__zput(he->mem_info->daddr.ms.map);
13349f87498fSJiri Olsa 		mem_info__zput(he->mem_info);
13355c24b67aSArnaldo Carvalho de Melo 	}
13365c24b67aSArnaldo Carvalho de Melo 
133799150a1fSJin Yao 	if (he->block_info)
133899150a1fSJin Yao 		block_info__zput(he->block_info);
133999150a1fSJin Yao 
1340f1e8f259SLeo Yan 	if (he->kvm_info)
1341f1e8f259SLeo Yan 		kvm_info__zput(he->kvm_info);
1342f1e8f259SLeo Yan 
13434968ac8fSAndi Kleen 	zfree(&he->res_samples);
1344f8be1c8cSNamhyung Kim 	zfree(&he->stat_acc);
1345625db36eSIan Rogers 	zfree_srcline(&he->srcline);
134631191a85SAndi Kleen 	if (he->srcfile && he->srcfile[0])
1347d8f9da24SArnaldo Carvalho de Melo 		zfree(&he->srcfile);
1348d114960cSNamhyung Kim 	free_callchain(he->callchain);
1349d8f9da24SArnaldo Carvalho de Melo 	zfree(&he->trace_output);
1350d8f9da24SArnaldo Carvalho de Melo 	zfree(&he->raw_data);
1351f542e767SJiri Olsa 	ops->free(he);
13523d1d07ecSJohn Kacur }
13533d1d07ecSJohn Kacur 
13543d1d07ecSJohn Kacur /*
135589fee709SArnaldo Carvalho de Melo  * If this is not the last column, then we need to pad it according to the
1356adba1634SIngo Molnar  * pre-calculated max length for this column, otherwise don't bother adding
135789fee709SArnaldo Carvalho de Melo  * spaces because that would break viewing this with, for instance, 'less',
135889fee709SArnaldo Carvalho de Melo  * that would show tons of trailing spaces when a long C++ demangled method
135989fee709SArnaldo Carvalho de Melo  * names is sampled.
136089fee709SArnaldo Carvalho de Melo */
hist_entry__snprintf_alignment(struct hist_entry * he,struct perf_hpp * hpp,struct perf_hpp_fmt * fmt,int printed)136189fee709SArnaldo Carvalho de Melo int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp,
136289fee709SArnaldo Carvalho de Melo 				   struct perf_hpp_fmt *fmt, int printed)
136389fee709SArnaldo Carvalho de Melo {
136489fee709SArnaldo Carvalho de Melo 	if (!list_is_last(&fmt->list, &he->hists->hpp_list->fields)) {
1365da1b0407SJiri Olsa 		const int width = fmt->width(fmt, hpp, he->hists);
136689fee709SArnaldo Carvalho de Melo 		if (printed < width) {
136789fee709SArnaldo Carvalho de Melo 			advance_hpp(hpp, printed);
136889fee709SArnaldo Carvalho de Melo 			printed = scnprintf(hpp->buf, hpp->size, "%-*s", width - printed, " ");
136989fee709SArnaldo Carvalho de Melo 		}
137089fee709SArnaldo Carvalho de Melo 	}
137189fee709SArnaldo Carvalho de Melo 
137289fee709SArnaldo Carvalho de Melo 	return printed;
137389fee709SArnaldo Carvalho de Melo }
137489fee709SArnaldo Carvalho de Melo 
137589fee709SArnaldo Carvalho de Melo /*
13763d1d07ecSJohn Kacur  * collapse the histogram
13773d1d07ecSJohn Kacur  */
13783d1d07ecSJohn Kacur 
1379aef810ecSNamhyung Kim static void hists__apply_filters(struct hists *hists, struct hist_entry *he);
1380aec13a7eSNamhyung Kim static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *he,
1381aec13a7eSNamhyung Kim 				       enum hist_filter type);
1382aec13a7eSNamhyung Kim 
1383aec13a7eSNamhyung Kim typedef bool (*fmt_chk_fn)(struct perf_hpp_fmt *fmt);
1384aec13a7eSNamhyung Kim 
check_thread_entry(struct perf_hpp_fmt * fmt)1385aec13a7eSNamhyung Kim static bool check_thread_entry(struct perf_hpp_fmt *fmt)
1386aec13a7eSNamhyung Kim {
1387aec13a7eSNamhyung Kim 	return perf_hpp__is_thread_entry(fmt) || perf_hpp__is_comm_entry(fmt);
1388aec13a7eSNamhyung Kim }
1389aec13a7eSNamhyung Kim 
hist_entry__check_and_remove_filter(struct hist_entry * he,enum hist_filter type,fmt_chk_fn check)1390aec13a7eSNamhyung Kim static void hist_entry__check_and_remove_filter(struct hist_entry *he,
1391aec13a7eSNamhyung Kim 						enum hist_filter type,
1392aec13a7eSNamhyung Kim 						fmt_chk_fn check)
1393aec13a7eSNamhyung Kim {
1394aec13a7eSNamhyung Kim 	struct perf_hpp_fmt *fmt;
1395aec13a7eSNamhyung Kim 	bool type_match = false;
1396aec13a7eSNamhyung Kim 	struct hist_entry *parent = he->parent_he;
1397aec13a7eSNamhyung Kim 
1398aec13a7eSNamhyung Kim 	switch (type) {
1399aec13a7eSNamhyung Kim 	case HIST_FILTER__THREAD:
1400aec13a7eSNamhyung Kim 		if (symbol_conf.comm_list == NULL &&
1401aec13a7eSNamhyung Kim 		    symbol_conf.pid_list == NULL &&
1402aec13a7eSNamhyung Kim 		    symbol_conf.tid_list == NULL)
1403aec13a7eSNamhyung Kim 			return;
1404aec13a7eSNamhyung Kim 		break;
1405aec13a7eSNamhyung Kim 	case HIST_FILTER__DSO:
1406aec13a7eSNamhyung Kim 		if (symbol_conf.dso_list == NULL)
1407aec13a7eSNamhyung Kim 			return;
1408aec13a7eSNamhyung Kim 		break;
1409aec13a7eSNamhyung Kim 	case HIST_FILTER__SYMBOL:
1410aec13a7eSNamhyung Kim 		if (symbol_conf.sym_list == NULL)
1411aec13a7eSNamhyung Kim 			return;
1412aec13a7eSNamhyung Kim 		break;
1413aec13a7eSNamhyung Kim 	case HIST_FILTER__PARENT:
1414aec13a7eSNamhyung Kim 	case HIST_FILTER__GUEST:
1415aec13a7eSNamhyung Kim 	case HIST_FILTER__HOST:
1416aec13a7eSNamhyung Kim 	case HIST_FILTER__SOCKET:
14179857b717SJiri Olsa 	case HIST_FILTER__C2C:
1418aec13a7eSNamhyung Kim 	default:
1419aec13a7eSNamhyung Kim 		return;
1420aec13a7eSNamhyung Kim 	}
1421aec13a7eSNamhyung Kim 
1422aec13a7eSNamhyung Kim 	/* if it's filtered by own fmt, it has to have filter bits */
1423aec13a7eSNamhyung Kim 	perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1424aec13a7eSNamhyung Kim 		if (check(fmt)) {
1425aec13a7eSNamhyung Kim 			type_match = true;
1426aec13a7eSNamhyung Kim 			break;
1427aec13a7eSNamhyung Kim 		}
1428aec13a7eSNamhyung Kim 	}
1429aec13a7eSNamhyung Kim 
1430aec13a7eSNamhyung Kim 	if (type_match) {
1431aec13a7eSNamhyung Kim 		/*
1432aec13a7eSNamhyung Kim 		 * If the filter is for current level entry, propagate
1433aec13a7eSNamhyung Kim 		 * filter marker to parents.  The marker bit was
1434aec13a7eSNamhyung Kim 		 * already set by default so it only needs to clear
1435aec13a7eSNamhyung Kim 		 * non-filtered entries.
1436aec13a7eSNamhyung Kim 		 */
1437aec13a7eSNamhyung Kim 		if (!(he->filtered & (1 << type))) {
1438aec13a7eSNamhyung Kim 			while (parent) {
1439aec13a7eSNamhyung Kim 				parent->filtered &= ~(1 << type);
1440aec13a7eSNamhyung Kim 				parent = parent->parent_he;
1441aec13a7eSNamhyung Kim 			}
1442aec13a7eSNamhyung Kim 		}
1443aec13a7eSNamhyung Kim 	} else {
1444aec13a7eSNamhyung Kim 		/*
1445aec13a7eSNamhyung Kim 		 * If current entry doesn't have matching formats, set
1446aec13a7eSNamhyung Kim 		 * filter marker for upper level entries.  it will be
1447aec13a7eSNamhyung Kim 		 * cleared if its lower level entries is not filtered.
1448aec13a7eSNamhyung Kim 		 *
1449aec13a7eSNamhyung Kim 		 * For lower-level entries, it inherits parent's
1450aec13a7eSNamhyung Kim 		 * filter bit so that lower level entries of a
1451aec13a7eSNamhyung Kim 		 * non-filtered entry won't set the filter marker.
1452aec13a7eSNamhyung Kim 		 */
1453aec13a7eSNamhyung Kim 		if (parent == NULL)
1454aec13a7eSNamhyung Kim 			he->filtered |= (1 << type);
1455aec13a7eSNamhyung Kim 		else
1456aec13a7eSNamhyung Kim 			he->filtered |= (parent->filtered & (1 << type));
1457aec13a7eSNamhyung Kim 	}
1458aec13a7eSNamhyung Kim }
1459aec13a7eSNamhyung Kim 
hist_entry__apply_hierarchy_filters(struct hist_entry * he)1460aec13a7eSNamhyung Kim static void hist_entry__apply_hierarchy_filters(struct hist_entry *he)
1461aec13a7eSNamhyung Kim {
1462aec13a7eSNamhyung Kim 	hist_entry__check_and_remove_filter(he, HIST_FILTER__THREAD,
1463aec13a7eSNamhyung Kim 					    check_thread_entry);
1464aec13a7eSNamhyung Kim 
1465aec13a7eSNamhyung Kim 	hist_entry__check_and_remove_filter(he, HIST_FILTER__DSO,
1466aec13a7eSNamhyung Kim 					    perf_hpp__is_dso_entry);
1467aec13a7eSNamhyung Kim 
1468aec13a7eSNamhyung Kim 	hist_entry__check_and_remove_filter(he, HIST_FILTER__SYMBOL,
1469aec13a7eSNamhyung Kim 					    perf_hpp__is_sym_entry);
1470aec13a7eSNamhyung Kim 
1471aec13a7eSNamhyung Kim 	hists__apply_filters(he->hists, he);
1472aec13a7eSNamhyung Kim }
1473aef810ecSNamhyung Kim 
hierarchy_insert_entry(struct hists * hists,struct rb_root_cached * root,struct hist_entry * he,struct hist_entry * parent_he,struct perf_hpp_list * hpp_list)1474aef810ecSNamhyung Kim static struct hist_entry *hierarchy_insert_entry(struct hists *hists,
14752eb3d689SDavidlohr Bueso 						 struct rb_root_cached *root,
1476aef810ecSNamhyung Kim 						 struct hist_entry *he,
1477aec13a7eSNamhyung Kim 						 struct hist_entry *parent_he,
14781b2dbbf4SNamhyung Kim 						 struct perf_hpp_list *hpp_list)
1479aef810ecSNamhyung Kim {
14802eb3d689SDavidlohr Bueso 	struct rb_node **p = &root->rb_root.rb_node;
1481aef810ecSNamhyung Kim 	struct rb_node *parent = NULL;
1482aef810ecSNamhyung Kim 	struct hist_entry *iter, *new;
14831b2dbbf4SNamhyung Kim 	struct perf_hpp_fmt *fmt;
1484aef810ecSNamhyung Kim 	int64_t cmp;
14852eb3d689SDavidlohr Bueso 	bool leftmost = true;
1486aef810ecSNamhyung Kim 
1487aef810ecSNamhyung Kim 	while (*p != NULL) {
1488aef810ecSNamhyung Kim 		parent = *p;
1489aef810ecSNamhyung Kim 		iter = rb_entry(parent, struct hist_entry, rb_node_in);
1490aef810ecSNamhyung Kim 
14911b2dbbf4SNamhyung Kim 		cmp = 0;
14921b2dbbf4SNamhyung Kim 		perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
1493aef810ecSNamhyung Kim 			cmp = fmt->collapse(fmt, iter, he);
14941b2dbbf4SNamhyung Kim 			if (cmp)
14951b2dbbf4SNamhyung Kim 				break;
14961b2dbbf4SNamhyung Kim 		}
14971b2dbbf4SNamhyung Kim 
1498aef810ecSNamhyung Kim 		if (!cmp) {
1499aef810ecSNamhyung Kim 			he_stat__add_stat(&iter->stat, &he->stat);
1500aef810ecSNamhyung Kim 			return iter;
1501aef810ecSNamhyung Kim 		}
1502aef810ecSNamhyung Kim 
1503aef810ecSNamhyung Kim 		if (cmp < 0)
1504aef810ecSNamhyung Kim 			p = &parent->rb_left;
15052eb3d689SDavidlohr Bueso 		else {
1506aef810ecSNamhyung Kim 			p = &parent->rb_right;
15072eb3d689SDavidlohr Bueso 			leftmost = false;
15082eb3d689SDavidlohr Bueso 		}
1509aef810ecSNamhyung Kim 	}
1510aef810ecSNamhyung Kim 
1511aef810ecSNamhyung Kim 	new = hist_entry__new(he, true);
1512aef810ecSNamhyung Kim 	if (new == NULL)
1513aef810ecSNamhyung Kim 		return NULL;
1514aef810ecSNamhyung Kim 
1515aef810ecSNamhyung Kim 	hists->nr_entries++;
1516aef810ecSNamhyung Kim 
15171b2dbbf4SNamhyung Kim 	/* save related format list for output */
15181b2dbbf4SNamhyung Kim 	new->hpp_list = hpp_list;
1519aec13a7eSNamhyung Kim 	new->parent_he = parent_he;
1520aec13a7eSNamhyung Kim 
1521aec13a7eSNamhyung Kim 	hist_entry__apply_hierarchy_filters(new);
1522aef810ecSNamhyung Kim 
1523aef810ecSNamhyung Kim 	/* some fields are now passed to 'new' */
15241b2dbbf4SNamhyung Kim 	perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
1525e049d4a3SNamhyung Kim 		if (perf_hpp__is_trace_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
1526aef810ecSNamhyung Kim 			he->trace_output = NULL;
1527aef810ecSNamhyung Kim 		else
1528aef810ecSNamhyung Kim 			new->trace_output = NULL;
1529aef810ecSNamhyung Kim 
1530aef810ecSNamhyung Kim 		if (perf_hpp__is_srcline_entry(fmt))
1531aef810ecSNamhyung Kim 			he->srcline = NULL;
1532aef810ecSNamhyung Kim 		else
1533aef810ecSNamhyung Kim 			new->srcline = NULL;
1534aef810ecSNamhyung Kim 
1535aef810ecSNamhyung Kim 		if (perf_hpp__is_srcfile_entry(fmt))
1536aef810ecSNamhyung Kim 			he->srcfile = NULL;
1537aef810ecSNamhyung Kim 		else
1538aef810ecSNamhyung Kim 			new->srcfile = NULL;
15391b2dbbf4SNamhyung Kim 	}
1540aef810ecSNamhyung Kim 
1541aef810ecSNamhyung Kim 	rb_link_node(&new->rb_node_in, parent, p);
15422eb3d689SDavidlohr Bueso 	rb_insert_color_cached(&new->rb_node_in, root, leftmost);
1543aef810ecSNamhyung Kim 	return new;
1544aef810ecSNamhyung Kim }
1545aef810ecSNamhyung Kim 
hists__hierarchy_insert_entry(struct hists * hists,struct rb_root_cached * root,struct hist_entry * he)1546aef810ecSNamhyung Kim static int hists__hierarchy_insert_entry(struct hists *hists,
15472eb3d689SDavidlohr Bueso 					 struct rb_root_cached *root,
1548aef810ecSNamhyung Kim 					 struct hist_entry *he)
1549aef810ecSNamhyung Kim {
15501b2dbbf4SNamhyung Kim 	struct perf_hpp_list_node *node;
1551aef810ecSNamhyung Kim 	struct hist_entry *new_he = NULL;
1552aef810ecSNamhyung Kim 	struct hist_entry *parent = NULL;
1553aef810ecSNamhyung Kim 	int depth = 0;
1554aef810ecSNamhyung Kim 	int ret = 0;
1555aef810ecSNamhyung Kim 
15561b2dbbf4SNamhyung Kim 	list_for_each_entry(node, &hists->hpp_formats, list) {
15571b2dbbf4SNamhyung Kim 		/* skip period (overhead) and elided columns */
15581b2dbbf4SNamhyung Kim 		if (node->level == 0 || node->skip)
1559aef810ecSNamhyung Kim 			continue;
1560aef810ecSNamhyung Kim 
1561aef810ecSNamhyung Kim 		/* insert copy of 'he' for each fmt into the hierarchy */
1562aec13a7eSNamhyung Kim 		new_he = hierarchy_insert_entry(hists, root, he, parent, &node->hpp);
1563aef810ecSNamhyung Kim 		if (new_he == NULL) {
1564aef810ecSNamhyung Kim 			ret = -1;
1565aef810ecSNamhyung Kim 			break;
1566aef810ecSNamhyung Kim 		}
1567aef810ecSNamhyung Kim 
1568aef810ecSNamhyung Kim 		root = &new_he->hroot_in;
1569aef810ecSNamhyung Kim 		new_he->depth = depth++;
1570aef810ecSNamhyung Kim 		parent = new_he;
1571aef810ecSNamhyung Kim 	}
1572aef810ecSNamhyung Kim 
1573aef810ecSNamhyung Kim 	if (new_he) {
1574aef810ecSNamhyung Kim 		new_he->leaf = true;
1575aef810ecSNamhyung Kim 
1576fabd37b8SArnaldo Carvalho de Melo 		if (hist_entry__has_callchains(new_he) &&
1577fabd37b8SArnaldo Carvalho de Melo 		    symbol_conf.use_callchain) {
15788ab12a20SIan Rogers 			struct callchain_cursor *cursor = get_tls_callchain_cursor();
15798ab12a20SIan Rogers 
15808ab12a20SIan Rogers 			if (cursor == NULL)
15818ab12a20SIan Rogers 				return -1;
15828ab12a20SIan Rogers 
15838ab12a20SIan Rogers 			callchain_cursor_reset(cursor);
15848ab12a20SIan Rogers 			if (callchain_merge(cursor,
1585aef810ecSNamhyung Kim 					    new_he->callchain,
1586aef810ecSNamhyung Kim 					    he->callchain) < 0)
1587aef810ecSNamhyung Kim 				ret = -1;
1588aef810ecSNamhyung Kim 		}
1589aef810ecSNamhyung Kim 	}
1590aef810ecSNamhyung Kim 
1591aef810ecSNamhyung Kim 	/* 'he' is no longer used */
1592aef810ecSNamhyung Kim 	hist_entry__delete(he);
1593aef810ecSNamhyung Kim 
1594aef810ecSNamhyung Kim 	/* return 0 (or -1) since it already applied filters */
1595aef810ecSNamhyung Kim 	return ret;
1596aef810ecSNamhyung Kim }
1597aef810ecSNamhyung Kim 
hists__collapse_insert_entry(struct hists * hists,struct rb_root_cached * root,struct hist_entry * he)1598592dac6fSJiri Olsa static int hists__collapse_insert_entry(struct hists *hists,
15992eb3d689SDavidlohr Bueso 					struct rb_root_cached *root,
1600bba58cdfSNamhyung Kim 					struct hist_entry *he)
16013d1d07ecSJohn Kacur {
16022eb3d689SDavidlohr Bueso 	struct rb_node **p = &root->rb_root.rb_node;
16033d1d07ecSJohn Kacur 	struct rb_node *parent = NULL;
16043d1d07ecSJohn Kacur 	struct hist_entry *iter;
16053d1d07ecSJohn Kacur 	int64_t cmp;
16062eb3d689SDavidlohr Bueso 	bool leftmost = true;
16073d1d07ecSJohn Kacur 
1608aef810ecSNamhyung Kim 	if (symbol_conf.report_hierarchy)
1609aef810ecSNamhyung Kim 		return hists__hierarchy_insert_entry(hists, root, he);
1610aef810ecSNamhyung Kim 
16113d1d07ecSJohn Kacur 	while (*p != NULL) {
16123d1d07ecSJohn Kacur 		parent = *p;
16131980c2ebSArnaldo Carvalho de Melo 		iter = rb_entry(parent, struct hist_entry, rb_node_in);
16143d1d07ecSJohn Kacur 
16153d1d07ecSJohn Kacur 		cmp = hist_entry__collapse(iter, he);
16163d1d07ecSJohn Kacur 
16173d1d07ecSJohn Kacur 		if (!cmp) {
1618bba58cdfSNamhyung Kim 			int ret = 0;
1619bba58cdfSNamhyung Kim 
1620139c0815SNamhyung Kim 			he_stat__add_stat(&iter->stat, &he->stat);
1621f8be1c8cSNamhyung Kim 			if (symbol_conf.cumulate_callchain)
1622f8be1c8cSNamhyung Kim 				he_stat__add_stat(iter->stat_acc, he->stat_acc);
16239ec60972SNamhyung Kim 
1624fabd37b8SArnaldo Carvalho de Melo 			if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
16258ab12a20SIan Rogers 				struct callchain_cursor *cursor = get_tls_callchain_cursor();
16268ab12a20SIan Rogers 
16278ab12a20SIan Rogers 				if (cursor != NULL) {
16288ab12a20SIan Rogers 					callchain_cursor_reset(cursor);
16298ab12a20SIan Rogers 					if (callchain_merge(cursor, iter->callchain, he->callchain) < 0)
1630bba58cdfSNamhyung Kim 						ret = -1;
16318ab12a20SIan Rogers 				} else {
16328ab12a20SIan Rogers 					ret = 0;
16338ab12a20SIan Rogers 				}
16341b3a0e95SFrederic Weisbecker 			}
16356733d1bfSArnaldo Carvalho de Melo 			hist_entry__delete(he);
1636bba58cdfSNamhyung Kim 			return ret;
16373d1d07ecSJohn Kacur 		}
16383d1d07ecSJohn Kacur 
16393d1d07ecSJohn Kacur 		if (cmp < 0)
16403d1d07ecSJohn Kacur 			p = &(*p)->rb_left;
16412eb3d689SDavidlohr Bueso 		else {
16423d1d07ecSJohn Kacur 			p = &(*p)->rb_right;
16432eb3d689SDavidlohr Bueso 			leftmost = false;
16442eb3d689SDavidlohr Bueso 		}
16453d1d07ecSJohn Kacur 	}
1646740b97f9SNamhyung Kim 	hists->nr_entries++;
16473d1d07ecSJohn Kacur 
16481980c2ebSArnaldo Carvalho de Melo 	rb_link_node(&he->rb_node_in, parent, p);
16492eb3d689SDavidlohr Bueso 	rb_insert_color_cached(&he->rb_node_in, root, leftmost);
1650bba58cdfSNamhyung Kim 	return 1;
16513d1d07ecSJohn Kacur }
16523d1d07ecSJohn Kacur 
hists__get_rotate_entries_in(struct hists * hists)16532eb3d689SDavidlohr Bueso struct rb_root_cached *hists__get_rotate_entries_in(struct hists *hists)
16541980c2ebSArnaldo Carvalho de Melo {
16552eb3d689SDavidlohr Bueso 	struct rb_root_cached *root;
16561980c2ebSArnaldo Carvalho de Melo 
16578e03bb88SIan Rogers 	mutex_lock(&hists->lock);
16581980c2ebSArnaldo Carvalho de Melo 
16591980c2ebSArnaldo Carvalho de Melo 	root = hists->entries_in;
16601980c2ebSArnaldo Carvalho de Melo 	if (++hists->entries_in > &hists->entries_in_array[1])
16611980c2ebSArnaldo Carvalho de Melo 		hists->entries_in = &hists->entries_in_array[0];
16621980c2ebSArnaldo Carvalho de Melo 
16638e03bb88SIan Rogers 	mutex_unlock(&hists->lock);
16641980c2ebSArnaldo Carvalho de Melo 
16651980c2ebSArnaldo Carvalho de Melo 	return root;
16661980c2ebSArnaldo Carvalho de Melo }
16671980c2ebSArnaldo Carvalho de Melo 
hists__apply_filters(struct hists * hists,struct hist_entry * he)166890cf1fb5SArnaldo Carvalho de Melo static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
166990cf1fb5SArnaldo Carvalho de Melo {
167090cf1fb5SArnaldo Carvalho de Melo 	hists__filter_entry_by_dso(hists, he);
167190cf1fb5SArnaldo Carvalho de Melo 	hists__filter_entry_by_thread(hists, he);
1672e94d53ebSNamhyung Kim 	hists__filter_entry_by_symbol(hists, he);
167321394d94SKan Liang 	hists__filter_entry_by_socket(hists, he);
167490cf1fb5SArnaldo Carvalho de Melo }
167590cf1fb5SArnaldo Carvalho de Melo 
hists__collapse_resort(struct hists * hists,struct ui_progress * prog)1676bba58cdfSNamhyung Kim int hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
16771980c2ebSArnaldo Carvalho de Melo {
16782eb3d689SDavidlohr Bueso 	struct rb_root_cached *root;
16791980c2ebSArnaldo Carvalho de Melo 	struct rb_node *next;
16801980c2ebSArnaldo Carvalho de Melo 	struct hist_entry *n;
1681bba58cdfSNamhyung Kim 	int ret;
16821980c2ebSArnaldo Carvalho de Melo 
168352225036SJiri Olsa 	if (!hists__has(hists, need_collapse))
1684bba58cdfSNamhyung Kim 		return 0;
16851980c2ebSArnaldo Carvalho de Melo 
1686740b97f9SNamhyung Kim 	hists->nr_entries = 0;
1687740b97f9SNamhyung Kim 
16881980c2ebSArnaldo Carvalho de Melo 	root = hists__get_rotate_entries_in(hists);
1689740b97f9SNamhyung Kim 
16902eb3d689SDavidlohr Bueso 	next = rb_first_cached(root);
16911980c2ebSArnaldo Carvalho de Melo 
16921980c2ebSArnaldo Carvalho de Melo 	while (next) {
169333e940a2SArnaldo Carvalho de Melo 		if (session_done())
169433e940a2SArnaldo Carvalho de Melo 			break;
16951980c2ebSArnaldo Carvalho de Melo 		n = rb_entry(next, struct hist_entry, rb_node_in);
16961980c2ebSArnaldo Carvalho de Melo 		next = rb_next(&n->rb_node_in);
16971980c2ebSArnaldo Carvalho de Melo 
16982eb3d689SDavidlohr Bueso 		rb_erase_cached(&n->rb_node_in, root);
1699bba58cdfSNamhyung Kim 		ret = hists__collapse_insert_entry(hists, &hists->entries_collapsed, n);
1700bba58cdfSNamhyung Kim 		if (ret < 0)
1701bba58cdfSNamhyung Kim 			return -1;
1702bba58cdfSNamhyung Kim 
1703bba58cdfSNamhyung Kim 		if (ret) {
170490cf1fb5SArnaldo Carvalho de Melo 			/*
170590cf1fb5SArnaldo Carvalho de Melo 			 * If it wasn't combined with one of the entries already
170690cf1fb5SArnaldo Carvalho de Melo 			 * collapsed, we need to apply the filters that may have
170790cf1fb5SArnaldo Carvalho de Melo 			 * been set by, say, the hist_browser.
170890cf1fb5SArnaldo Carvalho de Melo 			 */
170990cf1fb5SArnaldo Carvalho de Melo 			hists__apply_filters(hists, n);
17101980c2ebSArnaldo Carvalho de Melo 		}
1711c1fb5651SNamhyung Kim 		if (prog)
1712c1fb5651SNamhyung Kim 			ui_progress__update(prog, 1);
17131980c2ebSArnaldo Carvalho de Melo 	}
1714bba58cdfSNamhyung Kim 	return 0;
171590cf1fb5SArnaldo Carvalho de Melo }
17161980c2ebSArnaldo Carvalho de Melo 
hist_entry__sort(struct hist_entry * a,struct hist_entry * b)1717722ddfdeSJiri Olsa static int64_t hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
171829d720edSNamhyung Kim {
1719aa6f50afSJiri Olsa 	struct hists *hists = a->hists;
1720043ca389SNamhyung Kim 	struct perf_hpp_fmt *fmt;
1721043ca389SNamhyung Kim 	int64_t cmp = 0;
172229d720edSNamhyung Kim 
1723aa6f50afSJiri Olsa 	hists__for_each_sort_list(hists, fmt) {
1724361459f1SNamhyung Kim 		if (perf_hpp__should_skip(fmt, a->hists))
1725e67d49a7SNamhyung Kim 			continue;
1726e67d49a7SNamhyung Kim 
172787bbdf76SNamhyung Kim 		cmp = fmt->sort(fmt, a, b);
1728043ca389SNamhyung Kim 		if (cmp)
172929d720edSNamhyung Kim 			break;
173029d720edSNamhyung Kim 	}
173129d720edSNamhyung Kim 
1732043ca389SNamhyung Kim 	return cmp;
173329d720edSNamhyung Kim }
173429d720edSNamhyung Kim 
hists__reset_filter_stats(struct hists * hists)17359283ba9bSNamhyung Kim static void hists__reset_filter_stats(struct hists *hists)
17369283ba9bSNamhyung Kim {
17379283ba9bSNamhyung Kim 	hists->nr_non_filtered_entries = 0;
17389283ba9bSNamhyung Kim 	hists->stats.total_non_filtered_period = 0;
17399283ba9bSNamhyung Kim }
17409283ba9bSNamhyung Kim 
hists__reset_stats(struct hists * hists)17419283ba9bSNamhyung Kim void hists__reset_stats(struct hists *hists)
17429283ba9bSNamhyung Kim {
17439283ba9bSNamhyung Kim 	hists->nr_entries = 0;
17449283ba9bSNamhyung Kim 	hists->stats.total_period = 0;
17459283ba9bSNamhyung Kim 
17469283ba9bSNamhyung Kim 	hists__reset_filter_stats(hists);
17479283ba9bSNamhyung Kim }
17489283ba9bSNamhyung Kim 
hists__inc_filter_stats(struct hists * hists,struct hist_entry * h)17499283ba9bSNamhyung Kim static void hists__inc_filter_stats(struct hists *hists, struct hist_entry *h)
17509283ba9bSNamhyung Kim {
17519283ba9bSNamhyung Kim 	hists->nr_non_filtered_entries++;
17529283ba9bSNamhyung Kim 	hists->stats.total_non_filtered_period += h->stat.period;
17539283ba9bSNamhyung Kim }
17549283ba9bSNamhyung Kim 
hists__inc_stats(struct hists * hists,struct hist_entry * h)17559283ba9bSNamhyung Kim void hists__inc_stats(struct hists *hists, struct hist_entry *h)
17569283ba9bSNamhyung Kim {
17579283ba9bSNamhyung Kim 	if (!h->filtered)
17589283ba9bSNamhyung Kim 		hists__inc_filter_stats(hists, h);
17599283ba9bSNamhyung Kim 
17609283ba9bSNamhyung Kim 	hists->nr_entries++;
17619283ba9bSNamhyung Kim 	hists->stats.total_period += h->stat.period;
17629283ba9bSNamhyung Kim }
17639283ba9bSNamhyung Kim 
hierarchy_recalc_total_periods(struct hists * hists)1764f7fb538aSNamhyung Kim static void hierarchy_recalc_total_periods(struct hists *hists)
1765f7fb538aSNamhyung Kim {
1766f7fb538aSNamhyung Kim 	struct rb_node *node;
1767f7fb538aSNamhyung Kim 	struct hist_entry *he;
1768f7fb538aSNamhyung Kim 
17692eb3d689SDavidlohr Bueso 	node = rb_first_cached(&hists->entries);
1770f7fb538aSNamhyung Kim 
1771f7fb538aSNamhyung Kim 	hists->stats.total_period = 0;
1772f7fb538aSNamhyung Kim 	hists->stats.total_non_filtered_period = 0;
1773f7fb538aSNamhyung Kim 
1774f7fb538aSNamhyung Kim 	/*
1775f7fb538aSNamhyung Kim 	 * recalculate total period using top-level entries only
1776f7fb538aSNamhyung Kim 	 * since lower level entries only see non-filtered entries
1777f7fb538aSNamhyung Kim 	 * but upper level entries have sum of both entries.
1778f7fb538aSNamhyung Kim 	 */
1779f7fb538aSNamhyung Kim 	while (node) {
1780f7fb538aSNamhyung Kim 		he = rb_entry(node, struct hist_entry, rb_node);
1781f7fb538aSNamhyung Kim 		node = rb_next(node);
1782f7fb538aSNamhyung Kim 
1783f7fb538aSNamhyung Kim 		hists->stats.total_period += he->stat.period;
1784f7fb538aSNamhyung Kim 		if (!he->filtered)
1785f7fb538aSNamhyung Kim 			hists->stats.total_non_filtered_period += he->stat.period;
1786f7fb538aSNamhyung Kim 	}
1787f7fb538aSNamhyung Kim }
1788f7fb538aSNamhyung Kim 
hierarchy_insert_output_entry(struct rb_root_cached * root,struct hist_entry * he)17892eb3d689SDavidlohr Bueso static void hierarchy_insert_output_entry(struct rb_root_cached *root,
17901a3906a7SNamhyung Kim 					  struct hist_entry *he)
17911a3906a7SNamhyung Kim {
17922eb3d689SDavidlohr Bueso 	struct rb_node **p = &root->rb_root.rb_node;
17931a3906a7SNamhyung Kim 	struct rb_node *parent = NULL;
17941a3906a7SNamhyung Kim 	struct hist_entry *iter;
17951b2dbbf4SNamhyung Kim 	struct perf_hpp_fmt *fmt;
17962eb3d689SDavidlohr Bueso 	bool leftmost = true;
17971a3906a7SNamhyung Kim 
17981a3906a7SNamhyung Kim 	while (*p != NULL) {
17991a3906a7SNamhyung Kim 		parent = *p;
18001a3906a7SNamhyung Kim 		iter = rb_entry(parent, struct hist_entry, rb_node);
18011a3906a7SNamhyung Kim 
18021a3906a7SNamhyung Kim 		if (hist_entry__sort(he, iter) > 0)
18031a3906a7SNamhyung Kim 			p = &parent->rb_left;
18042eb3d689SDavidlohr Bueso 		else {
18051a3906a7SNamhyung Kim 			p = &parent->rb_right;
18062eb3d689SDavidlohr Bueso 			leftmost = false;
18072eb3d689SDavidlohr Bueso 		}
18081a3906a7SNamhyung Kim 	}
18091a3906a7SNamhyung Kim 
18101a3906a7SNamhyung Kim 	rb_link_node(&he->rb_node, parent, p);
18112eb3d689SDavidlohr Bueso 	rb_insert_color_cached(&he->rb_node, root, leftmost);
1812abab5e7fSNamhyung Kim 
1813abab5e7fSNamhyung Kim 	/* update column width of dynamic entry */
18141b2dbbf4SNamhyung Kim 	perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
1815cb6e92c7SNamhyung Kim 		if (fmt->init)
1816cb6e92c7SNamhyung Kim 			fmt->init(fmt, he);
18171b2dbbf4SNamhyung Kim 	}
18181a3906a7SNamhyung Kim }
18191a3906a7SNamhyung Kim 
hists__hierarchy_output_resort(struct hists * hists,struct ui_progress * prog,struct rb_root_cached * root_in,struct rb_root_cached * root_out,u64 min_callchain_hits,bool use_callchain)18201a3906a7SNamhyung Kim static void hists__hierarchy_output_resort(struct hists *hists,
18211a3906a7SNamhyung Kim 					   struct ui_progress *prog,
18222eb3d689SDavidlohr Bueso 					   struct rb_root_cached *root_in,
18232eb3d689SDavidlohr Bueso 					   struct rb_root_cached *root_out,
18241a3906a7SNamhyung Kim 					   u64 min_callchain_hits,
18251a3906a7SNamhyung Kim 					   bool use_callchain)
18261a3906a7SNamhyung Kim {
18271a3906a7SNamhyung Kim 	struct rb_node *node;
18281a3906a7SNamhyung Kim 	struct hist_entry *he;
18291a3906a7SNamhyung Kim 
18302eb3d689SDavidlohr Bueso 	*root_out = RB_ROOT_CACHED;
18312eb3d689SDavidlohr Bueso 	node = rb_first_cached(root_in);
18321a3906a7SNamhyung Kim 
18331a3906a7SNamhyung Kim 	while (node) {
18341a3906a7SNamhyung Kim 		he = rb_entry(node, struct hist_entry, rb_node_in);
18351a3906a7SNamhyung Kim 		node = rb_next(node);
18361a3906a7SNamhyung Kim 
18371a3906a7SNamhyung Kim 		hierarchy_insert_output_entry(root_out, he);
18381a3906a7SNamhyung Kim 
18391a3906a7SNamhyung Kim 		if (prog)
18401a3906a7SNamhyung Kim 			ui_progress__update(prog, 1);
18411a3906a7SNamhyung Kim 
18421a3906a7SNamhyung Kim 		hists->nr_entries++;
18431a3906a7SNamhyung Kim 		if (!he->filtered) {
18441a3906a7SNamhyung Kim 			hists->nr_non_filtered_entries++;
18451a3906a7SNamhyung Kim 			hists__calc_col_len(hists, he);
18461a3906a7SNamhyung Kim 		}
18471a3906a7SNamhyung Kim 
1848c72ab446SNamhyung Kim 		if (!he->leaf) {
1849c72ab446SNamhyung Kim 			hists__hierarchy_output_resort(hists, prog,
1850c72ab446SNamhyung Kim 						       &he->hroot_in,
1851c72ab446SNamhyung Kim 						       &he->hroot_out,
1852c72ab446SNamhyung Kim 						       min_callchain_hits,
1853c72ab446SNamhyung Kim 						       use_callchain);
18541a3906a7SNamhyung Kim 			continue;
18551a3906a7SNamhyung Kim 		}
18561a3906a7SNamhyung Kim 
18571a3906a7SNamhyung Kim 		if (!use_callchain)
18581a3906a7SNamhyung Kim 			continue;
18591a3906a7SNamhyung Kim 
18601a3906a7SNamhyung Kim 		if (callchain_param.mode == CHAIN_GRAPH_REL) {
18611a3906a7SNamhyung Kim 			u64 total = he->stat.period;
18621a3906a7SNamhyung Kim 
18631a3906a7SNamhyung Kim 			if (symbol_conf.cumulate_callchain)
18641a3906a7SNamhyung Kim 				total = he->stat_acc->period;
18651a3906a7SNamhyung Kim 
18661a3906a7SNamhyung Kim 			min_callchain_hits = total * (callchain_param.min_percent / 100);
18671a3906a7SNamhyung Kim 		}
18681a3906a7SNamhyung Kim 
18691a3906a7SNamhyung Kim 		callchain_param.sort(&he->sorted_chain, he->callchain,
18701a3906a7SNamhyung Kim 				     min_callchain_hits, &callchain_param);
18711a3906a7SNamhyung Kim 	}
18721a3906a7SNamhyung Kim }
18731a3906a7SNamhyung Kim 
__hists__insert_output_entry(struct rb_root_cached * entries,struct hist_entry * he,u64 min_callchain_hits,bool use_callchain)18742eb3d689SDavidlohr Bueso static void __hists__insert_output_entry(struct rb_root_cached *entries,
18754e4f06e4SArnaldo Carvalho de Melo 					 struct hist_entry *he,
1876f9db0d0fSKan Liang 					 u64 min_callchain_hits,
1877f9db0d0fSKan Liang 					 bool use_callchain)
18783d1d07ecSJohn Kacur {
18792eb3d689SDavidlohr Bueso 	struct rb_node **p = &entries->rb_root.rb_node;
18803d1d07ecSJohn Kacur 	struct rb_node *parent = NULL;
18813d1d07ecSJohn Kacur 	struct hist_entry *iter;
1882abab5e7fSNamhyung Kim 	struct perf_hpp_fmt *fmt;
18832eb3d689SDavidlohr Bueso 	bool leftmost = true;
18843d1d07ecSJohn Kacur 
1885744070e0SNamhyung Kim 	if (use_callchain) {
1886744070e0SNamhyung Kim 		if (callchain_param.mode == CHAIN_GRAPH_REL) {
1887744070e0SNamhyung Kim 			u64 total = he->stat.period;
1888744070e0SNamhyung Kim 
1889744070e0SNamhyung Kim 			if (symbol_conf.cumulate_callchain)
1890744070e0SNamhyung Kim 				total = he->stat_acc->period;
1891744070e0SNamhyung Kim 
1892744070e0SNamhyung Kim 			min_callchain_hits = total * (callchain_param.min_percent / 100);
1893744070e0SNamhyung Kim 		}
1894b9fb9304SArnaldo Carvalho de Melo 		callchain_param.sort(&he->sorted_chain, he->callchain,
18953d1d07ecSJohn Kacur 				      min_callchain_hits, &callchain_param);
1896744070e0SNamhyung Kim 	}
18973d1d07ecSJohn Kacur 
18983d1d07ecSJohn Kacur 	while (*p != NULL) {
18993d1d07ecSJohn Kacur 		parent = *p;
19003d1d07ecSJohn Kacur 		iter = rb_entry(parent, struct hist_entry, rb_node);
19013d1d07ecSJohn Kacur 
1902043ca389SNamhyung Kim 		if (hist_entry__sort(he, iter) > 0)
19033d1d07ecSJohn Kacur 			p = &(*p)->rb_left;
19042eb3d689SDavidlohr Bueso 		else {
19053d1d07ecSJohn Kacur 			p = &(*p)->rb_right;
19062eb3d689SDavidlohr Bueso 			leftmost = false;
19072eb3d689SDavidlohr Bueso 		}
19083d1d07ecSJohn Kacur 	}
19093d1d07ecSJohn Kacur 
19103d1d07ecSJohn Kacur 	rb_link_node(&he->rb_node, parent, p);
19112eb3d689SDavidlohr Bueso 	rb_insert_color_cached(&he->rb_node, entries, leftmost);
1912abab5e7fSNamhyung Kim 
1913cb6e92c7SNamhyung Kim 	/* update column width of dynamic entries */
1914abab5e7fSNamhyung Kim 	perf_hpp_list__for_each_sort_list(&perf_hpp_list, fmt) {
1915cb6e92c7SNamhyung Kim 		if (fmt->init)
1916cb6e92c7SNamhyung Kim 			fmt->init(fmt, he);
1917abab5e7fSNamhyung Kim 	}
19183d1d07ecSJohn Kacur }
19193d1d07ecSJohn Kacur 
output_resort(struct hists * hists,struct ui_progress * prog,bool use_callchain,hists__resort_cb_t cb,void * cb_arg)192001441af5SJiri Olsa static void output_resort(struct hists *hists, struct ui_progress *prog,
1921e4c38fd4SJiri Olsa 			  bool use_callchain, hists__resort_cb_t cb,
1922e4c38fd4SJiri Olsa 			  void *cb_arg)
19233d1d07ecSJohn Kacur {
19242eb3d689SDavidlohr Bueso 	struct rb_root_cached *root;
19253d1d07ecSJohn Kacur 	struct rb_node *next;
19263d1d07ecSJohn Kacur 	struct hist_entry *n;
1927467ef10cSNamhyung Kim 	u64 callchain_total;
19283d1d07ecSJohn Kacur 	u64 min_callchain_hits;
19293d1d07ecSJohn Kacur 
1930467ef10cSNamhyung Kim 	callchain_total = hists->callchain_period;
1931467ef10cSNamhyung Kim 	if (symbol_conf.filter_relative)
1932467ef10cSNamhyung Kim 		callchain_total = hists->callchain_non_filtered_period;
1933467ef10cSNamhyung Kim 
1934467ef10cSNamhyung Kim 	min_callchain_hits = callchain_total * (callchain_param.min_percent / 100);
19353d1d07ecSJohn Kacur 
19361a3906a7SNamhyung Kim 	hists__reset_stats(hists);
19371a3906a7SNamhyung Kim 	hists__reset_col_len(hists);
19381a3906a7SNamhyung Kim 
19391a3906a7SNamhyung Kim 	if (symbol_conf.report_hierarchy) {
1940f7fb538aSNamhyung Kim 		hists__hierarchy_output_resort(hists, prog,
19411a3906a7SNamhyung Kim 					       &hists->entries_collapsed,
19421a3906a7SNamhyung Kim 					       &hists->entries,
19431a3906a7SNamhyung Kim 					       min_callchain_hits,
19441a3906a7SNamhyung Kim 					       use_callchain);
1945f7fb538aSNamhyung Kim 		hierarchy_recalc_total_periods(hists);
1946f7fb538aSNamhyung Kim 		return;
19471a3906a7SNamhyung Kim 	}
19481a3906a7SNamhyung Kim 
194952225036SJiri Olsa 	if (hists__has(hists, need_collapse))
19501980c2ebSArnaldo Carvalho de Melo 		root = &hists->entries_collapsed;
19511980c2ebSArnaldo Carvalho de Melo 	else
19521980c2ebSArnaldo Carvalho de Melo 		root = hists->entries_in;
19531980c2ebSArnaldo Carvalho de Melo 
19542eb3d689SDavidlohr Bueso 	next = rb_first_cached(root);
19552eb3d689SDavidlohr Bueso 	hists->entries = RB_ROOT_CACHED;
19563d1d07ecSJohn Kacur 
19573d1d07ecSJohn Kacur 	while (next) {
19581980c2ebSArnaldo Carvalho de Melo 		n = rb_entry(next, struct hist_entry, rb_node_in);
19591980c2ebSArnaldo Carvalho de Melo 		next = rb_next(&n->rb_node_in);
19603d1d07ecSJohn Kacur 
1961e4c38fd4SJiri Olsa 		if (cb && cb(n, cb_arg))
196252c5cc36SJiri Olsa 			continue;
196352c5cc36SJiri Olsa 
1964f9db0d0fSKan Liang 		__hists__insert_output_entry(&hists->entries, n, min_callchain_hits, use_callchain);
19656263835aSNamhyung Kim 		hists__inc_stats(hists, n);
1966ae993efcSNamhyung Kim 
1967ae993efcSNamhyung Kim 		if (!n->filtered)
1968ae993efcSNamhyung Kim 			hists__calc_col_len(hists, n);
1969740b97f9SNamhyung Kim 
1970740b97f9SNamhyung Kim 		if (prog)
1971740b97f9SNamhyung Kim 			ui_progress__update(prog, 1);
19723d1d07ecSJohn Kacur 	}
19731980c2ebSArnaldo Carvalho de Melo }
1974b9bf0892SArnaldo Carvalho de Melo 
evsel__output_resort_cb(struct evsel * evsel,struct ui_progress * prog,hists__resort_cb_t cb,void * cb_arg)197510c513f7SArnaldo Carvalho de Melo void evsel__output_resort_cb(struct evsel *evsel, struct ui_progress *prog,
197657496187SJiri Olsa 			     hists__resort_cb_t cb, void *cb_arg)
197701441af5SJiri Olsa {
197801441af5SJiri Olsa 	bool use_callchain;
197901441af5SJiri Olsa 
198001441af5SJiri Olsa 	if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph)
198127de9b2bSArnaldo Carvalho de Melo 		use_callchain = evsel__has_callchain(evsel);
198201441af5SJiri Olsa 	else
198301441af5SJiri Olsa 		use_callchain = symbol_conf.use_callchain;
198401441af5SJiri Olsa 
1985b49a821eSJin Yao 	use_callchain |= symbol_conf.show_branchflag_count;
1986b49a821eSJin Yao 
198757496187SJiri Olsa 	output_resort(evsel__hists(evsel), prog, use_callchain, cb, cb_arg);
198857496187SJiri Olsa }
198957496187SJiri Olsa 
evsel__output_resort(struct evsel * evsel,struct ui_progress * prog)199010c513f7SArnaldo Carvalho de Melo void evsel__output_resort(struct evsel *evsel, struct ui_progress *prog)
199157496187SJiri Olsa {
199210c513f7SArnaldo Carvalho de Melo 	return evsel__output_resort_cb(evsel, prog, NULL, NULL);
1993452ce03bSJiri Olsa }
1994452ce03bSJiri Olsa 
hists__output_resort(struct hists * hists,struct ui_progress * prog)1995452ce03bSJiri Olsa void hists__output_resort(struct hists *hists, struct ui_progress *prog)
1996452ce03bSJiri Olsa {
1997e4c38fd4SJiri Olsa 	output_resort(hists, prog, symbol_conf.use_callchain, NULL, NULL);
199852c5cc36SJiri Olsa }
199952c5cc36SJiri Olsa 
hists__output_resort_cb(struct hists * hists,struct ui_progress * prog,hists__resort_cb_t cb)200052c5cc36SJiri Olsa void hists__output_resort_cb(struct hists *hists, struct ui_progress *prog,
200152c5cc36SJiri Olsa 			     hists__resort_cb_t cb)
200252c5cc36SJiri Olsa {
2003e4c38fd4SJiri Olsa 	output_resort(hists, prog, symbol_conf.use_callchain, cb, NULL);
200401441af5SJiri Olsa }
200501441af5SJiri Olsa 
can_goto_child(struct hist_entry * he,enum hierarchy_move_dir hmd)20068c01872fSNamhyung Kim static bool can_goto_child(struct hist_entry *he, enum hierarchy_move_dir hmd)
20078c01872fSNamhyung Kim {
20088c01872fSNamhyung Kim 	if (he->leaf || hmd == HMD_FORCE_SIBLING)
20098c01872fSNamhyung Kim 		return false;
20108c01872fSNamhyung Kim 
20118c01872fSNamhyung Kim 	if (he->unfolded || hmd == HMD_FORCE_CHILD)
20128c01872fSNamhyung Kim 		return true;
20138c01872fSNamhyung Kim 
20148c01872fSNamhyung Kim 	return false;
20158c01872fSNamhyung Kim }
20168c01872fSNamhyung Kim 
rb_hierarchy_last(struct rb_node * node)20178c01872fSNamhyung Kim struct rb_node *rb_hierarchy_last(struct rb_node *node)
20188c01872fSNamhyung Kim {
20198c01872fSNamhyung Kim 	struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
20208c01872fSNamhyung Kim 
20218c01872fSNamhyung Kim 	while (can_goto_child(he, HMD_NORMAL)) {
20222eb3d689SDavidlohr Bueso 		node = rb_last(&he->hroot_out.rb_root);
20238c01872fSNamhyung Kim 		he = rb_entry(node, struct hist_entry, rb_node);
20248c01872fSNamhyung Kim 	}
20258c01872fSNamhyung Kim 	return node;
20268c01872fSNamhyung Kim }
20278c01872fSNamhyung Kim 
__rb_hierarchy_next(struct rb_node * node,enum hierarchy_move_dir hmd)20288c01872fSNamhyung Kim struct rb_node *__rb_hierarchy_next(struct rb_node *node, enum hierarchy_move_dir hmd)
20298c01872fSNamhyung Kim {
20308c01872fSNamhyung Kim 	struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
20318c01872fSNamhyung Kim 
20328c01872fSNamhyung Kim 	if (can_goto_child(he, hmd))
20332eb3d689SDavidlohr Bueso 		node = rb_first_cached(&he->hroot_out);
20348c01872fSNamhyung Kim 	else
20358c01872fSNamhyung Kim 		node = rb_next(node);
20368c01872fSNamhyung Kim 
20378c01872fSNamhyung Kim 	while (node == NULL) {
20388c01872fSNamhyung Kim 		he = he->parent_he;
20398c01872fSNamhyung Kim 		if (he == NULL)
20408c01872fSNamhyung Kim 			break;
20418c01872fSNamhyung Kim 
20428c01872fSNamhyung Kim 		node = rb_next(&he->rb_node);
20438c01872fSNamhyung Kim 	}
20448c01872fSNamhyung Kim 	return node;
20458c01872fSNamhyung Kim }
20468c01872fSNamhyung Kim 
rb_hierarchy_prev(struct rb_node * node)20478c01872fSNamhyung Kim struct rb_node *rb_hierarchy_prev(struct rb_node *node)
20488c01872fSNamhyung Kim {
20498c01872fSNamhyung Kim 	struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
20508c01872fSNamhyung Kim 
20518c01872fSNamhyung Kim 	node = rb_prev(node);
20528c01872fSNamhyung Kim 	if (node)
20538c01872fSNamhyung Kim 		return rb_hierarchy_last(node);
20548c01872fSNamhyung Kim 
20558c01872fSNamhyung Kim 	he = he->parent_he;
20568c01872fSNamhyung Kim 	if (he == NULL)
20578c01872fSNamhyung Kim 		return NULL;
20588c01872fSNamhyung Kim 
20598c01872fSNamhyung Kim 	return &he->rb_node;
20608c01872fSNamhyung Kim }
20618c01872fSNamhyung Kim 
hist_entry__has_hierarchy_children(struct hist_entry * he,float limit)2062a7b5895bSNamhyung Kim bool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit)
2063a7b5895bSNamhyung Kim {
2064a7b5895bSNamhyung Kim 	struct rb_node *node;
2065a7b5895bSNamhyung Kim 	struct hist_entry *child;
2066a7b5895bSNamhyung Kim 	float percent;
2067a7b5895bSNamhyung Kim 
2068a7b5895bSNamhyung Kim 	if (he->leaf)
2069a7b5895bSNamhyung Kim 		return false;
2070a7b5895bSNamhyung Kim 
20712eb3d689SDavidlohr Bueso 	node = rb_first_cached(&he->hroot_out);
2072a7b5895bSNamhyung Kim 	child = rb_entry(node, struct hist_entry, rb_node);
2073a7b5895bSNamhyung Kim 
2074a7b5895bSNamhyung Kim 	while (node && child->filtered) {
2075a7b5895bSNamhyung Kim 		node = rb_next(node);
2076a7b5895bSNamhyung Kim 		child = rb_entry(node, struct hist_entry, rb_node);
2077a7b5895bSNamhyung Kim 	}
2078a7b5895bSNamhyung Kim 
2079a7b5895bSNamhyung Kim 	if (node)
2080a7b5895bSNamhyung Kim 		percent = hist_entry__get_percent_limit(child);
2081a7b5895bSNamhyung Kim 	else
2082a7b5895bSNamhyung Kim 		percent = 0;
2083a7b5895bSNamhyung Kim 
2084a7b5895bSNamhyung Kim 	return node && percent >= limit;
2085a7b5895bSNamhyung Kim }
2086a7b5895bSNamhyung Kim 
hists__remove_entry_filter(struct hists * hists,struct hist_entry * h,enum hist_filter filter)208742b28ac0SArnaldo Carvalho de Melo static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
2088cc5edb0eSArnaldo Carvalho de Melo 				       enum hist_filter filter)
2089cc5edb0eSArnaldo Carvalho de Melo {
2090cc5edb0eSArnaldo Carvalho de Melo 	h->filtered &= ~(1 << filter);
2091155e9affSNamhyung Kim 
2092155e9affSNamhyung Kim 	if (symbol_conf.report_hierarchy) {
2093155e9affSNamhyung Kim 		struct hist_entry *parent = h->parent_he;
2094155e9affSNamhyung Kim 
2095155e9affSNamhyung Kim 		while (parent) {
2096155e9affSNamhyung Kim 			he_stat__add_stat(&parent->stat, &h->stat);
2097155e9affSNamhyung Kim 
2098155e9affSNamhyung Kim 			parent->filtered &= ~(1 << filter);
2099155e9affSNamhyung Kim 
2100155e9affSNamhyung Kim 			if (parent->filtered)
2101155e9affSNamhyung Kim 				goto next;
2102155e9affSNamhyung Kim 
2103155e9affSNamhyung Kim 			/* force fold unfiltered entry for simplicity */
2104155e9affSNamhyung Kim 			parent->unfolded = false;
210579dded87SNamhyung Kim 			parent->has_no_entry = false;
2106155e9affSNamhyung Kim 			parent->row_offset = 0;
2107155e9affSNamhyung Kim 			parent->nr_rows = 0;
2108155e9affSNamhyung Kim next:
2109155e9affSNamhyung Kim 			parent = parent->parent_he;
2110155e9affSNamhyung Kim 		}
2111155e9affSNamhyung Kim 	}
2112155e9affSNamhyung Kim 
2113cc5edb0eSArnaldo Carvalho de Melo 	if (h->filtered)
2114cc5edb0eSArnaldo Carvalho de Melo 		return;
2115cc5edb0eSArnaldo Carvalho de Melo 
211687e90f43SNamhyung Kim 	/* force fold unfiltered entry for simplicity */
21173698dab1SNamhyung Kim 	h->unfolded = false;
211879dded87SNamhyung Kim 	h->has_no_entry = false;
21190f0cbf7aSArnaldo Carvalho de Melo 	h->row_offset = 0;
2120a8cd1f43SHe Kuang 	h->nr_rows = 0;
21219283ba9bSNamhyung Kim 
21221ab1fa5dSNamhyung Kim 	hists->stats.nr_non_filtered_samples += h->stat.nr_events;
2123cc5edb0eSArnaldo Carvalho de Melo 
21249283ba9bSNamhyung Kim 	hists__inc_filter_stats(hists, h);
212542b28ac0SArnaldo Carvalho de Melo 	hists__calc_col_len(hists, h);
2126cc5edb0eSArnaldo Carvalho de Melo }
2127cc5edb0eSArnaldo Carvalho de Melo 
212890cf1fb5SArnaldo Carvalho de Melo 
hists__filter_entry_by_dso(struct hists * hists,struct hist_entry * he)212990cf1fb5SArnaldo Carvalho de Melo static bool hists__filter_entry_by_dso(struct hists *hists,
213090cf1fb5SArnaldo Carvalho de Melo 				       struct hist_entry *he)
213190cf1fb5SArnaldo Carvalho de Melo {
213290cf1fb5SArnaldo Carvalho de Melo 	if (hists->dso_filter != NULL &&
213363df0e4bSIan Rogers 	    (he->ms.map == NULL || map__dso(he->ms.map) != hists->dso_filter)) {
213490cf1fb5SArnaldo Carvalho de Melo 		he->filtered |= (1 << HIST_FILTER__DSO);
213590cf1fb5SArnaldo Carvalho de Melo 		return true;
213690cf1fb5SArnaldo Carvalho de Melo 	}
213790cf1fb5SArnaldo Carvalho de Melo 
213890cf1fb5SArnaldo Carvalho de Melo 	return false;
213990cf1fb5SArnaldo Carvalho de Melo }
214090cf1fb5SArnaldo Carvalho de Melo 
hists__filter_entry_by_thread(struct hists * hists,struct hist_entry * he)214190cf1fb5SArnaldo Carvalho de Melo static bool hists__filter_entry_by_thread(struct hists *hists,
214290cf1fb5SArnaldo Carvalho de Melo 					  struct hist_entry *he)
214390cf1fb5SArnaldo Carvalho de Melo {
214490cf1fb5SArnaldo Carvalho de Melo 	if (hists->thread_filter != NULL &&
2145f6005cafSIan Rogers 	    RC_CHK_ACCESS(he->thread) != RC_CHK_ACCESS(hists->thread_filter)) {
214690cf1fb5SArnaldo Carvalho de Melo 		he->filtered |= (1 << HIST_FILTER__THREAD);
214790cf1fb5SArnaldo Carvalho de Melo 		return true;
214890cf1fb5SArnaldo Carvalho de Melo 	}
214990cf1fb5SArnaldo Carvalho de Melo 
215090cf1fb5SArnaldo Carvalho de Melo 	return false;
215190cf1fb5SArnaldo Carvalho de Melo }
215290cf1fb5SArnaldo Carvalho de Melo 
hists__filter_entry_by_symbol(struct hists * hists,struct hist_entry * he)2153e94d53ebSNamhyung Kim static bool hists__filter_entry_by_symbol(struct hists *hists,
2154e94d53ebSNamhyung Kim 					  struct hist_entry *he)
2155e94d53ebSNamhyung Kim {
2156e94d53ebSNamhyung Kim 	if (hists->symbol_filter_str != NULL &&
2157e94d53ebSNamhyung Kim 	    (!he->ms.sym || strstr(he->ms.sym->name,
2158e94d53ebSNamhyung Kim 				   hists->symbol_filter_str) == NULL)) {
2159e94d53ebSNamhyung Kim 		he->filtered |= (1 << HIST_FILTER__SYMBOL);
2160e94d53ebSNamhyung Kim 		return true;
2161e94d53ebSNamhyung Kim 	}
2162e94d53ebSNamhyung Kim 
2163e94d53ebSNamhyung Kim 	return false;
2164e94d53ebSNamhyung Kim }
2165e94d53ebSNamhyung Kim 
hists__filter_entry_by_socket(struct hists * hists,struct hist_entry * he)216621394d94SKan Liang static bool hists__filter_entry_by_socket(struct hists *hists,
216721394d94SKan Liang 					  struct hist_entry *he)
216821394d94SKan Liang {
216921394d94SKan Liang 	if ((hists->socket_filter > -1) &&
217021394d94SKan Liang 	    (he->socket != hists->socket_filter)) {
217121394d94SKan Liang 		he->filtered |= (1 << HIST_FILTER__SOCKET);
217221394d94SKan Liang 		return true;
217321394d94SKan Liang 	}
217421394d94SKan Liang 
217521394d94SKan Liang 	return false;
217621394d94SKan Liang }
217721394d94SKan Liang 
21781f7c2541SNamhyung Kim typedef bool (*filter_fn_t)(struct hists *hists, struct hist_entry *he);
21791f7c2541SNamhyung Kim 
hists__filter_by_type(struct hists * hists,int type,filter_fn_t filter)21801f7c2541SNamhyung Kim static void hists__filter_by_type(struct hists *hists, int type, filter_fn_t filter)
218184734b06SKan Liang {
218284734b06SKan Liang 	struct rb_node *nd;
218384734b06SKan Liang 
218484734b06SKan Liang 	hists->stats.nr_non_filtered_samples = 0;
218584734b06SKan Liang 
218684734b06SKan Liang 	hists__reset_filter_stats(hists);
218784734b06SKan Liang 	hists__reset_col_len(hists);
218884734b06SKan Liang 
21892eb3d689SDavidlohr Bueso 	for (nd = rb_first_cached(&hists->entries); nd; nd = rb_next(nd)) {
219084734b06SKan Liang 		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
219184734b06SKan Liang 
21921f7c2541SNamhyung Kim 		if (filter(hists, h))
219384734b06SKan Liang 			continue;
219484734b06SKan Liang 
21951f7c2541SNamhyung Kim 		hists__remove_entry_filter(hists, h, type);
219684734b06SKan Liang 	}
219784734b06SKan Liang }
219884734b06SKan Liang 
resort_filtered_entry(struct rb_root_cached * root,struct hist_entry * he)21992eb3d689SDavidlohr Bueso static void resort_filtered_entry(struct rb_root_cached *root,
22002eb3d689SDavidlohr Bueso 				  struct hist_entry *he)
220170642850SNamhyung Kim {
22022eb3d689SDavidlohr Bueso 	struct rb_node **p = &root->rb_root.rb_node;
220370642850SNamhyung Kim 	struct rb_node *parent = NULL;
220470642850SNamhyung Kim 	struct hist_entry *iter;
22052eb3d689SDavidlohr Bueso 	struct rb_root_cached new_root = RB_ROOT_CACHED;
220670642850SNamhyung Kim 	struct rb_node *nd;
22072eb3d689SDavidlohr Bueso 	bool leftmost = true;
220870642850SNamhyung Kim 
220970642850SNamhyung Kim 	while (*p != NULL) {
221070642850SNamhyung Kim 		parent = *p;
221170642850SNamhyung Kim 		iter = rb_entry(parent, struct hist_entry, rb_node);
221270642850SNamhyung Kim 
221370642850SNamhyung Kim 		if (hist_entry__sort(he, iter) > 0)
221470642850SNamhyung Kim 			p = &(*p)->rb_left;
22152eb3d689SDavidlohr Bueso 		else {
221670642850SNamhyung Kim 			p = &(*p)->rb_right;
22172eb3d689SDavidlohr Bueso 			leftmost = false;
22182eb3d689SDavidlohr Bueso 		}
221970642850SNamhyung Kim 	}
222070642850SNamhyung Kim 
222170642850SNamhyung Kim 	rb_link_node(&he->rb_node, parent, p);
22222eb3d689SDavidlohr Bueso 	rb_insert_color_cached(&he->rb_node, root, leftmost);
222370642850SNamhyung Kim 
222470642850SNamhyung Kim 	if (he->leaf || he->filtered)
222570642850SNamhyung Kim 		return;
222670642850SNamhyung Kim 
22272eb3d689SDavidlohr Bueso 	nd = rb_first_cached(&he->hroot_out);
222870642850SNamhyung Kim 	while (nd) {
222970642850SNamhyung Kim 		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
223070642850SNamhyung Kim 
223170642850SNamhyung Kim 		nd = rb_next(nd);
22322eb3d689SDavidlohr Bueso 		rb_erase_cached(&h->rb_node, &he->hroot_out);
223370642850SNamhyung Kim 
223470642850SNamhyung Kim 		resort_filtered_entry(&new_root, h);
223570642850SNamhyung Kim 	}
223670642850SNamhyung Kim 
223770642850SNamhyung Kim 	he->hroot_out = new_root;
223870642850SNamhyung Kim }
223970642850SNamhyung Kim 
hists__filter_hierarchy(struct hists * hists,int type,const void * arg)2240155e9affSNamhyung Kim static void hists__filter_hierarchy(struct hists *hists, int type, const void *arg)
2241155e9affSNamhyung Kim {
2242155e9affSNamhyung Kim 	struct rb_node *nd;
22432eb3d689SDavidlohr Bueso 	struct rb_root_cached new_root = RB_ROOT_CACHED;
2244155e9affSNamhyung Kim 
2245155e9affSNamhyung Kim 	hists->stats.nr_non_filtered_samples = 0;
2246155e9affSNamhyung Kim 
2247155e9affSNamhyung Kim 	hists__reset_filter_stats(hists);
2248155e9affSNamhyung Kim 	hists__reset_col_len(hists);
2249155e9affSNamhyung Kim 
22502eb3d689SDavidlohr Bueso 	nd = rb_first_cached(&hists->entries);
2251155e9affSNamhyung Kim 	while (nd) {
2252155e9affSNamhyung Kim 		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2253155e9affSNamhyung Kim 		int ret;
2254155e9affSNamhyung Kim 
2255155e9affSNamhyung Kim 		ret = hist_entry__filter(h, type, arg);
2256155e9affSNamhyung Kim 
2257155e9affSNamhyung Kim 		/*
2258155e9affSNamhyung Kim 		 * case 1. non-matching type
2259155e9affSNamhyung Kim 		 * zero out the period, set filter marker and move to child
2260155e9affSNamhyung Kim 		 */
2261155e9affSNamhyung Kim 		if (ret < 0) {
2262155e9affSNamhyung Kim 			memset(&h->stat, 0, sizeof(h->stat));
2263155e9affSNamhyung Kim 			h->filtered |= (1 << type);
2264155e9affSNamhyung Kim 
2265155e9affSNamhyung Kim 			nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_CHILD);
2266155e9affSNamhyung Kim 		}
2267155e9affSNamhyung Kim 		/*
2268155e9affSNamhyung Kim 		 * case 2. matched type (filter out)
2269155e9affSNamhyung Kim 		 * set filter marker and move to next
2270155e9affSNamhyung Kim 		 */
2271155e9affSNamhyung Kim 		else if (ret == 1) {
2272155e9affSNamhyung Kim 			h->filtered |= (1 << type);
2273155e9affSNamhyung Kim 
2274155e9affSNamhyung Kim 			nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
2275155e9affSNamhyung Kim 		}
2276155e9affSNamhyung Kim 		/*
2277155e9affSNamhyung Kim 		 * case 3. ok (not filtered)
2278155e9affSNamhyung Kim 		 * add period to hists and parents, erase the filter marker
2279155e9affSNamhyung Kim 		 * and move to next sibling
2280155e9affSNamhyung Kim 		 */
2281155e9affSNamhyung Kim 		else {
2282155e9affSNamhyung Kim 			hists__remove_entry_filter(hists, h, type);
2283155e9affSNamhyung Kim 
2284155e9affSNamhyung Kim 			nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
2285155e9affSNamhyung Kim 		}
2286155e9affSNamhyung Kim 	}
228770642850SNamhyung Kim 
2288f7fb538aSNamhyung Kim 	hierarchy_recalc_total_periods(hists);
2289f7fb538aSNamhyung Kim 
229070642850SNamhyung Kim 	/*
229170642850SNamhyung Kim 	 * resort output after applying a new filter since filter in a lower
229270642850SNamhyung Kim 	 * hierarchy can change periods in a upper hierarchy.
229370642850SNamhyung Kim 	 */
22942eb3d689SDavidlohr Bueso 	nd = rb_first_cached(&hists->entries);
229570642850SNamhyung Kim 	while (nd) {
229670642850SNamhyung Kim 		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
229770642850SNamhyung Kim 
229870642850SNamhyung Kim 		nd = rb_next(nd);
22992eb3d689SDavidlohr Bueso 		rb_erase_cached(&h->rb_node, &hists->entries);
230070642850SNamhyung Kim 
230170642850SNamhyung Kim 		resort_filtered_entry(&new_root, h);
230270642850SNamhyung Kim 	}
230370642850SNamhyung Kim 
230470642850SNamhyung Kim 	hists->entries = new_root;
2305155e9affSNamhyung Kim }
2306155e9affSNamhyung Kim 
hists__filter_by_thread(struct hists * hists)23071f7c2541SNamhyung Kim void hists__filter_by_thread(struct hists *hists)
23081f7c2541SNamhyung Kim {
2309155e9affSNamhyung Kim 	if (symbol_conf.report_hierarchy)
2310155e9affSNamhyung Kim 		hists__filter_hierarchy(hists, HIST_FILTER__THREAD,
2311155e9affSNamhyung Kim 					hists->thread_filter);
2312155e9affSNamhyung Kim 	else
23131f7c2541SNamhyung Kim 		hists__filter_by_type(hists, HIST_FILTER__THREAD,
23141f7c2541SNamhyung Kim 				      hists__filter_entry_by_thread);
23151f7c2541SNamhyung Kim }
23161f7c2541SNamhyung Kim 
hists__filter_by_dso(struct hists * hists)23171f7c2541SNamhyung Kim void hists__filter_by_dso(struct hists *hists)
23181f7c2541SNamhyung Kim {
2319155e9affSNamhyung Kim 	if (symbol_conf.report_hierarchy)
2320155e9affSNamhyung Kim 		hists__filter_hierarchy(hists, HIST_FILTER__DSO,
2321155e9affSNamhyung Kim 					hists->dso_filter);
2322155e9affSNamhyung Kim 	else
23231f7c2541SNamhyung Kim 		hists__filter_by_type(hists, HIST_FILTER__DSO,
23241f7c2541SNamhyung Kim 				      hists__filter_entry_by_dso);
23251f7c2541SNamhyung Kim }
23261f7c2541SNamhyung Kim 
hists__filter_by_symbol(struct hists * hists)23271f7c2541SNamhyung Kim void hists__filter_by_symbol(struct hists *hists)
23281f7c2541SNamhyung Kim {
2329155e9affSNamhyung Kim 	if (symbol_conf.report_hierarchy)
2330155e9affSNamhyung Kim 		hists__filter_hierarchy(hists, HIST_FILTER__SYMBOL,
2331155e9affSNamhyung Kim 					hists->symbol_filter_str);
2332155e9affSNamhyung Kim 	else
23331f7c2541SNamhyung Kim 		hists__filter_by_type(hists, HIST_FILTER__SYMBOL,
23341f7c2541SNamhyung Kim 				      hists__filter_entry_by_symbol);
23351f7c2541SNamhyung Kim }
23361f7c2541SNamhyung Kim 
hists__filter_by_socket(struct hists * hists)23371f7c2541SNamhyung Kim void hists__filter_by_socket(struct hists *hists)
23381f7c2541SNamhyung Kim {
2339155e9affSNamhyung Kim 	if (symbol_conf.report_hierarchy)
2340155e9affSNamhyung Kim 		hists__filter_hierarchy(hists, HIST_FILTER__SOCKET,
2341155e9affSNamhyung Kim 					&hists->socket_filter);
2342155e9affSNamhyung Kim 	else
23431f7c2541SNamhyung Kim 		hists__filter_by_type(hists, HIST_FILTER__SOCKET,
23441f7c2541SNamhyung Kim 				      hists__filter_entry_by_socket);
23451f7c2541SNamhyung Kim }
23461f7c2541SNamhyung Kim 
events_stats__inc(struct events_stats * stats,u32 type)234728a6b6aaSArnaldo Carvalho de Melo void events_stats__inc(struct events_stats *stats, u32 type)
234828a6b6aaSArnaldo Carvalho de Melo {
234928a6b6aaSArnaldo Carvalho de Melo 	++stats->nr_events[0];
235028a6b6aaSArnaldo Carvalho de Melo 	++stats->nr_events[type];
235128a6b6aaSArnaldo Carvalho de Melo }
235228a6b6aaSArnaldo Carvalho de Melo 
hists_stats__inc(struct hists_stats * stats)23530f0abbacSNamhyung Kim static void hists_stats__inc(struct hists_stats *stats)
2354c8446b9bSArnaldo Carvalho de Melo {
23550f0abbacSNamhyung Kim 	++stats->nr_samples;
23560f0abbacSNamhyung Kim }
23570f0abbacSNamhyung Kim 
hists__inc_nr_events(struct hists * hists)23580f0abbacSNamhyung Kim void hists__inc_nr_events(struct hists *hists)
23590f0abbacSNamhyung Kim {
23600f0abbacSNamhyung Kim 	hists_stats__inc(&hists->stats);
2361c8446b9bSArnaldo Carvalho de Melo }
236295529be4SArnaldo Carvalho de Melo 
hists__inc_nr_samples(struct hists * hists,bool filtered)23631844dbcbSNamhyung Kim void hists__inc_nr_samples(struct hists *hists, bool filtered)
23641844dbcbSNamhyung Kim {
23650f0abbacSNamhyung Kim 	hists_stats__inc(&hists->stats);
23661844dbcbSNamhyung Kim 	if (!filtered)
23671844dbcbSNamhyung Kim 		hists->stats.nr_non_filtered_samples++;
23681844dbcbSNamhyung Kim }
23691844dbcbSNamhyung Kim 
hists__inc_nr_lost_samples(struct hists * hists,u32 lost)237075b37db0SNamhyung Kim void hists__inc_nr_lost_samples(struct hists *hists, u32 lost)
237175b37db0SNamhyung Kim {
237275b37db0SNamhyung Kim 	hists->stats.nr_lost_samples += lost;
237375b37db0SNamhyung Kim }
237475b37db0SNamhyung Kim 
hists__add_dummy_entry(struct hists * hists,struct hist_entry * pair)2375494d70a1SArnaldo Carvalho de Melo static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
2376494d70a1SArnaldo Carvalho de Melo 						 struct hist_entry *pair)
2377494d70a1SArnaldo Carvalho de Melo {
23782eb3d689SDavidlohr Bueso 	struct rb_root_cached *root;
2379ce74f60eSNamhyung Kim 	struct rb_node **p;
2380494d70a1SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
2381494d70a1SArnaldo Carvalho de Melo 	struct hist_entry *he;
2382354cc40eSAndi Kleen 	int64_t cmp;
23832eb3d689SDavidlohr Bueso 	bool leftmost = true;
2384494d70a1SArnaldo Carvalho de Melo 
238552225036SJiri Olsa 	if (hists__has(hists, need_collapse))
2386ce74f60eSNamhyung Kim 		root = &hists->entries_collapsed;
2387ce74f60eSNamhyung Kim 	else
2388ce74f60eSNamhyung Kim 		root = hists->entries_in;
2389ce74f60eSNamhyung Kim 
23902eb3d689SDavidlohr Bueso 	p = &root->rb_root.rb_node;
2391ce74f60eSNamhyung Kim 
2392494d70a1SArnaldo Carvalho de Melo 	while (*p != NULL) {
2393494d70a1SArnaldo Carvalho de Melo 		parent = *p;
2394ce74f60eSNamhyung Kim 		he = rb_entry(parent, struct hist_entry, rb_node_in);
2395494d70a1SArnaldo Carvalho de Melo 
2396ce74f60eSNamhyung Kim 		cmp = hist_entry__collapse(he, pair);
2397494d70a1SArnaldo Carvalho de Melo 
2398494d70a1SArnaldo Carvalho de Melo 		if (!cmp)
2399494d70a1SArnaldo Carvalho de Melo 			goto out;
2400494d70a1SArnaldo Carvalho de Melo 
2401494d70a1SArnaldo Carvalho de Melo 		if (cmp < 0)
2402494d70a1SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
24032eb3d689SDavidlohr Bueso 		else {
2404494d70a1SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
24052eb3d689SDavidlohr Bueso 			leftmost = false;
24062eb3d689SDavidlohr Bueso 		}
2407494d70a1SArnaldo Carvalho de Melo 	}
2408494d70a1SArnaldo Carvalho de Melo 
2409a0b51af3SNamhyung Kim 	he = hist_entry__new(pair, true);
2410494d70a1SArnaldo Carvalho de Melo 	if (he) {
241130193d78SArnaldo Carvalho de Melo 		memset(&he->stat, 0, sizeof(he->stat));
2412494d70a1SArnaldo Carvalho de Melo 		he->hists = hists;
241309623d79SKan Liang 		if (symbol_conf.cumulate_callchain)
241409623d79SKan Liang 			memset(he->stat_acc, 0, sizeof(he->stat));
2415ce74f60eSNamhyung Kim 		rb_link_node(&he->rb_node_in, parent, p);
24162eb3d689SDavidlohr Bueso 		rb_insert_color_cached(&he->rb_node_in, root, leftmost);
24176263835aSNamhyung Kim 		hists__inc_stats(hists, he);
2418e0af43d2SJiri Olsa 		he->dummy = true;
2419494d70a1SArnaldo Carvalho de Melo 	}
2420494d70a1SArnaldo Carvalho de Melo out:
2421494d70a1SArnaldo Carvalho de Melo 	return he;
2422494d70a1SArnaldo Carvalho de Melo }
2423494d70a1SArnaldo Carvalho de Melo 
add_dummy_hierarchy_entry(struct hists * hists,struct rb_root_cached * root,struct hist_entry * pair)24249d97b8f5SNamhyung Kim static struct hist_entry *add_dummy_hierarchy_entry(struct hists *hists,
24252eb3d689SDavidlohr Bueso 						    struct rb_root_cached *root,
24269d97b8f5SNamhyung Kim 						    struct hist_entry *pair)
24279d97b8f5SNamhyung Kim {
24289d97b8f5SNamhyung Kim 	struct rb_node **p;
24299d97b8f5SNamhyung Kim 	struct rb_node *parent = NULL;
24309d97b8f5SNamhyung Kim 	struct hist_entry *he;
24319d97b8f5SNamhyung Kim 	struct perf_hpp_fmt *fmt;
24322eb3d689SDavidlohr Bueso 	bool leftmost = true;
24339d97b8f5SNamhyung Kim 
24342eb3d689SDavidlohr Bueso 	p = &root->rb_root.rb_node;
24359d97b8f5SNamhyung Kim 	while (*p != NULL) {
24369d97b8f5SNamhyung Kim 		int64_t cmp = 0;
24379d97b8f5SNamhyung Kim 
24389d97b8f5SNamhyung Kim 		parent = *p;
24399d97b8f5SNamhyung Kim 		he = rb_entry(parent, struct hist_entry, rb_node_in);
24409d97b8f5SNamhyung Kim 
24419d97b8f5SNamhyung Kim 		perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
24429d97b8f5SNamhyung Kim 			cmp = fmt->collapse(fmt, he, pair);
24439d97b8f5SNamhyung Kim 			if (cmp)
24449d97b8f5SNamhyung Kim 				break;
24459d97b8f5SNamhyung Kim 		}
24469d97b8f5SNamhyung Kim 		if (!cmp)
24479d97b8f5SNamhyung Kim 			goto out;
24489d97b8f5SNamhyung Kim 
24499d97b8f5SNamhyung Kim 		if (cmp < 0)
24509d97b8f5SNamhyung Kim 			p = &parent->rb_left;
24512eb3d689SDavidlohr Bueso 		else {
24529d97b8f5SNamhyung Kim 			p = &parent->rb_right;
24532eb3d689SDavidlohr Bueso 			leftmost = false;
24542eb3d689SDavidlohr Bueso 		}
24559d97b8f5SNamhyung Kim 	}
24569d97b8f5SNamhyung Kim 
24579d97b8f5SNamhyung Kim 	he = hist_entry__new(pair, true);
24589d97b8f5SNamhyung Kim 	if (he) {
24599d97b8f5SNamhyung Kim 		rb_link_node(&he->rb_node_in, parent, p);
24602eb3d689SDavidlohr Bueso 		rb_insert_color_cached(&he->rb_node_in, root, leftmost);
24619d97b8f5SNamhyung Kim 
24629d97b8f5SNamhyung Kim 		he->dummy = true;
24639d97b8f5SNamhyung Kim 		he->hists = hists;
24649d97b8f5SNamhyung Kim 		memset(&he->stat, 0, sizeof(he->stat));
24659d97b8f5SNamhyung Kim 		hists__inc_stats(hists, he);
24669d97b8f5SNamhyung Kim 	}
24679d97b8f5SNamhyung Kim out:
24689d97b8f5SNamhyung Kim 	return he;
24699d97b8f5SNamhyung Kim }
24709d97b8f5SNamhyung Kim 
hists__find_entry(struct hists * hists,struct hist_entry * he)247195529be4SArnaldo Carvalho de Melo static struct hist_entry *hists__find_entry(struct hists *hists,
247295529be4SArnaldo Carvalho de Melo 					    struct hist_entry *he)
247395529be4SArnaldo Carvalho de Melo {
2474ce74f60eSNamhyung Kim 	struct rb_node *n;
2475ce74f60eSNamhyung Kim 
247652225036SJiri Olsa 	if (hists__has(hists, need_collapse))
24772eb3d689SDavidlohr Bueso 		n = hists->entries_collapsed.rb_root.rb_node;
2478ce74f60eSNamhyung Kim 	else
24792eb3d689SDavidlohr Bueso 		n = hists->entries_in->rb_root.rb_node;
248095529be4SArnaldo Carvalho de Melo 
248195529be4SArnaldo Carvalho de Melo 	while (n) {
2482ce74f60eSNamhyung Kim 		struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in);
2483ce74f60eSNamhyung Kim 		int64_t cmp = hist_entry__collapse(iter, he);
248495529be4SArnaldo Carvalho de Melo 
248595529be4SArnaldo Carvalho de Melo 		if (cmp < 0)
248695529be4SArnaldo Carvalho de Melo 			n = n->rb_left;
248795529be4SArnaldo Carvalho de Melo 		else if (cmp > 0)
248895529be4SArnaldo Carvalho de Melo 			n = n->rb_right;
248995529be4SArnaldo Carvalho de Melo 		else
249095529be4SArnaldo Carvalho de Melo 			return iter;
249195529be4SArnaldo Carvalho de Melo 	}
249295529be4SArnaldo Carvalho de Melo 
249395529be4SArnaldo Carvalho de Melo 	return NULL;
249495529be4SArnaldo Carvalho de Melo }
249595529be4SArnaldo Carvalho de Melo 
hists__find_hierarchy_entry(struct rb_root_cached * root,struct hist_entry * he)24962eb3d689SDavidlohr Bueso static struct hist_entry *hists__find_hierarchy_entry(struct rb_root_cached *root,
249709034de6SNamhyung Kim 						      struct hist_entry *he)
249809034de6SNamhyung Kim {
24992eb3d689SDavidlohr Bueso 	struct rb_node *n = root->rb_root.rb_node;
250009034de6SNamhyung Kim 
250109034de6SNamhyung Kim 	while (n) {
250209034de6SNamhyung Kim 		struct hist_entry *iter;
250309034de6SNamhyung Kim 		struct perf_hpp_fmt *fmt;
250409034de6SNamhyung Kim 		int64_t cmp = 0;
250509034de6SNamhyung Kim 
250609034de6SNamhyung Kim 		iter = rb_entry(n, struct hist_entry, rb_node_in);
250709034de6SNamhyung Kim 		perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
250809034de6SNamhyung Kim 			cmp = fmt->collapse(fmt, iter, he);
250909034de6SNamhyung Kim 			if (cmp)
251009034de6SNamhyung Kim 				break;
251109034de6SNamhyung Kim 		}
251209034de6SNamhyung Kim 
251309034de6SNamhyung Kim 		if (cmp < 0)
251409034de6SNamhyung Kim 			n = n->rb_left;
251509034de6SNamhyung Kim 		else if (cmp > 0)
251609034de6SNamhyung Kim 			n = n->rb_right;
251709034de6SNamhyung Kim 		else
251809034de6SNamhyung Kim 			return iter;
251909034de6SNamhyung Kim 	}
252009034de6SNamhyung Kim 
252109034de6SNamhyung Kim 	return NULL;
252209034de6SNamhyung Kim }
252309034de6SNamhyung Kim 
hists__match_hierarchy(struct rb_root_cached * leader_root,struct rb_root_cached * other_root)25242eb3d689SDavidlohr Bueso static void hists__match_hierarchy(struct rb_root_cached *leader_root,
25252eb3d689SDavidlohr Bueso 				   struct rb_root_cached *other_root)
252609034de6SNamhyung Kim {
252709034de6SNamhyung Kim 	struct rb_node *nd;
252809034de6SNamhyung Kim 	struct hist_entry *pos, *pair;
252909034de6SNamhyung Kim 
25302eb3d689SDavidlohr Bueso 	for (nd = rb_first_cached(leader_root); nd; nd = rb_next(nd)) {
253109034de6SNamhyung Kim 		pos  = rb_entry(nd, struct hist_entry, rb_node_in);
253209034de6SNamhyung Kim 		pair = hists__find_hierarchy_entry(other_root, pos);
253309034de6SNamhyung Kim 
253409034de6SNamhyung Kim 		if (pair) {
253509034de6SNamhyung Kim 			hist_entry__add_pair(pair, pos);
253609034de6SNamhyung Kim 			hists__match_hierarchy(&pos->hroot_in, &pair->hroot_in);
253709034de6SNamhyung Kim 		}
253809034de6SNamhyung Kim 	}
253909034de6SNamhyung Kim }
254009034de6SNamhyung Kim 
254195529be4SArnaldo Carvalho de Melo /*
254295529be4SArnaldo Carvalho de Melo  * Look for pairs to link to the leader buckets (hist_entries):
254395529be4SArnaldo Carvalho de Melo  */
hists__match(struct hists * leader,struct hists * other)254495529be4SArnaldo Carvalho de Melo void hists__match(struct hists *leader, struct hists *other)
254595529be4SArnaldo Carvalho de Melo {
25462eb3d689SDavidlohr Bueso 	struct rb_root_cached *root;
254795529be4SArnaldo Carvalho de Melo 	struct rb_node *nd;
2548be5863b7SNamhyung Kim 	struct hist_entry *pos, *pair;
254995529be4SArnaldo Carvalho de Melo 
255009034de6SNamhyung Kim 	if (symbol_conf.report_hierarchy) {
255109034de6SNamhyung Kim 		/* hierarchy report always collapses entries */
255209034de6SNamhyung Kim 		return hists__match_hierarchy(&leader->entries_collapsed,
255309034de6SNamhyung Kim 					      &other->entries_collapsed);
255409034de6SNamhyung Kim 	}
255509034de6SNamhyung Kim 
255652225036SJiri Olsa 	if (hists__has(leader, need_collapse))
2557ce74f60eSNamhyung Kim 		root = &leader->entries_collapsed;
2558ce74f60eSNamhyung Kim 	else
2559ce74f60eSNamhyung Kim 		root = leader->entries_in;
2560ce74f60eSNamhyung Kim 
25612eb3d689SDavidlohr Bueso 	for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
2562ce74f60eSNamhyung Kim 		pos  = rb_entry(nd, struct hist_entry, rb_node_in);
256395529be4SArnaldo Carvalho de Melo 		pair = hists__find_entry(other, pos);
256495529be4SArnaldo Carvalho de Melo 
2565be5863b7SNamhyung Kim 		if (pair)
25665fa9041bSNamhyung Kim 			hist_entry__add_pair(pair, pos);
256795529be4SArnaldo Carvalho de Melo 	}
256895529be4SArnaldo Carvalho de Melo }
2569494d70a1SArnaldo Carvalho de Melo 
hists__link_hierarchy(struct hists * leader_hists,struct hist_entry * parent,struct rb_root_cached * leader_root,struct rb_root_cached * other_root)25709d97b8f5SNamhyung Kim static int hists__link_hierarchy(struct hists *leader_hists,
25719d97b8f5SNamhyung Kim 				 struct hist_entry *parent,
25722eb3d689SDavidlohr Bueso 				 struct rb_root_cached *leader_root,
25732eb3d689SDavidlohr Bueso 				 struct rb_root_cached *other_root)
25749d97b8f5SNamhyung Kim {
25759d97b8f5SNamhyung Kim 	struct rb_node *nd;
25769d97b8f5SNamhyung Kim 	struct hist_entry *pos, *leader;
25779d97b8f5SNamhyung Kim 
25782eb3d689SDavidlohr Bueso 	for (nd = rb_first_cached(other_root); nd; nd = rb_next(nd)) {
25799d97b8f5SNamhyung Kim 		pos = rb_entry(nd, struct hist_entry, rb_node_in);
25809d97b8f5SNamhyung Kim 
25819d97b8f5SNamhyung Kim 		if (hist_entry__has_pairs(pos)) {
25829d97b8f5SNamhyung Kim 			bool found = false;
25839d97b8f5SNamhyung Kim 
25849d97b8f5SNamhyung Kim 			list_for_each_entry(leader, &pos->pairs.head, pairs.node) {
25859d97b8f5SNamhyung Kim 				if (leader->hists == leader_hists) {
25869d97b8f5SNamhyung Kim 					found = true;
25879d97b8f5SNamhyung Kim 					break;
25889d97b8f5SNamhyung Kim 				}
25899d97b8f5SNamhyung Kim 			}
25909d97b8f5SNamhyung Kim 			if (!found)
25919d97b8f5SNamhyung Kim 				return -1;
25929d97b8f5SNamhyung Kim 		} else {
25939d97b8f5SNamhyung Kim 			leader = add_dummy_hierarchy_entry(leader_hists,
25949d97b8f5SNamhyung Kim 							   leader_root, pos);
25959d97b8f5SNamhyung Kim 			if (leader == NULL)
25969d97b8f5SNamhyung Kim 				return -1;
25979d97b8f5SNamhyung Kim 
25989d97b8f5SNamhyung Kim 			/* do not point parent in the pos */
25999d97b8f5SNamhyung Kim 			leader->parent_he = parent;
26009d97b8f5SNamhyung Kim 
26019d97b8f5SNamhyung Kim 			hist_entry__add_pair(pos, leader);
26029d97b8f5SNamhyung Kim 		}
26039d97b8f5SNamhyung Kim 
26049d97b8f5SNamhyung Kim 		if (!pos->leaf) {
26059d97b8f5SNamhyung Kim 			if (hists__link_hierarchy(leader_hists, leader,
26069d97b8f5SNamhyung Kim 						  &leader->hroot_in,
26079d97b8f5SNamhyung Kim 						  &pos->hroot_in) < 0)
26089d97b8f5SNamhyung Kim 				return -1;
26099d97b8f5SNamhyung Kim 		}
26109d97b8f5SNamhyung Kim 	}
26119d97b8f5SNamhyung Kim 	return 0;
26129d97b8f5SNamhyung Kim }
26139d97b8f5SNamhyung Kim 
2614494d70a1SArnaldo Carvalho de Melo /*
2615494d70a1SArnaldo Carvalho de Melo  * Look for entries in the other hists that are not present in the leader, if
2616494d70a1SArnaldo Carvalho de Melo  * we find them, just add a dummy entry on the leader hists, with period=0,
2617494d70a1SArnaldo Carvalho de Melo  * nr_events=0, to serve as the list header.
2618494d70a1SArnaldo Carvalho de Melo  */
hists__link(struct hists * leader,struct hists * other)2619494d70a1SArnaldo Carvalho de Melo int hists__link(struct hists *leader, struct hists *other)
2620494d70a1SArnaldo Carvalho de Melo {
26212eb3d689SDavidlohr Bueso 	struct rb_root_cached *root;
2622494d70a1SArnaldo Carvalho de Melo 	struct rb_node *nd;
2623494d70a1SArnaldo Carvalho de Melo 	struct hist_entry *pos, *pair;
2624494d70a1SArnaldo Carvalho de Melo 
26259d97b8f5SNamhyung Kim 	if (symbol_conf.report_hierarchy) {
26269d97b8f5SNamhyung Kim 		/* hierarchy report always collapses entries */
26279d97b8f5SNamhyung Kim 		return hists__link_hierarchy(leader, NULL,
26289d97b8f5SNamhyung Kim 					     &leader->entries_collapsed,
26299d97b8f5SNamhyung Kim 					     &other->entries_collapsed);
26309d97b8f5SNamhyung Kim 	}
26319d97b8f5SNamhyung Kim 
263252225036SJiri Olsa 	if (hists__has(other, need_collapse))
2633ce74f60eSNamhyung Kim 		root = &other->entries_collapsed;
2634ce74f60eSNamhyung Kim 	else
2635ce74f60eSNamhyung Kim 		root = other->entries_in;
2636ce74f60eSNamhyung Kim 
26372eb3d689SDavidlohr Bueso 	for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
2638ce74f60eSNamhyung Kim 		pos = rb_entry(nd, struct hist_entry, rb_node_in);
2639494d70a1SArnaldo Carvalho de Melo 
2640494d70a1SArnaldo Carvalho de Melo 		if (!hist_entry__has_pairs(pos)) {
2641494d70a1SArnaldo Carvalho de Melo 			pair = hists__add_dummy_entry(leader, pos);
2642494d70a1SArnaldo Carvalho de Melo 			if (pair == NULL)
2643494d70a1SArnaldo Carvalho de Melo 				return -1;
26445fa9041bSNamhyung Kim 			hist_entry__add_pair(pos, pair);
2645494d70a1SArnaldo Carvalho de Melo 		}
2646494d70a1SArnaldo Carvalho de Melo 	}
2647494d70a1SArnaldo Carvalho de Melo 
2648494d70a1SArnaldo Carvalho de Melo 	return 0;
2649494d70a1SArnaldo Carvalho de Melo }
2650f2148330SNamhyung Kim 
hists__unlink(struct hists * hists)2651be5863b7SNamhyung Kim int hists__unlink(struct hists *hists)
2652be5863b7SNamhyung Kim {
2653be5863b7SNamhyung Kim 	struct rb_root_cached *root;
2654be5863b7SNamhyung Kim 	struct rb_node *nd;
2655be5863b7SNamhyung Kim 	struct hist_entry *pos;
2656be5863b7SNamhyung Kim 
2657be5863b7SNamhyung Kim 	if (hists__has(hists, need_collapse))
2658be5863b7SNamhyung Kim 		root = &hists->entries_collapsed;
2659be5863b7SNamhyung Kim 	else
2660be5863b7SNamhyung Kim 		root = hists->entries_in;
2661be5863b7SNamhyung Kim 
2662be5863b7SNamhyung Kim 	for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
2663be5863b7SNamhyung Kim 		pos = rb_entry(nd, struct hist_entry, rb_node_in);
2664be5863b7SNamhyung Kim 		list_del_init(&pos->pairs.node);
2665be5863b7SNamhyung Kim 	}
2666be5863b7SNamhyung Kim 
2667be5863b7SNamhyung Kim 	return 0;
2668be5863b7SNamhyung Kim }
2669be5863b7SNamhyung Kim 
hist__account_cycles(struct branch_stack * bs,struct addr_location * al,struct perf_sample * sample,bool nonany_branch_mode,u64 * total_cycles)267057849998SAndi Kleen void hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
26717841f40aSJin Yao 			  struct perf_sample *sample, bool nonany_branch_mode,
26727841f40aSJin Yao 			  u64 *total_cycles)
267357849998SAndi Kleen {
267457849998SAndi Kleen 	struct branch_info *bi;
267542bbabedSKan Liang 	struct branch_entry *entries = perf_sample__branch_entries(sample);
267657849998SAndi Kleen 
267757849998SAndi Kleen 	/* If we have branch cycles always annotate them. */
267842bbabedSKan Liang 	if (bs && bs->nr && entries[0].flags.cycles) {
267957849998SAndi Kleen 		bi = sample__resolve_bstack(sample, al);
268057849998SAndi Kleen 		if (bi) {
268157849998SAndi Kleen 			struct addr_map_symbol *prev = NULL;
268257849998SAndi Kleen 
268357849998SAndi Kleen 			/*
268457849998SAndi Kleen 			 * Ignore errors, still want to process the
268557849998SAndi Kleen 			 * other entries.
268657849998SAndi Kleen 			 *
268757849998SAndi Kleen 			 * For non standard branch modes always
268857849998SAndi Kleen 			 * force no IPC (prev == NULL)
268957849998SAndi Kleen 			 *
269057849998SAndi Kleen 			 * Note that perf stores branches reversed from
269157849998SAndi Kleen 			 * program order!
269257849998SAndi Kleen 			 */
2693*58157004SIan Rogers 			for (int i = bs->nr - 1; i >= 0; i--) {
269457849998SAndi Kleen 				addr_map_symbol__account_cycles(&bi[i].from,
269557849998SAndi Kleen 					nonany_branch_mode ? NULL : prev,
269657849998SAndi Kleen 					bi[i].flags.cycles);
269757849998SAndi Kleen 				prev = &bi[i].to;
26987841f40aSJin Yao 
26997841f40aSJin Yao 				if (total_cycles)
27007841f40aSJin Yao 					*total_cycles += bi[i].flags.cycles;
270157849998SAndi Kleen 			}
2702*58157004SIan Rogers 			for (unsigned int i = 0; i < bs->nr; i++) {
2703*58157004SIan Rogers 				map__put(bi[i].to.ms.map);
2704*58157004SIan Rogers 				maps__put(bi[i].to.ms.maps);
2705*58157004SIan Rogers 				map__put(bi[i].from.ms.map);
2706*58157004SIan Rogers 				maps__put(bi[i].from.ms.maps);
2707*58157004SIan Rogers 			}
270857849998SAndi Kleen 			free(bi);
270957849998SAndi Kleen 		}
271057849998SAndi Kleen 	}
271157849998SAndi Kleen }
27122a1731fbSArnaldo Carvalho de Melo 
evlist__fprintf_nr_events(struct evlist * evlist,FILE * fp,bool skip_empty)27132775de0bSNamhyung Kim size_t evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp,
27142775de0bSNamhyung Kim 				 bool skip_empty)
27152a1731fbSArnaldo Carvalho de Melo {
271632dcd021SJiri Olsa 	struct evsel *pos;
27172a1731fbSArnaldo Carvalho de Melo 	size_t ret = 0;
27182a1731fbSArnaldo Carvalho de Melo 
2719e5cadb93SArnaldo Carvalho de Melo 	evlist__for_each_entry(evlist, pos) {
27200f0abbacSNamhyung Kim 		struct hists *hists = evsel__hists(pos);
27210f0abbacSNamhyung Kim 
2722d7ba22d4SNamhyung Kim 		if (skip_empty && !hists->stats.nr_samples && !hists->stats.nr_lost_samples)
27232775de0bSNamhyung Kim 			continue;
27242775de0bSNamhyung Kim 
27258ab2e96dSArnaldo Carvalho de Melo 		ret += fprintf(fp, "%s stats:\n", evsel__name(pos));
2726d7ba22d4SNamhyung Kim 		if (hists->stats.nr_samples)
27270f0abbacSNamhyung Kim 			ret += fprintf(fp, "%16s events: %10d\n",
27280f0abbacSNamhyung Kim 				       "SAMPLE", hists->stats.nr_samples);
2729d7ba22d4SNamhyung Kim 		if (hists->stats.nr_lost_samples)
2730d7ba22d4SNamhyung Kim 			ret += fprintf(fp, "%16s events: %10d\n",
2731d7ba22d4SNamhyung Kim 				       "LOST_SAMPLES", hists->stats.nr_lost_samples);
27322a1731fbSArnaldo Carvalho de Melo 	}
27332a1731fbSArnaldo Carvalho de Melo 
27342a1731fbSArnaldo Carvalho de Melo 	return ret;
27352a1731fbSArnaldo Carvalho de Melo }
27362a1731fbSArnaldo Carvalho de Melo 
27372a1731fbSArnaldo Carvalho de Melo 
hists__total_period(struct hists * hists)2738f2148330SNamhyung Kim u64 hists__total_period(struct hists *hists)
2739f2148330SNamhyung Kim {
2740f2148330SNamhyung Kim 	return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period :
2741f2148330SNamhyung Kim 		hists->stats.total_period;
2742f2148330SNamhyung Kim }
274333db4568SNamhyung Kim 
__hists__scnprintf_title(struct hists * hists,char * bf,size_t size,bool show_freq)274425c312dbSArnaldo Carvalho de Melo int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool show_freq)
274525c312dbSArnaldo Carvalho de Melo {
274625c312dbSArnaldo Carvalho de Melo 	char unit;
274725c312dbSArnaldo Carvalho de Melo 	int printed;
274825c312dbSArnaldo Carvalho de Melo 	const struct dso *dso = hists->dso_filter;
27497cb10a08SNamhyung Kim 	struct thread *thread = hists->thread_filter;
275025c312dbSArnaldo Carvalho de Melo 	int socket_id = hists->socket_filter;
27510f0abbacSNamhyung Kim 	unsigned long nr_samples = hists->stats.nr_samples;
275225c312dbSArnaldo Carvalho de Melo 	u64 nr_events = hists->stats.total_period;
275332dcd021SJiri Olsa 	struct evsel *evsel = hists_to_evsel(hists);
27548ab2e96dSArnaldo Carvalho de Melo 	const char *ev_name = evsel__name(evsel);
275525c312dbSArnaldo Carvalho de Melo 	char buf[512], sample_freq_str[64] = "";
275625c312dbSArnaldo Carvalho de Melo 	size_t buflen = sizeof(buf);
275725c312dbSArnaldo Carvalho de Melo 	char ref[30] = " show reference callgraph, ";
275825c312dbSArnaldo Carvalho de Melo 	bool enable_ref = false;
275925c312dbSArnaldo Carvalho de Melo 
276025c312dbSArnaldo Carvalho de Melo 	if (symbol_conf.filter_relative) {
276125c312dbSArnaldo Carvalho de Melo 		nr_samples = hists->stats.nr_non_filtered_samples;
276225c312dbSArnaldo Carvalho de Melo 		nr_events = hists->stats.total_non_filtered_period;
276325c312dbSArnaldo Carvalho de Melo 	}
276425c312dbSArnaldo Carvalho de Melo 
2765c754c382SArnaldo Carvalho de Melo 	if (evsel__is_group_event(evsel)) {
276632dcd021SJiri Olsa 		struct evsel *pos;
276725c312dbSArnaldo Carvalho de Melo 
2768347c751aSArnaldo Carvalho de Melo 		evsel__group_desc(evsel, buf, buflen);
276925c312dbSArnaldo Carvalho de Melo 		ev_name = buf;
277025c312dbSArnaldo Carvalho de Melo 
277125c312dbSArnaldo Carvalho de Melo 		for_each_group_member(pos, evsel) {
277225c312dbSArnaldo Carvalho de Melo 			struct hists *pos_hists = evsel__hists(pos);
277325c312dbSArnaldo Carvalho de Melo 
277425c312dbSArnaldo Carvalho de Melo 			if (symbol_conf.filter_relative) {
277525c312dbSArnaldo Carvalho de Melo 				nr_samples += pos_hists->stats.nr_non_filtered_samples;
277625c312dbSArnaldo Carvalho de Melo 				nr_events += pos_hists->stats.total_non_filtered_period;
277725c312dbSArnaldo Carvalho de Melo 			} else {
27780f0abbacSNamhyung Kim 				nr_samples += pos_hists->stats.nr_samples;
277925c312dbSArnaldo Carvalho de Melo 				nr_events += pos_hists->stats.total_period;
278025c312dbSArnaldo Carvalho de Melo 			}
278125c312dbSArnaldo Carvalho de Melo 		}
278225c312dbSArnaldo Carvalho de Melo 	}
278325c312dbSArnaldo Carvalho de Melo 
278425c312dbSArnaldo Carvalho de Melo 	if (symbol_conf.show_ref_callgraph &&
278525c312dbSArnaldo Carvalho de Melo 	    strstr(ev_name, "call-graph=no"))
278625c312dbSArnaldo Carvalho de Melo 		enable_ref = true;
278725c312dbSArnaldo Carvalho de Melo 
278825c312dbSArnaldo Carvalho de Melo 	if (show_freq)
27891fc632ceSJiri Olsa 		scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->core.attr.sample_freq);
279025c312dbSArnaldo Carvalho de Melo 
279125c312dbSArnaldo Carvalho de Melo 	nr_samples = convert_unit(nr_samples, &unit);
279225c312dbSArnaldo Carvalho de Melo 	printed = scnprintf(bf, size,
279325c312dbSArnaldo Carvalho de Melo 			   "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64,
27945643b1a5SJiri Olsa 			   nr_samples, unit, evsel->core.nr_members > 1 ? "s" : "",
279525c312dbSArnaldo Carvalho de Melo 			   ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events);
279625c312dbSArnaldo Carvalho de Melo 
279725c312dbSArnaldo Carvalho de Melo 
279825c312dbSArnaldo Carvalho de Melo 	if (hists->uid_filter_str)
279925c312dbSArnaldo Carvalho de Melo 		printed += snprintf(bf + printed, size - printed,
280025c312dbSArnaldo Carvalho de Melo 				    ", UID: %s", hists->uid_filter_str);
280125c312dbSArnaldo Carvalho de Melo 	if (thread) {
280225c312dbSArnaldo Carvalho de Melo 		if (hists__has(hists, thread)) {
280325c312dbSArnaldo Carvalho de Melo 			printed += scnprintf(bf + printed, size - printed,
280425c312dbSArnaldo Carvalho de Melo 				    ", Thread: %s(%d)",
2805ee84a303SIan Rogers 				    (thread__comm_set(thread) ? thread__comm_str(thread) : ""),
2806ee84a303SIan Rogers 					thread__tid(thread));
280725c312dbSArnaldo Carvalho de Melo 		} else {
280825c312dbSArnaldo Carvalho de Melo 			printed += scnprintf(bf + printed, size - printed,
280925c312dbSArnaldo Carvalho de Melo 				    ", Thread: %s",
2810ee84a303SIan Rogers 				    (thread__comm_set(thread) ? thread__comm_str(thread) : ""));
281125c312dbSArnaldo Carvalho de Melo 		}
281225c312dbSArnaldo Carvalho de Melo 	}
281325c312dbSArnaldo Carvalho de Melo 	if (dso)
281425c312dbSArnaldo Carvalho de Melo 		printed += scnprintf(bf + printed, size - printed,
281525c312dbSArnaldo Carvalho de Melo 				    ", DSO: %s", dso->short_name);
281625c312dbSArnaldo Carvalho de Melo 	if (socket_id > -1)
281725c312dbSArnaldo Carvalho de Melo 		printed += scnprintf(bf + printed, size - printed,
281825c312dbSArnaldo Carvalho de Melo 				    ", Processor Socket: %d", socket_id);
281925c312dbSArnaldo Carvalho de Melo 
282025c312dbSArnaldo Carvalho de Melo 	return printed;
282125c312dbSArnaldo Carvalho de Melo }
282225c312dbSArnaldo Carvalho de Melo 
parse_filter_percentage(const struct option * opt __maybe_unused,const char * arg,int unset __maybe_unused)282333db4568SNamhyung Kim int parse_filter_percentage(const struct option *opt __maybe_unused,
282433db4568SNamhyung Kim 			    const char *arg, int unset __maybe_unused)
282533db4568SNamhyung Kim {
282633db4568SNamhyung Kim 	if (!strcmp(arg, "relative"))
282733db4568SNamhyung Kim 		symbol_conf.filter_relative = true;
282833db4568SNamhyung Kim 	else if (!strcmp(arg, "absolute"))
282933db4568SNamhyung Kim 		symbol_conf.filter_relative = false;
2830ecc4c561SArnaldo Carvalho de Melo 	else {
2831a596a877SColin Ian King 		pr_debug("Invalid percentage: %s\n", arg);
283233db4568SNamhyung Kim 		return -1;
2833ecc4c561SArnaldo Carvalho de Melo 	}
283433db4568SNamhyung Kim 
283533db4568SNamhyung Kim 	return 0;
283633db4568SNamhyung Kim }
28370b93da17SNamhyung Kim 
perf_hist_config(const char * var,const char * value)28380b93da17SNamhyung Kim int perf_hist_config(const char *var, const char *value)
28390b93da17SNamhyung Kim {
28400b93da17SNamhyung Kim 	if (!strcmp(var, "hist.percentage"))
28410b93da17SNamhyung Kim 		return parse_filter_percentage(NULL, value, 0);
28420b93da17SNamhyung Kim 
28430b93da17SNamhyung Kim 	return 0;
28440b93da17SNamhyung Kim }
2845a635fc51SArnaldo Carvalho de Melo 
__hists__init(struct hists * hists,struct perf_hpp_list * hpp_list)28465b65855eSJiri Olsa int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list)
2847a635fc51SArnaldo Carvalho de Melo {
2848a635fc51SArnaldo Carvalho de Melo 	memset(hists, 0, sizeof(*hists));
28492eb3d689SDavidlohr Bueso 	hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT_CACHED;
2850a635fc51SArnaldo Carvalho de Melo 	hists->entries_in = &hists->entries_in_array[0];
28512eb3d689SDavidlohr Bueso 	hists->entries_collapsed = RB_ROOT_CACHED;
28522eb3d689SDavidlohr Bueso 	hists->entries = RB_ROOT_CACHED;
28538e03bb88SIan Rogers 	mutex_init(&hists->lock);
285421394d94SKan Liang 	hists->socket_filter = -1;
28555b65855eSJiri Olsa 	hists->hpp_list = hpp_list;
2856c3bc0c43SNamhyung Kim 	INIT_LIST_HEAD(&hists->hpp_formats);
2857a635fc51SArnaldo Carvalho de Melo 	return 0;
2858a635fc51SArnaldo Carvalho de Melo }
2859a635fc51SArnaldo Carvalho de Melo 
hists__delete_remaining_entries(struct rb_root_cached * root)28602eb3d689SDavidlohr Bueso static void hists__delete_remaining_entries(struct rb_root_cached *root)
286161fa0e94SNamhyung Kim {
286261fa0e94SNamhyung Kim 	struct rb_node *node;
286361fa0e94SNamhyung Kim 	struct hist_entry *he;
286461fa0e94SNamhyung Kim 
28652eb3d689SDavidlohr Bueso 	while (!RB_EMPTY_ROOT(&root->rb_root)) {
28662eb3d689SDavidlohr Bueso 		node = rb_first_cached(root);
28672eb3d689SDavidlohr Bueso 		rb_erase_cached(node, root);
286861fa0e94SNamhyung Kim 
286961fa0e94SNamhyung Kim 		he = rb_entry(node, struct hist_entry, rb_node_in);
287061fa0e94SNamhyung Kim 		hist_entry__delete(he);
287161fa0e94SNamhyung Kim 	}
287261fa0e94SNamhyung Kim }
287361fa0e94SNamhyung Kim 
hists__delete_all_entries(struct hists * hists)287461fa0e94SNamhyung Kim static void hists__delete_all_entries(struct hists *hists)
287561fa0e94SNamhyung Kim {
287661fa0e94SNamhyung Kim 	hists__delete_entries(hists);
287761fa0e94SNamhyung Kim 	hists__delete_remaining_entries(&hists->entries_in_array[0]);
287861fa0e94SNamhyung Kim 	hists__delete_remaining_entries(&hists->entries_in_array[1]);
287961fa0e94SNamhyung Kim 	hists__delete_remaining_entries(&hists->entries_collapsed);
288061fa0e94SNamhyung Kim }
288161fa0e94SNamhyung Kim 
hists_evsel__exit(struct evsel * evsel)288232dcd021SJiri Olsa static void hists_evsel__exit(struct evsel *evsel)
288317577decSMasami Hiramatsu {
288417577decSMasami Hiramatsu 	struct hists *hists = evsel__hists(evsel);
2885c3bc0c43SNamhyung Kim 	struct perf_hpp_fmt *fmt, *pos;
2886c3bc0c43SNamhyung Kim 	struct perf_hpp_list_node *node, *tmp;
288717577decSMasami Hiramatsu 
288861fa0e94SNamhyung Kim 	hists__delete_all_entries(hists);
2889c3bc0c43SNamhyung Kim 
2890c3bc0c43SNamhyung Kim 	list_for_each_entry_safe(node, tmp, &hists->hpp_formats, list) {
2891c3bc0c43SNamhyung Kim 		perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
2892e56fbc9dSArnaldo Carvalho de Melo 			list_del_init(&fmt->list);
2893c3bc0c43SNamhyung Kim 			free(fmt);
2894c3bc0c43SNamhyung Kim 		}
2895e56fbc9dSArnaldo Carvalho de Melo 		list_del_init(&node->list);
2896c3bc0c43SNamhyung Kim 		free(node);
2897c3bc0c43SNamhyung Kim 	}
289817577decSMasami Hiramatsu }
289917577decSMasami Hiramatsu 
hists_evsel__init(struct evsel * evsel)290032dcd021SJiri Olsa static int hists_evsel__init(struct evsel *evsel)
2901fc284be9SNamhyung Kim {
2902fc284be9SNamhyung Kim 	struct hists *hists = evsel__hists(evsel);
2903fc284be9SNamhyung Kim 
29045b65855eSJiri Olsa 	__hists__init(hists, &perf_hpp_list);
2905fc284be9SNamhyung Kim 	return 0;
2906fc284be9SNamhyung Kim }
2907fc284be9SNamhyung Kim 
2908a635fc51SArnaldo Carvalho de Melo /*
2909a635fc51SArnaldo Carvalho de Melo  * XXX We probably need a hists_evsel__exit() to free the hist_entries
2910a635fc51SArnaldo Carvalho de Melo  * stored in the rbtree...
2911a635fc51SArnaldo Carvalho de Melo  */
2912a635fc51SArnaldo Carvalho de Melo 
hists__init(void)2913a635fc51SArnaldo Carvalho de Melo int hists__init(void)
2914a635fc51SArnaldo Carvalho de Melo {
29154c703828SArnaldo Carvalho de Melo 	int err = evsel__object_config(sizeof(struct hists_evsel),
29164c703828SArnaldo Carvalho de Melo 				       hists_evsel__init, hists_evsel__exit);
2917a635fc51SArnaldo Carvalho de Melo 	if (err)
2918a635fc51SArnaldo Carvalho de Melo 		fputs("FATAL ERROR: Couldn't setup hists class\n", stderr);
2919a635fc51SArnaldo Carvalho de Melo 
2920a635fc51SArnaldo Carvalho de Melo 	return err;
2921a635fc51SArnaldo Carvalho de Melo }
292294b3dc38SJiri Olsa 
perf_hpp_list__init(struct perf_hpp_list * list)292394b3dc38SJiri Olsa void perf_hpp_list__init(struct perf_hpp_list *list)
292494b3dc38SJiri Olsa {
292594b3dc38SJiri Olsa 	INIT_LIST_HEAD(&list->fields);
292694b3dc38SJiri Olsa 	INIT_LIST_HEAD(&list->sorts);
292794b3dc38SJiri Olsa }
2928