18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include "callchain.h"
38c2ecf20Sopenharmony_ci#include "debug.h"
48c2ecf20Sopenharmony_ci#include "dso.h"
58c2ecf20Sopenharmony_ci#include "build-id.h"
68c2ecf20Sopenharmony_ci#include "hist.h"
78c2ecf20Sopenharmony_ci#include "map.h"
88c2ecf20Sopenharmony_ci#include "map_symbol.h"
98c2ecf20Sopenharmony_ci#include "branch.h"
108c2ecf20Sopenharmony_ci#include "mem-events.h"
118c2ecf20Sopenharmony_ci#include "session.h"
128c2ecf20Sopenharmony_ci#include "namespaces.h"
138c2ecf20Sopenharmony_ci#include "cgroup.h"
148c2ecf20Sopenharmony_ci#include "sort.h"
158c2ecf20Sopenharmony_ci#include "units.h"
168c2ecf20Sopenharmony_ci#include "evlist.h"
178c2ecf20Sopenharmony_ci#include "evsel.h"
188c2ecf20Sopenharmony_ci#include "annotate.h"
198c2ecf20Sopenharmony_ci#include "srcline.h"
208c2ecf20Sopenharmony_ci#include "symbol.h"
218c2ecf20Sopenharmony_ci#include "thread.h"
228c2ecf20Sopenharmony_ci#include "block-info.h"
238c2ecf20Sopenharmony_ci#include "ui/progress.h"
248c2ecf20Sopenharmony_ci#include <errno.h>
258c2ecf20Sopenharmony_ci#include <math.h>
268c2ecf20Sopenharmony_ci#include <inttypes.h>
278c2ecf20Sopenharmony_ci#include <sys/param.h>
288c2ecf20Sopenharmony_ci#include <linux/rbtree.h>
298c2ecf20Sopenharmony_ci#include <linux/string.h>
308c2ecf20Sopenharmony_ci#include <linux/time64.h>
318c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic bool hists__filter_entry_by_dso(struct hists *hists,
348c2ecf20Sopenharmony_ci				       struct hist_entry *he);
358c2ecf20Sopenharmony_cistatic bool hists__filter_entry_by_thread(struct hists *hists,
368c2ecf20Sopenharmony_ci					  struct hist_entry *he);
378c2ecf20Sopenharmony_cistatic bool hists__filter_entry_by_symbol(struct hists *hists,
388c2ecf20Sopenharmony_ci					  struct hist_entry *he);
398c2ecf20Sopenharmony_cistatic bool hists__filter_entry_by_socket(struct hists *hists,
408c2ecf20Sopenharmony_ci					  struct hist_entry *he);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ciu16 hists__col_len(struct hists *hists, enum hist_column col)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	return hists->col_len[col];
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_civoid hists__set_col_len(struct hists *hists, enum hist_column col, u16 len)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	hists->col_len[col] = len;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cibool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	if (len > hists__col_len(hists, col)) {
558c2ecf20Sopenharmony_ci		hists__set_col_len(hists, col, len);
568c2ecf20Sopenharmony_ci		return true;
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci	return false;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_civoid hists__reset_col_len(struct hists *hists)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	enum hist_column col;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	for (col = 0; col < HISTC_NR_COLS; ++col)
668c2ecf20Sopenharmony_ci		hists__set_col_len(hists, col, 0);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic void hists__set_unres_dso_col_len(struct hists *hists, int dso)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (hists__col_len(hists, dso) < unresolved_col_width &&
748c2ecf20Sopenharmony_ci	    !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
758c2ecf20Sopenharmony_ci	    !symbol_conf.dso_list)
768c2ecf20Sopenharmony_ci		hists__set_col_len(hists, dso, unresolved_col_width);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_civoid hists__calc_col_len(struct hists *hists, struct hist_entry *h)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
828c2ecf20Sopenharmony_ci	int symlen;
838c2ecf20Sopenharmony_ci	u16 len;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (h->block_info)
868c2ecf20Sopenharmony_ci		return;
878c2ecf20Sopenharmony_ci	/*
888c2ecf20Sopenharmony_ci	 * +4 accounts for '[x] ' priv level info
898c2ecf20Sopenharmony_ci	 * +2 accounts for 0x prefix on raw addresses
908c2ecf20Sopenharmony_ci	 * +3 accounts for ' y ' symtab origin info
918c2ecf20Sopenharmony_ci	 */
928c2ecf20Sopenharmony_ci	if (h->ms.sym) {
938c2ecf20Sopenharmony_ci		symlen = h->ms.sym->namelen + 4;
948c2ecf20Sopenharmony_ci		if (verbose > 0)
958c2ecf20Sopenharmony_ci			symlen += BITS_PER_LONG / 4 + 2 + 3;
968c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_SYMBOL, symlen);
978c2ecf20Sopenharmony_ci	} else {
988c2ecf20Sopenharmony_ci		symlen = unresolved_col_width + 4 + 2;
998c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_SYMBOL, symlen);
1008c2ecf20Sopenharmony_ci		hists__set_unres_dso_col_len(hists, HISTC_DSO);
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	len = thread__comm_len(h->thread);
1048c2ecf20Sopenharmony_ci	if (hists__new_col_len(hists, HISTC_COMM, len))
1058c2ecf20Sopenharmony_ci		hists__set_col_len(hists, HISTC_THREAD, len + 8);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (h->ms.map) {
1088c2ecf20Sopenharmony_ci		len = dso__name_len(h->ms.map->dso);
1098c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_DSO, len);
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	if (h->parent)
1138c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (h->branch_info) {
1168c2ecf20Sopenharmony_ci		if (h->branch_info->from.ms.sym) {
1178c2ecf20Sopenharmony_ci			symlen = (int)h->branch_info->from.ms.sym->namelen + 4;
1188c2ecf20Sopenharmony_ci			if (verbose > 0)
1198c2ecf20Sopenharmony_ci				symlen += BITS_PER_LONG / 4 + 2 + 3;
1208c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci			symlen = dso__name_len(h->branch_info->from.ms.map->dso);
1238c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_DSO_FROM, symlen);
1248c2ecf20Sopenharmony_ci		} else {
1258c2ecf20Sopenharmony_ci			symlen = unresolved_col_width + 4 + 2;
1268c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
1278c2ecf20Sopenharmony_ci			hists__set_unres_dso_col_len(hists, HISTC_DSO_FROM);
1288c2ecf20Sopenharmony_ci		}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci		if (h->branch_info->to.ms.sym) {
1318c2ecf20Sopenharmony_ci			symlen = (int)h->branch_info->to.ms.sym->namelen + 4;
1328c2ecf20Sopenharmony_ci			if (verbose > 0)
1338c2ecf20Sopenharmony_ci				symlen += BITS_PER_LONG / 4 + 2 + 3;
1348c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci			symlen = dso__name_len(h->branch_info->to.ms.map->dso);
1378c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_DSO_TO, symlen);
1388c2ecf20Sopenharmony_ci		} else {
1398c2ecf20Sopenharmony_ci			symlen = unresolved_col_width + 4 + 2;
1408c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
1418c2ecf20Sopenharmony_ci			hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
1428c2ecf20Sopenharmony_ci		}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		if (h->branch_info->srcline_from)
1458c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_SRCLINE_FROM,
1468c2ecf20Sopenharmony_ci					strlen(h->branch_info->srcline_from));
1478c2ecf20Sopenharmony_ci		if (h->branch_info->srcline_to)
1488c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_SRCLINE_TO,
1498c2ecf20Sopenharmony_ci					strlen(h->branch_info->srcline_to));
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	if (h->mem_info) {
1538c2ecf20Sopenharmony_ci		if (h->mem_info->daddr.ms.sym) {
1548c2ecf20Sopenharmony_ci			symlen = (int)h->mem_info->daddr.ms.sym->namelen + 4
1558c2ecf20Sopenharmony_ci			       + unresolved_col_width + 2;
1568c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
1578c2ecf20Sopenharmony_ci					   symlen);
1588c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
1598c2ecf20Sopenharmony_ci					   symlen + 1);
1608c2ecf20Sopenharmony_ci		} else {
1618c2ecf20Sopenharmony_ci			symlen = unresolved_col_width + 4 + 2;
1628c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
1638c2ecf20Sopenharmony_ci					   symlen);
1648c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
1658c2ecf20Sopenharmony_ci					   symlen);
1668c2ecf20Sopenharmony_ci		}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci		if (h->mem_info->iaddr.ms.sym) {
1698c2ecf20Sopenharmony_ci			symlen = (int)h->mem_info->iaddr.ms.sym->namelen + 4
1708c2ecf20Sopenharmony_ci			       + unresolved_col_width + 2;
1718c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL,
1728c2ecf20Sopenharmony_ci					   symlen);
1738c2ecf20Sopenharmony_ci		} else {
1748c2ecf20Sopenharmony_ci			symlen = unresolved_col_width + 4 + 2;
1758c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL,
1768c2ecf20Sopenharmony_ci					   symlen);
1778c2ecf20Sopenharmony_ci		}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci		if (h->mem_info->daddr.ms.map) {
1808c2ecf20Sopenharmony_ci			symlen = dso__name_len(h->mem_info->daddr.ms.map->dso);
1818c2ecf20Sopenharmony_ci			hists__new_col_len(hists, HISTC_MEM_DADDR_DSO,
1828c2ecf20Sopenharmony_ci					   symlen);
1838c2ecf20Sopenharmony_ci		} else {
1848c2ecf20Sopenharmony_ci			symlen = unresolved_col_width + 4 + 2;
1858c2ecf20Sopenharmony_ci			hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
1868c2ecf20Sopenharmony_ci		}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_MEM_PHYS_DADDR,
1898c2ecf20Sopenharmony_ci				   unresolved_col_width + 4 + 2);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	} else {
1928c2ecf20Sopenharmony_ci		symlen = unresolved_col_width + 4 + 2;
1938c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen);
1948c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL, symlen);
1958c2ecf20Sopenharmony_ci		hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	hists__new_col_len(hists, HISTC_CGROUP, 6);
1998c2ecf20Sopenharmony_ci	hists__new_col_len(hists, HISTC_CGROUP_ID, 20);
2008c2ecf20Sopenharmony_ci	hists__new_col_len(hists, HISTC_CPU, 3);
2018c2ecf20Sopenharmony_ci	hists__new_col_len(hists, HISTC_SOCKET, 6);
2028c2ecf20Sopenharmony_ci	hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
2038c2ecf20Sopenharmony_ci	hists__new_col_len(hists, HISTC_MEM_TLB, 22);
2048c2ecf20Sopenharmony_ci	hists__new_col_len(hists, HISTC_MEM_SNOOP, 12);
2058c2ecf20Sopenharmony_ci	hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3);
2068c2ecf20Sopenharmony_ci	hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
2078c2ecf20Sopenharmony_ci	hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
2088c2ecf20Sopenharmony_ci	if (symbol_conf.nanosecs)
2098c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_TIME, 16);
2108c2ecf20Sopenharmony_ci	else
2118c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_TIME, 12);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (h->srcline) {
2148c2ecf20Sopenharmony_ci		len = MAX(strlen(h->srcline), strlen(sort_srcline.se_header));
2158c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_SRCLINE, len);
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	if (h->srcfile)
2198c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_SRCFILE, strlen(h->srcfile));
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (h->transaction)
2228c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_TRANSACTION,
2238c2ecf20Sopenharmony_ci				   hist_entry__transaction_len());
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (h->trace_output)
2268c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_TRACE, strlen(h->trace_output));
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (h->cgroup) {
2298c2ecf20Sopenharmony_ci		const char *cgrp_name = "unknown";
2308c2ecf20Sopenharmony_ci		struct cgroup *cgrp = cgroup__find(h->ms.maps->machine->env,
2318c2ecf20Sopenharmony_ci						   h->cgroup);
2328c2ecf20Sopenharmony_ci		if (cgrp != NULL)
2338c2ecf20Sopenharmony_ci			cgrp_name = cgrp->name;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci		hists__new_col_len(hists, HISTC_CGROUP, strlen(cgrp_name));
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_civoid hists__output_recalc_col_len(struct hists *hists, int max_rows)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	struct rb_node *next = rb_first_cached(&hists->entries);
2428c2ecf20Sopenharmony_ci	struct hist_entry *n;
2438c2ecf20Sopenharmony_ci	int row = 0;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	hists__reset_col_len(hists);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	while (next && row++ < max_rows) {
2488c2ecf20Sopenharmony_ci		n = rb_entry(next, struct hist_entry, rb_node);
2498c2ecf20Sopenharmony_ci		if (!n->filtered)
2508c2ecf20Sopenharmony_ci			hists__calc_col_len(hists, n);
2518c2ecf20Sopenharmony_ci		next = rb_next(&n->rb_node);
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic void he_stat__add_cpumode_period(struct he_stat *he_stat,
2568c2ecf20Sopenharmony_ci					unsigned int cpumode, u64 period)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	switch (cpumode) {
2598c2ecf20Sopenharmony_ci	case PERF_RECORD_MISC_KERNEL:
2608c2ecf20Sopenharmony_ci		he_stat->period_sys += period;
2618c2ecf20Sopenharmony_ci		break;
2628c2ecf20Sopenharmony_ci	case PERF_RECORD_MISC_USER:
2638c2ecf20Sopenharmony_ci		he_stat->period_us += period;
2648c2ecf20Sopenharmony_ci		break;
2658c2ecf20Sopenharmony_ci	case PERF_RECORD_MISC_GUEST_KERNEL:
2668c2ecf20Sopenharmony_ci		he_stat->period_guest_sys += period;
2678c2ecf20Sopenharmony_ci		break;
2688c2ecf20Sopenharmony_ci	case PERF_RECORD_MISC_GUEST_USER:
2698c2ecf20Sopenharmony_ci		he_stat->period_guest_us += period;
2708c2ecf20Sopenharmony_ci		break;
2718c2ecf20Sopenharmony_ci	default:
2728c2ecf20Sopenharmony_ci		break;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic long hist_time(unsigned long htime)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	unsigned long time_quantum = symbol_conf.time_quantum;
2798c2ecf20Sopenharmony_ci	if (time_quantum)
2808c2ecf20Sopenharmony_ci		return (htime / time_quantum) * time_quantum;
2818c2ecf20Sopenharmony_ci	return htime;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic void he_stat__add_period(struct he_stat *he_stat, u64 period,
2858c2ecf20Sopenharmony_ci				u64 weight)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	he_stat->period		+= period;
2898c2ecf20Sopenharmony_ci	he_stat->weight		+= weight;
2908c2ecf20Sopenharmony_ci	he_stat->nr_events	+= 1;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	dest->period		+= src->period;
2968c2ecf20Sopenharmony_ci	dest->period_sys	+= src->period_sys;
2978c2ecf20Sopenharmony_ci	dest->period_us		+= src->period_us;
2988c2ecf20Sopenharmony_ci	dest->period_guest_sys	+= src->period_guest_sys;
2998c2ecf20Sopenharmony_ci	dest->period_guest_us	+= src->period_guest_us;
3008c2ecf20Sopenharmony_ci	dest->nr_events		+= src->nr_events;
3018c2ecf20Sopenharmony_ci	dest->weight		+= src->weight;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic void he_stat__decay(struct he_stat *he_stat)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	he_stat->period = (he_stat->period * 7) / 8;
3078c2ecf20Sopenharmony_ci	he_stat->nr_events = (he_stat->nr_events * 7) / 8;
3088c2ecf20Sopenharmony_ci	/* XXX need decay for weight too? */
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic void hists__delete_entry(struct hists *hists, struct hist_entry *he);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	u64 prev_period = he->stat.period;
3168c2ecf20Sopenharmony_ci	u64 diff;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (prev_period == 0)
3198c2ecf20Sopenharmony_ci		return true;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	he_stat__decay(&he->stat);
3228c2ecf20Sopenharmony_ci	if (symbol_conf.cumulate_callchain)
3238c2ecf20Sopenharmony_ci		he_stat__decay(he->stat_acc);
3248c2ecf20Sopenharmony_ci	decay_callchain(he->callchain);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	diff = prev_period - he->stat.period;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (!he->depth) {
3298c2ecf20Sopenharmony_ci		hists->stats.total_period -= diff;
3308c2ecf20Sopenharmony_ci		if (!he->filtered)
3318c2ecf20Sopenharmony_ci			hists->stats.total_non_filtered_period -= diff;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (!he->leaf) {
3358c2ecf20Sopenharmony_ci		struct hist_entry *child;
3368c2ecf20Sopenharmony_ci		struct rb_node *node = rb_first_cached(&he->hroot_out);
3378c2ecf20Sopenharmony_ci		while (node) {
3388c2ecf20Sopenharmony_ci			child = rb_entry(node, struct hist_entry, rb_node);
3398c2ecf20Sopenharmony_ci			node = rb_next(node);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci			if (hists__decay_entry(hists, child))
3428c2ecf20Sopenharmony_ci				hists__delete_entry(hists, child);
3438c2ecf20Sopenharmony_ci		}
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return he->stat.period == 0;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic void hists__delete_entry(struct hists *hists, struct hist_entry *he)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct rb_root_cached *root_in;
3528c2ecf20Sopenharmony_ci	struct rb_root_cached *root_out;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	if (he->parent_he) {
3558c2ecf20Sopenharmony_ci		root_in  = &he->parent_he->hroot_in;
3568c2ecf20Sopenharmony_ci		root_out = &he->parent_he->hroot_out;
3578c2ecf20Sopenharmony_ci	} else {
3588c2ecf20Sopenharmony_ci		if (hists__has(hists, need_collapse))
3598c2ecf20Sopenharmony_ci			root_in = &hists->entries_collapsed;
3608c2ecf20Sopenharmony_ci		else
3618c2ecf20Sopenharmony_ci			root_in = hists->entries_in;
3628c2ecf20Sopenharmony_ci		root_out = &hists->entries;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	rb_erase_cached(&he->rb_node_in, root_in);
3668c2ecf20Sopenharmony_ci	rb_erase_cached(&he->rb_node, root_out);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	--hists->nr_entries;
3698c2ecf20Sopenharmony_ci	if (!he->filtered)
3708c2ecf20Sopenharmony_ci		--hists->nr_non_filtered_entries;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	hist_entry__delete(he);
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_civoid hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	struct rb_node *next = rb_first_cached(&hists->entries);
3788c2ecf20Sopenharmony_ci	struct hist_entry *n;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	while (next) {
3818c2ecf20Sopenharmony_ci		n = rb_entry(next, struct hist_entry, rb_node);
3828c2ecf20Sopenharmony_ci		next = rb_next(&n->rb_node);
3838c2ecf20Sopenharmony_ci		if (((zap_user && n->level == '.') ||
3848c2ecf20Sopenharmony_ci		     (zap_kernel && n->level != '.') ||
3858c2ecf20Sopenharmony_ci		     hists__decay_entry(hists, n))) {
3868c2ecf20Sopenharmony_ci			hists__delete_entry(hists, n);
3878c2ecf20Sopenharmony_ci		}
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_civoid hists__delete_entries(struct hists *hists)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	struct rb_node *next = rb_first_cached(&hists->entries);
3948c2ecf20Sopenharmony_ci	struct hist_entry *n;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	while (next) {
3978c2ecf20Sopenharmony_ci		n = rb_entry(next, struct hist_entry, rb_node);
3988c2ecf20Sopenharmony_ci		next = rb_next(&n->rb_node);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci		hists__delete_entry(hists, n);
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistruct hist_entry *hists__get_entry(struct hists *hists, int idx)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct rb_node *next = rb_first_cached(&hists->entries);
4078c2ecf20Sopenharmony_ci	struct hist_entry *n;
4088c2ecf20Sopenharmony_ci	int i = 0;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	while (next) {
4118c2ecf20Sopenharmony_ci		n = rb_entry(next, struct hist_entry, rb_node);
4128c2ecf20Sopenharmony_ci		if (i == idx)
4138c2ecf20Sopenharmony_ci			return n;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		next = rb_next(&n->rb_node);
4168c2ecf20Sopenharmony_ci		i++;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	return NULL;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci/*
4238c2ecf20Sopenharmony_ci * histogram, sorted on item, collects periods
4248c2ecf20Sopenharmony_ci */
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic int hist_entry__init(struct hist_entry *he,
4278c2ecf20Sopenharmony_ci			    struct hist_entry *template,
4288c2ecf20Sopenharmony_ci			    bool sample_self,
4298c2ecf20Sopenharmony_ci			    size_t callchain_size)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	*he = *template;
4328c2ecf20Sopenharmony_ci	he->callchain_size = callchain_size;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (symbol_conf.cumulate_callchain) {
4358c2ecf20Sopenharmony_ci		he->stat_acc = malloc(sizeof(he->stat));
4368c2ecf20Sopenharmony_ci		if (he->stat_acc == NULL)
4378c2ecf20Sopenharmony_ci			return -ENOMEM;
4388c2ecf20Sopenharmony_ci		memcpy(he->stat_acc, &he->stat, sizeof(he->stat));
4398c2ecf20Sopenharmony_ci		if (!sample_self)
4408c2ecf20Sopenharmony_ci			memset(&he->stat, 0, sizeof(he->stat));
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	map__get(he->ms.map);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	if (he->branch_info) {
4468c2ecf20Sopenharmony_ci		/*
4478c2ecf20Sopenharmony_ci		 * This branch info is (a part of) allocated from
4488c2ecf20Sopenharmony_ci		 * sample__resolve_bstack() and will be freed after
4498c2ecf20Sopenharmony_ci		 * adding new entries.  So we need to save a copy.
4508c2ecf20Sopenharmony_ci		 */
4518c2ecf20Sopenharmony_ci		he->branch_info = malloc(sizeof(*he->branch_info));
4528c2ecf20Sopenharmony_ci		if (he->branch_info == NULL)
4538c2ecf20Sopenharmony_ci			goto err;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci		memcpy(he->branch_info, template->branch_info,
4568c2ecf20Sopenharmony_ci		       sizeof(*he->branch_info));
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		map__get(he->branch_info->from.ms.map);
4598c2ecf20Sopenharmony_ci		map__get(he->branch_info->to.ms.map);
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	if (he->mem_info) {
4638c2ecf20Sopenharmony_ci		map__get(he->mem_info->iaddr.ms.map);
4648c2ecf20Sopenharmony_ci		map__get(he->mem_info->daddr.ms.map);
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	if (hist_entry__has_callchains(he) && symbol_conf.use_callchain)
4688c2ecf20Sopenharmony_ci		callchain_init(he->callchain);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	if (he->raw_data) {
4718c2ecf20Sopenharmony_ci		he->raw_data = memdup(he->raw_data, he->raw_size);
4728c2ecf20Sopenharmony_ci		if (he->raw_data == NULL)
4738c2ecf20Sopenharmony_ci			goto err_infos;
4748c2ecf20Sopenharmony_ci	}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	if (he->srcline) {
4778c2ecf20Sopenharmony_ci		he->srcline = strdup(he->srcline);
4788c2ecf20Sopenharmony_ci		if (he->srcline == NULL)
4798c2ecf20Sopenharmony_ci			goto err_rawdata;
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	if (symbol_conf.res_sample) {
4838c2ecf20Sopenharmony_ci		he->res_samples = calloc(sizeof(struct res_sample),
4848c2ecf20Sopenharmony_ci					symbol_conf.res_sample);
4858c2ecf20Sopenharmony_ci		if (!he->res_samples)
4868c2ecf20Sopenharmony_ci			goto err_srcline;
4878c2ecf20Sopenharmony_ci	}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&he->pairs.node);
4908c2ecf20Sopenharmony_ci	thread__get(he->thread);
4918c2ecf20Sopenharmony_ci	he->hroot_in  = RB_ROOT_CACHED;
4928c2ecf20Sopenharmony_ci	he->hroot_out = RB_ROOT_CACHED;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	if (!symbol_conf.report_hierarchy)
4958c2ecf20Sopenharmony_ci		he->leaf = true;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	return 0;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_cierr_srcline:
5008c2ecf20Sopenharmony_ci	zfree(&he->srcline);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_cierr_rawdata:
5038c2ecf20Sopenharmony_ci	zfree(&he->raw_data);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_cierr_infos:
5068c2ecf20Sopenharmony_ci	if (he->branch_info) {
5078c2ecf20Sopenharmony_ci		map__put(he->branch_info->from.ms.map);
5088c2ecf20Sopenharmony_ci		map__put(he->branch_info->to.ms.map);
5098c2ecf20Sopenharmony_ci		zfree(&he->branch_info);
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci	if (he->mem_info) {
5128c2ecf20Sopenharmony_ci		map__put(he->mem_info->iaddr.ms.map);
5138c2ecf20Sopenharmony_ci		map__put(he->mem_info->daddr.ms.map);
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_cierr:
5168c2ecf20Sopenharmony_ci	map__zput(he->ms.map);
5178c2ecf20Sopenharmony_ci	zfree(&he->stat_acc);
5188c2ecf20Sopenharmony_ci	return -ENOMEM;
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic void *hist_entry__zalloc(size_t size)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	return zalloc(size + sizeof(struct hist_entry));
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_cistatic void hist_entry__free(void *ptr)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci	free(ptr);
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistatic struct hist_entry_ops default_ops = {
5328c2ecf20Sopenharmony_ci	.new	= hist_entry__zalloc,
5338c2ecf20Sopenharmony_ci	.free	= hist_entry__free,
5348c2ecf20Sopenharmony_ci};
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_cistatic struct hist_entry *hist_entry__new(struct hist_entry *template,
5378c2ecf20Sopenharmony_ci					  bool sample_self)
5388c2ecf20Sopenharmony_ci{
5398c2ecf20Sopenharmony_ci	struct hist_entry_ops *ops = template->ops;
5408c2ecf20Sopenharmony_ci	size_t callchain_size = 0;
5418c2ecf20Sopenharmony_ci	struct hist_entry *he;
5428c2ecf20Sopenharmony_ci	int err = 0;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	if (!ops)
5458c2ecf20Sopenharmony_ci		ops = template->ops = &default_ops;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	if (symbol_conf.use_callchain)
5488c2ecf20Sopenharmony_ci		callchain_size = sizeof(struct callchain_root);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	he = ops->new(callchain_size);
5518c2ecf20Sopenharmony_ci	if (he) {
5528c2ecf20Sopenharmony_ci		err = hist_entry__init(he, template, sample_self, callchain_size);
5538c2ecf20Sopenharmony_ci		if (err) {
5548c2ecf20Sopenharmony_ci			ops->free(he);
5558c2ecf20Sopenharmony_ci			he = NULL;
5568c2ecf20Sopenharmony_ci		}
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	return he;
5608c2ecf20Sopenharmony_ci}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_cistatic u8 symbol__parent_filter(const struct symbol *parent)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	if (symbol_conf.exclude_other && parent == NULL)
5658c2ecf20Sopenharmony_ci		return 1 << HIST_FILTER__PARENT;
5668c2ecf20Sopenharmony_ci	return 0;
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_cistatic void hist_entry__add_callchain_period(struct hist_entry *he, u64 period)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	if (!hist_entry__has_callchains(he) || !symbol_conf.use_callchain)
5728c2ecf20Sopenharmony_ci		return;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	he->hists->callchain_period += period;
5758c2ecf20Sopenharmony_ci	if (!he->filtered)
5768c2ecf20Sopenharmony_ci		he->hists->callchain_non_filtered_period += period;
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_cistatic struct hist_entry *hists__findnew_entry(struct hists *hists,
5808c2ecf20Sopenharmony_ci					       struct hist_entry *entry,
5818c2ecf20Sopenharmony_ci					       struct addr_location *al,
5828c2ecf20Sopenharmony_ci					       bool sample_self)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	struct rb_node **p;
5858c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
5868c2ecf20Sopenharmony_ci	struct hist_entry *he;
5878c2ecf20Sopenharmony_ci	int64_t cmp;
5888c2ecf20Sopenharmony_ci	u64 period = entry->stat.period;
5898c2ecf20Sopenharmony_ci	u64 weight = entry->stat.weight;
5908c2ecf20Sopenharmony_ci	bool leftmost = true;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	p = &hists->entries_in->rb_root.rb_node;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	while (*p != NULL) {
5958c2ecf20Sopenharmony_ci		parent = *p;
5968c2ecf20Sopenharmony_ci		he = rb_entry(parent, struct hist_entry, rb_node_in);
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci		/*
5998c2ecf20Sopenharmony_ci		 * Make sure that it receives arguments in a same order as
6008c2ecf20Sopenharmony_ci		 * hist_entry__collapse() so that we can use an appropriate
6018c2ecf20Sopenharmony_ci		 * function when searching an entry regardless which sort
6028c2ecf20Sopenharmony_ci		 * keys were used.
6038c2ecf20Sopenharmony_ci		 */
6048c2ecf20Sopenharmony_ci		cmp = hist_entry__cmp(he, entry);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci		if (!cmp) {
6078c2ecf20Sopenharmony_ci			if (sample_self) {
6088c2ecf20Sopenharmony_ci				he_stat__add_period(&he->stat, period, weight);
6098c2ecf20Sopenharmony_ci				hist_entry__add_callchain_period(he, period);
6108c2ecf20Sopenharmony_ci			}
6118c2ecf20Sopenharmony_ci			if (symbol_conf.cumulate_callchain)
6128c2ecf20Sopenharmony_ci				he_stat__add_period(he->stat_acc, period, weight);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci			/*
6158c2ecf20Sopenharmony_ci			 * This mem info was allocated from sample__resolve_mem
6168c2ecf20Sopenharmony_ci			 * and will not be used anymore.
6178c2ecf20Sopenharmony_ci			 */
6188c2ecf20Sopenharmony_ci			mem_info__zput(entry->mem_info);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci			block_info__zput(entry->block_info);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci			/* If the map of an existing hist_entry has
6238c2ecf20Sopenharmony_ci			 * become out-of-date due to an exec() or
6248c2ecf20Sopenharmony_ci			 * similar, update it.  Otherwise we will
6258c2ecf20Sopenharmony_ci			 * mis-adjust symbol addresses when computing
6268c2ecf20Sopenharmony_ci			 * the history counter to increment.
6278c2ecf20Sopenharmony_ci			 */
6288c2ecf20Sopenharmony_ci			if (he->ms.map != entry->ms.map) {
6298c2ecf20Sopenharmony_ci				map__put(he->ms.map);
6308c2ecf20Sopenharmony_ci				he->ms.map = map__get(entry->ms.map);
6318c2ecf20Sopenharmony_ci			}
6328c2ecf20Sopenharmony_ci			goto out;
6338c2ecf20Sopenharmony_ci		}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci		if (cmp < 0)
6368c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
6378c2ecf20Sopenharmony_ci		else {
6388c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
6398c2ecf20Sopenharmony_ci			leftmost = false;
6408c2ecf20Sopenharmony_ci		}
6418c2ecf20Sopenharmony_ci	}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	he = hist_entry__new(entry, sample_self);
6448c2ecf20Sopenharmony_ci	if (!he)
6458c2ecf20Sopenharmony_ci		return NULL;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	if (sample_self)
6488c2ecf20Sopenharmony_ci		hist_entry__add_callchain_period(he, period);
6498c2ecf20Sopenharmony_ci	hists->nr_entries++;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	rb_link_node(&he->rb_node_in, parent, p);
6528c2ecf20Sopenharmony_ci	rb_insert_color_cached(&he->rb_node_in, hists->entries_in, leftmost);
6538c2ecf20Sopenharmony_ciout:
6548c2ecf20Sopenharmony_ci	if (sample_self)
6558c2ecf20Sopenharmony_ci		he_stat__add_cpumode_period(&he->stat, al->cpumode, period);
6568c2ecf20Sopenharmony_ci	if (symbol_conf.cumulate_callchain)
6578c2ecf20Sopenharmony_ci		he_stat__add_cpumode_period(he->stat_acc, al->cpumode, period);
6588c2ecf20Sopenharmony_ci	return he;
6598c2ecf20Sopenharmony_ci}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_cistatic unsigned random_max(unsigned high)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	unsigned thresh = -high % high;
6648c2ecf20Sopenharmony_ci	for (;;) {
6658c2ecf20Sopenharmony_ci		unsigned r = random();
6668c2ecf20Sopenharmony_ci		if (r >= thresh)
6678c2ecf20Sopenharmony_ci			return r % high;
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic void hists__res_sample(struct hist_entry *he, struct perf_sample *sample)
6728c2ecf20Sopenharmony_ci{
6738c2ecf20Sopenharmony_ci	struct res_sample *r;
6748c2ecf20Sopenharmony_ci	int j;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	if (he->num_res < symbol_conf.res_sample) {
6778c2ecf20Sopenharmony_ci		j = he->num_res++;
6788c2ecf20Sopenharmony_ci	} else {
6798c2ecf20Sopenharmony_ci		j = random_max(symbol_conf.res_sample);
6808c2ecf20Sopenharmony_ci	}
6818c2ecf20Sopenharmony_ci	r = &he->res_samples[j];
6828c2ecf20Sopenharmony_ci	r->time = sample->time;
6838c2ecf20Sopenharmony_ci	r->cpu = sample->cpu;
6848c2ecf20Sopenharmony_ci	r->tid = sample->tid;
6858c2ecf20Sopenharmony_ci}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_cistatic struct hist_entry*
6888c2ecf20Sopenharmony_ci__hists__add_entry(struct hists *hists,
6898c2ecf20Sopenharmony_ci		   struct addr_location *al,
6908c2ecf20Sopenharmony_ci		   struct symbol *sym_parent,
6918c2ecf20Sopenharmony_ci		   struct branch_info *bi,
6928c2ecf20Sopenharmony_ci		   struct mem_info *mi,
6938c2ecf20Sopenharmony_ci		   struct block_info *block_info,
6948c2ecf20Sopenharmony_ci		   struct perf_sample *sample,
6958c2ecf20Sopenharmony_ci		   bool sample_self,
6968c2ecf20Sopenharmony_ci		   struct hist_entry_ops *ops)
6978c2ecf20Sopenharmony_ci{
6988c2ecf20Sopenharmony_ci	struct namespaces *ns = thread__namespaces(al->thread);
6998c2ecf20Sopenharmony_ci	struct hist_entry entry = {
7008c2ecf20Sopenharmony_ci		.thread	= al->thread,
7018c2ecf20Sopenharmony_ci		.comm = thread__comm(al->thread),
7028c2ecf20Sopenharmony_ci		.cgroup_id = {
7038c2ecf20Sopenharmony_ci			.dev = ns ? ns->link_info[CGROUP_NS_INDEX].dev : 0,
7048c2ecf20Sopenharmony_ci			.ino = ns ? ns->link_info[CGROUP_NS_INDEX].ino : 0,
7058c2ecf20Sopenharmony_ci		},
7068c2ecf20Sopenharmony_ci		.cgroup = sample->cgroup,
7078c2ecf20Sopenharmony_ci		.ms = {
7088c2ecf20Sopenharmony_ci			.maps	= al->maps,
7098c2ecf20Sopenharmony_ci			.map	= al->map,
7108c2ecf20Sopenharmony_ci			.sym	= al->sym,
7118c2ecf20Sopenharmony_ci		},
7128c2ecf20Sopenharmony_ci		.srcline = (char *) al->srcline,
7138c2ecf20Sopenharmony_ci		.socket	 = al->socket,
7148c2ecf20Sopenharmony_ci		.cpu	 = al->cpu,
7158c2ecf20Sopenharmony_ci		.cpumode = al->cpumode,
7168c2ecf20Sopenharmony_ci		.ip	 = al->addr,
7178c2ecf20Sopenharmony_ci		.level	 = al->level,
7188c2ecf20Sopenharmony_ci		.stat = {
7198c2ecf20Sopenharmony_ci			.nr_events = 1,
7208c2ecf20Sopenharmony_ci			.period	= sample->period,
7218c2ecf20Sopenharmony_ci			.weight = sample->weight,
7228c2ecf20Sopenharmony_ci		},
7238c2ecf20Sopenharmony_ci		.parent = sym_parent,
7248c2ecf20Sopenharmony_ci		.filtered = symbol__parent_filter(sym_parent) | al->filtered,
7258c2ecf20Sopenharmony_ci		.hists	= hists,
7268c2ecf20Sopenharmony_ci		.branch_info = bi,
7278c2ecf20Sopenharmony_ci		.mem_info = mi,
7288c2ecf20Sopenharmony_ci		.block_info = block_info,
7298c2ecf20Sopenharmony_ci		.transaction = sample->transaction,
7308c2ecf20Sopenharmony_ci		.raw_data = sample->raw_data,
7318c2ecf20Sopenharmony_ci		.raw_size = sample->raw_size,
7328c2ecf20Sopenharmony_ci		.ops = ops,
7338c2ecf20Sopenharmony_ci		.time = hist_time(sample->time),
7348c2ecf20Sopenharmony_ci	}, *he = hists__findnew_entry(hists, &entry, al, sample_self);
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	if (!hists->has_callchains && he && he->callchain_size != 0)
7378c2ecf20Sopenharmony_ci		hists->has_callchains = true;
7388c2ecf20Sopenharmony_ci	if (he && symbol_conf.res_sample)
7398c2ecf20Sopenharmony_ci		hists__res_sample(he, sample);
7408c2ecf20Sopenharmony_ci	return he;
7418c2ecf20Sopenharmony_ci}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_cistruct hist_entry *hists__add_entry(struct hists *hists,
7448c2ecf20Sopenharmony_ci				    struct addr_location *al,
7458c2ecf20Sopenharmony_ci				    struct symbol *sym_parent,
7468c2ecf20Sopenharmony_ci				    struct branch_info *bi,
7478c2ecf20Sopenharmony_ci				    struct mem_info *mi,
7488c2ecf20Sopenharmony_ci				    struct perf_sample *sample,
7498c2ecf20Sopenharmony_ci				    bool sample_self)
7508c2ecf20Sopenharmony_ci{
7518c2ecf20Sopenharmony_ci	return __hists__add_entry(hists, al, sym_parent, bi, mi, NULL,
7528c2ecf20Sopenharmony_ci				  sample, sample_self, NULL);
7538c2ecf20Sopenharmony_ci}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cistruct hist_entry *hists__add_entry_ops(struct hists *hists,
7568c2ecf20Sopenharmony_ci					struct hist_entry_ops *ops,
7578c2ecf20Sopenharmony_ci					struct addr_location *al,
7588c2ecf20Sopenharmony_ci					struct symbol *sym_parent,
7598c2ecf20Sopenharmony_ci					struct branch_info *bi,
7608c2ecf20Sopenharmony_ci					struct mem_info *mi,
7618c2ecf20Sopenharmony_ci					struct perf_sample *sample,
7628c2ecf20Sopenharmony_ci					bool sample_self)
7638c2ecf20Sopenharmony_ci{
7648c2ecf20Sopenharmony_ci	return __hists__add_entry(hists, al, sym_parent, bi, mi, NULL,
7658c2ecf20Sopenharmony_ci				  sample, sample_self, ops);
7668c2ecf20Sopenharmony_ci}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_cistruct hist_entry *hists__add_entry_block(struct hists *hists,
7698c2ecf20Sopenharmony_ci					  struct addr_location *al,
7708c2ecf20Sopenharmony_ci					  struct block_info *block_info)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	struct hist_entry entry = {
7738c2ecf20Sopenharmony_ci		.block_info = block_info,
7748c2ecf20Sopenharmony_ci		.hists = hists,
7758c2ecf20Sopenharmony_ci		.ms = {
7768c2ecf20Sopenharmony_ci			.maps = al->maps,
7778c2ecf20Sopenharmony_ci			.map = al->map,
7788c2ecf20Sopenharmony_ci			.sym = al->sym,
7798c2ecf20Sopenharmony_ci		},
7808c2ecf20Sopenharmony_ci	}, *he = hists__findnew_entry(hists, &entry, al, false);
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	return he;
7838c2ecf20Sopenharmony_ci}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_cistatic int
7868c2ecf20Sopenharmony_ciiter_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
7878c2ecf20Sopenharmony_ci		    struct addr_location *al __maybe_unused)
7888c2ecf20Sopenharmony_ci{
7898c2ecf20Sopenharmony_ci	return 0;
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_cistatic int
7938c2ecf20Sopenharmony_ciiter_add_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
7948c2ecf20Sopenharmony_ci			struct addr_location *al __maybe_unused)
7958c2ecf20Sopenharmony_ci{
7968c2ecf20Sopenharmony_ci	return 0;
7978c2ecf20Sopenharmony_ci}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_cistatic int
8008c2ecf20Sopenharmony_ciiter_prepare_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	struct perf_sample *sample = iter->sample;
8038c2ecf20Sopenharmony_ci	struct mem_info *mi;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	mi = sample__resolve_mem(sample, al);
8068c2ecf20Sopenharmony_ci	if (mi == NULL)
8078c2ecf20Sopenharmony_ci		return -ENOMEM;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	iter->priv = mi;
8108c2ecf20Sopenharmony_ci	return 0;
8118c2ecf20Sopenharmony_ci}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_cistatic int
8148c2ecf20Sopenharmony_ciiter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	u64 cost;
8178c2ecf20Sopenharmony_ci	struct mem_info *mi = iter->priv;
8188c2ecf20Sopenharmony_ci	struct hists *hists = evsel__hists(iter->evsel);
8198c2ecf20Sopenharmony_ci	struct perf_sample *sample = iter->sample;
8208c2ecf20Sopenharmony_ci	struct hist_entry *he;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	if (mi == NULL)
8238c2ecf20Sopenharmony_ci		return -EINVAL;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	cost = sample->weight;
8268c2ecf20Sopenharmony_ci	if (!cost)
8278c2ecf20Sopenharmony_ci		cost = 1;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	/*
8308c2ecf20Sopenharmony_ci	 * must pass period=weight in order to get the correct
8318c2ecf20Sopenharmony_ci	 * sorting from hists__collapse_resort() which is solely
8328c2ecf20Sopenharmony_ci	 * based on periods. We want sorting be done on nr_events * weight
8338c2ecf20Sopenharmony_ci	 * and this is indirectly achieved by passing period=weight here
8348c2ecf20Sopenharmony_ci	 * and the he_stat__add_period() function.
8358c2ecf20Sopenharmony_ci	 */
8368c2ecf20Sopenharmony_ci	sample->period = cost;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	he = hists__add_entry(hists, al, iter->parent, NULL, mi,
8398c2ecf20Sopenharmony_ci			      sample, true);
8408c2ecf20Sopenharmony_ci	if (!he)
8418c2ecf20Sopenharmony_ci		return -ENOMEM;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	iter->he = he;
8448c2ecf20Sopenharmony_ci	return 0;
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_cistatic int
8488c2ecf20Sopenharmony_ciiter_finish_mem_entry(struct hist_entry_iter *iter,
8498c2ecf20Sopenharmony_ci		      struct addr_location *al __maybe_unused)
8508c2ecf20Sopenharmony_ci{
8518c2ecf20Sopenharmony_ci	struct evsel *evsel = iter->evsel;
8528c2ecf20Sopenharmony_ci	struct hists *hists = evsel__hists(evsel);
8538c2ecf20Sopenharmony_ci	struct hist_entry *he = iter->he;
8548c2ecf20Sopenharmony_ci	int err = -EINVAL;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	if (he == NULL)
8578c2ecf20Sopenharmony_ci		goto out;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	hists__inc_nr_samples(hists, he->filtered);
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	err = hist_entry__append_callchain(he, iter->sample);
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ciout:
8648c2ecf20Sopenharmony_ci	/*
8658c2ecf20Sopenharmony_ci	 * We don't need to free iter->priv (mem_info) here since the mem info
8668c2ecf20Sopenharmony_ci	 * was either already freed in hists__findnew_entry() or passed to a
8678c2ecf20Sopenharmony_ci	 * new hist entry by hist_entry__new().
8688c2ecf20Sopenharmony_ci	 */
8698c2ecf20Sopenharmony_ci	iter->priv = NULL;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	iter->he = NULL;
8728c2ecf20Sopenharmony_ci	return err;
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_cistatic int
8768c2ecf20Sopenharmony_ciiter_prepare_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	struct branch_info *bi;
8798c2ecf20Sopenharmony_ci	struct perf_sample *sample = iter->sample;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	bi = sample__resolve_bstack(sample, al);
8828c2ecf20Sopenharmony_ci	if (!bi)
8838c2ecf20Sopenharmony_ci		return -ENOMEM;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	iter->curr = 0;
8868c2ecf20Sopenharmony_ci	iter->total = sample->branch_stack->nr;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	iter->priv = bi;
8898c2ecf20Sopenharmony_ci	return 0;
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_cistatic int
8938c2ecf20Sopenharmony_ciiter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused,
8948c2ecf20Sopenharmony_ci			     struct addr_location *al __maybe_unused)
8958c2ecf20Sopenharmony_ci{
8968c2ecf20Sopenharmony_ci	return 0;
8978c2ecf20Sopenharmony_ci}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_cistatic int
9008c2ecf20Sopenharmony_ciiter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
9018c2ecf20Sopenharmony_ci{
9028c2ecf20Sopenharmony_ci	struct branch_info *bi = iter->priv;
9038c2ecf20Sopenharmony_ci	int i = iter->curr;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	if (bi == NULL)
9068c2ecf20Sopenharmony_ci		return 0;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	if (iter->curr >= iter->total)
9098c2ecf20Sopenharmony_ci		return 0;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	al->maps = bi[i].to.ms.maps;
9128c2ecf20Sopenharmony_ci	al->map = bi[i].to.ms.map;
9138c2ecf20Sopenharmony_ci	al->sym = bi[i].to.ms.sym;
9148c2ecf20Sopenharmony_ci	al->addr = bi[i].to.addr;
9158c2ecf20Sopenharmony_ci	return 1;
9168c2ecf20Sopenharmony_ci}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_cistatic int
9198c2ecf20Sopenharmony_ciiter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
9208c2ecf20Sopenharmony_ci{
9218c2ecf20Sopenharmony_ci	struct branch_info *bi;
9228c2ecf20Sopenharmony_ci	struct evsel *evsel = iter->evsel;
9238c2ecf20Sopenharmony_ci	struct hists *hists = evsel__hists(evsel);
9248c2ecf20Sopenharmony_ci	struct perf_sample *sample = iter->sample;
9258c2ecf20Sopenharmony_ci	struct hist_entry *he = NULL;
9268c2ecf20Sopenharmony_ci	int i = iter->curr;
9278c2ecf20Sopenharmony_ci	int err = 0;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	bi = iter->priv;
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	if (iter->hide_unresolved && !(bi[i].from.ms.sym && bi[i].to.ms.sym))
9328c2ecf20Sopenharmony_ci		goto out;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	/*
9358c2ecf20Sopenharmony_ci	 * The report shows the percentage of total branches captured
9368c2ecf20Sopenharmony_ci	 * and not events sampled. Thus we use a pseudo period of 1.
9378c2ecf20Sopenharmony_ci	 */
9388c2ecf20Sopenharmony_ci	sample->period = 1;
9398c2ecf20Sopenharmony_ci	sample->weight = bi->flags.cycles ? bi->flags.cycles : 1;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	he = hists__add_entry(hists, al, iter->parent, &bi[i], NULL,
9428c2ecf20Sopenharmony_ci			      sample, true);
9438c2ecf20Sopenharmony_ci	if (he == NULL)
9448c2ecf20Sopenharmony_ci		return -ENOMEM;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	hists__inc_nr_samples(hists, he->filtered);
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ciout:
9498c2ecf20Sopenharmony_ci	iter->he = he;
9508c2ecf20Sopenharmony_ci	iter->curr++;
9518c2ecf20Sopenharmony_ci	return err;
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_cistatic int
9558c2ecf20Sopenharmony_ciiter_finish_branch_entry(struct hist_entry_iter *iter,
9568c2ecf20Sopenharmony_ci			 struct addr_location *al __maybe_unused)
9578c2ecf20Sopenharmony_ci{
9588c2ecf20Sopenharmony_ci	zfree(&iter->priv);
9598c2ecf20Sopenharmony_ci	iter->he = NULL;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	return iter->curr >= iter->total ? 0 : -1;
9628c2ecf20Sopenharmony_ci}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_cistatic int
9658c2ecf20Sopenharmony_ciiter_prepare_normal_entry(struct hist_entry_iter *iter __maybe_unused,
9668c2ecf20Sopenharmony_ci			  struct addr_location *al __maybe_unused)
9678c2ecf20Sopenharmony_ci{
9688c2ecf20Sopenharmony_ci	return 0;
9698c2ecf20Sopenharmony_ci}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_cistatic int
9728c2ecf20Sopenharmony_ciiter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location *al)
9738c2ecf20Sopenharmony_ci{
9748c2ecf20Sopenharmony_ci	struct evsel *evsel = iter->evsel;
9758c2ecf20Sopenharmony_ci	struct perf_sample *sample = iter->sample;
9768c2ecf20Sopenharmony_ci	struct hist_entry *he;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
9798c2ecf20Sopenharmony_ci			      sample, true);
9808c2ecf20Sopenharmony_ci	if (he == NULL)
9818c2ecf20Sopenharmony_ci		return -ENOMEM;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	iter->he = he;
9848c2ecf20Sopenharmony_ci	return 0;
9858c2ecf20Sopenharmony_ci}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_cistatic int
9888c2ecf20Sopenharmony_ciiter_finish_normal_entry(struct hist_entry_iter *iter,
9898c2ecf20Sopenharmony_ci			 struct addr_location *al __maybe_unused)
9908c2ecf20Sopenharmony_ci{
9918c2ecf20Sopenharmony_ci	struct hist_entry *he = iter->he;
9928c2ecf20Sopenharmony_ci	struct evsel *evsel = iter->evsel;
9938c2ecf20Sopenharmony_ci	struct perf_sample *sample = iter->sample;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	if (he == NULL)
9968c2ecf20Sopenharmony_ci		return 0;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	iter->he = NULL;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	hists__inc_nr_samples(evsel__hists(evsel), he->filtered);
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	return hist_entry__append_callchain(he, sample);
10038c2ecf20Sopenharmony_ci}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_cistatic int
10068c2ecf20Sopenharmony_ciiter_prepare_cumulative_entry(struct hist_entry_iter *iter,
10078c2ecf20Sopenharmony_ci			      struct addr_location *al __maybe_unused)
10088c2ecf20Sopenharmony_ci{
10098c2ecf20Sopenharmony_ci	struct hist_entry **he_cache;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	callchain_cursor_commit(&callchain_cursor);
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	/*
10148c2ecf20Sopenharmony_ci	 * This is for detecting cycles or recursions so that they're
10158c2ecf20Sopenharmony_ci	 * cumulated only one time to prevent entries more than 100%
10168c2ecf20Sopenharmony_ci	 * overhead.
10178c2ecf20Sopenharmony_ci	 */
10188c2ecf20Sopenharmony_ci	he_cache = malloc(sizeof(*he_cache) * (callchain_cursor.nr + 1));
10198c2ecf20Sopenharmony_ci	if (he_cache == NULL)
10208c2ecf20Sopenharmony_ci		return -ENOMEM;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	iter->priv = he_cache;
10238c2ecf20Sopenharmony_ci	iter->curr = 0;
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	return 0;
10268c2ecf20Sopenharmony_ci}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_cistatic int
10298c2ecf20Sopenharmony_ciiter_add_single_cumulative_entry(struct hist_entry_iter *iter,
10308c2ecf20Sopenharmony_ci				 struct addr_location *al)
10318c2ecf20Sopenharmony_ci{
10328c2ecf20Sopenharmony_ci	struct evsel *evsel = iter->evsel;
10338c2ecf20Sopenharmony_ci	struct hists *hists = evsel__hists(evsel);
10348c2ecf20Sopenharmony_ci	struct perf_sample *sample = iter->sample;
10358c2ecf20Sopenharmony_ci	struct hist_entry **he_cache = iter->priv;
10368c2ecf20Sopenharmony_ci	struct hist_entry *he;
10378c2ecf20Sopenharmony_ci	int err = 0;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	he = hists__add_entry(hists, al, iter->parent, NULL, NULL,
10408c2ecf20Sopenharmony_ci			      sample, true);
10418c2ecf20Sopenharmony_ci	if (he == NULL)
10428c2ecf20Sopenharmony_ci		return -ENOMEM;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	iter->he = he;
10458c2ecf20Sopenharmony_ci	he_cache[iter->curr++] = he;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	hist_entry__append_callchain(he, sample);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	/*
10508c2ecf20Sopenharmony_ci	 * We need to re-initialize the cursor since callchain_append()
10518c2ecf20Sopenharmony_ci	 * advanced the cursor to the end.
10528c2ecf20Sopenharmony_ci	 */
10538c2ecf20Sopenharmony_ci	callchain_cursor_commit(&callchain_cursor);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	hists__inc_nr_samples(hists, he->filtered);
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	return err;
10588c2ecf20Sopenharmony_ci}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_cistatic int
10618c2ecf20Sopenharmony_ciiter_next_cumulative_entry(struct hist_entry_iter *iter,
10628c2ecf20Sopenharmony_ci			   struct addr_location *al)
10638c2ecf20Sopenharmony_ci{
10648c2ecf20Sopenharmony_ci	struct callchain_cursor_node *node;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	node = callchain_cursor_current(&callchain_cursor);
10678c2ecf20Sopenharmony_ci	if (node == NULL)
10688c2ecf20Sopenharmony_ci		return 0;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	return fill_callchain_info(al, node, iter->hide_unresolved);
10718c2ecf20Sopenharmony_ci}
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_cistatic bool
10748c2ecf20Sopenharmony_cihist_entry__fast__sym_diff(struct hist_entry *left,
10758c2ecf20Sopenharmony_ci			   struct hist_entry *right)
10768c2ecf20Sopenharmony_ci{
10778c2ecf20Sopenharmony_ci	struct symbol *sym_l = left->ms.sym;
10788c2ecf20Sopenharmony_ci	struct symbol *sym_r = right->ms.sym;
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	if (!sym_l && !sym_r)
10818c2ecf20Sopenharmony_ci		return left->ip != right->ip;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	return !!_sort__sym_cmp(sym_l, sym_r);
10848c2ecf20Sopenharmony_ci}
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_cistatic int
10888c2ecf20Sopenharmony_ciiter_add_next_cumulative_entry(struct hist_entry_iter *iter,
10898c2ecf20Sopenharmony_ci			       struct addr_location *al)
10908c2ecf20Sopenharmony_ci{
10918c2ecf20Sopenharmony_ci	struct evsel *evsel = iter->evsel;
10928c2ecf20Sopenharmony_ci	struct perf_sample *sample = iter->sample;
10938c2ecf20Sopenharmony_ci	struct hist_entry **he_cache = iter->priv;
10948c2ecf20Sopenharmony_ci	struct hist_entry *he;
10958c2ecf20Sopenharmony_ci	struct hist_entry he_tmp = {
10968c2ecf20Sopenharmony_ci		.hists = evsel__hists(evsel),
10978c2ecf20Sopenharmony_ci		.cpu = al->cpu,
10988c2ecf20Sopenharmony_ci		.thread = al->thread,
10998c2ecf20Sopenharmony_ci		.comm = thread__comm(al->thread),
11008c2ecf20Sopenharmony_ci		.ip = al->addr,
11018c2ecf20Sopenharmony_ci		.ms = {
11028c2ecf20Sopenharmony_ci			.maps = al->maps,
11038c2ecf20Sopenharmony_ci			.map = al->map,
11048c2ecf20Sopenharmony_ci			.sym = al->sym,
11058c2ecf20Sopenharmony_ci		},
11068c2ecf20Sopenharmony_ci		.srcline = (char *) al->srcline,
11078c2ecf20Sopenharmony_ci		.parent = iter->parent,
11088c2ecf20Sopenharmony_ci		.raw_data = sample->raw_data,
11098c2ecf20Sopenharmony_ci		.raw_size = sample->raw_size,
11108c2ecf20Sopenharmony_ci	};
11118c2ecf20Sopenharmony_ci	int i;
11128c2ecf20Sopenharmony_ci	struct callchain_cursor cursor;
11138c2ecf20Sopenharmony_ci	bool fast = hists__has(he_tmp.hists, sym);
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	callchain_cursor_snapshot(&cursor, &callchain_cursor);
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	callchain_cursor_advance(&callchain_cursor);
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	/*
11208c2ecf20Sopenharmony_ci	 * Check if there's duplicate entries in the callchain.
11218c2ecf20Sopenharmony_ci	 * It's possible that it has cycles or recursive calls.
11228c2ecf20Sopenharmony_ci	 */
11238c2ecf20Sopenharmony_ci	for (i = 0; i < iter->curr; i++) {
11248c2ecf20Sopenharmony_ci		/*
11258c2ecf20Sopenharmony_ci		 * For most cases, there are no duplicate entries in callchain.
11268c2ecf20Sopenharmony_ci		 * The symbols are usually different. Do a quick check for
11278c2ecf20Sopenharmony_ci		 * symbols first.
11288c2ecf20Sopenharmony_ci		 */
11298c2ecf20Sopenharmony_ci		if (fast && hist_entry__fast__sym_diff(he_cache[i], &he_tmp))
11308c2ecf20Sopenharmony_ci			continue;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci		if (hist_entry__cmp(he_cache[i], &he_tmp) == 0) {
11338c2ecf20Sopenharmony_ci			/* to avoid calling callback function */
11348c2ecf20Sopenharmony_ci			iter->he = NULL;
11358c2ecf20Sopenharmony_ci			return 0;
11368c2ecf20Sopenharmony_ci		}
11378c2ecf20Sopenharmony_ci	}
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
11408c2ecf20Sopenharmony_ci			      sample, false);
11418c2ecf20Sopenharmony_ci	if (he == NULL)
11428c2ecf20Sopenharmony_ci		return -ENOMEM;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	iter->he = he;
11458c2ecf20Sopenharmony_ci	he_cache[iter->curr++] = he;
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	if (hist_entry__has_callchains(he) && symbol_conf.use_callchain)
11488c2ecf20Sopenharmony_ci		callchain_append(he->callchain, &cursor, sample->period);
11498c2ecf20Sopenharmony_ci	return 0;
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_cistatic int
11538c2ecf20Sopenharmony_ciiter_finish_cumulative_entry(struct hist_entry_iter *iter,
11548c2ecf20Sopenharmony_ci			     struct addr_location *al __maybe_unused)
11558c2ecf20Sopenharmony_ci{
11568c2ecf20Sopenharmony_ci	zfree(&iter->priv);
11578c2ecf20Sopenharmony_ci	iter->he = NULL;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	return 0;
11608c2ecf20Sopenharmony_ci}
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ciconst struct hist_iter_ops hist_iter_mem = {
11638c2ecf20Sopenharmony_ci	.prepare_entry 		= iter_prepare_mem_entry,
11648c2ecf20Sopenharmony_ci	.add_single_entry 	= iter_add_single_mem_entry,
11658c2ecf20Sopenharmony_ci	.next_entry 		= iter_next_nop_entry,
11668c2ecf20Sopenharmony_ci	.add_next_entry 	= iter_add_next_nop_entry,
11678c2ecf20Sopenharmony_ci	.finish_entry 		= iter_finish_mem_entry,
11688c2ecf20Sopenharmony_ci};
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ciconst struct hist_iter_ops hist_iter_branch = {
11718c2ecf20Sopenharmony_ci	.prepare_entry 		= iter_prepare_branch_entry,
11728c2ecf20Sopenharmony_ci	.add_single_entry 	= iter_add_single_branch_entry,
11738c2ecf20Sopenharmony_ci	.next_entry 		= iter_next_branch_entry,
11748c2ecf20Sopenharmony_ci	.add_next_entry 	= iter_add_next_branch_entry,
11758c2ecf20Sopenharmony_ci	.finish_entry 		= iter_finish_branch_entry,
11768c2ecf20Sopenharmony_ci};
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ciconst struct hist_iter_ops hist_iter_normal = {
11798c2ecf20Sopenharmony_ci	.prepare_entry 		= iter_prepare_normal_entry,
11808c2ecf20Sopenharmony_ci	.add_single_entry 	= iter_add_single_normal_entry,
11818c2ecf20Sopenharmony_ci	.next_entry 		= iter_next_nop_entry,
11828c2ecf20Sopenharmony_ci	.add_next_entry 	= iter_add_next_nop_entry,
11838c2ecf20Sopenharmony_ci	.finish_entry 		= iter_finish_normal_entry,
11848c2ecf20Sopenharmony_ci};
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ciconst struct hist_iter_ops hist_iter_cumulative = {
11878c2ecf20Sopenharmony_ci	.prepare_entry 		= iter_prepare_cumulative_entry,
11888c2ecf20Sopenharmony_ci	.add_single_entry 	= iter_add_single_cumulative_entry,
11898c2ecf20Sopenharmony_ci	.next_entry 		= iter_next_cumulative_entry,
11908c2ecf20Sopenharmony_ci	.add_next_entry 	= iter_add_next_cumulative_entry,
11918c2ecf20Sopenharmony_ci	.finish_entry 		= iter_finish_cumulative_entry,
11928c2ecf20Sopenharmony_ci};
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ciint hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
11958c2ecf20Sopenharmony_ci			 int max_stack_depth, void *arg)
11968c2ecf20Sopenharmony_ci{
11978c2ecf20Sopenharmony_ci	int err, err2;
11988c2ecf20Sopenharmony_ci	struct map *alm = NULL;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	if (al)
12018c2ecf20Sopenharmony_ci		alm = map__get(al->map);
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent,
12048c2ecf20Sopenharmony_ci					iter->evsel, al, max_stack_depth);
12058c2ecf20Sopenharmony_ci	if (err) {
12068c2ecf20Sopenharmony_ci		map__put(alm);
12078c2ecf20Sopenharmony_ci		return err;
12088c2ecf20Sopenharmony_ci	}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	err = iter->ops->prepare_entry(iter, al);
12118c2ecf20Sopenharmony_ci	if (err)
12128c2ecf20Sopenharmony_ci		goto out;
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	err = iter->ops->add_single_entry(iter, al);
12158c2ecf20Sopenharmony_ci	if (err)
12168c2ecf20Sopenharmony_ci		goto out;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	if (iter->he && iter->add_entry_cb) {
12198c2ecf20Sopenharmony_ci		err = iter->add_entry_cb(iter, al, true, arg);
12208c2ecf20Sopenharmony_ci		if (err)
12218c2ecf20Sopenharmony_ci			goto out;
12228c2ecf20Sopenharmony_ci	}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	while (iter->ops->next_entry(iter, al)) {
12258c2ecf20Sopenharmony_ci		err = iter->ops->add_next_entry(iter, al);
12268c2ecf20Sopenharmony_ci		if (err)
12278c2ecf20Sopenharmony_ci			break;
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci		if (iter->he && iter->add_entry_cb) {
12308c2ecf20Sopenharmony_ci			err = iter->add_entry_cb(iter, al, false, arg);
12318c2ecf20Sopenharmony_ci			if (err)
12328c2ecf20Sopenharmony_ci				goto out;
12338c2ecf20Sopenharmony_ci		}
12348c2ecf20Sopenharmony_ci	}
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ciout:
12378c2ecf20Sopenharmony_ci	err2 = iter->ops->finish_entry(iter, al);
12388c2ecf20Sopenharmony_ci	if (!err)
12398c2ecf20Sopenharmony_ci		err = err2;
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	map__put(alm);
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	return err;
12448c2ecf20Sopenharmony_ci}
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ciint64_t
12478c2ecf20Sopenharmony_cihist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	struct hists *hists = left->hists;
12508c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
12518c2ecf20Sopenharmony_ci	int64_t cmp = 0;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	hists__for_each_sort_list(hists, fmt) {
12548c2ecf20Sopenharmony_ci		if (perf_hpp__is_dynamic_entry(fmt) &&
12558c2ecf20Sopenharmony_ci		    !perf_hpp__defined_dynamic_entry(fmt, hists))
12568c2ecf20Sopenharmony_ci			continue;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci		cmp = fmt->cmp(fmt, left, right);
12598c2ecf20Sopenharmony_ci		if (cmp)
12608c2ecf20Sopenharmony_ci			break;
12618c2ecf20Sopenharmony_ci	}
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	return cmp;
12648c2ecf20Sopenharmony_ci}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ciint64_t
12678c2ecf20Sopenharmony_cihist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
12688c2ecf20Sopenharmony_ci{
12698c2ecf20Sopenharmony_ci	struct hists *hists = left->hists;
12708c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
12718c2ecf20Sopenharmony_ci	int64_t cmp = 0;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	hists__for_each_sort_list(hists, fmt) {
12748c2ecf20Sopenharmony_ci		if (perf_hpp__is_dynamic_entry(fmt) &&
12758c2ecf20Sopenharmony_ci		    !perf_hpp__defined_dynamic_entry(fmt, hists))
12768c2ecf20Sopenharmony_ci			continue;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci		cmp = fmt->collapse(fmt, left, right);
12798c2ecf20Sopenharmony_ci		if (cmp)
12808c2ecf20Sopenharmony_ci			break;
12818c2ecf20Sopenharmony_ci	}
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	return cmp;
12848c2ecf20Sopenharmony_ci}
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_civoid hist_entry__delete(struct hist_entry *he)
12878c2ecf20Sopenharmony_ci{
12888c2ecf20Sopenharmony_ci	struct hist_entry_ops *ops = he->ops;
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	thread__zput(he->thread);
12918c2ecf20Sopenharmony_ci	map__zput(he->ms.map);
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	if (he->branch_info) {
12948c2ecf20Sopenharmony_ci		map__zput(he->branch_info->from.ms.map);
12958c2ecf20Sopenharmony_ci		map__zput(he->branch_info->to.ms.map);
12968c2ecf20Sopenharmony_ci		free_srcline(he->branch_info->srcline_from);
12978c2ecf20Sopenharmony_ci		free_srcline(he->branch_info->srcline_to);
12988c2ecf20Sopenharmony_ci		zfree(&he->branch_info);
12998c2ecf20Sopenharmony_ci	}
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	if (he->mem_info) {
13028c2ecf20Sopenharmony_ci		map__zput(he->mem_info->iaddr.ms.map);
13038c2ecf20Sopenharmony_ci		map__zput(he->mem_info->daddr.ms.map);
13048c2ecf20Sopenharmony_ci		mem_info__zput(he->mem_info);
13058c2ecf20Sopenharmony_ci	}
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	if (he->block_info)
13088c2ecf20Sopenharmony_ci		block_info__zput(he->block_info);
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	zfree(&he->res_samples);
13118c2ecf20Sopenharmony_ci	zfree(&he->stat_acc);
13128c2ecf20Sopenharmony_ci	free_srcline(he->srcline);
13138c2ecf20Sopenharmony_ci	if (he->srcfile && he->srcfile[0])
13148c2ecf20Sopenharmony_ci		zfree(&he->srcfile);
13158c2ecf20Sopenharmony_ci	free_callchain(he->callchain);
13168c2ecf20Sopenharmony_ci	zfree(&he->trace_output);
13178c2ecf20Sopenharmony_ci	zfree(&he->raw_data);
13188c2ecf20Sopenharmony_ci	ops->free(he);
13198c2ecf20Sopenharmony_ci}
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci/*
13228c2ecf20Sopenharmony_ci * If this is not the last column, then we need to pad it according to the
13238c2ecf20Sopenharmony_ci * pre-calculated max length for this column, otherwise don't bother adding
13248c2ecf20Sopenharmony_ci * spaces because that would break viewing this with, for instance, 'less',
13258c2ecf20Sopenharmony_ci * that would show tons of trailing spaces when a long C++ demangled method
13268c2ecf20Sopenharmony_ci * names is sampled.
13278c2ecf20Sopenharmony_ci*/
13288c2ecf20Sopenharmony_ciint hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp,
13298c2ecf20Sopenharmony_ci				   struct perf_hpp_fmt *fmt, int printed)
13308c2ecf20Sopenharmony_ci{
13318c2ecf20Sopenharmony_ci	if (!list_is_last(&fmt->list, &he->hists->hpp_list->fields)) {
13328c2ecf20Sopenharmony_ci		const int width = fmt->width(fmt, hpp, he->hists);
13338c2ecf20Sopenharmony_ci		if (printed < width) {
13348c2ecf20Sopenharmony_ci			advance_hpp(hpp, printed);
13358c2ecf20Sopenharmony_ci			printed = scnprintf(hpp->buf, hpp->size, "%-*s", width - printed, " ");
13368c2ecf20Sopenharmony_ci		}
13378c2ecf20Sopenharmony_ci	}
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	return printed;
13408c2ecf20Sopenharmony_ci}
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci/*
13438c2ecf20Sopenharmony_ci * collapse the histogram
13448c2ecf20Sopenharmony_ci */
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_cistatic void hists__apply_filters(struct hists *hists, struct hist_entry *he);
13478c2ecf20Sopenharmony_cistatic void hists__remove_entry_filter(struct hists *hists, struct hist_entry *he,
13488c2ecf20Sopenharmony_ci				       enum hist_filter type);
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_citypedef bool (*fmt_chk_fn)(struct perf_hpp_fmt *fmt);
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_cistatic bool check_thread_entry(struct perf_hpp_fmt *fmt)
13538c2ecf20Sopenharmony_ci{
13548c2ecf20Sopenharmony_ci	return perf_hpp__is_thread_entry(fmt) || perf_hpp__is_comm_entry(fmt);
13558c2ecf20Sopenharmony_ci}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_cistatic void hist_entry__check_and_remove_filter(struct hist_entry *he,
13588c2ecf20Sopenharmony_ci						enum hist_filter type,
13598c2ecf20Sopenharmony_ci						fmt_chk_fn check)
13608c2ecf20Sopenharmony_ci{
13618c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
13628c2ecf20Sopenharmony_ci	bool type_match = false;
13638c2ecf20Sopenharmony_ci	struct hist_entry *parent = he->parent_he;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	switch (type) {
13668c2ecf20Sopenharmony_ci	case HIST_FILTER__THREAD:
13678c2ecf20Sopenharmony_ci		if (symbol_conf.comm_list == NULL &&
13688c2ecf20Sopenharmony_ci		    symbol_conf.pid_list == NULL &&
13698c2ecf20Sopenharmony_ci		    symbol_conf.tid_list == NULL)
13708c2ecf20Sopenharmony_ci			return;
13718c2ecf20Sopenharmony_ci		break;
13728c2ecf20Sopenharmony_ci	case HIST_FILTER__DSO:
13738c2ecf20Sopenharmony_ci		if (symbol_conf.dso_list == NULL)
13748c2ecf20Sopenharmony_ci			return;
13758c2ecf20Sopenharmony_ci		break;
13768c2ecf20Sopenharmony_ci	case HIST_FILTER__SYMBOL:
13778c2ecf20Sopenharmony_ci		if (symbol_conf.sym_list == NULL)
13788c2ecf20Sopenharmony_ci			return;
13798c2ecf20Sopenharmony_ci		break;
13808c2ecf20Sopenharmony_ci	case HIST_FILTER__PARENT:
13818c2ecf20Sopenharmony_ci	case HIST_FILTER__GUEST:
13828c2ecf20Sopenharmony_ci	case HIST_FILTER__HOST:
13838c2ecf20Sopenharmony_ci	case HIST_FILTER__SOCKET:
13848c2ecf20Sopenharmony_ci	case HIST_FILTER__C2C:
13858c2ecf20Sopenharmony_ci	default:
13868c2ecf20Sopenharmony_ci		return;
13878c2ecf20Sopenharmony_ci	}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	/* if it's filtered by own fmt, it has to have filter bits */
13908c2ecf20Sopenharmony_ci	perf_hpp_list__for_each_format(he->hpp_list, fmt) {
13918c2ecf20Sopenharmony_ci		if (check(fmt)) {
13928c2ecf20Sopenharmony_ci			type_match = true;
13938c2ecf20Sopenharmony_ci			break;
13948c2ecf20Sopenharmony_ci		}
13958c2ecf20Sopenharmony_ci	}
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	if (type_match) {
13988c2ecf20Sopenharmony_ci		/*
13998c2ecf20Sopenharmony_ci		 * If the filter is for current level entry, propagate
14008c2ecf20Sopenharmony_ci		 * filter marker to parents.  The marker bit was
14018c2ecf20Sopenharmony_ci		 * already set by default so it only needs to clear
14028c2ecf20Sopenharmony_ci		 * non-filtered entries.
14038c2ecf20Sopenharmony_ci		 */
14048c2ecf20Sopenharmony_ci		if (!(he->filtered & (1 << type))) {
14058c2ecf20Sopenharmony_ci			while (parent) {
14068c2ecf20Sopenharmony_ci				parent->filtered &= ~(1 << type);
14078c2ecf20Sopenharmony_ci				parent = parent->parent_he;
14088c2ecf20Sopenharmony_ci			}
14098c2ecf20Sopenharmony_ci		}
14108c2ecf20Sopenharmony_ci	} else {
14118c2ecf20Sopenharmony_ci		/*
14128c2ecf20Sopenharmony_ci		 * If current entry doesn't have matching formats, set
14138c2ecf20Sopenharmony_ci		 * filter marker for upper level entries.  it will be
14148c2ecf20Sopenharmony_ci		 * cleared if its lower level entries is not filtered.
14158c2ecf20Sopenharmony_ci		 *
14168c2ecf20Sopenharmony_ci		 * For lower-level entries, it inherits parent's
14178c2ecf20Sopenharmony_ci		 * filter bit so that lower level entries of a
14188c2ecf20Sopenharmony_ci		 * non-filtered entry won't set the filter marker.
14198c2ecf20Sopenharmony_ci		 */
14208c2ecf20Sopenharmony_ci		if (parent == NULL)
14218c2ecf20Sopenharmony_ci			he->filtered |= (1 << type);
14228c2ecf20Sopenharmony_ci		else
14238c2ecf20Sopenharmony_ci			he->filtered |= (parent->filtered & (1 << type));
14248c2ecf20Sopenharmony_ci	}
14258c2ecf20Sopenharmony_ci}
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_cistatic void hist_entry__apply_hierarchy_filters(struct hist_entry *he)
14288c2ecf20Sopenharmony_ci{
14298c2ecf20Sopenharmony_ci	hist_entry__check_and_remove_filter(he, HIST_FILTER__THREAD,
14308c2ecf20Sopenharmony_ci					    check_thread_entry);
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	hist_entry__check_and_remove_filter(he, HIST_FILTER__DSO,
14338c2ecf20Sopenharmony_ci					    perf_hpp__is_dso_entry);
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	hist_entry__check_and_remove_filter(he, HIST_FILTER__SYMBOL,
14368c2ecf20Sopenharmony_ci					    perf_hpp__is_sym_entry);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	hists__apply_filters(he->hists, he);
14398c2ecf20Sopenharmony_ci}
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_cistatic struct hist_entry *hierarchy_insert_entry(struct hists *hists,
14428c2ecf20Sopenharmony_ci						 struct rb_root_cached *root,
14438c2ecf20Sopenharmony_ci						 struct hist_entry *he,
14448c2ecf20Sopenharmony_ci						 struct hist_entry *parent_he,
14458c2ecf20Sopenharmony_ci						 struct perf_hpp_list *hpp_list)
14468c2ecf20Sopenharmony_ci{
14478c2ecf20Sopenharmony_ci	struct rb_node **p = &root->rb_root.rb_node;
14488c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
14498c2ecf20Sopenharmony_ci	struct hist_entry *iter, *new;
14508c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
14518c2ecf20Sopenharmony_ci	int64_t cmp;
14528c2ecf20Sopenharmony_ci	bool leftmost = true;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	while (*p != NULL) {
14558c2ecf20Sopenharmony_ci		parent = *p;
14568c2ecf20Sopenharmony_ci		iter = rb_entry(parent, struct hist_entry, rb_node_in);
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci		cmp = 0;
14598c2ecf20Sopenharmony_ci		perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
14608c2ecf20Sopenharmony_ci			cmp = fmt->collapse(fmt, iter, he);
14618c2ecf20Sopenharmony_ci			if (cmp)
14628c2ecf20Sopenharmony_ci				break;
14638c2ecf20Sopenharmony_ci		}
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci		if (!cmp) {
14668c2ecf20Sopenharmony_ci			he_stat__add_stat(&iter->stat, &he->stat);
14678c2ecf20Sopenharmony_ci			return iter;
14688c2ecf20Sopenharmony_ci		}
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci		if (cmp < 0)
14718c2ecf20Sopenharmony_ci			p = &parent->rb_left;
14728c2ecf20Sopenharmony_ci		else {
14738c2ecf20Sopenharmony_ci			p = &parent->rb_right;
14748c2ecf20Sopenharmony_ci			leftmost = false;
14758c2ecf20Sopenharmony_ci		}
14768c2ecf20Sopenharmony_ci	}
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	new = hist_entry__new(he, true);
14798c2ecf20Sopenharmony_ci	if (new == NULL)
14808c2ecf20Sopenharmony_ci		return NULL;
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	hists->nr_entries++;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	/* save related format list for output */
14858c2ecf20Sopenharmony_ci	new->hpp_list = hpp_list;
14868c2ecf20Sopenharmony_ci	new->parent_he = parent_he;
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	hist_entry__apply_hierarchy_filters(new);
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	/* some fields are now passed to 'new' */
14918c2ecf20Sopenharmony_ci	perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
14928c2ecf20Sopenharmony_ci		if (perf_hpp__is_trace_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
14938c2ecf20Sopenharmony_ci			he->trace_output = NULL;
14948c2ecf20Sopenharmony_ci		else
14958c2ecf20Sopenharmony_ci			new->trace_output = NULL;
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci		if (perf_hpp__is_srcline_entry(fmt))
14988c2ecf20Sopenharmony_ci			he->srcline = NULL;
14998c2ecf20Sopenharmony_ci		else
15008c2ecf20Sopenharmony_ci			new->srcline = NULL;
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci		if (perf_hpp__is_srcfile_entry(fmt))
15038c2ecf20Sopenharmony_ci			he->srcfile = NULL;
15048c2ecf20Sopenharmony_ci		else
15058c2ecf20Sopenharmony_ci			new->srcfile = NULL;
15068c2ecf20Sopenharmony_ci	}
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	rb_link_node(&new->rb_node_in, parent, p);
15098c2ecf20Sopenharmony_ci	rb_insert_color_cached(&new->rb_node_in, root, leftmost);
15108c2ecf20Sopenharmony_ci	return new;
15118c2ecf20Sopenharmony_ci}
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_cistatic int hists__hierarchy_insert_entry(struct hists *hists,
15148c2ecf20Sopenharmony_ci					 struct rb_root_cached *root,
15158c2ecf20Sopenharmony_ci					 struct hist_entry *he)
15168c2ecf20Sopenharmony_ci{
15178c2ecf20Sopenharmony_ci	struct perf_hpp_list_node *node;
15188c2ecf20Sopenharmony_ci	struct hist_entry *new_he = NULL;
15198c2ecf20Sopenharmony_ci	struct hist_entry *parent = NULL;
15208c2ecf20Sopenharmony_ci	int depth = 0;
15218c2ecf20Sopenharmony_ci	int ret = 0;
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	list_for_each_entry(node, &hists->hpp_formats, list) {
15248c2ecf20Sopenharmony_ci		/* skip period (overhead) and elided columns */
15258c2ecf20Sopenharmony_ci		if (node->level == 0 || node->skip)
15268c2ecf20Sopenharmony_ci			continue;
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci		/* insert copy of 'he' for each fmt into the hierarchy */
15298c2ecf20Sopenharmony_ci		new_he = hierarchy_insert_entry(hists, root, he, parent, &node->hpp);
15308c2ecf20Sopenharmony_ci		if (new_he == NULL) {
15318c2ecf20Sopenharmony_ci			ret = -1;
15328c2ecf20Sopenharmony_ci			break;
15338c2ecf20Sopenharmony_ci		}
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci		root = &new_he->hroot_in;
15368c2ecf20Sopenharmony_ci		new_he->depth = depth++;
15378c2ecf20Sopenharmony_ci		parent = new_he;
15388c2ecf20Sopenharmony_ci	}
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	if (new_he) {
15418c2ecf20Sopenharmony_ci		new_he->leaf = true;
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci		if (hist_entry__has_callchains(new_he) &&
15448c2ecf20Sopenharmony_ci		    symbol_conf.use_callchain) {
15458c2ecf20Sopenharmony_ci			callchain_cursor_reset(&callchain_cursor);
15468c2ecf20Sopenharmony_ci			if (callchain_merge(&callchain_cursor,
15478c2ecf20Sopenharmony_ci					    new_he->callchain,
15488c2ecf20Sopenharmony_ci					    he->callchain) < 0)
15498c2ecf20Sopenharmony_ci				ret = -1;
15508c2ecf20Sopenharmony_ci		}
15518c2ecf20Sopenharmony_ci	}
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	/* 'he' is no longer used */
15548c2ecf20Sopenharmony_ci	hist_entry__delete(he);
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	/* return 0 (or -1) since it already applied filters */
15578c2ecf20Sopenharmony_ci	return ret;
15588c2ecf20Sopenharmony_ci}
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_cistatic int hists__collapse_insert_entry(struct hists *hists,
15618c2ecf20Sopenharmony_ci					struct rb_root_cached *root,
15628c2ecf20Sopenharmony_ci					struct hist_entry *he)
15638c2ecf20Sopenharmony_ci{
15648c2ecf20Sopenharmony_ci	struct rb_node **p = &root->rb_root.rb_node;
15658c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
15668c2ecf20Sopenharmony_ci	struct hist_entry *iter;
15678c2ecf20Sopenharmony_ci	int64_t cmp;
15688c2ecf20Sopenharmony_ci	bool leftmost = true;
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	if (symbol_conf.report_hierarchy)
15718c2ecf20Sopenharmony_ci		return hists__hierarchy_insert_entry(hists, root, he);
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	while (*p != NULL) {
15748c2ecf20Sopenharmony_ci		parent = *p;
15758c2ecf20Sopenharmony_ci		iter = rb_entry(parent, struct hist_entry, rb_node_in);
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci		cmp = hist_entry__collapse(iter, he);
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci		if (!cmp) {
15808c2ecf20Sopenharmony_ci			int ret = 0;
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci			he_stat__add_stat(&iter->stat, &he->stat);
15838c2ecf20Sopenharmony_ci			if (symbol_conf.cumulate_callchain)
15848c2ecf20Sopenharmony_ci				he_stat__add_stat(iter->stat_acc, he->stat_acc);
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci			if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
15878c2ecf20Sopenharmony_ci				callchain_cursor_reset(&callchain_cursor);
15888c2ecf20Sopenharmony_ci				if (callchain_merge(&callchain_cursor,
15898c2ecf20Sopenharmony_ci						    iter->callchain,
15908c2ecf20Sopenharmony_ci						    he->callchain) < 0)
15918c2ecf20Sopenharmony_ci					ret = -1;
15928c2ecf20Sopenharmony_ci			}
15938c2ecf20Sopenharmony_ci			hist_entry__delete(he);
15948c2ecf20Sopenharmony_ci			return ret;
15958c2ecf20Sopenharmony_ci		}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci		if (cmp < 0)
15988c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
15998c2ecf20Sopenharmony_ci		else {
16008c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
16018c2ecf20Sopenharmony_ci			leftmost = false;
16028c2ecf20Sopenharmony_ci		}
16038c2ecf20Sopenharmony_ci	}
16048c2ecf20Sopenharmony_ci	hists->nr_entries++;
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	rb_link_node(&he->rb_node_in, parent, p);
16078c2ecf20Sopenharmony_ci	rb_insert_color_cached(&he->rb_node_in, root, leftmost);
16088c2ecf20Sopenharmony_ci	return 1;
16098c2ecf20Sopenharmony_ci}
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_cistruct rb_root_cached *hists__get_rotate_entries_in(struct hists *hists)
16128c2ecf20Sopenharmony_ci{
16138c2ecf20Sopenharmony_ci	struct rb_root_cached *root;
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	pthread_mutex_lock(&hists->lock);
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	root = hists->entries_in;
16188c2ecf20Sopenharmony_ci	if (++hists->entries_in > &hists->entries_in_array[1])
16198c2ecf20Sopenharmony_ci		hists->entries_in = &hists->entries_in_array[0];
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&hists->lock);
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	return root;
16248c2ecf20Sopenharmony_ci}
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_cistatic void hists__apply_filters(struct hists *hists, struct hist_entry *he)
16278c2ecf20Sopenharmony_ci{
16288c2ecf20Sopenharmony_ci	hists__filter_entry_by_dso(hists, he);
16298c2ecf20Sopenharmony_ci	hists__filter_entry_by_thread(hists, he);
16308c2ecf20Sopenharmony_ci	hists__filter_entry_by_symbol(hists, he);
16318c2ecf20Sopenharmony_ci	hists__filter_entry_by_socket(hists, he);
16328c2ecf20Sopenharmony_ci}
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ciint hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
16358c2ecf20Sopenharmony_ci{
16368c2ecf20Sopenharmony_ci	struct rb_root_cached *root;
16378c2ecf20Sopenharmony_ci	struct rb_node *next;
16388c2ecf20Sopenharmony_ci	struct hist_entry *n;
16398c2ecf20Sopenharmony_ci	int ret;
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	if (!hists__has(hists, need_collapse))
16428c2ecf20Sopenharmony_ci		return 0;
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	hists->nr_entries = 0;
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	root = hists__get_rotate_entries_in(hists);
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	next = rb_first_cached(root);
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci	while (next) {
16518c2ecf20Sopenharmony_ci		if (session_done())
16528c2ecf20Sopenharmony_ci			break;
16538c2ecf20Sopenharmony_ci		n = rb_entry(next, struct hist_entry, rb_node_in);
16548c2ecf20Sopenharmony_ci		next = rb_next(&n->rb_node_in);
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci		rb_erase_cached(&n->rb_node_in, root);
16578c2ecf20Sopenharmony_ci		ret = hists__collapse_insert_entry(hists, &hists->entries_collapsed, n);
16588c2ecf20Sopenharmony_ci		if (ret < 0)
16598c2ecf20Sopenharmony_ci			return -1;
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci		if (ret) {
16628c2ecf20Sopenharmony_ci			/*
16638c2ecf20Sopenharmony_ci			 * If it wasn't combined with one of the entries already
16648c2ecf20Sopenharmony_ci			 * collapsed, we need to apply the filters that may have
16658c2ecf20Sopenharmony_ci			 * been set by, say, the hist_browser.
16668c2ecf20Sopenharmony_ci			 */
16678c2ecf20Sopenharmony_ci			hists__apply_filters(hists, n);
16688c2ecf20Sopenharmony_ci		}
16698c2ecf20Sopenharmony_ci		if (prog)
16708c2ecf20Sopenharmony_ci			ui_progress__update(prog, 1);
16718c2ecf20Sopenharmony_ci	}
16728c2ecf20Sopenharmony_ci	return 0;
16738c2ecf20Sopenharmony_ci}
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_cistatic int64_t hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
16768c2ecf20Sopenharmony_ci{
16778c2ecf20Sopenharmony_ci	struct hists *hists = a->hists;
16788c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
16798c2ecf20Sopenharmony_ci	int64_t cmp = 0;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	hists__for_each_sort_list(hists, fmt) {
16828c2ecf20Sopenharmony_ci		if (perf_hpp__should_skip(fmt, a->hists))
16838c2ecf20Sopenharmony_ci			continue;
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci		cmp = fmt->sort(fmt, a, b);
16868c2ecf20Sopenharmony_ci		if (cmp)
16878c2ecf20Sopenharmony_ci			break;
16888c2ecf20Sopenharmony_ci	}
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci	return cmp;
16918c2ecf20Sopenharmony_ci}
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_cistatic void hists__reset_filter_stats(struct hists *hists)
16948c2ecf20Sopenharmony_ci{
16958c2ecf20Sopenharmony_ci	hists->nr_non_filtered_entries = 0;
16968c2ecf20Sopenharmony_ci	hists->stats.total_non_filtered_period = 0;
16978c2ecf20Sopenharmony_ci}
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_civoid hists__reset_stats(struct hists *hists)
17008c2ecf20Sopenharmony_ci{
17018c2ecf20Sopenharmony_ci	hists->nr_entries = 0;
17028c2ecf20Sopenharmony_ci	hists->stats.total_period = 0;
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	hists__reset_filter_stats(hists);
17058c2ecf20Sopenharmony_ci}
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_cistatic void hists__inc_filter_stats(struct hists *hists, struct hist_entry *h)
17088c2ecf20Sopenharmony_ci{
17098c2ecf20Sopenharmony_ci	hists->nr_non_filtered_entries++;
17108c2ecf20Sopenharmony_ci	hists->stats.total_non_filtered_period += h->stat.period;
17118c2ecf20Sopenharmony_ci}
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_civoid hists__inc_stats(struct hists *hists, struct hist_entry *h)
17148c2ecf20Sopenharmony_ci{
17158c2ecf20Sopenharmony_ci	if (!h->filtered)
17168c2ecf20Sopenharmony_ci		hists__inc_filter_stats(hists, h);
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	hists->nr_entries++;
17198c2ecf20Sopenharmony_ci	hists->stats.total_period += h->stat.period;
17208c2ecf20Sopenharmony_ci}
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_cistatic void hierarchy_recalc_total_periods(struct hists *hists)
17238c2ecf20Sopenharmony_ci{
17248c2ecf20Sopenharmony_ci	struct rb_node *node;
17258c2ecf20Sopenharmony_ci	struct hist_entry *he;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	node = rb_first_cached(&hists->entries);
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	hists->stats.total_period = 0;
17308c2ecf20Sopenharmony_ci	hists->stats.total_non_filtered_period = 0;
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	/*
17338c2ecf20Sopenharmony_ci	 * recalculate total period using top-level entries only
17348c2ecf20Sopenharmony_ci	 * since lower level entries only see non-filtered entries
17358c2ecf20Sopenharmony_ci	 * but upper level entries have sum of both entries.
17368c2ecf20Sopenharmony_ci	 */
17378c2ecf20Sopenharmony_ci	while (node) {
17388c2ecf20Sopenharmony_ci		he = rb_entry(node, struct hist_entry, rb_node);
17398c2ecf20Sopenharmony_ci		node = rb_next(node);
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci		hists->stats.total_period += he->stat.period;
17428c2ecf20Sopenharmony_ci		if (!he->filtered)
17438c2ecf20Sopenharmony_ci			hists->stats.total_non_filtered_period += he->stat.period;
17448c2ecf20Sopenharmony_ci	}
17458c2ecf20Sopenharmony_ci}
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_cistatic void hierarchy_insert_output_entry(struct rb_root_cached *root,
17488c2ecf20Sopenharmony_ci					  struct hist_entry *he)
17498c2ecf20Sopenharmony_ci{
17508c2ecf20Sopenharmony_ci	struct rb_node **p = &root->rb_root.rb_node;
17518c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
17528c2ecf20Sopenharmony_ci	struct hist_entry *iter;
17538c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
17548c2ecf20Sopenharmony_ci	bool leftmost = true;
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	while (*p != NULL) {
17578c2ecf20Sopenharmony_ci		parent = *p;
17588c2ecf20Sopenharmony_ci		iter = rb_entry(parent, struct hist_entry, rb_node);
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci		if (hist_entry__sort(he, iter) > 0)
17618c2ecf20Sopenharmony_ci			p = &parent->rb_left;
17628c2ecf20Sopenharmony_ci		else {
17638c2ecf20Sopenharmony_ci			p = &parent->rb_right;
17648c2ecf20Sopenharmony_ci			leftmost = false;
17658c2ecf20Sopenharmony_ci		}
17668c2ecf20Sopenharmony_ci	}
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	rb_link_node(&he->rb_node, parent, p);
17698c2ecf20Sopenharmony_ci	rb_insert_color_cached(&he->rb_node, root, leftmost);
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	/* update column width of dynamic entry */
17728c2ecf20Sopenharmony_ci	perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
17738c2ecf20Sopenharmony_ci		if (perf_hpp__is_dynamic_entry(fmt))
17748c2ecf20Sopenharmony_ci			fmt->sort(fmt, he, NULL);
17758c2ecf20Sopenharmony_ci	}
17768c2ecf20Sopenharmony_ci}
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_cistatic void hists__hierarchy_output_resort(struct hists *hists,
17798c2ecf20Sopenharmony_ci					   struct ui_progress *prog,
17808c2ecf20Sopenharmony_ci					   struct rb_root_cached *root_in,
17818c2ecf20Sopenharmony_ci					   struct rb_root_cached *root_out,
17828c2ecf20Sopenharmony_ci					   u64 min_callchain_hits,
17838c2ecf20Sopenharmony_ci					   bool use_callchain)
17848c2ecf20Sopenharmony_ci{
17858c2ecf20Sopenharmony_ci	struct rb_node *node;
17868c2ecf20Sopenharmony_ci	struct hist_entry *he;
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci	*root_out = RB_ROOT_CACHED;
17898c2ecf20Sopenharmony_ci	node = rb_first_cached(root_in);
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	while (node) {
17928c2ecf20Sopenharmony_ci		he = rb_entry(node, struct hist_entry, rb_node_in);
17938c2ecf20Sopenharmony_ci		node = rb_next(node);
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci		hierarchy_insert_output_entry(root_out, he);
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci		if (prog)
17988c2ecf20Sopenharmony_ci			ui_progress__update(prog, 1);
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci		hists->nr_entries++;
18018c2ecf20Sopenharmony_ci		if (!he->filtered) {
18028c2ecf20Sopenharmony_ci			hists->nr_non_filtered_entries++;
18038c2ecf20Sopenharmony_ci			hists__calc_col_len(hists, he);
18048c2ecf20Sopenharmony_ci		}
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci		if (!he->leaf) {
18078c2ecf20Sopenharmony_ci			hists__hierarchy_output_resort(hists, prog,
18088c2ecf20Sopenharmony_ci						       &he->hroot_in,
18098c2ecf20Sopenharmony_ci						       &he->hroot_out,
18108c2ecf20Sopenharmony_ci						       min_callchain_hits,
18118c2ecf20Sopenharmony_ci						       use_callchain);
18128c2ecf20Sopenharmony_ci			continue;
18138c2ecf20Sopenharmony_ci		}
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci		if (!use_callchain)
18168c2ecf20Sopenharmony_ci			continue;
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci		if (callchain_param.mode == CHAIN_GRAPH_REL) {
18198c2ecf20Sopenharmony_ci			u64 total = he->stat.period;
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci			if (symbol_conf.cumulate_callchain)
18228c2ecf20Sopenharmony_ci				total = he->stat_acc->period;
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci			min_callchain_hits = total * (callchain_param.min_percent / 100);
18258c2ecf20Sopenharmony_ci		}
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci		callchain_param.sort(&he->sorted_chain, he->callchain,
18288c2ecf20Sopenharmony_ci				     min_callchain_hits, &callchain_param);
18298c2ecf20Sopenharmony_ci	}
18308c2ecf20Sopenharmony_ci}
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_cistatic void __hists__insert_output_entry(struct rb_root_cached *entries,
18338c2ecf20Sopenharmony_ci					 struct hist_entry *he,
18348c2ecf20Sopenharmony_ci					 u64 min_callchain_hits,
18358c2ecf20Sopenharmony_ci					 bool use_callchain)
18368c2ecf20Sopenharmony_ci{
18378c2ecf20Sopenharmony_ci	struct rb_node **p = &entries->rb_root.rb_node;
18388c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
18398c2ecf20Sopenharmony_ci	struct hist_entry *iter;
18408c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
18418c2ecf20Sopenharmony_ci	bool leftmost = true;
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	if (use_callchain) {
18448c2ecf20Sopenharmony_ci		if (callchain_param.mode == CHAIN_GRAPH_REL) {
18458c2ecf20Sopenharmony_ci			u64 total = he->stat.period;
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci			if (symbol_conf.cumulate_callchain)
18488c2ecf20Sopenharmony_ci				total = he->stat_acc->period;
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci			min_callchain_hits = total * (callchain_param.min_percent / 100);
18518c2ecf20Sopenharmony_ci		}
18528c2ecf20Sopenharmony_ci		callchain_param.sort(&he->sorted_chain, he->callchain,
18538c2ecf20Sopenharmony_ci				      min_callchain_hits, &callchain_param);
18548c2ecf20Sopenharmony_ci	}
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	while (*p != NULL) {
18578c2ecf20Sopenharmony_ci		parent = *p;
18588c2ecf20Sopenharmony_ci		iter = rb_entry(parent, struct hist_entry, rb_node);
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci		if (hist_entry__sort(he, iter) > 0)
18618c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
18628c2ecf20Sopenharmony_ci		else {
18638c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
18648c2ecf20Sopenharmony_ci			leftmost = false;
18658c2ecf20Sopenharmony_ci		}
18668c2ecf20Sopenharmony_ci	}
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	rb_link_node(&he->rb_node, parent, p);
18698c2ecf20Sopenharmony_ci	rb_insert_color_cached(&he->rb_node, entries, leftmost);
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	perf_hpp_list__for_each_sort_list(&perf_hpp_list, fmt) {
18728c2ecf20Sopenharmony_ci		if (perf_hpp__is_dynamic_entry(fmt) &&
18738c2ecf20Sopenharmony_ci		    perf_hpp__defined_dynamic_entry(fmt, he->hists))
18748c2ecf20Sopenharmony_ci			fmt->sort(fmt, he, NULL);  /* update column width */
18758c2ecf20Sopenharmony_ci	}
18768c2ecf20Sopenharmony_ci}
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_cistatic void output_resort(struct hists *hists, struct ui_progress *prog,
18798c2ecf20Sopenharmony_ci			  bool use_callchain, hists__resort_cb_t cb,
18808c2ecf20Sopenharmony_ci			  void *cb_arg)
18818c2ecf20Sopenharmony_ci{
18828c2ecf20Sopenharmony_ci	struct rb_root_cached *root;
18838c2ecf20Sopenharmony_ci	struct rb_node *next;
18848c2ecf20Sopenharmony_ci	struct hist_entry *n;
18858c2ecf20Sopenharmony_ci	u64 callchain_total;
18868c2ecf20Sopenharmony_ci	u64 min_callchain_hits;
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	callchain_total = hists->callchain_period;
18898c2ecf20Sopenharmony_ci	if (symbol_conf.filter_relative)
18908c2ecf20Sopenharmony_ci		callchain_total = hists->callchain_non_filtered_period;
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	min_callchain_hits = callchain_total * (callchain_param.min_percent / 100);
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	hists__reset_stats(hists);
18958c2ecf20Sopenharmony_ci	hists__reset_col_len(hists);
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	if (symbol_conf.report_hierarchy) {
18988c2ecf20Sopenharmony_ci		hists__hierarchy_output_resort(hists, prog,
18998c2ecf20Sopenharmony_ci					       &hists->entries_collapsed,
19008c2ecf20Sopenharmony_ci					       &hists->entries,
19018c2ecf20Sopenharmony_ci					       min_callchain_hits,
19028c2ecf20Sopenharmony_ci					       use_callchain);
19038c2ecf20Sopenharmony_ci		hierarchy_recalc_total_periods(hists);
19048c2ecf20Sopenharmony_ci		return;
19058c2ecf20Sopenharmony_ci	}
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	if (hists__has(hists, need_collapse))
19088c2ecf20Sopenharmony_ci		root = &hists->entries_collapsed;
19098c2ecf20Sopenharmony_ci	else
19108c2ecf20Sopenharmony_ci		root = hists->entries_in;
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	next = rb_first_cached(root);
19138c2ecf20Sopenharmony_ci	hists->entries = RB_ROOT_CACHED;
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	while (next) {
19168c2ecf20Sopenharmony_ci		n = rb_entry(next, struct hist_entry, rb_node_in);
19178c2ecf20Sopenharmony_ci		next = rb_next(&n->rb_node_in);
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci		if (cb && cb(n, cb_arg))
19208c2ecf20Sopenharmony_ci			continue;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci		__hists__insert_output_entry(&hists->entries, n, min_callchain_hits, use_callchain);
19238c2ecf20Sopenharmony_ci		hists__inc_stats(hists, n);
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci		if (!n->filtered)
19268c2ecf20Sopenharmony_ci			hists__calc_col_len(hists, n);
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci		if (prog)
19298c2ecf20Sopenharmony_ci			ui_progress__update(prog, 1);
19308c2ecf20Sopenharmony_ci	}
19318c2ecf20Sopenharmony_ci}
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_civoid evsel__output_resort_cb(struct evsel *evsel, struct ui_progress *prog,
19348c2ecf20Sopenharmony_ci			     hists__resort_cb_t cb, void *cb_arg)
19358c2ecf20Sopenharmony_ci{
19368c2ecf20Sopenharmony_ci	bool use_callchain;
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph)
19398c2ecf20Sopenharmony_ci		use_callchain = evsel__has_callchain(evsel);
19408c2ecf20Sopenharmony_ci	else
19418c2ecf20Sopenharmony_ci		use_callchain = symbol_conf.use_callchain;
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci	use_callchain |= symbol_conf.show_branchflag_count;
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci	output_resort(evsel__hists(evsel), prog, use_callchain, cb, cb_arg);
19468c2ecf20Sopenharmony_ci}
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_civoid evsel__output_resort(struct evsel *evsel, struct ui_progress *prog)
19498c2ecf20Sopenharmony_ci{
19508c2ecf20Sopenharmony_ci	return evsel__output_resort_cb(evsel, prog, NULL, NULL);
19518c2ecf20Sopenharmony_ci}
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_civoid hists__output_resort(struct hists *hists, struct ui_progress *prog)
19548c2ecf20Sopenharmony_ci{
19558c2ecf20Sopenharmony_ci	output_resort(hists, prog, symbol_conf.use_callchain, NULL, NULL);
19568c2ecf20Sopenharmony_ci}
19578c2ecf20Sopenharmony_ci
19588c2ecf20Sopenharmony_civoid hists__output_resort_cb(struct hists *hists, struct ui_progress *prog,
19598c2ecf20Sopenharmony_ci			     hists__resort_cb_t cb)
19608c2ecf20Sopenharmony_ci{
19618c2ecf20Sopenharmony_ci	output_resort(hists, prog, symbol_conf.use_callchain, cb, NULL);
19628c2ecf20Sopenharmony_ci}
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_cistatic bool can_goto_child(struct hist_entry *he, enum hierarchy_move_dir hmd)
19658c2ecf20Sopenharmony_ci{
19668c2ecf20Sopenharmony_ci	if (he->leaf || hmd == HMD_FORCE_SIBLING)
19678c2ecf20Sopenharmony_ci		return false;
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	if (he->unfolded || hmd == HMD_FORCE_CHILD)
19708c2ecf20Sopenharmony_ci		return true;
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci	return false;
19738c2ecf20Sopenharmony_ci}
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_cistruct rb_node *rb_hierarchy_last(struct rb_node *node)
19768c2ecf20Sopenharmony_ci{
19778c2ecf20Sopenharmony_ci	struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	while (can_goto_child(he, HMD_NORMAL)) {
19808c2ecf20Sopenharmony_ci		node = rb_last(&he->hroot_out.rb_root);
19818c2ecf20Sopenharmony_ci		he = rb_entry(node, struct hist_entry, rb_node);
19828c2ecf20Sopenharmony_ci	}
19838c2ecf20Sopenharmony_ci	return node;
19848c2ecf20Sopenharmony_ci}
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_cistruct rb_node *__rb_hierarchy_next(struct rb_node *node, enum hierarchy_move_dir hmd)
19878c2ecf20Sopenharmony_ci{
19888c2ecf20Sopenharmony_ci	struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_ci	if (can_goto_child(he, hmd))
19918c2ecf20Sopenharmony_ci		node = rb_first_cached(&he->hroot_out);
19928c2ecf20Sopenharmony_ci	else
19938c2ecf20Sopenharmony_ci		node = rb_next(node);
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	while (node == NULL) {
19968c2ecf20Sopenharmony_ci		he = he->parent_he;
19978c2ecf20Sopenharmony_ci		if (he == NULL)
19988c2ecf20Sopenharmony_ci			break;
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci		node = rb_next(&he->rb_node);
20018c2ecf20Sopenharmony_ci	}
20028c2ecf20Sopenharmony_ci	return node;
20038c2ecf20Sopenharmony_ci}
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_cistruct rb_node *rb_hierarchy_prev(struct rb_node *node)
20068c2ecf20Sopenharmony_ci{
20078c2ecf20Sopenharmony_ci	struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci	node = rb_prev(node);
20108c2ecf20Sopenharmony_ci	if (node)
20118c2ecf20Sopenharmony_ci		return rb_hierarchy_last(node);
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci	he = he->parent_he;
20148c2ecf20Sopenharmony_ci	if (he == NULL)
20158c2ecf20Sopenharmony_ci		return NULL;
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci	return &he->rb_node;
20188c2ecf20Sopenharmony_ci}
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_cibool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit)
20218c2ecf20Sopenharmony_ci{
20228c2ecf20Sopenharmony_ci	struct rb_node *node;
20238c2ecf20Sopenharmony_ci	struct hist_entry *child;
20248c2ecf20Sopenharmony_ci	float percent;
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci	if (he->leaf)
20278c2ecf20Sopenharmony_ci		return false;
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	node = rb_first_cached(&he->hroot_out);
20308c2ecf20Sopenharmony_ci	child = rb_entry(node, struct hist_entry, rb_node);
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	while (node && child->filtered) {
20338c2ecf20Sopenharmony_ci		node = rb_next(node);
20348c2ecf20Sopenharmony_ci		child = rb_entry(node, struct hist_entry, rb_node);
20358c2ecf20Sopenharmony_ci	}
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci	if (node)
20388c2ecf20Sopenharmony_ci		percent = hist_entry__get_percent_limit(child);
20398c2ecf20Sopenharmony_ci	else
20408c2ecf20Sopenharmony_ci		percent = 0;
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	return node && percent >= limit;
20438c2ecf20Sopenharmony_ci}
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_cistatic void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
20468c2ecf20Sopenharmony_ci				       enum hist_filter filter)
20478c2ecf20Sopenharmony_ci{
20488c2ecf20Sopenharmony_ci	h->filtered &= ~(1 << filter);
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	if (symbol_conf.report_hierarchy) {
20518c2ecf20Sopenharmony_ci		struct hist_entry *parent = h->parent_he;
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci		while (parent) {
20548c2ecf20Sopenharmony_ci			he_stat__add_stat(&parent->stat, &h->stat);
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci			parent->filtered &= ~(1 << filter);
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci			if (parent->filtered)
20598c2ecf20Sopenharmony_ci				goto next;
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci			/* force fold unfiltered entry for simplicity */
20628c2ecf20Sopenharmony_ci			parent->unfolded = false;
20638c2ecf20Sopenharmony_ci			parent->has_no_entry = false;
20648c2ecf20Sopenharmony_ci			parent->row_offset = 0;
20658c2ecf20Sopenharmony_ci			parent->nr_rows = 0;
20668c2ecf20Sopenharmony_cinext:
20678c2ecf20Sopenharmony_ci			parent = parent->parent_he;
20688c2ecf20Sopenharmony_ci		}
20698c2ecf20Sopenharmony_ci	}
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci	if (h->filtered)
20728c2ecf20Sopenharmony_ci		return;
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci	/* force fold unfiltered entry for simplicity */
20758c2ecf20Sopenharmony_ci	h->unfolded = false;
20768c2ecf20Sopenharmony_ci	h->has_no_entry = false;
20778c2ecf20Sopenharmony_ci	h->row_offset = 0;
20788c2ecf20Sopenharmony_ci	h->nr_rows = 0;
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci	hists->stats.nr_non_filtered_samples += h->stat.nr_events;
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci	hists__inc_filter_stats(hists, h);
20838c2ecf20Sopenharmony_ci	hists__calc_col_len(hists, h);
20848c2ecf20Sopenharmony_ci}
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_cistatic bool hists__filter_entry_by_dso(struct hists *hists,
20888c2ecf20Sopenharmony_ci				       struct hist_entry *he)
20898c2ecf20Sopenharmony_ci{
20908c2ecf20Sopenharmony_ci	if (hists->dso_filter != NULL &&
20918c2ecf20Sopenharmony_ci	    (he->ms.map == NULL || he->ms.map->dso != hists->dso_filter)) {
20928c2ecf20Sopenharmony_ci		he->filtered |= (1 << HIST_FILTER__DSO);
20938c2ecf20Sopenharmony_ci		return true;
20948c2ecf20Sopenharmony_ci	}
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	return false;
20978c2ecf20Sopenharmony_ci}
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_cistatic bool hists__filter_entry_by_thread(struct hists *hists,
21008c2ecf20Sopenharmony_ci					  struct hist_entry *he)
21018c2ecf20Sopenharmony_ci{
21028c2ecf20Sopenharmony_ci	if (hists->thread_filter != NULL &&
21038c2ecf20Sopenharmony_ci	    he->thread != hists->thread_filter) {
21048c2ecf20Sopenharmony_ci		he->filtered |= (1 << HIST_FILTER__THREAD);
21058c2ecf20Sopenharmony_ci		return true;
21068c2ecf20Sopenharmony_ci	}
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci	return false;
21098c2ecf20Sopenharmony_ci}
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_cistatic bool hists__filter_entry_by_symbol(struct hists *hists,
21128c2ecf20Sopenharmony_ci					  struct hist_entry *he)
21138c2ecf20Sopenharmony_ci{
21148c2ecf20Sopenharmony_ci	if (hists->symbol_filter_str != NULL &&
21158c2ecf20Sopenharmony_ci	    (!he->ms.sym || strstr(he->ms.sym->name,
21168c2ecf20Sopenharmony_ci				   hists->symbol_filter_str) == NULL)) {
21178c2ecf20Sopenharmony_ci		he->filtered |= (1 << HIST_FILTER__SYMBOL);
21188c2ecf20Sopenharmony_ci		return true;
21198c2ecf20Sopenharmony_ci	}
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci	return false;
21228c2ecf20Sopenharmony_ci}
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_cistatic bool hists__filter_entry_by_socket(struct hists *hists,
21258c2ecf20Sopenharmony_ci					  struct hist_entry *he)
21268c2ecf20Sopenharmony_ci{
21278c2ecf20Sopenharmony_ci	if ((hists->socket_filter > -1) &&
21288c2ecf20Sopenharmony_ci	    (he->socket != hists->socket_filter)) {
21298c2ecf20Sopenharmony_ci		he->filtered |= (1 << HIST_FILTER__SOCKET);
21308c2ecf20Sopenharmony_ci		return true;
21318c2ecf20Sopenharmony_ci	}
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ci	return false;
21348c2ecf20Sopenharmony_ci}
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_citypedef bool (*filter_fn_t)(struct hists *hists, struct hist_entry *he);
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_cistatic void hists__filter_by_type(struct hists *hists, int type, filter_fn_t filter)
21398c2ecf20Sopenharmony_ci{
21408c2ecf20Sopenharmony_ci	struct rb_node *nd;
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	hists->stats.nr_non_filtered_samples = 0;
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci	hists__reset_filter_stats(hists);
21458c2ecf20Sopenharmony_ci	hists__reset_col_len(hists);
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_ci	for (nd = rb_first_cached(&hists->entries); nd; nd = rb_next(nd)) {
21488c2ecf20Sopenharmony_ci		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci		if (filter(hists, h))
21518c2ecf20Sopenharmony_ci			continue;
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_ci		hists__remove_entry_filter(hists, h, type);
21548c2ecf20Sopenharmony_ci	}
21558c2ecf20Sopenharmony_ci}
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_cistatic void resort_filtered_entry(struct rb_root_cached *root,
21588c2ecf20Sopenharmony_ci				  struct hist_entry *he)
21598c2ecf20Sopenharmony_ci{
21608c2ecf20Sopenharmony_ci	struct rb_node **p = &root->rb_root.rb_node;
21618c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
21628c2ecf20Sopenharmony_ci	struct hist_entry *iter;
21638c2ecf20Sopenharmony_ci	struct rb_root_cached new_root = RB_ROOT_CACHED;
21648c2ecf20Sopenharmony_ci	struct rb_node *nd;
21658c2ecf20Sopenharmony_ci	bool leftmost = true;
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	while (*p != NULL) {
21688c2ecf20Sopenharmony_ci		parent = *p;
21698c2ecf20Sopenharmony_ci		iter = rb_entry(parent, struct hist_entry, rb_node);
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci		if (hist_entry__sort(he, iter) > 0)
21728c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
21738c2ecf20Sopenharmony_ci		else {
21748c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
21758c2ecf20Sopenharmony_ci			leftmost = false;
21768c2ecf20Sopenharmony_ci		}
21778c2ecf20Sopenharmony_ci	}
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_ci	rb_link_node(&he->rb_node, parent, p);
21808c2ecf20Sopenharmony_ci	rb_insert_color_cached(&he->rb_node, root, leftmost);
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	if (he->leaf || he->filtered)
21838c2ecf20Sopenharmony_ci		return;
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_ci	nd = rb_first_cached(&he->hroot_out);
21868c2ecf20Sopenharmony_ci	while (nd) {
21878c2ecf20Sopenharmony_ci		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci		nd = rb_next(nd);
21908c2ecf20Sopenharmony_ci		rb_erase_cached(&h->rb_node, &he->hroot_out);
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci		resort_filtered_entry(&new_root, h);
21938c2ecf20Sopenharmony_ci	}
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci	he->hroot_out = new_root;
21968c2ecf20Sopenharmony_ci}
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_cistatic void hists__filter_hierarchy(struct hists *hists, int type, const void *arg)
21998c2ecf20Sopenharmony_ci{
22008c2ecf20Sopenharmony_ci	struct rb_node *nd;
22018c2ecf20Sopenharmony_ci	struct rb_root_cached new_root = RB_ROOT_CACHED;
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	hists->stats.nr_non_filtered_samples = 0;
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	hists__reset_filter_stats(hists);
22068c2ecf20Sopenharmony_ci	hists__reset_col_len(hists);
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci	nd = rb_first_cached(&hists->entries);
22098c2ecf20Sopenharmony_ci	while (nd) {
22108c2ecf20Sopenharmony_ci		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
22118c2ecf20Sopenharmony_ci		int ret;
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci		ret = hist_entry__filter(h, type, arg);
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci		/*
22168c2ecf20Sopenharmony_ci		 * case 1. non-matching type
22178c2ecf20Sopenharmony_ci		 * zero out the period, set filter marker and move to child
22188c2ecf20Sopenharmony_ci		 */
22198c2ecf20Sopenharmony_ci		if (ret < 0) {
22208c2ecf20Sopenharmony_ci			memset(&h->stat, 0, sizeof(h->stat));
22218c2ecf20Sopenharmony_ci			h->filtered |= (1 << type);
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci			nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_CHILD);
22248c2ecf20Sopenharmony_ci		}
22258c2ecf20Sopenharmony_ci		/*
22268c2ecf20Sopenharmony_ci		 * case 2. matched type (filter out)
22278c2ecf20Sopenharmony_ci		 * set filter marker and move to next
22288c2ecf20Sopenharmony_ci		 */
22298c2ecf20Sopenharmony_ci		else if (ret == 1) {
22308c2ecf20Sopenharmony_ci			h->filtered |= (1 << type);
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci			nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
22338c2ecf20Sopenharmony_ci		}
22348c2ecf20Sopenharmony_ci		/*
22358c2ecf20Sopenharmony_ci		 * case 3. ok (not filtered)
22368c2ecf20Sopenharmony_ci		 * add period to hists and parents, erase the filter marker
22378c2ecf20Sopenharmony_ci		 * and move to next sibling
22388c2ecf20Sopenharmony_ci		 */
22398c2ecf20Sopenharmony_ci		else {
22408c2ecf20Sopenharmony_ci			hists__remove_entry_filter(hists, h, type);
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci			nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
22438c2ecf20Sopenharmony_ci		}
22448c2ecf20Sopenharmony_ci	}
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_ci	hierarchy_recalc_total_periods(hists);
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	/*
22498c2ecf20Sopenharmony_ci	 * resort output after applying a new filter since filter in a lower
22508c2ecf20Sopenharmony_ci	 * hierarchy can change periods in a upper hierarchy.
22518c2ecf20Sopenharmony_ci	 */
22528c2ecf20Sopenharmony_ci	nd = rb_first_cached(&hists->entries);
22538c2ecf20Sopenharmony_ci	while (nd) {
22548c2ecf20Sopenharmony_ci		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
22558c2ecf20Sopenharmony_ci
22568c2ecf20Sopenharmony_ci		nd = rb_next(nd);
22578c2ecf20Sopenharmony_ci		rb_erase_cached(&h->rb_node, &hists->entries);
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci		resort_filtered_entry(&new_root, h);
22608c2ecf20Sopenharmony_ci	}
22618c2ecf20Sopenharmony_ci
22628c2ecf20Sopenharmony_ci	hists->entries = new_root;
22638c2ecf20Sopenharmony_ci}
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_civoid hists__filter_by_thread(struct hists *hists)
22668c2ecf20Sopenharmony_ci{
22678c2ecf20Sopenharmony_ci	if (symbol_conf.report_hierarchy)
22688c2ecf20Sopenharmony_ci		hists__filter_hierarchy(hists, HIST_FILTER__THREAD,
22698c2ecf20Sopenharmony_ci					hists->thread_filter);
22708c2ecf20Sopenharmony_ci	else
22718c2ecf20Sopenharmony_ci		hists__filter_by_type(hists, HIST_FILTER__THREAD,
22728c2ecf20Sopenharmony_ci				      hists__filter_entry_by_thread);
22738c2ecf20Sopenharmony_ci}
22748c2ecf20Sopenharmony_ci
22758c2ecf20Sopenharmony_civoid hists__filter_by_dso(struct hists *hists)
22768c2ecf20Sopenharmony_ci{
22778c2ecf20Sopenharmony_ci	if (symbol_conf.report_hierarchy)
22788c2ecf20Sopenharmony_ci		hists__filter_hierarchy(hists, HIST_FILTER__DSO,
22798c2ecf20Sopenharmony_ci					hists->dso_filter);
22808c2ecf20Sopenharmony_ci	else
22818c2ecf20Sopenharmony_ci		hists__filter_by_type(hists, HIST_FILTER__DSO,
22828c2ecf20Sopenharmony_ci				      hists__filter_entry_by_dso);
22838c2ecf20Sopenharmony_ci}
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_civoid hists__filter_by_symbol(struct hists *hists)
22868c2ecf20Sopenharmony_ci{
22878c2ecf20Sopenharmony_ci	if (symbol_conf.report_hierarchy)
22888c2ecf20Sopenharmony_ci		hists__filter_hierarchy(hists, HIST_FILTER__SYMBOL,
22898c2ecf20Sopenharmony_ci					hists->symbol_filter_str);
22908c2ecf20Sopenharmony_ci	else
22918c2ecf20Sopenharmony_ci		hists__filter_by_type(hists, HIST_FILTER__SYMBOL,
22928c2ecf20Sopenharmony_ci				      hists__filter_entry_by_symbol);
22938c2ecf20Sopenharmony_ci}
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_civoid hists__filter_by_socket(struct hists *hists)
22968c2ecf20Sopenharmony_ci{
22978c2ecf20Sopenharmony_ci	if (symbol_conf.report_hierarchy)
22988c2ecf20Sopenharmony_ci		hists__filter_hierarchy(hists, HIST_FILTER__SOCKET,
22998c2ecf20Sopenharmony_ci					&hists->socket_filter);
23008c2ecf20Sopenharmony_ci	else
23018c2ecf20Sopenharmony_ci		hists__filter_by_type(hists, HIST_FILTER__SOCKET,
23028c2ecf20Sopenharmony_ci				      hists__filter_entry_by_socket);
23038c2ecf20Sopenharmony_ci}
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_civoid events_stats__inc(struct events_stats *stats, u32 type)
23068c2ecf20Sopenharmony_ci{
23078c2ecf20Sopenharmony_ci	++stats->nr_events[0];
23088c2ecf20Sopenharmony_ci	++stats->nr_events[type];
23098c2ecf20Sopenharmony_ci}
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_civoid hists__inc_nr_events(struct hists *hists, u32 type)
23128c2ecf20Sopenharmony_ci{
23138c2ecf20Sopenharmony_ci	events_stats__inc(&hists->stats, type);
23148c2ecf20Sopenharmony_ci}
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_civoid hists__inc_nr_samples(struct hists *hists, bool filtered)
23178c2ecf20Sopenharmony_ci{
23188c2ecf20Sopenharmony_ci	events_stats__inc(&hists->stats, PERF_RECORD_SAMPLE);
23198c2ecf20Sopenharmony_ci	if (!filtered)
23208c2ecf20Sopenharmony_ci		hists->stats.nr_non_filtered_samples++;
23218c2ecf20Sopenharmony_ci}
23228c2ecf20Sopenharmony_ci
23238c2ecf20Sopenharmony_cistatic struct hist_entry *hists__add_dummy_entry(struct hists *hists,
23248c2ecf20Sopenharmony_ci						 struct hist_entry *pair)
23258c2ecf20Sopenharmony_ci{
23268c2ecf20Sopenharmony_ci	struct rb_root_cached *root;
23278c2ecf20Sopenharmony_ci	struct rb_node **p;
23288c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
23298c2ecf20Sopenharmony_ci	struct hist_entry *he;
23308c2ecf20Sopenharmony_ci	int64_t cmp;
23318c2ecf20Sopenharmony_ci	bool leftmost = true;
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	if (hists__has(hists, need_collapse))
23348c2ecf20Sopenharmony_ci		root = &hists->entries_collapsed;
23358c2ecf20Sopenharmony_ci	else
23368c2ecf20Sopenharmony_ci		root = hists->entries_in;
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci	p = &root->rb_root.rb_node;
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci	while (*p != NULL) {
23418c2ecf20Sopenharmony_ci		parent = *p;
23428c2ecf20Sopenharmony_ci		he = rb_entry(parent, struct hist_entry, rb_node_in);
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci		cmp = hist_entry__collapse(he, pair);
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci		if (!cmp)
23478c2ecf20Sopenharmony_ci			goto out;
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci		if (cmp < 0)
23508c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
23518c2ecf20Sopenharmony_ci		else {
23528c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
23538c2ecf20Sopenharmony_ci			leftmost = false;
23548c2ecf20Sopenharmony_ci		}
23558c2ecf20Sopenharmony_ci	}
23568c2ecf20Sopenharmony_ci
23578c2ecf20Sopenharmony_ci	he = hist_entry__new(pair, true);
23588c2ecf20Sopenharmony_ci	if (he) {
23598c2ecf20Sopenharmony_ci		memset(&he->stat, 0, sizeof(he->stat));
23608c2ecf20Sopenharmony_ci		he->hists = hists;
23618c2ecf20Sopenharmony_ci		if (symbol_conf.cumulate_callchain)
23628c2ecf20Sopenharmony_ci			memset(he->stat_acc, 0, sizeof(he->stat));
23638c2ecf20Sopenharmony_ci		rb_link_node(&he->rb_node_in, parent, p);
23648c2ecf20Sopenharmony_ci		rb_insert_color_cached(&he->rb_node_in, root, leftmost);
23658c2ecf20Sopenharmony_ci		hists__inc_stats(hists, he);
23668c2ecf20Sopenharmony_ci		he->dummy = true;
23678c2ecf20Sopenharmony_ci	}
23688c2ecf20Sopenharmony_ciout:
23698c2ecf20Sopenharmony_ci	return he;
23708c2ecf20Sopenharmony_ci}
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_cistatic struct hist_entry *add_dummy_hierarchy_entry(struct hists *hists,
23738c2ecf20Sopenharmony_ci						    struct rb_root_cached *root,
23748c2ecf20Sopenharmony_ci						    struct hist_entry *pair)
23758c2ecf20Sopenharmony_ci{
23768c2ecf20Sopenharmony_ci	struct rb_node **p;
23778c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
23788c2ecf20Sopenharmony_ci	struct hist_entry *he;
23798c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt;
23808c2ecf20Sopenharmony_ci	bool leftmost = true;
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_ci	p = &root->rb_root.rb_node;
23838c2ecf20Sopenharmony_ci	while (*p != NULL) {
23848c2ecf20Sopenharmony_ci		int64_t cmp = 0;
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci		parent = *p;
23878c2ecf20Sopenharmony_ci		he = rb_entry(parent, struct hist_entry, rb_node_in);
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci		perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
23908c2ecf20Sopenharmony_ci			cmp = fmt->collapse(fmt, he, pair);
23918c2ecf20Sopenharmony_ci			if (cmp)
23928c2ecf20Sopenharmony_ci				break;
23938c2ecf20Sopenharmony_ci		}
23948c2ecf20Sopenharmony_ci		if (!cmp)
23958c2ecf20Sopenharmony_ci			goto out;
23968c2ecf20Sopenharmony_ci
23978c2ecf20Sopenharmony_ci		if (cmp < 0)
23988c2ecf20Sopenharmony_ci			p = &parent->rb_left;
23998c2ecf20Sopenharmony_ci		else {
24008c2ecf20Sopenharmony_ci			p = &parent->rb_right;
24018c2ecf20Sopenharmony_ci			leftmost = false;
24028c2ecf20Sopenharmony_ci		}
24038c2ecf20Sopenharmony_ci	}
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_ci	he = hist_entry__new(pair, true);
24068c2ecf20Sopenharmony_ci	if (he) {
24078c2ecf20Sopenharmony_ci		rb_link_node(&he->rb_node_in, parent, p);
24088c2ecf20Sopenharmony_ci		rb_insert_color_cached(&he->rb_node_in, root, leftmost);
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci		he->dummy = true;
24118c2ecf20Sopenharmony_ci		he->hists = hists;
24128c2ecf20Sopenharmony_ci		memset(&he->stat, 0, sizeof(he->stat));
24138c2ecf20Sopenharmony_ci		hists__inc_stats(hists, he);
24148c2ecf20Sopenharmony_ci	}
24158c2ecf20Sopenharmony_ciout:
24168c2ecf20Sopenharmony_ci	return he;
24178c2ecf20Sopenharmony_ci}
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_cistatic struct hist_entry *hists__find_entry(struct hists *hists,
24208c2ecf20Sopenharmony_ci					    struct hist_entry *he)
24218c2ecf20Sopenharmony_ci{
24228c2ecf20Sopenharmony_ci	struct rb_node *n;
24238c2ecf20Sopenharmony_ci
24248c2ecf20Sopenharmony_ci	if (hists__has(hists, need_collapse))
24258c2ecf20Sopenharmony_ci		n = hists->entries_collapsed.rb_root.rb_node;
24268c2ecf20Sopenharmony_ci	else
24278c2ecf20Sopenharmony_ci		n = hists->entries_in->rb_root.rb_node;
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ci	while (n) {
24308c2ecf20Sopenharmony_ci		struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in);
24318c2ecf20Sopenharmony_ci		int64_t cmp = hist_entry__collapse(iter, he);
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_ci		if (cmp < 0)
24348c2ecf20Sopenharmony_ci			n = n->rb_left;
24358c2ecf20Sopenharmony_ci		else if (cmp > 0)
24368c2ecf20Sopenharmony_ci			n = n->rb_right;
24378c2ecf20Sopenharmony_ci		else
24388c2ecf20Sopenharmony_ci			return iter;
24398c2ecf20Sopenharmony_ci	}
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci	return NULL;
24428c2ecf20Sopenharmony_ci}
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_cistatic struct hist_entry *hists__find_hierarchy_entry(struct rb_root_cached *root,
24458c2ecf20Sopenharmony_ci						      struct hist_entry *he)
24468c2ecf20Sopenharmony_ci{
24478c2ecf20Sopenharmony_ci	struct rb_node *n = root->rb_root.rb_node;
24488c2ecf20Sopenharmony_ci
24498c2ecf20Sopenharmony_ci	while (n) {
24508c2ecf20Sopenharmony_ci		struct hist_entry *iter;
24518c2ecf20Sopenharmony_ci		struct perf_hpp_fmt *fmt;
24528c2ecf20Sopenharmony_ci		int64_t cmp = 0;
24538c2ecf20Sopenharmony_ci
24548c2ecf20Sopenharmony_ci		iter = rb_entry(n, struct hist_entry, rb_node_in);
24558c2ecf20Sopenharmony_ci		perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
24568c2ecf20Sopenharmony_ci			cmp = fmt->collapse(fmt, iter, he);
24578c2ecf20Sopenharmony_ci			if (cmp)
24588c2ecf20Sopenharmony_ci				break;
24598c2ecf20Sopenharmony_ci		}
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci		if (cmp < 0)
24628c2ecf20Sopenharmony_ci			n = n->rb_left;
24638c2ecf20Sopenharmony_ci		else if (cmp > 0)
24648c2ecf20Sopenharmony_ci			n = n->rb_right;
24658c2ecf20Sopenharmony_ci		else
24668c2ecf20Sopenharmony_ci			return iter;
24678c2ecf20Sopenharmony_ci	}
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	return NULL;
24708c2ecf20Sopenharmony_ci}
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_cistatic void hists__match_hierarchy(struct rb_root_cached *leader_root,
24738c2ecf20Sopenharmony_ci				   struct rb_root_cached *other_root)
24748c2ecf20Sopenharmony_ci{
24758c2ecf20Sopenharmony_ci	struct rb_node *nd;
24768c2ecf20Sopenharmony_ci	struct hist_entry *pos, *pair;
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci	for (nd = rb_first_cached(leader_root); nd; nd = rb_next(nd)) {
24798c2ecf20Sopenharmony_ci		pos  = rb_entry(nd, struct hist_entry, rb_node_in);
24808c2ecf20Sopenharmony_ci		pair = hists__find_hierarchy_entry(other_root, pos);
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci		if (pair) {
24838c2ecf20Sopenharmony_ci			hist_entry__add_pair(pair, pos);
24848c2ecf20Sopenharmony_ci			hists__match_hierarchy(&pos->hroot_in, &pair->hroot_in);
24858c2ecf20Sopenharmony_ci		}
24868c2ecf20Sopenharmony_ci	}
24878c2ecf20Sopenharmony_ci}
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_ci/*
24908c2ecf20Sopenharmony_ci * Look for pairs to link to the leader buckets (hist_entries):
24918c2ecf20Sopenharmony_ci */
24928c2ecf20Sopenharmony_civoid hists__match(struct hists *leader, struct hists *other)
24938c2ecf20Sopenharmony_ci{
24948c2ecf20Sopenharmony_ci	struct rb_root_cached *root;
24958c2ecf20Sopenharmony_ci	struct rb_node *nd;
24968c2ecf20Sopenharmony_ci	struct hist_entry *pos, *pair;
24978c2ecf20Sopenharmony_ci
24988c2ecf20Sopenharmony_ci	if (symbol_conf.report_hierarchy) {
24998c2ecf20Sopenharmony_ci		/* hierarchy report always collapses entries */
25008c2ecf20Sopenharmony_ci		return hists__match_hierarchy(&leader->entries_collapsed,
25018c2ecf20Sopenharmony_ci					      &other->entries_collapsed);
25028c2ecf20Sopenharmony_ci	}
25038c2ecf20Sopenharmony_ci
25048c2ecf20Sopenharmony_ci	if (hists__has(leader, need_collapse))
25058c2ecf20Sopenharmony_ci		root = &leader->entries_collapsed;
25068c2ecf20Sopenharmony_ci	else
25078c2ecf20Sopenharmony_ci		root = leader->entries_in;
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci	for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
25108c2ecf20Sopenharmony_ci		pos  = rb_entry(nd, struct hist_entry, rb_node_in);
25118c2ecf20Sopenharmony_ci		pair = hists__find_entry(other, pos);
25128c2ecf20Sopenharmony_ci
25138c2ecf20Sopenharmony_ci		if (pair)
25148c2ecf20Sopenharmony_ci			hist_entry__add_pair(pair, pos);
25158c2ecf20Sopenharmony_ci	}
25168c2ecf20Sopenharmony_ci}
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_cistatic int hists__link_hierarchy(struct hists *leader_hists,
25198c2ecf20Sopenharmony_ci				 struct hist_entry *parent,
25208c2ecf20Sopenharmony_ci				 struct rb_root_cached *leader_root,
25218c2ecf20Sopenharmony_ci				 struct rb_root_cached *other_root)
25228c2ecf20Sopenharmony_ci{
25238c2ecf20Sopenharmony_ci	struct rb_node *nd;
25248c2ecf20Sopenharmony_ci	struct hist_entry *pos, *leader;
25258c2ecf20Sopenharmony_ci
25268c2ecf20Sopenharmony_ci	for (nd = rb_first_cached(other_root); nd; nd = rb_next(nd)) {
25278c2ecf20Sopenharmony_ci		pos = rb_entry(nd, struct hist_entry, rb_node_in);
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci		if (hist_entry__has_pairs(pos)) {
25308c2ecf20Sopenharmony_ci			bool found = false;
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_ci			list_for_each_entry(leader, &pos->pairs.head, pairs.node) {
25338c2ecf20Sopenharmony_ci				if (leader->hists == leader_hists) {
25348c2ecf20Sopenharmony_ci					found = true;
25358c2ecf20Sopenharmony_ci					break;
25368c2ecf20Sopenharmony_ci				}
25378c2ecf20Sopenharmony_ci			}
25388c2ecf20Sopenharmony_ci			if (!found)
25398c2ecf20Sopenharmony_ci				return -1;
25408c2ecf20Sopenharmony_ci		} else {
25418c2ecf20Sopenharmony_ci			leader = add_dummy_hierarchy_entry(leader_hists,
25428c2ecf20Sopenharmony_ci							   leader_root, pos);
25438c2ecf20Sopenharmony_ci			if (leader == NULL)
25448c2ecf20Sopenharmony_ci				return -1;
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci			/* do not point parent in the pos */
25478c2ecf20Sopenharmony_ci			leader->parent_he = parent;
25488c2ecf20Sopenharmony_ci
25498c2ecf20Sopenharmony_ci			hist_entry__add_pair(pos, leader);
25508c2ecf20Sopenharmony_ci		}
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci		if (!pos->leaf) {
25538c2ecf20Sopenharmony_ci			if (hists__link_hierarchy(leader_hists, leader,
25548c2ecf20Sopenharmony_ci						  &leader->hroot_in,
25558c2ecf20Sopenharmony_ci						  &pos->hroot_in) < 0)
25568c2ecf20Sopenharmony_ci				return -1;
25578c2ecf20Sopenharmony_ci		}
25588c2ecf20Sopenharmony_ci	}
25598c2ecf20Sopenharmony_ci	return 0;
25608c2ecf20Sopenharmony_ci}
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci/*
25638c2ecf20Sopenharmony_ci * Look for entries in the other hists that are not present in the leader, if
25648c2ecf20Sopenharmony_ci * we find them, just add a dummy entry on the leader hists, with period=0,
25658c2ecf20Sopenharmony_ci * nr_events=0, to serve as the list header.
25668c2ecf20Sopenharmony_ci */
25678c2ecf20Sopenharmony_ciint hists__link(struct hists *leader, struct hists *other)
25688c2ecf20Sopenharmony_ci{
25698c2ecf20Sopenharmony_ci	struct rb_root_cached *root;
25708c2ecf20Sopenharmony_ci	struct rb_node *nd;
25718c2ecf20Sopenharmony_ci	struct hist_entry *pos, *pair;
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci	if (symbol_conf.report_hierarchy) {
25748c2ecf20Sopenharmony_ci		/* hierarchy report always collapses entries */
25758c2ecf20Sopenharmony_ci		return hists__link_hierarchy(leader, NULL,
25768c2ecf20Sopenharmony_ci					     &leader->entries_collapsed,
25778c2ecf20Sopenharmony_ci					     &other->entries_collapsed);
25788c2ecf20Sopenharmony_ci	}
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	if (hists__has(other, need_collapse))
25818c2ecf20Sopenharmony_ci		root = &other->entries_collapsed;
25828c2ecf20Sopenharmony_ci	else
25838c2ecf20Sopenharmony_ci		root = other->entries_in;
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci	for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
25868c2ecf20Sopenharmony_ci		pos = rb_entry(nd, struct hist_entry, rb_node_in);
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci		if (!hist_entry__has_pairs(pos)) {
25898c2ecf20Sopenharmony_ci			pair = hists__add_dummy_entry(leader, pos);
25908c2ecf20Sopenharmony_ci			if (pair == NULL)
25918c2ecf20Sopenharmony_ci				return -1;
25928c2ecf20Sopenharmony_ci			hist_entry__add_pair(pos, pair);
25938c2ecf20Sopenharmony_ci		}
25948c2ecf20Sopenharmony_ci	}
25958c2ecf20Sopenharmony_ci
25968c2ecf20Sopenharmony_ci	return 0;
25978c2ecf20Sopenharmony_ci}
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ciint hists__unlink(struct hists *hists)
26008c2ecf20Sopenharmony_ci{
26018c2ecf20Sopenharmony_ci	struct rb_root_cached *root;
26028c2ecf20Sopenharmony_ci	struct rb_node *nd;
26038c2ecf20Sopenharmony_ci	struct hist_entry *pos;
26048c2ecf20Sopenharmony_ci
26058c2ecf20Sopenharmony_ci	if (hists__has(hists, need_collapse))
26068c2ecf20Sopenharmony_ci		root = &hists->entries_collapsed;
26078c2ecf20Sopenharmony_ci	else
26088c2ecf20Sopenharmony_ci		root = hists->entries_in;
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci	for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
26118c2ecf20Sopenharmony_ci		pos = rb_entry(nd, struct hist_entry, rb_node_in);
26128c2ecf20Sopenharmony_ci		list_del_init(&pos->pairs.node);
26138c2ecf20Sopenharmony_ci	}
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_ci	return 0;
26168c2ecf20Sopenharmony_ci}
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_civoid hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
26198c2ecf20Sopenharmony_ci			  struct perf_sample *sample, bool nonany_branch_mode,
26208c2ecf20Sopenharmony_ci			  u64 *total_cycles)
26218c2ecf20Sopenharmony_ci{
26228c2ecf20Sopenharmony_ci	struct branch_info *bi;
26238c2ecf20Sopenharmony_ci	struct branch_entry *entries = perf_sample__branch_entries(sample);
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci	/* If we have branch cycles always annotate them. */
26268c2ecf20Sopenharmony_ci	if (bs && bs->nr && entries[0].flags.cycles) {
26278c2ecf20Sopenharmony_ci		bi = sample__resolve_bstack(sample, al);
26288c2ecf20Sopenharmony_ci		if (bi) {
26298c2ecf20Sopenharmony_ci			struct addr_map_symbol *prev = NULL;
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci			/*
26328c2ecf20Sopenharmony_ci			 * Ignore errors, still want to process the
26338c2ecf20Sopenharmony_ci			 * other entries.
26348c2ecf20Sopenharmony_ci			 *
26358c2ecf20Sopenharmony_ci			 * For non standard branch modes always
26368c2ecf20Sopenharmony_ci			 * force no IPC (prev == NULL)
26378c2ecf20Sopenharmony_ci			 *
26388c2ecf20Sopenharmony_ci			 * Note that perf stores branches reversed from
26398c2ecf20Sopenharmony_ci			 * program order!
26408c2ecf20Sopenharmony_ci			 */
26418c2ecf20Sopenharmony_ci			for (int i = bs->nr - 1; i >= 0; i--) {
26428c2ecf20Sopenharmony_ci				addr_map_symbol__account_cycles(&bi[i].from,
26438c2ecf20Sopenharmony_ci					nonany_branch_mode ? NULL : prev,
26448c2ecf20Sopenharmony_ci					bi[i].flags.cycles);
26458c2ecf20Sopenharmony_ci				prev = &bi[i].to;
26468c2ecf20Sopenharmony_ci
26478c2ecf20Sopenharmony_ci				if (total_cycles)
26488c2ecf20Sopenharmony_ci					*total_cycles += bi[i].flags.cycles;
26498c2ecf20Sopenharmony_ci			}
26508c2ecf20Sopenharmony_ci			for (unsigned int i = 0; i < bs->nr; i++) {
26518c2ecf20Sopenharmony_ci				map__put(bi[i].to.ms.map);
26528c2ecf20Sopenharmony_ci				maps__put(bi[i].to.ms.maps);
26538c2ecf20Sopenharmony_ci				map__put(bi[i].from.ms.map);
26548c2ecf20Sopenharmony_ci				maps__put(bi[i].from.ms.maps);
26558c2ecf20Sopenharmony_ci			}
26568c2ecf20Sopenharmony_ci			free(bi);
26578c2ecf20Sopenharmony_ci		}
26588c2ecf20Sopenharmony_ci	}
26598c2ecf20Sopenharmony_ci}
26608c2ecf20Sopenharmony_ci
26618c2ecf20Sopenharmony_cisize_t perf_evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp)
26628c2ecf20Sopenharmony_ci{
26638c2ecf20Sopenharmony_ci	struct evsel *pos;
26648c2ecf20Sopenharmony_ci	size_t ret = 0;
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
26678c2ecf20Sopenharmony_ci		ret += fprintf(fp, "%s stats:\n", evsel__name(pos));
26688c2ecf20Sopenharmony_ci		ret += events_stats__fprintf(&evsel__hists(pos)->stats, fp);
26698c2ecf20Sopenharmony_ci	}
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_ci	return ret;
26728c2ecf20Sopenharmony_ci}
26738c2ecf20Sopenharmony_ci
26748c2ecf20Sopenharmony_ci
26758c2ecf20Sopenharmony_ciu64 hists__total_period(struct hists *hists)
26768c2ecf20Sopenharmony_ci{
26778c2ecf20Sopenharmony_ci	return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period :
26788c2ecf20Sopenharmony_ci		hists->stats.total_period;
26798c2ecf20Sopenharmony_ci}
26808c2ecf20Sopenharmony_ci
26818c2ecf20Sopenharmony_ciint __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool show_freq)
26828c2ecf20Sopenharmony_ci{
26838c2ecf20Sopenharmony_ci	char unit;
26848c2ecf20Sopenharmony_ci	int printed;
26858c2ecf20Sopenharmony_ci	const struct dso *dso = hists->dso_filter;
26868c2ecf20Sopenharmony_ci	struct thread *thread = hists->thread_filter;
26878c2ecf20Sopenharmony_ci	int socket_id = hists->socket_filter;
26888c2ecf20Sopenharmony_ci	unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
26898c2ecf20Sopenharmony_ci	u64 nr_events = hists->stats.total_period;
26908c2ecf20Sopenharmony_ci	struct evsel *evsel = hists_to_evsel(hists);
26918c2ecf20Sopenharmony_ci	const char *ev_name = evsel__name(evsel);
26928c2ecf20Sopenharmony_ci	char buf[512], sample_freq_str[64] = "";
26938c2ecf20Sopenharmony_ci	size_t buflen = sizeof(buf);
26948c2ecf20Sopenharmony_ci	char ref[30] = " show reference callgraph, ";
26958c2ecf20Sopenharmony_ci	bool enable_ref = false;
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci	if (symbol_conf.filter_relative) {
26988c2ecf20Sopenharmony_ci		nr_samples = hists->stats.nr_non_filtered_samples;
26998c2ecf20Sopenharmony_ci		nr_events = hists->stats.total_non_filtered_period;
27008c2ecf20Sopenharmony_ci	}
27018c2ecf20Sopenharmony_ci
27028c2ecf20Sopenharmony_ci	if (evsel__is_group_event(evsel)) {
27038c2ecf20Sopenharmony_ci		struct evsel *pos;
27048c2ecf20Sopenharmony_ci
27058c2ecf20Sopenharmony_ci		evsel__group_desc(evsel, buf, buflen);
27068c2ecf20Sopenharmony_ci		ev_name = buf;
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci		for_each_group_member(pos, evsel) {
27098c2ecf20Sopenharmony_ci			struct hists *pos_hists = evsel__hists(pos);
27108c2ecf20Sopenharmony_ci
27118c2ecf20Sopenharmony_ci			if (symbol_conf.filter_relative) {
27128c2ecf20Sopenharmony_ci				nr_samples += pos_hists->stats.nr_non_filtered_samples;
27138c2ecf20Sopenharmony_ci				nr_events += pos_hists->stats.total_non_filtered_period;
27148c2ecf20Sopenharmony_ci			} else {
27158c2ecf20Sopenharmony_ci				nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
27168c2ecf20Sopenharmony_ci				nr_events += pos_hists->stats.total_period;
27178c2ecf20Sopenharmony_ci			}
27188c2ecf20Sopenharmony_ci		}
27198c2ecf20Sopenharmony_ci	}
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci	if (symbol_conf.show_ref_callgraph &&
27228c2ecf20Sopenharmony_ci	    strstr(ev_name, "call-graph=no"))
27238c2ecf20Sopenharmony_ci		enable_ref = true;
27248c2ecf20Sopenharmony_ci
27258c2ecf20Sopenharmony_ci	if (show_freq)
27268c2ecf20Sopenharmony_ci		scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->core.attr.sample_freq);
27278c2ecf20Sopenharmony_ci
27288c2ecf20Sopenharmony_ci	nr_samples = convert_unit(nr_samples, &unit);
27298c2ecf20Sopenharmony_ci	printed = scnprintf(bf, size,
27308c2ecf20Sopenharmony_ci			   "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64,
27318c2ecf20Sopenharmony_ci			   nr_samples, unit, evsel->core.nr_members > 1 ? "s" : "",
27328c2ecf20Sopenharmony_ci			   ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events);
27338c2ecf20Sopenharmony_ci
27348c2ecf20Sopenharmony_ci
27358c2ecf20Sopenharmony_ci	if (hists->uid_filter_str)
27368c2ecf20Sopenharmony_ci		printed += snprintf(bf + printed, size - printed,
27378c2ecf20Sopenharmony_ci				    ", UID: %s", hists->uid_filter_str);
27388c2ecf20Sopenharmony_ci	if (thread) {
27398c2ecf20Sopenharmony_ci		if (hists__has(hists, thread)) {
27408c2ecf20Sopenharmony_ci			printed += scnprintf(bf + printed, size - printed,
27418c2ecf20Sopenharmony_ci				    ", Thread: %s(%d)",
27428c2ecf20Sopenharmony_ci				     (thread->comm_set ? thread__comm_str(thread) : ""),
27438c2ecf20Sopenharmony_ci				    thread->tid);
27448c2ecf20Sopenharmony_ci		} else {
27458c2ecf20Sopenharmony_ci			printed += scnprintf(bf + printed, size - printed,
27468c2ecf20Sopenharmony_ci				    ", Thread: %s",
27478c2ecf20Sopenharmony_ci				     (thread->comm_set ? thread__comm_str(thread) : ""));
27488c2ecf20Sopenharmony_ci		}
27498c2ecf20Sopenharmony_ci	}
27508c2ecf20Sopenharmony_ci	if (dso)
27518c2ecf20Sopenharmony_ci		printed += scnprintf(bf + printed, size - printed,
27528c2ecf20Sopenharmony_ci				    ", DSO: %s", dso->short_name);
27538c2ecf20Sopenharmony_ci	if (socket_id > -1)
27548c2ecf20Sopenharmony_ci		printed += scnprintf(bf + printed, size - printed,
27558c2ecf20Sopenharmony_ci				    ", Processor Socket: %d", socket_id);
27568c2ecf20Sopenharmony_ci
27578c2ecf20Sopenharmony_ci	return printed;
27588c2ecf20Sopenharmony_ci}
27598c2ecf20Sopenharmony_ci
27608c2ecf20Sopenharmony_ciint parse_filter_percentage(const struct option *opt __maybe_unused,
27618c2ecf20Sopenharmony_ci			    const char *arg, int unset __maybe_unused)
27628c2ecf20Sopenharmony_ci{
27638c2ecf20Sopenharmony_ci	if (!strcmp(arg, "relative"))
27648c2ecf20Sopenharmony_ci		symbol_conf.filter_relative = true;
27658c2ecf20Sopenharmony_ci	else if (!strcmp(arg, "absolute"))
27668c2ecf20Sopenharmony_ci		symbol_conf.filter_relative = false;
27678c2ecf20Sopenharmony_ci	else {
27688c2ecf20Sopenharmony_ci		pr_debug("Invalid percentage: %s\n", arg);
27698c2ecf20Sopenharmony_ci		return -1;
27708c2ecf20Sopenharmony_ci	}
27718c2ecf20Sopenharmony_ci
27728c2ecf20Sopenharmony_ci	return 0;
27738c2ecf20Sopenharmony_ci}
27748c2ecf20Sopenharmony_ci
27758c2ecf20Sopenharmony_ciint perf_hist_config(const char *var, const char *value)
27768c2ecf20Sopenharmony_ci{
27778c2ecf20Sopenharmony_ci	if (!strcmp(var, "hist.percentage"))
27788c2ecf20Sopenharmony_ci		return parse_filter_percentage(NULL, value, 0);
27798c2ecf20Sopenharmony_ci
27808c2ecf20Sopenharmony_ci	return 0;
27818c2ecf20Sopenharmony_ci}
27828c2ecf20Sopenharmony_ci
27838c2ecf20Sopenharmony_ciint __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list)
27848c2ecf20Sopenharmony_ci{
27858c2ecf20Sopenharmony_ci	memset(hists, 0, sizeof(*hists));
27868c2ecf20Sopenharmony_ci	hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT_CACHED;
27878c2ecf20Sopenharmony_ci	hists->entries_in = &hists->entries_in_array[0];
27888c2ecf20Sopenharmony_ci	hists->entries_collapsed = RB_ROOT_CACHED;
27898c2ecf20Sopenharmony_ci	hists->entries = RB_ROOT_CACHED;
27908c2ecf20Sopenharmony_ci	pthread_mutex_init(&hists->lock, NULL);
27918c2ecf20Sopenharmony_ci	hists->socket_filter = -1;
27928c2ecf20Sopenharmony_ci	hists->hpp_list = hpp_list;
27938c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&hists->hpp_formats);
27948c2ecf20Sopenharmony_ci	return 0;
27958c2ecf20Sopenharmony_ci}
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_cistatic void hists__delete_remaining_entries(struct rb_root_cached *root)
27988c2ecf20Sopenharmony_ci{
27998c2ecf20Sopenharmony_ci	struct rb_node *node;
28008c2ecf20Sopenharmony_ci	struct hist_entry *he;
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci	while (!RB_EMPTY_ROOT(&root->rb_root)) {
28038c2ecf20Sopenharmony_ci		node = rb_first_cached(root);
28048c2ecf20Sopenharmony_ci		rb_erase_cached(node, root);
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_ci		he = rb_entry(node, struct hist_entry, rb_node_in);
28078c2ecf20Sopenharmony_ci		hist_entry__delete(he);
28088c2ecf20Sopenharmony_ci	}
28098c2ecf20Sopenharmony_ci}
28108c2ecf20Sopenharmony_ci
28118c2ecf20Sopenharmony_cistatic void hists__delete_all_entries(struct hists *hists)
28128c2ecf20Sopenharmony_ci{
28138c2ecf20Sopenharmony_ci	hists__delete_entries(hists);
28148c2ecf20Sopenharmony_ci	hists__delete_remaining_entries(&hists->entries_in_array[0]);
28158c2ecf20Sopenharmony_ci	hists__delete_remaining_entries(&hists->entries_in_array[1]);
28168c2ecf20Sopenharmony_ci	hists__delete_remaining_entries(&hists->entries_collapsed);
28178c2ecf20Sopenharmony_ci}
28188c2ecf20Sopenharmony_ci
28198c2ecf20Sopenharmony_cistatic void hists_evsel__exit(struct evsel *evsel)
28208c2ecf20Sopenharmony_ci{
28218c2ecf20Sopenharmony_ci	struct hists *hists = evsel__hists(evsel);
28228c2ecf20Sopenharmony_ci	struct perf_hpp_fmt *fmt, *pos;
28238c2ecf20Sopenharmony_ci	struct perf_hpp_list_node *node, *tmp;
28248c2ecf20Sopenharmony_ci
28258c2ecf20Sopenharmony_ci	hists__delete_all_entries(hists);
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_ci	list_for_each_entry_safe(node, tmp, &hists->hpp_formats, list) {
28288c2ecf20Sopenharmony_ci		perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
28298c2ecf20Sopenharmony_ci			list_del_init(&fmt->list);
28308c2ecf20Sopenharmony_ci			free(fmt);
28318c2ecf20Sopenharmony_ci		}
28328c2ecf20Sopenharmony_ci		list_del_init(&node->list);
28338c2ecf20Sopenharmony_ci		free(node);
28348c2ecf20Sopenharmony_ci	}
28358c2ecf20Sopenharmony_ci}
28368c2ecf20Sopenharmony_ci
28378c2ecf20Sopenharmony_cistatic int hists_evsel__init(struct evsel *evsel)
28388c2ecf20Sopenharmony_ci{
28398c2ecf20Sopenharmony_ci	struct hists *hists = evsel__hists(evsel);
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci	__hists__init(hists, &perf_hpp_list);
28428c2ecf20Sopenharmony_ci	return 0;
28438c2ecf20Sopenharmony_ci}
28448c2ecf20Sopenharmony_ci
28458c2ecf20Sopenharmony_ci/*
28468c2ecf20Sopenharmony_ci * XXX We probably need a hists_evsel__exit() to free the hist_entries
28478c2ecf20Sopenharmony_ci * stored in the rbtree...
28488c2ecf20Sopenharmony_ci */
28498c2ecf20Sopenharmony_ci
28508c2ecf20Sopenharmony_ciint hists__init(void)
28518c2ecf20Sopenharmony_ci{
28528c2ecf20Sopenharmony_ci	int err = evsel__object_config(sizeof(struct hists_evsel),
28538c2ecf20Sopenharmony_ci				       hists_evsel__init, hists_evsel__exit);
28548c2ecf20Sopenharmony_ci	if (err)
28558c2ecf20Sopenharmony_ci		fputs("FATAL ERROR: Couldn't setup hists class\n", stderr);
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ci	return err;
28588c2ecf20Sopenharmony_ci}
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_civoid perf_hpp_list__init(struct perf_hpp_list *list)
28618c2ecf20Sopenharmony_ci{
28628c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&list->fields);
28638c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&list->sorts);
28648c2ecf20Sopenharmony_ci}
2865