162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include "callchain.h"
362306a36Sopenharmony_ci#include "debug.h"
462306a36Sopenharmony_ci#include "dso.h"
562306a36Sopenharmony_ci#include "build-id.h"
662306a36Sopenharmony_ci#include "hist.h"
762306a36Sopenharmony_ci#include "kvm-stat.h"
862306a36Sopenharmony_ci#include "map.h"
962306a36Sopenharmony_ci#include "map_symbol.h"
1062306a36Sopenharmony_ci#include "branch.h"
1162306a36Sopenharmony_ci#include "mem-events.h"
1262306a36Sopenharmony_ci#include "session.h"
1362306a36Sopenharmony_ci#include "namespaces.h"
1462306a36Sopenharmony_ci#include "cgroup.h"
1562306a36Sopenharmony_ci#include "sort.h"
1662306a36Sopenharmony_ci#include "units.h"
1762306a36Sopenharmony_ci#include "evlist.h"
1862306a36Sopenharmony_ci#include "evsel.h"
1962306a36Sopenharmony_ci#include "annotate.h"
2062306a36Sopenharmony_ci#include "srcline.h"
2162306a36Sopenharmony_ci#include "symbol.h"
2262306a36Sopenharmony_ci#include "thread.h"
2362306a36Sopenharmony_ci#include "block-info.h"
2462306a36Sopenharmony_ci#include "ui/progress.h"
2562306a36Sopenharmony_ci#include <errno.h>
2662306a36Sopenharmony_ci#include <math.h>
2762306a36Sopenharmony_ci#include <inttypes.h>
2862306a36Sopenharmony_ci#include <sys/param.h>
2962306a36Sopenharmony_ci#include <linux/rbtree.h>
3062306a36Sopenharmony_ci#include <linux/string.h>
3162306a36Sopenharmony_ci#include <linux/time64.h>
3262306a36Sopenharmony_ci#include <linux/zalloc.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic bool hists__filter_entry_by_dso(struct hists *hists,
3562306a36Sopenharmony_ci				       struct hist_entry *he);
3662306a36Sopenharmony_cistatic bool hists__filter_entry_by_thread(struct hists *hists,
3762306a36Sopenharmony_ci					  struct hist_entry *he);
3862306a36Sopenharmony_cistatic bool hists__filter_entry_by_symbol(struct hists *hists,
3962306a36Sopenharmony_ci					  struct hist_entry *he);
4062306a36Sopenharmony_cistatic bool hists__filter_entry_by_socket(struct hists *hists,
4162306a36Sopenharmony_ci					  struct hist_entry *he);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ciu16 hists__col_len(struct hists *hists, enum hist_column col)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	return hists->col_len[col];
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_civoid hists__set_col_len(struct hists *hists, enum hist_column col, u16 len)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	hists->col_len[col] = len;
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cibool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	if (len > hists__col_len(hists, col)) {
5662306a36Sopenharmony_ci		hists__set_col_len(hists, col, len);
5762306a36Sopenharmony_ci		return true;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci	return false;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_civoid hists__reset_col_len(struct hists *hists)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	enum hist_column col;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	for (col = 0; col < HISTC_NR_COLS; ++col)
6762306a36Sopenharmony_ci		hists__set_col_len(hists, col, 0);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic void hists__set_unres_dso_col_len(struct hists *hists, int dso)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (hists__col_len(hists, dso) < unresolved_col_width &&
7562306a36Sopenharmony_ci	    !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
7662306a36Sopenharmony_ci	    !symbol_conf.dso_list)
7762306a36Sopenharmony_ci		hists__set_col_len(hists, dso, unresolved_col_width);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_civoid hists__calc_col_len(struct hists *hists, struct hist_entry *h)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
8362306a36Sopenharmony_ci	int symlen;
8462306a36Sopenharmony_ci	u16 len;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	if (h->block_info)
8762306a36Sopenharmony_ci		return;
8862306a36Sopenharmony_ci	/*
8962306a36Sopenharmony_ci	 * +4 accounts for '[x] ' priv level info
9062306a36Sopenharmony_ci	 * +2 accounts for 0x prefix on raw addresses
9162306a36Sopenharmony_ci	 * +3 accounts for ' y ' symtab origin info
9262306a36Sopenharmony_ci	 */
9362306a36Sopenharmony_ci	if (h->ms.sym) {
9462306a36Sopenharmony_ci		symlen = h->ms.sym->namelen + 4;
9562306a36Sopenharmony_ci		if (verbose > 0)
9662306a36Sopenharmony_ci			symlen += BITS_PER_LONG / 4 + 2 + 3;
9762306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_SYMBOL, symlen);
9862306a36Sopenharmony_ci	} else {
9962306a36Sopenharmony_ci		symlen = unresolved_col_width + 4 + 2;
10062306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_SYMBOL, symlen);
10162306a36Sopenharmony_ci		hists__set_unres_dso_col_len(hists, HISTC_DSO);
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	len = thread__comm_len(h->thread);
10562306a36Sopenharmony_ci	if (hists__new_col_len(hists, HISTC_COMM, len))
10662306a36Sopenharmony_ci		hists__set_col_len(hists, HISTC_THREAD, len + 8);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (h->ms.map) {
10962306a36Sopenharmony_ci		len = dso__name_len(map__dso(h->ms.map));
11062306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_DSO, len);
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if (h->parent)
11462306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (h->branch_info) {
11762306a36Sopenharmony_ci		if (h->branch_info->from.ms.sym) {
11862306a36Sopenharmony_ci			symlen = (int)h->branch_info->from.ms.sym->namelen + 4;
11962306a36Sopenharmony_ci			if (verbose > 0)
12062306a36Sopenharmony_ci				symlen += BITS_PER_LONG / 4 + 2 + 3;
12162306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci			symlen = dso__name_len(map__dso(h->branch_info->from.ms.map));
12462306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_DSO_FROM, symlen);
12562306a36Sopenharmony_ci		} else {
12662306a36Sopenharmony_ci			symlen = unresolved_col_width + 4 + 2;
12762306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
12862306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_ADDR_FROM, symlen);
12962306a36Sopenharmony_ci			hists__set_unres_dso_col_len(hists, HISTC_DSO_FROM);
13062306a36Sopenharmony_ci		}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		if (h->branch_info->to.ms.sym) {
13362306a36Sopenharmony_ci			symlen = (int)h->branch_info->to.ms.sym->namelen + 4;
13462306a36Sopenharmony_ci			if (verbose > 0)
13562306a36Sopenharmony_ci				symlen += BITS_PER_LONG / 4 + 2 + 3;
13662306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci			symlen = dso__name_len(map__dso(h->branch_info->to.ms.map));
13962306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_DSO_TO, symlen);
14062306a36Sopenharmony_ci		} else {
14162306a36Sopenharmony_ci			symlen = unresolved_col_width + 4 + 2;
14262306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
14362306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_ADDR_TO, symlen);
14462306a36Sopenharmony_ci			hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
14562306a36Sopenharmony_ci		}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		if (h->branch_info->srcline_from)
14862306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_SRCLINE_FROM,
14962306a36Sopenharmony_ci					strlen(h->branch_info->srcline_from));
15062306a36Sopenharmony_ci		if (h->branch_info->srcline_to)
15162306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_SRCLINE_TO,
15262306a36Sopenharmony_ci					strlen(h->branch_info->srcline_to));
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (h->mem_info) {
15662306a36Sopenharmony_ci		if (h->mem_info->daddr.ms.sym) {
15762306a36Sopenharmony_ci			symlen = (int)h->mem_info->daddr.ms.sym->namelen + 4
15862306a36Sopenharmony_ci			       + unresolved_col_width + 2;
15962306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
16062306a36Sopenharmony_ci					   symlen);
16162306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
16262306a36Sopenharmony_ci					   symlen + 1);
16362306a36Sopenharmony_ci		} else {
16462306a36Sopenharmony_ci			symlen = unresolved_col_width + 4 + 2;
16562306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
16662306a36Sopenharmony_ci					   symlen);
16762306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
16862306a36Sopenharmony_ci					   symlen);
16962306a36Sopenharmony_ci		}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci		if (h->mem_info->iaddr.ms.sym) {
17262306a36Sopenharmony_ci			symlen = (int)h->mem_info->iaddr.ms.sym->namelen + 4
17362306a36Sopenharmony_ci			       + unresolved_col_width + 2;
17462306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL,
17562306a36Sopenharmony_ci					   symlen);
17662306a36Sopenharmony_ci		} else {
17762306a36Sopenharmony_ci			symlen = unresolved_col_width + 4 + 2;
17862306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL,
17962306a36Sopenharmony_ci					   symlen);
18062306a36Sopenharmony_ci		}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci		if (h->mem_info->daddr.ms.map) {
18362306a36Sopenharmony_ci			symlen = dso__name_len(map__dso(h->mem_info->daddr.ms.map));
18462306a36Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_DADDR_DSO,
18562306a36Sopenharmony_ci					   symlen);
18662306a36Sopenharmony_ci		} else {
18762306a36Sopenharmony_ci			symlen = unresolved_col_width + 4 + 2;
18862306a36Sopenharmony_ci			hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
18962306a36Sopenharmony_ci		}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_MEM_PHYS_DADDR,
19262306a36Sopenharmony_ci				   unresolved_col_width + 4 + 2);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_MEM_DATA_PAGE_SIZE,
19562306a36Sopenharmony_ci				   unresolved_col_width + 4 + 2);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	} else {
19862306a36Sopenharmony_ci		symlen = unresolved_col_width + 4 + 2;
19962306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen);
20062306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL, symlen);
20162306a36Sopenharmony_ci		hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_CGROUP, 6);
20562306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_CGROUP_ID, 20);
20662306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_CPU, 3);
20762306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_SOCKET, 6);
20862306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
20962306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_MEM_TLB, 22);
21062306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_MEM_SNOOP, 12);
21162306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_MEM_LVL, 36 + 3);
21262306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
21362306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
21462306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_MEM_BLOCKED, 10);
21562306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_LOCAL_INS_LAT, 13);
21662306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_GLOBAL_INS_LAT, 13);
21762306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_LOCAL_P_STAGE_CYC, 13);
21862306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_GLOBAL_P_STAGE_CYC, 13);
21962306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_ADDR, BITS_PER_LONG / 4 + 2);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (symbol_conf.nanosecs)
22262306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_TIME, 16);
22362306a36Sopenharmony_ci	else
22462306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_TIME, 12);
22562306a36Sopenharmony_ci	hists__new_col_len(hists, HISTC_CODE_PAGE_SIZE, 6);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (h->srcline) {
22862306a36Sopenharmony_ci		len = MAX(strlen(h->srcline), strlen(sort_srcline.se_header));
22962306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_SRCLINE, len);
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (h->srcfile)
23362306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_SRCFILE, strlen(h->srcfile));
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (h->transaction)
23662306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_TRANSACTION,
23762306a36Sopenharmony_ci				   hist_entry__transaction_len());
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	if (h->trace_output)
24062306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_TRACE, strlen(h->trace_output));
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	if (h->cgroup) {
24362306a36Sopenharmony_ci		const char *cgrp_name = "unknown";
24462306a36Sopenharmony_ci		struct cgroup *cgrp = cgroup__find(maps__machine(h->ms.maps)->env,
24562306a36Sopenharmony_ci						   h->cgroup);
24662306a36Sopenharmony_ci		if (cgrp != NULL)
24762306a36Sopenharmony_ci			cgrp_name = cgrp->name;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci		hists__new_col_len(hists, HISTC_CGROUP, strlen(cgrp_name));
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_civoid hists__output_recalc_col_len(struct hists *hists, int max_rows)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	struct rb_node *next = rb_first_cached(&hists->entries);
25662306a36Sopenharmony_ci	struct hist_entry *n;
25762306a36Sopenharmony_ci	int row = 0;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	hists__reset_col_len(hists);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	while (next && row++ < max_rows) {
26262306a36Sopenharmony_ci		n = rb_entry(next, struct hist_entry, rb_node);
26362306a36Sopenharmony_ci		if (!n->filtered)
26462306a36Sopenharmony_ci			hists__calc_col_len(hists, n);
26562306a36Sopenharmony_ci		next = rb_next(&n->rb_node);
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic void he_stat__add_cpumode_period(struct he_stat *he_stat,
27062306a36Sopenharmony_ci					unsigned int cpumode, u64 period)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	switch (cpumode) {
27362306a36Sopenharmony_ci	case PERF_RECORD_MISC_KERNEL:
27462306a36Sopenharmony_ci		he_stat->period_sys += period;
27562306a36Sopenharmony_ci		break;
27662306a36Sopenharmony_ci	case PERF_RECORD_MISC_USER:
27762306a36Sopenharmony_ci		he_stat->period_us += period;
27862306a36Sopenharmony_ci		break;
27962306a36Sopenharmony_ci	case PERF_RECORD_MISC_GUEST_KERNEL:
28062306a36Sopenharmony_ci		he_stat->period_guest_sys += period;
28162306a36Sopenharmony_ci		break;
28262306a36Sopenharmony_ci	case PERF_RECORD_MISC_GUEST_USER:
28362306a36Sopenharmony_ci		he_stat->period_guest_us += period;
28462306a36Sopenharmony_ci		break;
28562306a36Sopenharmony_ci	default:
28662306a36Sopenharmony_ci		break;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic long hist_time(unsigned long htime)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	unsigned long time_quantum = symbol_conf.time_quantum;
29362306a36Sopenharmony_ci	if (time_quantum)
29462306a36Sopenharmony_ci		return (htime / time_quantum) * time_quantum;
29562306a36Sopenharmony_ci	return htime;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic void he_stat__add_period(struct he_stat *he_stat, u64 period)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	he_stat->period		+= period;
30162306a36Sopenharmony_ci	he_stat->nr_events	+= 1;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	dest->period		+= src->period;
30762306a36Sopenharmony_ci	dest->period_sys	+= src->period_sys;
30862306a36Sopenharmony_ci	dest->period_us		+= src->period_us;
30962306a36Sopenharmony_ci	dest->period_guest_sys	+= src->period_guest_sys;
31062306a36Sopenharmony_ci	dest->period_guest_us	+= src->period_guest_us;
31162306a36Sopenharmony_ci	dest->nr_events		+= src->nr_events;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic void he_stat__decay(struct he_stat *he_stat)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	he_stat->period = (he_stat->period * 7) / 8;
31762306a36Sopenharmony_ci	he_stat->nr_events = (he_stat->nr_events * 7) / 8;
31862306a36Sopenharmony_ci	/* XXX need decay for weight too? */
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic void hists__delete_entry(struct hists *hists, struct hist_entry *he);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	u64 prev_period = he->stat.period;
32662306a36Sopenharmony_ci	u64 diff;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (prev_period == 0)
32962306a36Sopenharmony_ci		return true;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	he_stat__decay(&he->stat);
33262306a36Sopenharmony_ci	if (symbol_conf.cumulate_callchain)
33362306a36Sopenharmony_ci		he_stat__decay(he->stat_acc);
33462306a36Sopenharmony_ci	decay_callchain(he->callchain);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	diff = prev_period - he->stat.period;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	if (!he->depth) {
33962306a36Sopenharmony_ci		hists->stats.total_period -= diff;
34062306a36Sopenharmony_ci		if (!he->filtered)
34162306a36Sopenharmony_ci			hists->stats.total_non_filtered_period -= diff;
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (!he->leaf) {
34562306a36Sopenharmony_ci		struct hist_entry *child;
34662306a36Sopenharmony_ci		struct rb_node *node = rb_first_cached(&he->hroot_out);
34762306a36Sopenharmony_ci		while (node) {
34862306a36Sopenharmony_ci			child = rb_entry(node, struct hist_entry, rb_node);
34962306a36Sopenharmony_ci			node = rb_next(node);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci			if (hists__decay_entry(hists, child))
35262306a36Sopenharmony_ci				hists__delete_entry(hists, child);
35362306a36Sopenharmony_ci		}
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	return he->stat.period == 0;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic void hists__delete_entry(struct hists *hists, struct hist_entry *he)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct rb_root_cached *root_in;
36262306a36Sopenharmony_ci	struct rb_root_cached *root_out;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (he->parent_he) {
36562306a36Sopenharmony_ci		root_in  = &he->parent_he->hroot_in;
36662306a36Sopenharmony_ci		root_out = &he->parent_he->hroot_out;
36762306a36Sopenharmony_ci	} else {
36862306a36Sopenharmony_ci		if (hists__has(hists, need_collapse))
36962306a36Sopenharmony_ci			root_in = &hists->entries_collapsed;
37062306a36Sopenharmony_ci		else
37162306a36Sopenharmony_ci			root_in = hists->entries_in;
37262306a36Sopenharmony_ci		root_out = &hists->entries;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	rb_erase_cached(&he->rb_node_in, root_in);
37662306a36Sopenharmony_ci	rb_erase_cached(&he->rb_node, root_out);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	--hists->nr_entries;
37962306a36Sopenharmony_ci	if (!he->filtered)
38062306a36Sopenharmony_ci		--hists->nr_non_filtered_entries;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	hist_entry__delete(he);
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_civoid hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	struct rb_node *next = rb_first_cached(&hists->entries);
38862306a36Sopenharmony_ci	struct hist_entry *n;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	while (next) {
39162306a36Sopenharmony_ci		n = rb_entry(next, struct hist_entry, rb_node);
39262306a36Sopenharmony_ci		next = rb_next(&n->rb_node);
39362306a36Sopenharmony_ci		if (((zap_user && n->level == '.') ||
39462306a36Sopenharmony_ci		     (zap_kernel && n->level != '.') ||
39562306a36Sopenharmony_ci		     hists__decay_entry(hists, n))) {
39662306a36Sopenharmony_ci			hists__delete_entry(hists, n);
39762306a36Sopenharmony_ci		}
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_civoid hists__delete_entries(struct hists *hists)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	struct rb_node *next = rb_first_cached(&hists->entries);
40462306a36Sopenharmony_ci	struct hist_entry *n;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	while (next) {
40762306a36Sopenharmony_ci		n = rb_entry(next, struct hist_entry, rb_node);
40862306a36Sopenharmony_ci		next = rb_next(&n->rb_node);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		hists__delete_entry(hists, n);
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistruct hist_entry *hists__get_entry(struct hists *hists, int idx)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	struct rb_node *next = rb_first_cached(&hists->entries);
41762306a36Sopenharmony_ci	struct hist_entry *n;
41862306a36Sopenharmony_ci	int i = 0;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	while (next) {
42162306a36Sopenharmony_ci		n = rb_entry(next, struct hist_entry, rb_node);
42262306a36Sopenharmony_ci		if (i == idx)
42362306a36Sopenharmony_ci			return n;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci		next = rb_next(&n->rb_node);
42662306a36Sopenharmony_ci		i++;
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	return NULL;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci/*
43362306a36Sopenharmony_ci * histogram, sorted on item, collects periods
43462306a36Sopenharmony_ci */
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic int hist_entry__init(struct hist_entry *he,
43762306a36Sopenharmony_ci			    struct hist_entry *template,
43862306a36Sopenharmony_ci			    bool sample_self,
43962306a36Sopenharmony_ci			    size_t callchain_size)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	*he = *template;
44262306a36Sopenharmony_ci	he->callchain_size = callchain_size;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (symbol_conf.cumulate_callchain) {
44562306a36Sopenharmony_ci		he->stat_acc = malloc(sizeof(he->stat));
44662306a36Sopenharmony_ci		if (he->stat_acc == NULL)
44762306a36Sopenharmony_ci			return -ENOMEM;
44862306a36Sopenharmony_ci		memcpy(he->stat_acc, &he->stat, sizeof(he->stat));
44962306a36Sopenharmony_ci		if (!sample_self)
45062306a36Sopenharmony_ci			memset(&he->stat, 0, sizeof(he->stat));
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	he->ms.maps = maps__get(he->ms.maps);
45462306a36Sopenharmony_ci	he->ms.map = map__get(he->ms.map);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	if (he->branch_info) {
45762306a36Sopenharmony_ci		/*
45862306a36Sopenharmony_ci		 * This branch info is (a part of) allocated from
45962306a36Sopenharmony_ci		 * sample__resolve_bstack() and will be freed after
46062306a36Sopenharmony_ci		 * adding new entries.  So we need to save a copy.
46162306a36Sopenharmony_ci		 */
46262306a36Sopenharmony_ci		he->branch_info = malloc(sizeof(*he->branch_info));
46362306a36Sopenharmony_ci		if (he->branch_info == NULL)
46462306a36Sopenharmony_ci			goto err;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci		memcpy(he->branch_info, template->branch_info,
46762306a36Sopenharmony_ci		       sizeof(*he->branch_info));
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci		he->branch_info->from.ms.map = map__get(he->branch_info->from.ms.map);
47062306a36Sopenharmony_ci		he->branch_info->to.ms.map = map__get(he->branch_info->to.ms.map);
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (he->mem_info) {
47462306a36Sopenharmony_ci		he->mem_info->iaddr.ms.map = map__get(he->mem_info->iaddr.ms.map);
47562306a36Sopenharmony_ci		he->mem_info->daddr.ms.map = map__get(he->mem_info->daddr.ms.map);
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (hist_entry__has_callchains(he) && symbol_conf.use_callchain)
47962306a36Sopenharmony_ci		callchain_init(he->callchain);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	if (he->raw_data) {
48262306a36Sopenharmony_ci		he->raw_data = memdup(he->raw_data, he->raw_size);
48362306a36Sopenharmony_ci		if (he->raw_data == NULL)
48462306a36Sopenharmony_ci			goto err_infos;
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (he->srcline && he->srcline != SRCLINE_UNKNOWN) {
48862306a36Sopenharmony_ci		he->srcline = strdup(he->srcline);
48962306a36Sopenharmony_ci		if (he->srcline == NULL)
49062306a36Sopenharmony_ci			goto err_rawdata;
49162306a36Sopenharmony_ci	}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	if (symbol_conf.res_sample) {
49462306a36Sopenharmony_ci		he->res_samples = calloc(sizeof(struct res_sample),
49562306a36Sopenharmony_ci					symbol_conf.res_sample);
49662306a36Sopenharmony_ci		if (!he->res_samples)
49762306a36Sopenharmony_ci			goto err_srcline;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	INIT_LIST_HEAD(&he->pairs.node);
50162306a36Sopenharmony_ci	he->thread = thread__get(he->thread);
50262306a36Sopenharmony_ci	he->hroot_in  = RB_ROOT_CACHED;
50362306a36Sopenharmony_ci	he->hroot_out = RB_ROOT_CACHED;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (!symbol_conf.report_hierarchy)
50662306a36Sopenharmony_ci		he->leaf = true;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	return 0;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cierr_srcline:
51162306a36Sopenharmony_ci	zfree(&he->srcline);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cierr_rawdata:
51462306a36Sopenharmony_ci	zfree(&he->raw_data);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cierr_infos:
51762306a36Sopenharmony_ci	if (he->branch_info) {
51862306a36Sopenharmony_ci		map__put(he->branch_info->from.ms.map);
51962306a36Sopenharmony_ci		map__put(he->branch_info->to.ms.map);
52062306a36Sopenharmony_ci		zfree(&he->branch_info);
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci	if (he->mem_info) {
52362306a36Sopenharmony_ci		map__put(he->mem_info->iaddr.ms.map);
52462306a36Sopenharmony_ci		map__put(he->mem_info->daddr.ms.map);
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_cierr:
52762306a36Sopenharmony_ci	maps__zput(he->ms.maps);
52862306a36Sopenharmony_ci	map__zput(he->ms.map);
52962306a36Sopenharmony_ci	zfree(&he->stat_acc);
53062306a36Sopenharmony_ci	return -ENOMEM;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic void *hist_entry__zalloc(size_t size)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	return zalloc(size + sizeof(struct hist_entry));
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic void hist_entry__free(void *ptr)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	free(ptr);
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic struct hist_entry_ops default_ops = {
54462306a36Sopenharmony_ci	.new	= hist_entry__zalloc,
54562306a36Sopenharmony_ci	.free	= hist_entry__free,
54662306a36Sopenharmony_ci};
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic struct hist_entry *hist_entry__new(struct hist_entry *template,
54962306a36Sopenharmony_ci					  bool sample_self)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	struct hist_entry_ops *ops = template->ops;
55262306a36Sopenharmony_ci	size_t callchain_size = 0;
55362306a36Sopenharmony_ci	struct hist_entry *he;
55462306a36Sopenharmony_ci	int err = 0;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	if (!ops)
55762306a36Sopenharmony_ci		ops = template->ops = &default_ops;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if (symbol_conf.use_callchain)
56062306a36Sopenharmony_ci		callchain_size = sizeof(struct callchain_root);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	he = ops->new(callchain_size);
56362306a36Sopenharmony_ci	if (he) {
56462306a36Sopenharmony_ci		err = hist_entry__init(he, template, sample_self, callchain_size);
56562306a36Sopenharmony_ci		if (err) {
56662306a36Sopenharmony_ci			ops->free(he);
56762306a36Sopenharmony_ci			he = NULL;
56862306a36Sopenharmony_ci		}
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	return he;
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cistatic u8 symbol__parent_filter(const struct symbol *parent)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	if (symbol_conf.exclude_other && parent == NULL)
57762306a36Sopenharmony_ci		return 1 << HIST_FILTER__PARENT;
57862306a36Sopenharmony_ci	return 0;
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic void hist_entry__add_callchain_period(struct hist_entry *he, u64 period)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	if (!hist_entry__has_callchains(he) || !symbol_conf.use_callchain)
58462306a36Sopenharmony_ci		return;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	he->hists->callchain_period += period;
58762306a36Sopenharmony_ci	if (!he->filtered)
58862306a36Sopenharmony_ci		he->hists->callchain_non_filtered_period += period;
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic struct hist_entry *hists__findnew_entry(struct hists *hists,
59262306a36Sopenharmony_ci					       struct hist_entry *entry,
59362306a36Sopenharmony_ci					       const struct addr_location *al,
59462306a36Sopenharmony_ci					       bool sample_self)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct rb_node **p;
59762306a36Sopenharmony_ci	struct rb_node *parent = NULL;
59862306a36Sopenharmony_ci	struct hist_entry *he;
59962306a36Sopenharmony_ci	int64_t cmp;
60062306a36Sopenharmony_ci	u64 period = entry->stat.period;
60162306a36Sopenharmony_ci	bool leftmost = true;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	p = &hists->entries_in->rb_root.rb_node;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	while (*p != NULL) {
60662306a36Sopenharmony_ci		parent = *p;
60762306a36Sopenharmony_ci		he = rb_entry(parent, struct hist_entry, rb_node_in);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci		/*
61062306a36Sopenharmony_ci		 * Make sure that it receives arguments in a same order as
61162306a36Sopenharmony_ci		 * hist_entry__collapse() so that we can use an appropriate
61262306a36Sopenharmony_ci		 * function when searching an entry regardless which sort
61362306a36Sopenharmony_ci		 * keys were used.
61462306a36Sopenharmony_ci		 */
61562306a36Sopenharmony_ci		cmp = hist_entry__cmp(he, entry);
61662306a36Sopenharmony_ci		if (!cmp) {
61762306a36Sopenharmony_ci			if (sample_self) {
61862306a36Sopenharmony_ci				he_stat__add_period(&he->stat, period);
61962306a36Sopenharmony_ci				hist_entry__add_callchain_period(he, period);
62062306a36Sopenharmony_ci			}
62162306a36Sopenharmony_ci			if (symbol_conf.cumulate_callchain)
62262306a36Sopenharmony_ci				he_stat__add_period(he->stat_acc, period);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci			/*
62562306a36Sopenharmony_ci			 * This mem info was allocated from sample__resolve_mem
62662306a36Sopenharmony_ci			 * and will not be used anymore.
62762306a36Sopenharmony_ci			 */
62862306a36Sopenharmony_ci			mem_info__zput(entry->mem_info);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci			block_info__zput(entry->block_info);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci			kvm_info__zput(entry->kvm_info);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci			/* If the map of an existing hist_entry has
63562306a36Sopenharmony_ci			 * become out-of-date due to an exec() or
63662306a36Sopenharmony_ci			 * similar, update it.  Otherwise we will
63762306a36Sopenharmony_ci			 * mis-adjust symbol addresses when computing
63862306a36Sopenharmony_ci			 * the history counter to increment.
63962306a36Sopenharmony_ci			 */
64062306a36Sopenharmony_ci			if (he->ms.map != entry->ms.map) {
64162306a36Sopenharmony_ci				map__put(he->ms.map);
64262306a36Sopenharmony_ci				he->ms.map = map__get(entry->ms.map);
64362306a36Sopenharmony_ci			}
64462306a36Sopenharmony_ci			goto out;
64562306a36Sopenharmony_ci		}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci		if (cmp < 0)
64862306a36Sopenharmony_ci			p = &(*p)->rb_left;
64962306a36Sopenharmony_ci		else {
65062306a36Sopenharmony_ci			p = &(*p)->rb_right;
65162306a36Sopenharmony_ci			leftmost = false;
65262306a36Sopenharmony_ci		}
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	he = hist_entry__new(entry, sample_self);
65662306a36Sopenharmony_ci	if (!he)
65762306a36Sopenharmony_ci		return NULL;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	if (sample_self)
66062306a36Sopenharmony_ci		hist_entry__add_callchain_period(he, period);
66162306a36Sopenharmony_ci	hists->nr_entries++;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	rb_link_node(&he->rb_node_in, parent, p);
66462306a36Sopenharmony_ci	rb_insert_color_cached(&he->rb_node_in, hists->entries_in, leftmost);
66562306a36Sopenharmony_ciout:
66662306a36Sopenharmony_ci	if (sample_self)
66762306a36Sopenharmony_ci		he_stat__add_cpumode_period(&he->stat, al->cpumode, period);
66862306a36Sopenharmony_ci	if (symbol_conf.cumulate_callchain)
66962306a36Sopenharmony_ci		he_stat__add_cpumode_period(he->stat_acc, al->cpumode, period);
67062306a36Sopenharmony_ci	return he;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic unsigned random_max(unsigned high)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	unsigned thresh = -high % high;
67662306a36Sopenharmony_ci	for (;;) {
67762306a36Sopenharmony_ci		unsigned r = random();
67862306a36Sopenharmony_ci		if (r >= thresh)
67962306a36Sopenharmony_ci			return r % high;
68062306a36Sopenharmony_ci	}
68162306a36Sopenharmony_ci}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_cistatic void hists__res_sample(struct hist_entry *he, struct perf_sample *sample)
68462306a36Sopenharmony_ci{
68562306a36Sopenharmony_ci	struct res_sample *r;
68662306a36Sopenharmony_ci	int j;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	if (he->num_res < symbol_conf.res_sample) {
68962306a36Sopenharmony_ci		j = he->num_res++;
69062306a36Sopenharmony_ci	} else {
69162306a36Sopenharmony_ci		j = random_max(symbol_conf.res_sample);
69262306a36Sopenharmony_ci	}
69362306a36Sopenharmony_ci	r = &he->res_samples[j];
69462306a36Sopenharmony_ci	r->time = sample->time;
69562306a36Sopenharmony_ci	r->cpu = sample->cpu;
69662306a36Sopenharmony_ci	r->tid = sample->tid;
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_cistatic struct hist_entry*
70062306a36Sopenharmony_ci__hists__add_entry(struct hists *hists,
70162306a36Sopenharmony_ci		   struct addr_location *al,
70262306a36Sopenharmony_ci		   struct symbol *sym_parent,
70362306a36Sopenharmony_ci		   struct branch_info *bi,
70462306a36Sopenharmony_ci		   struct mem_info *mi,
70562306a36Sopenharmony_ci		   struct kvm_info *ki,
70662306a36Sopenharmony_ci		   struct block_info *block_info,
70762306a36Sopenharmony_ci		   struct perf_sample *sample,
70862306a36Sopenharmony_ci		   bool sample_self,
70962306a36Sopenharmony_ci		   struct hist_entry_ops *ops)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	struct namespaces *ns = thread__namespaces(al->thread);
71262306a36Sopenharmony_ci	struct hist_entry entry = {
71362306a36Sopenharmony_ci		.thread	= al->thread,
71462306a36Sopenharmony_ci		.comm = thread__comm(al->thread),
71562306a36Sopenharmony_ci		.cgroup_id = {
71662306a36Sopenharmony_ci			.dev = ns ? ns->link_info[CGROUP_NS_INDEX].dev : 0,
71762306a36Sopenharmony_ci			.ino = ns ? ns->link_info[CGROUP_NS_INDEX].ino : 0,
71862306a36Sopenharmony_ci		},
71962306a36Sopenharmony_ci		.cgroup = sample->cgroup,
72062306a36Sopenharmony_ci		.ms = {
72162306a36Sopenharmony_ci			.maps	= al->maps,
72262306a36Sopenharmony_ci			.map	= al->map,
72362306a36Sopenharmony_ci			.sym	= al->sym,
72462306a36Sopenharmony_ci		},
72562306a36Sopenharmony_ci		.srcline = (char *) al->srcline,
72662306a36Sopenharmony_ci		.socket	 = al->socket,
72762306a36Sopenharmony_ci		.cpu	 = al->cpu,
72862306a36Sopenharmony_ci		.cpumode = al->cpumode,
72962306a36Sopenharmony_ci		.ip	 = al->addr,
73062306a36Sopenharmony_ci		.level	 = al->level,
73162306a36Sopenharmony_ci		.code_page_size = sample->code_page_size,
73262306a36Sopenharmony_ci		.stat = {
73362306a36Sopenharmony_ci			.nr_events = 1,
73462306a36Sopenharmony_ci			.period	= sample->period,
73562306a36Sopenharmony_ci		},
73662306a36Sopenharmony_ci		.parent = sym_parent,
73762306a36Sopenharmony_ci		.filtered = symbol__parent_filter(sym_parent) | al->filtered,
73862306a36Sopenharmony_ci		.hists	= hists,
73962306a36Sopenharmony_ci		.branch_info = bi,
74062306a36Sopenharmony_ci		.mem_info = mi,
74162306a36Sopenharmony_ci		.kvm_info = ki,
74262306a36Sopenharmony_ci		.block_info = block_info,
74362306a36Sopenharmony_ci		.transaction = sample->transaction,
74462306a36Sopenharmony_ci		.raw_data = sample->raw_data,
74562306a36Sopenharmony_ci		.raw_size = sample->raw_size,
74662306a36Sopenharmony_ci		.ops = ops,
74762306a36Sopenharmony_ci		.time = hist_time(sample->time),
74862306a36Sopenharmony_ci		.weight = sample->weight,
74962306a36Sopenharmony_ci		.ins_lat = sample->ins_lat,
75062306a36Sopenharmony_ci		.p_stage_cyc = sample->p_stage_cyc,
75162306a36Sopenharmony_ci		.simd_flags = sample->simd_flags,
75262306a36Sopenharmony_ci	}, *he = hists__findnew_entry(hists, &entry, al, sample_self);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	if (!hists->has_callchains && he && he->callchain_size != 0)
75562306a36Sopenharmony_ci		hists->has_callchains = true;
75662306a36Sopenharmony_ci	if (he && symbol_conf.res_sample)
75762306a36Sopenharmony_ci		hists__res_sample(he, sample);
75862306a36Sopenharmony_ci	return he;
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_cistruct hist_entry *hists__add_entry(struct hists *hists,
76262306a36Sopenharmony_ci				    struct addr_location *al,
76362306a36Sopenharmony_ci				    struct symbol *sym_parent,
76462306a36Sopenharmony_ci				    struct branch_info *bi,
76562306a36Sopenharmony_ci				    struct mem_info *mi,
76662306a36Sopenharmony_ci				    struct kvm_info *ki,
76762306a36Sopenharmony_ci				    struct perf_sample *sample,
76862306a36Sopenharmony_ci				    bool sample_self)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	return __hists__add_entry(hists, al, sym_parent, bi, mi, ki, NULL,
77162306a36Sopenharmony_ci				  sample, sample_self, NULL);
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistruct hist_entry *hists__add_entry_ops(struct hists *hists,
77562306a36Sopenharmony_ci					struct hist_entry_ops *ops,
77662306a36Sopenharmony_ci					struct addr_location *al,
77762306a36Sopenharmony_ci					struct symbol *sym_parent,
77862306a36Sopenharmony_ci					struct branch_info *bi,
77962306a36Sopenharmony_ci					struct mem_info *mi,
78062306a36Sopenharmony_ci					struct kvm_info *ki,
78162306a36Sopenharmony_ci					struct perf_sample *sample,
78262306a36Sopenharmony_ci					bool sample_self)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	return __hists__add_entry(hists, al, sym_parent, bi, mi, ki, NULL,
78562306a36Sopenharmony_ci				  sample, sample_self, ops);
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cistruct hist_entry *hists__add_entry_block(struct hists *hists,
78962306a36Sopenharmony_ci					  struct addr_location *al,
79062306a36Sopenharmony_ci					  struct block_info *block_info)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	struct hist_entry entry = {
79362306a36Sopenharmony_ci		.block_info = block_info,
79462306a36Sopenharmony_ci		.hists = hists,
79562306a36Sopenharmony_ci		.ms = {
79662306a36Sopenharmony_ci			.maps = al->maps,
79762306a36Sopenharmony_ci			.map = al->map,
79862306a36Sopenharmony_ci			.sym = al->sym,
79962306a36Sopenharmony_ci		},
80062306a36Sopenharmony_ci	}, *he = hists__findnew_entry(hists, &entry, al, false);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	return he;
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_cistatic int
80662306a36Sopenharmony_ciiter_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
80762306a36Sopenharmony_ci		    struct addr_location *al __maybe_unused)
80862306a36Sopenharmony_ci{
80962306a36Sopenharmony_ci	return 0;
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic int
81362306a36Sopenharmony_ciiter_add_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
81462306a36Sopenharmony_ci			struct addr_location *al __maybe_unused)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	return 0;
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic int
82062306a36Sopenharmony_ciiter_prepare_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
82162306a36Sopenharmony_ci{
82262306a36Sopenharmony_ci	struct perf_sample *sample = iter->sample;
82362306a36Sopenharmony_ci	struct mem_info *mi;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	mi = sample__resolve_mem(sample, al);
82662306a36Sopenharmony_ci	if (mi == NULL)
82762306a36Sopenharmony_ci		return -ENOMEM;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	iter->priv = mi;
83062306a36Sopenharmony_ci	return 0;
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_cistatic int
83462306a36Sopenharmony_ciiter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	u64 cost;
83762306a36Sopenharmony_ci	struct mem_info *mi = iter->priv;
83862306a36Sopenharmony_ci	struct hists *hists = evsel__hists(iter->evsel);
83962306a36Sopenharmony_ci	struct perf_sample *sample = iter->sample;
84062306a36Sopenharmony_ci	struct hist_entry *he;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	if (mi == NULL)
84362306a36Sopenharmony_ci		return -EINVAL;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	cost = sample->weight;
84662306a36Sopenharmony_ci	if (!cost)
84762306a36Sopenharmony_ci		cost = 1;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	/*
85062306a36Sopenharmony_ci	 * must pass period=weight in order to get the correct
85162306a36Sopenharmony_ci	 * sorting from hists__collapse_resort() which is solely
85262306a36Sopenharmony_ci	 * based on periods. We want sorting be done on nr_events * weight
85362306a36Sopenharmony_ci	 * and this is indirectly achieved by passing period=weight here
85462306a36Sopenharmony_ci	 * and the he_stat__add_period() function.
85562306a36Sopenharmony_ci	 */
85662306a36Sopenharmony_ci	sample->period = cost;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	he = hists__add_entry(hists, al, iter->parent, NULL, mi, NULL,
85962306a36Sopenharmony_ci			      sample, true);
86062306a36Sopenharmony_ci	if (!he)
86162306a36Sopenharmony_ci		return -ENOMEM;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	iter->he = he;
86462306a36Sopenharmony_ci	return 0;
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic int
86862306a36Sopenharmony_ciiter_finish_mem_entry(struct hist_entry_iter *iter,
86962306a36Sopenharmony_ci		      struct addr_location *al __maybe_unused)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	struct evsel *evsel = iter->evsel;
87262306a36Sopenharmony_ci	struct hists *hists = evsel__hists(evsel);
87362306a36Sopenharmony_ci	struct hist_entry *he = iter->he;
87462306a36Sopenharmony_ci	int err = -EINVAL;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	if (he == NULL)
87762306a36Sopenharmony_ci		goto out;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	hists__inc_nr_samples(hists, he->filtered);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	err = hist_entry__append_callchain(he, iter->sample);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ciout:
88462306a36Sopenharmony_ci	/*
88562306a36Sopenharmony_ci	 * We don't need to free iter->priv (mem_info) here since the mem info
88662306a36Sopenharmony_ci	 * was either already freed in hists__findnew_entry() or passed to a
88762306a36Sopenharmony_ci	 * new hist entry by hist_entry__new().
88862306a36Sopenharmony_ci	 */
88962306a36Sopenharmony_ci	iter->priv = NULL;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	iter->he = NULL;
89262306a36Sopenharmony_ci	return err;
89362306a36Sopenharmony_ci}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_cistatic int
89662306a36Sopenharmony_ciiter_prepare_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
89762306a36Sopenharmony_ci{
89862306a36Sopenharmony_ci	struct branch_info *bi;
89962306a36Sopenharmony_ci	struct perf_sample *sample = iter->sample;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	bi = sample__resolve_bstack(sample, al);
90262306a36Sopenharmony_ci	if (!bi)
90362306a36Sopenharmony_ci		return -ENOMEM;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	iter->curr = 0;
90662306a36Sopenharmony_ci	iter->total = sample->branch_stack->nr;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	iter->priv = bi;
90962306a36Sopenharmony_ci	return 0;
91062306a36Sopenharmony_ci}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_cistatic int
91362306a36Sopenharmony_ciiter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused,
91462306a36Sopenharmony_ci			     struct addr_location *al __maybe_unused)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	return 0;
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_cistatic int
92062306a36Sopenharmony_ciiter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
92162306a36Sopenharmony_ci{
92262306a36Sopenharmony_ci	struct branch_info *bi = iter->priv;
92362306a36Sopenharmony_ci	int i = iter->curr;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	if (bi == NULL)
92662306a36Sopenharmony_ci		return 0;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	if (iter->curr >= iter->total)
92962306a36Sopenharmony_ci		return 0;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	maps__put(al->maps);
93262306a36Sopenharmony_ci	al->maps = maps__get(bi[i].to.ms.maps);
93362306a36Sopenharmony_ci	map__put(al->map);
93462306a36Sopenharmony_ci	al->map = map__get(bi[i].to.ms.map);
93562306a36Sopenharmony_ci	al->sym = bi[i].to.ms.sym;
93662306a36Sopenharmony_ci	al->addr = bi[i].to.addr;
93762306a36Sopenharmony_ci	return 1;
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_cistatic int
94162306a36Sopenharmony_ciiter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	struct branch_info *bi;
94462306a36Sopenharmony_ci	struct evsel *evsel = iter->evsel;
94562306a36Sopenharmony_ci	struct hists *hists = evsel__hists(evsel);
94662306a36Sopenharmony_ci	struct perf_sample *sample = iter->sample;
94762306a36Sopenharmony_ci	struct hist_entry *he = NULL;
94862306a36Sopenharmony_ci	int i = iter->curr;
94962306a36Sopenharmony_ci	int err = 0;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	bi = iter->priv;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	if (iter->hide_unresolved && !(bi[i].from.ms.sym && bi[i].to.ms.sym))
95462306a36Sopenharmony_ci		goto out;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	/*
95762306a36Sopenharmony_ci	 * The report shows the percentage of total branches captured
95862306a36Sopenharmony_ci	 * and not events sampled. Thus we use a pseudo period of 1.
95962306a36Sopenharmony_ci	 */
96062306a36Sopenharmony_ci	sample->period = 1;
96162306a36Sopenharmony_ci	sample->weight = bi->flags.cycles ? bi->flags.cycles : 1;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	he = hists__add_entry(hists, al, iter->parent, &bi[i], NULL, NULL,
96462306a36Sopenharmony_ci			      sample, true);
96562306a36Sopenharmony_ci	if (he == NULL)
96662306a36Sopenharmony_ci		return -ENOMEM;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	hists__inc_nr_samples(hists, he->filtered);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ciout:
97162306a36Sopenharmony_ci	iter->he = he;
97262306a36Sopenharmony_ci	iter->curr++;
97362306a36Sopenharmony_ci	return err;
97462306a36Sopenharmony_ci}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_cistatic int
97762306a36Sopenharmony_ciiter_finish_branch_entry(struct hist_entry_iter *iter,
97862306a36Sopenharmony_ci			 struct addr_location *al __maybe_unused)
97962306a36Sopenharmony_ci{
98062306a36Sopenharmony_ci	zfree(&iter->priv);
98162306a36Sopenharmony_ci	iter->he = NULL;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	return iter->curr >= iter->total ? 0 : -1;
98462306a36Sopenharmony_ci}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_cistatic int
98762306a36Sopenharmony_ciiter_prepare_normal_entry(struct hist_entry_iter *iter __maybe_unused,
98862306a36Sopenharmony_ci			  struct addr_location *al __maybe_unused)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	return 0;
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_cistatic int
99462306a36Sopenharmony_ciiter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location *al)
99562306a36Sopenharmony_ci{
99662306a36Sopenharmony_ci	struct evsel *evsel = iter->evsel;
99762306a36Sopenharmony_ci	struct perf_sample *sample = iter->sample;
99862306a36Sopenharmony_ci	struct hist_entry *he;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
100162306a36Sopenharmony_ci			      NULL, sample, true);
100262306a36Sopenharmony_ci	if (he == NULL)
100362306a36Sopenharmony_ci		return -ENOMEM;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	iter->he = he;
100662306a36Sopenharmony_ci	return 0;
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic int
101062306a36Sopenharmony_ciiter_finish_normal_entry(struct hist_entry_iter *iter,
101162306a36Sopenharmony_ci			 struct addr_location *al __maybe_unused)
101262306a36Sopenharmony_ci{
101362306a36Sopenharmony_ci	struct hist_entry *he = iter->he;
101462306a36Sopenharmony_ci	struct evsel *evsel = iter->evsel;
101562306a36Sopenharmony_ci	struct perf_sample *sample = iter->sample;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	if (he == NULL)
101862306a36Sopenharmony_ci		return 0;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	iter->he = NULL;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	hists__inc_nr_samples(evsel__hists(evsel), he->filtered);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	return hist_entry__append_callchain(he, sample);
102562306a36Sopenharmony_ci}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_cistatic int
102862306a36Sopenharmony_ciiter_prepare_cumulative_entry(struct hist_entry_iter *iter,
102962306a36Sopenharmony_ci			      struct addr_location *al __maybe_unused)
103062306a36Sopenharmony_ci{
103162306a36Sopenharmony_ci	struct hist_entry **he_cache;
103262306a36Sopenharmony_ci	struct callchain_cursor *cursor = get_tls_callchain_cursor();
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	if (cursor == NULL)
103562306a36Sopenharmony_ci		return -ENOMEM;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	callchain_cursor_commit(cursor);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	/*
104062306a36Sopenharmony_ci	 * This is for detecting cycles or recursions so that they're
104162306a36Sopenharmony_ci	 * cumulated only one time to prevent entries more than 100%
104262306a36Sopenharmony_ci	 * overhead.
104362306a36Sopenharmony_ci	 */
104462306a36Sopenharmony_ci	he_cache = malloc(sizeof(*he_cache) * (cursor->nr + 1));
104562306a36Sopenharmony_ci	if (he_cache == NULL)
104662306a36Sopenharmony_ci		return -ENOMEM;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	iter->priv = he_cache;
104962306a36Sopenharmony_ci	iter->curr = 0;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	return 0;
105262306a36Sopenharmony_ci}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_cistatic int
105562306a36Sopenharmony_ciiter_add_single_cumulative_entry(struct hist_entry_iter *iter,
105662306a36Sopenharmony_ci				 struct addr_location *al)
105762306a36Sopenharmony_ci{
105862306a36Sopenharmony_ci	struct evsel *evsel = iter->evsel;
105962306a36Sopenharmony_ci	struct hists *hists = evsel__hists(evsel);
106062306a36Sopenharmony_ci	struct perf_sample *sample = iter->sample;
106162306a36Sopenharmony_ci	struct hist_entry **he_cache = iter->priv;
106262306a36Sopenharmony_ci	struct hist_entry *he;
106362306a36Sopenharmony_ci	int err = 0;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	he = hists__add_entry(hists, al, iter->parent, NULL, NULL, NULL,
106662306a36Sopenharmony_ci			      sample, true);
106762306a36Sopenharmony_ci	if (he == NULL)
106862306a36Sopenharmony_ci		return -ENOMEM;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	iter->he = he;
107162306a36Sopenharmony_ci	he_cache[iter->curr++] = he;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	hist_entry__append_callchain(he, sample);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	/*
107662306a36Sopenharmony_ci	 * We need to re-initialize the cursor since callchain_append()
107762306a36Sopenharmony_ci	 * advanced the cursor to the end.
107862306a36Sopenharmony_ci	 */
107962306a36Sopenharmony_ci	callchain_cursor_commit(get_tls_callchain_cursor());
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	hists__inc_nr_samples(hists, he->filtered);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	return err;
108462306a36Sopenharmony_ci}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_cistatic int
108762306a36Sopenharmony_ciiter_next_cumulative_entry(struct hist_entry_iter *iter,
108862306a36Sopenharmony_ci			   struct addr_location *al)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	struct callchain_cursor_node *node;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	node = callchain_cursor_current(get_tls_callchain_cursor());
109362306a36Sopenharmony_ci	if (node == NULL)
109462306a36Sopenharmony_ci		return 0;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	return fill_callchain_info(al, node, iter->hide_unresolved);
109762306a36Sopenharmony_ci}
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_cistatic bool
110062306a36Sopenharmony_cihist_entry__fast__sym_diff(struct hist_entry *left,
110162306a36Sopenharmony_ci			   struct hist_entry *right)
110262306a36Sopenharmony_ci{
110362306a36Sopenharmony_ci	struct symbol *sym_l = left->ms.sym;
110462306a36Sopenharmony_ci	struct symbol *sym_r = right->ms.sym;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	if (!sym_l && !sym_r)
110762306a36Sopenharmony_ci		return left->ip != right->ip;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	return !!_sort__sym_cmp(sym_l, sym_r);
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_cistatic int
111462306a36Sopenharmony_ciiter_add_next_cumulative_entry(struct hist_entry_iter *iter,
111562306a36Sopenharmony_ci			       struct addr_location *al)
111662306a36Sopenharmony_ci{
111762306a36Sopenharmony_ci	struct evsel *evsel = iter->evsel;
111862306a36Sopenharmony_ci	struct perf_sample *sample = iter->sample;
111962306a36Sopenharmony_ci	struct hist_entry **he_cache = iter->priv;
112062306a36Sopenharmony_ci	struct hist_entry *he;
112162306a36Sopenharmony_ci	struct hist_entry he_tmp = {
112262306a36Sopenharmony_ci		.hists = evsel__hists(evsel),
112362306a36Sopenharmony_ci		.cpu = al->cpu,
112462306a36Sopenharmony_ci		.thread = al->thread,
112562306a36Sopenharmony_ci		.comm = thread__comm(al->thread),
112662306a36Sopenharmony_ci		.ip = al->addr,
112762306a36Sopenharmony_ci		.ms = {
112862306a36Sopenharmony_ci			.maps = al->maps,
112962306a36Sopenharmony_ci			.map = al->map,
113062306a36Sopenharmony_ci			.sym = al->sym,
113162306a36Sopenharmony_ci		},
113262306a36Sopenharmony_ci		.srcline = (char *) al->srcline,
113362306a36Sopenharmony_ci		.parent = iter->parent,
113462306a36Sopenharmony_ci		.raw_data = sample->raw_data,
113562306a36Sopenharmony_ci		.raw_size = sample->raw_size,
113662306a36Sopenharmony_ci	};
113762306a36Sopenharmony_ci	int i;
113862306a36Sopenharmony_ci	struct callchain_cursor cursor, *tls_cursor = get_tls_callchain_cursor();
113962306a36Sopenharmony_ci	bool fast = hists__has(he_tmp.hists, sym);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	if (tls_cursor == NULL)
114262306a36Sopenharmony_ci		return -ENOMEM;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	callchain_cursor_snapshot(&cursor, tls_cursor);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	callchain_cursor_advance(tls_cursor);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	/*
114962306a36Sopenharmony_ci	 * Check if there's duplicate entries in the callchain.
115062306a36Sopenharmony_ci	 * It's possible that it has cycles or recursive calls.
115162306a36Sopenharmony_ci	 */
115262306a36Sopenharmony_ci	for (i = 0; i < iter->curr; i++) {
115362306a36Sopenharmony_ci		/*
115462306a36Sopenharmony_ci		 * For most cases, there are no duplicate entries in callchain.
115562306a36Sopenharmony_ci		 * The symbols are usually different. Do a quick check for
115662306a36Sopenharmony_ci		 * symbols first.
115762306a36Sopenharmony_ci		 */
115862306a36Sopenharmony_ci		if (fast && hist_entry__fast__sym_diff(he_cache[i], &he_tmp))
115962306a36Sopenharmony_ci			continue;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci		if (hist_entry__cmp(he_cache[i], &he_tmp) == 0) {
116262306a36Sopenharmony_ci			/* to avoid calling callback function */
116362306a36Sopenharmony_ci			iter->he = NULL;
116462306a36Sopenharmony_ci			return 0;
116562306a36Sopenharmony_ci		}
116662306a36Sopenharmony_ci	}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
116962306a36Sopenharmony_ci			      NULL, sample, false);
117062306a36Sopenharmony_ci	if (he == NULL)
117162306a36Sopenharmony_ci		return -ENOMEM;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	iter->he = he;
117462306a36Sopenharmony_ci	he_cache[iter->curr++] = he;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	if (hist_entry__has_callchains(he) && symbol_conf.use_callchain)
117762306a36Sopenharmony_ci		callchain_append(he->callchain, &cursor, sample->period);
117862306a36Sopenharmony_ci	return 0;
117962306a36Sopenharmony_ci}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_cistatic int
118262306a36Sopenharmony_ciiter_finish_cumulative_entry(struct hist_entry_iter *iter,
118362306a36Sopenharmony_ci			     struct addr_location *al __maybe_unused)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	zfree(&iter->priv);
118662306a36Sopenharmony_ci	iter->he = NULL;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	return 0;
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ciconst struct hist_iter_ops hist_iter_mem = {
119262306a36Sopenharmony_ci	.prepare_entry 		= iter_prepare_mem_entry,
119362306a36Sopenharmony_ci	.add_single_entry 	= iter_add_single_mem_entry,
119462306a36Sopenharmony_ci	.next_entry 		= iter_next_nop_entry,
119562306a36Sopenharmony_ci	.add_next_entry 	= iter_add_next_nop_entry,
119662306a36Sopenharmony_ci	.finish_entry 		= iter_finish_mem_entry,
119762306a36Sopenharmony_ci};
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ciconst struct hist_iter_ops hist_iter_branch = {
120062306a36Sopenharmony_ci	.prepare_entry 		= iter_prepare_branch_entry,
120162306a36Sopenharmony_ci	.add_single_entry 	= iter_add_single_branch_entry,
120262306a36Sopenharmony_ci	.next_entry 		= iter_next_branch_entry,
120362306a36Sopenharmony_ci	.add_next_entry 	= iter_add_next_branch_entry,
120462306a36Sopenharmony_ci	.finish_entry 		= iter_finish_branch_entry,
120562306a36Sopenharmony_ci};
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ciconst struct hist_iter_ops hist_iter_normal = {
120862306a36Sopenharmony_ci	.prepare_entry 		= iter_prepare_normal_entry,
120962306a36Sopenharmony_ci	.add_single_entry 	= iter_add_single_normal_entry,
121062306a36Sopenharmony_ci	.next_entry 		= iter_next_nop_entry,
121162306a36Sopenharmony_ci	.add_next_entry 	= iter_add_next_nop_entry,
121262306a36Sopenharmony_ci	.finish_entry 		= iter_finish_normal_entry,
121362306a36Sopenharmony_ci};
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ciconst struct hist_iter_ops hist_iter_cumulative = {
121662306a36Sopenharmony_ci	.prepare_entry 		= iter_prepare_cumulative_entry,
121762306a36Sopenharmony_ci	.add_single_entry 	= iter_add_single_cumulative_entry,
121862306a36Sopenharmony_ci	.next_entry 		= iter_next_cumulative_entry,
121962306a36Sopenharmony_ci	.add_next_entry 	= iter_add_next_cumulative_entry,
122062306a36Sopenharmony_ci	.finish_entry 		= iter_finish_cumulative_entry,
122162306a36Sopenharmony_ci};
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ciint hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
122462306a36Sopenharmony_ci			 int max_stack_depth, void *arg)
122562306a36Sopenharmony_ci{
122662306a36Sopenharmony_ci	int err, err2;
122762306a36Sopenharmony_ci	struct map *alm = NULL;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	if (al)
123062306a36Sopenharmony_ci		alm = map__get(al->map);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	err = sample__resolve_callchain(iter->sample, get_tls_callchain_cursor(), &iter->parent,
123362306a36Sopenharmony_ci					iter->evsel, al, max_stack_depth);
123462306a36Sopenharmony_ci	if (err) {
123562306a36Sopenharmony_ci		map__put(alm);
123662306a36Sopenharmony_ci		return err;
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	err = iter->ops->prepare_entry(iter, al);
124062306a36Sopenharmony_ci	if (err)
124162306a36Sopenharmony_ci		goto out;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	err = iter->ops->add_single_entry(iter, al);
124462306a36Sopenharmony_ci	if (err)
124562306a36Sopenharmony_ci		goto out;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	if (iter->he && iter->add_entry_cb) {
124862306a36Sopenharmony_ci		err = iter->add_entry_cb(iter, al, true, arg);
124962306a36Sopenharmony_ci		if (err)
125062306a36Sopenharmony_ci			goto out;
125162306a36Sopenharmony_ci	}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	while (iter->ops->next_entry(iter, al)) {
125462306a36Sopenharmony_ci		err = iter->ops->add_next_entry(iter, al);
125562306a36Sopenharmony_ci		if (err)
125662306a36Sopenharmony_ci			break;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci		if (iter->he && iter->add_entry_cb) {
125962306a36Sopenharmony_ci			err = iter->add_entry_cb(iter, al, false, arg);
126062306a36Sopenharmony_ci			if (err)
126162306a36Sopenharmony_ci				goto out;
126262306a36Sopenharmony_ci		}
126362306a36Sopenharmony_ci	}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ciout:
126662306a36Sopenharmony_ci	err2 = iter->ops->finish_entry(iter, al);
126762306a36Sopenharmony_ci	if (!err)
126862306a36Sopenharmony_ci		err = err2;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	map__put(alm);
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	return err;
127362306a36Sopenharmony_ci}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ciint64_t
127662306a36Sopenharmony_cihist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	struct hists *hists = left->hists;
127962306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
128062306a36Sopenharmony_ci	int64_t cmp = 0;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	hists__for_each_sort_list(hists, fmt) {
128362306a36Sopenharmony_ci		if (perf_hpp__is_dynamic_entry(fmt) &&
128462306a36Sopenharmony_ci		    !perf_hpp__defined_dynamic_entry(fmt, hists))
128562306a36Sopenharmony_ci			continue;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci		cmp = fmt->cmp(fmt, left, right);
128862306a36Sopenharmony_ci		if (cmp)
128962306a36Sopenharmony_ci			break;
129062306a36Sopenharmony_ci	}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	return cmp;
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ciint64_t
129662306a36Sopenharmony_cihist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	struct hists *hists = left->hists;
129962306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
130062306a36Sopenharmony_ci	int64_t cmp = 0;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	hists__for_each_sort_list(hists, fmt) {
130362306a36Sopenharmony_ci		if (perf_hpp__is_dynamic_entry(fmt) &&
130462306a36Sopenharmony_ci		    !perf_hpp__defined_dynamic_entry(fmt, hists))
130562306a36Sopenharmony_ci			continue;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci		cmp = fmt->collapse(fmt, left, right);
130862306a36Sopenharmony_ci		if (cmp)
130962306a36Sopenharmony_ci			break;
131062306a36Sopenharmony_ci	}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	return cmp;
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_civoid hist_entry__delete(struct hist_entry *he)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	struct hist_entry_ops *ops = he->ops;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	thread__zput(he->thread);
132062306a36Sopenharmony_ci	maps__zput(he->ms.maps);
132162306a36Sopenharmony_ci	map__zput(he->ms.map);
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	if (he->branch_info) {
132462306a36Sopenharmony_ci		map__zput(he->branch_info->from.ms.map);
132562306a36Sopenharmony_ci		map__zput(he->branch_info->to.ms.map);
132662306a36Sopenharmony_ci		zfree_srcline(&he->branch_info->srcline_from);
132762306a36Sopenharmony_ci		zfree_srcline(&he->branch_info->srcline_to);
132862306a36Sopenharmony_ci		zfree(&he->branch_info);
132962306a36Sopenharmony_ci	}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	if (he->mem_info) {
133262306a36Sopenharmony_ci		map__zput(he->mem_info->iaddr.ms.map);
133362306a36Sopenharmony_ci		map__zput(he->mem_info->daddr.ms.map);
133462306a36Sopenharmony_ci		mem_info__zput(he->mem_info);
133562306a36Sopenharmony_ci	}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	if (he->block_info)
133862306a36Sopenharmony_ci		block_info__zput(he->block_info);
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	if (he->kvm_info)
134162306a36Sopenharmony_ci		kvm_info__zput(he->kvm_info);
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	zfree(&he->res_samples);
134462306a36Sopenharmony_ci	zfree(&he->stat_acc);
134562306a36Sopenharmony_ci	zfree_srcline(&he->srcline);
134662306a36Sopenharmony_ci	if (he->srcfile && he->srcfile[0])
134762306a36Sopenharmony_ci		zfree(&he->srcfile);
134862306a36Sopenharmony_ci	free_callchain(he->callchain);
134962306a36Sopenharmony_ci	zfree(&he->trace_output);
135062306a36Sopenharmony_ci	zfree(&he->raw_data);
135162306a36Sopenharmony_ci	ops->free(he);
135262306a36Sopenharmony_ci}
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci/*
135562306a36Sopenharmony_ci * If this is not the last column, then we need to pad it according to the
135662306a36Sopenharmony_ci * pre-calculated max length for this column, otherwise don't bother adding
135762306a36Sopenharmony_ci * spaces because that would break viewing this with, for instance, 'less',
135862306a36Sopenharmony_ci * that would show tons of trailing spaces when a long C++ demangled method
135962306a36Sopenharmony_ci * names is sampled.
136062306a36Sopenharmony_ci*/
136162306a36Sopenharmony_ciint hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp,
136262306a36Sopenharmony_ci				   struct perf_hpp_fmt *fmt, int printed)
136362306a36Sopenharmony_ci{
136462306a36Sopenharmony_ci	if (!list_is_last(&fmt->list, &he->hists->hpp_list->fields)) {
136562306a36Sopenharmony_ci		const int width = fmt->width(fmt, hpp, he->hists);
136662306a36Sopenharmony_ci		if (printed < width) {
136762306a36Sopenharmony_ci			advance_hpp(hpp, printed);
136862306a36Sopenharmony_ci			printed = scnprintf(hpp->buf, hpp->size, "%-*s", width - printed, " ");
136962306a36Sopenharmony_ci		}
137062306a36Sopenharmony_ci	}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	return printed;
137362306a36Sopenharmony_ci}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci/*
137662306a36Sopenharmony_ci * collapse the histogram
137762306a36Sopenharmony_ci */
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_cistatic void hists__apply_filters(struct hists *hists, struct hist_entry *he);
138062306a36Sopenharmony_cistatic void hists__remove_entry_filter(struct hists *hists, struct hist_entry *he,
138162306a36Sopenharmony_ci				       enum hist_filter type);
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_citypedef bool (*fmt_chk_fn)(struct perf_hpp_fmt *fmt);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_cistatic bool check_thread_entry(struct perf_hpp_fmt *fmt)
138662306a36Sopenharmony_ci{
138762306a36Sopenharmony_ci	return perf_hpp__is_thread_entry(fmt) || perf_hpp__is_comm_entry(fmt);
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic void hist_entry__check_and_remove_filter(struct hist_entry *he,
139162306a36Sopenharmony_ci						enum hist_filter type,
139262306a36Sopenharmony_ci						fmt_chk_fn check)
139362306a36Sopenharmony_ci{
139462306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
139562306a36Sopenharmony_ci	bool type_match = false;
139662306a36Sopenharmony_ci	struct hist_entry *parent = he->parent_he;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	switch (type) {
139962306a36Sopenharmony_ci	case HIST_FILTER__THREAD:
140062306a36Sopenharmony_ci		if (symbol_conf.comm_list == NULL &&
140162306a36Sopenharmony_ci		    symbol_conf.pid_list == NULL &&
140262306a36Sopenharmony_ci		    symbol_conf.tid_list == NULL)
140362306a36Sopenharmony_ci			return;
140462306a36Sopenharmony_ci		break;
140562306a36Sopenharmony_ci	case HIST_FILTER__DSO:
140662306a36Sopenharmony_ci		if (symbol_conf.dso_list == NULL)
140762306a36Sopenharmony_ci			return;
140862306a36Sopenharmony_ci		break;
140962306a36Sopenharmony_ci	case HIST_FILTER__SYMBOL:
141062306a36Sopenharmony_ci		if (symbol_conf.sym_list == NULL)
141162306a36Sopenharmony_ci			return;
141262306a36Sopenharmony_ci		break;
141362306a36Sopenharmony_ci	case HIST_FILTER__PARENT:
141462306a36Sopenharmony_ci	case HIST_FILTER__GUEST:
141562306a36Sopenharmony_ci	case HIST_FILTER__HOST:
141662306a36Sopenharmony_ci	case HIST_FILTER__SOCKET:
141762306a36Sopenharmony_ci	case HIST_FILTER__C2C:
141862306a36Sopenharmony_ci	default:
141962306a36Sopenharmony_ci		return;
142062306a36Sopenharmony_ci	}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	/* if it's filtered by own fmt, it has to have filter bits */
142362306a36Sopenharmony_ci	perf_hpp_list__for_each_format(he->hpp_list, fmt) {
142462306a36Sopenharmony_ci		if (check(fmt)) {
142562306a36Sopenharmony_ci			type_match = true;
142662306a36Sopenharmony_ci			break;
142762306a36Sopenharmony_ci		}
142862306a36Sopenharmony_ci	}
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	if (type_match) {
143162306a36Sopenharmony_ci		/*
143262306a36Sopenharmony_ci		 * If the filter is for current level entry, propagate
143362306a36Sopenharmony_ci		 * filter marker to parents.  The marker bit was
143462306a36Sopenharmony_ci		 * already set by default so it only needs to clear
143562306a36Sopenharmony_ci		 * non-filtered entries.
143662306a36Sopenharmony_ci		 */
143762306a36Sopenharmony_ci		if (!(he->filtered & (1 << type))) {
143862306a36Sopenharmony_ci			while (parent) {
143962306a36Sopenharmony_ci				parent->filtered &= ~(1 << type);
144062306a36Sopenharmony_ci				parent = parent->parent_he;
144162306a36Sopenharmony_ci			}
144262306a36Sopenharmony_ci		}
144362306a36Sopenharmony_ci	} else {
144462306a36Sopenharmony_ci		/*
144562306a36Sopenharmony_ci		 * If current entry doesn't have matching formats, set
144662306a36Sopenharmony_ci		 * filter marker for upper level entries.  it will be
144762306a36Sopenharmony_ci		 * cleared if its lower level entries is not filtered.
144862306a36Sopenharmony_ci		 *
144962306a36Sopenharmony_ci		 * For lower-level entries, it inherits parent's
145062306a36Sopenharmony_ci		 * filter bit so that lower level entries of a
145162306a36Sopenharmony_ci		 * non-filtered entry won't set the filter marker.
145262306a36Sopenharmony_ci		 */
145362306a36Sopenharmony_ci		if (parent == NULL)
145462306a36Sopenharmony_ci			he->filtered |= (1 << type);
145562306a36Sopenharmony_ci		else
145662306a36Sopenharmony_ci			he->filtered |= (parent->filtered & (1 << type));
145762306a36Sopenharmony_ci	}
145862306a36Sopenharmony_ci}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_cistatic void hist_entry__apply_hierarchy_filters(struct hist_entry *he)
146162306a36Sopenharmony_ci{
146262306a36Sopenharmony_ci	hist_entry__check_and_remove_filter(he, HIST_FILTER__THREAD,
146362306a36Sopenharmony_ci					    check_thread_entry);
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	hist_entry__check_and_remove_filter(he, HIST_FILTER__DSO,
146662306a36Sopenharmony_ci					    perf_hpp__is_dso_entry);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	hist_entry__check_and_remove_filter(he, HIST_FILTER__SYMBOL,
146962306a36Sopenharmony_ci					    perf_hpp__is_sym_entry);
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	hists__apply_filters(he->hists, he);
147262306a36Sopenharmony_ci}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_cistatic struct hist_entry *hierarchy_insert_entry(struct hists *hists,
147562306a36Sopenharmony_ci						 struct rb_root_cached *root,
147662306a36Sopenharmony_ci						 struct hist_entry *he,
147762306a36Sopenharmony_ci						 struct hist_entry *parent_he,
147862306a36Sopenharmony_ci						 struct perf_hpp_list *hpp_list)
147962306a36Sopenharmony_ci{
148062306a36Sopenharmony_ci	struct rb_node **p = &root->rb_root.rb_node;
148162306a36Sopenharmony_ci	struct rb_node *parent = NULL;
148262306a36Sopenharmony_ci	struct hist_entry *iter, *new;
148362306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
148462306a36Sopenharmony_ci	int64_t cmp;
148562306a36Sopenharmony_ci	bool leftmost = true;
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	while (*p != NULL) {
148862306a36Sopenharmony_ci		parent = *p;
148962306a36Sopenharmony_ci		iter = rb_entry(parent, struct hist_entry, rb_node_in);
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci		cmp = 0;
149262306a36Sopenharmony_ci		perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
149362306a36Sopenharmony_ci			cmp = fmt->collapse(fmt, iter, he);
149462306a36Sopenharmony_ci			if (cmp)
149562306a36Sopenharmony_ci				break;
149662306a36Sopenharmony_ci		}
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci		if (!cmp) {
149962306a36Sopenharmony_ci			he_stat__add_stat(&iter->stat, &he->stat);
150062306a36Sopenharmony_ci			return iter;
150162306a36Sopenharmony_ci		}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci		if (cmp < 0)
150462306a36Sopenharmony_ci			p = &parent->rb_left;
150562306a36Sopenharmony_ci		else {
150662306a36Sopenharmony_ci			p = &parent->rb_right;
150762306a36Sopenharmony_ci			leftmost = false;
150862306a36Sopenharmony_ci		}
150962306a36Sopenharmony_ci	}
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	new = hist_entry__new(he, true);
151262306a36Sopenharmony_ci	if (new == NULL)
151362306a36Sopenharmony_ci		return NULL;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	hists->nr_entries++;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	/* save related format list for output */
151862306a36Sopenharmony_ci	new->hpp_list = hpp_list;
151962306a36Sopenharmony_ci	new->parent_he = parent_he;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	hist_entry__apply_hierarchy_filters(new);
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	/* some fields are now passed to 'new' */
152462306a36Sopenharmony_ci	perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
152562306a36Sopenharmony_ci		if (perf_hpp__is_trace_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
152662306a36Sopenharmony_ci			he->trace_output = NULL;
152762306a36Sopenharmony_ci		else
152862306a36Sopenharmony_ci			new->trace_output = NULL;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci		if (perf_hpp__is_srcline_entry(fmt))
153162306a36Sopenharmony_ci			he->srcline = NULL;
153262306a36Sopenharmony_ci		else
153362306a36Sopenharmony_ci			new->srcline = NULL;
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci		if (perf_hpp__is_srcfile_entry(fmt))
153662306a36Sopenharmony_ci			he->srcfile = NULL;
153762306a36Sopenharmony_ci		else
153862306a36Sopenharmony_ci			new->srcfile = NULL;
153962306a36Sopenharmony_ci	}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	rb_link_node(&new->rb_node_in, parent, p);
154262306a36Sopenharmony_ci	rb_insert_color_cached(&new->rb_node_in, root, leftmost);
154362306a36Sopenharmony_ci	return new;
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_cistatic int hists__hierarchy_insert_entry(struct hists *hists,
154762306a36Sopenharmony_ci					 struct rb_root_cached *root,
154862306a36Sopenharmony_ci					 struct hist_entry *he)
154962306a36Sopenharmony_ci{
155062306a36Sopenharmony_ci	struct perf_hpp_list_node *node;
155162306a36Sopenharmony_ci	struct hist_entry *new_he = NULL;
155262306a36Sopenharmony_ci	struct hist_entry *parent = NULL;
155362306a36Sopenharmony_ci	int depth = 0;
155462306a36Sopenharmony_ci	int ret = 0;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	list_for_each_entry(node, &hists->hpp_formats, list) {
155762306a36Sopenharmony_ci		/* skip period (overhead) and elided columns */
155862306a36Sopenharmony_ci		if (node->level == 0 || node->skip)
155962306a36Sopenharmony_ci			continue;
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci		/* insert copy of 'he' for each fmt into the hierarchy */
156262306a36Sopenharmony_ci		new_he = hierarchy_insert_entry(hists, root, he, parent, &node->hpp);
156362306a36Sopenharmony_ci		if (new_he == NULL) {
156462306a36Sopenharmony_ci			ret = -1;
156562306a36Sopenharmony_ci			break;
156662306a36Sopenharmony_ci		}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci		root = &new_he->hroot_in;
156962306a36Sopenharmony_ci		new_he->depth = depth++;
157062306a36Sopenharmony_ci		parent = new_he;
157162306a36Sopenharmony_ci	}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	if (new_he) {
157462306a36Sopenharmony_ci		new_he->leaf = true;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci		if (hist_entry__has_callchains(new_he) &&
157762306a36Sopenharmony_ci		    symbol_conf.use_callchain) {
157862306a36Sopenharmony_ci			struct callchain_cursor *cursor = get_tls_callchain_cursor();
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci			if (cursor == NULL)
158162306a36Sopenharmony_ci				return -1;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci			callchain_cursor_reset(cursor);
158462306a36Sopenharmony_ci			if (callchain_merge(cursor,
158562306a36Sopenharmony_ci					    new_he->callchain,
158662306a36Sopenharmony_ci					    he->callchain) < 0)
158762306a36Sopenharmony_ci				ret = -1;
158862306a36Sopenharmony_ci		}
158962306a36Sopenharmony_ci	}
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	/* 'he' is no longer used */
159262306a36Sopenharmony_ci	hist_entry__delete(he);
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	/* return 0 (or -1) since it already applied filters */
159562306a36Sopenharmony_ci	return ret;
159662306a36Sopenharmony_ci}
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_cistatic int hists__collapse_insert_entry(struct hists *hists,
159962306a36Sopenharmony_ci					struct rb_root_cached *root,
160062306a36Sopenharmony_ci					struct hist_entry *he)
160162306a36Sopenharmony_ci{
160262306a36Sopenharmony_ci	struct rb_node **p = &root->rb_root.rb_node;
160362306a36Sopenharmony_ci	struct rb_node *parent = NULL;
160462306a36Sopenharmony_ci	struct hist_entry *iter;
160562306a36Sopenharmony_ci	int64_t cmp;
160662306a36Sopenharmony_ci	bool leftmost = true;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	if (symbol_conf.report_hierarchy)
160962306a36Sopenharmony_ci		return hists__hierarchy_insert_entry(hists, root, he);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	while (*p != NULL) {
161262306a36Sopenharmony_ci		parent = *p;
161362306a36Sopenharmony_ci		iter = rb_entry(parent, struct hist_entry, rb_node_in);
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci		cmp = hist_entry__collapse(iter, he);
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci		if (!cmp) {
161862306a36Sopenharmony_ci			int ret = 0;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci			he_stat__add_stat(&iter->stat, &he->stat);
162162306a36Sopenharmony_ci			if (symbol_conf.cumulate_callchain)
162262306a36Sopenharmony_ci				he_stat__add_stat(iter->stat_acc, he->stat_acc);
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci			if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
162562306a36Sopenharmony_ci				struct callchain_cursor *cursor = get_tls_callchain_cursor();
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci				if (cursor != NULL) {
162862306a36Sopenharmony_ci					callchain_cursor_reset(cursor);
162962306a36Sopenharmony_ci					if (callchain_merge(cursor, iter->callchain, he->callchain) < 0)
163062306a36Sopenharmony_ci						ret = -1;
163162306a36Sopenharmony_ci				} else {
163262306a36Sopenharmony_ci					ret = 0;
163362306a36Sopenharmony_ci				}
163462306a36Sopenharmony_ci			}
163562306a36Sopenharmony_ci			hist_entry__delete(he);
163662306a36Sopenharmony_ci			return ret;
163762306a36Sopenharmony_ci		}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci		if (cmp < 0)
164062306a36Sopenharmony_ci			p = &(*p)->rb_left;
164162306a36Sopenharmony_ci		else {
164262306a36Sopenharmony_ci			p = &(*p)->rb_right;
164362306a36Sopenharmony_ci			leftmost = false;
164462306a36Sopenharmony_ci		}
164562306a36Sopenharmony_ci	}
164662306a36Sopenharmony_ci	hists->nr_entries++;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	rb_link_node(&he->rb_node_in, parent, p);
164962306a36Sopenharmony_ci	rb_insert_color_cached(&he->rb_node_in, root, leftmost);
165062306a36Sopenharmony_ci	return 1;
165162306a36Sopenharmony_ci}
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_cistruct rb_root_cached *hists__get_rotate_entries_in(struct hists *hists)
165462306a36Sopenharmony_ci{
165562306a36Sopenharmony_ci	struct rb_root_cached *root;
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	mutex_lock(&hists->lock);
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	root = hists->entries_in;
166062306a36Sopenharmony_ci	if (++hists->entries_in > &hists->entries_in_array[1])
166162306a36Sopenharmony_ci		hists->entries_in = &hists->entries_in_array[0];
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	mutex_unlock(&hists->lock);
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	return root;
166662306a36Sopenharmony_ci}
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_cistatic void hists__apply_filters(struct hists *hists, struct hist_entry *he)
166962306a36Sopenharmony_ci{
167062306a36Sopenharmony_ci	hists__filter_entry_by_dso(hists, he);
167162306a36Sopenharmony_ci	hists__filter_entry_by_thread(hists, he);
167262306a36Sopenharmony_ci	hists__filter_entry_by_symbol(hists, he);
167362306a36Sopenharmony_ci	hists__filter_entry_by_socket(hists, he);
167462306a36Sopenharmony_ci}
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ciint hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
167762306a36Sopenharmony_ci{
167862306a36Sopenharmony_ci	struct rb_root_cached *root;
167962306a36Sopenharmony_ci	struct rb_node *next;
168062306a36Sopenharmony_ci	struct hist_entry *n;
168162306a36Sopenharmony_ci	int ret;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	if (!hists__has(hists, need_collapse))
168462306a36Sopenharmony_ci		return 0;
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	hists->nr_entries = 0;
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	root = hists__get_rotate_entries_in(hists);
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	next = rb_first_cached(root);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	while (next) {
169362306a36Sopenharmony_ci		if (session_done())
169462306a36Sopenharmony_ci			break;
169562306a36Sopenharmony_ci		n = rb_entry(next, struct hist_entry, rb_node_in);
169662306a36Sopenharmony_ci		next = rb_next(&n->rb_node_in);
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci		rb_erase_cached(&n->rb_node_in, root);
169962306a36Sopenharmony_ci		ret = hists__collapse_insert_entry(hists, &hists->entries_collapsed, n);
170062306a36Sopenharmony_ci		if (ret < 0)
170162306a36Sopenharmony_ci			return -1;
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci		if (ret) {
170462306a36Sopenharmony_ci			/*
170562306a36Sopenharmony_ci			 * If it wasn't combined with one of the entries already
170662306a36Sopenharmony_ci			 * collapsed, we need to apply the filters that may have
170762306a36Sopenharmony_ci			 * been set by, say, the hist_browser.
170862306a36Sopenharmony_ci			 */
170962306a36Sopenharmony_ci			hists__apply_filters(hists, n);
171062306a36Sopenharmony_ci		}
171162306a36Sopenharmony_ci		if (prog)
171262306a36Sopenharmony_ci			ui_progress__update(prog, 1);
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci	return 0;
171562306a36Sopenharmony_ci}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_cistatic int64_t hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
171862306a36Sopenharmony_ci{
171962306a36Sopenharmony_ci	struct hists *hists = a->hists;
172062306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
172162306a36Sopenharmony_ci	int64_t cmp = 0;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	hists__for_each_sort_list(hists, fmt) {
172462306a36Sopenharmony_ci		if (perf_hpp__should_skip(fmt, a->hists))
172562306a36Sopenharmony_ci			continue;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci		cmp = fmt->sort(fmt, a, b);
172862306a36Sopenharmony_ci		if (cmp)
172962306a36Sopenharmony_ci			break;
173062306a36Sopenharmony_ci	}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	return cmp;
173362306a36Sopenharmony_ci}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_cistatic void hists__reset_filter_stats(struct hists *hists)
173662306a36Sopenharmony_ci{
173762306a36Sopenharmony_ci	hists->nr_non_filtered_entries = 0;
173862306a36Sopenharmony_ci	hists->stats.total_non_filtered_period = 0;
173962306a36Sopenharmony_ci}
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_civoid hists__reset_stats(struct hists *hists)
174262306a36Sopenharmony_ci{
174362306a36Sopenharmony_ci	hists->nr_entries = 0;
174462306a36Sopenharmony_ci	hists->stats.total_period = 0;
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	hists__reset_filter_stats(hists);
174762306a36Sopenharmony_ci}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_cistatic void hists__inc_filter_stats(struct hists *hists, struct hist_entry *h)
175062306a36Sopenharmony_ci{
175162306a36Sopenharmony_ci	hists->nr_non_filtered_entries++;
175262306a36Sopenharmony_ci	hists->stats.total_non_filtered_period += h->stat.period;
175362306a36Sopenharmony_ci}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_civoid hists__inc_stats(struct hists *hists, struct hist_entry *h)
175662306a36Sopenharmony_ci{
175762306a36Sopenharmony_ci	if (!h->filtered)
175862306a36Sopenharmony_ci		hists__inc_filter_stats(hists, h);
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	hists->nr_entries++;
176162306a36Sopenharmony_ci	hists->stats.total_period += h->stat.period;
176262306a36Sopenharmony_ci}
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_cistatic void hierarchy_recalc_total_periods(struct hists *hists)
176562306a36Sopenharmony_ci{
176662306a36Sopenharmony_ci	struct rb_node *node;
176762306a36Sopenharmony_ci	struct hist_entry *he;
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	node = rb_first_cached(&hists->entries);
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	hists->stats.total_period = 0;
177262306a36Sopenharmony_ci	hists->stats.total_non_filtered_period = 0;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	/*
177562306a36Sopenharmony_ci	 * recalculate total period using top-level entries only
177662306a36Sopenharmony_ci	 * since lower level entries only see non-filtered entries
177762306a36Sopenharmony_ci	 * but upper level entries have sum of both entries.
177862306a36Sopenharmony_ci	 */
177962306a36Sopenharmony_ci	while (node) {
178062306a36Sopenharmony_ci		he = rb_entry(node, struct hist_entry, rb_node);
178162306a36Sopenharmony_ci		node = rb_next(node);
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci		hists->stats.total_period += he->stat.period;
178462306a36Sopenharmony_ci		if (!he->filtered)
178562306a36Sopenharmony_ci			hists->stats.total_non_filtered_period += he->stat.period;
178662306a36Sopenharmony_ci	}
178762306a36Sopenharmony_ci}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_cistatic void hierarchy_insert_output_entry(struct rb_root_cached *root,
179062306a36Sopenharmony_ci					  struct hist_entry *he)
179162306a36Sopenharmony_ci{
179262306a36Sopenharmony_ci	struct rb_node **p = &root->rb_root.rb_node;
179362306a36Sopenharmony_ci	struct rb_node *parent = NULL;
179462306a36Sopenharmony_ci	struct hist_entry *iter;
179562306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
179662306a36Sopenharmony_ci	bool leftmost = true;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	while (*p != NULL) {
179962306a36Sopenharmony_ci		parent = *p;
180062306a36Sopenharmony_ci		iter = rb_entry(parent, struct hist_entry, rb_node);
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci		if (hist_entry__sort(he, iter) > 0)
180362306a36Sopenharmony_ci			p = &parent->rb_left;
180462306a36Sopenharmony_ci		else {
180562306a36Sopenharmony_ci			p = &parent->rb_right;
180662306a36Sopenharmony_ci			leftmost = false;
180762306a36Sopenharmony_ci		}
180862306a36Sopenharmony_ci	}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	rb_link_node(&he->rb_node, parent, p);
181162306a36Sopenharmony_ci	rb_insert_color_cached(&he->rb_node, root, leftmost);
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	/* update column width of dynamic entry */
181462306a36Sopenharmony_ci	perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
181562306a36Sopenharmony_ci		if (fmt->init)
181662306a36Sopenharmony_ci			fmt->init(fmt, he);
181762306a36Sopenharmony_ci	}
181862306a36Sopenharmony_ci}
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_cistatic void hists__hierarchy_output_resort(struct hists *hists,
182162306a36Sopenharmony_ci					   struct ui_progress *prog,
182262306a36Sopenharmony_ci					   struct rb_root_cached *root_in,
182362306a36Sopenharmony_ci					   struct rb_root_cached *root_out,
182462306a36Sopenharmony_ci					   u64 min_callchain_hits,
182562306a36Sopenharmony_ci					   bool use_callchain)
182662306a36Sopenharmony_ci{
182762306a36Sopenharmony_ci	struct rb_node *node;
182862306a36Sopenharmony_ci	struct hist_entry *he;
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	*root_out = RB_ROOT_CACHED;
183162306a36Sopenharmony_ci	node = rb_first_cached(root_in);
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	while (node) {
183462306a36Sopenharmony_ci		he = rb_entry(node, struct hist_entry, rb_node_in);
183562306a36Sopenharmony_ci		node = rb_next(node);
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci		hierarchy_insert_output_entry(root_out, he);
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci		if (prog)
184062306a36Sopenharmony_ci			ui_progress__update(prog, 1);
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci		hists->nr_entries++;
184362306a36Sopenharmony_ci		if (!he->filtered) {
184462306a36Sopenharmony_ci			hists->nr_non_filtered_entries++;
184562306a36Sopenharmony_ci			hists__calc_col_len(hists, he);
184662306a36Sopenharmony_ci		}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci		if (!he->leaf) {
184962306a36Sopenharmony_ci			hists__hierarchy_output_resort(hists, prog,
185062306a36Sopenharmony_ci						       &he->hroot_in,
185162306a36Sopenharmony_ci						       &he->hroot_out,
185262306a36Sopenharmony_ci						       min_callchain_hits,
185362306a36Sopenharmony_ci						       use_callchain);
185462306a36Sopenharmony_ci			continue;
185562306a36Sopenharmony_ci		}
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci		if (!use_callchain)
185862306a36Sopenharmony_ci			continue;
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci		if (callchain_param.mode == CHAIN_GRAPH_REL) {
186162306a36Sopenharmony_ci			u64 total = he->stat.period;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci			if (symbol_conf.cumulate_callchain)
186462306a36Sopenharmony_ci				total = he->stat_acc->period;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci			min_callchain_hits = total * (callchain_param.min_percent / 100);
186762306a36Sopenharmony_ci		}
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci		callchain_param.sort(&he->sorted_chain, he->callchain,
187062306a36Sopenharmony_ci				     min_callchain_hits, &callchain_param);
187162306a36Sopenharmony_ci	}
187262306a36Sopenharmony_ci}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_cistatic void __hists__insert_output_entry(struct rb_root_cached *entries,
187562306a36Sopenharmony_ci					 struct hist_entry *he,
187662306a36Sopenharmony_ci					 u64 min_callchain_hits,
187762306a36Sopenharmony_ci					 bool use_callchain)
187862306a36Sopenharmony_ci{
187962306a36Sopenharmony_ci	struct rb_node **p = &entries->rb_root.rb_node;
188062306a36Sopenharmony_ci	struct rb_node *parent = NULL;
188162306a36Sopenharmony_ci	struct hist_entry *iter;
188262306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
188362306a36Sopenharmony_ci	bool leftmost = true;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	if (use_callchain) {
188662306a36Sopenharmony_ci		if (callchain_param.mode == CHAIN_GRAPH_REL) {
188762306a36Sopenharmony_ci			u64 total = he->stat.period;
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci			if (symbol_conf.cumulate_callchain)
189062306a36Sopenharmony_ci				total = he->stat_acc->period;
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci			min_callchain_hits = total * (callchain_param.min_percent / 100);
189362306a36Sopenharmony_ci		}
189462306a36Sopenharmony_ci		callchain_param.sort(&he->sorted_chain, he->callchain,
189562306a36Sopenharmony_ci				      min_callchain_hits, &callchain_param);
189662306a36Sopenharmony_ci	}
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	while (*p != NULL) {
189962306a36Sopenharmony_ci		parent = *p;
190062306a36Sopenharmony_ci		iter = rb_entry(parent, struct hist_entry, rb_node);
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci		if (hist_entry__sort(he, iter) > 0)
190362306a36Sopenharmony_ci			p = &(*p)->rb_left;
190462306a36Sopenharmony_ci		else {
190562306a36Sopenharmony_ci			p = &(*p)->rb_right;
190662306a36Sopenharmony_ci			leftmost = false;
190762306a36Sopenharmony_ci		}
190862306a36Sopenharmony_ci	}
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	rb_link_node(&he->rb_node, parent, p);
191162306a36Sopenharmony_ci	rb_insert_color_cached(&he->rb_node, entries, leftmost);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	/* update column width of dynamic entries */
191462306a36Sopenharmony_ci	perf_hpp_list__for_each_sort_list(&perf_hpp_list, fmt) {
191562306a36Sopenharmony_ci		if (fmt->init)
191662306a36Sopenharmony_ci			fmt->init(fmt, he);
191762306a36Sopenharmony_ci	}
191862306a36Sopenharmony_ci}
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_cistatic void output_resort(struct hists *hists, struct ui_progress *prog,
192162306a36Sopenharmony_ci			  bool use_callchain, hists__resort_cb_t cb,
192262306a36Sopenharmony_ci			  void *cb_arg)
192362306a36Sopenharmony_ci{
192462306a36Sopenharmony_ci	struct rb_root_cached *root;
192562306a36Sopenharmony_ci	struct rb_node *next;
192662306a36Sopenharmony_ci	struct hist_entry *n;
192762306a36Sopenharmony_ci	u64 callchain_total;
192862306a36Sopenharmony_ci	u64 min_callchain_hits;
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	callchain_total = hists->callchain_period;
193162306a36Sopenharmony_ci	if (symbol_conf.filter_relative)
193262306a36Sopenharmony_ci		callchain_total = hists->callchain_non_filtered_period;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	min_callchain_hits = callchain_total * (callchain_param.min_percent / 100);
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	hists__reset_stats(hists);
193762306a36Sopenharmony_ci	hists__reset_col_len(hists);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	if (symbol_conf.report_hierarchy) {
194062306a36Sopenharmony_ci		hists__hierarchy_output_resort(hists, prog,
194162306a36Sopenharmony_ci					       &hists->entries_collapsed,
194262306a36Sopenharmony_ci					       &hists->entries,
194362306a36Sopenharmony_ci					       min_callchain_hits,
194462306a36Sopenharmony_ci					       use_callchain);
194562306a36Sopenharmony_ci		hierarchy_recalc_total_periods(hists);
194662306a36Sopenharmony_ci		return;
194762306a36Sopenharmony_ci	}
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	if (hists__has(hists, need_collapse))
195062306a36Sopenharmony_ci		root = &hists->entries_collapsed;
195162306a36Sopenharmony_ci	else
195262306a36Sopenharmony_ci		root = hists->entries_in;
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	next = rb_first_cached(root);
195562306a36Sopenharmony_ci	hists->entries = RB_ROOT_CACHED;
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	while (next) {
195862306a36Sopenharmony_ci		n = rb_entry(next, struct hist_entry, rb_node_in);
195962306a36Sopenharmony_ci		next = rb_next(&n->rb_node_in);
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci		if (cb && cb(n, cb_arg))
196262306a36Sopenharmony_ci			continue;
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci		__hists__insert_output_entry(&hists->entries, n, min_callchain_hits, use_callchain);
196562306a36Sopenharmony_ci		hists__inc_stats(hists, n);
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci		if (!n->filtered)
196862306a36Sopenharmony_ci			hists__calc_col_len(hists, n);
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci		if (prog)
197162306a36Sopenharmony_ci			ui_progress__update(prog, 1);
197262306a36Sopenharmony_ci	}
197362306a36Sopenharmony_ci}
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_civoid evsel__output_resort_cb(struct evsel *evsel, struct ui_progress *prog,
197662306a36Sopenharmony_ci			     hists__resort_cb_t cb, void *cb_arg)
197762306a36Sopenharmony_ci{
197862306a36Sopenharmony_ci	bool use_callchain;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph)
198162306a36Sopenharmony_ci		use_callchain = evsel__has_callchain(evsel);
198262306a36Sopenharmony_ci	else
198362306a36Sopenharmony_ci		use_callchain = symbol_conf.use_callchain;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	use_callchain |= symbol_conf.show_branchflag_count;
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	output_resort(evsel__hists(evsel), prog, use_callchain, cb, cb_arg);
198862306a36Sopenharmony_ci}
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_civoid evsel__output_resort(struct evsel *evsel, struct ui_progress *prog)
199162306a36Sopenharmony_ci{
199262306a36Sopenharmony_ci	return evsel__output_resort_cb(evsel, prog, NULL, NULL);
199362306a36Sopenharmony_ci}
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_civoid hists__output_resort(struct hists *hists, struct ui_progress *prog)
199662306a36Sopenharmony_ci{
199762306a36Sopenharmony_ci	output_resort(hists, prog, symbol_conf.use_callchain, NULL, NULL);
199862306a36Sopenharmony_ci}
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_civoid hists__output_resort_cb(struct hists *hists, struct ui_progress *prog,
200162306a36Sopenharmony_ci			     hists__resort_cb_t cb)
200262306a36Sopenharmony_ci{
200362306a36Sopenharmony_ci	output_resort(hists, prog, symbol_conf.use_callchain, cb, NULL);
200462306a36Sopenharmony_ci}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_cistatic bool can_goto_child(struct hist_entry *he, enum hierarchy_move_dir hmd)
200762306a36Sopenharmony_ci{
200862306a36Sopenharmony_ci	if (he->leaf || hmd == HMD_FORCE_SIBLING)
200962306a36Sopenharmony_ci		return false;
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	if (he->unfolded || hmd == HMD_FORCE_CHILD)
201262306a36Sopenharmony_ci		return true;
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci	return false;
201562306a36Sopenharmony_ci}
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_cistruct rb_node *rb_hierarchy_last(struct rb_node *node)
201862306a36Sopenharmony_ci{
201962306a36Sopenharmony_ci	struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	while (can_goto_child(he, HMD_NORMAL)) {
202262306a36Sopenharmony_ci		node = rb_last(&he->hroot_out.rb_root);
202362306a36Sopenharmony_ci		he = rb_entry(node, struct hist_entry, rb_node);
202462306a36Sopenharmony_ci	}
202562306a36Sopenharmony_ci	return node;
202662306a36Sopenharmony_ci}
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_cistruct rb_node *__rb_hierarchy_next(struct rb_node *node, enum hierarchy_move_dir hmd)
202962306a36Sopenharmony_ci{
203062306a36Sopenharmony_ci	struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	if (can_goto_child(he, hmd))
203362306a36Sopenharmony_ci		node = rb_first_cached(&he->hroot_out);
203462306a36Sopenharmony_ci	else
203562306a36Sopenharmony_ci		node = rb_next(node);
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	while (node == NULL) {
203862306a36Sopenharmony_ci		he = he->parent_he;
203962306a36Sopenharmony_ci		if (he == NULL)
204062306a36Sopenharmony_ci			break;
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci		node = rb_next(&he->rb_node);
204362306a36Sopenharmony_ci	}
204462306a36Sopenharmony_ci	return node;
204562306a36Sopenharmony_ci}
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_cistruct rb_node *rb_hierarchy_prev(struct rb_node *node)
204862306a36Sopenharmony_ci{
204962306a36Sopenharmony_ci	struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	node = rb_prev(node);
205262306a36Sopenharmony_ci	if (node)
205362306a36Sopenharmony_ci		return rb_hierarchy_last(node);
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	he = he->parent_he;
205662306a36Sopenharmony_ci	if (he == NULL)
205762306a36Sopenharmony_ci		return NULL;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	return &he->rb_node;
206062306a36Sopenharmony_ci}
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_cibool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit)
206362306a36Sopenharmony_ci{
206462306a36Sopenharmony_ci	struct rb_node *node;
206562306a36Sopenharmony_ci	struct hist_entry *child;
206662306a36Sopenharmony_ci	float percent;
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	if (he->leaf)
206962306a36Sopenharmony_ci		return false;
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	node = rb_first_cached(&he->hroot_out);
207262306a36Sopenharmony_ci	child = rb_entry(node, struct hist_entry, rb_node);
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	while (node && child->filtered) {
207562306a36Sopenharmony_ci		node = rb_next(node);
207662306a36Sopenharmony_ci		child = rb_entry(node, struct hist_entry, rb_node);
207762306a36Sopenharmony_ci	}
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	if (node)
208062306a36Sopenharmony_ci		percent = hist_entry__get_percent_limit(child);
208162306a36Sopenharmony_ci	else
208262306a36Sopenharmony_ci		percent = 0;
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	return node && percent >= limit;
208562306a36Sopenharmony_ci}
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_cistatic void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
208862306a36Sopenharmony_ci				       enum hist_filter filter)
208962306a36Sopenharmony_ci{
209062306a36Sopenharmony_ci	h->filtered &= ~(1 << filter);
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	if (symbol_conf.report_hierarchy) {
209362306a36Sopenharmony_ci		struct hist_entry *parent = h->parent_he;
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci		while (parent) {
209662306a36Sopenharmony_ci			he_stat__add_stat(&parent->stat, &h->stat);
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci			parent->filtered &= ~(1 << filter);
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci			if (parent->filtered)
210162306a36Sopenharmony_ci				goto next;
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci			/* force fold unfiltered entry for simplicity */
210462306a36Sopenharmony_ci			parent->unfolded = false;
210562306a36Sopenharmony_ci			parent->has_no_entry = false;
210662306a36Sopenharmony_ci			parent->row_offset = 0;
210762306a36Sopenharmony_ci			parent->nr_rows = 0;
210862306a36Sopenharmony_cinext:
210962306a36Sopenharmony_ci			parent = parent->parent_he;
211062306a36Sopenharmony_ci		}
211162306a36Sopenharmony_ci	}
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci	if (h->filtered)
211462306a36Sopenharmony_ci		return;
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	/* force fold unfiltered entry for simplicity */
211762306a36Sopenharmony_ci	h->unfolded = false;
211862306a36Sopenharmony_ci	h->has_no_entry = false;
211962306a36Sopenharmony_ci	h->row_offset = 0;
212062306a36Sopenharmony_ci	h->nr_rows = 0;
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	hists->stats.nr_non_filtered_samples += h->stat.nr_events;
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	hists__inc_filter_stats(hists, h);
212562306a36Sopenharmony_ci	hists__calc_col_len(hists, h);
212662306a36Sopenharmony_ci}
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_cistatic bool hists__filter_entry_by_dso(struct hists *hists,
213062306a36Sopenharmony_ci				       struct hist_entry *he)
213162306a36Sopenharmony_ci{
213262306a36Sopenharmony_ci	if (hists->dso_filter != NULL &&
213362306a36Sopenharmony_ci	    (he->ms.map == NULL || map__dso(he->ms.map) != hists->dso_filter)) {
213462306a36Sopenharmony_ci		he->filtered |= (1 << HIST_FILTER__DSO);
213562306a36Sopenharmony_ci		return true;
213662306a36Sopenharmony_ci	}
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	return false;
213962306a36Sopenharmony_ci}
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_cistatic bool hists__filter_entry_by_thread(struct hists *hists,
214262306a36Sopenharmony_ci					  struct hist_entry *he)
214362306a36Sopenharmony_ci{
214462306a36Sopenharmony_ci	if (hists->thread_filter != NULL &&
214562306a36Sopenharmony_ci	    RC_CHK_ACCESS(he->thread) != RC_CHK_ACCESS(hists->thread_filter)) {
214662306a36Sopenharmony_ci		he->filtered |= (1 << HIST_FILTER__THREAD);
214762306a36Sopenharmony_ci		return true;
214862306a36Sopenharmony_ci	}
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	return false;
215162306a36Sopenharmony_ci}
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_cistatic bool hists__filter_entry_by_symbol(struct hists *hists,
215462306a36Sopenharmony_ci					  struct hist_entry *he)
215562306a36Sopenharmony_ci{
215662306a36Sopenharmony_ci	if (hists->symbol_filter_str != NULL &&
215762306a36Sopenharmony_ci	    (!he->ms.sym || strstr(he->ms.sym->name,
215862306a36Sopenharmony_ci				   hists->symbol_filter_str) == NULL)) {
215962306a36Sopenharmony_ci		he->filtered |= (1 << HIST_FILTER__SYMBOL);
216062306a36Sopenharmony_ci		return true;
216162306a36Sopenharmony_ci	}
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	return false;
216462306a36Sopenharmony_ci}
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_cistatic bool hists__filter_entry_by_socket(struct hists *hists,
216762306a36Sopenharmony_ci					  struct hist_entry *he)
216862306a36Sopenharmony_ci{
216962306a36Sopenharmony_ci	if ((hists->socket_filter > -1) &&
217062306a36Sopenharmony_ci	    (he->socket != hists->socket_filter)) {
217162306a36Sopenharmony_ci		he->filtered |= (1 << HIST_FILTER__SOCKET);
217262306a36Sopenharmony_ci		return true;
217362306a36Sopenharmony_ci	}
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	return false;
217662306a36Sopenharmony_ci}
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_citypedef bool (*filter_fn_t)(struct hists *hists, struct hist_entry *he);
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_cistatic void hists__filter_by_type(struct hists *hists, int type, filter_fn_t filter)
218162306a36Sopenharmony_ci{
218262306a36Sopenharmony_ci	struct rb_node *nd;
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	hists->stats.nr_non_filtered_samples = 0;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	hists__reset_filter_stats(hists);
218762306a36Sopenharmony_ci	hists__reset_col_len(hists);
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	for (nd = rb_first_cached(&hists->entries); nd; nd = rb_next(nd)) {
219062306a36Sopenharmony_ci		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci		if (filter(hists, h))
219362306a36Sopenharmony_ci			continue;
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci		hists__remove_entry_filter(hists, h, type);
219662306a36Sopenharmony_ci	}
219762306a36Sopenharmony_ci}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_cistatic void resort_filtered_entry(struct rb_root_cached *root,
220062306a36Sopenharmony_ci				  struct hist_entry *he)
220162306a36Sopenharmony_ci{
220262306a36Sopenharmony_ci	struct rb_node **p = &root->rb_root.rb_node;
220362306a36Sopenharmony_ci	struct rb_node *parent = NULL;
220462306a36Sopenharmony_ci	struct hist_entry *iter;
220562306a36Sopenharmony_ci	struct rb_root_cached new_root = RB_ROOT_CACHED;
220662306a36Sopenharmony_ci	struct rb_node *nd;
220762306a36Sopenharmony_ci	bool leftmost = true;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	while (*p != NULL) {
221062306a36Sopenharmony_ci		parent = *p;
221162306a36Sopenharmony_ci		iter = rb_entry(parent, struct hist_entry, rb_node);
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci		if (hist_entry__sort(he, iter) > 0)
221462306a36Sopenharmony_ci			p = &(*p)->rb_left;
221562306a36Sopenharmony_ci		else {
221662306a36Sopenharmony_ci			p = &(*p)->rb_right;
221762306a36Sopenharmony_ci			leftmost = false;
221862306a36Sopenharmony_ci		}
221962306a36Sopenharmony_ci	}
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	rb_link_node(&he->rb_node, parent, p);
222262306a36Sopenharmony_ci	rb_insert_color_cached(&he->rb_node, root, leftmost);
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	if (he->leaf || he->filtered)
222562306a36Sopenharmony_ci		return;
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	nd = rb_first_cached(&he->hroot_out);
222862306a36Sopenharmony_ci	while (nd) {
222962306a36Sopenharmony_ci		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci		nd = rb_next(nd);
223262306a36Sopenharmony_ci		rb_erase_cached(&h->rb_node, &he->hroot_out);
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci		resort_filtered_entry(&new_root, h);
223562306a36Sopenharmony_ci	}
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	he->hroot_out = new_root;
223862306a36Sopenharmony_ci}
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_cistatic void hists__filter_hierarchy(struct hists *hists, int type, const void *arg)
224162306a36Sopenharmony_ci{
224262306a36Sopenharmony_ci	struct rb_node *nd;
224362306a36Sopenharmony_ci	struct rb_root_cached new_root = RB_ROOT_CACHED;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	hists->stats.nr_non_filtered_samples = 0;
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	hists__reset_filter_stats(hists);
224862306a36Sopenharmony_ci	hists__reset_col_len(hists);
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	nd = rb_first_cached(&hists->entries);
225162306a36Sopenharmony_ci	while (nd) {
225262306a36Sopenharmony_ci		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
225362306a36Sopenharmony_ci		int ret;
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci		ret = hist_entry__filter(h, type, arg);
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci		/*
225862306a36Sopenharmony_ci		 * case 1. non-matching type
225962306a36Sopenharmony_ci		 * zero out the period, set filter marker and move to child
226062306a36Sopenharmony_ci		 */
226162306a36Sopenharmony_ci		if (ret < 0) {
226262306a36Sopenharmony_ci			memset(&h->stat, 0, sizeof(h->stat));
226362306a36Sopenharmony_ci			h->filtered |= (1 << type);
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci			nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_CHILD);
226662306a36Sopenharmony_ci		}
226762306a36Sopenharmony_ci		/*
226862306a36Sopenharmony_ci		 * case 2. matched type (filter out)
226962306a36Sopenharmony_ci		 * set filter marker and move to next
227062306a36Sopenharmony_ci		 */
227162306a36Sopenharmony_ci		else if (ret == 1) {
227262306a36Sopenharmony_ci			h->filtered |= (1 << type);
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci			nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
227562306a36Sopenharmony_ci		}
227662306a36Sopenharmony_ci		/*
227762306a36Sopenharmony_ci		 * case 3. ok (not filtered)
227862306a36Sopenharmony_ci		 * add period to hists and parents, erase the filter marker
227962306a36Sopenharmony_ci		 * and move to next sibling
228062306a36Sopenharmony_ci		 */
228162306a36Sopenharmony_ci		else {
228262306a36Sopenharmony_ci			hists__remove_entry_filter(hists, h, type);
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci			nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
228562306a36Sopenharmony_ci		}
228662306a36Sopenharmony_ci	}
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	hierarchy_recalc_total_periods(hists);
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci	/*
229162306a36Sopenharmony_ci	 * resort output after applying a new filter since filter in a lower
229262306a36Sopenharmony_ci	 * hierarchy can change periods in a upper hierarchy.
229362306a36Sopenharmony_ci	 */
229462306a36Sopenharmony_ci	nd = rb_first_cached(&hists->entries);
229562306a36Sopenharmony_ci	while (nd) {
229662306a36Sopenharmony_ci		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci		nd = rb_next(nd);
229962306a36Sopenharmony_ci		rb_erase_cached(&h->rb_node, &hists->entries);
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci		resort_filtered_entry(&new_root, h);
230262306a36Sopenharmony_ci	}
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci	hists->entries = new_root;
230562306a36Sopenharmony_ci}
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_civoid hists__filter_by_thread(struct hists *hists)
230862306a36Sopenharmony_ci{
230962306a36Sopenharmony_ci	if (symbol_conf.report_hierarchy)
231062306a36Sopenharmony_ci		hists__filter_hierarchy(hists, HIST_FILTER__THREAD,
231162306a36Sopenharmony_ci					hists->thread_filter);
231262306a36Sopenharmony_ci	else
231362306a36Sopenharmony_ci		hists__filter_by_type(hists, HIST_FILTER__THREAD,
231462306a36Sopenharmony_ci				      hists__filter_entry_by_thread);
231562306a36Sopenharmony_ci}
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_civoid hists__filter_by_dso(struct hists *hists)
231862306a36Sopenharmony_ci{
231962306a36Sopenharmony_ci	if (symbol_conf.report_hierarchy)
232062306a36Sopenharmony_ci		hists__filter_hierarchy(hists, HIST_FILTER__DSO,
232162306a36Sopenharmony_ci					hists->dso_filter);
232262306a36Sopenharmony_ci	else
232362306a36Sopenharmony_ci		hists__filter_by_type(hists, HIST_FILTER__DSO,
232462306a36Sopenharmony_ci				      hists__filter_entry_by_dso);
232562306a36Sopenharmony_ci}
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_civoid hists__filter_by_symbol(struct hists *hists)
232862306a36Sopenharmony_ci{
232962306a36Sopenharmony_ci	if (symbol_conf.report_hierarchy)
233062306a36Sopenharmony_ci		hists__filter_hierarchy(hists, HIST_FILTER__SYMBOL,
233162306a36Sopenharmony_ci					hists->symbol_filter_str);
233262306a36Sopenharmony_ci	else
233362306a36Sopenharmony_ci		hists__filter_by_type(hists, HIST_FILTER__SYMBOL,
233462306a36Sopenharmony_ci				      hists__filter_entry_by_symbol);
233562306a36Sopenharmony_ci}
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_civoid hists__filter_by_socket(struct hists *hists)
233862306a36Sopenharmony_ci{
233962306a36Sopenharmony_ci	if (symbol_conf.report_hierarchy)
234062306a36Sopenharmony_ci		hists__filter_hierarchy(hists, HIST_FILTER__SOCKET,
234162306a36Sopenharmony_ci					&hists->socket_filter);
234262306a36Sopenharmony_ci	else
234362306a36Sopenharmony_ci		hists__filter_by_type(hists, HIST_FILTER__SOCKET,
234462306a36Sopenharmony_ci				      hists__filter_entry_by_socket);
234562306a36Sopenharmony_ci}
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_civoid events_stats__inc(struct events_stats *stats, u32 type)
234862306a36Sopenharmony_ci{
234962306a36Sopenharmony_ci	++stats->nr_events[0];
235062306a36Sopenharmony_ci	++stats->nr_events[type];
235162306a36Sopenharmony_ci}
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_cistatic void hists_stats__inc(struct hists_stats *stats)
235462306a36Sopenharmony_ci{
235562306a36Sopenharmony_ci	++stats->nr_samples;
235662306a36Sopenharmony_ci}
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_civoid hists__inc_nr_events(struct hists *hists)
235962306a36Sopenharmony_ci{
236062306a36Sopenharmony_ci	hists_stats__inc(&hists->stats);
236162306a36Sopenharmony_ci}
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_civoid hists__inc_nr_samples(struct hists *hists, bool filtered)
236462306a36Sopenharmony_ci{
236562306a36Sopenharmony_ci	hists_stats__inc(&hists->stats);
236662306a36Sopenharmony_ci	if (!filtered)
236762306a36Sopenharmony_ci		hists->stats.nr_non_filtered_samples++;
236862306a36Sopenharmony_ci}
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_civoid hists__inc_nr_lost_samples(struct hists *hists, u32 lost)
237162306a36Sopenharmony_ci{
237262306a36Sopenharmony_ci	hists->stats.nr_lost_samples += lost;
237362306a36Sopenharmony_ci}
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_cistatic struct hist_entry *hists__add_dummy_entry(struct hists *hists,
237662306a36Sopenharmony_ci						 struct hist_entry *pair)
237762306a36Sopenharmony_ci{
237862306a36Sopenharmony_ci	struct rb_root_cached *root;
237962306a36Sopenharmony_ci	struct rb_node **p;
238062306a36Sopenharmony_ci	struct rb_node *parent = NULL;
238162306a36Sopenharmony_ci	struct hist_entry *he;
238262306a36Sopenharmony_ci	int64_t cmp;
238362306a36Sopenharmony_ci	bool leftmost = true;
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci	if (hists__has(hists, need_collapse))
238662306a36Sopenharmony_ci		root = &hists->entries_collapsed;
238762306a36Sopenharmony_ci	else
238862306a36Sopenharmony_ci		root = hists->entries_in;
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci	p = &root->rb_root.rb_node;
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	while (*p != NULL) {
239362306a36Sopenharmony_ci		parent = *p;
239462306a36Sopenharmony_ci		he = rb_entry(parent, struct hist_entry, rb_node_in);
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci		cmp = hist_entry__collapse(he, pair);
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci		if (!cmp)
239962306a36Sopenharmony_ci			goto out;
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci		if (cmp < 0)
240262306a36Sopenharmony_ci			p = &(*p)->rb_left;
240362306a36Sopenharmony_ci		else {
240462306a36Sopenharmony_ci			p = &(*p)->rb_right;
240562306a36Sopenharmony_ci			leftmost = false;
240662306a36Sopenharmony_ci		}
240762306a36Sopenharmony_ci	}
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci	he = hist_entry__new(pair, true);
241062306a36Sopenharmony_ci	if (he) {
241162306a36Sopenharmony_ci		memset(&he->stat, 0, sizeof(he->stat));
241262306a36Sopenharmony_ci		he->hists = hists;
241362306a36Sopenharmony_ci		if (symbol_conf.cumulate_callchain)
241462306a36Sopenharmony_ci			memset(he->stat_acc, 0, sizeof(he->stat));
241562306a36Sopenharmony_ci		rb_link_node(&he->rb_node_in, parent, p);
241662306a36Sopenharmony_ci		rb_insert_color_cached(&he->rb_node_in, root, leftmost);
241762306a36Sopenharmony_ci		hists__inc_stats(hists, he);
241862306a36Sopenharmony_ci		he->dummy = true;
241962306a36Sopenharmony_ci	}
242062306a36Sopenharmony_ciout:
242162306a36Sopenharmony_ci	return he;
242262306a36Sopenharmony_ci}
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_cistatic struct hist_entry *add_dummy_hierarchy_entry(struct hists *hists,
242562306a36Sopenharmony_ci						    struct rb_root_cached *root,
242662306a36Sopenharmony_ci						    struct hist_entry *pair)
242762306a36Sopenharmony_ci{
242862306a36Sopenharmony_ci	struct rb_node **p;
242962306a36Sopenharmony_ci	struct rb_node *parent = NULL;
243062306a36Sopenharmony_ci	struct hist_entry *he;
243162306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
243262306a36Sopenharmony_ci	bool leftmost = true;
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	p = &root->rb_root.rb_node;
243562306a36Sopenharmony_ci	while (*p != NULL) {
243662306a36Sopenharmony_ci		int64_t cmp = 0;
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci		parent = *p;
243962306a36Sopenharmony_ci		he = rb_entry(parent, struct hist_entry, rb_node_in);
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci		perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
244262306a36Sopenharmony_ci			cmp = fmt->collapse(fmt, he, pair);
244362306a36Sopenharmony_ci			if (cmp)
244462306a36Sopenharmony_ci				break;
244562306a36Sopenharmony_ci		}
244662306a36Sopenharmony_ci		if (!cmp)
244762306a36Sopenharmony_ci			goto out;
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci		if (cmp < 0)
245062306a36Sopenharmony_ci			p = &parent->rb_left;
245162306a36Sopenharmony_ci		else {
245262306a36Sopenharmony_ci			p = &parent->rb_right;
245362306a36Sopenharmony_ci			leftmost = false;
245462306a36Sopenharmony_ci		}
245562306a36Sopenharmony_ci	}
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	he = hist_entry__new(pair, true);
245862306a36Sopenharmony_ci	if (he) {
245962306a36Sopenharmony_ci		rb_link_node(&he->rb_node_in, parent, p);
246062306a36Sopenharmony_ci		rb_insert_color_cached(&he->rb_node_in, root, leftmost);
246162306a36Sopenharmony_ci
246262306a36Sopenharmony_ci		he->dummy = true;
246362306a36Sopenharmony_ci		he->hists = hists;
246462306a36Sopenharmony_ci		memset(&he->stat, 0, sizeof(he->stat));
246562306a36Sopenharmony_ci		hists__inc_stats(hists, he);
246662306a36Sopenharmony_ci	}
246762306a36Sopenharmony_ciout:
246862306a36Sopenharmony_ci	return he;
246962306a36Sopenharmony_ci}
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_cistatic struct hist_entry *hists__find_entry(struct hists *hists,
247262306a36Sopenharmony_ci					    struct hist_entry *he)
247362306a36Sopenharmony_ci{
247462306a36Sopenharmony_ci	struct rb_node *n;
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci	if (hists__has(hists, need_collapse))
247762306a36Sopenharmony_ci		n = hists->entries_collapsed.rb_root.rb_node;
247862306a36Sopenharmony_ci	else
247962306a36Sopenharmony_ci		n = hists->entries_in->rb_root.rb_node;
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci	while (n) {
248262306a36Sopenharmony_ci		struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in);
248362306a36Sopenharmony_ci		int64_t cmp = hist_entry__collapse(iter, he);
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci		if (cmp < 0)
248662306a36Sopenharmony_ci			n = n->rb_left;
248762306a36Sopenharmony_ci		else if (cmp > 0)
248862306a36Sopenharmony_ci			n = n->rb_right;
248962306a36Sopenharmony_ci		else
249062306a36Sopenharmony_ci			return iter;
249162306a36Sopenharmony_ci	}
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	return NULL;
249462306a36Sopenharmony_ci}
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_cistatic struct hist_entry *hists__find_hierarchy_entry(struct rb_root_cached *root,
249762306a36Sopenharmony_ci						      struct hist_entry *he)
249862306a36Sopenharmony_ci{
249962306a36Sopenharmony_ci	struct rb_node *n = root->rb_root.rb_node;
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	while (n) {
250262306a36Sopenharmony_ci		struct hist_entry *iter;
250362306a36Sopenharmony_ci		struct perf_hpp_fmt *fmt;
250462306a36Sopenharmony_ci		int64_t cmp = 0;
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci		iter = rb_entry(n, struct hist_entry, rb_node_in);
250762306a36Sopenharmony_ci		perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
250862306a36Sopenharmony_ci			cmp = fmt->collapse(fmt, iter, he);
250962306a36Sopenharmony_ci			if (cmp)
251062306a36Sopenharmony_ci				break;
251162306a36Sopenharmony_ci		}
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci		if (cmp < 0)
251462306a36Sopenharmony_ci			n = n->rb_left;
251562306a36Sopenharmony_ci		else if (cmp > 0)
251662306a36Sopenharmony_ci			n = n->rb_right;
251762306a36Sopenharmony_ci		else
251862306a36Sopenharmony_ci			return iter;
251962306a36Sopenharmony_ci	}
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ci	return NULL;
252262306a36Sopenharmony_ci}
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_cistatic void hists__match_hierarchy(struct rb_root_cached *leader_root,
252562306a36Sopenharmony_ci				   struct rb_root_cached *other_root)
252662306a36Sopenharmony_ci{
252762306a36Sopenharmony_ci	struct rb_node *nd;
252862306a36Sopenharmony_ci	struct hist_entry *pos, *pair;
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	for (nd = rb_first_cached(leader_root); nd; nd = rb_next(nd)) {
253162306a36Sopenharmony_ci		pos  = rb_entry(nd, struct hist_entry, rb_node_in);
253262306a36Sopenharmony_ci		pair = hists__find_hierarchy_entry(other_root, pos);
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci		if (pair) {
253562306a36Sopenharmony_ci			hist_entry__add_pair(pair, pos);
253662306a36Sopenharmony_ci			hists__match_hierarchy(&pos->hroot_in, &pair->hroot_in);
253762306a36Sopenharmony_ci		}
253862306a36Sopenharmony_ci	}
253962306a36Sopenharmony_ci}
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci/*
254262306a36Sopenharmony_ci * Look for pairs to link to the leader buckets (hist_entries):
254362306a36Sopenharmony_ci */
254462306a36Sopenharmony_civoid hists__match(struct hists *leader, struct hists *other)
254562306a36Sopenharmony_ci{
254662306a36Sopenharmony_ci	struct rb_root_cached *root;
254762306a36Sopenharmony_ci	struct rb_node *nd;
254862306a36Sopenharmony_ci	struct hist_entry *pos, *pair;
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	if (symbol_conf.report_hierarchy) {
255162306a36Sopenharmony_ci		/* hierarchy report always collapses entries */
255262306a36Sopenharmony_ci		return hists__match_hierarchy(&leader->entries_collapsed,
255362306a36Sopenharmony_ci					      &other->entries_collapsed);
255462306a36Sopenharmony_ci	}
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_ci	if (hists__has(leader, need_collapse))
255762306a36Sopenharmony_ci		root = &leader->entries_collapsed;
255862306a36Sopenharmony_ci	else
255962306a36Sopenharmony_ci		root = leader->entries_in;
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
256262306a36Sopenharmony_ci		pos  = rb_entry(nd, struct hist_entry, rb_node_in);
256362306a36Sopenharmony_ci		pair = hists__find_entry(other, pos);
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci		if (pair)
256662306a36Sopenharmony_ci			hist_entry__add_pair(pair, pos);
256762306a36Sopenharmony_ci	}
256862306a36Sopenharmony_ci}
256962306a36Sopenharmony_ci
257062306a36Sopenharmony_cistatic int hists__link_hierarchy(struct hists *leader_hists,
257162306a36Sopenharmony_ci				 struct hist_entry *parent,
257262306a36Sopenharmony_ci				 struct rb_root_cached *leader_root,
257362306a36Sopenharmony_ci				 struct rb_root_cached *other_root)
257462306a36Sopenharmony_ci{
257562306a36Sopenharmony_ci	struct rb_node *nd;
257662306a36Sopenharmony_ci	struct hist_entry *pos, *leader;
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci	for (nd = rb_first_cached(other_root); nd; nd = rb_next(nd)) {
257962306a36Sopenharmony_ci		pos = rb_entry(nd, struct hist_entry, rb_node_in);
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci		if (hist_entry__has_pairs(pos)) {
258262306a36Sopenharmony_ci			bool found = false;
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci			list_for_each_entry(leader, &pos->pairs.head, pairs.node) {
258562306a36Sopenharmony_ci				if (leader->hists == leader_hists) {
258662306a36Sopenharmony_ci					found = true;
258762306a36Sopenharmony_ci					break;
258862306a36Sopenharmony_ci				}
258962306a36Sopenharmony_ci			}
259062306a36Sopenharmony_ci			if (!found)
259162306a36Sopenharmony_ci				return -1;
259262306a36Sopenharmony_ci		} else {
259362306a36Sopenharmony_ci			leader = add_dummy_hierarchy_entry(leader_hists,
259462306a36Sopenharmony_ci							   leader_root, pos);
259562306a36Sopenharmony_ci			if (leader == NULL)
259662306a36Sopenharmony_ci				return -1;
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_ci			/* do not point parent in the pos */
259962306a36Sopenharmony_ci			leader->parent_he = parent;
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci			hist_entry__add_pair(pos, leader);
260262306a36Sopenharmony_ci		}
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci		if (!pos->leaf) {
260562306a36Sopenharmony_ci			if (hists__link_hierarchy(leader_hists, leader,
260662306a36Sopenharmony_ci						  &leader->hroot_in,
260762306a36Sopenharmony_ci						  &pos->hroot_in) < 0)
260862306a36Sopenharmony_ci				return -1;
260962306a36Sopenharmony_ci		}
261062306a36Sopenharmony_ci	}
261162306a36Sopenharmony_ci	return 0;
261262306a36Sopenharmony_ci}
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci/*
261562306a36Sopenharmony_ci * Look for entries in the other hists that are not present in the leader, if
261662306a36Sopenharmony_ci * we find them, just add a dummy entry on the leader hists, with period=0,
261762306a36Sopenharmony_ci * nr_events=0, to serve as the list header.
261862306a36Sopenharmony_ci */
261962306a36Sopenharmony_ciint hists__link(struct hists *leader, struct hists *other)
262062306a36Sopenharmony_ci{
262162306a36Sopenharmony_ci	struct rb_root_cached *root;
262262306a36Sopenharmony_ci	struct rb_node *nd;
262362306a36Sopenharmony_ci	struct hist_entry *pos, *pair;
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	if (symbol_conf.report_hierarchy) {
262662306a36Sopenharmony_ci		/* hierarchy report always collapses entries */
262762306a36Sopenharmony_ci		return hists__link_hierarchy(leader, NULL,
262862306a36Sopenharmony_ci					     &leader->entries_collapsed,
262962306a36Sopenharmony_ci					     &other->entries_collapsed);
263062306a36Sopenharmony_ci	}
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci	if (hists__has(other, need_collapse))
263362306a36Sopenharmony_ci		root = &other->entries_collapsed;
263462306a36Sopenharmony_ci	else
263562306a36Sopenharmony_ci		root = other->entries_in;
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci	for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
263862306a36Sopenharmony_ci		pos = rb_entry(nd, struct hist_entry, rb_node_in);
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci		if (!hist_entry__has_pairs(pos)) {
264162306a36Sopenharmony_ci			pair = hists__add_dummy_entry(leader, pos);
264262306a36Sopenharmony_ci			if (pair == NULL)
264362306a36Sopenharmony_ci				return -1;
264462306a36Sopenharmony_ci			hist_entry__add_pair(pos, pair);
264562306a36Sopenharmony_ci		}
264662306a36Sopenharmony_ci	}
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_ci	return 0;
264962306a36Sopenharmony_ci}
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ciint hists__unlink(struct hists *hists)
265262306a36Sopenharmony_ci{
265362306a36Sopenharmony_ci	struct rb_root_cached *root;
265462306a36Sopenharmony_ci	struct rb_node *nd;
265562306a36Sopenharmony_ci	struct hist_entry *pos;
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	if (hists__has(hists, need_collapse))
265862306a36Sopenharmony_ci		root = &hists->entries_collapsed;
265962306a36Sopenharmony_ci	else
266062306a36Sopenharmony_ci		root = hists->entries_in;
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
266362306a36Sopenharmony_ci		pos = rb_entry(nd, struct hist_entry, rb_node_in);
266462306a36Sopenharmony_ci		list_del_init(&pos->pairs.node);
266562306a36Sopenharmony_ci	}
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	return 0;
266862306a36Sopenharmony_ci}
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_civoid hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
267162306a36Sopenharmony_ci			  struct perf_sample *sample, bool nonany_branch_mode,
267262306a36Sopenharmony_ci			  u64 *total_cycles)
267362306a36Sopenharmony_ci{
267462306a36Sopenharmony_ci	struct branch_info *bi;
267562306a36Sopenharmony_ci	struct branch_entry *entries = perf_sample__branch_entries(sample);
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	/* If we have branch cycles always annotate them. */
267862306a36Sopenharmony_ci	if (bs && bs->nr && entries[0].flags.cycles) {
267962306a36Sopenharmony_ci		bi = sample__resolve_bstack(sample, al);
268062306a36Sopenharmony_ci		if (bi) {
268162306a36Sopenharmony_ci			struct addr_map_symbol *prev = NULL;
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci			/*
268462306a36Sopenharmony_ci			 * Ignore errors, still want to process the
268562306a36Sopenharmony_ci			 * other entries.
268662306a36Sopenharmony_ci			 *
268762306a36Sopenharmony_ci			 * For non standard branch modes always
268862306a36Sopenharmony_ci			 * force no IPC (prev == NULL)
268962306a36Sopenharmony_ci			 *
269062306a36Sopenharmony_ci			 * Note that perf stores branches reversed from
269162306a36Sopenharmony_ci			 * program order!
269262306a36Sopenharmony_ci			 */
269362306a36Sopenharmony_ci			for (int i = bs->nr - 1; i >= 0; i--) {
269462306a36Sopenharmony_ci				addr_map_symbol__account_cycles(&bi[i].from,
269562306a36Sopenharmony_ci					nonany_branch_mode ? NULL : prev,
269662306a36Sopenharmony_ci					bi[i].flags.cycles);
269762306a36Sopenharmony_ci				prev = &bi[i].to;
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci				if (total_cycles)
270062306a36Sopenharmony_ci					*total_cycles += bi[i].flags.cycles;
270162306a36Sopenharmony_ci			}
270262306a36Sopenharmony_ci			for (unsigned int i = 0; i < bs->nr; i++) {
270362306a36Sopenharmony_ci				map__put(bi[i].to.ms.map);
270462306a36Sopenharmony_ci				maps__put(bi[i].to.ms.maps);
270562306a36Sopenharmony_ci				map__put(bi[i].from.ms.map);
270662306a36Sopenharmony_ci				maps__put(bi[i].from.ms.maps);
270762306a36Sopenharmony_ci			}
270862306a36Sopenharmony_ci			free(bi);
270962306a36Sopenharmony_ci		}
271062306a36Sopenharmony_ci	}
271162306a36Sopenharmony_ci}
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_cisize_t evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp,
271462306a36Sopenharmony_ci				 bool skip_empty)
271562306a36Sopenharmony_ci{
271662306a36Sopenharmony_ci	struct evsel *pos;
271762306a36Sopenharmony_ci	size_t ret = 0;
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
272062306a36Sopenharmony_ci		struct hists *hists = evsel__hists(pos);
272162306a36Sopenharmony_ci
272262306a36Sopenharmony_ci		if (skip_empty && !hists->stats.nr_samples && !hists->stats.nr_lost_samples)
272362306a36Sopenharmony_ci			continue;
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci		ret += fprintf(fp, "%s stats:\n", evsel__name(pos));
272662306a36Sopenharmony_ci		if (hists->stats.nr_samples)
272762306a36Sopenharmony_ci			ret += fprintf(fp, "%16s events: %10d\n",
272862306a36Sopenharmony_ci				       "SAMPLE", hists->stats.nr_samples);
272962306a36Sopenharmony_ci		if (hists->stats.nr_lost_samples)
273062306a36Sopenharmony_ci			ret += fprintf(fp, "%16s events: %10d\n",
273162306a36Sopenharmony_ci				       "LOST_SAMPLES", hists->stats.nr_lost_samples);
273262306a36Sopenharmony_ci	}
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	return ret;
273562306a36Sopenharmony_ci}
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ciu64 hists__total_period(struct hists *hists)
273962306a36Sopenharmony_ci{
274062306a36Sopenharmony_ci	return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period :
274162306a36Sopenharmony_ci		hists->stats.total_period;
274262306a36Sopenharmony_ci}
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ciint __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool show_freq)
274562306a36Sopenharmony_ci{
274662306a36Sopenharmony_ci	char unit;
274762306a36Sopenharmony_ci	int printed;
274862306a36Sopenharmony_ci	const struct dso *dso = hists->dso_filter;
274962306a36Sopenharmony_ci	struct thread *thread = hists->thread_filter;
275062306a36Sopenharmony_ci	int socket_id = hists->socket_filter;
275162306a36Sopenharmony_ci	unsigned long nr_samples = hists->stats.nr_samples;
275262306a36Sopenharmony_ci	u64 nr_events = hists->stats.total_period;
275362306a36Sopenharmony_ci	struct evsel *evsel = hists_to_evsel(hists);
275462306a36Sopenharmony_ci	const char *ev_name = evsel__name(evsel);
275562306a36Sopenharmony_ci	char buf[512], sample_freq_str[64] = "";
275662306a36Sopenharmony_ci	size_t buflen = sizeof(buf);
275762306a36Sopenharmony_ci	char ref[30] = " show reference callgraph, ";
275862306a36Sopenharmony_ci	bool enable_ref = false;
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci	if (symbol_conf.filter_relative) {
276162306a36Sopenharmony_ci		nr_samples = hists->stats.nr_non_filtered_samples;
276262306a36Sopenharmony_ci		nr_events = hists->stats.total_non_filtered_period;
276362306a36Sopenharmony_ci	}
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci	if (evsel__is_group_event(evsel)) {
276662306a36Sopenharmony_ci		struct evsel *pos;
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci		evsel__group_desc(evsel, buf, buflen);
276962306a36Sopenharmony_ci		ev_name = buf;
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci		for_each_group_member(pos, evsel) {
277262306a36Sopenharmony_ci			struct hists *pos_hists = evsel__hists(pos);
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci			if (symbol_conf.filter_relative) {
277562306a36Sopenharmony_ci				nr_samples += pos_hists->stats.nr_non_filtered_samples;
277662306a36Sopenharmony_ci				nr_events += pos_hists->stats.total_non_filtered_period;
277762306a36Sopenharmony_ci			} else {
277862306a36Sopenharmony_ci				nr_samples += pos_hists->stats.nr_samples;
277962306a36Sopenharmony_ci				nr_events += pos_hists->stats.total_period;
278062306a36Sopenharmony_ci			}
278162306a36Sopenharmony_ci		}
278262306a36Sopenharmony_ci	}
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci	if (symbol_conf.show_ref_callgraph &&
278562306a36Sopenharmony_ci	    strstr(ev_name, "call-graph=no"))
278662306a36Sopenharmony_ci		enable_ref = true;
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci	if (show_freq)
278962306a36Sopenharmony_ci		scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->core.attr.sample_freq);
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ci	nr_samples = convert_unit(nr_samples, &unit);
279262306a36Sopenharmony_ci	printed = scnprintf(bf, size,
279362306a36Sopenharmony_ci			   "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64,
279462306a36Sopenharmony_ci			   nr_samples, unit, evsel->core.nr_members > 1 ? "s" : "",
279562306a36Sopenharmony_ci			   ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events);
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_ci	if (hists->uid_filter_str)
279962306a36Sopenharmony_ci		printed += snprintf(bf + printed, size - printed,
280062306a36Sopenharmony_ci				    ", UID: %s", hists->uid_filter_str);
280162306a36Sopenharmony_ci	if (thread) {
280262306a36Sopenharmony_ci		if (hists__has(hists, thread)) {
280362306a36Sopenharmony_ci			printed += scnprintf(bf + printed, size - printed,
280462306a36Sopenharmony_ci				    ", Thread: %s(%d)",
280562306a36Sopenharmony_ci				    (thread__comm_set(thread) ? thread__comm_str(thread) : ""),
280662306a36Sopenharmony_ci					thread__tid(thread));
280762306a36Sopenharmony_ci		} else {
280862306a36Sopenharmony_ci			printed += scnprintf(bf + printed, size - printed,
280962306a36Sopenharmony_ci				    ", Thread: %s",
281062306a36Sopenharmony_ci				    (thread__comm_set(thread) ? thread__comm_str(thread) : ""));
281162306a36Sopenharmony_ci		}
281262306a36Sopenharmony_ci	}
281362306a36Sopenharmony_ci	if (dso)
281462306a36Sopenharmony_ci		printed += scnprintf(bf + printed, size - printed,
281562306a36Sopenharmony_ci				    ", DSO: %s", dso->short_name);
281662306a36Sopenharmony_ci	if (socket_id > -1)
281762306a36Sopenharmony_ci		printed += scnprintf(bf + printed, size - printed,
281862306a36Sopenharmony_ci				    ", Processor Socket: %d", socket_id);
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci	return printed;
282162306a36Sopenharmony_ci}
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ciint parse_filter_percentage(const struct option *opt __maybe_unused,
282462306a36Sopenharmony_ci			    const char *arg, int unset __maybe_unused)
282562306a36Sopenharmony_ci{
282662306a36Sopenharmony_ci	if (!strcmp(arg, "relative"))
282762306a36Sopenharmony_ci		symbol_conf.filter_relative = true;
282862306a36Sopenharmony_ci	else if (!strcmp(arg, "absolute"))
282962306a36Sopenharmony_ci		symbol_conf.filter_relative = false;
283062306a36Sopenharmony_ci	else {
283162306a36Sopenharmony_ci		pr_debug("Invalid percentage: %s\n", arg);
283262306a36Sopenharmony_ci		return -1;
283362306a36Sopenharmony_ci	}
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci	return 0;
283662306a36Sopenharmony_ci}
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ciint perf_hist_config(const char *var, const char *value)
283962306a36Sopenharmony_ci{
284062306a36Sopenharmony_ci	if (!strcmp(var, "hist.percentage"))
284162306a36Sopenharmony_ci		return parse_filter_percentage(NULL, value, 0);
284262306a36Sopenharmony_ci
284362306a36Sopenharmony_ci	return 0;
284462306a36Sopenharmony_ci}
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ciint __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list)
284762306a36Sopenharmony_ci{
284862306a36Sopenharmony_ci	memset(hists, 0, sizeof(*hists));
284962306a36Sopenharmony_ci	hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT_CACHED;
285062306a36Sopenharmony_ci	hists->entries_in = &hists->entries_in_array[0];
285162306a36Sopenharmony_ci	hists->entries_collapsed = RB_ROOT_CACHED;
285262306a36Sopenharmony_ci	hists->entries = RB_ROOT_CACHED;
285362306a36Sopenharmony_ci	mutex_init(&hists->lock);
285462306a36Sopenharmony_ci	hists->socket_filter = -1;
285562306a36Sopenharmony_ci	hists->hpp_list = hpp_list;
285662306a36Sopenharmony_ci	INIT_LIST_HEAD(&hists->hpp_formats);
285762306a36Sopenharmony_ci	return 0;
285862306a36Sopenharmony_ci}
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_cistatic void hists__delete_remaining_entries(struct rb_root_cached *root)
286162306a36Sopenharmony_ci{
286262306a36Sopenharmony_ci	struct rb_node *node;
286362306a36Sopenharmony_ci	struct hist_entry *he;
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	while (!RB_EMPTY_ROOT(&root->rb_root)) {
286662306a36Sopenharmony_ci		node = rb_first_cached(root);
286762306a36Sopenharmony_ci		rb_erase_cached(node, root);
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci		he = rb_entry(node, struct hist_entry, rb_node_in);
287062306a36Sopenharmony_ci		hist_entry__delete(he);
287162306a36Sopenharmony_ci	}
287262306a36Sopenharmony_ci}
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_cistatic void hists__delete_all_entries(struct hists *hists)
287562306a36Sopenharmony_ci{
287662306a36Sopenharmony_ci	hists__delete_entries(hists);
287762306a36Sopenharmony_ci	hists__delete_remaining_entries(&hists->entries_in_array[0]);
287862306a36Sopenharmony_ci	hists__delete_remaining_entries(&hists->entries_in_array[1]);
287962306a36Sopenharmony_ci	hists__delete_remaining_entries(&hists->entries_collapsed);
288062306a36Sopenharmony_ci}
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_cistatic void hists_evsel__exit(struct evsel *evsel)
288362306a36Sopenharmony_ci{
288462306a36Sopenharmony_ci	struct hists *hists = evsel__hists(evsel);
288562306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt, *pos;
288662306a36Sopenharmony_ci	struct perf_hpp_list_node *node, *tmp;
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_ci	hists__delete_all_entries(hists);
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	list_for_each_entry_safe(node, tmp, &hists->hpp_formats, list) {
289162306a36Sopenharmony_ci		perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
289262306a36Sopenharmony_ci			list_del_init(&fmt->list);
289362306a36Sopenharmony_ci			free(fmt);
289462306a36Sopenharmony_ci		}
289562306a36Sopenharmony_ci		list_del_init(&node->list);
289662306a36Sopenharmony_ci		free(node);
289762306a36Sopenharmony_ci	}
289862306a36Sopenharmony_ci}
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_cistatic int hists_evsel__init(struct evsel *evsel)
290162306a36Sopenharmony_ci{
290262306a36Sopenharmony_ci	struct hists *hists = evsel__hists(evsel);
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci	__hists__init(hists, &perf_hpp_list);
290562306a36Sopenharmony_ci	return 0;
290662306a36Sopenharmony_ci}
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ci/*
290962306a36Sopenharmony_ci * XXX We probably need a hists_evsel__exit() to free the hist_entries
291062306a36Sopenharmony_ci * stored in the rbtree...
291162306a36Sopenharmony_ci */
291262306a36Sopenharmony_ci
291362306a36Sopenharmony_ciint hists__init(void)
291462306a36Sopenharmony_ci{
291562306a36Sopenharmony_ci	int err = evsel__object_config(sizeof(struct hists_evsel),
291662306a36Sopenharmony_ci				       hists_evsel__init, hists_evsel__exit);
291762306a36Sopenharmony_ci	if (err)
291862306a36Sopenharmony_ci		fputs("FATAL ERROR: Couldn't setup hists class\n", stderr);
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci	return err;
292162306a36Sopenharmony_ci}
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_civoid perf_hpp_list__init(struct perf_hpp_list *list)
292462306a36Sopenharmony_ci{
292562306a36Sopenharmony_ci	INIT_LIST_HEAD(&list->fields);
292662306a36Sopenharmony_ci	INIT_LIST_HEAD(&list->sorts);
292762306a36Sopenharmony_ci}
2928