162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <errno.h>
362306a36Sopenharmony_ci#include <inttypes.h>
462306a36Sopenharmony_ci#include <regex.h>
562306a36Sopenharmony_ci#include <stdlib.h>
662306a36Sopenharmony_ci#include <linux/mman.h>
762306a36Sopenharmony_ci#include <linux/time64.h>
862306a36Sopenharmony_ci#include "debug.h"
962306a36Sopenharmony_ci#include "dso.h"
1062306a36Sopenharmony_ci#include "sort.h"
1162306a36Sopenharmony_ci#include "hist.h"
1262306a36Sopenharmony_ci#include "cacheline.h"
1362306a36Sopenharmony_ci#include "comm.h"
1462306a36Sopenharmony_ci#include "map.h"
1562306a36Sopenharmony_ci#include "maps.h"
1662306a36Sopenharmony_ci#include "symbol.h"
1762306a36Sopenharmony_ci#include "map_symbol.h"
1862306a36Sopenharmony_ci#include "branch.h"
1962306a36Sopenharmony_ci#include "thread.h"
2062306a36Sopenharmony_ci#include "evsel.h"
2162306a36Sopenharmony_ci#include "evlist.h"
2262306a36Sopenharmony_ci#include "srcline.h"
2362306a36Sopenharmony_ci#include "strlist.h"
2462306a36Sopenharmony_ci#include "strbuf.h"
2562306a36Sopenharmony_ci#include "mem-events.h"
2662306a36Sopenharmony_ci#include "annotate.h"
2762306a36Sopenharmony_ci#include "event.h"
2862306a36Sopenharmony_ci#include "time-utils.h"
2962306a36Sopenharmony_ci#include "cgroup.h"
3062306a36Sopenharmony_ci#include "machine.h"
3162306a36Sopenharmony_ci#include "trace-event.h"
3262306a36Sopenharmony_ci#include <linux/kernel.h>
3362306a36Sopenharmony_ci#include <linux/string.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
3662306a36Sopenharmony_ci#include <traceevent/event-parse.h>
3762306a36Sopenharmony_ci#endif
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ciregex_t		parent_regex;
4062306a36Sopenharmony_ciconst char	default_parent_pattern[] = "^sys_|^do_page_fault";
4162306a36Sopenharmony_ciconst char	*parent_pattern = default_parent_pattern;
4262306a36Sopenharmony_ciconst char	*default_sort_order = "comm,dso,symbol";
4362306a36Sopenharmony_ciconst char	default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles";
4462306a36Sopenharmony_ciconst char	default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked,blocked,local_ins_lat,local_p_stage_cyc";
4562306a36Sopenharmony_ciconst char	default_top_sort_order[] = "dso,symbol";
4662306a36Sopenharmony_ciconst char	default_diff_sort_order[] = "dso,symbol";
4762306a36Sopenharmony_ciconst char	default_tracepoint_sort_order[] = "trace";
4862306a36Sopenharmony_ciconst char	*sort_order;
4962306a36Sopenharmony_ciconst char	*field_order;
5062306a36Sopenharmony_ciregex_t		ignore_callees_regex;
5162306a36Sopenharmony_ciint		have_ignore_callees = 0;
5262306a36Sopenharmony_cienum sort_mode	sort__mode = SORT_MODE__NORMAL;
5362306a36Sopenharmony_cistatic const char *const dynamic_headers[] = {"local_ins_lat", "ins_lat", "local_p_stage_cyc", "p_stage_cyc"};
5462306a36Sopenharmony_cistatic const char *const arch_specific_sort_keys[] = {"local_p_stage_cyc", "p_stage_cyc"};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/*
5762306a36Sopenharmony_ci * Some architectures have Adjacent Cacheline Prefetch feature, which
5862306a36Sopenharmony_ci * behaves like the cacheline size is doubled. Enable this flag to
5962306a36Sopenharmony_ci * check things in double cacheline granularity.
6062306a36Sopenharmony_ci */
6162306a36Sopenharmony_cibool chk_double_cl;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/*
6462306a36Sopenharmony_ci * Replaces all occurrences of a char used with the:
6562306a36Sopenharmony_ci *
6662306a36Sopenharmony_ci * -t, --field-separator
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * option, that uses a special separator character and don't pad with spaces,
6962306a36Sopenharmony_ci * replacing all occurrences of this separator in symbol names (and other
7062306a36Sopenharmony_ci * output) with a '.' character, that thus it's the only non valid separator.
7162306a36Sopenharmony_ci*/
7262306a36Sopenharmony_cistatic int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	int n;
7562306a36Sopenharmony_ci	va_list ap;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	va_start(ap, fmt);
7862306a36Sopenharmony_ci	n = vsnprintf(bf, size, fmt, ap);
7962306a36Sopenharmony_ci	if (symbol_conf.field_sep && n > 0) {
8062306a36Sopenharmony_ci		char *sep = bf;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci		while (1) {
8362306a36Sopenharmony_ci			sep = strchr(sep, *symbol_conf.field_sep);
8462306a36Sopenharmony_ci			if (sep == NULL)
8562306a36Sopenharmony_ci				break;
8662306a36Sopenharmony_ci			*sep = '.';
8762306a36Sopenharmony_ci		}
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci	va_end(ap);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (n >= (int)size)
9262306a36Sopenharmony_ci		return size - 1;
9362306a36Sopenharmony_ci	return n;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic int64_t cmp_null(const void *l, const void *r)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	if (!l && !r)
9962306a36Sopenharmony_ci		return 0;
10062306a36Sopenharmony_ci	else if (!l)
10162306a36Sopenharmony_ci		return -1;
10262306a36Sopenharmony_ci	else
10362306a36Sopenharmony_ci		return 1;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/* --sort pid */
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic int64_t
10962306a36Sopenharmony_cisort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	return thread__tid(right->thread) - thread__tid(left->thread);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
11562306a36Sopenharmony_ci				       size_t size, unsigned int width)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	const char *comm = thread__comm_str(he->thread);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	width = max(7U, width) - 8;
12062306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%7d:%-*.*s", thread__tid(he->thread),
12162306a36Sopenharmony_ci			       width, width, comm ?: "");
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic int hist_entry__thread_filter(struct hist_entry *he, int type, const void *arg)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	const struct thread *th = arg;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	if (type != HIST_FILTER__THREAD)
12962306a36Sopenharmony_ci		return -1;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	return th && RC_CHK_ACCESS(he->thread) != RC_CHK_ACCESS(th);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistruct sort_entry sort_thread = {
13562306a36Sopenharmony_ci	.se_header	= "    Pid:Command",
13662306a36Sopenharmony_ci	.se_cmp		= sort__thread_cmp,
13762306a36Sopenharmony_ci	.se_snprintf	= hist_entry__thread_snprintf,
13862306a36Sopenharmony_ci	.se_filter	= hist_entry__thread_filter,
13962306a36Sopenharmony_ci	.se_width_idx	= HISTC_THREAD,
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/* --sort simd */
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int64_t
14562306a36Sopenharmony_cisort__simd_cmp(struct hist_entry *left, struct hist_entry *right)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	if (left->simd_flags.arch != right->simd_flags.arch)
14862306a36Sopenharmony_ci		return (int64_t) left->simd_flags.arch - right->simd_flags.arch;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return (int64_t) left->simd_flags.pred - right->simd_flags.pred;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic const char *hist_entry__get_simd_name(struct simd_flags *simd_flags)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	u64 arch = simd_flags->arch;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (arch & SIMD_OP_FLAGS_ARCH_SVE)
15862306a36Sopenharmony_ci		return "SVE";
15962306a36Sopenharmony_ci	else
16062306a36Sopenharmony_ci		return "n/a";
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic int hist_entry__simd_snprintf(struct hist_entry *he, char *bf,
16462306a36Sopenharmony_ci				     size_t size, unsigned int width __maybe_unused)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	const char *name;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (!he->simd_flags.arch)
16962306a36Sopenharmony_ci		return repsep_snprintf(bf, size, "");
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	name = hist_entry__get_simd_name(&he->simd_flags);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	if (he->simd_flags.pred & SIMD_OP_FLAGS_PRED_EMPTY)
17462306a36Sopenharmony_ci		return repsep_snprintf(bf, size, "[e] %s", name);
17562306a36Sopenharmony_ci	else if (he->simd_flags.pred & SIMD_OP_FLAGS_PRED_PARTIAL)
17662306a36Sopenharmony_ci		return repsep_snprintf(bf, size, "[p] %s", name);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "[.] %s", name);
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistruct sort_entry sort_simd = {
18262306a36Sopenharmony_ci	.se_header	= "Simd   ",
18362306a36Sopenharmony_ci	.se_cmp		= sort__simd_cmp,
18462306a36Sopenharmony_ci	.se_snprintf	= hist_entry__simd_snprintf,
18562306a36Sopenharmony_ci	.se_width_idx	= HISTC_SIMD,
18662306a36Sopenharmony_ci};
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/* --sort comm */
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/*
19162306a36Sopenharmony_ci * We can't use pointer comparison in functions below,
19262306a36Sopenharmony_ci * because it gives different results based on pointer
19362306a36Sopenharmony_ci * values, which could break some sorting assumptions.
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_cistatic int64_t
19662306a36Sopenharmony_cisort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	return strcmp(comm__str(right->comm), comm__str(left->comm));
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic int64_t
20262306a36Sopenharmony_cisort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	return strcmp(comm__str(right->comm), comm__str(left->comm));
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic int64_t
20862306a36Sopenharmony_cisort__comm_sort(struct hist_entry *left, struct hist_entry *right)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	return strcmp(comm__str(right->comm), comm__str(left->comm));
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
21462306a36Sopenharmony_ci				     size_t size, unsigned int width)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistruct sort_entry sort_comm = {
22062306a36Sopenharmony_ci	.se_header	= "Command",
22162306a36Sopenharmony_ci	.se_cmp		= sort__comm_cmp,
22262306a36Sopenharmony_ci	.se_collapse	= sort__comm_collapse,
22362306a36Sopenharmony_ci	.se_sort	= sort__comm_sort,
22462306a36Sopenharmony_ci	.se_snprintf	= hist_entry__comm_snprintf,
22562306a36Sopenharmony_ci	.se_filter	= hist_entry__thread_filter,
22662306a36Sopenharmony_ci	.se_width_idx	= HISTC_COMM,
22762306a36Sopenharmony_ci};
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci/* --sort dso */
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	struct dso *dso_l = map_l ? map__dso(map_l) : NULL;
23462306a36Sopenharmony_ci	struct dso *dso_r = map_r ? map__dso(map_r) : NULL;
23562306a36Sopenharmony_ci	const char *dso_name_l, *dso_name_r;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (!dso_l || !dso_r)
23862306a36Sopenharmony_ci		return cmp_null(dso_r, dso_l);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	if (verbose > 0) {
24162306a36Sopenharmony_ci		dso_name_l = dso_l->long_name;
24262306a36Sopenharmony_ci		dso_name_r = dso_r->long_name;
24362306a36Sopenharmony_ci	} else {
24462306a36Sopenharmony_ci		dso_name_l = dso_l->short_name;
24562306a36Sopenharmony_ci		dso_name_r = dso_r->short_name;
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return strcmp(dso_name_l, dso_name_r);
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int64_t
25262306a36Sopenharmony_cisort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	return _sort__dso_cmp(right->ms.map, left->ms.map);
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic int _hist_entry__dso_snprintf(struct map *map, char *bf,
25862306a36Sopenharmony_ci				     size_t size, unsigned int width)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	const struct dso *dso = map ? map__dso(map) : NULL;
26162306a36Sopenharmony_ci	const char *dso_name = "[unknown]";
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	if (dso)
26462306a36Sopenharmony_ci		dso_name = verbose > 0 ? dso->long_name : dso->short_name;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
27062306a36Sopenharmony_ci				    size_t size, unsigned int width)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic int hist_entry__dso_filter(struct hist_entry *he, int type, const void *arg)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	const struct dso *dso = arg;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	if (type != HIST_FILTER__DSO)
28062306a36Sopenharmony_ci		return -1;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	return dso && (!he->ms.map || map__dso(he->ms.map) != dso);
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistruct sort_entry sort_dso = {
28662306a36Sopenharmony_ci	.se_header	= "Shared Object",
28762306a36Sopenharmony_ci	.se_cmp		= sort__dso_cmp,
28862306a36Sopenharmony_ci	.se_snprintf	= hist_entry__dso_snprintf,
28962306a36Sopenharmony_ci	.se_filter	= hist_entry__dso_filter,
29062306a36Sopenharmony_ci	.se_width_idx	= HISTC_DSO,
29162306a36Sopenharmony_ci};
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci/* --sort symbol */
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	return (int64_t)(right_ip - left_ip);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ciint64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	if (!sym_l || !sym_r)
30362306a36Sopenharmony_ci		return cmp_null(sym_l, sym_r);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (sym_l == sym_r)
30662306a36Sopenharmony_ci		return 0;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (sym_l->inlined || sym_r->inlined) {
30962306a36Sopenharmony_ci		int ret = strcmp(sym_l->name, sym_r->name);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci		if (ret)
31262306a36Sopenharmony_ci			return ret;
31362306a36Sopenharmony_ci		if ((sym_l->start <= sym_r->end) && (sym_l->end >= sym_r->start))
31462306a36Sopenharmony_ci			return 0;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (sym_l->start != sym_r->start)
31862306a36Sopenharmony_ci		return (int64_t)(sym_r->start - sym_l->start);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	return (int64_t)(sym_r->end - sym_l->end);
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic int64_t
32462306a36Sopenharmony_cisort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	int64_t ret;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (!left->ms.sym && !right->ms.sym)
32962306a36Sopenharmony_ci		return _sort__addr_cmp(left->ip, right->ip);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/*
33262306a36Sopenharmony_ci	 * comparing symbol address alone is not enough since it's a
33362306a36Sopenharmony_ci	 * relative address within a dso.
33462306a36Sopenharmony_ci	 */
33562306a36Sopenharmony_ci	if (!hists__has(left->hists, dso) || hists__has(right->hists, dso)) {
33662306a36Sopenharmony_ci		ret = sort__dso_cmp(left, right);
33762306a36Sopenharmony_ci		if (ret != 0)
33862306a36Sopenharmony_ci			return ret;
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	return _sort__sym_cmp(left->ms.sym, right->ms.sym);
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic int64_t
34562306a36Sopenharmony_cisort__sym_sort(struct hist_entry *left, struct hist_entry *right)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	if (!left->ms.sym || !right->ms.sym)
34862306a36Sopenharmony_ci		return cmp_null(left->ms.sym, right->ms.sym);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	return strcmp(right->ms.sym->name, left->ms.sym->name);
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic int _hist_entry__sym_snprintf(struct map_symbol *ms,
35462306a36Sopenharmony_ci				     u64 ip, char level, char *bf, size_t size,
35562306a36Sopenharmony_ci				     unsigned int width)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct symbol *sym = ms->sym;
35862306a36Sopenharmony_ci	struct map *map = ms->map;
35962306a36Sopenharmony_ci	size_t ret = 0;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (verbose > 0) {
36262306a36Sopenharmony_ci		struct dso *dso = map ? map__dso(map) : NULL;
36362306a36Sopenharmony_ci		char o = dso ? dso__symtab_origin(dso) : '!';
36462306a36Sopenharmony_ci		u64 rip = ip;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci		if (dso && dso->kernel && dso->adjust_symbols)
36762306a36Sopenharmony_ci			rip = map__unmap_ip(map, ip);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci		ret += repsep_snprintf(bf, size, "%-#*llx %c ",
37062306a36Sopenharmony_ci				       BITS_PER_LONG / 4 + 2, rip, o);
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
37462306a36Sopenharmony_ci	if (sym && map) {
37562306a36Sopenharmony_ci		if (sym->type == STT_OBJECT) {
37662306a36Sopenharmony_ci			ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
37762306a36Sopenharmony_ci			ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
37862306a36Sopenharmony_ci					ip - map__unmap_ip(map, sym->start));
37962306a36Sopenharmony_ci		} else {
38062306a36Sopenharmony_ci			ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
38162306a36Sopenharmony_ci					       width - ret,
38262306a36Sopenharmony_ci					       sym->name);
38362306a36Sopenharmony_ci			if (sym->inlined)
38462306a36Sopenharmony_ci				ret += repsep_snprintf(bf + ret, size - ret,
38562306a36Sopenharmony_ci						       " (inlined)");
38662306a36Sopenharmony_ci		}
38762306a36Sopenharmony_ci	} else {
38862306a36Sopenharmony_ci		size_t len = BITS_PER_LONG / 4;
38962306a36Sopenharmony_ci		ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
39062306a36Sopenharmony_ci				       len, ip);
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return ret;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ciint hist_entry__sym_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	return _hist_entry__sym_snprintf(&he->ms, he->ip,
39962306a36Sopenharmony_ci					 he->level, bf, size, width);
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic int hist_entry__sym_filter(struct hist_entry *he, int type, const void *arg)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	const char *sym = arg;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	if (type != HIST_FILTER__SYMBOL)
40762306a36Sopenharmony_ci		return -1;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	return sym && (!he->ms.sym || !strstr(he->ms.sym->name, sym));
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistruct sort_entry sort_sym = {
41362306a36Sopenharmony_ci	.se_header	= "Symbol",
41462306a36Sopenharmony_ci	.se_cmp		= sort__sym_cmp,
41562306a36Sopenharmony_ci	.se_sort	= sort__sym_sort,
41662306a36Sopenharmony_ci	.se_snprintf	= hist_entry__sym_snprintf,
41762306a36Sopenharmony_ci	.se_filter	= hist_entry__sym_filter,
41862306a36Sopenharmony_ci	.se_width_idx	= HISTC_SYMBOL,
41962306a36Sopenharmony_ci};
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci/* --sort srcline */
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cichar *hist_entry__srcline(struct hist_entry *he)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	return map__srcline(he->ms.map, he->ip, he->ms.sym);
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic int64_t
42962306a36Sopenharmony_cisort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	int64_t ret;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	ret = _sort__addr_cmp(left->ip, right->ip);
43462306a36Sopenharmony_ci	if (ret)
43562306a36Sopenharmony_ci		return ret;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	return sort__dso_cmp(left, right);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic int64_t
44162306a36Sopenharmony_cisort__srcline_collapse(struct hist_entry *left, struct hist_entry *right)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	if (!left->srcline)
44462306a36Sopenharmony_ci		left->srcline = hist_entry__srcline(left);
44562306a36Sopenharmony_ci	if (!right->srcline)
44662306a36Sopenharmony_ci		right->srcline = hist_entry__srcline(right);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	return strcmp(right->srcline, left->srcline);
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic int64_t
45262306a36Sopenharmony_cisort__srcline_sort(struct hist_entry *left, struct hist_entry *right)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	return sort__srcline_collapse(left, right);
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic void
45862306a36Sopenharmony_cisort__srcline_init(struct hist_entry *he)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	if (!he->srcline)
46162306a36Sopenharmony_ci		he->srcline = hist_entry__srcline(he);
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
46562306a36Sopenharmony_ci					size_t size, unsigned int width)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-.*s", width, he->srcline);
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistruct sort_entry sort_srcline = {
47162306a36Sopenharmony_ci	.se_header	= "Source:Line",
47262306a36Sopenharmony_ci	.se_cmp		= sort__srcline_cmp,
47362306a36Sopenharmony_ci	.se_collapse	= sort__srcline_collapse,
47462306a36Sopenharmony_ci	.se_sort	= sort__srcline_sort,
47562306a36Sopenharmony_ci	.se_init	= sort__srcline_init,
47662306a36Sopenharmony_ci	.se_snprintf	= hist_entry__srcline_snprintf,
47762306a36Sopenharmony_ci	.se_width_idx	= HISTC_SRCLINE,
47862306a36Sopenharmony_ci};
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci/* --sort srcline_from */
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic char *addr_map_symbol__srcline(struct addr_map_symbol *ams)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	return map__srcline(ams->ms.map, ams->al_addr, ams->ms.sym);
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic int64_t
48862306a36Sopenharmony_cisort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	return left->branch_info->from.addr - right->branch_info->from.addr;
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic int64_t
49462306a36Sopenharmony_cisort__srcline_from_collapse(struct hist_entry *left, struct hist_entry *right)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	if (!left->branch_info->srcline_from)
49762306a36Sopenharmony_ci		left->branch_info->srcline_from = addr_map_symbol__srcline(&left->branch_info->from);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if (!right->branch_info->srcline_from)
50062306a36Sopenharmony_ci		right->branch_info->srcline_from = addr_map_symbol__srcline(&right->branch_info->from);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from);
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic int64_t
50662306a36Sopenharmony_cisort__srcline_from_sort(struct hist_entry *left, struct hist_entry *right)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	return sort__srcline_from_collapse(left, right);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic void sort__srcline_from_init(struct hist_entry *he)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	if (!he->branch_info->srcline_from)
51462306a36Sopenharmony_ci		he->branch_info->srcline_from = addr_map_symbol__srcline(&he->branch_info->from);
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic int hist_entry__srcline_from_snprintf(struct hist_entry *he, char *bf,
51862306a36Sopenharmony_ci					size_t size, unsigned int width)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_from);
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_cistruct sort_entry sort_srcline_from = {
52462306a36Sopenharmony_ci	.se_header	= "From Source:Line",
52562306a36Sopenharmony_ci	.se_cmp		= sort__srcline_from_cmp,
52662306a36Sopenharmony_ci	.se_collapse	= sort__srcline_from_collapse,
52762306a36Sopenharmony_ci	.se_sort	= sort__srcline_from_sort,
52862306a36Sopenharmony_ci	.se_init	= sort__srcline_from_init,
52962306a36Sopenharmony_ci	.se_snprintf	= hist_entry__srcline_from_snprintf,
53062306a36Sopenharmony_ci	.se_width_idx	= HISTC_SRCLINE_FROM,
53162306a36Sopenharmony_ci};
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci/* --sort srcline_to */
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic int64_t
53662306a36Sopenharmony_cisort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	return left->branch_info->to.addr - right->branch_info->to.addr;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic int64_t
54262306a36Sopenharmony_cisort__srcline_to_collapse(struct hist_entry *left, struct hist_entry *right)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	if (!left->branch_info->srcline_to)
54562306a36Sopenharmony_ci		left->branch_info->srcline_to = addr_map_symbol__srcline(&left->branch_info->to);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	if (!right->branch_info->srcline_to)
54862306a36Sopenharmony_ci		right->branch_info->srcline_to = addr_map_symbol__srcline(&right->branch_info->to);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to);
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic int64_t
55462306a36Sopenharmony_cisort__srcline_to_sort(struct hist_entry *left, struct hist_entry *right)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	return sort__srcline_to_collapse(left, right);
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic void sort__srcline_to_init(struct hist_entry *he)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	if (!he->branch_info->srcline_to)
56262306a36Sopenharmony_ci		he->branch_info->srcline_to = addr_map_symbol__srcline(&he->branch_info->to);
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic int hist_entry__srcline_to_snprintf(struct hist_entry *he, char *bf,
56662306a36Sopenharmony_ci					size_t size, unsigned int width)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_to);
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_cistruct sort_entry sort_srcline_to = {
57262306a36Sopenharmony_ci	.se_header	= "To Source:Line",
57362306a36Sopenharmony_ci	.se_cmp		= sort__srcline_to_cmp,
57462306a36Sopenharmony_ci	.se_collapse	= sort__srcline_to_collapse,
57562306a36Sopenharmony_ci	.se_sort	= sort__srcline_to_sort,
57662306a36Sopenharmony_ci	.se_init	= sort__srcline_to_init,
57762306a36Sopenharmony_ci	.se_snprintf	= hist_entry__srcline_to_snprintf,
57862306a36Sopenharmony_ci	.se_width_idx	= HISTC_SRCLINE_TO,
57962306a36Sopenharmony_ci};
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic int hist_entry__sym_ipc_snprintf(struct hist_entry *he, char *bf,
58262306a36Sopenharmony_ci					size_t size, unsigned int width)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	struct symbol *sym = he->ms.sym;
58662306a36Sopenharmony_ci	struct annotation *notes;
58762306a36Sopenharmony_ci	double ipc = 0.0, coverage = 0.0;
58862306a36Sopenharmony_ci	char tmp[64];
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	if (!sym)
59162306a36Sopenharmony_ci		return repsep_snprintf(bf, size, "%-*s", width, "-");
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	notes = symbol__annotation(sym);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	if (notes->hit_cycles)
59662306a36Sopenharmony_ci		ipc = notes->hit_insn / ((double)notes->hit_cycles);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	if (notes->total_insn) {
59962306a36Sopenharmony_ci		coverage = notes->cover_insn * 100.0 /
60062306a36Sopenharmony_ci			((double)notes->total_insn);
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	snprintf(tmp, sizeof(tmp), "%-5.2f [%5.1f%%]", ipc, coverage);
60462306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*s", width, tmp);
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistruct sort_entry sort_sym_ipc = {
60862306a36Sopenharmony_ci	.se_header	= "IPC   [IPC Coverage]",
60962306a36Sopenharmony_ci	.se_cmp		= sort__sym_cmp,
61062306a36Sopenharmony_ci	.se_snprintf	= hist_entry__sym_ipc_snprintf,
61162306a36Sopenharmony_ci	.se_width_idx	= HISTC_SYMBOL_IPC,
61262306a36Sopenharmony_ci};
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_cistatic int hist_entry__sym_ipc_null_snprintf(struct hist_entry *he
61562306a36Sopenharmony_ci					     __maybe_unused,
61662306a36Sopenharmony_ci					     char *bf, size_t size,
61762306a36Sopenharmony_ci					     unsigned int width)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	char tmp[64];
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	snprintf(tmp, sizeof(tmp), "%-5s %2s", "-", "-");
62262306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*s", width, tmp);
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistruct sort_entry sort_sym_ipc_null = {
62662306a36Sopenharmony_ci	.se_header	= "IPC   [IPC Coverage]",
62762306a36Sopenharmony_ci	.se_cmp		= sort__sym_cmp,
62862306a36Sopenharmony_ci	.se_snprintf	= hist_entry__sym_ipc_null_snprintf,
62962306a36Sopenharmony_ci	.se_width_idx	= HISTC_SYMBOL_IPC,
63062306a36Sopenharmony_ci};
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci/* --sort srcfile */
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic char no_srcfile[1];
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic char *hist_entry__get_srcfile(struct hist_entry *e)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	char *sf, *p;
63962306a36Sopenharmony_ci	struct map *map = e->ms.map;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	if (!map)
64262306a36Sopenharmony_ci		return no_srcfile;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	sf = __get_srcline(map__dso(map), map__rip_2objdump(map, e->ip),
64562306a36Sopenharmony_ci			 e->ms.sym, false, true, true, e->ip);
64662306a36Sopenharmony_ci	if (sf == SRCLINE_UNKNOWN)
64762306a36Sopenharmony_ci		return no_srcfile;
64862306a36Sopenharmony_ci	p = strchr(sf, ':');
64962306a36Sopenharmony_ci	if (p && *sf) {
65062306a36Sopenharmony_ci		*p = 0;
65162306a36Sopenharmony_ci		return sf;
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci	free(sf);
65462306a36Sopenharmony_ci	return no_srcfile;
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic int64_t
65862306a36Sopenharmony_cisort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	return sort__srcline_cmp(left, right);
66162306a36Sopenharmony_ci}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_cistatic int64_t
66462306a36Sopenharmony_cisort__srcfile_collapse(struct hist_entry *left, struct hist_entry *right)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	if (!left->srcfile)
66762306a36Sopenharmony_ci		left->srcfile = hist_entry__get_srcfile(left);
66862306a36Sopenharmony_ci	if (!right->srcfile)
66962306a36Sopenharmony_ci		right->srcfile = hist_entry__get_srcfile(right);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	return strcmp(right->srcfile, left->srcfile);
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic int64_t
67562306a36Sopenharmony_cisort__srcfile_sort(struct hist_entry *left, struct hist_entry *right)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	return sort__srcfile_collapse(left, right);
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic void sort__srcfile_init(struct hist_entry *he)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	if (!he->srcfile)
68362306a36Sopenharmony_ci		he->srcfile = hist_entry__get_srcfile(he);
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cistatic int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
68762306a36Sopenharmony_ci					size_t size, unsigned int width)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-.*s", width, he->srcfile);
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistruct sort_entry sort_srcfile = {
69362306a36Sopenharmony_ci	.se_header	= "Source File",
69462306a36Sopenharmony_ci	.se_cmp		= sort__srcfile_cmp,
69562306a36Sopenharmony_ci	.se_collapse	= sort__srcfile_collapse,
69662306a36Sopenharmony_ci	.se_sort	= sort__srcfile_sort,
69762306a36Sopenharmony_ci	.se_init	= sort__srcfile_init,
69862306a36Sopenharmony_ci	.se_snprintf	= hist_entry__srcfile_snprintf,
69962306a36Sopenharmony_ci	.se_width_idx	= HISTC_SRCFILE,
70062306a36Sopenharmony_ci};
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci/* --sort parent */
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_cistatic int64_t
70562306a36Sopenharmony_cisort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	struct symbol *sym_l = left->parent;
70862306a36Sopenharmony_ci	struct symbol *sym_r = right->parent;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	if (!sym_l || !sym_r)
71162306a36Sopenharmony_ci		return cmp_null(sym_l, sym_r);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	return strcmp(sym_r->name, sym_l->name);
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
71762306a36Sopenharmony_ci				       size_t size, unsigned int width)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*.*s", width, width,
72062306a36Sopenharmony_ci			      he->parent ? he->parent->name : "[other]");
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistruct sort_entry sort_parent = {
72462306a36Sopenharmony_ci	.se_header	= "Parent symbol",
72562306a36Sopenharmony_ci	.se_cmp		= sort__parent_cmp,
72662306a36Sopenharmony_ci	.se_snprintf	= hist_entry__parent_snprintf,
72762306a36Sopenharmony_ci	.se_width_idx	= HISTC_PARENT,
72862306a36Sopenharmony_ci};
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci/* --sort cpu */
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_cistatic int64_t
73362306a36Sopenharmony_cisort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
73462306a36Sopenharmony_ci{
73562306a36Sopenharmony_ci	return right->cpu - left->cpu;
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_cistatic int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
73962306a36Sopenharmony_ci				    size_t size, unsigned int width)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
74262306a36Sopenharmony_ci}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_cistruct sort_entry sort_cpu = {
74562306a36Sopenharmony_ci	.se_header      = "CPU",
74662306a36Sopenharmony_ci	.se_cmp	        = sort__cpu_cmp,
74762306a36Sopenharmony_ci	.se_snprintf    = hist_entry__cpu_snprintf,
74862306a36Sopenharmony_ci	.se_width_idx	= HISTC_CPU,
74962306a36Sopenharmony_ci};
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci/* --sort cgroup_id */
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic int64_t _sort__cgroup_dev_cmp(u64 left_dev, u64 right_dev)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	return (int64_t)(right_dev - left_dev);
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cistatic int64_t _sort__cgroup_inode_cmp(u64 left_ino, u64 right_ino)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	return (int64_t)(right_ino - left_ino);
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_cistatic int64_t
76462306a36Sopenharmony_cisort__cgroup_id_cmp(struct hist_entry *left, struct hist_entry *right)
76562306a36Sopenharmony_ci{
76662306a36Sopenharmony_ci	int64_t ret;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	ret = _sort__cgroup_dev_cmp(right->cgroup_id.dev, left->cgroup_id.dev);
76962306a36Sopenharmony_ci	if (ret != 0)
77062306a36Sopenharmony_ci		return ret;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	return _sort__cgroup_inode_cmp(right->cgroup_id.ino,
77362306a36Sopenharmony_ci				       left->cgroup_id.ino);
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_cistatic int hist_entry__cgroup_id_snprintf(struct hist_entry *he,
77762306a36Sopenharmony_ci					  char *bf, size_t size,
77862306a36Sopenharmony_ci					  unsigned int width __maybe_unused)
77962306a36Sopenharmony_ci{
78062306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%lu/0x%lx", he->cgroup_id.dev,
78162306a36Sopenharmony_ci			       he->cgroup_id.ino);
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_cistruct sort_entry sort_cgroup_id = {
78562306a36Sopenharmony_ci	.se_header      = "cgroup id (dev/inode)",
78662306a36Sopenharmony_ci	.se_cmp	        = sort__cgroup_id_cmp,
78762306a36Sopenharmony_ci	.se_snprintf    = hist_entry__cgroup_id_snprintf,
78862306a36Sopenharmony_ci	.se_width_idx	= HISTC_CGROUP_ID,
78962306a36Sopenharmony_ci};
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci/* --sort cgroup */
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_cistatic int64_t
79462306a36Sopenharmony_cisort__cgroup_cmp(struct hist_entry *left, struct hist_entry *right)
79562306a36Sopenharmony_ci{
79662306a36Sopenharmony_ci	return right->cgroup - left->cgroup;
79762306a36Sopenharmony_ci}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_cistatic int hist_entry__cgroup_snprintf(struct hist_entry *he,
80062306a36Sopenharmony_ci				       char *bf, size_t size,
80162306a36Sopenharmony_ci				       unsigned int width __maybe_unused)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	const char *cgrp_name = "N/A";
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	if (he->cgroup) {
80662306a36Sopenharmony_ci		struct cgroup *cgrp = cgroup__find(maps__machine(he->ms.maps)->env,
80762306a36Sopenharmony_ci						   he->cgroup);
80862306a36Sopenharmony_ci		if (cgrp != NULL)
80962306a36Sopenharmony_ci			cgrp_name = cgrp->name;
81062306a36Sopenharmony_ci		else
81162306a36Sopenharmony_ci			cgrp_name = "unknown";
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%s", cgrp_name);
81562306a36Sopenharmony_ci}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cistruct sort_entry sort_cgroup = {
81862306a36Sopenharmony_ci	.se_header      = "Cgroup",
81962306a36Sopenharmony_ci	.se_cmp	        = sort__cgroup_cmp,
82062306a36Sopenharmony_ci	.se_snprintf    = hist_entry__cgroup_snprintf,
82162306a36Sopenharmony_ci	.se_width_idx	= HISTC_CGROUP,
82262306a36Sopenharmony_ci};
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci/* --sort socket */
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cistatic int64_t
82762306a36Sopenharmony_cisort__socket_cmp(struct hist_entry *left, struct hist_entry *right)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	return right->socket - left->socket;
83062306a36Sopenharmony_ci}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cistatic int hist_entry__socket_snprintf(struct hist_entry *he, char *bf,
83362306a36Sopenharmony_ci				    size_t size, unsigned int width)
83462306a36Sopenharmony_ci{
83562306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket);
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cistatic int hist_entry__socket_filter(struct hist_entry *he, int type, const void *arg)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	int sk = *(const int *)arg;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	if (type != HIST_FILTER__SOCKET)
84362306a36Sopenharmony_ci		return -1;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	return sk >= 0 && he->socket != sk;
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistruct sort_entry sort_socket = {
84962306a36Sopenharmony_ci	.se_header      = "Socket",
85062306a36Sopenharmony_ci	.se_cmp	        = sort__socket_cmp,
85162306a36Sopenharmony_ci	.se_snprintf    = hist_entry__socket_snprintf,
85262306a36Sopenharmony_ci	.se_filter      = hist_entry__socket_filter,
85362306a36Sopenharmony_ci	.se_width_idx	= HISTC_SOCKET,
85462306a36Sopenharmony_ci};
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci/* --sort time */
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic int64_t
85962306a36Sopenharmony_cisort__time_cmp(struct hist_entry *left, struct hist_entry *right)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	return right->time - left->time;
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cistatic int hist_entry__time_snprintf(struct hist_entry *he, char *bf,
86562306a36Sopenharmony_ci				    size_t size, unsigned int width)
86662306a36Sopenharmony_ci{
86762306a36Sopenharmony_ci	char he_time[32];
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	if (symbol_conf.nanosecs)
87062306a36Sopenharmony_ci		timestamp__scnprintf_nsec(he->time, he_time,
87162306a36Sopenharmony_ci					  sizeof(he_time));
87262306a36Sopenharmony_ci	else
87362306a36Sopenharmony_ci		timestamp__scnprintf_usec(he->time, he_time,
87462306a36Sopenharmony_ci					  sizeof(he_time));
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-.*s", width, he_time);
87762306a36Sopenharmony_ci}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_cistruct sort_entry sort_time = {
88062306a36Sopenharmony_ci	.se_header      = "Time",
88162306a36Sopenharmony_ci	.se_cmp	        = sort__time_cmp,
88262306a36Sopenharmony_ci	.se_snprintf    = hist_entry__time_snprintf,
88362306a36Sopenharmony_ci	.se_width_idx	= HISTC_TIME,
88462306a36Sopenharmony_ci};
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci/* --sort trace */
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
88962306a36Sopenharmony_cistatic char *get_trace_output(struct hist_entry *he)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	struct trace_seq seq;
89262306a36Sopenharmony_ci	struct evsel *evsel;
89362306a36Sopenharmony_ci	struct tep_record rec = {
89462306a36Sopenharmony_ci		.data = he->raw_data,
89562306a36Sopenharmony_ci		.size = he->raw_size,
89662306a36Sopenharmony_ci	};
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	evsel = hists_to_evsel(he->hists);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	trace_seq_init(&seq);
90162306a36Sopenharmony_ci	if (symbol_conf.raw_trace) {
90262306a36Sopenharmony_ci		tep_print_fields(&seq, he->raw_data, he->raw_size,
90362306a36Sopenharmony_ci				 evsel->tp_format);
90462306a36Sopenharmony_ci	} else {
90562306a36Sopenharmony_ci		tep_print_event(evsel->tp_format->tep,
90662306a36Sopenharmony_ci				&seq, &rec, "%s", TEP_PRINT_INFO);
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci	/*
90962306a36Sopenharmony_ci	 * Trim the buffer, it starts at 4KB and we're not going to
91062306a36Sopenharmony_ci	 * add anything more to this buffer.
91162306a36Sopenharmony_ci	 */
91262306a36Sopenharmony_ci	return realloc(seq.buffer, seq.len + 1);
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_cistatic int64_t
91662306a36Sopenharmony_cisort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
91762306a36Sopenharmony_ci{
91862306a36Sopenharmony_ci	struct evsel *evsel;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	evsel = hists_to_evsel(left->hists);
92162306a36Sopenharmony_ci	if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
92262306a36Sopenharmony_ci		return 0;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	if (left->trace_output == NULL)
92562306a36Sopenharmony_ci		left->trace_output = get_trace_output(left);
92662306a36Sopenharmony_ci	if (right->trace_output == NULL)
92762306a36Sopenharmony_ci		right->trace_output = get_trace_output(right);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	return strcmp(right->trace_output, left->trace_output);
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_cistatic int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
93362306a36Sopenharmony_ci				    size_t size, unsigned int width)
93462306a36Sopenharmony_ci{
93562306a36Sopenharmony_ci	struct evsel *evsel;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	evsel = hists_to_evsel(he->hists);
93862306a36Sopenharmony_ci	if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
93962306a36Sopenharmony_ci		return scnprintf(bf, size, "%-.*s", width, "N/A");
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	if (he->trace_output == NULL)
94262306a36Sopenharmony_ci		he->trace_output = get_trace_output(he);
94362306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-.*s", width, he->trace_output);
94462306a36Sopenharmony_ci}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_cistruct sort_entry sort_trace = {
94762306a36Sopenharmony_ci	.se_header      = "Trace output",
94862306a36Sopenharmony_ci	.se_cmp	        = sort__trace_cmp,
94962306a36Sopenharmony_ci	.se_snprintf    = hist_entry__trace_snprintf,
95062306a36Sopenharmony_ci	.se_width_idx	= HISTC_TRACE,
95162306a36Sopenharmony_ci};
95262306a36Sopenharmony_ci#endif /* HAVE_LIBTRACEEVENT */
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci/* sort keys for branch stacks */
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_cistatic int64_t
95762306a36Sopenharmony_cisort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	if (!left->branch_info || !right->branch_info)
96062306a36Sopenharmony_ci		return cmp_null(left->branch_info, right->branch_info);
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	return _sort__dso_cmp(left->branch_info->from.ms.map,
96362306a36Sopenharmony_ci			      right->branch_info->from.ms.map);
96462306a36Sopenharmony_ci}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_cistatic int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
96762306a36Sopenharmony_ci				    size_t size, unsigned int width)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	if (he->branch_info)
97062306a36Sopenharmony_ci		return _hist_entry__dso_snprintf(he->branch_info->from.ms.map,
97162306a36Sopenharmony_ci						 bf, size, width);
97262306a36Sopenharmony_ci	else
97362306a36Sopenharmony_ci		return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
97462306a36Sopenharmony_ci}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_cistatic int hist_entry__dso_from_filter(struct hist_entry *he, int type,
97762306a36Sopenharmony_ci				       const void *arg)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	const struct dso *dso = arg;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	if (type != HIST_FILTER__DSO)
98262306a36Sopenharmony_ci		return -1;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	return dso && (!he->branch_info || !he->branch_info->from.ms.map ||
98562306a36Sopenharmony_ci		map__dso(he->branch_info->from.ms.map) != dso);
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_cistatic int64_t
98962306a36Sopenharmony_cisort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	if (!left->branch_info || !right->branch_info)
99262306a36Sopenharmony_ci		return cmp_null(left->branch_info, right->branch_info);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	return _sort__dso_cmp(left->branch_info->to.ms.map,
99562306a36Sopenharmony_ci			      right->branch_info->to.ms.map);
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
99962306a36Sopenharmony_ci				       size_t size, unsigned int width)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	if (he->branch_info)
100262306a36Sopenharmony_ci		return _hist_entry__dso_snprintf(he->branch_info->to.ms.map,
100362306a36Sopenharmony_ci						 bf, size, width);
100462306a36Sopenharmony_ci	else
100562306a36Sopenharmony_ci		return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
100662306a36Sopenharmony_ci}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_cistatic int hist_entry__dso_to_filter(struct hist_entry *he, int type,
100962306a36Sopenharmony_ci				     const void *arg)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	const struct dso *dso = arg;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	if (type != HIST_FILTER__DSO)
101462306a36Sopenharmony_ci		return -1;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	return dso && (!he->branch_info || !he->branch_info->to.ms.map ||
101762306a36Sopenharmony_ci		map__dso(he->branch_info->to.ms.map) != dso);
101862306a36Sopenharmony_ci}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_cistatic int64_t
102162306a36Sopenharmony_cisort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
102262306a36Sopenharmony_ci{
102362306a36Sopenharmony_ci	struct addr_map_symbol *from_l, *from_r;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	if (!left->branch_info || !right->branch_info)
102662306a36Sopenharmony_ci		return cmp_null(left->branch_info, right->branch_info);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	from_l = &left->branch_info->from;
102962306a36Sopenharmony_ci	from_r = &right->branch_info->from;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	if (!from_l->ms.sym && !from_r->ms.sym)
103262306a36Sopenharmony_ci		return _sort__addr_cmp(from_l->addr, from_r->addr);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	return _sort__sym_cmp(from_l->ms.sym, from_r->ms.sym);
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_cistatic int64_t
103862306a36Sopenharmony_cisort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
103962306a36Sopenharmony_ci{
104062306a36Sopenharmony_ci	struct addr_map_symbol *to_l, *to_r;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	if (!left->branch_info || !right->branch_info)
104362306a36Sopenharmony_ci		return cmp_null(left->branch_info, right->branch_info);
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	to_l = &left->branch_info->to;
104662306a36Sopenharmony_ci	to_r = &right->branch_info->to;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	if (!to_l->ms.sym && !to_r->ms.sym)
104962306a36Sopenharmony_ci		return _sort__addr_cmp(to_l->addr, to_r->addr);
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	return _sort__sym_cmp(to_l->ms.sym, to_r->ms.sym);
105262306a36Sopenharmony_ci}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_cistatic int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
105562306a36Sopenharmony_ci					 size_t size, unsigned int width)
105662306a36Sopenharmony_ci{
105762306a36Sopenharmony_ci	if (he->branch_info) {
105862306a36Sopenharmony_ci		struct addr_map_symbol *from = &he->branch_info->from;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci		return _hist_entry__sym_snprintf(&from->ms, from->al_addr,
106162306a36Sopenharmony_ci						 from->al_level, bf, size, width);
106262306a36Sopenharmony_ci	}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
106562306a36Sopenharmony_ci}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_cistatic int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
106862306a36Sopenharmony_ci				       size_t size, unsigned int width)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	if (he->branch_info) {
107162306a36Sopenharmony_ci		struct addr_map_symbol *to = &he->branch_info->to;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci		return _hist_entry__sym_snprintf(&to->ms, to->al_addr,
107462306a36Sopenharmony_ci						 to->al_level, bf, size, width);
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_cistatic int hist_entry__sym_from_filter(struct hist_entry *he, int type,
108162306a36Sopenharmony_ci				       const void *arg)
108262306a36Sopenharmony_ci{
108362306a36Sopenharmony_ci	const char *sym = arg;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	if (type != HIST_FILTER__SYMBOL)
108662306a36Sopenharmony_ci		return -1;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	return sym && !(he->branch_info && he->branch_info->from.ms.sym &&
108962306a36Sopenharmony_ci			strstr(he->branch_info->from.ms.sym->name, sym));
109062306a36Sopenharmony_ci}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_cistatic int hist_entry__sym_to_filter(struct hist_entry *he, int type,
109362306a36Sopenharmony_ci				       const void *arg)
109462306a36Sopenharmony_ci{
109562306a36Sopenharmony_ci	const char *sym = arg;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	if (type != HIST_FILTER__SYMBOL)
109862306a36Sopenharmony_ci		return -1;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	return sym && !(he->branch_info && he->branch_info->to.ms.sym &&
110162306a36Sopenharmony_ci		        strstr(he->branch_info->to.ms.sym->name, sym));
110262306a36Sopenharmony_ci}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_cistruct sort_entry sort_dso_from = {
110562306a36Sopenharmony_ci	.se_header	= "Source Shared Object",
110662306a36Sopenharmony_ci	.se_cmp		= sort__dso_from_cmp,
110762306a36Sopenharmony_ci	.se_snprintf	= hist_entry__dso_from_snprintf,
110862306a36Sopenharmony_ci	.se_filter	= hist_entry__dso_from_filter,
110962306a36Sopenharmony_ci	.se_width_idx	= HISTC_DSO_FROM,
111062306a36Sopenharmony_ci};
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_cistruct sort_entry sort_dso_to = {
111362306a36Sopenharmony_ci	.se_header	= "Target Shared Object",
111462306a36Sopenharmony_ci	.se_cmp		= sort__dso_to_cmp,
111562306a36Sopenharmony_ci	.se_snprintf	= hist_entry__dso_to_snprintf,
111662306a36Sopenharmony_ci	.se_filter	= hist_entry__dso_to_filter,
111762306a36Sopenharmony_ci	.se_width_idx	= HISTC_DSO_TO,
111862306a36Sopenharmony_ci};
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_cistruct sort_entry sort_sym_from = {
112162306a36Sopenharmony_ci	.se_header	= "Source Symbol",
112262306a36Sopenharmony_ci	.se_cmp		= sort__sym_from_cmp,
112362306a36Sopenharmony_ci	.se_snprintf	= hist_entry__sym_from_snprintf,
112462306a36Sopenharmony_ci	.se_filter	= hist_entry__sym_from_filter,
112562306a36Sopenharmony_ci	.se_width_idx	= HISTC_SYMBOL_FROM,
112662306a36Sopenharmony_ci};
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_cistruct sort_entry sort_sym_to = {
112962306a36Sopenharmony_ci	.se_header	= "Target Symbol",
113062306a36Sopenharmony_ci	.se_cmp		= sort__sym_to_cmp,
113162306a36Sopenharmony_ci	.se_snprintf	= hist_entry__sym_to_snprintf,
113262306a36Sopenharmony_ci	.se_filter	= hist_entry__sym_to_filter,
113362306a36Sopenharmony_ci	.se_width_idx	= HISTC_SYMBOL_TO,
113462306a36Sopenharmony_ci};
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_cistatic int _hist_entry__addr_snprintf(struct map_symbol *ms,
113762306a36Sopenharmony_ci				     u64 ip, char level, char *bf, size_t size,
113862306a36Sopenharmony_ci				     unsigned int width)
113962306a36Sopenharmony_ci{
114062306a36Sopenharmony_ci	struct symbol *sym = ms->sym;
114162306a36Sopenharmony_ci	struct map *map = ms->map;
114262306a36Sopenharmony_ci	size_t ret = 0, offs;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
114562306a36Sopenharmony_ci	if (sym && map) {
114662306a36Sopenharmony_ci		if (sym->type == STT_OBJECT) {
114762306a36Sopenharmony_ci			ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
114862306a36Sopenharmony_ci			ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
114962306a36Sopenharmony_ci					ip - map__unmap_ip(map, sym->start));
115062306a36Sopenharmony_ci		} else {
115162306a36Sopenharmony_ci			ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
115262306a36Sopenharmony_ci					       width - ret,
115362306a36Sopenharmony_ci					       sym->name);
115462306a36Sopenharmony_ci			offs = ip - sym->start;
115562306a36Sopenharmony_ci			if (offs)
115662306a36Sopenharmony_ci				ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", offs);
115762306a36Sopenharmony_ci		}
115862306a36Sopenharmony_ci	} else {
115962306a36Sopenharmony_ci		size_t len = BITS_PER_LONG / 4;
116062306a36Sopenharmony_ci		ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
116162306a36Sopenharmony_ci				       len, ip);
116262306a36Sopenharmony_ci	}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	return ret;
116562306a36Sopenharmony_ci}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_cistatic int hist_entry__addr_from_snprintf(struct hist_entry *he, char *bf,
116862306a36Sopenharmony_ci					 size_t size, unsigned int width)
116962306a36Sopenharmony_ci{
117062306a36Sopenharmony_ci	if (he->branch_info) {
117162306a36Sopenharmony_ci		struct addr_map_symbol *from = &he->branch_info->from;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci		return _hist_entry__addr_snprintf(&from->ms, from->al_addr,
117462306a36Sopenharmony_ci						 he->level, bf, size, width);
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
117862306a36Sopenharmony_ci}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic int hist_entry__addr_to_snprintf(struct hist_entry *he, char *bf,
118162306a36Sopenharmony_ci				       size_t size, unsigned int width)
118262306a36Sopenharmony_ci{
118362306a36Sopenharmony_ci	if (he->branch_info) {
118462306a36Sopenharmony_ci		struct addr_map_symbol *to = &he->branch_info->to;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci		return _hist_entry__addr_snprintf(&to->ms, to->al_addr,
118762306a36Sopenharmony_ci						 he->level, bf, size, width);
118862306a36Sopenharmony_ci	}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
119162306a36Sopenharmony_ci}
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_cistatic int64_t
119462306a36Sopenharmony_cisort__addr_from_cmp(struct hist_entry *left, struct hist_entry *right)
119562306a36Sopenharmony_ci{
119662306a36Sopenharmony_ci	struct addr_map_symbol *from_l;
119762306a36Sopenharmony_ci	struct addr_map_symbol *from_r;
119862306a36Sopenharmony_ci	int64_t ret;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	if (!left->branch_info || !right->branch_info)
120162306a36Sopenharmony_ci		return cmp_null(left->branch_info, right->branch_info);
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	from_l = &left->branch_info->from;
120462306a36Sopenharmony_ci	from_r = &right->branch_info->from;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	/*
120762306a36Sopenharmony_ci	 * comparing symbol address alone is not enough since it's a
120862306a36Sopenharmony_ci	 * relative address within a dso.
120962306a36Sopenharmony_ci	 */
121062306a36Sopenharmony_ci	ret = _sort__dso_cmp(from_l->ms.map, from_r->ms.map);
121162306a36Sopenharmony_ci	if (ret != 0)
121262306a36Sopenharmony_ci		return ret;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	return _sort__addr_cmp(from_l->addr, from_r->addr);
121562306a36Sopenharmony_ci}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_cistatic int64_t
121862306a36Sopenharmony_cisort__addr_to_cmp(struct hist_entry *left, struct hist_entry *right)
121962306a36Sopenharmony_ci{
122062306a36Sopenharmony_ci	struct addr_map_symbol *to_l;
122162306a36Sopenharmony_ci	struct addr_map_symbol *to_r;
122262306a36Sopenharmony_ci	int64_t ret;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	if (!left->branch_info || !right->branch_info)
122562306a36Sopenharmony_ci		return cmp_null(left->branch_info, right->branch_info);
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	to_l = &left->branch_info->to;
122862306a36Sopenharmony_ci	to_r = &right->branch_info->to;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	/*
123162306a36Sopenharmony_ci	 * comparing symbol address alone is not enough since it's a
123262306a36Sopenharmony_ci	 * relative address within a dso.
123362306a36Sopenharmony_ci	 */
123462306a36Sopenharmony_ci	ret = _sort__dso_cmp(to_l->ms.map, to_r->ms.map);
123562306a36Sopenharmony_ci	if (ret != 0)
123662306a36Sopenharmony_ci		return ret;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	return _sort__addr_cmp(to_l->addr, to_r->addr);
123962306a36Sopenharmony_ci}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_cistruct sort_entry sort_addr_from = {
124262306a36Sopenharmony_ci	.se_header	= "Source Address",
124362306a36Sopenharmony_ci	.se_cmp		= sort__addr_from_cmp,
124462306a36Sopenharmony_ci	.se_snprintf	= hist_entry__addr_from_snprintf,
124562306a36Sopenharmony_ci	.se_filter	= hist_entry__sym_from_filter, /* shared with sym_from */
124662306a36Sopenharmony_ci	.se_width_idx	= HISTC_ADDR_FROM,
124762306a36Sopenharmony_ci};
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_cistruct sort_entry sort_addr_to = {
125062306a36Sopenharmony_ci	.se_header	= "Target Address",
125162306a36Sopenharmony_ci	.se_cmp		= sort__addr_to_cmp,
125262306a36Sopenharmony_ci	.se_snprintf	= hist_entry__addr_to_snprintf,
125362306a36Sopenharmony_ci	.se_filter	= hist_entry__sym_to_filter, /* shared with sym_to */
125462306a36Sopenharmony_ci	.se_width_idx	= HISTC_ADDR_TO,
125562306a36Sopenharmony_ci};
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_cistatic int64_t
125962306a36Sopenharmony_cisort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
126062306a36Sopenharmony_ci{
126162306a36Sopenharmony_ci	unsigned char mp, p;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	if (!left->branch_info || !right->branch_info)
126462306a36Sopenharmony_ci		return cmp_null(left->branch_info, right->branch_info);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
126762306a36Sopenharmony_ci	p  = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
126862306a36Sopenharmony_ci	return mp || p;
126962306a36Sopenharmony_ci}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_cistatic int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
127262306a36Sopenharmony_ci				    size_t size, unsigned int width){
127362306a36Sopenharmony_ci	static const char *out = "N/A";
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	if (he->branch_info) {
127662306a36Sopenharmony_ci		if (he->branch_info->flags.predicted)
127762306a36Sopenharmony_ci			out = "N";
127862306a36Sopenharmony_ci		else if (he->branch_info->flags.mispred)
127962306a36Sopenharmony_ci			out = "Y";
128062306a36Sopenharmony_ci	}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
128362306a36Sopenharmony_ci}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_cistatic int64_t
128662306a36Sopenharmony_cisort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
128762306a36Sopenharmony_ci{
128862306a36Sopenharmony_ci	if (!left->branch_info || !right->branch_info)
128962306a36Sopenharmony_ci		return cmp_null(left->branch_info, right->branch_info);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	return left->branch_info->flags.cycles -
129262306a36Sopenharmony_ci		right->branch_info->flags.cycles;
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_cistatic int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
129662306a36Sopenharmony_ci				    size_t size, unsigned int width)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	if (!he->branch_info)
129962306a36Sopenharmony_ci		return scnprintf(bf, size, "%-.*s", width, "N/A");
130062306a36Sopenharmony_ci	if (he->branch_info->flags.cycles == 0)
130162306a36Sopenharmony_ci		return repsep_snprintf(bf, size, "%-*s", width, "-");
130262306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*hd", width,
130362306a36Sopenharmony_ci			       he->branch_info->flags.cycles);
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_cistruct sort_entry sort_cycles = {
130762306a36Sopenharmony_ci	.se_header	= "Basic Block Cycles",
130862306a36Sopenharmony_ci	.se_cmp		= sort__cycles_cmp,
130962306a36Sopenharmony_ci	.se_snprintf	= hist_entry__cycles_snprintf,
131062306a36Sopenharmony_ci	.se_width_idx	= HISTC_CYCLES,
131162306a36Sopenharmony_ci};
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci/* --sort daddr_sym */
131462306a36Sopenharmony_ciint64_t
131562306a36Sopenharmony_cisort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	uint64_t l = 0, r = 0;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	if (left->mem_info)
132062306a36Sopenharmony_ci		l = left->mem_info->daddr.addr;
132162306a36Sopenharmony_ci	if (right->mem_info)
132262306a36Sopenharmony_ci		r = right->mem_info->daddr.addr;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	return (int64_t)(r - l);
132562306a36Sopenharmony_ci}
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_cistatic int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
132862306a36Sopenharmony_ci				    size_t size, unsigned int width)
132962306a36Sopenharmony_ci{
133062306a36Sopenharmony_ci	uint64_t addr = 0;
133162306a36Sopenharmony_ci	struct map_symbol *ms = NULL;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	if (he->mem_info) {
133462306a36Sopenharmony_ci		addr = he->mem_info->daddr.addr;
133562306a36Sopenharmony_ci		ms = &he->mem_info->daddr.ms;
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci	return _hist_entry__sym_snprintf(ms, addr, he->level, bf, size, width);
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ciint64_t
134162306a36Sopenharmony_cisort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	uint64_t l = 0, r = 0;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	if (left->mem_info)
134662306a36Sopenharmony_ci		l = left->mem_info->iaddr.addr;
134762306a36Sopenharmony_ci	if (right->mem_info)
134862306a36Sopenharmony_ci		r = right->mem_info->iaddr.addr;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	return (int64_t)(r - l);
135162306a36Sopenharmony_ci}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_cistatic int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf,
135462306a36Sopenharmony_ci				    size_t size, unsigned int width)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	uint64_t addr = 0;
135762306a36Sopenharmony_ci	struct map_symbol *ms = NULL;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	if (he->mem_info) {
136062306a36Sopenharmony_ci		addr = he->mem_info->iaddr.addr;
136162306a36Sopenharmony_ci		ms   = &he->mem_info->iaddr.ms;
136262306a36Sopenharmony_ci	}
136362306a36Sopenharmony_ci	return _hist_entry__sym_snprintf(ms, addr, he->level, bf, size, width);
136462306a36Sopenharmony_ci}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_cistatic int64_t
136762306a36Sopenharmony_cisort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
136862306a36Sopenharmony_ci{
136962306a36Sopenharmony_ci	struct map *map_l = NULL;
137062306a36Sopenharmony_ci	struct map *map_r = NULL;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	if (left->mem_info)
137362306a36Sopenharmony_ci		map_l = left->mem_info->daddr.ms.map;
137462306a36Sopenharmony_ci	if (right->mem_info)
137562306a36Sopenharmony_ci		map_r = right->mem_info->daddr.ms.map;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	return _sort__dso_cmp(map_l, map_r);
137862306a36Sopenharmony_ci}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_cistatic int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
138162306a36Sopenharmony_ci				    size_t size, unsigned int width)
138262306a36Sopenharmony_ci{
138362306a36Sopenharmony_ci	struct map *map = NULL;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	if (he->mem_info)
138662306a36Sopenharmony_ci		map = he->mem_info->daddr.ms.map;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	return _hist_entry__dso_snprintf(map, bf, size, width);
138962306a36Sopenharmony_ci}
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_cistatic int64_t
139262306a36Sopenharmony_cisort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
139362306a36Sopenharmony_ci{
139462306a36Sopenharmony_ci	union perf_mem_data_src data_src_l;
139562306a36Sopenharmony_ci	union perf_mem_data_src data_src_r;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	if (left->mem_info)
139862306a36Sopenharmony_ci		data_src_l = left->mem_info->data_src;
139962306a36Sopenharmony_ci	else
140062306a36Sopenharmony_ci		data_src_l.mem_lock = PERF_MEM_LOCK_NA;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	if (right->mem_info)
140362306a36Sopenharmony_ci		data_src_r = right->mem_info->data_src;
140462306a36Sopenharmony_ci	else
140562306a36Sopenharmony_ci		data_src_r.mem_lock = PERF_MEM_LOCK_NA;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
140862306a36Sopenharmony_ci}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_cistatic int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
141162306a36Sopenharmony_ci				    size_t size, unsigned int width)
141262306a36Sopenharmony_ci{
141362306a36Sopenharmony_ci	char out[10];
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	perf_mem__lck_scnprintf(out, sizeof(out), he->mem_info);
141662306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%.*s", width, out);
141762306a36Sopenharmony_ci}
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_cistatic int64_t
142062306a36Sopenharmony_cisort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
142162306a36Sopenharmony_ci{
142262306a36Sopenharmony_ci	union perf_mem_data_src data_src_l;
142362306a36Sopenharmony_ci	union perf_mem_data_src data_src_r;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	if (left->mem_info)
142662306a36Sopenharmony_ci		data_src_l = left->mem_info->data_src;
142762306a36Sopenharmony_ci	else
142862306a36Sopenharmony_ci		data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	if (right->mem_info)
143162306a36Sopenharmony_ci		data_src_r = right->mem_info->data_src;
143262306a36Sopenharmony_ci	else
143362306a36Sopenharmony_ci		data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
143662306a36Sopenharmony_ci}
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_cistatic int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
143962306a36Sopenharmony_ci				    size_t size, unsigned int width)
144062306a36Sopenharmony_ci{
144162306a36Sopenharmony_ci	char out[64];
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	perf_mem__tlb_scnprintf(out, sizeof(out), he->mem_info);
144462306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*s", width, out);
144562306a36Sopenharmony_ci}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_cistatic int64_t
144862306a36Sopenharmony_cisort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
144962306a36Sopenharmony_ci{
145062306a36Sopenharmony_ci	union perf_mem_data_src data_src_l;
145162306a36Sopenharmony_ci	union perf_mem_data_src data_src_r;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	if (left->mem_info)
145462306a36Sopenharmony_ci		data_src_l = left->mem_info->data_src;
145562306a36Sopenharmony_ci	else
145662306a36Sopenharmony_ci		data_src_l.mem_lvl = PERF_MEM_LVL_NA;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	if (right->mem_info)
145962306a36Sopenharmony_ci		data_src_r = right->mem_info->data_src;
146062306a36Sopenharmony_ci	else
146162306a36Sopenharmony_ci		data_src_r.mem_lvl = PERF_MEM_LVL_NA;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
146462306a36Sopenharmony_ci}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_cistatic int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
146762306a36Sopenharmony_ci				    size_t size, unsigned int width)
146862306a36Sopenharmony_ci{
146962306a36Sopenharmony_ci	char out[64];
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	perf_mem__lvl_scnprintf(out, sizeof(out), he->mem_info);
147262306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*s", width, out);
147362306a36Sopenharmony_ci}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_cistatic int64_t
147662306a36Sopenharmony_cisort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
147762306a36Sopenharmony_ci{
147862306a36Sopenharmony_ci	union perf_mem_data_src data_src_l;
147962306a36Sopenharmony_ci	union perf_mem_data_src data_src_r;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	if (left->mem_info)
148262306a36Sopenharmony_ci		data_src_l = left->mem_info->data_src;
148362306a36Sopenharmony_ci	else
148462306a36Sopenharmony_ci		data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	if (right->mem_info)
148762306a36Sopenharmony_ci		data_src_r = right->mem_info->data_src;
148862306a36Sopenharmony_ci	else
148962306a36Sopenharmony_ci		data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
149262306a36Sopenharmony_ci}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_cistatic int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
149562306a36Sopenharmony_ci				    size_t size, unsigned int width)
149662306a36Sopenharmony_ci{
149762306a36Sopenharmony_ci	char out[64];
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	perf_mem__snp_scnprintf(out, sizeof(out), he->mem_info);
150062306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*s", width, out);
150162306a36Sopenharmony_ci}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ciint64_t
150462306a36Sopenharmony_cisort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
150562306a36Sopenharmony_ci{
150662306a36Sopenharmony_ci	u64 l, r;
150762306a36Sopenharmony_ci	struct map *l_map, *r_map;
150862306a36Sopenharmony_ci	struct dso *l_dso, *r_dso;
150962306a36Sopenharmony_ci	int rc;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	if (!left->mem_info)  return -1;
151262306a36Sopenharmony_ci	if (!right->mem_info) return 1;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	/* group event types together */
151562306a36Sopenharmony_ci	if (left->cpumode > right->cpumode) return -1;
151662306a36Sopenharmony_ci	if (left->cpumode < right->cpumode) return 1;
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	l_map = left->mem_info->daddr.ms.map;
151962306a36Sopenharmony_ci	r_map = right->mem_info->daddr.ms.map;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	/* if both are NULL, jump to sort on al_addr instead */
152262306a36Sopenharmony_ci	if (!l_map && !r_map)
152362306a36Sopenharmony_ci		goto addr;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	if (!l_map) return -1;
152662306a36Sopenharmony_ci	if (!r_map) return 1;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	l_dso = map__dso(l_map);
152962306a36Sopenharmony_ci	r_dso = map__dso(r_map);
153062306a36Sopenharmony_ci	rc = dso__cmp_id(l_dso, r_dso);
153162306a36Sopenharmony_ci	if (rc)
153262306a36Sopenharmony_ci		return rc;
153362306a36Sopenharmony_ci	/*
153462306a36Sopenharmony_ci	 * Addresses with no major/minor numbers are assumed to be
153562306a36Sopenharmony_ci	 * anonymous in userspace.  Sort those on pid then address.
153662306a36Sopenharmony_ci	 *
153762306a36Sopenharmony_ci	 * The kernel and non-zero major/minor mapped areas are
153862306a36Sopenharmony_ci	 * assumed to be unity mapped.  Sort those on address.
153962306a36Sopenharmony_ci	 */
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
154262306a36Sopenharmony_ci	    (!(map__flags(l_map) & MAP_SHARED)) && !l_dso->id.maj && !l_dso->id.min &&
154362306a36Sopenharmony_ci	    !l_dso->id.ino && !l_dso->id.ino_generation) {
154462306a36Sopenharmony_ci		/* userspace anonymous */
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci		if (thread__pid(left->thread) > thread__pid(right->thread))
154762306a36Sopenharmony_ci			return -1;
154862306a36Sopenharmony_ci		if (thread__pid(left->thread) < thread__pid(right->thread))
154962306a36Sopenharmony_ci			return 1;
155062306a36Sopenharmony_ci	}
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ciaddr:
155362306a36Sopenharmony_ci	/* al_addr does all the right addr - start + offset calculations */
155462306a36Sopenharmony_ci	l = cl_address(left->mem_info->daddr.al_addr, chk_double_cl);
155562306a36Sopenharmony_ci	r = cl_address(right->mem_info->daddr.al_addr, chk_double_cl);
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	if (l > r) return -1;
155862306a36Sopenharmony_ci	if (l < r) return 1;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	return 0;
156162306a36Sopenharmony_ci}
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_cistatic int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
156462306a36Sopenharmony_ci					  size_t size, unsigned int width)
156562306a36Sopenharmony_ci{
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	uint64_t addr = 0;
156862306a36Sopenharmony_ci	struct map_symbol *ms = NULL;
156962306a36Sopenharmony_ci	char level = he->level;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	if (he->mem_info) {
157262306a36Sopenharmony_ci		struct map *map = he->mem_info->daddr.ms.map;
157362306a36Sopenharmony_ci		struct dso *dso = map ? map__dso(map) : NULL;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci		addr = cl_address(he->mem_info->daddr.al_addr, chk_double_cl);
157662306a36Sopenharmony_ci		ms = &he->mem_info->daddr.ms;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci		/* print [s] for shared data mmaps */
157962306a36Sopenharmony_ci		if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
158062306a36Sopenharmony_ci		     map && !(map__prot(map) & PROT_EXEC) &&
158162306a36Sopenharmony_ci		     (map__flags(map) & MAP_SHARED) &&
158262306a36Sopenharmony_ci		    (dso->id.maj || dso->id.min || dso->id.ino || dso->id.ino_generation))
158362306a36Sopenharmony_ci			level = 's';
158462306a36Sopenharmony_ci		else if (!map)
158562306a36Sopenharmony_ci			level = 'X';
158662306a36Sopenharmony_ci	}
158762306a36Sopenharmony_ci	return _hist_entry__sym_snprintf(ms, addr, level, bf, size, width);
158862306a36Sopenharmony_ci}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_cistruct sort_entry sort_mispredict = {
159162306a36Sopenharmony_ci	.se_header	= "Branch Mispredicted",
159262306a36Sopenharmony_ci	.se_cmp		= sort__mispredict_cmp,
159362306a36Sopenharmony_ci	.se_snprintf	= hist_entry__mispredict_snprintf,
159462306a36Sopenharmony_ci	.se_width_idx	= HISTC_MISPREDICT,
159562306a36Sopenharmony_ci};
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_cistatic int64_t
159862306a36Sopenharmony_cisort__weight_cmp(struct hist_entry *left, struct hist_entry *right)
159962306a36Sopenharmony_ci{
160062306a36Sopenharmony_ci	return left->weight - right->weight;
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_cistatic int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
160462306a36Sopenharmony_ci				    size_t size, unsigned int width)
160562306a36Sopenharmony_ci{
160662306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*llu", width, he->weight);
160762306a36Sopenharmony_ci}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_cistruct sort_entry sort_local_weight = {
161062306a36Sopenharmony_ci	.se_header	= "Local Weight",
161162306a36Sopenharmony_ci	.se_cmp		= sort__weight_cmp,
161262306a36Sopenharmony_ci	.se_snprintf	= hist_entry__local_weight_snprintf,
161362306a36Sopenharmony_ci	.se_width_idx	= HISTC_LOCAL_WEIGHT,
161462306a36Sopenharmony_ci};
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_cistatic int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
161762306a36Sopenharmony_ci					      size_t size, unsigned int width)
161862306a36Sopenharmony_ci{
161962306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*llu", width,
162062306a36Sopenharmony_ci			       he->weight * he->stat.nr_events);
162162306a36Sopenharmony_ci}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_cistruct sort_entry sort_global_weight = {
162462306a36Sopenharmony_ci	.se_header	= "Weight",
162562306a36Sopenharmony_ci	.se_cmp		= sort__weight_cmp,
162662306a36Sopenharmony_ci	.se_snprintf	= hist_entry__global_weight_snprintf,
162762306a36Sopenharmony_ci	.se_width_idx	= HISTC_GLOBAL_WEIGHT,
162862306a36Sopenharmony_ci};
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_cistatic int64_t
163162306a36Sopenharmony_cisort__ins_lat_cmp(struct hist_entry *left, struct hist_entry *right)
163262306a36Sopenharmony_ci{
163362306a36Sopenharmony_ci	return left->ins_lat - right->ins_lat;
163462306a36Sopenharmony_ci}
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_cistatic int hist_entry__local_ins_lat_snprintf(struct hist_entry *he, char *bf,
163762306a36Sopenharmony_ci					      size_t size, unsigned int width)
163862306a36Sopenharmony_ci{
163962306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*u", width, he->ins_lat);
164062306a36Sopenharmony_ci}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_cistruct sort_entry sort_local_ins_lat = {
164362306a36Sopenharmony_ci	.se_header	= "Local INSTR Latency",
164462306a36Sopenharmony_ci	.se_cmp		= sort__ins_lat_cmp,
164562306a36Sopenharmony_ci	.se_snprintf	= hist_entry__local_ins_lat_snprintf,
164662306a36Sopenharmony_ci	.se_width_idx	= HISTC_LOCAL_INS_LAT,
164762306a36Sopenharmony_ci};
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_cistatic int hist_entry__global_ins_lat_snprintf(struct hist_entry *he, char *bf,
165062306a36Sopenharmony_ci					       size_t size, unsigned int width)
165162306a36Sopenharmony_ci{
165262306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*u", width,
165362306a36Sopenharmony_ci			       he->ins_lat * he->stat.nr_events);
165462306a36Sopenharmony_ci}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_cistruct sort_entry sort_global_ins_lat = {
165762306a36Sopenharmony_ci	.se_header	= "INSTR Latency",
165862306a36Sopenharmony_ci	.se_cmp		= sort__ins_lat_cmp,
165962306a36Sopenharmony_ci	.se_snprintf	= hist_entry__global_ins_lat_snprintf,
166062306a36Sopenharmony_ci	.se_width_idx	= HISTC_GLOBAL_INS_LAT,
166162306a36Sopenharmony_ci};
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_cistatic int64_t
166462306a36Sopenharmony_cisort__p_stage_cyc_cmp(struct hist_entry *left, struct hist_entry *right)
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	return left->p_stage_cyc - right->p_stage_cyc;
166762306a36Sopenharmony_ci}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_cistatic int hist_entry__global_p_stage_cyc_snprintf(struct hist_entry *he, char *bf,
167062306a36Sopenharmony_ci					size_t size, unsigned int width)
167162306a36Sopenharmony_ci{
167262306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*u", width,
167362306a36Sopenharmony_ci			he->p_stage_cyc * he->stat.nr_events);
167462306a36Sopenharmony_ci}
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_cistatic int hist_entry__p_stage_cyc_snprintf(struct hist_entry *he, char *bf,
167862306a36Sopenharmony_ci					size_t size, unsigned int width)
167962306a36Sopenharmony_ci{
168062306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*u", width, he->p_stage_cyc);
168162306a36Sopenharmony_ci}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_cistruct sort_entry sort_local_p_stage_cyc = {
168462306a36Sopenharmony_ci	.se_header      = "Local Pipeline Stage Cycle",
168562306a36Sopenharmony_ci	.se_cmp         = sort__p_stage_cyc_cmp,
168662306a36Sopenharmony_ci	.se_snprintf	= hist_entry__p_stage_cyc_snprintf,
168762306a36Sopenharmony_ci	.se_width_idx	= HISTC_LOCAL_P_STAGE_CYC,
168862306a36Sopenharmony_ci};
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_cistruct sort_entry sort_global_p_stage_cyc = {
169162306a36Sopenharmony_ci	.se_header      = "Pipeline Stage Cycle",
169262306a36Sopenharmony_ci	.se_cmp         = sort__p_stage_cyc_cmp,
169362306a36Sopenharmony_ci	.se_snprintf    = hist_entry__global_p_stage_cyc_snprintf,
169462306a36Sopenharmony_ci	.se_width_idx   = HISTC_GLOBAL_P_STAGE_CYC,
169562306a36Sopenharmony_ci};
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_cistruct sort_entry sort_mem_daddr_sym = {
169862306a36Sopenharmony_ci	.se_header	= "Data Symbol",
169962306a36Sopenharmony_ci	.se_cmp		= sort__daddr_cmp,
170062306a36Sopenharmony_ci	.se_snprintf	= hist_entry__daddr_snprintf,
170162306a36Sopenharmony_ci	.se_width_idx	= HISTC_MEM_DADDR_SYMBOL,
170262306a36Sopenharmony_ci};
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_cistruct sort_entry sort_mem_iaddr_sym = {
170562306a36Sopenharmony_ci	.se_header	= "Code Symbol",
170662306a36Sopenharmony_ci	.se_cmp		= sort__iaddr_cmp,
170762306a36Sopenharmony_ci	.se_snprintf	= hist_entry__iaddr_snprintf,
170862306a36Sopenharmony_ci	.se_width_idx	= HISTC_MEM_IADDR_SYMBOL,
170962306a36Sopenharmony_ci};
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_cistruct sort_entry sort_mem_daddr_dso = {
171262306a36Sopenharmony_ci	.se_header	= "Data Object",
171362306a36Sopenharmony_ci	.se_cmp		= sort__dso_daddr_cmp,
171462306a36Sopenharmony_ci	.se_snprintf	= hist_entry__dso_daddr_snprintf,
171562306a36Sopenharmony_ci	.se_width_idx	= HISTC_MEM_DADDR_DSO,
171662306a36Sopenharmony_ci};
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_cistruct sort_entry sort_mem_locked = {
171962306a36Sopenharmony_ci	.se_header	= "Locked",
172062306a36Sopenharmony_ci	.se_cmp		= sort__locked_cmp,
172162306a36Sopenharmony_ci	.se_snprintf	= hist_entry__locked_snprintf,
172262306a36Sopenharmony_ci	.se_width_idx	= HISTC_MEM_LOCKED,
172362306a36Sopenharmony_ci};
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_cistruct sort_entry sort_mem_tlb = {
172662306a36Sopenharmony_ci	.se_header	= "TLB access",
172762306a36Sopenharmony_ci	.se_cmp		= sort__tlb_cmp,
172862306a36Sopenharmony_ci	.se_snprintf	= hist_entry__tlb_snprintf,
172962306a36Sopenharmony_ci	.se_width_idx	= HISTC_MEM_TLB,
173062306a36Sopenharmony_ci};
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_cistruct sort_entry sort_mem_lvl = {
173362306a36Sopenharmony_ci	.se_header	= "Memory access",
173462306a36Sopenharmony_ci	.se_cmp		= sort__lvl_cmp,
173562306a36Sopenharmony_ci	.se_snprintf	= hist_entry__lvl_snprintf,
173662306a36Sopenharmony_ci	.se_width_idx	= HISTC_MEM_LVL,
173762306a36Sopenharmony_ci};
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_cistruct sort_entry sort_mem_snoop = {
174062306a36Sopenharmony_ci	.se_header	= "Snoop",
174162306a36Sopenharmony_ci	.se_cmp		= sort__snoop_cmp,
174262306a36Sopenharmony_ci	.se_snprintf	= hist_entry__snoop_snprintf,
174362306a36Sopenharmony_ci	.se_width_idx	= HISTC_MEM_SNOOP,
174462306a36Sopenharmony_ci};
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_cistruct sort_entry sort_mem_dcacheline = {
174762306a36Sopenharmony_ci	.se_header	= "Data Cacheline",
174862306a36Sopenharmony_ci	.se_cmp		= sort__dcacheline_cmp,
174962306a36Sopenharmony_ci	.se_snprintf	= hist_entry__dcacheline_snprintf,
175062306a36Sopenharmony_ci	.se_width_idx	= HISTC_MEM_DCACHELINE,
175162306a36Sopenharmony_ci};
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_cistatic int64_t
175462306a36Sopenharmony_cisort__blocked_cmp(struct hist_entry *left, struct hist_entry *right)
175562306a36Sopenharmony_ci{
175662306a36Sopenharmony_ci	union perf_mem_data_src data_src_l;
175762306a36Sopenharmony_ci	union perf_mem_data_src data_src_r;
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	if (left->mem_info)
176062306a36Sopenharmony_ci		data_src_l = left->mem_info->data_src;
176162306a36Sopenharmony_ci	else
176262306a36Sopenharmony_ci		data_src_l.mem_blk = PERF_MEM_BLK_NA;
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	if (right->mem_info)
176562306a36Sopenharmony_ci		data_src_r = right->mem_info->data_src;
176662306a36Sopenharmony_ci	else
176762306a36Sopenharmony_ci		data_src_r.mem_blk = PERF_MEM_BLK_NA;
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	return (int64_t)(data_src_r.mem_blk - data_src_l.mem_blk);
177062306a36Sopenharmony_ci}
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_cistatic int hist_entry__blocked_snprintf(struct hist_entry *he, char *bf,
177362306a36Sopenharmony_ci					size_t size, unsigned int width)
177462306a36Sopenharmony_ci{
177562306a36Sopenharmony_ci	char out[16];
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	perf_mem__blk_scnprintf(out, sizeof(out), he->mem_info);
177862306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%.*s", width, out);
177962306a36Sopenharmony_ci}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_cistruct sort_entry sort_mem_blocked = {
178262306a36Sopenharmony_ci	.se_header	= "Blocked",
178362306a36Sopenharmony_ci	.se_cmp		= sort__blocked_cmp,
178462306a36Sopenharmony_ci	.se_snprintf	= hist_entry__blocked_snprintf,
178562306a36Sopenharmony_ci	.se_width_idx	= HISTC_MEM_BLOCKED,
178662306a36Sopenharmony_ci};
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_cistatic int64_t
178962306a36Sopenharmony_cisort__phys_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
179062306a36Sopenharmony_ci{
179162306a36Sopenharmony_ci	uint64_t l = 0, r = 0;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	if (left->mem_info)
179462306a36Sopenharmony_ci		l = left->mem_info->daddr.phys_addr;
179562306a36Sopenharmony_ci	if (right->mem_info)
179662306a36Sopenharmony_ci		r = right->mem_info->daddr.phys_addr;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	return (int64_t)(r - l);
179962306a36Sopenharmony_ci}
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_cistatic int hist_entry__phys_daddr_snprintf(struct hist_entry *he, char *bf,
180262306a36Sopenharmony_ci					   size_t size, unsigned int width)
180362306a36Sopenharmony_ci{
180462306a36Sopenharmony_ci	uint64_t addr = 0;
180562306a36Sopenharmony_ci	size_t ret = 0;
180662306a36Sopenharmony_ci	size_t len = BITS_PER_LONG / 4;
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	addr = he->mem_info->daddr.phys_addr;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", he->level);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", len, addr);
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	ret += repsep_snprintf(bf + ret, size - ret, "%-*s", width - ret, "");
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	if (ret > width)
181762306a36Sopenharmony_ci		bf[width] = '\0';
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	return width;
182062306a36Sopenharmony_ci}
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_cistruct sort_entry sort_mem_phys_daddr = {
182362306a36Sopenharmony_ci	.se_header	= "Data Physical Address",
182462306a36Sopenharmony_ci	.se_cmp		= sort__phys_daddr_cmp,
182562306a36Sopenharmony_ci	.se_snprintf	= hist_entry__phys_daddr_snprintf,
182662306a36Sopenharmony_ci	.se_width_idx	= HISTC_MEM_PHYS_DADDR,
182762306a36Sopenharmony_ci};
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_cistatic int64_t
183062306a36Sopenharmony_cisort__data_page_size_cmp(struct hist_entry *left, struct hist_entry *right)
183162306a36Sopenharmony_ci{
183262306a36Sopenharmony_ci	uint64_t l = 0, r = 0;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	if (left->mem_info)
183562306a36Sopenharmony_ci		l = left->mem_info->daddr.data_page_size;
183662306a36Sopenharmony_ci	if (right->mem_info)
183762306a36Sopenharmony_ci		r = right->mem_info->daddr.data_page_size;
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	return (int64_t)(r - l);
184062306a36Sopenharmony_ci}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_cistatic int hist_entry__data_page_size_snprintf(struct hist_entry *he, char *bf,
184362306a36Sopenharmony_ci					  size_t size, unsigned int width)
184462306a36Sopenharmony_ci{
184562306a36Sopenharmony_ci	char str[PAGE_SIZE_NAME_LEN];
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*s", width,
184862306a36Sopenharmony_ci			       get_page_size_name(he->mem_info->daddr.data_page_size, str));
184962306a36Sopenharmony_ci}
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_cistruct sort_entry sort_mem_data_page_size = {
185262306a36Sopenharmony_ci	.se_header	= "Data Page Size",
185362306a36Sopenharmony_ci	.se_cmp		= sort__data_page_size_cmp,
185462306a36Sopenharmony_ci	.se_snprintf	= hist_entry__data_page_size_snprintf,
185562306a36Sopenharmony_ci	.se_width_idx	= HISTC_MEM_DATA_PAGE_SIZE,
185662306a36Sopenharmony_ci};
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_cistatic int64_t
185962306a36Sopenharmony_cisort__code_page_size_cmp(struct hist_entry *left, struct hist_entry *right)
186062306a36Sopenharmony_ci{
186162306a36Sopenharmony_ci	uint64_t l = left->code_page_size;
186262306a36Sopenharmony_ci	uint64_t r = right->code_page_size;
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	return (int64_t)(r - l);
186562306a36Sopenharmony_ci}
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_cistatic int hist_entry__code_page_size_snprintf(struct hist_entry *he, char *bf,
186862306a36Sopenharmony_ci					  size_t size, unsigned int width)
186962306a36Sopenharmony_ci{
187062306a36Sopenharmony_ci	char str[PAGE_SIZE_NAME_LEN];
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*s", width,
187362306a36Sopenharmony_ci			       get_page_size_name(he->code_page_size, str));
187462306a36Sopenharmony_ci}
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_cistruct sort_entry sort_code_page_size = {
187762306a36Sopenharmony_ci	.se_header	= "Code Page Size",
187862306a36Sopenharmony_ci	.se_cmp		= sort__code_page_size_cmp,
187962306a36Sopenharmony_ci	.se_snprintf	= hist_entry__code_page_size_snprintf,
188062306a36Sopenharmony_ci	.se_width_idx	= HISTC_CODE_PAGE_SIZE,
188162306a36Sopenharmony_ci};
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_cistatic int64_t
188462306a36Sopenharmony_cisort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
188562306a36Sopenharmony_ci{
188662306a36Sopenharmony_ci	if (!left->branch_info || !right->branch_info)
188762306a36Sopenharmony_ci		return cmp_null(left->branch_info, right->branch_info);
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	return left->branch_info->flags.abort !=
189062306a36Sopenharmony_ci		right->branch_info->flags.abort;
189162306a36Sopenharmony_ci}
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_cistatic int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
189462306a36Sopenharmony_ci				    size_t size, unsigned int width)
189562306a36Sopenharmony_ci{
189662306a36Sopenharmony_ci	static const char *out = "N/A";
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	if (he->branch_info) {
189962306a36Sopenharmony_ci		if (he->branch_info->flags.abort)
190062306a36Sopenharmony_ci			out = "A";
190162306a36Sopenharmony_ci		else
190262306a36Sopenharmony_ci			out = ".";
190362306a36Sopenharmony_ci	}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*s", width, out);
190662306a36Sopenharmony_ci}
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_cistruct sort_entry sort_abort = {
190962306a36Sopenharmony_ci	.se_header	= "Transaction abort",
191062306a36Sopenharmony_ci	.se_cmp		= sort__abort_cmp,
191162306a36Sopenharmony_ci	.se_snprintf	= hist_entry__abort_snprintf,
191262306a36Sopenharmony_ci	.se_width_idx	= HISTC_ABORT,
191362306a36Sopenharmony_ci};
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_cistatic int64_t
191662306a36Sopenharmony_cisort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
191762306a36Sopenharmony_ci{
191862306a36Sopenharmony_ci	if (!left->branch_info || !right->branch_info)
191962306a36Sopenharmony_ci		return cmp_null(left->branch_info, right->branch_info);
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	return left->branch_info->flags.in_tx !=
192262306a36Sopenharmony_ci		right->branch_info->flags.in_tx;
192362306a36Sopenharmony_ci}
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_cistatic int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
192662306a36Sopenharmony_ci				    size_t size, unsigned int width)
192762306a36Sopenharmony_ci{
192862306a36Sopenharmony_ci	static const char *out = "N/A";
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	if (he->branch_info) {
193162306a36Sopenharmony_ci		if (he->branch_info->flags.in_tx)
193262306a36Sopenharmony_ci			out = "T";
193362306a36Sopenharmony_ci		else
193462306a36Sopenharmony_ci			out = ".";
193562306a36Sopenharmony_ci	}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*s", width, out);
193862306a36Sopenharmony_ci}
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_cistruct sort_entry sort_in_tx = {
194162306a36Sopenharmony_ci	.se_header	= "Branch in transaction",
194262306a36Sopenharmony_ci	.se_cmp		= sort__in_tx_cmp,
194362306a36Sopenharmony_ci	.se_snprintf	= hist_entry__in_tx_snprintf,
194462306a36Sopenharmony_ci	.se_width_idx	= HISTC_IN_TX,
194562306a36Sopenharmony_ci};
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_cistatic int64_t
194862306a36Sopenharmony_cisort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
194962306a36Sopenharmony_ci{
195062306a36Sopenharmony_ci	return left->transaction - right->transaction;
195162306a36Sopenharmony_ci}
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_cistatic inline char *add_str(char *p, const char *str)
195462306a36Sopenharmony_ci{
195562306a36Sopenharmony_ci	strcpy(p, str);
195662306a36Sopenharmony_ci	return p + strlen(str);
195762306a36Sopenharmony_ci}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_cistatic struct txbit {
196062306a36Sopenharmony_ci	unsigned flag;
196162306a36Sopenharmony_ci	const char *name;
196262306a36Sopenharmony_ci	int skip_for_len;
196362306a36Sopenharmony_ci} txbits[] = {
196462306a36Sopenharmony_ci	{ PERF_TXN_ELISION,        "EL ",        0 },
196562306a36Sopenharmony_ci	{ PERF_TXN_TRANSACTION,    "TX ",        1 },
196662306a36Sopenharmony_ci	{ PERF_TXN_SYNC,           "SYNC ",      1 },
196762306a36Sopenharmony_ci	{ PERF_TXN_ASYNC,          "ASYNC ",     0 },
196862306a36Sopenharmony_ci	{ PERF_TXN_RETRY,          "RETRY ",     0 },
196962306a36Sopenharmony_ci	{ PERF_TXN_CONFLICT,       "CON ",       0 },
197062306a36Sopenharmony_ci	{ PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
197162306a36Sopenharmony_ci	{ PERF_TXN_CAPACITY_READ,  "CAP-READ ",  0 },
197262306a36Sopenharmony_ci	{ 0, NULL, 0 }
197362306a36Sopenharmony_ci};
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ciint hist_entry__transaction_len(void)
197662306a36Sopenharmony_ci{
197762306a36Sopenharmony_ci	int i;
197862306a36Sopenharmony_ci	int len = 0;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	for (i = 0; txbits[i].name; i++) {
198162306a36Sopenharmony_ci		if (!txbits[i].skip_for_len)
198262306a36Sopenharmony_ci			len += strlen(txbits[i].name);
198362306a36Sopenharmony_ci	}
198462306a36Sopenharmony_ci	len += 4; /* :XX<space> */
198562306a36Sopenharmony_ci	return len;
198662306a36Sopenharmony_ci}
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_cistatic int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
198962306a36Sopenharmony_ci					    size_t size, unsigned int width)
199062306a36Sopenharmony_ci{
199162306a36Sopenharmony_ci	u64 t = he->transaction;
199262306a36Sopenharmony_ci	char buf[128];
199362306a36Sopenharmony_ci	char *p = buf;
199462306a36Sopenharmony_ci	int i;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	buf[0] = 0;
199762306a36Sopenharmony_ci	for (i = 0; txbits[i].name; i++)
199862306a36Sopenharmony_ci		if (txbits[i].flag & t)
199962306a36Sopenharmony_ci			p = add_str(p, txbits[i].name);
200062306a36Sopenharmony_ci	if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
200162306a36Sopenharmony_ci		p = add_str(p, "NEITHER ");
200262306a36Sopenharmony_ci	if (t & PERF_TXN_ABORT_MASK) {
200362306a36Sopenharmony_ci		sprintf(p, ":%" PRIx64,
200462306a36Sopenharmony_ci			(t & PERF_TXN_ABORT_MASK) >>
200562306a36Sopenharmony_ci			PERF_TXN_ABORT_SHIFT);
200662306a36Sopenharmony_ci		p += strlen(p);
200762306a36Sopenharmony_ci	}
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-*s", width, buf);
201062306a36Sopenharmony_ci}
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_cistruct sort_entry sort_transaction = {
201362306a36Sopenharmony_ci	.se_header	= "Transaction                ",
201462306a36Sopenharmony_ci	.se_cmp		= sort__transaction_cmp,
201562306a36Sopenharmony_ci	.se_snprintf	= hist_entry__transaction_snprintf,
201662306a36Sopenharmony_ci	.se_width_idx	= HISTC_TRANSACTION,
201762306a36Sopenharmony_ci};
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci/* --sort symbol_size */
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_cistatic int64_t _sort__sym_size_cmp(struct symbol *sym_l, struct symbol *sym_r)
202262306a36Sopenharmony_ci{
202362306a36Sopenharmony_ci	int64_t size_l = sym_l != NULL ? symbol__size(sym_l) : 0;
202462306a36Sopenharmony_ci	int64_t size_r = sym_r != NULL ? symbol__size(sym_r) : 0;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	return size_l < size_r ? -1 :
202762306a36Sopenharmony_ci		size_l == size_r ? 0 : 1;
202862306a36Sopenharmony_ci}
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_cistatic int64_t
203162306a36Sopenharmony_cisort__sym_size_cmp(struct hist_entry *left, struct hist_entry *right)
203262306a36Sopenharmony_ci{
203362306a36Sopenharmony_ci	return _sort__sym_size_cmp(right->ms.sym, left->ms.sym);
203462306a36Sopenharmony_ci}
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_cistatic int _hist_entry__sym_size_snprintf(struct symbol *sym, char *bf,
203762306a36Sopenharmony_ci					  size_t bf_size, unsigned int width)
203862306a36Sopenharmony_ci{
203962306a36Sopenharmony_ci	if (sym)
204062306a36Sopenharmony_ci		return repsep_snprintf(bf, bf_size, "%*d", width, symbol__size(sym));
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	return repsep_snprintf(bf, bf_size, "%*s", width, "unknown");
204362306a36Sopenharmony_ci}
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_cistatic int hist_entry__sym_size_snprintf(struct hist_entry *he, char *bf,
204662306a36Sopenharmony_ci					 size_t size, unsigned int width)
204762306a36Sopenharmony_ci{
204862306a36Sopenharmony_ci	return _hist_entry__sym_size_snprintf(he->ms.sym, bf, size, width);
204962306a36Sopenharmony_ci}
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_cistruct sort_entry sort_sym_size = {
205262306a36Sopenharmony_ci	.se_header	= "Symbol size",
205362306a36Sopenharmony_ci	.se_cmp		= sort__sym_size_cmp,
205462306a36Sopenharmony_ci	.se_snprintf	= hist_entry__sym_size_snprintf,
205562306a36Sopenharmony_ci	.se_width_idx	= HISTC_SYM_SIZE,
205662306a36Sopenharmony_ci};
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci/* --sort dso_size */
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_cistatic int64_t _sort__dso_size_cmp(struct map *map_l, struct map *map_r)
206162306a36Sopenharmony_ci{
206262306a36Sopenharmony_ci	int64_t size_l = map_l != NULL ? map__size(map_l) : 0;
206362306a36Sopenharmony_ci	int64_t size_r = map_r != NULL ? map__size(map_r) : 0;
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	return size_l < size_r ? -1 :
206662306a36Sopenharmony_ci		size_l == size_r ? 0 : 1;
206762306a36Sopenharmony_ci}
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_cistatic int64_t
207062306a36Sopenharmony_cisort__dso_size_cmp(struct hist_entry *left, struct hist_entry *right)
207162306a36Sopenharmony_ci{
207262306a36Sopenharmony_ci	return _sort__dso_size_cmp(right->ms.map, left->ms.map);
207362306a36Sopenharmony_ci}
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_cistatic int _hist_entry__dso_size_snprintf(struct map *map, char *bf,
207662306a36Sopenharmony_ci					  size_t bf_size, unsigned int width)
207762306a36Sopenharmony_ci{
207862306a36Sopenharmony_ci	if (map && map__dso(map))
207962306a36Sopenharmony_ci		return repsep_snprintf(bf, bf_size, "%*d", width, map__size(map));
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	return repsep_snprintf(bf, bf_size, "%*s", width, "unknown");
208262306a36Sopenharmony_ci}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_cistatic int hist_entry__dso_size_snprintf(struct hist_entry *he, char *bf,
208562306a36Sopenharmony_ci					 size_t size, unsigned int width)
208662306a36Sopenharmony_ci{
208762306a36Sopenharmony_ci	return _hist_entry__dso_size_snprintf(he->ms.map, bf, size, width);
208862306a36Sopenharmony_ci}
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_cistruct sort_entry sort_dso_size = {
209162306a36Sopenharmony_ci	.se_header	= "DSO size",
209262306a36Sopenharmony_ci	.se_cmp		= sort__dso_size_cmp,
209362306a36Sopenharmony_ci	.se_snprintf	= hist_entry__dso_size_snprintf,
209462306a36Sopenharmony_ci	.se_width_idx	= HISTC_DSO_SIZE,
209562306a36Sopenharmony_ci};
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci/* --sort dso_size */
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_cistatic int64_t
210062306a36Sopenharmony_cisort__addr_cmp(struct hist_entry *left, struct hist_entry *right)
210162306a36Sopenharmony_ci{
210262306a36Sopenharmony_ci	u64 left_ip = left->ip;
210362306a36Sopenharmony_ci	u64 right_ip = right->ip;
210462306a36Sopenharmony_ci	struct map *left_map = left->ms.map;
210562306a36Sopenharmony_ci	struct map *right_map = right->ms.map;
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	if (left_map)
210862306a36Sopenharmony_ci		left_ip = map__unmap_ip(left_map, left_ip);
210962306a36Sopenharmony_ci	if (right_map)
211062306a36Sopenharmony_ci		right_ip = map__unmap_ip(right_map, right_ip);
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	return _sort__addr_cmp(left_ip, right_ip);
211362306a36Sopenharmony_ci}
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_cistatic int hist_entry__addr_snprintf(struct hist_entry *he, char *bf,
211662306a36Sopenharmony_ci				     size_t size, unsigned int width)
211762306a36Sopenharmony_ci{
211862306a36Sopenharmony_ci	u64 ip = he->ip;
211962306a36Sopenharmony_ci	struct map *map = he->ms.map;
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	if (map)
212262306a36Sopenharmony_ci		ip = map__unmap_ip(map, ip);
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	return repsep_snprintf(bf, size, "%-#*llx", width, ip);
212562306a36Sopenharmony_ci}
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_cistruct sort_entry sort_addr = {
212862306a36Sopenharmony_ci	.se_header	= "Address",
212962306a36Sopenharmony_ci	.se_cmp		= sort__addr_cmp,
213062306a36Sopenharmony_ci	.se_snprintf	= hist_entry__addr_snprintf,
213162306a36Sopenharmony_ci	.se_width_idx	= HISTC_ADDR,
213262306a36Sopenharmony_ci};
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_cistruct sort_dimension {
213662306a36Sopenharmony_ci	const char		*name;
213762306a36Sopenharmony_ci	struct sort_entry	*entry;
213862306a36Sopenharmony_ci	int			taken;
213962306a36Sopenharmony_ci};
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ciint __weak arch_support_sort_key(const char *sort_key __maybe_unused)
214262306a36Sopenharmony_ci{
214362306a36Sopenharmony_ci	return 0;
214462306a36Sopenharmony_ci}
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ciconst char * __weak arch_perf_header_entry(const char *se_header)
214762306a36Sopenharmony_ci{
214862306a36Sopenharmony_ci	return se_header;
214962306a36Sopenharmony_ci}
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_cistatic void sort_dimension_add_dynamic_header(struct sort_dimension *sd)
215262306a36Sopenharmony_ci{
215362306a36Sopenharmony_ci	sd->entry->se_header = arch_perf_header_entry(sd->entry->se_header);
215462306a36Sopenharmony_ci}
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_cistatic struct sort_dimension common_sort_dimensions[] = {
215962306a36Sopenharmony_ci	DIM(SORT_PID, "pid", sort_thread),
216062306a36Sopenharmony_ci	DIM(SORT_COMM, "comm", sort_comm),
216162306a36Sopenharmony_ci	DIM(SORT_DSO, "dso", sort_dso),
216262306a36Sopenharmony_ci	DIM(SORT_SYM, "symbol", sort_sym),
216362306a36Sopenharmony_ci	DIM(SORT_PARENT, "parent", sort_parent),
216462306a36Sopenharmony_ci	DIM(SORT_CPU, "cpu", sort_cpu),
216562306a36Sopenharmony_ci	DIM(SORT_SOCKET, "socket", sort_socket),
216662306a36Sopenharmony_ci	DIM(SORT_SRCLINE, "srcline", sort_srcline),
216762306a36Sopenharmony_ci	DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
216862306a36Sopenharmony_ci	DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
216962306a36Sopenharmony_ci	DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
217062306a36Sopenharmony_ci	DIM(SORT_TRANSACTION, "transaction", sort_transaction),
217162306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
217262306a36Sopenharmony_ci	DIM(SORT_TRACE, "trace", sort_trace),
217362306a36Sopenharmony_ci#endif
217462306a36Sopenharmony_ci	DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size),
217562306a36Sopenharmony_ci	DIM(SORT_DSO_SIZE, "dso_size", sort_dso_size),
217662306a36Sopenharmony_ci	DIM(SORT_CGROUP, "cgroup", sort_cgroup),
217762306a36Sopenharmony_ci	DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id),
217862306a36Sopenharmony_ci	DIM(SORT_SYM_IPC_NULL, "ipc_null", sort_sym_ipc_null),
217962306a36Sopenharmony_ci	DIM(SORT_TIME, "time", sort_time),
218062306a36Sopenharmony_ci	DIM(SORT_CODE_PAGE_SIZE, "code_page_size", sort_code_page_size),
218162306a36Sopenharmony_ci	DIM(SORT_LOCAL_INS_LAT, "local_ins_lat", sort_local_ins_lat),
218262306a36Sopenharmony_ci	DIM(SORT_GLOBAL_INS_LAT, "ins_lat", sort_global_ins_lat),
218362306a36Sopenharmony_ci	DIM(SORT_LOCAL_PIPELINE_STAGE_CYC, "local_p_stage_cyc", sort_local_p_stage_cyc),
218462306a36Sopenharmony_ci	DIM(SORT_GLOBAL_PIPELINE_STAGE_CYC, "p_stage_cyc", sort_global_p_stage_cyc),
218562306a36Sopenharmony_ci	DIM(SORT_ADDR, "addr", sort_addr),
218662306a36Sopenharmony_ci	DIM(SORT_LOCAL_RETIRE_LAT, "local_retire_lat", sort_local_p_stage_cyc),
218762306a36Sopenharmony_ci	DIM(SORT_GLOBAL_RETIRE_LAT, "retire_lat", sort_global_p_stage_cyc),
218862306a36Sopenharmony_ci	DIM(SORT_SIMD, "simd", sort_simd)
218962306a36Sopenharmony_ci};
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci#undef DIM
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_cistatic struct sort_dimension bstack_sort_dimensions[] = {
219662306a36Sopenharmony_ci	DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
219762306a36Sopenharmony_ci	DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
219862306a36Sopenharmony_ci	DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
219962306a36Sopenharmony_ci	DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
220062306a36Sopenharmony_ci	DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
220162306a36Sopenharmony_ci	DIM(SORT_IN_TX, "in_tx", sort_in_tx),
220262306a36Sopenharmony_ci	DIM(SORT_ABORT, "abort", sort_abort),
220362306a36Sopenharmony_ci	DIM(SORT_CYCLES, "cycles", sort_cycles),
220462306a36Sopenharmony_ci	DIM(SORT_SRCLINE_FROM, "srcline_from", sort_srcline_from),
220562306a36Sopenharmony_ci	DIM(SORT_SRCLINE_TO, "srcline_to", sort_srcline_to),
220662306a36Sopenharmony_ci	DIM(SORT_SYM_IPC, "ipc_lbr", sort_sym_ipc),
220762306a36Sopenharmony_ci	DIM(SORT_ADDR_FROM, "addr_from", sort_addr_from),
220862306a36Sopenharmony_ci	DIM(SORT_ADDR_TO, "addr_to", sort_addr_to),
220962306a36Sopenharmony_ci};
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci#undef DIM
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_cistatic struct sort_dimension memory_sort_dimensions[] = {
221662306a36Sopenharmony_ci	DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
221762306a36Sopenharmony_ci	DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym),
221862306a36Sopenharmony_ci	DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
221962306a36Sopenharmony_ci	DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
222062306a36Sopenharmony_ci	DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
222162306a36Sopenharmony_ci	DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
222262306a36Sopenharmony_ci	DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
222362306a36Sopenharmony_ci	DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
222462306a36Sopenharmony_ci	DIM(SORT_MEM_PHYS_DADDR, "phys_daddr", sort_mem_phys_daddr),
222562306a36Sopenharmony_ci	DIM(SORT_MEM_DATA_PAGE_SIZE, "data_page_size", sort_mem_data_page_size),
222662306a36Sopenharmony_ci	DIM(SORT_MEM_BLOCKED, "blocked", sort_mem_blocked),
222762306a36Sopenharmony_ci};
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci#undef DIM
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_cistruct hpp_dimension {
223262306a36Sopenharmony_ci	const char		*name;
223362306a36Sopenharmony_ci	struct perf_hpp_fmt	*fmt;
223462306a36Sopenharmony_ci	int			taken;
223562306a36Sopenharmony_ci};
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_cistatic struct hpp_dimension hpp_sort_dimensions[] = {
224062306a36Sopenharmony_ci	DIM(PERF_HPP__OVERHEAD, "overhead"),
224162306a36Sopenharmony_ci	DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
224262306a36Sopenharmony_ci	DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
224362306a36Sopenharmony_ci	DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
224462306a36Sopenharmony_ci	DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
224562306a36Sopenharmony_ci	DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
224662306a36Sopenharmony_ci	DIM(PERF_HPP__SAMPLES, "sample"),
224762306a36Sopenharmony_ci	DIM(PERF_HPP__PERIOD, "period"),
224862306a36Sopenharmony_ci};
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci#undef DIM
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_cistruct hpp_sort_entry {
225362306a36Sopenharmony_ci	struct perf_hpp_fmt hpp;
225462306a36Sopenharmony_ci	struct sort_entry *se;
225562306a36Sopenharmony_ci};
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_civoid perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
225862306a36Sopenharmony_ci{
225962306a36Sopenharmony_ci	struct hpp_sort_entry *hse;
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	if (!perf_hpp__is_sort_entry(fmt))
226262306a36Sopenharmony_ci		return;
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_ci	hse = container_of(fmt, struct hpp_sort_entry, hpp);
226562306a36Sopenharmony_ci	hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
226662306a36Sopenharmony_ci}
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_cistatic int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
226962306a36Sopenharmony_ci			      struct hists *hists, int line __maybe_unused,
227062306a36Sopenharmony_ci			      int *span __maybe_unused)
227162306a36Sopenharmony_ci{
227262306a36Sopenharmony_ci	struct hpp_sort_entry *hse;
227362306a36Sopenharmony_ci	size_t len = fmt->user_len;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	hse = container_of(fmt, struct hpp_sort_entry, hpp);
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	if (!len)
227862306a36Sopenharmony_ci		len = hists__col_len(hists, hse->se->se_width_idx);
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci	return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
228162306a36Sopenharmony_ci}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_cistatic int __sort__hpp_width(struct perf_hpp_fmt *fmt,
228462306a36Sopenharmony_ci			     struct perf_hpp *hpp __maybe_unused,
228562306a36Sopenharmony_ci			     struct hists *hists)
228662306a36Sopenharmony_ci{
228762306a36Sopenharmony_ci	struct hpp_sort_entry *hse;
228862306a36Sopenharmony_ci	size_t len = fmt->user_len;
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci	hse = container_of(fmt, struct hpp_sort_entry, hpp);
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	if (!len)
229362306a36Sopenharmony_ci		len = hists__col_len(hists, hse->se->se_width_idx);
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	return len;
229662306a36Sopenharmony_ci}
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_cistatic int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
229962306a36Sopenharmony_ci			     struct hist_entry *he)
230062306a36Sopenharmony_ci{
230162306a36Sopenharmony_ci	struct hpp_sort_entry *hse;
230262306a36Sopenharmony_ci	size_t len = fmt->user_len;
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci	hse = container_of(fmt, struct hpp_sort_entry, hpp);
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	if (!len)
230762306a36Sopenharmony_ci		len = hists__col_len(he->hists, hse->se->se_width_idx);
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
231062306a36Sopenharmony_ci}
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_cistatic int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
231362306a36Sopenharmony_ci			       struct hist_entry *a, struct hist_entry *b)
231462306a36Sopenharmony_ci{
231562306a36Sopenharmony_ci	struct hpp_sort_entry *hse;
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci	hse = container_of(fmt, struct hpp_sort_entry, hpp);
231862306a36Sopenharmony_ci	return hse->se->se_cmp(a, b);
231962306a36Sopenharmony_ci}
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_cistatic int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
232262306a36Sopenharmony_ci				    struct hist_entry *a, struct hist_entry *b)
232362306a36Sopenharmony_ci{
232462306a36Sopenharmony_ci	struct hpp_sort_entry *hse;
232562306a36Sopenharmony_ci	int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	hse = container_of(fmt, struct hpp_sort_entry, hpp);
232862306a36Sopenharmony_ci	collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
232962306a36Sopenharmony_ci	return collapse_fn(a, b);
233062306a36Sopenharmony_ci}
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_cistatic int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
233362306a36Sopenharmony_ci				struct hist_entry *a, struct hist_entry *b)
233462306a36Sopenharmony_ci{
233562306a36Sopenharmony_ci	struct hpp_sort_entry *hse;
233662306a36Sopenharmony_ci	int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci	hse = container_of(fmt, struct hpp_sort_entry, hpp);
233962306a36Sopenharmony_ci	sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
234062306a36Sopenharmony_ci	return sort_fn(a, b);
234162306a36Sopenharmony_ci}
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_cibool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
234462306a36Sopenharmony_ci{
234562306a36Sopenharmony_ci	return format->header == __sort__hpp_header;
234662306a36Sopenharmony_ci}
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci#define MK_SORT_ENTRY_CHK(key)					\
234962306a36Sopenharmony_cibool perf_hpp__is_ ## key ## _entry(struct perf_hpp_fmt *fmt)	\
235062306a36Sopenharmony_ci{								\
235162306a36Sopenharmony_ci	struct hpp_sort_entry *hse;				\
235262306a36Sopenharmony_ci								\
235362306a36Sopenharmony_ci	if (!perf_hpp__is_sort_entry(fmt))			\
235462306a36Sopenharmony_ci		return false;					\
235562306a36Sopenharmony_ci								\
235662306a36Sopenharmony_ci	hse = container_of(fmt, struct hpp_sort_entry, hpp);	\
235762306a36Sopenharmony_ci	return hse->se == &sort_ ## key ;			\
235862306a36Sopenharmony_ci}
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
236162306a36Sopenharmony_ciMK_SORT_ENTRY_CHK(trace)
236262306a36Sopenharmony_ci#else
236362306a36Sopenharmony_cibool perf_hpp__is_trace_entry(struct perf_hpp_fmt *fmt __maybe_unused)
236462306a36Sopenharmony_ci{
236562306a36Sopenharmony_ci	return false;
236662306a36Sopenharmony_ci}
236762306a36Sopenharmony_ci#endif
236862306a36Sopenharmony_ciMK_SORT_ENTRY_CHK(srcline)
236962306a36Sopenharmony_ciMK_SORT_ENTRY_CHK(srcfile)
237062306a36Sopenharmony_ciMK_SORT_ENTRY_CHK(thread)
237162306a36Sopenharmony_ciMK_SORT_ENTRY_CHK(comm)
237262306a36Sopenharmony_ciMK_SORT_ENTRY_CHK(dso)
237362306a36Sopenharmony_ciMK_SORT_ENTRY_CHK(sym)
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_cistatic bool __sort__hpp_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
237762306a36Sopenharmony_ci{
237862306a36Sopenharmony_ci	struct hpp_sort_entry *hse_a;
237962306a36Sopenharmony_ci	struct hpp_sort_entry *hse_b;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
238262306a36Sopenharmony_ci		return false;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	hse_a = container_of(a, struct hpp_sort_entry, hpp);
238562306a36Sopenharmony_ci	hse_b = container_of(b, struct hpp_sort_entry, hpp);
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	return hse_a->se == hse_b->se;
238862306a36Sopenharmony_ci}
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_cistatic void hse_free(struct perf_hpp_fmt *fmt)
239162306a36Sopenharmony_ci{
239262306a36Sopenharmony_ci	struct hpp_sort_entry *hse;
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci	hse = container_of(fmt, struct hpp_sort_entry, hpp);
239562306a36Sopenharmony_ci	free(hse);
239662306a36Sopenharmony_ci}
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_cistatic void hse_init(struct perf_hpp_fmt *fmt, struct hist_entry *he)
239962306a36Sopenharmony_ci{
240062306a36Sopenharmony_ci	struct hpp_sort_entry *hse;
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	if (!perf_hpp__is_sort_entry(fmt))
240362306a36Sopenharmony_ci		return;
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	hse = container_of(fmt, struct hpp_sort_entry, hpp);
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci	if (hse->se->se_init)
240862306a36Sopenharmony_ci		hse->se->se_init(he);
240962306a36Sopenharmony_ci}
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_cistatic struct hpp_sort_entry *
241262306a36Sopenharmony_ci__sort_dimension__alloc_hpp(struct sort_dimension *sd, int level)
241362306a36Sopenharmony_ci{
241462306a36Sopenharmony_ci	struct hpp_sort_entry *hse;
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci	hse = malloc(sizeof(*hse));
241762306a36Sopenharmony_ci	if (hse == NULL) {
241862306a36Sopenharmony_ci		pr_err("Memory allocation failed\n");
241962306a36Sopenharmony_ci		return NULL;
242062306a36Sopenharmony_ci	}
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	hse->se = sd->entry;
242362306a36Sopenharmony_ci	hse->hpp.name = sd->entry->se_header;
242462306a36Sopenharmony_ci	hse->hpp.header = __sort__hpp_header;
242562306a36Sopenharmony_ci	hse->hpp.width = __sort__hpp_width;
242662306a36Sopenharmony_ci	hse->hpp.entry = __sort__hpp_entry;
242762306a36Sopenharmony_ci	hse->hpp.color = NULL;
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	hse->hpp.cmp = __sort__hpp_cmp;
243062306a36Sopenharmony_ci	hse->hpp.collapse = __sort__hpp_collapse;
243162306a36Sopenharmony_ci	hse->hpp.sort = __sort__hpp_sort;
243262306a36Sopenharmony_ci	hse->hpp.equal = __sort__hpp_equal;
243362306a36Sopenharmony_ci	hse->hpp.free = hse_free;
243462306a36Sopenharmony_ci	hse->hpp.init = hse_init;
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci	INIT_LIST_HEAD(&hse->hpp.list);
243762306a36Sopenharmony_ci	INIT_LIST_HEAD(&hse->hpp.sort_list);
243862306a36Sopenharmony_ci	hse->hpp.elide = false;
243962306a36Sopenharmony_ci	hse->hpp.len = 0;
244062306a36Sopenharmony_ci	hse->hpp.user_len = 0;
244162306a36Sopenharmony_ci	hse->hpp.level = level;
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	return hse;
244462306a36Sopenharmony_ci}
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_cistatic void hpp_free(struct perf_hpp_fmt *fmt)
244762306a36Sopenharmony_ci{
244862306a36Sopenharmony_ci	free(fmt);
244962306a36Sopenharmony_ci}
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_cistatic struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd,
245262306a36Sopenharmony_ci						       int level)
245362306a36Sopenharmony_ci{
245462306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	fmt = memdup(hd->fmt, sizeof(*fmt));
245762306a36Sopenharmony_ci	if (fmt) {
245862306a36Sopenharmony_ci		INIT_LIST_HEAD(&fmt->list);
245962306a36Sopenharmony_ci		INIT_LIST_HEAD(&fmt->sort_list);
246062306a36Sopenharmony_ci		fmt->free = hpp_free;
246162306a36Sopenharmony_ci		fmt->level = level;
246262306a36Sopenharmony_ci	}
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci	return fmt;
246562306a36Sopenharmony_ci}
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ciint hist_entry__filter(struct hist_entry *he, int type, const void *arg)
246862306a36Sopenharmony_ci{
246962306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
247062306a36Sopenharmony_ci	struct hpp_sort_entry *hse;
247162306a36Sopenharmony_ci	int ret = -1;
247262306a36Sopenharmony_ci	int r;
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	perf_hpp_list__for_each_format(he->hpp_list, fmt) {
247562306a36Sopenharmony_ci		if (!perf_hpp__is_sort_entry(fmt))
247662306a36Sopenharmony_ci			continue;
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci		hse = container_of(fmt, struct hpp_sort_entry, hpp);
247962306a36Sopenharmony_ci		if (hse->se->se_filter == NULL)
248062306a36Sopenharmony_ci			continue;
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci		/*
248362306a36Sopenharmony_ci		 * hist entry is filtered if any of sort key in the hpp list
248462306a36Sopenharmony_ci		 * is applied.  But it should skip non-matched filter types.
248562306a36Sopenharmony_ci		 */
248662306a36Sopenharmony_ci		r = hse->se->se_filter(he, type, arg);
248762306a36Sopenharmony_ci		if (r >= 0) {
248862306a36Sopenharmony_ci			if (ret < 0)
248962306a36Sopenharmony_ci				ret = 0;
249062306a36Sopenharmony_ci			ret |= r;
249162306a36Sopenharmony_ci		}
249262306a36Sopenharmony_ci	}
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci	return ret;
249562306a36Sopenharmony_ci}
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_cistatic int __sort_dimension__add_hpp_sort(struct sort_dimension *sd,
249862306a36Sopenharmony_ci					  struct perf_hpp_list *list,
249962306a36Sopenharmony_ci					  int level)
250062306a36Sopenharmony_ci{
250162306a36Sopenharmony_ci	struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, level);
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	if (hse == NULL)
250462306a36Sopenharmony_ci		return -1;
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	perf_hpp_list__register_sort_field(list, &hse->hpp);
250762306a36Sopenharmony_ci	return 0;
250862306a36Sopenharmony_ci}
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_cistatic int __sort_dimension__add_hpp_output(struct sort_dimension *sd,
251162306a36Sopenharmony_ci					    struct perf_hpp_list *list)
251262306a36Sopenharmony_ci{
251362306a36Sopenharmony_ci	struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, 0);
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	if (hse == NULL)
251662306a36Sopenharmony_ci		return -1;
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci	perf_hpp_list__column_register(list, &hse->hpp);
251962306a36Sopenharmony_ci	return 0;
252062306a36Sopenharmony_ci}
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci#ifndef HAVE_LIBTRACEEVENT
252362306a36Sopenharmony_cibool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt __maybe_unused)
252462306a36Sopenharmony_ci{
252562306a36Sopenharmony_ci	return false;
252662306a36Sopenharmony_ci}
252762306a36Sopenharmony_cibool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt __maybe_unused,
252862306a36Sopenharmony_ci				     struct hists *hists __maybe_unused)
252962306a36Sopenharmony_ci{
253062306a36Sopenharmony_ci	return false;
253162306a36Sopenharmony_ci}
253262306a36Sopenharmony_ci#else
253362306a36Sopenharmony_cistruct hpp_dynamic_entry {
253462306a36Sopenharmony_ci	struct perf_hpp_fmt hpp;
253562306a36Sopenharmony_ci	struct evsel *evsel;
253662306a36Sopenharmony_ci	struct tep_format_field *field;
253762306a36Sopenharmony_ci	unsigned dynamic_len;
253862306a36Sopenharmony_ci	bool raw_trace;
253962306a36Sopenharmony_ci};
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_cistatic int hde_width(struct hpp_dynamic_entry *hde)
254262306a36Sopenharmony_ci{
254362306a36Sopenharmony_ci	if (!hde->hpp.len) {
254462306a36Sopenharmony_ci		int len = hde->dynamic_len;
254562306a36Sopenharmony_ci		int namelen = strlen(hde->field->name);
254662306a36Sopenharmony_ci		int fieldlen = hde->field->size;
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci		if (namelen > len)
254962306a36Sopenharmony_ci			len = namelen;
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci		if (!(hde->field->flags & TEP_FIELD_IS_STRING)) {
255262306a36Sopenharmony_ci			/* length for print hex numbers */
255362306a36Sopenharmony_ci			fieldlen = hde->field->size * 2 + 2;
255462306a36Sopenharmony_ci		}
255562306a36Sopenharmony_ci		if (fieldlen > len)
255662306a36Sopenharmony_ci			len = fieldlen;
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci		hde->hpp.len = len;
255962306a36Sopenharmony_ci	}
256062306a36Sopenharmony_ci	return hde->hpp.len;
256162306a36Sopenharmony_ci}
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_cistatic void update_dynamic_len(struct hpp_dynamic_entry *hde,
256462306a36Sopenharmony_ci			       struct hist_entry *he)
256562306a36Sopenharmony_ci{
256662306a36Sopenharmony_ci	char *str, *pos;
256762306a36Sopenharmony_ci	struct tep_format_field *field = hde->field;
256862306a36Sopenharmony_ci	size_t namelen;
256962306a36Sopenharmony_ci	bool last = false;
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	if (hde->raw_trace)
257262306a36Sopenharmony_ci		return;
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_ci	/* parse pretty print result and update max length */
257562306a36Sopenharmony_ci	if (!he->trace_output)
257662306a36Sopenharmony_ci		he->trace_output = get_trace_output(he);
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci	namelen = strlen(field->name);
257962306a36Sopenharmony_ci	str = he->trace_output;
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci	while (str) {
258262306a36Sopenharmony_ci		pos = strchr(str, ' ');
258362306a36Sopenharmony_ci		if (pos == NULL) {
258462306a36Sopenharmony_ci			last = true;
258562306a36Sopenharmony_ci			pos = str + strlen(str);
258662306a36Sopenharmony_ci		}
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci		if (!strncmp(str, field->name, namelen)) {
258962306a36Sopenharmony_ci			size_t len;
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci			str += namelen + 1;
259262306a36Sopenharmony_ci			len = pos - str;
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_ci			if (len > hde->dynamic_len)
259562306a36Sopenharmony_ci				hde->dynamic_len = len;
259662306a36Sopenharmony_ci			break;
259762306a36Sopenharmony_ci		}
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci		if (last)
260062306a36Sopenharmony_ci			str = NULL;
260162306a36Sopenharmony_ci		else
260262306a36Sopenharmony_ci			str = pos + 1;
260362306a36Sopenharmony_ci	}
260462306a36Sopenharmony_ci}
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_cistatic int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
260762306a36Sopenharmony_ci			      struct hists *hists __maybe_unused,
260862306a36Sopenharmony_ci			      int line __maybe_unused,
260962306a36Sopenharmony_ci			      int *span __maybe_unused)
261062306a36Sopenharmony_ci{
261162306a36Sopenharmony_ci	struct hpp_dynamic_entry *hde;
261262306a36Sopenharmony_ci	size_t len = fmt->user_len;
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	if (!len)
261762306a36Sopenharmony_ci		len = hde_width(hde);
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
262062306a36Sopenharmony_ci}
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_cistatic int __sort__hde_width(struct perf_hpp_fmt *fmt,
262362306a36Sopenharmony_ci			     struct perf_hpp *hpp __maybe_unused,
262462306a36Sopenharmony_ci			     struct hists *hists __maybe_unused)
262562306a36Sopenharmony_ci{
262662306a36Sopenharmony_ci	struct hpp_dynamic_entry *hde;
262762306a36Sopenharmony_ci	size_t len = fmt->user_len;
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	if (!len)
263262306a36Sopenharmony_ci		len = hde_width(hde);
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci	return len;
263562306a36Sopenharmony_ci}
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_cibool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
263862306a36Sopenharmony_ci{
263962306a36Sopenharmony_ci	struct hpp_dynamic_entry *hde;
264062306a36Sopenharmony_ci
264162306a36Sopenharmony_ci	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci	return hists_to_evsel(hists) == hde->evsel;
264462306a36Sopenharmony_ci}
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_cistatic int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
264762306a36Sopenharmony_ci			     struct hist_entry *he)
264862306a36Sopenharmony_ci{
264962306a36Sopenharmony_ci	struct hpp_dynamic_entry *hde;
265062306a36Sopenharmony_ci	size_t len = fmt->user_len;
265162306a36Sopenharmony_ci	char *str, *pos;
265262306a36Sopenharmony_ci	struct tep_format_field *field;
265362306a36Sopenharmony_ci	size_t namelen;
265462306a36Sopenharmony_ci	bool last = false;
265562306a36Sopenharmony_ci	int ret;
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci	if (!len)
266062306a36Sopenharmony_ci		len = hde_width(hde);
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	if (hde->raw_trace)
266362306a36Sopenharmony_ci		goto raw_field;
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci	if (!he->trace_output)
266662306a36Sopenharmony_ci		he->trace_output = get_trace_output(he);
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci	field = hde->field;
266962306a36Sopenharmony_ci	namelen = strlen(field->name);
267062306a36Sopenharmony_ci	str = he->trace_output;
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci	while (str) {
267362306a36Sopenharmony_ci		pos = strchr(str, ' ');
267462306a36Sopenharmony_ci		if (pos == NULL) {
267562306a36Sopenharmony_ci			last = true;
267662306a36Sopenharmony_ci			pos = str + strlen(str);
267762306a36Sopenharmony_ci		}
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci		if (!strncmp(str, field->name, namelen)) {
268062306a36Sopenharmony_ci			str += namelen + 1;
268162306a36Sopenharmony_ci			str = strndup(str, pos - str);
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci			if (str == NULL)
268462306a36Sopenharmony_ci				return scnprintf(hpp->buf, hpp->size,
268562306a36Sopenharmony_ci						 "%*.*s", len, len, "ERROR");
268662306a36Sopenharmony_ci			break;
268762306a36Sopenharmony_ci		}
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci		if (last)
269062306a36Sopenharmony_ci			str = NULL;
269162306a36Sopenharmony_ci		else
269262306a36Sopenharmony_ci			str = pos + 1;
269362306a36Sopenharmony_ci	}
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	if (str == NULL) {
269662306a36Sopenharmony_ci		struct trace_seq seq;
269762306a36Sopenharmony_ciraw_field:
269862306a36Sopenharmony_ci		trace_seq_init(&seq);
269962306a36Sopenharmony_ci		tep_print_field(&seq, he->raw_data, hde->field);
270062306a36Sopenharmony_ci		str = seq.buffer;
270162306a36Sopenharmony_ci	}
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_ci	ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
270462306a36Sopenharmony_ci	free(str);
270562306a36Sopenharmony_ci	return ret;
270662306a36Sopenharmony_ci}
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_cistatic int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
270962306a36Sopenharmony_ci			       struct hist_entry *a, struct hist_entry *b)
271062306a36Sopenharmony_ci{
271162306a36Sopenharmony_ci	struct hpp_dynamic_entry *hde;
271262306a36Sopenharmony_ci	struct tep_format_field *field;
271362306a36Sopenharmony_ci	unsigned offset, size;
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci	field = hde->field;
271862306a36Sopenharmony_ci	if (field->flags & TEP_FIELD_IS_DYNAMIC) {
271962306a36Sopenharmony_ci		unsigned long long dyn;
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci		tep_read_number_field(field, a->raw_data, &dyn);
272262306a36Sopenharmony_ci		offset = dyn & 0xffff;
272362306a36Sopenharmony_ci		size = (dyn >> 16) & 0xffff;
272462306a36Sopenharmony_ci		if (tep_field_is_relative(field->flags))
272562306a36Sopenharmony_ci			offset += field->offset + field->size;
272662306a36Sopenharmony_ci		/* record max width for output */
272762306a36Sopenharmony_ci		if (size > hde->dynamic_len)
272862306a36Sopenharmony_ci			hde->dynamic_len = size;
272962306a36Sopenharmony_ci	} else {
273062306a36Sopenharmony_ci		offset = field->offset;
273162306a36Sopenharmony_ci		size = field->size;
273262306a36Sopenharmony_ci	}
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	return memcmp(a->raw_data + offset, b->raw_data + offset, size);
273562306a36Sopenharmony_ci}
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_cibool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
273862306a36Sopenharmony_ci{
273962306a36Sopenharmony_ci	return fmt->cmp == __sort__hde_cmp;
274062306a36Sopenharmony_ci}
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_cistatic bool __sort__hde_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
274362306a36Sopenharmony_ci{
274462306a36Sopenharmony_ci	struct hpp_dynamic_entry *hde_a;
274562306a36Sopenharmony_ci	struct hpp_dynamic_entry *hde_b;
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	if (!perf_hpp__is_dynamic_entry(a) || !perf_hpp__is_dynamic_entry(b))
274862306a36Sopenharmony_ci		return false;
274962306a36Sopenharmony_ci
275062306a36Sopenharmony_ci	hde_a = container_of(a, struct hpp_dynamic_entry, hpp);
275162306a36Sopenharmony_ci	hde_b = container_of(b, struct hpp_dynamic_entry, hpp);
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci	return hde_a->field == hde_b->field;
275462306a36Sopenharmony_ci}
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_cistatic void hde_free(struct perf_hpp_fmt *fmt)
275762306a36Sopenharmony_ci{
275862306a36Sopenharmony_ci	struct hpp_dynamic_entry *hde;
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
276162306a36Sopenharmony_ci	free(hde);
276262306a36Sopenharmony_ci}
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_cistatic void __sort__hde_init(struct perf_hpp_fmt *fmt, struct hist_entry *he)
276562306a36Sopenharmony_ci{
276662306a36Sopenharmony_ci	struct hpp_dynamic_entry *hde;
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci	if (!perf_hpp__is_dynamic_entry(fmt))
276962306a36Sopenharmony_ci		return;
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
277262306a36Sopenharmony_ci	update_dynamic_len(hde, he);
277362306a36Sopenharmony_ci}
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_cistatic struct hpp_dynamic_entry *
277662306a36Sopenharmony_ci__alloc_dynamic_entry(struct evsel *evsel, struct tep_format_field *field,
277762306a36Sopenharmony_ci		      int level)
277862306a36Sopenharmony_ci{
277962306a36Sopenharmony_ci	struct hpp_dynamic_entry *hde;
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci	hde = malloc(sizeof(*hde));
278262306a36Sopenharmony_ci	if (hde == NULL) {
278362306a36Sopenharmony_ci		pr_debug("Memory allocation failed\n");
278462306a36Sopenharmony_ci		return NULL;
278562306a36Sopenharmony_ci	}
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	hde->evsel = evsel;
278862306a36Sopenharmony_ci	hde->field = field;
278962306a36Sopenharmony_ci	hde->dynamic_len = 0;
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ci	hde->hpp.name = field->name;
279262306a36Sopenharmony_ci	hde->hpp.header = __sort__hde_header;
279362306a36Sopenharmony_ci	hde->hpp.width  = __sort__hde_width;
279462306a36Sopenharmony_ci	hde->hpp.entry  = __sort__hde_entry;
279562306a36Sopenharmony_ci	hde->hpp.color  = NULL;
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci	hde->hpp.init = __sort__hde_init;
279862306a36Sopenharmony_ci	hde->hpp.cmp = __sort__hde_cmp;
279962306a36Sopenharmony_ci	hde->hpp.collapse = __sort__hde_cmp;
280062306a36Sopenharmony_ci	hde->hpp.sort = __sort__hde_cmp;
280162306a36Sopenharmony_ci	hde->hpp.equal = __sort__hde_equal;
280262306a36Sopenharmony_ci	hde->hpp.free = hde_free;
280362306a36Sopenharmony_ci
280462306a36Sopenharmony_ci	INIT_LIST_HEAD(&hde->hpp.list);
280562306a36Sopenharmony_ci	INIT_LIST_HEAD(&hde->hpp.sort_list);
280662306a36Sopenharmony_ci	hde->hpp.elide = false;
280762306a36Sopenharmony_ci	hde->hpp.len = 0;
280862306a36Sopenharmony_ci	hde->hpp.user_len = 0;
280962306a36Sopenharmony_ci	hde->hpp.level = level;
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci	return hde;
281262306a36Sopenharmony_ci}
281362306a36Sopenharmony_ci#endif /* HAVE_LIBTRACEEVENT */
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_cistruct perf_hpp_fmt *perf_hpp_fmt__dup(struct perf_hpp_fmt *fmt)
281662306a36Sopenharmony_ci{
281762306a36Sopenharmony_ci	struct perf_hpp_fmt *new_fmt = NULL;
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_ci	if (perf_hpp__is_sort_entry(fmt)) {
282062306a36Sopenharmony_ci		struct hpp_sort_entry *hse, *new_hse;
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci		hse = container_of(fmt, struct hpp_sort_entry, hpp);
282362306a36Sopenharmony_ci		new_hse = memdup(hse, sizeof(*hse));
282462306a36Sopenharmony_ci		if (new_hse)
282562306a36Sopenharmony_ci			new_fmt = &new_hse->hpp;
282662306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
282762306a36Sopenharmony_ci	} else if (perf_hpp__is_dynamic_entry(fmt)) {
282862306a36Sopenharmony_ci		struct hpp_dynamic_entry *hde, *new_hde;
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci		hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
283162306a36Sopenharmony_ci		new_hde = memdup(hde, sizeof(*hde));
283262306a36Sopenharmony_ci		if (new_hde)
283362306a36Sopenharmony_ci			new_fmt = &new_hde->hpp;
283462306a36Sopenharmony_ci#endif
283562306a36Sopenharmony_ci	} else {
283662306a36Sopenharmony_ci		new_fmt = memdup(fmt, sizeof(*fmt));
283762306a36Sopenharmony_ci	}
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci	INIT_LIST_HEAD(&new_fmt->list);
284062306a36Sopenharmony_ci	INIT_LIST_HEAD(&new_fmt->sort_list);
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci	return new_fmt;
284362306a36Sopenharmony_ci}
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_cistatic int parse_field_name(char *str, char **event, char **field, char **opt)
284662306a36Sopenharmony_ci{
284762306a36Sopenharmony_ci	char *event_name, *field_name, *opt_name;
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_ci	event_name = str;
285062306a36Sopenharmony_ci	field_name = strchr(str, '.');
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci	if (field_name) {
285362306a36Sopenharmony_ci		*field_name++ = '\0';
285462306a36Sopenharmony_ci	} else {
285562306a36Sopenharmony_ci		event_name = NULL;
285662306a36Sopenharmony_ci		field_name = str;
285762306a36Sopenharmony_ci	}
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci	opt_name = strchr(field_name, '/');
286062306a36Sopenharmony_ci	if (opt_name)
286162306a36Sopenharmony_ci		*opt_name++ = '\0';
286262306a36Sopenharmony_ci
286362306a36Sopenharmony_ci	*event = event_name;
286462306a36Sopenharmony_ci	*field = field_name;
286562306a36Sopenharmony_ci	*opt   = opt_name;
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci	return 0;
286862306a36Sopenharmony_ci}
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci/* find match evsel using a given event name.  The event name can be:
287162306a36Sopenharmony_ci *   1. '%' + event index (e.g. '%1' for first event)
287262306a36Sopenharmony_ci *   2. full event name (e.g. sched:sched_switch)
287362306a36Sopenharmony_ci *   3. partial event name (should not contain ':')
287462306a36Sopenharmony_ci */
287562306a36Sopenharmony_cistatic struct evsel *find_evsel(struct evlist *evlist, char *event_name)
287662306a36Sopenharmony_ci{
287762306a36Sopenharmony_ci	struct evsel *evsel = NULL;
287862306a36Sopenharmony_ci	struct evsel *pos;
287962306a36Sopenharmony_ci	bool full_name;
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci	/* case 1 */
288262306a36Sopenharmony_ci	if (event_name[0] == '%') {
288362306a36Sopenharmony_ci		int nr = strtol(event_name+1, NULL, 0);
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci		if (nr > evlist->core.nr_entries)
288662306a36Sopenharmony_ci			return NULL;
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_ci		evsel = evlist__first(evlist);
288962306a36Sopenharmony_ci		while (--nr > 0)
289062306a36Sopenharmony_ci			evsel = evsel__next(evsel);
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci		return evsel;
289362306a36Sopenharmony_ci	}
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_ci	full_name = !!strchr(event_name, ':');
289662306a36Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
289762306a36Sopenharmony_ci		/* case 2 */
289862306a36Sopenharmony_ci		if (full_name && evsel__name_is(pos, event_name))
289962306a36Sopenharmony_ci			return pos;
290062306a36Sopenharmony_ci		/* case 3 */
290162306a36Sopenharmony_ci		if (!full_name && strstr(pos->name, event_name)) {
290262306a36Sopenharmony_ci			if (evsel) {
290362306a36Sopenharmony_ci				pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
290462306a36Sopenharmony_ci					 event_name, evsel->name, pos->name);
290562306a36Sopenharmony_ci				return NULL;
290662306a36Sopenharmony_ci			}
290762306a36Sopenharmony_ci			evsel = pos;
290862306a36Sopenharmony_ci		}
290962306a36Sopenharmony_ci	}
291062306a36Sopenharmony_ci
291162306a36Sopenharmony_ci	return evsel;
291262306a36Sopenharmony_ci}
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
291562306a36Sopenharmony_cistatic int __dynamic_dimension__add(struct evsel *evsel,
291662306a36Sopenharmony_ci				    struct tep_format_field *field,
291762306a36Sopenharmony_ci				    bool raw_trace, int level)
291862306a36Sopenharmony_ci{
291962306a36Sopenharmony_ci	struct hpp_dynamic_entry *hde;
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_ci	hde = __alloc_dynamic_entry(evsel, field, level);
292262306a36Sopenharmony_ci	if (hde == NULL)
292362306a36Sopenharmony_ci		return -ENOMEM;
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_ci	hde->raw_trace = raw_trace;
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_ci	perf_hpp__register_sort_field(&hde->hpp);
292862306a36Sopenharmony_ci	return 0;
292962306a36Sopenharmony_ci}
293062306a36Sopenharmony_ci
293162306a36Sopenharmony_cistatic int add_evsel_fields(struct evsel *evsel, bool raw_trace, int level)
293262306a36Sopenharmony_ci{
293362306a36Sopenharmony_ci	int ret;
293462306a36Sopenharmony_ci	struct tep_format_field *field;
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_ci	field = evsel->tp_format->format.fields;
293762306a36Sopenharmony_ci	while (field) {
293862306a36Sopenharmony_ci		ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
293962306a36Sopenharmony_ci		if (ret < 0)
294062306a36Sopenharmony_ci			return ret;
294162306a36Sopenharmony_ci
294262306a36Sopenharmony_ci		field = field->next;
294362306a36Sopenharmony_ci	}
294462306a36Sopenharmony_ci	return 0;
294562306a36Sopenharmony_ci}
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_cistatic int add_all_dynamic_fields(struct evlist *evlist, bool raw_trace,
294862306a36Sopenharmony_ci				  int level)
294962306a36Sopenharmony_ci{
295062306a36Sopenharmony_ci	int ret;
295162306a36Sopenharmony_ci	struct evsel *evsel;
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
295462306a36Sopenharmony_ci		if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
295562306a36Sopenharmony_ci			continue;
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci		ret = add_evsel_fields(evsel, raw_trace, level);
295862306a36Sopenharmony_ci		if (ret < 0)
295962306a36Sopenharmony_ci			return ret;
296062306a36Sopenharmony_ci	}
296162306a36Sopenharmony_ci	return 0;
296262306a36Sopenharmony_ci}
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_cistatic int add_all_matching_fields(struct evlist *evlist,
296562306a36Sopenharmony_ci				   char *field_name, bool raw_trace, int level)
296662306a36Sopenharmony_ci{
296762306a36Sopenharmony_ci	int ret = -ESRCH;
296862306a36Sopenharmony_ci	struct evsel *evsel;
296962306a36Sopenharmony_ci	struct tep_format_field *field;
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
297262306a36Sopenharmony_ci		if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
297362306a36Sopenharmony_ci			continue;
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ci		field = tep_find_any_field(evsel->tp_format, field_name);
297662306a36Sopenharmony_ci		if (field == NULL)
297762306a36Sopenharmony_ci			continue;
297862306a36Sopenharmony_ci
297962306a36Sopenharmony_ci		ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
298062306a36Sopenharmony_ci		if (ret < 0)
298162306a36Sopenharmony_ci			break;
298262306a36Sopenharmony_ci	}
298362306a36Sopenharmony_ci	return ret;
298462306a36Sopenharmony_ci}
298562306a36Sopenharmony_ci#endif /* HAVE_LIBTRACEEVENT */
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_cistatic int add_dynamic_entry(struct evlist *evlist, const char *tok,
298862306a36Sopenharmony_ci			     int level)
298962306a36Sopenharmony_ci{
299062306a36Sopenharmony_ci	char *str, *event_name, *field_name, *opt_name;
299162306a36Sopenharmony_ci	struct evsel *evsel;
299262306a36Sopenharmony_ci	bool raw_trace = symbol_conf.raw_trace;
299362306a36Sopenharmony_ci	int ret = 0;
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ci	if (evlist == NULL)
299662306a36Sopenharmony_ci		return -ENOENT;
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci	str = strdup(tok);
299962306a36Sopenharmony_ci	if (str == NULL)
300062306a36Sopenharmony_ci		return -ENOMEM;
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_ci	if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
300362306a36Sopenharmony_ci		ret = -EINVAL;
300462306a36Sopenharmony_ci		goto out;
300562306a36Sopenharmony_ci	}
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ci	if (opt_name) {
300862306a36Sopenharmony_ci		if (strcmp(opt_name, "raw")) {
300962306a36Sopenharmony_ci			pr_debug("unsupported field option %s\n", opt_name);
301062306a36Sopenharmony_ci			ret = -EINVAL;
301162306a36Sopenharmony_ci			goto out;
301262306a36Sopenharmony_ci		}
301362306a36Sopenharmony_ci		raw_trace = true;
301462306a36Sopenharmony_ci	}
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
301762306a36Sopenharmony_ci	if (!strcmp(field_name, "trace_fields")) {
301862306a36Sopenharmony_ci		ret = add_all_dynamic_fields(evlist, raw_trace, level);
301962306a36Sopenharmony_ci		goto out;
302062306a36Sopenharmony_ci	}
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_ci	if (event_name == NULL) {
302362306a36Sopenharmony_ci		ret = add_all_matching_fields(evlist, field_name, raw_trace, level);
302462306a36Sopenharmony_ci		goto out;
302562306a36Sopenharmony_ci	}
302662306a36Sopenharmony_ci#else
302762306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
302862306a36Sopenharmony_ci		if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) {
302962306a36Sopenharmony_ci			pr_err("%s %s", ret ? "," : "This perf binary isn't linked with libtraceevent, can't process", evsel__name(evsel));
303062306a36Sopenharmony_ci			ret = -ENOTSUP;
303162306a36Sopenharmony_ci		}
303262306a36Sopenharmony_ci	}
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci	if (ret) {
303562306a36Sopenharmony_ci		pr_err("\n");
303662306a36Sopenharmony_ci		goto out;
303762306a36Sopenharmony_ci	}
303862306a36Sopenharmony_ci#endif
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	evsel = find_evsel(evlist, event_name);
304162306a36Sopenharmony_ci	if (evsel == NULL) {
304262306a36Sopenharmony_ci		pr_debug("Cannot find event: %s\n", event_name);
304362306a36Sopenharmony_ci		ret = -ENOENT;
304462306a36Sopenharmony_ci		goto out;
304562306a36Sopenharmony_ci	}
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) {
304862306a36Sopenharmony_ci		pr_debug("%s is not a tracepoint event\n", event_name);
304962306a36Sopenharmony_ci		ret = -EINVAL;
305062306a36Sopenharmony_ci		goto out;
305162306a36Sopenharmony_ci	}
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
305462306a36Sopenharmony_ci	if (!strcmp(field_name, "*")) {
305562306a36Sopenharmony_ci		ret = add_evsel_fields(evsel, raw_trace, level);
305662306a36Sopenharmony_ci	} else {
305762306a36Sopenharmony_ci		struct tep_format_field *field = tep_find_any_field(evsel->tp_format, field_name);
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_ci		if (field == NULL) {
306062306a36Sopenharmony_ci			pr_debug("Cannot find event field for %s.%s\n",
306162306a36Sopenharmony_ci				 event_name, field_name);
306262306a36Sopenharmony_ci			return -ENOENT;
306362306a36Sopenharmony_ci		}
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci		ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
306662306a36Sopenharmony_ci	}
306762306a36Sopenharmony_ci#else
306862306a36Sopenharmony_ci	(void)level;
306962306a36Sopenharmony_ci	(void)raw_trace;
307062306a36Sopenharmony_ci#endif /* HAVE_LIBTRACEEVENT */
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ciout:
307362306a36Sopenharmony_ci	free(str);
307462306a36Sopenharmony_ci	return ret;
307562306a36Sopenharmony_ci}
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_cistatic int __sort_dimension__add(struct sort_dimension *sd,
307862306a36Sopenharmony_ci				 struct perf_hpp_list *list,
307962306a36Sopenharmony_ci				 int level)
308062306a36Sopenharmony_ci{
308162306a36Sopenharmony_ci	if (sd->taken)
308262306a36Sopenharmony_ci		return 0;
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_ci	if (__sort_dimension__add_hpp_sort(sd, list, level) < 0)
308562306a36Sopenharmony_ci		return -1;
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci	if (sd->entry->se_collapse)
308862306a36Sopenharmony_ci		list->need_collapse = 1;
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	sd->taken = 1;
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci	return 0;
309362306a36Sopenharmony_ci}
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_cistatic int __hpp_dimension__add(struct hpp_dimension *hd,
309662306a36Sopenharmony_ci				struct perf_hpp_list *list,
309762306a36Sopenharmony_ci				int level)
309862306a36Sopenharmony_ci{
309962306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_ci	if (hd->taken)
310262306a36Sopenharmony_ci		return 0;
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ci	fmt = __hpp_dimension__alloc_hpp(hd, level);
310562306a36Sopenharmony_ci	if (!fmt)
310662306a36Sopenharmony_ci		return -1;
310762306a36Sopenharmony_ci
310862306a36Sopenharmony_ci	hd->taken = 1;
310962306a36Sopenharmony_ci	perf_hpp_list__register_sort_field(list, fmt);
311062306a36Sopenharmony_ci	return 0;
311162306a36Sopenharmony_ci}
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_cistatic int __sort_dimension__add_output(struct perf_hpp_list *list,
311462306a36Sopenharmony_ci					struct sort_dimension *sd)
311562306a36Sopenharmony_ci{
311662306a36Sopenharmony_ci	if (sd->taken)
311762306a36Sopenharmony_ci		return 0;
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	if (__sort_dimension__add_hpp_output(sd, list) < 0)
312062306a36Sopenharmony_ci		return -1;
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	sd->taken = 1;
312362306a36Sopenharmony_ci	return 0;
312462306a36Sopenharmony_ci}
312562306a36Sopenharmony_ci
312662306a36Sopenharmony_cistatic int __hpp_dimension__add_output(struct perf_hpp_list *list,
312762306a36Sopenharmony_ci				       struct hpp_dimension *hd)
312862306a36Sopenharmony_ci{
312962306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	if (hd->taken)
313262306a36Sopenharmony_ci		return 0;
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_ci	fmt = __hpp_dimension__alloc_hpp(hd, 0);
313562306a36Sopenharmony_ci	if (!fmt)
313662306a36Sopenharmony_ci		return -1;
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_ci	hd->taken = 1;
313962306a36Sopenharmony_ci	perf_hpp_list__column_register(list, fmt);
314062306a36Sopenharmony_ci	return 0;
314162306a36Sopenharmony_ci}
314262306a36Sopenharmony_ci
314362306a36Sopenharmony_ciint hpp_dimension__add_output(unsigned col)
314462306a36Sopenharmony_ci{
314562306a36Sopenharmony_ci	BUG_ON(col >= PERF_HPP__MAX_INDEX);
314662306a36Sopenharmony_ci	return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
314762306a36Sopenharmony_ci}
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ciint sort_dimension__add(struct perf_hpp_list *list, const char *tok,
315062306a36Sopenharmony_ci			struct evlist *evlist,
315162306a36Sopenharmony_ci			int level)
315262306a36Sopenharmony_ci{
315362306a36Sopenharmony_ci	unsigned int i, j;
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_ci	/*
315662306a36Sopenharmony_ci	 * Check to see if there are any arch specific
315762306a36Sopenharmony_ci	 * sort dimensions not applicable for the current
315862306a36Sopenharmony_ci	 * architecture. If so, Skip that sort key since
315962306a36Sopenharmony_ci	 * we don't want to display it in the output fields.
316062306a36Sopenharmony_ci	 */
316162306a36Sopenharmony_ci	for (j = 0; j < ARRAY_SIZE(arch_specific_sort_keys); j++) {
316262306a36Sopenharmony_ci		if (!strcmp(arch_specific_sort_keys[j], tok) &&
316362306a36Sopenharmony_ci				!arch_support_sort_key(tok)) {
316462306a36Sopenharmony_ci			return 0;
316562306a36Sopenharmony_ci		}
316662306a36Sopenharmony_ci	}
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
316962306a36Sopenharmony_ci		struct sort_dimension *sd = &common_sort_dimensions[i];
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_ci		if (!sd->name || strncasecmp(tok, sd->name, strlen(tok)))
317262306a36Sopenharmony_ci			continue;
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(dynamic_headers); j++) {
317562306a36Sopenharmony_ci			if (sd->name && !strcmp(dynamic_headers[j], sd->name))
317662306a36Sopenharmony_ci				sort_dimension_add_dynamic_header(sd);
317762306a36Sopenharmony_ci		}
317862306a36Sopenharmony_ci
317962306a36Sopenharmony_ci		if (sd->entry == &sort_parent) {
318062306a36Sopenharmony_ci			int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
318162306a36Sopenharmony_ci			if (ret) {
318262306a36Sopenharmony_ci				char err[BUFSIZ];
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci				regerror(ret, &parent_regex, err, sizeof(err));
318562306a36Sopenharmony_ci				pr_err("Invalid regex: %s\n%s", parent_pattern, err);
318662306a36Sopenharmony_ci				return -EINVAL;
318762306a36Sopenharmony_ci			}
318862306a36Sopenharmony_ci			list->parent = 1;
318962306a36Sopenharmony_ci		} else if (sd->entry == &sort_sym) {
319062306a36Sopenharmony_ci			list->sym = 1;
319162306a36Sopenharmony_ci			/*
319262306a36Sopenharmony_ci			 * perf diff displays the performance difference amongst
319362306a36Sopenharmony_ci			 * two or more perf.data files. Those files could come
319462306a36Sopenharmony_ci			 * from different binaries. So we should not compare
319562306a36Sopenharmony_ci			 * their ips, but the name of symbol.
319662306a36Sopenharmony_ci			 */
319762306a36Sopenharmony_ci			if (sort__mode == SORT_MODE__DIFF)
319862306a36Sopenharmony_ci				sd->entry->se_collapse = sort__sym_sort;
319962306a36Sopenharmony_ci
320062306a36Sopenharmony_ci		} else if (sd->entry == &sort_dso) {
320162306a36Sopenharmony_ci			list->dso = 1;
320262306a36Sopenharmony_ci		} else if (sd->entry == &sort_socket) {
320362306a36Sopenharmony_ci			list->socket = 1;
320462306a36Sopenharmony_ci		} else if (sd->entry == &sort_thread) {
320562306a36Sopenharmony_ci			list->thread = 1;
320662306a36Sopenharmony_ci		} else if (sd->entry == &sort_comm) {
320762306a36Sopenharmony_ci			list->comm = 1;
320862306a36Sopenharmony_ci		}
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci		return __sort_dimension__add(sd, list, level);
321162306a36Sopenharmony_ci	}
321262306a36Sopenharmony_ci
321362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
321462306a36Sopenharmony_ci		struct hpp_dimension *hd = &hpp_sort_dimensions[i];
321562306a36Sopenharmony_ci
321662306a36Sopenharmony_ci		if (strncasecmp(tok, hd->name, strlen(tok)))
321762306a36Sopenharmony_ci			continue;
321862306a36Sopenharmony_ci
321962306a36Sopenharmony_ci		return __hpp_dimension__add(hd, list, level);
322062306a36Sopenharmony_ci	}
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
322362306a36Sopenharmony_ci		struct sort_dimension *sd = &bstack_sort_dimensions[i];
322462306a36Sopenharmony_ci
322562306a36Sopenharmony_ci		if (!sd->name || strncasecmp(tok, sd->name, strlen(tok)))
322662306a36Sopenharmony_ci			continue;
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci		if (sort__mode != SORT_MODE__BRANCH)
322962306a36Sopenharmony_ci			return -EINVAL;
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci		if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
323262306a36Sopenharmony_ci			list->sym = 1;
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ci		__sort_dimension__add(sd, list, level);
323562306a36Sopenharmony_ci		return 0;
323662306a36Sopenharmony_ci	}
323762306a36Sopenharmony_ci
323862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
323962306a36Sopenharmony_ci		struct sort_dimension *sd = &memory_sort_dimensions[i];
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_ci		if (!sd->name || strncasecmp(tok, sd->name, strlen(tok)))
324262306a36Sopenharmony_ci			continue;
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci		if (sort__mode != SORT_MODE__MEMORY)
324562306a36Sopenharmony_ci			return -EINVAL;
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_ci		if (sd->entry == &sort_mem_dcacheline && cacheline_size() == 0)
324862306a36Sopenharmony_ci			return -EINVAL;
324962306a36Sopenharmony_ci
325062306a36Sopenharmony_ci		if (sd->entry == &sort_mem_daddr_sym)
325162306a36Sopenharmony_ci			list->sym = 1;
325262306a36Sopenharmony_ci
325362306a36Sopenharmony_ci		__sort_dimension__add(sd, list, level);
325462306a36Sopenharmony_ci		return 0;
325562306a36Sopenharmony_ci	}
325662306a36Sopenharmony_ci
325762306a36Sopenharmony_ci	if (!add_dynamic_entry(evlist, tok, level))
325862306a36Sopenharmony_ci		return 0;
325962306a36Sopenharmony_ci
326062306a36Sopenharmony_ci	return -ESRCH;
326162306a36Sopenharmony_ci}
326262306a36Sopenharmony_ci
326362306a36Sopenharmony_cistatic int setup_sort_list(struct perf_hpp_list *list, char *str,
326462306a36Sopenharmony_ci			   struct evlist *evlist)
326562306a36Sopenharmony_ci{
326662306a36Sopenharmony_ci	char *tmp, *tok;
326762306a36Sopenharmony_ci	int ret = 0;
326862306a36Sopenharmony_ci	int level = 0;
326962306a36Sopenharmony_ci	int next_level = 1;
327062306a36Sopenharmony_ci	bool in_group = false;
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci	do {
327362306a36Sopenharmony_ci		tok = str;
327462306a36Sopenharmony_ci		tmp = strpbrk(str, "{}, ");
327562306a36Sopenharmony_ci		if (tmp) {
327662306a36Sopenharmony_ci			if (in_group)
327762306a36Sopenharmony_ci				next_level = level;
327862306a36Sopenharmony_ci			else
327962306a36Sopenharmony_ci				next_level = level + 1;
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci			if (*tmp == '{')
328262306a36Sopenharmony_ci				in_group = true;
328362306a36Sopenharmony_ci			else if (*tmp == '}')
328462306a36Sopenharmony_ci				in_group = false;
328562306a36Sopenharmony_ci
328662306a36Sopenharmony_ci			*tmp = '\0';
328762306a36Sopenharmony_ci			str = tmp + 1;
328862306a36Sopenharmony_ci		}
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci		if (*tok) {
329162306a36Sopenharmony_ci			ret = sort_dimension__add(list, tok, evlist, level);
329262306a36Sopenharmony_ci			if (ret == -EINVAL) {
329362306a36Sopenharmony_ci				if (!cacheline_size() && !strncasecmp(tok, "dcacheline", strlen(tok)))
329462306a36Sopenharmony_ci					ui__error("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system");
329562306a36Sopenharmony_ci				else
329662306a36Sopenharmony_ci					ui__error("Invalid --sort key: `%s'", tok);
329762306a36Sopenharmony_ci				break;
329862306a36Sopenharmony_ci			} else if (ret == -ESRCH) {
329962306a36Sopenharmony_ci				ui__error("Unknown --sort key: `%s'", tok);
330062306a36Sopenharmony_ci				break;
330162306a36Sopenharmony_ci			}
330262306a36Sopenharmony_ci		}
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci		level = next_level;
330562306a36Sopenharmony_ci	} while (tmp);
330662306a36Sopenharmony_ci
330762306a36Sopenharmony_ci	return ret;
330862306a36Sopenharmony_ci}
330962306a36Sopenharmony_ci
331062306a36Sopenharmony_cistatic const char *get_default_sort_order(struct evlist *evlist)
331162306a36Sopenharmony_ci{
331262306a36Sopenharmony_ci	const char *default_sort_orders[] = {
331362306a36Sopenharmony_ci		default_sort_order,
331462306a36Sopenharmony_ci		default_branch_sort_order,
331562306a36Sopenharmony_ci		default_mem_sort_order,
331662306a36Sopenharmony_ci		default_top_sort_order,
331762306a36Sopenharmony_ci		default_diff_sort_order,
331862306a36Sopenharmony_ci		default_tracepoint_sort_order,
331962306a36Sopenharmony_ci	};
332062306a36Sopenharmony_ci	bool use_trace = true;
332162306a36Sopenharmony_ci	struct evsel *evsel;
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci	BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci	if (evlist == NULL || evlist__empty(evlist))
332662306a36Sopenharmony_ci		goto out_no_evlist;
332762306a36Sopenharmony_ci
332862306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
332962306a36Sopenharmony_ci		if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) {
333062306a36Sopenharmony_ci			use_trace = false;
333162306a36Sopenharmony_ci			break;
333262306a36Sopenharmony_ci		}
333362306a36Sopenharmony_ci	}
333462306a36Sopenharmony_ci
333562306a36Sopenharmony_ci	if (use_trace) {
333662306a36Sopenharmony_ci		sort__mode = SORT_MODE__TRACEPOINT;
333762306a36Sopenharmony_ci		if (symbol_conf.raw_trace)
333862306a36Sopenharmony_ci			return "trace_fields";
333962306a36Sopenharmony_ci	}
334062306a36Sopenharmony_ciout_no_evlist:
334162306a36Sopenharmony_ci	return default_sort_orders[sort__mode];
334262306a36Sopenharmony_ci}
334362306a36Sopenharmony_ci
334462306a36Sopenharmony_cistatic int setup_sort_order(struct evlist *evlist)
334562306a36Sopenharmony_ci{
334662306a36Sopenharmony_ci	char *new_sort_order;
334762306a36Sopenharmony_ci
334862306a36Sopenharmony_ci	/*
334962306a36Sopenharmony_ci	 * Append '+'-prefixed sort order to the default sort
335062306a36Sopenharmony_ci	 * order string.
335162306a36Sopenharmony_ci	 */
335262306a36Sopenharmony_ci	if (!sort_order || is_strict_order(sort_order))
335362306a36Sopenharmony_ci		return 0;
335462306a36Sopenharmony_ci
335562306a36Sopenharmony_ci	if (sort_order[1] == '\0') {
335662306a36Sopenharmony_ci		ui__error("Invalid --sort key: `+'");
335762306a36Sopenharmony_ci		return -EINVAL;
335862306a36Sopenharmony_ci	}
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci	/*
336162306a36Sopenharmony_ci	 * We allocate new sort_order string, but we never free it,
336262306a36Sopenharmony_ci	 * because it's checked over the rest of the code.
336362306a36Sopenharmony_ci	 */
336462306a36Sopenharmony_ci	if (asprintf(&new_sort_order, "%s,%s",
336562306a36Sopenharmony_ci		     get_default_sort_order(evlist), sort_order + 1) < 0) {
336662306a36Sopenharmony_ci		pr_err("Not enough memory to set up --sort");
336762306a36Sopenharmony_ci		return -ENOMEM;
336862306a36Sopenharmony_ci	}
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci	sort_order = new_sort_order;
337162306a36Sopenharmony_ci	return 0;
337262306a36Sopenharmony_ci}
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_ci/*
337562306a36Sopenharmony_ci * Adds 'pre,' prefix into 'str' is 'pre' is
337662306a36Sopenharmony_ci * not already part of 'str'.
337762306a36Sopenharmony_ci */
337862306a36Sopenharmony_cistatic char *prefix_if_not_in(const char *pre, char *str)
337962306a36Sopenharmony_ci{
338062306a36Sopenharmony_ci	char *n;
338162306a36Sopenharmony_ci
338262306a36Sopenharmony_ci	if (!str || strstr(str, pre))
338362306a36Sopenharmony_ci		return str;
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ci	if (asprintf(&n, "%s,%s", pre, str) < 0)
338662306a36Sopenharmony_ci		n = NULL;
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci	free(str);
338962306a36Sopenharmony_ci	return n;
339062306a36Sopenharmony_ci}
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_cistatic char *setup_overhead(char *keys)
339362306a36Sopenharmony_ci{
339462306a36Sopenharmony_ci	if (sort__mode == SORT_MODE__DIFF)
339562306a36Sopenharmony_ci		return keys;
339662306a36Sopenharmony_ci
339762306a36Sopenharmony_ci	keys = prefix_if_not_in("overhead", keys);
339862306a36Sopenharmony_ci
339962306a36Sopenharmony_ci	if (symbol_conf.cumulate_callchain)
340062306a36Sopenharmony_ci		keys = prefix_if_not_in("overhead_children", keys);
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_ci	return keys;
340362306a36Sopenharmony_ci}
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_cistatic int __setup_sorting(struct evlist *evlist)
340662306a36Sopenharmony_ci{
340762306a36Sopenharmony_ci	char *str;
340862306a36Sopenharmony_ci	const char *sort_keys;
340962306a36Sopenharmony_ci	int ret = 0;
341062306a36Sopenharmony_ci
341162306a36Sopenharmony_ci	ret = setup_sort_order(evlist);
341262306a36Sopenharmony_ci	if (ret)
341362306a36Sopenharmony_ci		return ret;
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci	sort_keys = sort_order;
341662306a36Sopenharmony_ci	if (sort_keys == NULL) {
341762306a36Sopenharmony_ci		if (is_strict_order(field_order)) {
341862306a36Sopenharmony_ci			/*
341962306a36Sopenharmony_ci			 * If user specified field order but no sort order,
342062306a36Sopenharmony_ci			 * we'll honor it and not add default sort orders.
342162306a36Sopenharmony_ci			 */
342262306a36Sopenharmony_ci			return 0;
342362306a36Sopenharmony_ci		}
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci		sort_keys = get_default_sort_order(evlist);
342662306a36Sopenharmony_ci	}
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	str = strdup(sort_keys);
342962306a36Sopenharmony_ci	if (str == NULL) {
343062306a36Sopenharmony_ci		pr_err("Not enough memory to setup sort keys");
343162306a36Sopenharmony_ci		return -ENOMEM;
343262306a36Sopenharmony_ci	}
343362306a36Sopenharmony_ci
343462306a36Sopenharmony_ci	/*
343562306a36Sopenharmony_ci	 * Prepend overhead fields for backward compatibility.
343662306a36Sopenharmony_ci	 */
343762306a36Sopenharmony_ci	if (!is_strict_order(field_order)) {
343862306a36Sopenharmony_ci		str = setup_overhead(str);
343962306a36Sopenharmony_ci		if (str == NULL) {
344062306a36Sopenharmony_ci			pr_err("Not enough memory to setup overhead keys");
344162306a36Sopenharmony_ci			return -ENOMEM;
344262306a36Sopenharmony_ci		}
344362306a36Sopenharmony_ci	}
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_ci	ret = setup_sort_list(&perf_hpp_list, str, evlist);
344662306a36Sopenharmony_ci
344762306a36Sopenharmony_ci	free(str);
344862306a36Sopenharmony_ci	return ret;
344962306a36Sopenharmony_ci}
345062306a36Sopenharmony_ci
345162306a36Sopenharmony_civoid perf_hpp__set_elide(int idx, bool elide)
345262306a36Sopenharmony_ci{
345362306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
345462306a36Sopenharmony_ci	struct hpp_sort_entry *hse;
345562306a36Sopenharmony_ci
345662306a36Sopenharmony_ci	perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
345762306a36Sopenharmony_ci		if (!perf_hpp__is_sort_entry(fmt))
345862306a36Sopenharmony_ci			continue;
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci		hse = container_of(fmt, struct hpp_sort_entry, hpp);
346162306a36Sopenharmony_ci		if (hse->se->se_width_idx == idx) {
346262306a36Sopenharmony_ci			fmt->elide = elide;
346362306a36Sopenharmony_ci			break;
346462306a36Sopenharmony_ci		}
346562306a36Sopenharmony_ci	}
346662306a36Sopenharmony_ci}
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_cistatic bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
346962306a36Sopenharmony_ci{
347062306a36Sopenharmony_ci	if (list && strlist__nr_entries(list) == 1) {
347162306a36Sopenharmony_ci		if (fp != NULL)
347262306a36Sopenharmony_ci			fprintf(fp, "# %s: %s\n", list_name,
347362306a36Sopenharmony_ci				strlist__entry(list, 0)->s);
347462306a36Sopenharmony_ci		return true;
347562306a36Sopenharmony_ci	}
347662306a36Sopenharmony_ci	return false;
347762306a36Sopenharmony_ci}
347862306a36Sopenharmony_ci
347962306a36Sopenharmony_cistatic bool get_elide(int idx, FILE *output)
348062306a36Sopenharmony_ci{
348162306a36Sopenharmony_ci	switch (idx) {
348262306a36Sopenharmony_ci	case HISTC_SYMBOL:
348362306a36Sopenharmony_ci		return __get_elide(symbol_conf.sym_list, "symbol", output);
348462306a36Sopenharmony_ci	case HISTC_DSO:
348562306a36Sopenharmony_ci		return __get_elide(symbol_conf.dso_list, "dso", output);
348662306a36Sopenharmony_ci	case HISTC_COMM:
348762306a36Sopenharmony_ci		return __get_elide(symbol_conf.comm_list, "comm", output);
348862306a36Sopenharmony_ci	default:
348962306a36Sopenharmony_ci		break;
349062306a36Sopenharmony_ci	}
349162306a36Sopenharmony_ci
349262306a36Sopenharmony_ci	if (sort__mode != SORT_MODE__BRANCH)
349362306a36Sopenharmony_ci		return false;
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_ci	switch (idx) {
349662306a36Sopenharmony_ci	case HISTC_SYMBOL_FROM:
349762306a36Sopenharmony_ci		return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
349862306a36Sopenharmony_ci	case HISTC_SYMBOL_TO:
349962306a36Sopenharmony_ci		return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
350062306a36Sopenharmony_ci	case HISTC_DSO_FROM:
350162306a36Sopenharmony_ci		return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
350262306a36Sopenharmony_ci	case HISTC_DSO_TO:
350362306a36Sopenharmony_ci		return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
350462306a36Sopenharmony_ci	case HISTC_ADDR_FROM:
350562306a36Sopenharmony_ci		return __get_elide(symbol_conf.sym_from_list, "addr_from", output);
350662306a36Sopenharmony_ci	case HISTC_ADDR_TO:
350762306a36Sopenharmony_ci		return __get_elide(symbol_conf.sym_to_list, "addr_to", output);
350862306a36Sopenharmony_ci	default:
350962306a36Sopenharmony_ci		break;
351062306a36Sopenharmony_ci	}
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci	return false;
351362306a36Sopenharmony_ci}
351462306a36Sopenharmony_ci
351562306a36Sopenharmony_civoid sort__setup_elide(FILE *output)
351662306a36Sopenharmony_ci{
351762306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt;
351862306a36Sopenharmony_ci	struct hpp_sort_entry *hse;
351962306a36Sopenharmony_ci
352062306a36Sopenharmony_ci	perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
352162306a36Sopenharmony_ci		if (!perf_hpp__is_sort_entry(fmt))
352262306a36Sopenharmony_ci			continue;
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci		hse = container_of(fmt, struct hpp_sort_entry, hpp);
352562306a36Sopenharmony_ci		fmt->elide = get_elide(hse->se->se_width_idx, output);
352662306a36Sopenharmony_ci	}
352762306a36Sopenharmony_ci
352862306a36Sopenharmony_ci	/*
352962306a36Sopenharmony_ci	 * It makes no sense to elide all of sort entries.
353062306a36Sopenharmony_ci	 * Just revert them to show up again.
353162306a36Sopenharmony_ci	 */
353262306a36Sopenharmony_ci	perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
353362306a36Sopenharmony_ci		if (!perf_hpp__is_sort_entry(fmt))
353462306a36Sopenharmony_ci			continue;
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_ci		if (!fmt->elide)
353762306a36Sopenharmony_ci			return;
353862306a36Sopenharmony_ci	}
353962306a36Sopenharmony_ci
354062306a36Sopenharmony_ci	perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
354162306a36Sopenharmony_ci		if (!perf_hpp__is_sort_entry(fmt))
354262306a36Sopenharmony_ci			continue;
354362306a36Sopenharmony_ci
354462306a36Sopenharmony_ci		fmt->elide = false;
354562306a36Sopenharmony_ci	}
354662306a36Sopenharmony_ci}
354762306a36Sopenharmony_ci
354862306a36Sopenharmony_ciint output_field_add(struct perf_hpp_list *list, char *tok)
354962306a36Sopenharmony_ci{
355062306a36Sopenharmony_ci	unsigned int i;
355162306a36Sopenharmony_ci
355262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
355362306a36Sopenharmony_ci		struct sort_dimension *sd = &common_sort_dimensions[i];
355462306a36Sopenharmony_ci
355562306a36Sopenharmony_ci		if (!sd->name || strncasecmp(tok, sd->name, strlen(tok)))
355662306a36Sopenharmony_ci			continue;
355762306a36Sopenharmony_ci
355862306a36Sopenharmony_ci		return __sort_dimension__add_output(list, sd);
355962306a36Sopenharmony_ci	}
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
356262306a36Sopenharmony_ci		struct hpp_dimension *hd = &hpp_sort_dimensions[i];
356362306a36Sopenharmony_ci
356462306a36Sopenharmony_ci		if (strncasecmp(tok, hd->name, strlen(tok)))
356562306a36Sopenharmony_ci			continue;
356662306a36Sopenharmony_ci
356762306a36Sopenharmony_ci		return __hpp_dimension__add_output(list, hd);
356862306a36Sopenharmony_ci	}
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
357162306a36Sopenharmony_ci		struct sort_dimension *sd = &bstack_sort_dimensions[i];
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_ci		if (!sd->name || strncasecmp(tok, sd->name, strlen(tok)))
357462306a36Sopenharmony_ci			continue;
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ci		if (sort__mode != SORT_MODE__BRANCH)
357762306a36Sopenharmony_ci			return -EINVAL;
357862306a36Sopenharmony_ci
357962306a36Sopenharmony_ci		return __sort_dimension__add_output(list, sd);
358062306a36Sopenharmony_ci	}
358162306a36Sopenharmony_ci
358262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
358362306a36Sopenharmony_ci		struct sort_dimension *sd = &memory_sort_dimensions[i];
358462306a36Sopenharmony_ci
358562306a36Sopenharmony_ci		if (!sd->name || strncasecmp(tok, sd->name, strlen(tok)))
358662306a36Sopenharmony_ci			continue;
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_ci		if (sort__mode != SORT_MODE__MEMORY)
358962306a36Sopenharmony_ci			return -EINVAL;
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci		return __sort_dimension__add_output(list, sd);
359262306a36Sopenharmony_ci	}
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_ci	return -ESRCH;
359562306a36Sopenharmony_ci}
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_cistatic int setup_output_list(struct perf_hpp_list *list, char *str)
359862306a36Sopenharmony_ci{
359962306a36Sopenharmony_ci	char *tmp, *tok;
360062306a36Sopenharmony_ci	int ret = 0;
360162306a36Sopenharmony_ci
360262306a36Sopenharmony_ci	for (tok = strtok_r(str, ", ", &tmp);
360362306a36Sopenharmony_ci			tok; tok = strtok_r(NULL, ", ", &tmp)) {
360462306a36Sopenharmony_ci		ret = output_field_add(list, tok);
360562306a36Sopenharmony_ci		if (ret == -EINVAL) {
360662306a36Sopenharmony_ci			ui__error("Invalid --fields key: `%s'", tok);
360762306a36Sopenharmony_ci			break;
360862306a36Sopenharmony_ci		} else if (ret == -ESRCH) {
360962306a36Sopenharmony_ci			ui__error("Unknown --fields key: `%s'", tok);
361062306a36Sopenharmony_ci			break;
361162306a36Sopenharmony_ci		}
361262306a36Sopenharmony_ci	}
361362306a36Sopenharmony_ci
361462306a36Sopenharmony_ci	return ret;
361562306a36Sopenharmony_ci}
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_civoid reset_dimensions(void)
361862306a36Sopenharmony_ci{
361962306a36Sopenharmony_ci	unsigned int i;
362062306a36Sopenharmony_ci
362162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
362262306a36Sopenharmony_ci		common_sort_dimensions[i].taken = 0;
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
362562306a36Sopenharmony_ci		hpp_sort_dimensions[i].taken = 0;
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
362862306a36Sopenharmony_ci		bstack_sort_dimensions[i].taken = 0;
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
363162306a36Sopenharmony_ci		memory_sort_dimensions[i].taken = 0;
363262306a36Sopenharmony_ci}
363362306a36Sopenharmony_ci
363462306a36Sopenharmony_cibool is_strict_order(const char *order)
363562306a36Sopenharmony_ci{
363662306a36Sopenharmony_ci	return order && (*order != '+');
363762306a36Sopenharmony_ci}
363862306a36Sopenharmony_ci
363962306a36Sopenharmony_cistatic int __setup_output_field(void)
364062306a36Sopenharmony_ci{
364162306a36Sopenharmony_ci	char *str, *strp;
364262306a36Sopenharmony_ci	int ret = -EINVAL;
364362306a36Sopenharmony_ci
364462306a36Sopenharmony_ci	if (field_order == NULL)
364562306a36Sopenharmony_ci		return 0;
364662306a36Sopenharmony_ci
364762306a36Sopenharmony_ci	strp = str = strdup(field_order);
364862306a36Sopenharmony_ci	if (str == NULL) {
364962306a36Sopenharmony_ci		pr_err("Not enough memory to setup output fields");
365062306a36Sopenharmony_ci		return -ENOMEM;
365162306a36Sopenharmony_ci	}
365262306a36Sopenharmony_ci
365362306a36Sopenharmony_ci	if (!is_strict_order(field_order))
365462306a36Sopenharmony_ci		strp++;
365562306a36Sopenharmony_ci
365662306a36Sopenharmony_ci	if (!strlen(strp)) {
365762306a36Sopenharmony_ci		ui__error("Invalid --fields key: `+'");
365862306a36Sopenharmony_ci		goto out;
365962306a36Sopenharmony_ci	}
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci	ret = setup_output_list(&perf_hpp_list, strp);
366262306a36Sopenharmony_ci
366362306a36Sopenharmony_ciout:
366462306a36Sopenharmony_ci	free(str);
366562306a36Sopenharmony_ci	return ret;
366662306a36Sopenharmony_ci}
366762306a36Sopenharmony_ci
366862306a36Sopenharmony_ciint setup_sorting(struct evlist *evlist)
366962306a36Sopenharmony_ci{
367062306a36Sopenharmony_ci	int err;
367162306a36Sopenharmony_ci
367262306a36Sopenharmony_ci	err = __setup_sorting(evlist);
367362306a36Sopenharmony_ci	if (err < 0)
367462306a36Sopenharmony_ci		return err;
367562306a36Sopenharmony_ci
367662306a36Sopenharmony_ci	if (parent_pattern != default_parent_pattern) {
367762306a36Sopenharmony_ci		err = sort_dimension__add(&perf_hpp_list, "parent", evlist, -1);
367862306a36Sopenharmony_ci		if (err < 0)
367962306a36Sopenharmony_ci			return err;
368062306a36Sopenharmony_ci	}
368162306a36Sopenharmony_ci
368262306a36Sopenharmony_ci	reset_dimensions();
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_ci	/*
368562306a36Sopenharmony_ci	 * perf diff doesn't use default hpp output fields.
368662306a36Sopenharmony_ci	 */
368762306a36Sopenharmony_ci	if (sort__mode != SORT_MODE__DIFF)
368862306a36Sopenharmony_ci		perf_hpp__init();
368962306a36Sopenharmony_ci
369062306a36Sopenharmony_ci	err = __setup_output_field();
369162306a36Sopenharmony_ci	if (err < 0)
369262306a36Sopenharmony_ci		return err;
369362306a36Sopenharmony_ci
369462306a36Sopenharmony_ci	/* copy sort keys to output fields */
369562306a36Sopenharmony_ci	perf_hpp__setup_output_field(&perf_hpp_list);
369662306a36Sopenharmony_ci	/* and then copy output fields to sort keys */
369762306a36Sopenharmony_ci	perf_hpp__append_sort_keys(&perf_hpp_list);
369862306a36Sopenharmony_ci
369962306a36Sopenharmony_ci	/* setup hists-specific output fields */
370062306a36Sopenharmony_ci	if (perf_hpp__setup_hists_formats(&perf_hpp_list, evlist) < 0)
370162306a36Sopenharmony_ci		return -1;
370262306a36Sopenharmony_ci
370362306a36Sopenharmony_ci	return 0;
370462306a36Sopenharmony_ci}
370562306a36Sopenharmony_ci
370662306a36Sopenharmony_civoid reset_output_field(void)
370762306a36Sopenharmony_ci{
370862306a36Sopenharmony_ci	perf_hpp_list.need_collapse = 0;
370962306a36Sopenharmony_ci	perf_hpp_list.parent = 0;
371062306a36Sopenharmony_ci	perf_hpp_list.sym = 0;
371162306a36Sopenharmony_ci	perf_hpp_list.dso = 0;
371262306a36Sopenharmony_ci
371362306a36Sopenharmony_ci	field_order = NULL;
371462306a36Sopenharmony_ci	sort_order = NULL;
371562306a36Sopenharmony_ci
371662306a36Sopenharmony_ci	reset_dimensions();
371762306a36Sopenharmony_ci	perf_hpp__reset_output_field(&perf_hpp_list);
371862306a36Sopenharmony_ci}
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_ci#define INDENT (3*8 + 1)
372162306a36Sopenharmony_ci
372262306a36Sopenharmony_cistatic void add_key(struct strbuf *sb, const char *str, int *llen)
372362306a36Sopenharmony_ci{
372462306a36Sopenharmony_ci	if (!str)
372562306a36Sopenharmony_ci		return;
372662306a36Sopenharmony_ci
372762306a36Sopenharmony_ci	if (*llen >= 75) {
372862306a36Sopenharmony_ci		strbuf_addstr(sb, "\n\t\t\t ");
372962306a36Sopenharmony_ci		*llen = INDENT;
373062306a36Sopenharmony_ci	}
373162306a36Sopenharmony_ci	strbuf_addf(sb, " %s", str);
373262306a36Sopenharmony_ci	*llen += strlen(str) + 1;
373362306a36Sopenharmony_ci}
373462306a36Sopenharmony_ci
373562306a36Sopenharmony_cistatic void add_sort_string(struct strbuf *sb, struct sort_dimension *s, int n,
373662306a36Sopenharmony_ci			    int *llen)
373762306a36Sopenharmony_ci{
373862306a36Sopenharmony_ci	int i;
373962306a36Sopenharmony_ci
374062306a36Sopenharmony_ci	for (i = 0; i < n; i++)
374162306a36Sopenharmony_ci		add_key(sb, s[i].name, llen);
374262306a36Sopenharmony_ci}
374362306a36Sopenharmony_ci
374462306a36Sopenharmony_cistatic void add_hpp_sort_string(struct strbuf *sb, struct hpp_dimension *s, int n,
374562306a36Sopenharmony_ci				int *llen)
374662306a36Sopenharmony_ci{
374762306a36Sopenharmony_ci	int i;
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_ci	for (i = 0; i < n; i++)
375062306a36Sopenharmony_ci		add_key(sb, s[i].name, llen);
375162306a36Sopenharmony_ci}
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_cichar *sort_help(const char *prefix)
375462306a36Sopenharmony_ci{
375562306a36Sopenharmony_ci	struct strbuf sb;
375662306a36Sopenharmony_ci	char *s;
375762306a36Sopenharmony_ci	int len = strlen(prefix) + INDENT;
375862306a36Sopenharmony_ci
375962306a36Sopenharmony_ci	strbuf_init(&sb, 300);
376062306a36Sopenharmony_ci	strbuf_addstr(&sb, prefix);
376162306a36Sopenharmony_ci	add_hpp_sort_string(&sb, hpp_sort_dimensions,
376262306a36Sopenharmony_ci			    ARRAY_SIZE(hpp_sort_dimensions), &len);
376362306a36Sopenharmony_ci	add_sort_string(&sb, common_sort_dimensions,
376462306a36Sopenharmony_ci			    ARRAY_SIZE(common_sort_dimensions), &len);
376562306a36Sopenharmony_ci	add_sort_string(&sb, bstack_sort_dimensions,
376662306a36Sopenharmony_ci			    ARRAY_SIZE(bstack_sort_dimensions), &len);
376762306a36Sopenharmony_ci	add_sort_string(&sb, memory_sort_dimensions,
376862306a36Sopenharmony_ci			    ARRAY_SIZE(memory_sort_dimensions), &len);
376962306a36Sopenharmony_ci	s = strbuf_detach(&sb, NULL);
377062306a36Sopenharmony_ci	strbuf_release(&sb);
377162306a36Sopenharmony_ci	return s;
377262306a36Sopenharmony_ci}
3773