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