File Index
Files and directories
Sign in
FILE

sort.c

File preview with syntax highlighting.

linux-6.19.14/tools/perf/util/sort.c C
   1// SPDX-License-Identifier: GPL-2.0
   2#include <errno.h>
   3#include <inttypes.h>
   4#include <regex.h>
   5#include <stdlib.h>
   6#include <linux/mman.h>
   7#include <linux/time64.h>
   8#include "debug.h"
   9#include "dso.h"
  10#include "sort.h"
  11#include "hist.h"
  12#include "cacheline.h"
  13#include "comm.h"
  14#include "map.h"
  15#include "maps.h"
  16#include "symbol.h"
  17#include "map_symbol.h"
  18#include "branch.h"
  19#include "thread.h"
  20#include "evsel.h"
  21#include "evlist.h"
  22#include "srcline.h"
  23#include "strlist.h"
  24#include "strbuf.h"
  25#include "mem-events.h"
  26#include "mem-info.h"
  27#include "annotate.h"
  28#include "annotate-data.h"
  29#include "event.h"
  30#include "time-utils.h"
  31#include "cgroup.h"
  32#include "machine.h"
  33#include "trace-event.h"
  34#include <linux/kernel.h>
  35#include <linux/string.h>
  36
  37#ifdef HAVE_LIBTRACEEVENT
  38#include <event-parse.h>
  39#endif
  40
  41regex_t		parent_regex;
  42const char	default_parent_pattern[] = "^sys_|^do_page_fault";
  43const char	*parent_pattern = default_parent_pattern;
  44const char	*default_sort_order = "comm,dso,symbol";
  45const char	default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles";
  46const 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";
  47const char	default_top_sort_order[] = "dso,symbol";
  48const char	default_diff_sort_order[] = "dso,symbol";
  49const char	default_tracepoint_sort_order[] = "trace";
  50const char	*sort_order;
  51const char	*field_order;
  52regex_t		ignore_callees_regex;
  53int		have_ignore_callees = 0;
  54enum sort_mode	sort__mode = SORT_MODE__NORMAL;
  55static const char *const dynamic_headers[] = {"local_ins_lat", "ins_lat", "local_p_stage_cyc", "p_stage_cyc"};
  56static const char *const arch_specific_sort_keys[] = {"local_p_stage_cyc", "p_stage_cyc"};
  57
  58/*
  59 * Some architectures have Adjacent Cacheline Prefetch feature, which
  60 * behaves like the cacheline size is doubled. Enable this flag to
  61 * check things in double cacheline granularity.
  62 */
  63bool chk_double_cl;
  64
  65/*
  66 * Replaces all occurrences of a char used with the:
  67 *
  68 * -t, --field-separator
  69 *
  70 * option, that uses a special separator character and don't pad with spaces,
  71 * replacing all occurrences of this separator in symbol names (and other
  72 * output) with a '.' character, that thus it's the only non valid separator.
  73*/
  74static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
  75{
  76	int n;
  77	va_list ap;
  78
  79	va_start(ap, fmt);
  80	n = vsnprintf(bf, size, fmt, ap);
  81	if (symbol_conf.field_sep && n > 0) {
  82		char *sep = bf;
  83
  84		while (1) {
  85			sep = strchr(sep, *symbol_conf.field_sep);
  86			if (sep == NULL)
  87				break;
  88			*sep = '.';
  89		}
  90	}
  91	va_end(ap);
  92
  93	if (n >= (int)size)
  94		return size - 1;
  95	return n;
  96}
  97
  98static int64_t cmp_null(const void *l, const void *r)
  99{
 100	if (!l && !r)
 101		return 0;
 102	else if (!l)
 103		return -1;
 104	else
 105		return 1;
 106}
 107
 108/* --sort pid */
 109
 110static int64_t
 111sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
 112{
 113	return thread__tid(right->thread) - thread__tid(left->thread);
 114}
 115
 116static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
 117				       size_t size, unsigned int width)
 118{
 119	const char *comm = thread__comm_str(he->thread);
 120
 121	width = max(7U, width) - 8;
 122	return repsep_snprintf(bf, size, "%7d:%-*.*s", thread__tid(he->thread),
 123			       width, width, comm ?: "");
 124}
 125
 126static int hist_entry__thread_filter(struct hist_entry *he, int type, const void *arg)
 127{
 128	const struct thread *th = arg;
 129
 130	if (type != HIST_FILTER__THREAD)
 131		return -1;
 132
 133	return th && !RC_CHK_EQUAL(he->thread, th);
 134}
 135
 136struct sort_entry sort_thread = {
 137	.se_header	= "    Pid:Command",
 138	.se_cmp		= sort__thread_cmp,
 139	.se_snprintf	= hist_entry__thread_snprintf,
 140	.se_filter	= hist_entry__thread_filter,
 141	.se_width_idx	= HISTC_THREAD,
 142};
 143
 144/* --sort tgid */
 145
 146static int64_t
 147sort__tgid_cmp(struct hist_entry *left, struct hist_entry *right)
 148{
 149	return thread__pid(right->thread) - thread__pid(left->thread);
 150}
 151
 152static int hist_entry__tgid_snprintf(struct hist_entry *he, char *bf,
 153				       size_t size, unsigned int width)
 154{
 155	int tgid = thread__pid(he->thread);
 156	const char *comm = NULL;
 157
 158	/* display comm of the thread-group leader */
 159	if (thread__pid(he->thread) == thread__tid(he->thread)) {
 160		comm = thread__comm_str(he->thread);
 161	} else {
 162		struct maps *maps = thread__maps(he->thread);
 163		struct thread *leader = machine__find_thread(maps__machine(maps),
 164							     tgid, tgid);
 165		if (leader) {
 166			comm = thread__comm_str(leader);
 167			thread__put(leader);
 168		}
 169	}
 170	width = max(7U, width) - 8;
 171	return repsep_snprintf(bf, size, "%7d:%-*.*s", tgid, width, width, comm ?: "");
 172}
 173
 174struct sort_entry sort_tgid = {
 175	.se_header	= "   Tgid:Command",
 176	.se_cmp		= sort__tgid_cmp,
 177	.se_snprintf	= hist_entry__tgid_snprintf,
 178	.se_width_idx	= HISTC_TGID,
 179};
 180
 181/* --sort simd */
 182
 183static int64_t
 184sort__simd_cmp(struct hist_entry *left, struct hist_entry *right)
 185{
 186	if (left->simd_flags.arch != right->simd_flags.arch)
 187		return (int64_t) left->simd_flags.arch - right->simd_flags.arch;
 188
 189	return (int64_t) left->simd_flags.pred - right->simd_flags.pred;
 190}
 191
 192static const char *hist_entry__get_simd_name(struct simd_flags *simd_flags)
 193{
 194	u64 arch = simd_flags->arch;
 195
 196	if (arch & SIMD_OP_FLAGS_ARCH_SVE)
 197		return "SVE";
 198	else
 199		return "n/a";
 200}
 201
 202static int hist_entry__simd_snprintf(struct hist_entry *he, char *bf,
 203				     size_t size, unsigned int width __maybe_unused)
 204{
 205	const char *name;
 206
 207	if (!he->simd_flags.arch)
 208		return repsep_snprintf(bf, size, "");
 209
 210	name = hist_entry__get_simd_name(&he->simd_flags);
 211
 212	if (he->simd_flags.pred & SIMD_OP_FLAGS_PRED_EMPTY)
 213		return repsep_snprintf(bf, size, "[e] %s", name);
 214	else if (he->simd_flags.pred & SIMD_OP_FLAGS_PRED_PARTIAL)
 215		return repsep_snprintf(bf, size, "[p] %s", name);
 216
 217	return repsep_snprintf(bf, size, "[.] %s", name);
 218}
 219
 220struct sort_entry sort_simd = {
 221	.se_header	= "Simd   ",
 222	.se_cmp		= sort__simd_cmp,
 223	.se_snprintf	= hist_entry__simd_snprintf,
 224	.se_width_idx	= HISTC_SIMD,
 225};
 226
 227/* --sort comm */
 228
 229/*
 230 * We can't use pointer comparison in functions below,
 231 * because it gives different results based on pointer
 232 * values, which could break some sorting assumptions.
 233 */
 234static int64_t
 235sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
 236{
 237	return strcmp(comm__str(right->comm), comm__str(left->comm));
 238}
 239
 240static int64_t
 241sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
 242{
 243	return strcmp(comm__str(right->comm), comm__str(left->comm));
 244}
 245
 246static int64_t
 247sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
 248{
 249	return strcmp(comm__str(right->comm), comm__str(left->comm));
 250}
 251
 252static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
 253				     size_t size, unsigned int width)
 254{
 255	return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
 256}
 257
 258struct sort_entry sort_comm = {
 259	.se_header	= "Command",
 260	.se_cmp		= sort__comm_cmp,
 261	.se_collapse	= sort__comm_collapse,
 262	.se_sort	= sort__comm_sort,
 263	.se_snprintf	= hist_entry__comm_snprintf,
 264	.se_filter	= hist_entry__thread_filter,
 265	.se_width_idx	= HISTC_COMM,
 266};
 267
 268/* --sort dso */
 269
 270static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
 271{
 272	struct dso *dso_l = map_l ? map__dso(map_l) : NULL;
 273	struct dso *dso_r = map_r ? map__dso(map_r) : NULL;
 274	const char *dso_name_l, *dso_name_r;
 275
 276	if (!dso_l || !dso_r)
 277		return cmp_null(dso_r, dso_l);
 278
 279	if (verbose > 0) {
 280		dso_name_l = dso__long_name(dso_l);
 281		dso_name_r = dso__long_name(dso_r);
 282	} else {
 283		dso_name_l = dso__short_name(dso_l);
 284		dso_name_r = dso__short_name(dso_r);
 285	}
 286
 287	return strcmp(dso_name_l, dso_name_r);
 288}
 289
 290static int64_t
 291sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
 292{
 293	return _sort__dso_cmp(right->ms.map, left->ms.map);
 294}
 295
 296static int _hist_entry__dso_snprintf(struct map *map, char *bf,
 297				     size_t size, unsigned int width)
 298{
 299	const struct dso *dso = map ? map__dso(map) : NULL;
 300	const char *dso_name = "[unknown]";
 301
 302	if (dso)
 303		dso_name = verbose > 0 ? dso__long_name(dso) : dso__short_name(dso);
 304
 305	return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
 306}
 307
 308static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
 309				    size_t size, unsigned int width)
 310{
 311	return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
 312}
 313
 314static int hist_entry__dso_filter(struct hist_entry *he, int type, const void *arg)
 315{
 316	const struct dso *dso = arg;
 317
 318	if (type != HIST_FILTER__DSO)
 319		return -1;
 320
 321	return dso && (!he->ms.map || map__dso(he->ms.map) != dso);
 322}
 323
 324struct sort_entry sort_dso = {
 325	.se_header	= "Shared Object",
 326	.se_cmp		= sort__dso_cmp,
 327	.se_snprintf	= hist_entry__dso_snprintf,
 328	.se_filter	= hist_entry__dso_filter,
 329	.se_width_idx	= HISTC_DSO,
 330};
 331
 332/* --sort symbol */
 333
 334static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
 335{
 336	return (int64_t)(right_ip - left_ip);
 337}
 338
 339int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
 340{
 341	if (!sym_l || !sym_r)
 342		return cmp_null(sym_l, sym_r);
 343
 344	if (sym_l == sym_r)
 345		return 0;
 346
 347	if (sym_l->inlined || sym_r->inlined) {
 348		int ret = strcmp(sym_l->name, sym_r->name);
 349
 350		if (ret)
 351			return ret;
 352		if ((sym_l->start <= sym_r->end) && (sym_l->end >= sym_r->start))
 353			return 0;
 354	}
 355
 356	if (sym_l->start != sym_r->start)
 357		return (int64_t)(sym_r->start - sym_l->start);
 358
 359	return (int64_t)(sym_r->end - sym_l->end);
 360}
 361
 362static int64_t
 363sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
 364{
 365	int64_t ret;
 366
 367	if (!left->ms.sym && !right->ms.sym)
 368		return _sort__addr_cmp(left->ip, right->ip);
 369
 370	/*
 371	 * comparing symbol address alone is not enough since it's a
 372	 * relative address within a dso.
 373	 */
 374	if (!hists__has(left->hists, dso)) {
 375		ret = sort__dso_cmp(left, right);
 376		if (ret != 0)
 377			return ret;
 378	}
 379
 380	return _sort__sym_cmp(left->ms.sym, right->ms.sym);
 381}
 382
 383static int64_t
 384sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
 385{
 386	if (!left->ms.sym || !right->ms.sym)
 387		return cmp_null(left->ms.sym, right->ms.sym);
 388
 389	return strcmp(right->ms.sym->name, left->ms.sym->name);
 390}
 391
 392static int _hist_entry__sym_snprintf(struct map_symbol *ms,
 393				     u64 ip, char level, char *bf, size_t size,
 394				     unsigned int width)
 395{
 396	struct symbol *sym = ms->sym;
 397	struct map *map = ms->map;
 398	size_t ret = 0;
 399
 400	if (verbose > 0) {
 401		struct dso *dso = map ? map__dso(map) : NULL;
 402		char o = dso ? dso__symtab_origin(dso) : '!';
 403		u64 rip = ip;
 404
 405		if (dso && dso__kernel(dso) && dso__adjust_symbols(dso))
 406			rip = map__unmap_ip(map, ip);
 407
 408		ret += repsep_snprintf(bf, size, "%-#*llx %c ",
 409				       BITS_PER_LONG / 4 + 2, rip, o);
 410	}
 411
 412	ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
 413	if (sym && map) {
 414		if (sym->type == STT_OBJECT) {
 415			ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
 416			ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
 417					ip - map__unmap_ip(map, sym->start));
 418		} else {
 419			ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
 420					       width - ret,
 421					       sym->name);
 422			if (sym->inlined)
 423				ret += repsep_snprintf(bf + ret, size - ret,
 424						       " (inlined)");
 425		}
 426	} else {
 427		size_t len = BITS_PER_LONG / 4;
 428		ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
 429				       len, ip);
 430	}
 431
 432	return ret;
 433}
 434
 435int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width)
 436{
 437	return _hist_entry__sym_snprintf(&he->ms, he->ip,
 438					 he->level, bf, size, width);
 439}
 440
 441static int hist_entry__sym_filter(struct hist_entry *he, int type, const void *arg)
 442{
 443	const char *sym = arg;
 444
 445	if (type != HIST_FILTER__SYMBOL)
 446		return -1;
 447
 448	return sym && (!he->ms.sym || !strstr(he->ms.sym->name, sym));
 449}
 450
 451struct sort_entry sort_sym = {
 452	.se_header	= "Symbol",
 453	.se_cmp		= sort__sym_cmp,
 454	.se_sort	= sort__sym_sort,
 455	.se_snprintf	= hist_entry__sym_snprintf,
 456	.se_filter	= hist_entry__sym_filter,
 457	.se_width_idx	= HISTC_SYMBOL,
 458};
 459
 460/* --sort symoff */
 461
 462static int64_t
 463sort__symoff_cmp(struct hist_entry *left, struct hist_entry *right)
 464{
 465	int64_t ret;
 466
 467	ret = sort__sym_cmp(left, right);
 468	if (ret)
 469		return ret;
 470
 471	return left->ip - right->ip;
 472}
 473
 474static int64_t
 475sort__symoff_sort(struct hist_entry *left, struct hist_entry *right)
 476{
 477	int64_t ret;
 478
 479	ret = sort__sym_sort(left, right);
 480	if (ret)
 481		return ret;
 482
 483	return left->ip - right->ip;
 484}
 485
 486static int
 487hist_entry__symoff_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width)
 488{
 489	struct symbol *sym = he->ms.sym;
 490
 491	if (sym == NULL)
 492		return repsep_snprintf(bf, size, "[%c] %-#.*llx", he->level, width - 4, he->ip);
 493
 494	return repsep_snprintf(bf, size, "[%c] %s+0x%llx", he->level, sym->name, he->ip - sym->start);
 495}
 496
 497struct sort_entry sort_sym_offset = {
 498	.se_header	= "Symbol Offset",
 499	.se_cmp		= sort__symoff_cmp,
 500	.se_sort	= sort__symoff_sort,
 501	.se_snprintf	= hist_entry__symoff_snprintf,
 502	.se_filter	= hist_entry__sym_filter,
 503	.se_width_idx	= HISTC_SYMBOL_OFFSET,
 504};
 505
 506/* --sort srcline */
 507
 508char *hist_entry__srcline(struct hist_entry *he)
 509{
 510	return map__srcline(he->ms.map, he->ip, he->ms.sym);
 511}
 512
 513static int64_t
 514sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
 515{
 516	int64_t ret;
 517
 518	ret = _sort__addr_cmp(left->ip, right->ip);
 519	if (ret)
 520		return ret;
 521
 522	return sort__dso_cmp(left, right);
 523}
 524
 525static int64_t
 526sort__srcline_collapse(struct hist_entry *left, struct hist_entry *right)
 527{
 528	if (!left->srcline)
 529		left->srcline = hist_entry__srcline(left);
 530	if (!right->srcline)
 531		right->srcline = hist_entry__srcline(right);
 532
 533	return strcmp(right->srcline, left->srcline);
 534}
 535
 536static int64_t
 537sort__srcline_sort(struct hist_entry *left, struct hist_entry *right)
 538{
 539	return sort__srcline_collapse(left, right);
 540}
 541
 542static void
 543sort__srcline_init(struct hist_entry *he)
 544{
 545	if (!he->srcline)
 546		he->srcline = hist_entry__srcline(he);
 547}
 548
 549static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
 550					size_t size, unsigned int width)
 551{
 552	return repsep_snprintf(bf, size, "%-.*s", width, he->srcline);
 553}
 554
 555struct sort_entry sort_srcline = {
 556	.se_header	= "Source:Line",
 557	.se_cmp		= sort__srcline_cmp,
 558	.se_collapse	= sort__srcline_collapse,
 559	.se_sort	= sort__srcline_sort,
 560	.se_init	= sort__srcline_init,
 561	.se_snprintf	= hist_entry__srcline_snprintf,
 562	.se_width_idx	= HISTC_SRCLINE,
 563};
 564
 565/* --sort srcline_from */
 566
 567static char *addr_map_symbol__srcline(struct addr_map_symbol *ams)
 568{
 569	return map__srcline(ams->ms.map, ams->al_addr, ams->ms.sym);
 570}
 571
 572static int64_t
 573sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
 574{
 575	return left->branch_info->from.addr - right->branch_info->from.addr;
 576}
 577
 578static int64_t
 579sort__srcline_from_collapse(struct hist_entry *left, struct hist_entry *right)
 580{
 581	if (!left->branch_info->srcline_from)
 582		left->branch_info->srcline_from = addr_map_symbol__srcline(&left->branch_info->from);
 583
 584	if (!right->branch_info->srcline_from)
 585		right->branch_info->srcline_from = addr_map_symbol__srcline(&right->branch_info->from);
 586
 587	return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from);
 588}
 589
 590static int64_t
 591sort__srcline_from_sort(struct hist_entry *left, struct hist_entry *right)
 592{
 593	return sort__srcline_from_collapse(left, right);
 594}
 595
 596static void sort__srcline_from_init(struct hist_entry *he)
 597{
 598	if (!he->branch_info->srcline_from)
 599		he->branch_info->srcline_from = addr_map_symbol__srcline(&he->branch_info->from);
 600}
 601
 602static int hist_entry__srcline_from_snprintf(struct hist_entry *he, char *bf,
 603					size_t size, unsigned int width)
 604{
 605	return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_from);
 606}
 607
 608struct sort_entry sort_srcline_from = {
 609	.se_header	= "From Source:Line",
 610	.se_cmp		= sort__srcline_from_cmp,
 611	.se_collapse	= sort__srcline_from_collapse,
 612	.se_sort	= sort__srcline_from_sort,
 613	.se_init	= sort__srcline_from_init,
 614	.se_snprintf	= hist_entry__srcline_from_snprintf,
 615	.se_width_idx	= HISTC_SRCLINE_FROM,
 616};
 617
 618/* --sort srcline_to */
 619
 620static int64_t
 621sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
 622{
 623	return left->branch_info->to.addr - right->branch_info->to.addr;
 624}
 625
 626static int64_t
 627sort__srcline_to_collapse(struct hist_entry *left, struct hist_entry *right)
 628{
 629	if (!left->branch_info->srcline_to)
 630		left->branch_info->srcline_to = addr_map_symbol__srcline(&left->branch_info->to);
 631
 632	if (!right->branch_info->srcline_to)
 633		right->branch_info->srcline_to = addr_map_symbol__srcline(&right->branch_info->to);
 634
 635	return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to);
 636}
 637
 638static int64_t
 639sort__srcline_to_sort(struct hist_entry *left, struct hist_entry *right)
 640{
 641	return sort__srcline_to_collapse(left, right);
 642}
 643
 644static void sort__srcline_to_init(struct hist_entry *he)
 645{
 646	if (!he->branch_info->srcline_to)
 647		he->branch_info->srcline_to = addr_map_symbol__srcline(&he->branch_info->to);
 648}
 649
 650static int hist_entry__srcline_to_snprintf(struct hist_entry *he, char *bf,
 651					size_t size, unsigned int width)
 652{
 653	return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_to);
 654}
 655
 656struct sort_entry sort_srcline_to = {
 657	.se_header	= "To Source:Line",
 658	.se_cmp		= sort__srcline_to_cmp,
 659	.se_collapse	= sort__srcline_to_collapse,
 660	.se_sort	= sort__srcline_to_sort,
 661	.se_init	= sort__srcline_to_init,
 662	.se_snprintf	= hist_entry__srcline_to_snprintf,
 663	.se_width_idx	= HISTC_SRCLINE_TO,
 664};
 665
 666static int hist_entry__sym_ipc_snprintf(struct hist_entry *he, char *bf,
 667					size_t size, unsigned int width)
 668{
 669
 670	struct symbol *sym = he->ms.sym;
 671	struct annotated_branch *branch;
 672	double ipc = 0.0, coverage = 0.0;
 673	char tmp[64];
 674
 675	if (!sym)
 676		return repsep_snprintf(bf, size, "%-*s", width, "-");
 677
 678	branch = symbol__annotation(sym)->branch;
 679
 680	if (branch && branch->hit_cycles)
 681		ipc = branch->hit_insn / ((double)branch->hit_cycles);
 682
 683	if (branch && branch->total_insn) {
 684		coverage = branch->cover_insn * 100.0 /
 685			((double)branch->total_insn);
 686	}
 687
 688	snprintf(tmp, sizeof(tmp), "%-5.2f [%5.1f%%]", ipc, coverage);
 689	return repsep_snprintf(bf, size, "%-*s", width, tmp);
 690}
 691
 692struct sort_entry sort_sym_ipc = {
 693	.se_header	= "IPC   [IPC Coverage]",
 694	.se_cmp		= sort__sym_cmp,
 695	.se_snprintf	= hist_entry__sym_ipc_snprintf,
 696	.se_width_idx	= HISTC_SYMBOL_IPC,
 697};
 698
 699static int hist_entry__sym_ipc_null_snprintf(struct hist_entry *he
 700					     __maybe_unused,
 701					     char *bf, size_t size,
 702					     unsigned int width)
 703{
 704	char tmp[64];
 705
 706	snprintf(tmp, sizeof(tmp), "%-5s %2s", "-", "-");
 707	return repsep_snprintf(bf, size, "%-*s", width, tmp);
 708}
 709
 710struct sort_entry sort_sym_ipc_null = {
 711	.se_header	= "IPC   [IPC Coverage]",
 712	.se_cmp		= sort__sym_cmp,
 713	.se_snprintf	= hist_entry__sym_ipc_null_snprintf,
 714	.se_width_idx	= HISTC_SYMBOL_IPC,
 715};
 716
 717/* --sort callchain_branch_predicted */
 718
 719static int64_t
 720sort__callchain_branch_predicted_cmp(struct hist_entry *left __maybe_unused,
 721				     struct hist_entry *right __maybe_unused)
 722{
 723	return 0;
 724}
 725
 726static int hist_entry__callchain_branch_predicted_snprintf(
 727	struct hist_entry *he, char *bf, size_t size, unsigned int width)
 728{
 729	u64 branch_count, predicted_count;
 730	double percent = 0.0;
 731	char str[32];
 732
 733	callchain_branch_counts(he->callchain, &branch_count,
 734				&predicted_count, NULL, NULL);
 735
 736	if (branch_count)
 737		percent = predicted_count * 100.0 / branch_count;
 738
 739	snprintf(str, sizeof(str), "%.1f%%", percent);
 740	return repsep_snprintf(bf, size, "%-*.*s", width, width, str);
 741}
 742
 743struct sort_entry sort_callchain_branch_predicted = {
 744	.se_header	= "Predicted",
 745	.se_cmp		= sort__callchain_branch_predicted_cmp,
 746	.se_snprintf	= hist_entry__callchain_branch_predicted_snprintf,
 747	.se_width_idx	= HISTC_CALLCHAIN_BRANCH_PREDICTED,
 748};
 749
 750/* --sort callchain_branch_abort */
 751
 752static int64_t
 753sort__callchain_branch_abort_cmp(struct hist_entry *left __maybe_unused,
 754				 struct hist_entry *right __maybe_unused)
 755{
 756	return 0;
 757}
 758
 759static int hist_entry__callchain_branch_abort_snprintf(struct hist_entry *he,
 760						       char *bf, size_t size,
 761						       unsigned int width)
 762{
 763	u64 branch_count, abort_count;
 764	char str[32];
 765
 766	callchain_branch_counts(he->callchain, &branch_count,
 767				NULL, &abort_count, NULL);
 768
 769	snprintf(str, sizeof(str), "%" PRId64, abort_count);
 770	return repsep_snprintf(bf, size, "%-*.*s", width, width, str);
 771}
 772
 773struct sort_entry sort_callchain_branch_abort = {
 774	.se_header	= "Abort",
 775	.se_cmp		= sort__callchain_branch_abort_cmp,
 776	.se_snprintf	= hist_entry__callchain_branch_abort_snprintf,
 777	.se_width_idx	= HISTC_CALLCHAIN_BRANCH_ABORT,
 778};
 779
 780/* --sort callchain_branch_cycles */
 781
 782static int64_t
 783sort__callchain_branch_cycles_cmp(struct hist_entry *left __maybe_unused,
 784				  struct hist_entry *right __maybe_unused)
 785{
 786	return 0;
 787}
 788
 789static int hist_entry__callchain_branch_cycles_snprintf(struct hist_entry *he,
 790							char *bf, size_t size,
 791							unsigned int width)
 792{
 793	u64 branch_count, cycles_count, cycles = 0;
 794	char str[32];
 795
 796	callchain_branch_counts(he->callchain, &branch_count,
 797				NULL, NULL, &cycles_count);
 798
 799	if (branch_count)
 800		cycles = cycles_count / branch_count;
 801
 802	snprintf(str, sizeof(str), "%" PRId64 "", cycles);
 803	return repsep_snprintf(bf, size, "%-*.*s", width, width, str);
 804}
 805
 806struct sort_entry sort_callchain_branch_cycles = {
 807	.se_header	= "Cycles",
 808	.se_cmp		= sort__callchain_branch_cycles_cmp,
 809	.se_snprintf	= hist_entry__callchain_branch_cycles_snprintf,
 810	.se_width_idx	= HISTC_CALLCHAIN_BRANCH_CYCLES,
 811};
 812
 813/* --sort srcfile */
 814
 815static char no_srcfile[1];
 816
 817static char *hist_entry__get_srcfile(struct hist_entry *e)
 818{
 819	char *sf, *p;
 820	struct map *map = e->ms.map;
 821
 822	if (!map)
 823		return no_srcfile;
 824
 825	sf = __get_srcline(map__dso(map), map__rip_2objdump(map, e->ip),
 826			 e->ms.sym, false, true, true, e->ip);
 827	if (sf == SRCLINE_UNKNOWN)
 828		return no_srcfile;
 829	p = strchr(sf, ':');
 830	if (p && *sf) {
 831		*p = 0;
 832		return sf;
 833	}
 834	free(sf);
 835	return no_srcfile;
 836}
 837
 838static int64_t
 839sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
 840{
 841	return sort__srcline_cmp(left, right);
 842}
 843
 844static int64_t
 845sort__srcfile_collapse(struct hist_entry *left, struct hist_entry *right)
 846{
 847	if (!left->srcfile)
 848		left->srcfile = hist_entry__get_srcfile(left);
 849	if (!right->srcfile)
 850		right->srcfile = hist_entry__get_srcfile(right);
 851
 852	return strcmp(right->srcfile, left->srcfile);
 853}
 854
 855static int64_t
 856sort__srcfile_sort(struct hist_entry *left, struct hist_entry *right)
 857{
 858	return sort__srcfile_collapse(left, right);
 859}
 860
 861static void sort__srcfile_init(struct hist_entry *he)
 862{
 863	if (!he->srcfile)
 864		he->srcfile = hist_entry__get_srcfile(he);
 865}
 866
 867static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
 868					size_t size, unsigned int width)
 869{
 870	return repsep_snprintf(bf, size, "%-.*s", width, he->srcfile);
 871}
 872
 873struct sort_entry sort_srcfile = {
 874	.se_header	= "Source File",
 875	.se_cmp		= sort__srcfile_cmp,
 876	.se_collapse	= sort__srcfile_collapse,
 877	.se_sort	= sort__srcfile_sort,
 878	.se_init	= sort__srcfile_init,
 879	.se_snprintf	= hist_entry__srcfile_snprintf,
 880	.se_width_idx	= HISTC_SRCFILE,
 881};
 882
 883/* --sort parent */
 884
 885static int64_t
 886sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
 887{
 888	struct symbol *sym_l = left->parent;
 889	struct symbol *sym_r = right->parent;
 890
 891	if (!sym_l || !sym_r)
 892		return cmp_null(sym_l, sym_r);
 893
 894	return strcmp(sym_r->name, sym_l->name);
 895}
 896
 897static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
 898				       size_t size, unsigned int width)
 899{
 900	return repsep_snprintf(bf, size, "%-*.*s", width, width,
 901			      he->parent ? he->parent->name : "[other]");
 902}
 903
 904struct sort_entry sort_parent = {
 905	.se_header	= "Parent symbol",
 906	.se_cmp		= sort__parent_cmp,
 907	.se_snprintf	= hist_entry__parent_snprintf,
 908	.se_width_idx	= HISTC_PARENT,
 909};
 910
 911/* --sort cpu */
 912
 913static int64_t
 914sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
 915{
 916	return right->cpu - left->cpu;
 917}
 918
 919static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
 920				    size_t size, unsigned int width)
 921{
 922	return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
 923}
 924
 925struct sort_entry sort_cpu = {
 926	.se_header      = "CPU",
 927	.se_cmp	        = sort__cpu_cmp,
 928	.se_snprintf    = hist_entry__cpu_snprintf,
 929	.se_width_idx	= HISTC_CPU,
 930};
 931
 932/* --sort parallelism */
 933
 934static int64_t
 935sort__parallelism_cmp(struct hist_entry *left, struct hist_entry *right)
 936{
 937	return right->parallelism - left->parallelism;
 938}
 939
 940static int hist_entry__parallelism_filter(struct hist_entry *he, int type, const void *arg)
 941{
 942	const unsigned long *parallelism_filter = arg;
 943
 944	if (type != HIST_FILTER__PARALLELISM)
 945		return -1;
 946
 947	return test_bit(he->parallelism, parallelism_filter);
 948}
 949
 950static int hist_entry__parallelism_snprintf(struct hist_entry *he, char *bf,
 951				    size_t size, unsigned int width)
 952{
 953	return repsep_snprintf(bf, size, "%*d", width, he->parallelism);
 954}
 955
 956struct sort_entry sort_parallelism = {
 957	.se_header      = "Parallelism",
 958	.se_cmp	        = sort__parallelism_cmp,
 959	.se_filter	= hist_entry__parallelism_filter,
 960	.se_snprintf    = hist_entry__parallelism_snprintf,
 961	.se_width_idx	= HISTC_PARALLELISM,
 962};
 963
 964/* --sort cgroup_id */
 965
 966static int64_t _sort__cgroup_dev_cmp(u64 left_dev, u64 right_dev)
 967{
 968	return (int64_t)(right_dev - left_dev);
 969}
 970
 971static int64_t _sort__cgroup_inode_cmp(u64 left_ino, u64 right_ino)
 972{
 973	return (int64_t)(right_ino - left_ino);
 974}
 975
 976static int64_t
 977sort__cgroup_id_cmp(struct hist_entry *left, struct hist_entry *right)
 978{
 979	int64_t ret;
 980
 981	ret = _sort__cgroup_dev_cmp(right->cgroup_id.dev, left->cgroup_id.dev);
 982	if (ret != 0)
 983		return ret;
 984
 985	return _sort__cgroup_inode_cmp(right->cgroup_id.ino,
 986				       left->cgroup_id.ino);
 987}
 988
 989static int hist_entry__cgroup_id_snprintf(struct hist_entry *he,
 990					  char *bf, size_t size,
 991					  unsigned int width __maybe_unused)
 992{
 993	return repsep_snprintf(bf, size, "%lu/0x%lx", he->cgroup_id.dev,
 994			       he->cgroup_id.ino);
 995}
 996
 997struct sort_entry sort_cgroup_id = {
 998	.se_header      = "cgroup id (dev/inode)",
 999	.se_cmp	        = sort__cgroup_id_cmp,
1000	.se_snprintf    = hist_entry__cgroup_id_snprintf,
1001	.se_width_idx	= HISTC_CGROUP_ID,
1002};
1003
1004/* --sort cgroup */
1005
1006static int64_t
1007sort__cgroup_cmp(struct hist_entry *left, struct hist_entry *right)
1008{
1009	return right->cgroup - left->cgroup;
1010}
1011
1012static int hist_entry__cgroup_snprintf(struct hist_entry *he,
1013				       char *bf, size_t size,
1014				       unsigned int width __maybe_unused)
1015{
1016	const char *cgrp_name = "N/A";
1017
1018	if (he->cgroup) {
1019		struct cgroup *cgrp = cgroup__find(maps__machine(he->ms.maps)->env,
1020						   he->cgroup);
1021		if (cgrp != NULL)
1022			cgrp_name = cgrp->name;
1023		else
1024			cgrp_name = "unknown";
1025	}
1026
1027	return repsep_snprintf(bf, size, "%s", cgrp_name);
1028}
1029
1030struct sort_entry sort_cgroup = {
1031	.se_header      = "Cgroup",
1032	.se_cmp	        = sort__cgroup_cmp,
1033	.se_snprintf    = hist_entry__cgroup_snprintf,
1034	.se_width_idx	= HISTC_CGROUP,
1035};
1036
1037/* --sort socket */
1038
1039static int64_t
1040sort__socket_cmp(struct hist_entry *left, struct hist_entry *right)
1041{
1042	return right->socket - left->socket;
1043}
1044
1045static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf,
1046				    size_t size, unsigned int width)
1047{
1048	return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket);
1049}
1050
1051static int hist_entry__socket_filter(struct hist_entry *he, int type, const void *arg)
1052{
1053	int sk = *(const int *)arg;
1054
1055	if (type != HIST_FILTER__SOCKET)
1056		return -1;
1057
1058	return sk >= 0 && he->socket != sk;
1059}
1060
1061struct sort_entry sort_socket = {
1062	.se_header      = "Socket",
1063	.se_cmp	        = sort__socket_cmp,
1064	.se_snprintf    = hist_entry__socket_snprintf,
1065	.se_filter      = hist_entry__socket_filter,
1066	.se_width_idx	= HISTC_SOCKET,
1067};
1068
1069/* --sort time */
1070
1071static int64_t
1072sort__time_cmp(struct hist_entry *left, struct hist_entry *right)
1073{
1074	return right->time - left->time;
1075}
1076
1077static int hist_entry__time_snprintf(struct hist_entry *he, char *bf,
1078				    size_t size, unsigned int width)
1079{
1080	char he_time[32];
1081
1082	if (symbol_conf.nanosecs)
1083		timestamp__scnprintf_nsec(he->time, he_time,
1084					  sizeof(he_time));
1085	else
1086		timestamp__scnprintf_usec(he->time, he_time,
1087					  sizeof(he_time));
1088
1089	return repsep_snprintf(bf, size, "%-.*s", width, he_time);
1090}
1091
1092struct sort_entry sort_time = {
1093	.se_header      = "Time",
1094	.se_cmp	        = sort__time_cmp,
1095	.se_snprintf    = hist_entry__time_snprintf,
1096	.se_width_idx	= HISTC_TIME,
1097};
1098
1099/* --sort trace */
1100
1101#ifdef HAVE_LIBTRACEEVENT
1102static char *get_trace_output(struct hist_entry *he)
1103{
1104	struct trace_seq seq;
1105	struct evsel *evsel;
1106	struct tep_record rec = {
1107		.data = he->raw_data,
1108		.size = he->raw_size,
1109	};
1110	struct tep_event *tp_format;
1111
1112	evsel = hists_to_evsel(he->hists);
1113
1114	trace_seq_init(&seq);
1115	tp_format = evsel__tp_format(evsel);
1116	if (tp_format) {
1117		if (symbol_conf.raw_trace)
1118			tep_print_fields(&seq, he->raw_data, he->raw_size, tp_format);
1119		else
1120			tep_print_event(tp_format->tep, &seq, &rec, "%s", TEP_PRINT_INFO);
1121	}
1122
1123	/*
1124	 * Trim the buffer, it starts at 4KB and we're not going to
1125	 * add anything more to this buffer.
1126	 */
1127	return realloc(seq.buffer, seq.len + 1);
1128}
1129
1130static int64_t
1131sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
1132{
1133	struct evsel *evsel;
1134
1135	evsel = hists_to_evsel(left->hists);
1136	if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
1137		return 0;
1138
1139	if (left->trace_output == NULL)
1140		left->trace_output = get_trace_output(left);
1141	if (right->trace_output == NULL)
1142		right->trace_output = get_trace_output(right);
1143
1144	return strcmp(right->trace_output, left->trace_output);
1145}
1146
1147static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
1148				    size_t size, unsigned int width)
1149{
1150	struct evsel *evsel;
1151
1152	evsel = hists_to_evsel(he->hists);
1153	if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
1154		return scnprintf(bf, size, "%-.*s", width, "N/A");
1155
1156	if (he->trace_output == NULL)
1157		he->trace_output = get_trace_output(he);
1158	return repsep_snprintf(bf, size, "%-.*s", width, he->trace_output);
1159}
1160
1161struct sort_entry sort_trace = {
1162	.se_header      = "Trace output",
1163	.se_cmp	        = sort__trace_cmp,
1164	.se_snprintf    = hist_entry__trace_snprintf,
1165	.se_width_idx	= HISTC_TRACE,
1166};
1167#endif /* HAVE_LIBTRACEEVENT */
1168
1169/* sort keys for branch stacks */
1170
1171static int64_t
1172sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
1173{
1174	if (!left->branch_info || !right->branch_info)
1175		return cmp_null(left->branch_info, right->branch_info);
1176
1177	return _sort__dso_cmp(left->branch_info->from.ms.map,
1178			      right->branch_info->from.ms.map);
1179}
1180
1181static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
1182				    size_t size, unsigned int width)
1183{
1184	if (he->branch_info)
1185		return _hist_entry__dso_snprintf(he->branch_info->from.ms.map,
1186						 bf, size, width);
1187	else
1188		return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
1189}
1190
1191static int hist_entry__dso_from_filter(struct hist_entry *he, int type,
1192				       const void *arg)
1193{
1194	const struct dso *dso = arg;
1195
1196	if (type != HIST_FILTER__DSO)
1197		return -1;
1198
1199	return dso && (!he->branch_info || !he->branch_info->from.ms.map ||
1200		map__dso(he->branch_info->from.ms.map) != dso);
1201}
1202
1203static int64_t
1204sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
1205{
1206	if (!left->branch_info || !right->branch_info)
1207		return cmp_null(left->branch_info, right->branch_info);
1208
1209	return _sort__dso_cmp(left->branch_info->to.ms.map,
1210			      right->branch_info->to.ms.map);
1211}
1212
1213static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
1214				       size_t size, unsigned int width)
1215{
1216	if (he->branch_info)
1217		return _hist_entry__dso_snprintf(he->branch_info->to.ms.map,
1218						 bf, size, width);
1219	else
1220		return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
1221}
1222
1223static int hist_entry__dso_to_filter(struct hist_entry *he, int type,
1224				     const void *arg)
1225{
1226	const struct dso *dso = arg;
1227
1228	if (type != HIST_FILTER__DSO)
1229		return -1;
1230
1231	return dso && (!he->branch_info || !he->branch_info->to.ms.map ||
1232		map__dso(he->branch_info->to.ms.map) != dso);
1233}
1234
1235static int64_t
1236sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
1237{
1238	struct addr_map_symbol *from_l, *from_r;
1239
1240	if (!left->branch_info || !right->branch_info)
1241		return cmp_null(left->branch_info, right->branch_info);
1242
1243	from_l = &left->branch_info->from;
1244	from_r = &right->branch_info->from;
1245
1246	if (!from_l->ms.sym && !from_r->ms.sym)
1247		return _sort__addr_cmp(from_l->addr, from_r->addr);
1248
1249	return _sort__sym_cmp(from_l->ms.sym, from_r->ms.sym);
1250}
1251
1252static int64_t
1253sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
1254{
1255	struct addr_map_symbol *to_l, *to_r;
1256
1257	if (!left->branch_info || !right->branch_info)
1258		return cmp_null(left->branch_info, right->branch_info);
1259
1260	to_l = &left->branch_info->to;
1261	to_r = &right->branch_info->to;
1262
1263	if (!to_l->ms.sym && !to_r->ms.sym)
1264		return _sort__addr_cmp(to_l->addr, to_r->addr);
1265
1266	return _sort__sym_cmp(to_l->ms.sym, to_r->ms.sym);
1267}
1268
1269static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
1270					 size_t size, unsigned int width)
1271{
1272	if (he->branch_info) {
1273		struct addr_map_symbol *from = &he->branch_info->from;
1274
1275		return _hist_entry__sym_snprintf(&from->ms, from->al_addr,
1276						 from->al_level, bf, size, width);
1277	}
1278
1279	return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
1280}
1281
1282static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
1283				       size_t size, unsigned int width)
1284{
1285	if (he->branch_info) {
1286		struct addr_map_symbol *to = &he->branch_info->to;
1287
1288		return _hist_entry__sym_snprintf(&to->ms, to->al_addr,
1289						 to->al_level, bf, size, width);
1290	}
1291
1292	return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
1293}
1294
1295static int hist_entry__sym_from_filter(struct hist_entry *he, int type,
1296				       const void *arg)
1297{
1298	const char *sym = arg;
1299
1300	if (type != HIST_FILTER__SYMBOL)
1301		return -1;
1302
1303	return sym && !(he->branch_info && he->branch_info->from.ms.sym &&
1304			strstr(he->branch_info->from.ms.sym->name, sym));
1305}
1306
1307static int hist_entry__sym_to_filter(struct hist_entry *he, int type,
1308				       const void *arg)
1309{
1310	const char *sym = arg;
1311
1312	if (type != HIST_FILTER__SYMBOL)
1313		return -1;
1314
1315	return sym && !(he->branch_info && he->branch_info->to.ms.sym &&
1316		        strstr(he->branch_info->to.ms.sym->name, sym));
1317}
1318
1319struct sort_entry sort_dso_from = {
1320	.se_header	= "Source Shared Object",
1321	.se_cmp		= sort__dso_from_cmp,
1322	.se_snprintf	= hist_entry__dso_from_snprintf,
1323	.se_filter	= hist_entry__dso_from_filter,
1324	.se_width_idx	= HISTC_DSO_FROM,
1325};
1326
1327struct sort_entry sort_dso_to = {
1328	.se_header	= "Target Shared Object",
1329	.se_cmp		= sort__dso_to_cmp,
1330	.se_snprintf	= hist_entry__dso_to_snprintf,
1331	.se_filter	= hist_entry__dso_to_filter,
1332	.se_width_idx	= HISTC_DSO_TO,
1333};
1334
1335struct sort_entry sort_sym_from = {
1336	.se_header	= "Source Symbol",
1337	.se_cmp		= sort__sym_from_cmp,
1338	.se_snprintf	= hist_entry__sym_from_snprintf,
1339	.se_filter	= hist_entry__sym_from_filter,
1340	.se_width_idx	= HISTC_SYMBOL_FROM,
1341};
1342
1343struct sort_entry sort_sym_to = {
1344	.se_header	= "Target Symbol",
1345	.se_cmp		= sort__sym_to_cmp,
1346	.se_snprintf	= hist_entry__sym_to_snprintf,
1347	.se_filter	= hist_entry__sym_to_filter,
1348	.se_width_idx	= HISTC_SYMBOL_TO,
1349};
1350
1351static int _hist_entry__addr_snprintf(struct map_symbol *ms,
1352				     u64 ip, char level, char *bf, size_t size,
1353				     unsigned int width)
1354{
1355	struct symbol *sym = ms->sym;
1356	struct map *map = ms->map;
1357	size_t ret = 0, offs;
1358
1359	ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
1360	if (sym && map) {
1361		if (sym->type == STT_OBJECT) {
1362			ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
1363			ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
1364					ip - map__unmap_ip(map, sym->start));
1365		} else {
1366			ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
1367					       width - ret,
1368					       sym->name);
1369			offs = ip - sym->start;
1370			if (offs)
1371				ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", offs);
1372		}
1373	} else {
1374		size_t len = BITS_PER_LONG / 4;
1375		ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
1376				       len, ip);
1377	}
1378
1379	return ret;
1380}
1381
1382static int hist_entry__addr_from_snprintf(struct hist_entry *he, char *bf,
1383					 size_t size, unsigned int width)
1384{
1385	if (he->branch_info) {
1386		struct addr_map_symbol *from = &he->branch_info->from;
1387
1388		return _hist_entry__addr_snprintf(&from->ms, from->al_addr,
1389						 he->level, bf, size, width);
1390	}
1391
1392	return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
1393}
1394
1395static int hist_entry__addr_to_snprintf(struct hist_entry *he, char *bf,
1396				       size_t size, unsigned int width)
1397{
1398	if (he->branch_info) {
1399		struct addr_map_symbol *to = &he->branch_info->to;
1400
1401		return _hist_entry__addr_snprintf(&to->ms, to->al_addr,
1402						 he->level, bf, size, width);
1403	}
1404
1405	return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
1406}
1407
1408static int64_t
1409sort__addr_from_cmp(struct hist_entry *left, struct hist_entry *right)
1410{
1411	struct addr_map_symbol *from_l;
1412	struct addr_map_symbol *from_r;
1413	int64_t ret;
1414
1415	if (!left->branch_info || !right->branch_info)
1416		return cmp_null(left->branch_info, right->branch_info);
1417
1418	from_l = &left->branch_info->from;
1419	from_r = &right->branch_info->from;
1420
1421	/*
1422	 * comparing symbol address alone is not enough since it's a
1423	 * relative address within a dso.
1424	 */
1425	ret = _sort__dso_cmp(from_l->ms.map, from_r->ms.map);
1426	if (ret != 0)
1427		return ret;
1428
1429	return _sort__addr_cmp(from_l->addr, from_r->addr);
1430}
1431
1432static int64_t
1433sort__addr_to_cmp(struct hist_entry *left, struct hist_entry *right)
1434{
1435	struct addr_map_symbol *to_l;
1436	struct addr_map_symbol *to_r;
1437	int64_t ret;
1438
1439	if (!left->branch_info || !right->branch_info)
1440		return cmp_null(left->branch_info, right->branch_info);
1441
1442	to_l = &left->branch_info->to;
1443	to_r = &right->branch_info->to;
1444
1445	/*
1446	 * comparing symbol address alone is not enough since it's a
1447	 * relative address within a dso.
1448	 */
1449	ret = _sort__dso_cmp(to_l->ms.map, to_r->ms.map);
1450	if (ret != 0)
1451		return ret;
1452
1453	return _sort__addr_cmp(to_l->addr, to_r->addr);
1454}
1455
1456struct sort_entry sort_addr_from = {
1457	.se_header	= "Source Address",
1458	.se_cmp		= sort__addr_from_cmp,
1459	.se_snprintf	= hist_entry__addr_from_snprintf,
1460	.se_filter	= hist_entry__sym_from_filter, /* shared with sym_from */
1461	.se_width_idx	= HISTC_ADDR_FROM,
1462};
1463
1464struct sort_entry sort_addr_to = {
1465	.se_header	= "Target Address",
1466	.se_cmp		= sort__addr_to_cmp,
1467	.se_snprintf	= hist_entry__addr_to_snprintf,
1468	.se_filter	= hist_entry__sym_to_filter, /* shared with sym_to */
1469	.se_width_idx	= HISTC_ADDR_TO,
1470};
1471
1472
1473static int64_t
1474sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
1475{
1476	unsigned char mp, p;
1477
1478	if (!left->branch_info || !right->branch_info)
1479		return cmp_null(left->branch_info, right->branch_info);
1480
1481	mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
1482	p  = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
1483	return mp || p;
1484}
1485
1486static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
1487				    size_t size, unsigned int width){
1488	static const char *out = "N/A";
1489
1490	if (he->branch_info) {
1491		if (he->branch_info->flags.predicted)
1492			out = "N";
1493		else if (he->branch_info->flags.mispred)
1494			out = "Y";
1495	}
1496
1497	return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
1498}
1499
1500static int64_t
1501sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
1502{
1503	if (!left->branch_info || !right->branch_info)
1504		return cmp_null(left->branch_info, right->branch_info);
1505
1506	return left->branch_info->flags.cycles -
1507		right->branch_info->flags.cycles;
1508}
1509
1510static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
1511				    size_t size, unsigned int width)
1512{
1513	if (!he->branch_info)
1514		return scnprintf(bf, size, "%-.*s", width, "N/A");
1515	if (he->branch_info->flags.cycles == 0)
1516		return repsep_snprintf(bf, size, "%-*s", width, "-");
1517	return repsep_snprintf(bf, size, "%-*hd", width,
1518			       he->branch_info->flags.cycles);
1519}
1520
1521struct sort_entry sort_cycles = {
1522	.se_header	= "Basic Block Cycles",
1523	.se_cmp		= sort__cycles_cmp,
1524	.se_snprintf	= hist_entry__cycles_snprintf,
1525	.se_width_idx	= HISTC_CYCLES,
1526};
1527
1528/* --sort daddr_sym */
1529int64_t
1530sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
1531{
1532	uint64_t l = 0, r = 0;
1533
1534	if (left->mem_info)
1535		l = mem_info__daddr(left->mem_info)->addr;
1536	if (right->mem_info)
1537		r = mem_info__daddr(right->mem_info)->addr;
1538
1539	return (int64_t)(r - l);
1540}
1541
1542static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
1543				    size_t size, unsigned int width)
1544{
1545	uint64_t addr = 0;
1546	struct map_symbol *ms = NULL;
1547
1548	if (he->mem_info) {
1549		addr = mem_info__daddr(he->mem_info)->addr;
1550		ms = &mem_info__daddr(he->mem_info)->ms;
1551	}
1552	return _hist_entry__sym_snprintf(ms, addr, he->level, bf, size, width);
1553}
1554
1555int64_t
1556sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right)
1557{
1558	uint64_t l = 0, r = 0;
1559
1560	if (left->mem_info)
1561		l = mem_info__iaddr(left->mem_info)->addr;
1562	if (right->mem_info)
1563		r = mem_info__iaddr(right->mem_info)->addr;
1564
1565	return (int64_t)(r - l);
1566}
1567
1568static int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf,
1569				    size_t size, unsigned int width)
1570{
1571	uint64_t addr = 0;
1572	struct map_symbol *ms = NULL;
1573
1574	if (he->mem_info) {
1575		addr = mem_info__iaddr(he->mem_info)->addr;
1576		ms   = &mem_info__iaddr(he->mem_info)->ms;
1577	}
1578	return _hist_entry__sym_snprintf(ms, addr, he->level, bf, size, width);
1579}
1580
1581static int64_t
1582sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
1583{
1584	struct map *map_l = NULL;
1585	struct map *map_r = NULL;
1586
1587	if (left->mem_info)
1588		map_l = mem_info__daddr(left->mem_info)->ms.map;
1589	if (right->mem_info)
1590		map_r = mem_info__daddr(right->mem_info)->ms.map;
1591
1592	return _sort__dso_cmp(map_l, map_r);
1593}
1594
1595static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
1596				    size_t size, unsigned int width)
1597{
1598	struct map *map = NULL;
1599
1600	if (he->mem_info)
1601		map = mem_info__daddr(he->mem_info)->ms.map;
1602
1603	return _hist_entry__dso_snprintf(map, bf, size, width);
1604}
1605
1606static int64_t
1607sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
1608{
1609	union perf_mem_data_src data_src_l;
1610	union perf_mem_data_src data_src_r;
1611
1612	if (left->mem_info)
1613		data_src_l = *mem_info__data_src(left->mem_info);
1614	else
1615		data_src_l.mem_lock = PERF_MEM_LOCK_NA;
1616
1617	if (right->mem_info)
1618		data_src_r = *mem_info__data_src(right->mem_info);
1619	else
1620		data_src_r.mem_lock = PERF_MEM_LOCK_NA;
1621
1622	return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
1623}
1624
1625static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
1626				    size_t size, unsigned int width)
1627{
1628	char out[10];
1629
1630	perf_mem__lck_scnprintf(out, sizeof(out), he->mem_info);
1631	return repsep_snprintf(bf, size, "%.*s", width, out);
1632}
1633
1634static int64_t
1635sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
1636{
1637	union perf_mem_data_src data_src_l;
1638	union perf_mem_data_src data_src_r;
1639
1640	if (left->mem_info)
1641		data_src_l = *mem_info__data_src(left->mem_info);
1642	else
1643		data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
1644
1645	if (right->mem_info)
1646		data_src_r = *mem_info__data_src(right->mem_info);
1647	else
1648		data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
1649
1650	return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
1651}
1652
1653static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
1654				    size_t size, unsigned int width)
1655{
1656	char out[64];
1657
1658	perf_mem__tlb_scnprintf(out, sizeof(out), he->mem_info);
1659	return repsep_snprintf(bf, size, "%-*s", width, out);
1660}
1661
1662static int64_t
1663sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
1664{
1665	union perf_mem_data_src data_src_l;
1666	union perf_mem_data_src data_src_r;
1667
1668	if (left->mem_info)
1669		data_src_l = *mem_info__data_src(left->mem_info);
1670	else
1671		data_src_l.mem_lvl = PERF_MEM_LVL_NA;
1672
1673	if (right->mem_info)
1674		data_src_r = *mem_info__data_src(right->mem_info);
1675	else
1676		data_src_r.mem_lvl = PERF_MEM_LVL_NA;
1677
1678	return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
1679}
1680
1681static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
1682				    size_t size, unsigned int width)
1683{
1684	char out[64];
1685
1686	perf_mem__lvl_scnprintf(out, sizeof(out), he->mem_info);
1687	return repsep_snprintf(bf, size, "%-*s", width, out);
1688}
1689
1690static int64_t
1691sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
1692{
1693	union perf_mem_data_src data_src_l;
1694	union perf_mem_data_src data_src_r;
1695
1696	if (left->mem_info)
1697		data_src_l = *mem_info__data_src(left->mem_info);
1698	else
1699		data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
1700
1701	if (right->mem_info)
1702		data_src_r = *mem_info__data_src(right->mem_info);
1703	else
1704		data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
1705
1706	return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
1707}
1708
1709static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
1710				    size_t size, unsigned int width)
1711{
1712	char out[64];
1713
1714	perf_mem__snp_scnprintf(out, sizeof(out), he->mem_info);
1715	return repsep_snprintf(bf, size, "%-*s", width, out);
1716}
1717
1718int64_t
1719sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
1720{
1721	u64 l, r;
1722	struct map *l_map, *r_map;
1723	struct dso *l_dso, *r_dso;
1724	int rc;
1725
1726	if (!left->mem_info)  return -1;
1727	if (!right->mem_info) return 1;
1728
1729	/* group event types together */
1730	if (left->cpumode > right->cpumode) return -1;
1731	if (left->cpumode < right->cpumode) return 1;
1732
1733	l_map = mem_info__daddr(left->mem_info)->ms.map;
1734	r_map = mem_info__daddr(right->mem_info)->ms.map;
1735
1736	/* if both are NULL, jump to sort on al_addr instead */
1737	if (!l_map && !r_map)
1738		goto addr;
1739
1740	if (!l_map) return -1;
1741	if (!r_map) return 1;
1742
1743	l_dso = map__dso(l_map);
1744	r_dso = map__dso(r_map);
1745	rc = dso__cmp_id(l_dso, r_dso);
1746	if (rc)
1747		return rc;
1748	/*
1749	 * Addresses with no major/minor numbers or build ID are assumed to be
1750	 * anonymous in userspace.  Sort those on pid then address.
1751	 *
1752	 * The kernel and non-zero major/minor mapped areas are
1753	 * assumed to be unity mapped.  Sort those on address.
1754	 */
1755	if (left->cpumode != PERF_RECORD_MISC_KERNEL && (map__flags(l_map) & MAP_SHARED) == 0) {
1756		const struct dso_id *dso_id = dso__id_const(l_dso);
1757
1758		if (!dso_id->mmap2_valid)
1759			dso_id = dso__id_const(r_dso);
1760
1761		if (!build_id__is_defined(&dso_id->build_id) &&
1762		    (!dso_id->mmap2_valid || (dso_id->maj == 0 && dso_id->min == 0))) {
1763			/* userspace anonymous */
1764
1765			if (thread__pid(left->thread) > thread__pid(right->thread))
1766				return -1;
1767			if (thread__pid(left->thread) < thread__pid(right->thread))
1768				return 1;
1769		}
1770	}
1771
1772addr:
1773	/* al_addr does all the right addr - start + offset calculations */
1774	l = cl_address(mem_info__daddr(left->mem_info)->al_addr, chk_double_cl);
1775	r = cl_address(mem_info__daddr(right->mem_info)->al_addr, chk_double_cl);
1776
1777	if (l > r) return -1;
1778	if (l < r) return 1;
1779
1780	return 0;
1781}
1782
1783static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
1784					  size_t size, unsigned int width)
1785{
1786
1787	uint64_t addr = 0;
1788	struct map_symbol *ms = NULL;
1789	char level = he->level;
1790
1791	if (he->mem_info) {
1792		struct map *map = mem_info__daddr(he->mem_info)->ms.map;
1793		struct dso *dso = map ? map__dso(map) : NULL;
1794		const struct dso_id *dso_id = dso ? dso__id_const(dso) : &dso_id_empty;
1795
1796		addr = cl_address(mem_info__daddr(he->mem_info)->al_addr, chk_double_cl);
1797		ms = &mem_info__daddr(he->mem_info)->ms;
1798
1799		/* print [s] for shared data mmaps */
1800		if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
1801		     map && !(map__prot(map) & PROT_EXEC) &&
1802		     (map__flags(map) & MAP_SHARED) &&
1803		     (!dso_id->mmap2_valid || (dso_id->maj == 0 && dso_id->min == 0)))
1804			level = 's';
1805		else if (!map)
1806			level = 'X';
1807	}
1808	return _hist_entry__sym_snprintf(ms, addr, level, bf, size, width);
1809}
1810
1811struct sort_entry sort_mispredict = {
1812	.se_header	= "Branch Mispredicted",
1813	.se_cmp		= sort__mispredict_cmp,
1814	.se_snprintf	= hist_entry__mispredict_snprintf,
1815	.se_width_idx	= HISTC_MISPREDICT,
1816};
1817
1818static int64_t
1819sort__weight_cmp(struct hist_entry *left, struct hist_entry *right)
1820{
1821	return left->weight - right->weight;
1822}
1823
1824static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
1825				    size_t size, unsigned int width)
1826{
1827	return repsep_snprintf(bf, size, "%-*llu", width, he->weight);
1828}
1829
1830struct sort_entry sort_local_weight = {
1831	.se_header	= "Local Weight",
1832	.se_cmp		= sort__weight_cmp,
1833	.se_snprintf	= hist_entry__local_weight_snprintf,
1834	.se_width_idx	= HISTC_LOCAL_WEIGHT,
1835};
1836
1837static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
1838					      size_t size, unsigned int width)
1839{
1840	return repsep_snprintf(bf, size, "%-*llu", width,
1841			       he->weight * he->stat.nr_events);
1842}
1843
1844struct sort_entry sort_global_weight = {
1845	.se_header	= "Weight",
1846	.se_cmp		= sort__weight_cmp,
1847	.se_snprintf	= hist_entry__global_weight_snprintf,
1848	.se_width_idx	= HISTC_GLOBAL_WEIGHT,
1849};
1850
1851static int64_t
1852sort__ins_lat_cmp(struct hist_entry *left, struct hist_entry *right)
1853{
1854	return left->ins_lat - right->ins_lat;
1855}
1856
1857static int hist_entry__local_ins_lat_snprintf(struct hist_entry *he, char *bf,
1858					      size_t size, unsigned int width)
1859{
1860	return repsep_snprintf(bf, size, "%-*u", width, he->ins_lat);
1861}
1862
1863struct sort_entry sort_local_ins_lat = {
1864	.se_header	= "Local INSTR Latency",
1865	.se_cmp		= sort__ins_lat_cmp,
1866	.se_snprintf	= hist_entry__local_ins_lat_snprintf,
1867	.se_width_idx	= HISTC_LOCAL_INS_LAT,
1868};
1869
1870static int hist_entry__global_ins_lat_snprintf(struct hist_entry *he, char *bf,
1871					       size_t size, unsigned int width)
1872{
1873	return repsep_snprintf(bf, size, "%-*u", width,
1874			       he->ins_lat * he->stat.nr_events);
1875}
1876
1877struct sort_entry sort_global_ins_lat = {
1878	.se_header	= "INSTR Latency",
1879	.se_cmp		= sort__ins_lat_cmp,
1880	.se_snprintf	= hist_entry__global_ins_lat_snprintf,
1881	.se_width_idx	= HISTC_GLOBAL_INS_LAT,
1882};
1883
1884static int64_t
1885sort__p_stage_cyc_cmp(struct hist_entry *left, struct hist_entry *right)
1886{
1887	return left->weight3 - right->weight3;
1888}
1889
1890static int hist_entry__global_p_stage_cyc_snprintf(struct hist_entry *he, char *bf,
1891					size_t size, unsigned int width)
1892{
1893	return repsep_snprintf(bf, size, "%-*u", width, he->weight3 * he->stat.nr_events);
1894}
1895
1896
1897static int hist_entry__p_stage_cyc_snprintf(struct hist_entry *he, char *bf,
1898					size_t size, unsigned int width)
1899{
1900	return repsep_snprintf(bf, size, "%-*u", width, he->weight3);
1901}
1902
1903struct sort_entry sort_local_p_stage_cyc = {
1904	.se_header      = "Local Pipeline Stage Cycle",
1905	.se_cmp         = sort__p_stage_cyc_cmp,
1906	.se_snprintf	= hist_entry__p_stage_cyc_snprintf,
1907	.se_width_idx	= HISTC_LOCAL_P_STAGE_CYC,
1908};
1909
1910struct sort_entry sort_global_p_stage_cyc = {
1911	.se_header      = "Pipeline Stage Cycle",
1912	.se_cmp         = sort__p_stage_cyc_cmp,
1913	.se_snprintf    = hist_entry__global_p_stage_cyc_snprintf,
1914	.se_width_idx   = HISTC_GLOBAL_P_STAGE_CYC,
1915};
1916
1917struct sort_entry sort_mem_daddr_sym = {
1918	.se_header	= "Data Symbol",
1919	.se_cmp		= sort__daddr_cmp,
1920	.se_snprintf	= hist_entry__daddr_snprintf,
1921	.se_width_idx	= HISTC_MEM_DADDR_SYMBOL,
1922};
1923
1924struct sort_entry sort_mem_iaddr_sym = {
1925	.se_header	= "Code Symbol",
1926	.se_cmp		= sort__iaddr_cmp,
1927	.se_snprintf	= hist_entry__iaddr_snprintf,
1928	.se_width_idx	= HISTC_MEM_IADDR_SYMBOL,
1929};
1930
1931struct sort_entry sort_mem_daddr_dso = {
1932	.se_header	= "Data Object",
1933	.se_cmp		= sort__dso_daddr_cmp,
1934	.se_snprintf	= hist_entry__dso_daddr_snprintf,
1935	.se_width_idx	= HISTC_MEM_DADDR_DSO,
1936};
1937
1938struct sort_entry sort_mem_locked = {
1939	.se_header	= "Locked",
1940	.se_cmp		= sort__locked_cmp,
1941	.se_snprintf	= hist_entry__locked_snprintf,
1942	.se_width_idx	= HISTC_MEM_LOCKED,
1943};
1944
1945struct sort_entry sort_mem_tlb = {
1946	.se_header	= "TLB access",
1947	.se_cmp		= sort__tlb_cmp,
1948	.se_snprintf	= hist_entry__tlb_snprintf,
1949	.se_width_idx	= HISTC_MEM_TLB,
1950};
1951
1952struct sort_entry sort_mem_lvl = {
1953	.se_header	= "Memory access",
1954	.se_cmp		= sort__lvl_cmp,
1955	.se_snprintf	= hist_entry__lvl_snprintf,
1956	.se_width_idx	= HISTC_MEM_LVL,
1957};
1958
1959struct sort_entry sort_mem_snoop = {
1960	.se_header	= "Snoop",
1961	.se_cmp		= sort__snoop_cmp,
1962	.se_snprintf	= hist_entry__snoop_snprintf,
1963	.se_width_idx	= HISTC_MEM_SNOOP,
1964};
1965
1966struct sort_entry sort_mem_dcacheline = {
1967	.se_header	= "Data Cacheline",
1968	.se_cmp		= sort__dcacheline_cmp,
1969	.se_snprintf	= hist_entry__dcacheline_snprintf,
1970	.se_width_idx	= HISTC_MEM_DCACHELINE,
1971};
1972
1973static int64_t
1974sort__blocked_cmp(struct hist_entry *left, struct hist_entry *right)
1975{
1976	union perf_mem_data_src data_src_l;
1977	union perf_mem_data_src data_src_r;
1978
1979	if (left->mem_info)
1980		data_src_l = *mem_info__data_src(left->mem_info);
1981	else
1982		data_src_l.mem_blk = PERF_MEM_BLK_NA;
1983
1984	if (right->mem_info)
1985		data_src_r = *mem_info__data_src(right->mem_info);
1986	else
1987		data_src_r.mem_blk = PERF_MEM_BLK_NA;
1988
1989	return (int64_t)(data_src_r.mem_blk - data_src_l.mem_blk);
1990}
1991
1992static int hist_entry__blocked_snprintf(struct hist_entry *he, char *bf,
1993					size_t size, unsigned int width)
1994{
1995	char out[16];
1996
1997	perf_mem__blk_scnprintf(out, sizeof(out), he->mem_info);
1998	return repsep_snprintf(bf, size, "%.*s", width, out);
1999}
2000
2001struct sort_entry sort_mem_blocked = {
2002	.se_header	= "Blocked",
2003	.se_cmp		= sort__blocked_cmp,
2004	.se_snprintf	= hist_entry__blocked_snprintf,
2005	.se_width_idx	= HISTC_MEM_BLOCKED,
2006};
2007
2008static int64_t
2009sort__phys_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
2010{
2011	uint64_t l = 0, r = 0;
2012
2013	if (left->mem_info)
2014		l = mem_info__daddr(left->mem_info)->phys_addr;
2015	if (right->mem_info)
2016		r = mem_info__daddr(right->mem_info)->phys_addr;
2017
2018	return (int64_t)(r - l);
2019}
2020
2021static int hist_entry__phys_daddr_snprintf(struct hist_entry *he, char *bf,
2022					   size_t size, unsigned int width)
2023{
2024	uint64_t addr = 0;
2025	size_t ret = 0;
2026	size_t len = BITS_PER_LONG / 4;
2027
2028	addr = mem_info__daddr(he->mem_info)->phys_addr;
2029
2030	ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", he->level);
2031
2032	ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", len, addr);
2033
2034	ret += repsep_snprintf(bf + ret, size - ret, "%-*s", width - ret, "");
2035
2036	if (ret > width)
2037		bf[width] = '\0';
2038
2039	return width;
2040}
2041
2042struct sort_entry sort_mem_phys_daddr = {
2043	.se_header	= "Data Physical Address",
2044	.se_cmp		= sort__phys_daddr_cmp,
2045	.se_snprintf	= hist_entry__phys_daddr_snprintf,
2046	.se_width_idx	= HISTC_MEM_PHYS_DADDR,
2047};
2048
2049static int64_t
2050sort__data_page_size_cmp(struct hist_entry *left, struct hist_entry *right)
2051{
2052	uint64_t l = 0, r = 0;
2053
2054	if (left->mem_info)
2055		l = mem_info__daddr(left->mem_info)->data_page_size;
2056	if (right->mem_info)
2057		r = mem_info__daddr(right->mem_info)->data_page_size;
2058
2059	return (int64_t)(r - l);
2060}
2061
2062static int hist_entry__data_page_size_snprintf(struct hist_entry *he, char *bf,
2063					  size_t size, unsigned int width)
2064{
2065	char str[PAGE_SIZE_NAME_LEN];
2066
2067	return repsep_snprintf(bf, size, "%-*s", width,
2068			get_page_size_name(mem_info__daddr(he->mem_info)->data_page_size, str));
2069}
2070
2071struct sort_entry sort_mem_data_page_size = {
2072	.se_header	= "Data Page Size",
2073	.se_cmp		= sort__data_page_size_cmp,
2074	.se_snprintf	= hist_entry__data_page_size_snprintf,
2075	.se_width_idx	= HISTC_MEM_DATA_PAGE_SIZE,
2076};
2077
2078static int64_t
2079sort__code_page_size_cmp(struct hist_entry *left, struct hist_entry *right)
2080{
2081	uint64_t l = left->code_page_size;
2082	uint64_t r = right->code_page_size;
2083
2084	return (int64_t)(r - l);
2085}
2086
2087static int hist_entry__code_page_size_snprintf(struct hist_entry *he, char *bf,
2088					  size_t size, unsigned int width)
2089{
2090	char str[PAGE_SIZE_NAME_LEN];
2091
2092	return repsep_snprintf(bf, size, "%-*s", width,
2093			       get_page_size_name(he->code_page_size, str));
2094}
2095
2096struct sort_entry sort_code_page_size = {
2097	.se_header	= "Code Page Size",
2098	.se_cmp		= sort__code_page_size_cmp,
2099	.se_snprintf	= hist_entry__code_page_size_snprintf,
2100	.se_width_idx	= HISTC_CODE_PAGE_SIZE,
2101};
2102
2103static int64_t
2104sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
2105{
2106	if (!left->branch_info || !right->branch_info)
2107		return cmp_null(left->branch_info, right->branch_info);
2108
2109	return left->branch_info->flags.abort !=
2110		right->branch_info->flags.abort;
2111}
2112
2113static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
2114				    size_t size, unsigned int width)
2115{
2116	static const char *out = "N/A";
2117
2118	if (he->branch_info) {
2119		if (he->branch_info->flags.abort)
2120			out = "A";
2121		else
2122			out = ".";
2123	}
2124
2125	return repsep_snprintf(bf, size, "%-*s", width, out);
2126}
2127
2128struct sort_entry sort_abort = {
2129	.se_header	= "Transaction abort",
2130	.se_cmp		= sort__abort_cmp,
2131	.se_snprintf	= hist_entry__abort_snprintf,
2132	.se_width_idx	= HISTC_ABORT,
2133};
2134
2135static int64_t
2136sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
2137{
2138	if (!left->branch_info || !right->branch_info)
2139		return cmp_null(left->branch_info, right->branch_info);
2140
2141	return left->branch_info->flags.in_tx !=
2142		right->branch_info->flags.in_tx;
2143}
2144
2145static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
2146				    size_t size, unsigned int width)
2147{
2148	static const char *out = "N/A";
2149
2150	if (he->branch_info) {
2151		if (he->branch_info->flags.in_tx)
2152			out = "T";
2153		else
2154			out = ".";
2155	}
2156
2157	return repsep_snprintf(bf, size, "%-*s", width, out);
2158}
2159
2160struct sort_entry sort_in_tx = {
2161	.se_header	= "Branch in transaction",
2162	.se_cmp		= sort__in_tx_cmp,
2163	.se_snprintf	= hist_entry__in_tx_snprintf,
2164	.se_width_idx	= HISTC_IN_TX,
2165};
2166
2167static int64_t
2168sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
2169{
2170	return left->transaction - right->transaction;
2171}
2172
2173static inline char *add_str(char *p, const char *str)
2174{
2175	strcpy(p, str);
2176	return p + strlen(str);
2177}
2178
2179static struct txbit {
2180	unsigned flag;
2181	const char *name;
2182	int skip_for_len;
2183} txbits[] = {
2184	{ PERF_TXN_ELISION,        "EL ",        0 },
2185	{ PERF_TXN_TRANSACTION,    "TX ",        1 },
2186	{ PERF_TXN_SYNC,           "SYNC ",      1 },
2187	{ PERF_TXN_ASYNC,          "ASYNC ",     0 },
2188	{ PERF_TXN_RETRY,          "RETRY ",     0 },
2189	{ PERF_TXN_CONFLICT,       "CON ",       0 },
2190	{ PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
2191	{ PERF_TXN_CAPACITY_READ,  "CAP-READ ",  0 },
2192	{ 0, NULL, 0 }
2193};
2194
2195int hist_entry__transaction_len(void)
2196{
2197	int i;
2198	int len = 0;
2199
2200	for (i = 0; txbits[i].name; i++) {
2201		if (!txbits[i].skip_for_len)
2202			len += strlen(txbits[i].name);
2203	}
2204	len += 4; /* :XX<space> */
2205	return len;
2206}
2207
2208static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
2209					    size_t size, unsigned int width)
2210{
2211	u64 t = he->transaction;
2212	char buf[128];
2213	char *p = buf;
2214	int i;
2215
2216	buf[0] = 0;
2217	for (i = 0; txbits[i].name; i++)
2218		if (txbits[i].flag & t)
2219			p = add_str(p, txbits[i].name);
2220	if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
2221		p = add_str(p, "NEITHER ");
2222	if (t & PERF_TXN_ABORT_MASK) {
2223		sprintf(p, ":%" PRIx64,
2224			(t & PERF_TXN_ABORT_MASK) >>
2225			PERF_TXN_ABORT_SHIFT);
2226		p += strlen(p);
2227	}
2228
2229	return repsep_snprintf(bf, size, "%-*s", width, buf);
2230}
2231
2232struct sort_entry sort_transaction = {
2233	.se_header	= "Transaction                ",
2234	.se_cmp		= sort__transaction_cmp,
2235	.se_snprintf	= hist_entry__transaction_snprintf,
2236	.se_width_idx	= HISTC_TRANSACTION,
2237};
2238
2239/* --sort symbol_size */
2240
2241static int64_t _sort__sym_size_cmp(struct symbol *sym_l, struct symbol *sym_r)
2242{
2243	int64_t size_l = sym_l != NULL ? symbol__size(sym_l) : 0;
2244	int64_t size_r = sym_r != NULL ? symbol__size(sym_r) : 0;
2245
2246	return size_l < size_r ? -1 :
2247		size_l == size_r ? 0 : 1;
2248}
2249
2250static int64_t
2251sort__sym_size_cmp(struct hist_entry *left, struct hist_entry *right)
2252{
2253	return _sort__sym_size_cmp(right->ms.sym, left->ms.sym);
2254}
2255
2256static int _hist_entry__sym_size_snprintf(struct symbol *sym, char *bf,
2257					  size_t bf_size, unsigned int width)
2258{
2259	if (sym)
2260		return repsep_snprintf(bf, bf_size, "%*d", width, symbol__size(sym));
2261
2262	return repsep_snprintf(bf, bf_size, "%*s", width, "unknown");
2263}
2264
2265static int hist_entry__sym_size_snprintf(struct hist_entry *he, char *bf,
2266					 size_t size, unsigned int width)
2267{
2268	return _hist_entry__sym_size_snprintf(he->ms.sym, bf, size, width);
2269}
2270
2271struct sort_entry sort_sym_size = {
2272	.se_header	= "Symbol size",
2273	.se_cmp		= sort__sym_size_cmp,
2274	.se_snprintf	= hist_entry__sym_size_snprintf,
2275	.se_width_idx	= HISTC_SYM_SIZE,
2276};
2277
2278/* --sort dso_size */
2279
2280static int64_t _sort__dso_size_cmp(struct map *map_l, struct map *map_r)
2281{
2282	int64_t size_l = map_l != NULL ? map__size(map_l) : 0;
2283	int64_t size_r = map_r != NULL ? map__size(map_r) : 0;
2284
2285	return size_l < size_r ? -1 :
2286		size_l == size_r ? 0 : 1;
2287}
2288
2289static int64_t
2290sort__dso_size_cmp(struct hist_entry *left, struct hist_entry *right)
2291{
2292	return _sort__dso_size_cmp(right->ms.map, left->ms.map);
2293}
2294
2295static int _hist_entry__dso_size_snprintf(struct map *map, char *bf,
2296					  size_t bf_size, unsigned int width)
2297{
2298	if (map && map__dso(map))
2299		return repsep_snprintf(bf, bf_size, "%*d", width, map__size(map));
2300
2301	return repsep_snprintf(bf, bf_size, "%*s", width, "unknown");
2302}
2303
2304static int hist_entry__dso_size_snprintf(struct hist_entry *he, char *bf,
2305					 size_t size, unsigned int width)
2306{
2307	return _hist_entry__dso_size_snprintf(he->ms.map, bf, size, width);
2308}
2309
2310struct sort_entry sort_dso_size = {
2311	.se_header	= "DSO size",
2312	.se_cmp		= sort__dso_size_cmp,
2313	.se_snprintf	= hist_entry__dso_size_snprintf,
2314	.se_width_idx	= HISTC_DSO_SIZE,
2315};
2316
2317/* --sort addr */
2318
2319static int64_t
2320sort__addr_cmp(struct hist_entry *left, struct hist_entry *right)
2321{
2322	u64 left_ip = left->ip;
2323	u64 right_ip = right->ip;
2324	struct map *left_map = left->ms.map;
2325	struct map *right_map = right->ms.map;
2326
2327	if (left_map)
2328		left_ip = map__unmap_ip(left_map, left_ip);
2329	if (right_map)
2330		right_ip = map__unmap_ip(right_map, right_ip);
2331
2332	return _sort__addr_cmp(left_ip, right_ip);
2333}
2334
2335static int hist_entry__addr_snprintf(struct hist_entry *he, char *bf,
2336				     size_t size, unsigned int width)
2337{
2338	u64 ip = he->ip;
2339	struct map *map = he->ms.map;
2340
2341	if (map)
2342		ip = map__unmap_ip(map, ip);
2343
2344	return repsep_snprintf(bf, size, "%-#*llx", width, ip);
2345}
2346
2347struct sort_entry sort_addr = {
2348	.se_header	= "Address",
2349	.se_cmp		= sort__addr_cmp,
2350	.se_snprintf	= hist_entry__addr_snprintf,
2351	.se_width_idx	= HISTC_ADDR,
2352};
2353
2354/* --sort type */
2355
2356struct annotated_data_type unknown_type = {
2357	.self = {
2358		.type_name = (char *)"(unknown)",
2359		.children = LIST_HEAD_INIT(unknown_type.self.children),
2360	},
2361};
2362
2363static int64_t
2364sort__type_cmp(struct hist_entry *left, struct hist_entry *right)
2365{
2366	return sort__addr_cmp(left, right);
2367}
2368
2369static void sort__type_init(struct hist_entry *he)
2370{
2371	if (he->mem_type)
2372		return;
2373
2374	he->mem_type = hist_entry__get_data_type(he);
2375	if (he->mem_type == NULL) {
2376		he->mem_type = &unknown_type;
2377		he->mem_type_off = 0;
2378	}
2379}
2380
2381static int64_t
2382sort__type_collapse(struct hist_entry *left, struct hist_entry *right)
2383{
2384	struct annotated_data_type *left_type = left->mem_type;
2385	struct annotated_data_type *right_type = right->mem_type;
2386
2387	if (!left_type) {
2388		sort__type_init(left);
2389		left_type = left->mem_type;
2390	}
2391
2392	if (!right_type) {
2393		sort__type_init(right);
2394		right_type = right->mem_type;
2395	}
2396
2397	return strcmp(left_type->self.type_name, right_type->self.type_name);
2398}
2399
2400static int64_t
2401sort__type_sort(struct hist_entry *left, struct hist_entry *right)
2402{
2403	return sort__type_collapse(left, right);
2404}
2405
2406static int hist_entry__type_snprintf(struct hist_entry *he, char *bf,
2407				     size_t size, unsigned int width)
2408{
2409	return repsep_snprintf(bf, size, "%-*s", width, he->mem_type->self.type_name);
2410}
2411
2412struct sort_entry sort_type = {
2413	.se_header	= "Data Type",
2414	.se_cmp		= sort__type_cmp,
2415	.se_collapse	= sort__type_collapse,
2416	.se_sort	= sort__type_sort,
2417	.se_init	= sort__type_init,
2418	.se_snprintf	= hist_entry__type_snprintf,
2419	.se_width_idx	= HISTC_TYPE,
2420};
2421
2422/* --sort typeoff */
2423
2424static int64_t
2425sort__typeoff_sort(struct hist_entry *left, struct hist_entry *right)
2426{
2427	struct annotated_data_type *left_type = left->mem_type;
2428	struct annotated_data_type *right_type = right->mem_type;
2429	int64_t ret;
2430
2431	if (!left_type) {
2432		sort__type_init(left);
2433		left_type = left->mem_type;
2434	}
2435
2436	if (!right_type) {
2437		sort__type_init(right);
2438		right_type = right->mem_type;
2439	}
2440
2441	ret = strcmp(left_type->self.type_name, right_type->self.type_name);
2442	if (ret)
2443		return ret;
2444	return left->mem_type_off - right->mem_type_off;
2445}
2446
2447static int hist_entry__typeoff_snprintf(struct hist_entry *he, char *bf,
2448				     size_t size, unsigned int width __maybe_unused)
2449{
2450	struct annotated_data_type *he_type = he->mem_type;
2451	char buf[4096];
2452
2453	if (he_type == &unknown_type || he_type == &stackop_type ||
2454	    he_type == &canary_type)
2455		return repsep_snprintf(bf, size, "%s", he_type->self.type_name);
2456
2457	if (!annotated_data_type__get_member_name(he_type, buf, sizeof(buf),
2458						  he->mem_type_off))
2459		scnprintf(buf, sizeof(buf), "no field");
2460
2461	return repsep_snprintf(bf, size, "%s +%#x (%s)", he_type->self.type_name,
2462			       he->mem_type_off, buf);
2463}
2464
2465struct sort_entry sort_type_offset = {
2466	.se_header	= "Data Type Offset",
2467	.se_cmp		= sort__type_cmp,
2468	.se_collapse	= sort__typeoff_sort,
2469	.se_sort	= sort__typeoff_sort,
2470	.se_init	= sort__type_init,
2471	.se_snprintf	= hist_entry__typeoff_snprintf,
2472	.se_width_idx	= HISTC_TYPE_OFFSET,
2473};
2474
2475/* --sort typecln */
2476
2477/* TODO: use actual value in the system */
2478#define TYPE_CACHELINE_SIZE  64
2479
2480static int64_t
2481sort__typecln_sort(struct hist_entry *left, struct hist_entry *right)
2482{
2483	struct annotated_data_type *left_type = left->mem_type;
2484	struct annotated_data_type *right_type = right->mem_type;
2485	int64_t left_cln, right_cln;
2486	int64_t ret;
2487
2488	if (!left_type) {
2489		sort__type_init(left);
2490		left_type = left->mem_type;
2491	}
2492
2493	if (!right_type) {
2494		sort__type_init(right);
2495		right_type = right->mem_type;
2496	}
2497
2498	ret = strcmp(left_type->self.type_name, right_type->self.type_name);
2499	if (ret)
2500		return ret;
2501
2502	left_cln = left->mem_type_off / TYPE_CACHELINE_SIZE;
2503	right_cln = right->mem_type_off / TYPE_CACHELINE_SIZE;
2504	return left_cln - right_cln;
2505}
2506
2507static int hist_entry__typecln_snprintf(struct hist_entry *he, char *bf,
2508				     size_t size, unsigned int width __maybe_unused)
2509{
2510	struct annotated_data_type *he_type = he->mem_type;
2511
2512	return repsep_snprintf(bf, size, "%s: cache-line %d", he_type->self.type_name,
2513			       he->mem_type_off / TYPE_CACHELINE_SIZE);
2514}
2515
2516struct sort_entry sort_type_cacheline = {
2517	.se_header	= "Data Type Cacheline",
2518	.se_cmp		= sort__type_cmp,
2519	.se_collapse	= sort__typecln_sort,
2520	.se_sort	= sort__typecln_sort,
2521	.se_init	= sort__type_init,
2522	.se_snprintf	= hist_entry__typecln_snprintf,
2523	.se_width_idx	= HISTC_TYPE_CACHELINE,
2524};
2525
2526
2527struct sort_dimension {
2528	const char		*name;
2529	struct sort_entry	*entry;
2530	int			taken;
2531};
2532
2533static int arch_support_sort_key(const char *sort_key, struct perf_env *env)
2534{
2535	const char *arch = perf_env__arch(env);
2536
2537	if (!strcmp("x86", arch) || !strcmp("powerpc", arch)) {
2538		if (!strcmp(sort_key, "p_stage_cyc"))
2539			return 1;
2540		if (!strcmp(sort_key, "local_p_stage_cyc"))
2541			return 1;
2542	}
2543	return 0;
2544}
2545
2546static const char *arch_perf_header_entry(const char *se_header, struct perf_env *env)
2547{
2548	const char *arch = perf_env__arch(env);
2549
2550	if (!strcmp("x86", arch)) {
2551		if (!strcmp(se_header, "Local Pipeline Stage Cycle"))
2552			return "Local Retire Latency";
2553		else if (!strcmp(se_header, "Pipeline Stage Cycle"))
2554			return "Retire Latency";
2555	} else if (!strcmp("powerpc", arch)) {
2556		if (!strcmp(se_header, "Local INSTR Latency"))
2557			return "Finish Cyc";
2558		else if (!strcmp(se_header, "INSTR Latency"))
2559			return "Global Finish_cyc";
2560		else if (!strcmp(se_header, "Local Pipeline Stage Cycle"))
2561			return "Dispatch Cyc";
2562		else if (!strcmp(se_header, "Pipeline Stage Cycle"))
2563			return "Global Dispatch_cyc";
2564	}
2565	return se_header;
2566}
2567
2568static void sort_dimension_add_dynamic_header(struct sort_dimension *sd, struct perf_env *env)
2569{
2570	sd->entry->se_header = arch_perf_header_entry(sd->entry->se_header, env);
2571}
2572
2573#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
2574
2575static struct sort_dimension common_sort_dimensions[] = {
2576	DIM(SORT_PID, "pid", sort_thread),
2577	DIM(SORT_TGID, "tgid", sort_tgid),
2578	DIM(SORT_COMM, "comm", sort_comm),
2579	DIM(SORT_DSO, "dso", sort_dso),
2580	DIM(SORT_SYM, "symbol", sort_sym),
2581	DIM(SORT_PARENT, "parent", sort_parent),
2582	DIM(SORT_CPU, "cpu", sort_cpu),
2583	DIM(SORT_SOCKET, "socket", sort_socket),
2584	DIM(SORT_SRCLINE, "srcline", sort_srcline),
2585	DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
2586	DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
2587	DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
2588	DIM(SORT_TRANSACTION, "transaction", sort_transaction),
2589#ifdef HAVE_LIBTRACEEVENT
2590	DIM(SORT_TRACE, "trace", sort_trace),
2591#endif
2592	DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size),
2593	DIM(SORT_DSO_SIZE, "dso_size", sort_dso_size),
2594	DIM(SORT_CGROUP, "cgroup", sort_cgroup),
2595	DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id),
2596	DIM(SORT_SYM_IPC_NULL, "ipc_null", sort_sym_ipc_null),
2597	DIM(SORT_TIME, "time", sort_time),
2598	DIM(SORT_CODE_PAGE_SIZE, "code_page_size", sort_code_page_size),
2599	DIM(SORT_LOCAL_INS_LAT, "local_ins_lat", sort_local_ins_lat),
2600	DIM(SORT_GLOBAL_INS_LAT, "ins_lat", sort_global_ins_lat),
2601	DIM(SORT_LOCAL_PIPELINE_STAGE_CYC, "local_p_stage_cyc", sort_local_p_stage_cyc),
2602	DIM(SORT_GLOBAL_PIPELINE_STAGE_CYC, "p_stage_cyc", sort_global_p_stage_cyc),
2603	DIM(SORT_ADDR, "addr", sort_addr),
2604	DIM(SORT_LOCAL_RETIRE_LAT, "local_retire_lat", sort_local_p_stage_cyc),
2605	DIM(SORT_GLOBAL_RETIRE_LAT, "retire_lat", sort_global_p_stage_cyc),
2606	DIM(SORT_SIMD, "simd", sort_simd),
2607	DIM(SORT_ANNOTATE_DATA_TYPE, "type", sort_type),
2608	DIM(SORT_ANNOTATE_DATA_TYPE_OFFSET, "typeoff", sort_type_offset),
2609	DIM(SORT_SYM_OFFSET, "symoff", sort_sym_offset),
2610	DIM(SORT_ANNOTATE_DATA_TYPE_CACHELINE, "typecln", sort_type_cacheline),
2611	DIM(SORT_PARALLELISM, "parallelism", sort_parallelism),
2612};
2613
2614#undef DIM
2615
2616#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
2617
2618static struct sort_dimension bstack_sort_dimensions[] = {
2619	DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
2620	DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
2621	DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
2622	DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
2623	DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
2624	DIM(SORT_IN_TX, "in_tx", sort_in_tx),
2625	DIM(SORT_ABORT, "abort", sort_abort),
2626	DIM(SORT_CYCLES, "cycles", sort_cycles),
2627	DIM(SORT_SRCLINE_FROM, "srcline_from", sort_srcline_from),
2628	DIM(SORT_SRCLINE_TO, "srcline_to", sort_srcline_to),
2629	DIM(SORT_SYM_IPC, "ipc_lbr", sort_sym_ipc),
2630	DIM(SORT_ADDR_FROM, "addr_from", sort_addr_from),
2631	DIM(SORT_ADDR_TO, "addr_to", sort_addr_to),
2632	DIM(SORT_CALLCHAIN_BRANCH_PREDICTED,
2633		"callchain_branch_predicted",
2634		sort_callchain_branch_predicted),
2635	DIM(SORT_CALLCHAIN_BRANCH_ABORT,
2636		"callchain_branch_abort",
2637		sort_callchain_branch_abort),
2638	DIM(SORT_CALLCHAIN_BRANCH_CYCLES,
2639		"callchain_branch_cycles",
2640		sort_callchain_branch_cycles)
2641};
2642
2643#undef DIM
2644
2645#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
2646
2647static struct sort_dimension memory_sort_dimensions[] = {
2648	DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
2649	DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym),
2650	DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
2651	DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
2652	DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
2653	DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
2654	DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
2655	DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
2656	DIM(SORT_MEM_PHYS_DADDR, "phys_daddr", sort_mem_phys_daddr),
2657	DIM(SORT_MEM_DATA_PAGE_SIZE, "data_page_size", sort_mem_data_page_size),
2658	DIM(SORT_MEM_BLOCKED, "blocked", sort_mem_blocked),
2659};
2660
2661#undef DIM
2662
2663struct hpp_dimension {
2664	const char		*name;
2665	struct perf_hpp_fmt	*fmt;
2666	int			taken;
2667	int			was_taken;
2668	int			mem_mode;
2669};
2670
2671#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
2672#define DIM_MEM(d, n) { .name = n, .fmt = &perf_hpp__format[d], .mem_mode = 1, }
2673
2674static struct hpp_dimension hpp_sort_dimensions[] = {
2675	DIM(PERF_HPP__OVERHEAD, "overhead"),
2676	DIM(PERF_HPP__LATENCY, "latency"),
2677	DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
2678	DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
2679	DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
2680	DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
2681	DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
2682	DIM(PERF_HPP__LATENCY_ACC, "latency_children"),
2683	DIM(PERF_HPP__SAMPLES, "sample"),
2684	DIM(PERF_HPP__PERIOD, "period"),
2685	DIM(PERF_HPP__WEIGHT1, "weight1"),
2686	DIM(PERF_HPP__WEIGHT2, "weight2"),
2687	DIM(PERF_HPP__WEIGHT3, "weight3"),
2688	/* aliases for weight_struct */
2689	DIM(PERF_HPP__WEIGHT2, "ins_lat"),
2690	DIM(PERF_HPP__WEIGHT3, "retire_lat"),
2691	DIM(PERF_HPP__WEIGHT3, "p_stage_cyc"),
2692	/* used for output only when SORT_MODE__MEM */
2693	DIM_MEM(PERF_HPP__MEM_STAT_OP, "op"),
2694	DIM_MEM(PERF_HPP__MEM_STAT_CACHE, "cache"),
2695	DIM_MEM(PERF_HPP__MEM_STAT_MEMORY, "memory"),
2696	DIM_MEM(PERF_HPP__MEM_STAT_SNOOP, "snoop"),
2697	DIM_MEM(PERF_HPP__MEM_STAT_DTLB, "dtlb"),
2698};
2699
2700#undef DIM_MEM
2701#undef DIM
2702
2703struct hpp_sort_entry {
2704	struct perf_hpp_fmt hpp;
2705	struct sort_entry *se;
2706};
2707
2708void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
2709{
2710	struct hpp_sort_entry *hse;
2711
2712	if (!perf_hpp__is_sort_entry(fmt))
2713		return;
2714
2715	hse = container_of(fmt, struct hpp_sort_entry, hpp);
2716	hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
2717}
2718
2719static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
2720			      struct hists *hists, int line,
2721			      int *span __maybe_unused)
2722{
2723	struct hpp_sort_entry *hse;
2724	size_t len = fmt->user_len;
2725	const char *hdr = "";
2726
2727	if (line == hists->hpp_list->nr_header_lines - 1)
2728		hdr = fmt->name;
2729
2730	hse = container_of(fmt, struct hpp_sort_entry, hpp);
2731
2732	if (!len)
2733		len = hists__col_len(hists, hse->se->se_width_idx);
2734
2735	return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, hdr);
2736}
2737
2738static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
2739			     struct perf_hpp *hpp __maybe_unused,
2740			     struct hists *hists)
2741{
2742	struct hpp_sort_entry *hse;
2743	size_t len = fmt->user_len;
2744
2745	hse = container_of(fmt, struct hpp_sort_entry, hpp);
2746
2747	if (!len)
2748		len = hists__col_len(hists, hse->se->se_width_idx);
2749
2750	return len;
2751}
2752
2753static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
2754			     struct hist_entry *he)
2755{
2756	struct hpp_sort_entry *hse;
2757	size_t len = fmt->user_len;
2758
2759	hse = container_of(fmt, struct hpp_sort_entry, hpp);
2760
2761	if (!len)
2762		len = hists__col_len(he->hists, hse->se->se_width_idx);
2763
2764	return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
2765}
2766
2767static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
2768			       struct hist_entry *a, struct hist_entry *b)
2769{
2770	struct hpp_sort_entry *hse;
2771
2772	hse = container_of(fmt, struct hpp_sort_entry, hpp);
2773	return hse->se->se_cmp(a, b);
2774}
2775
2776static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
2777				    struct hist_entry *a, struct hist_entry *b)
2778{
2779	struct hpp_sort_entry *hse;
2780	int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
2781
2782	hse = container_of(fmt, struct hpp_sort_entry, hpp);
2783	collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
2784	return collapse_fn(a, b);
2785}
2786
2787static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
2788				struct hist_entry *a, struct hist_entry *b)
2789{
2790	struct hpp_sort_entry *hse;
2791	int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
2792
2793	hse = container_of(fmt, struct hpp_sort_entry, hpp);
2794	sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
2795	return sort_fn(a, b);
2796}
2797
2798bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
2799{
2800	return format->header == __sort__hpp_header;
2801}
2802
2803#define MK_SORT_ENTRY_CHK(key)					\
2804bool perf_hpp__is_ ## key ## _entry(struct perf_hpp_fmt *fmt)	\
2805{								\
2806	struct hpp_sort_entry *hse;				\
2807								\
2808	if (!perf_hpp__is_sort_entry(fmt))			\
2809		return false;					\
2810								\
2811	hse = container_of(fmt, struct hpp_sort_entry, hpp);	\
2812	return hse->se == &sort_ ## key ;			\
2813}
2814
2815#ifdef HAVE_LIBTRACEEVENT
2816MK_SORT_ENTRY_CHK(trace)
2817#else
2818bool perf_hpp__is_trace_entry(struct perf_hpp_fmt *fmt __maybe_unused)
2819{
2820	return false;
2821}
2822#endif
2823MK_SORT_ENTRY_CHK(srcline)
2824MK_SORT_ENTRY_CHK(srcfile)
2825MK_SORT_ENTRY_CHK(thread)
2826MK_SORT_ENTRY_CHK(comm)
2827MK_SORT_ENTRY_CHK(dso)
2828MK_SORT_ENTRY_CHK(sym)
2829MK_SORT_ENTRY_CHK(parallelism)
2830
2831
2832static bool __sort__hpp_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
2833{
2834	struct hpp_sort_entry *hse_a;
2835	struct hpp_sort_entry *hse_b;
2836
2837	if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
2838		return false;
2839
2840	hse_a = container_of(a, struct hpp_sort_entry, hpp);
2841	hse_b = container_of(b, struct hpp_sort_entry, hpp);
2842
2843	return hse_a->se == hse_b->se;
2844}
2845
2846static void hse_free(struct perf_hpp_fmt *fmt)
2847{
2848	struct hpp_sort_entry *hse;
2849
2850	hse = container_of(fmt, struct hpp_sort_entry, hpp);
2851	free(hse);
2852}
2853
2854static void hse_init(struct perf_hpp_fmt *fmt, struct hist_entry *he)
2855{
2856	struct hpp_sort_entry *hse;
2857
2858	if (!perf_hpp__is_sort_entry(fmt))
2859		return;
2860
2861	hse = container_of(fmt, struct hpp_sort_entry, hpp);
2862
2863	if (hse->se->se_init)
2864		hse->se->se_init(he);
2865}
2866
2867static struct hpp_sort_entry *
2868__sort_dimension__alloc_hpp(struct sort_dimension *sd, int level)
2869{
2870	struct hpp_sort_entry *hse;
2871
2872	hse = malloc(sizeof(*hse));
2873	if (hse == NULL) {
2874		pr_err("Memory allocation failed\n");
2875		return NULL;
2876	}
2877
2878	hse->se = sd->entry;
2879	hse->hpp.name = sd->entry->se_header;
2880	hse->hpp.header = __sort__hpp_header;
2881	hse->hpp.width = __sort__hpp_width;
2882	hse->hpp.entry = __sort__hpp_entry;
2883	hse->hpp.color = NULL;
2884
2885	hse->hpp.cmp = __sort__hpp_cmp;
2886	hse->hpp.collapse = __sort__hpp_collapse;
2887	hse->hpp.sort = __sort__hpp_sort;
2888	hse->hpp.equal = __sort__hpp_equal;
2889	hse->hpp.free = hse_free;
2890	hse->hpp.init = hse_init;
2891
2892	INIT_LIST_HEAD(&hse->hpp.list);
2893	INIT_LIST_HEAD(&hse->hpp.sort_list);
2894	hse->hpp.elide = false;
2895	hse->hpp.len = 0;
2896	hse->hpp.user_len = 0;
2897	hse->hpp.level = level;
2898
2899	return hse;
2900}
2901
2902static void hpp_free(struct perf_hpp_fmt *fmt)
2903{
2904	free(fmt);
2905}
2906
2907static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd,
2908						       int level)
2909{
2910	struct perf_hpp_fmt *fmt;
2911
2912	fmt = memdup(hd->fmt, sizeof(*fmt));
2913	if (fmt) {
2914		INIT_LIST_HEAD(&fmt->list);
2915		INIT_LIST_HEAD(&fmt->sort_list);
2916		fmt->free = hpp_free;
2917		fmt->level = level;
2918	}
2919
2920	return fmt;
2921}
2922
2923int hist_entry__filter(struct hist_entry *he, int type, const void *arg)
2924{
2925	struct perf_hpp_fmt *fmt;
2926	struct hpp_sort_entry *hse;
2927	int ret = -1;
2928	int r;
2929
2930	perf_hpp_list__for_each_format(he->hpp_list, fmt) {
2931		if (!perf_hpp__is_sort_entry(fmt))
2932			continue;
2933
2934		hse = container_of(fmt, struct hpp_sort_entry, hpp);
2935		if (hse->se->se_filter == NULL)
2936			continue;
2937
2938		/*
2939		 * hist entry is filtered if any of sort key in the hpp list
2940		 * is applied.  But it should skip non-matched filter types.
2941		 */
2942		r = hse->se->se_filter(he, type, arg);
2943		if (r >= 0) {
2944			if (ret < 0)
2945				ret = 0;
2946			ret |= r;
2947		}
2948	}
2949
2950	return ret;
2951}
2952
2953static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd,
2954					  struct perf_hpp_list *list,
2955					  int level)
2956{
2957	struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, level);
2958
2959	if (hse == NULL)
2960		return -1;
2961
2962	perf_hpp_list__register_sort_field(list, &hse->hpp);
2963	return 0;
2964}
2965
2966static int __sort_dimension__add_hpp_output(struct sort_dimension *sd,
2967					    struct perf_hpp_list *list,
2968					    int level)
2969{
2970	struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, level);
2971
2972	if (hse == NULL)
2973		return -1;
2974
2975	perf_hpp_list__column_register(list, &hse->hpp);
2976	return 0;
2977}
2978
2979#ifndef HAVE_LIBTRACEEVENT
2980bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt __maybe_unused)
2981{
2982	return false;
2983}
2984bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt __maybe_unused,
2985				     struct hists *hists __maybe_unused)
2986{
2987	return false;
2988}
2989#else
2990struct hpp_dynamic_entry {
2991	struct perf_hpp_fmt hpp;
2992	struct evsel *evsel;
2993	struct tep_format_field *field;
2994	unsigned dynamic_len;
2995	bool raw_trace;
2996};
2997
2998static int hde_width(struct hpp_dynamic_entry *hde)
2999{
3000	if (!hde->hpp.len) {
3001		int len = hde->dynamic_len;
3002		int namelen = strlen(hde->field->name);
3003		int fieldlen = hde->field->size;
3004
3005		if (namelen > len)
3006			len = namelen;
3007
3008		if (!(hde->field->flags & TEP_FIELD_IS_STRING)) {
3009			/* length for print hex numbers */
3010			fieldlen = hde->field->size * 2 + 2;
3011		}
3012		if (fieldlen > len)
3013			len = fieldlen;
3014
3015		hde->hpp.len = len;
3016	}
3017	return hde->hpp.len;
3018}
3019
3020static void update_dynamic_len(struct hpp_dynamic_entry *hde,
3021			       struct hist_entry *he)
3022{
3023	char *str, *pos;
3024	struct tep_format_field *field = hde->field;
3025	size_t namelen;
3026	bool last = false;
3027
3028	if (hde->raw_trace)
3029		return;
3030
3031	/* parse pretty print result and update max length */
3032	if (!he->trace_output)
3033		he->trace_output = get_trace_output(he);
3034
3035	namelen = strlen(field->name);
3036	str = he->trace_output;
3037
3038	while (str) {
3039		pos = strchr(str, ' ');
3040		if (pos == NULL) {
3041			last = true;
3042			pos = str + strlen(str);
3043		}
3044
3045		if (!strncmp(str, field->name, namelen)) {
3046			size_t len;
3047
3048			str += namelen + 1;
3049			len = pos - str;
3050
3051			if (len > hde->dynamic_len)
3052				hde->dynamic_len = len;
3053			break;
3054		}
3055
3056		if (last)
3057			str = NULL;
3058		else
3059			str = pos + 1;
3060	}
3061}
3062
3063static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
3064			      struct hists *hists __maybe_unused,
3065			      int line __maybe_unused,
3066			      int *span __maybe_unused)
3067{
3068	struct hpp_dynamic_entry *hde;
3069	size_t len = fmt->user_len;
3070
3071	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
3072
3073	if (!len)
3074		len = hde_width(hde);
3075
3076	return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
3077}
3078
3079static int __sort__hde_width(struct perf_hpp_fmt *fmt,
3080			     struct perf_hpp *hpp __maybe_unused,
3081			     struct hists *hists __maybe_unused)
3082{
3083	struct hpp_dynamic_entry *hde;
3084	size_t len = fmt->user_len;
3085
3086	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
3087
3088	if (!len)
3089		len = hde_width(hde);
3090
3091	return len;
3092}
3093
3094bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
3095{
3096	struct hpp_dynamic_entry *hde;
3097
3098	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
3099
3100	return hists_to_evsel(hists) == hde->evsel;
3101}
3102
3103static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
3104			     struct hist_entry *he)
3105{
3106	struct hpp_dynamic_entry *hde;
3107	size_t len = fmt->user_len;
3108	char *str, *pos;
3109	struct tep_format_field *field;
3110	size_t namelen;
3111	bool last = false;
3112	int ret;
3113
3114	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
3115
3116	if (!len)
3117		len = hde_width(hde);
3118
3119	if (hde->raw_trace)
3120		goto raw_field;
3121
3122	if (!he->trace_output)
3123		he->trace_output = get_trace_output(he);
3124
3125	field = hde->field;
3126	namelen = strlen(field->name);
3127	str = he->trace_output;
3128
3129	while (str) {
3130		pos = strchr(str, ' ');
3131		if (pos == NULL) {
3132			last = true;
3133			pos = str + strlen(str);
3134		}
3135
3136		if (!strncmp(str, field->name, namelen)) {
3137			str += namelen + 1;
3138			str = strndup(str, pos - str);
3139
3140			if (str == NULL)
3141				return scnprintf(hpp->buf, hpp->size,
3142						 "%*.*s", len, len, "ERROR");
3143			break;
3144		}
3145
3146		if (last)
3147			str = NULL;
3148		else
3149			str = pos + 1;
3150	}
3151
3152	if (str == NULL) {
3153		struct trace_seq seq;
3154raw_field:
3155		trace_seq_init(&seq);
3156		tep_print_field(&seq, he->raw_data, hde->field);
3157		str = seq.buffer;
3158	}
3159
3160	ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
3161	free(str);
3162	return ret;
3163}
3164
3165static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
3166			       struct hist_entry *a, struct hist_entry *b)
3167{
3168	struct hpp_dynamic_entry *hde;
3169	struct tep_format_field *field;
3170	unsigned offset, size;
3171
3172	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
3173
3174	field = hde->field;
3175	if (field->flags & TEP_FIELD_IS_DYNAMIC) {
3176		unsigned long long dyn;
3177
3178		tep_read_number_field(field, a->raw_data, &dyn);
3179		offset = dyn & 0xffff;
3180		size = (dyn >> 16) & 0xffff;
3181		if (tep_field_is_relative(field->flags))
3182			offset += field->offset + field->size;
3183		/* record max width for output */
3184		if (size > hde->dynamic_len)
3185			hde->dynamic_len = size;
3186	} else {
3187		offset = field->offset;
3188		size = field->size;
3189	}
3190
3191	return memcmp(a->raw_data + offset, b->raw_data + offset, size);
3192}
3193
3194bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
3195{
3196	return fmt->cmp == __sort__hde_cmp;
3197}
3198
3199static bool __sort__hde_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
3200{
3201	struct hpp_dynamic_entry *hde_a;
3202	struct hpp_dynamic_entry *hde_b;
3203
3204	if (!perf_hpp__is_dynamic_entry(a) || !perf_hpp__is_dynamic_entry(b))
3205		return false;
3206
3207	hde_a = container_of(a, struct hpp_dynamic_entry, hpp);
3208	hde_b = container_of(b, struct hpp_dynamic_entry, hpp);
3209
3210	return hde_a->field == hde_b->field;
3211}
3212
3213static void hde_free(struct perf_hpp_fmt *fmt)
3214{
3215	struct hpp_dynamic_entry *hde;
3216
3217	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
3218	free(hde);
3219}
3220
3221static void __sort__hde_init(struct perf_hpp_fmt *fmt, struct hist_entry *he)
3222{
3223	struct hpp_dynamic_entry *hde;
3224
3225	if (!perf_hpp__is_dynamic_entry(fmt))
3226		return;
3227
3228	hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
3229	update_dynamic_len(hde, he);
3230}
3231
3232static struct hpp_dynamic_entry *
3233__alloc_dynamic_entry(struct evsel *evsel, struct tep_format_field *field,
3234		      int level)
3235{
3236	struct hpp_dynamic_entry *hde;
3237
3238	hde = malloc(sizeof(*hde));
3239	if (hde == NULL) {
3240		pr_debug("Memory allocation failed\n");
3241		return NULL;
3242	}
3243
3244	hde->evsel = evsel;
3245	hde->field = field;
3246	hde->dynamic_len = 0;
3247
3248	hde->hpp.name = field->name;
3249	hde->hpp.header = __sort__hde_header;
3250	hde->hpp.width  = __sort__hde_width;
3251	hde->hpp.entry  = __sort__hde_entry;
3252	hde->hpp.color  = NULL;
3253
3254	hde->hpp.init = __sort__hde_init;
3255	hde->hpp.cmp = __sort__hde_cmp;
3256	hde->hpp.collapse = __sort__hde_cmp;
3257	hde->hpp.sort = __sort__hde_cmp;
3258	hde->hpp.equal = __sort__hde_equal;
3259	hde->hpp.free = hde_free;
3260
3261	INIT_LIST_HEAD(&hde->hpp.list);
3262	INIT_LIST_HEAD(&hde->hpp.sort_list);
3263	hde->hpp.elide = false;
3264	hde->hpp.len = 0;
3265	hde->hpp.user_len = 0;
3266	hde->hpp.level = level;
3267
3268	return hde;
3269}
3270#endif /* HAVE_LIBTRACEEVENT */
3271
3272struct perf_hpp_fmt *perf_hpp_fmt__dup(struct perf_hpp_fmt *fmt)
3273{
3274	struct perf_hpp_fmt *new_fmt = NULL;
3275
3276	if (perf_hpp__is_sort_entry(fmt)) {
3277		struct hpp_sort_entry *hse, *new_hse;
3278
3279		hse = container_of(fmt, struct hpp_sort_entry, hpp);
3280		new_hse = memdup(hse, sizeof(*hse));
3281		if (new_hse)
3282			new_fmt = &new_hse->hpp;
3283#ifdef HAVE_LIBTRACEEVENT
3284	} else if (perf_hpp__is_dynamic_entry(fmt)) {
3285		struct hpp_dynamic_entry *hde, *new_hde;
3286
3287		hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
3288		new_hde = memdup(hde, sizeof(*hde));
3289		if (new_hde)
3290			new_fmt = &new_hde->hpp;
3291#endif
3292	} else {
3293		new_fmt = memdup(fmt, sizeof(*fmt));
3294	}
3295
3296	INIT_LIST_HEAD(&new_fmt->list);
3297	INIT_LIST_HEAD(&new_fmt->sort_list);
3298
3299	return new_fmt;
3300}
3301
3302static int parse_field_name(char *str, char **event, char **field, char **opt)
3303{
3304	char *event_name, *field_name, *opt_name;
3305
3306	event_name = str;
3307	field_name = strchr(str, '.');
3308
3309	if (field_name) {
3310		*field_name++ = '\0';
3311	} else {
3312		event_name = NULL;
3313		field_name = str;
3314	}
3315
3316	opt_name = strchr(field_name, '/');
3317	if (opt_name)
3318		*opt_name++ = '\0';
3319
3320	*event = event_name;
3321	*field = field_name;
3322	*opt   = opt_name;
3323
3324	return 0;
3325}
3326
3327/* find match evsel using a given event name.  The event name can be:
3328 *   1. '%' + event index (e.g. '%1' for first event)
3329 *   2. full event name (e.g. sched:sched_switch)
3330 *   3. partial event name (should not contain ':')
3331 */
3332static struct evsel *find_evsel(struct evlist *evlist, char *event_name)
3333{
3334	struct evsel *evsel = NULL;
3335	struct evsel *pos;
3336	bool full_name;
3337
3338	/* case 1 */
3339	if (event_name[0] == '%') {
3340		int nr = strtol(event_name+1, NULL, 0);
3341
3342		if (nr > evlist->core.nr_entries)
3343			return NULL;
3344
3345		evsel = evlist__first(evlist);
3346		while (--nr > 0)
3347			evsel = evsel__next(evsel);
3348
3349		return evsel;
3350	}
3351
3352	full_name = !!strchr(event_name, ':');
3353	evlist__for_each_entry(evlist, pos) {
3354		/* case 2 */
3355		if (full_name && evsel__name_is(pos, event_name))
3356			return pos;
3357		/* case 3 */
3358		if (!full_name && strstr(pos->name, event_name)) {
3359			if (evsel) {
3360				pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
3361					 event_name, evsel->name, pos->name);
3362				return NULL;
3363			}
3364			evsel = pos;
3365		}
3366	}
3367
3368	return evsel;
3369}
3370
3371#ifdef HAVE_LIBTRACEEVENT
3372static int __dynamic_dimension__add(struct evsel *evsel,
3373				    struct tep_format_field *field,
3374				    bool raw_trace, int level)
3375{
3376	struct hpp_dynamic_entry *hde;
3377
3378	hde = __alloc_dynamic_entry(evsel, field, level);
3379	if (hde == NULL)
3380		return -ENOMEM;
3381
3382	hde->raw_trace = raw_trace;
3383
3384	perf_hpp__register_sort_field(&hde->hpp);
3385	return 0;
3386}
3387
3388static int add_evsel_fields(struct evsel *evsel, bool raw_trace, int level)
3389{
3390	int ret;
3391	struct tep_event *tp_format = evsel__tp_format(evsel);
3392	struct tep_format_field *field = tp_format ? tp_format->format.fields : NULL;
3393	while (field) {
3394		ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
3395		if (ret < 0)
3396			return ret;
3397
3398		field = field->next;
3399	}
3400	return 0;
3401}
3402
3403static int add_all_dynamic_fields(struct evlist *evlist, bool raw_trace,
3404				  int level)
3405{
3406	int ret;
3407	struct evsel *evsel;
3408
3409	evlist__for_each_entry(evlist, evsel) {
3410		if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
3411			continue;
3412
3413		ret = add_evsel_fields(evsel, raw_trace, level);
3414		if (ret < 0)
3415			return ret;
3416	}
3417	return 0;
3418}
3419
3420static int add_all_matching_fields(struct evlist *evlist,
3421				   char *field_name, bool raw_trace, int level)
3422{
3423	int ret = -ESRCH;
3424	struct evsel *evsel;
3425
3426	evlist__for_each_entry(evlist, evsel) {
3427		struct tep_event *tp_format;
3428		struct tep_format_field *field;
3429
3430		if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
3431			continue;
3432
3433		tp_format = evsel__tp_format(evsel);
3434		if (tp_format == NULL)
3435			continue;
3436
3437		field = tep_find_any_field(tp_format, field_name);
3438		if (field == NULL)
3439			continue;
3440
3441		ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
3442		if (ret < 0)
3443			break;
3444	}
3445	return ret;
3446}
3447#endif /* HAVE_LIBTRACEEVENT */
3448
3449static int add_dynamic_entry(struct evlist *evlist, const char *tok,
3450			     int level)
3451{
3452	char *str, *event_name, *field_name, *opt_name;
3453	struct evsel *evsel;
3454	bool raw_trace = symbol_conf.raw_trace;
3455	int ret = 0;
3456
3457	if (evlist == NULL)
3458		return -ENOENT;
3459
3460	str = strdup(tok);
3461	if (str == NULL)
3462		return -ENOMEM;
3463
3464	if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
3465		ret = -EINVAL;
3466		goto out;
3467	}
3468
3469	if (opt_name) {
3470		if (strcmp(opt_name, "raw")) {
3471			pr_debug("unsupported field option %s\n", opt_name);
3472			ret = -EINVAL;
3473			goto out;
3474		}
3475		raw_trace = true;
3476	}
3477
3478#ifdef HAVE_LIBTRACEEVENT
3479	if (!strcmp(field_name, "trace_fields")) {
3480		ret = add_all_dynamic_fields(evlist, raw_trace, level);
3481		goto out;
3482	}
3483
3484	if (event_name == NULL) {
3485		ret = add_all_matching_fields(evlist, field_name, raw_trace, level);
3486		goto out;
3487	}
3488#else
3489	evlist__for_each_entry(evlist, evsel) {
3490		if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) {
3491			pr_err("%s %s", ret ? "," : "This perf binary isn't linked with libtraceevent, can't process", evsel__name(evsel));
3492			ret = -ENOTSUP;
3493		}
3494	}
3495
3496	if (ret) {
3497		pr_err("\n");
3498		goto out;
3499	}
3500#endif
3501
3502	evsel = find_evsel(evlist, event_name);
3503	if (evsel == NULL) {
3504		pr_debug("Cannot find event: %s\n", event_name);
3505		ret = -ENOENT;
3506		goto out;
3507	}
3508
3509	if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) {
3510		pr_debug("%s is not a tracepoint event\n", event_name);
3511		ret = -EINVAL;
3512		goto out;
3513	}
3514
3515#ifdef HAVE_LIBTRACEEVENT
3516	if (!strcmp(field_name, "*")) {
3517		ret = add_evsel_fields(evsel, raw_trace, level);
3518	} else {
3519		struct tep_event *tp_format = evsel__tp_format(evsel);
3520		struct tep_format_field *field =
3521			tp_format ? tep_find_any_field(tp_format, field_name) : NULL;
3522
3523		if (field == NULL) {
3524			pr_debug("Cannot find event field for %s.%s\n",
3525				 event_name, field_name);
3526			return -ENOENT;
3527		}
3528
3529		ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
3530	}
3531#else
3532	(void)level;
3533	(void)raw_trace;
3534#endif /* HAVE_LIBTRACEEVENT */
3535
3536out:
3537	free(str);
3538	return ret;
3539}
3540
3541static int __sort_dimension__add(struct sort_dimension *sd,
3542				 struct perf_hpp_list *list,
3543				 int level)
3544{
3545	if (sd->taken)
3546		return 0;
3547
3548	if (__sort_dimension__add_hpp_sort(sd, list, level) < 0)
3549		return -1;
3550
3551	if (sd->entry->se_collapse)
3552		list->need_collapse = 1;
3553
3554	sd->taken = 1;
3555
3556	return 0;
3557}
3558
3559static int __hpp_dimension__add(struct hpp_dimension *hd,
3560				struct perf_hpp_list *list,
3561				int level)
3562{
3563	struct perf_hpp_fmt *fmt;
3564
3565	if (hd->taken)
3566		return 0;
3567
3568	fmt = __hpp_dimension__alloc_hpp(hd, level);
3569	if (!fmt)
3570		return -1;
3571
3572	hd->taken = 1;
3573	hd->was_taken = 1;
3574	perf_hpp_list__register_sort_field(list, fmt);
3575	return 0;
3576}
3577
3578static int __sort_dimension__add_output(struct perf_hpp_list *list,
3579					struct sort_dimension *sd,
3580					int level)
3581{
3582	if (sd->taken)
3583		return 0;
3584
3585	if (__sort_dimension__add_hpp_output(sd, list, level) < 0)
3586		return -1;
3587
3588	sd->taken = 1;
3589	return 0;
3590}
3591
3592static int __hpp_dimension__add_output(struct perf_hpp_list *list,
3593				       struct hpp_dimension *hd,
3594				       int level)
3595{
3596	struct perf_hpp_fmt *fmt;
3597
3598	if (hd->taken)
3599		return 0;
3600
3601	fmt = __hpp_dimension__alloc_hpp(hd, level);
3602	if (!fmt)
3603		return -1;
3604
3605	hd->taken = 1;
3606	perf_hpp_list__column_register(list, fmt);
3607	return 0;
3608}
3609
3610int hpp_dimension__add_output(unsigned col, bool implicit)
3611{
3612	struct hpp_dimension *hd;
3613
3614	BUG_ON(col >= PERF_HPP__MAX_INDEX);
3615	hd = &hpp_sort_dimensions[col];
3616	if (implicit && !hd->was_taken)
3617		return 0;
3618	return __hpp_dimension__add_output(&perf_hpp_list, hd, /*level=*/0);
3619}
3620
3621int sort_dimension__add(struct perf_hpp_list *list, const char *tok,
3622			struct evlist *evlist, struct perf_env *env,
3623			int level)
3624{
3625	unsigned int i, j;
3626
3627	/*
3628	 * Check to see if there are any arch specific
3629	 * sort dimensions not applicable for the current
3630	 * architecture. If so, Skip that sort key since
3631	 * we don't want to display it in the output fields.
3632	 */
3633	for (j = 0; j < ARRAY_SIZE(arch_specific_sort_keys); j++) {
3634		if (!strcmp(arch_specific_sort_keys[j], tok) &&
3635		    !arch_support_sort_key(tok, env)) {
3636			return 0;
3637		}
3638	}
3639
3640	for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
3641		struct sort_dimension *sd = &common_sort_dimensions[i];
3642
3643		if (!sd->name || strncasecmp(tok, sd->name, strlen(tok)))
3644			continue;
3645
3646		for (j = 0; j < ARRAY_SIZE(dynamic_headers); j++) {
3647			if (sd->name && !strcmp(dynamic_headers[j], sd->name))
3648				sort_dimension_add_dynamic_header(sd, env);
3649		}
3650
3651		if (sd->entry == &sort_parent && parent_pattern) {
3652			int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
3653			if (ret) {
3654				char err[BUFSIZ];
3655
3656				regerror(ret, &parent_regex, err, sizeof(err));
3657				pr_err("Invalid regex: %s\n%s", parent_pattern, err);
3658				return -EINVAL;
3659			}
3660			list->parent = 1;
3661		} else if (sd->entry == &sort_sym) {
3662			list->sym = 1;
3663			/*
3664			 * perf diff displays the performance difference amongst
3665			 * two or more perf.data files. Those files could come
3666			 * from different binaries. So we should not compare
3667			 * their ips, but the name of symbol.
3668			 */
3669			if (sort__mode == SORT_MODE__DIFF)
3670				sd->entry->se_collapse = sort__sym_sort;
3671
3672		} else if (sd->entry == &sort_dso) {
3673			list->dso = 1;
3674		} else if (sd->entry == &sort_socket) {
3675			list->socket = 1;
3676		} else if (sd->entry == &sort_thread) {
3677			list->thread = 1;
3678		} else if (sd->entry == &sort_comm) {
3679			list->comm = 1;
3680		} else if (sd->entry == &sort_type_offset) {
3681			symbol_conf.annotate_data_member = true;
3682		}
3683
3684		return __sort_dimension__add(sd, list, level);
3685	}
3686
3687	for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
3688		struct sort_dimension *sd = &bstack_sort_dimensions[i];
3689
3690		if (!sd->name || strncasecmp(tok, sd->name, strlen(tok)))
3691			continue;
3692
3693		if ((sort__mode != SORT_MODE__BRANCH) &&
3694			strncasecmp(tok, "callchain_branch_predicted",
3695				    strlen(tok)) &&
3696			strncasecmp(tok, "callchain_branch_abort",
3697				    strlen(tok)) &&
3698			strncasecmp(tok, "callchain_branch_cycles",
3699				    strlen(tok)))
3700			return -EINVAL;
3701
3702		if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
3703			list->sym = 1;
3704
3705		__sort_dimension__add(sd, list, level);
3706		return 0;
3707	}
3708
3709	for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
3710		struct sort_dimension *sd = &memory_sort_dimensions[i];
3711
3712		if (!sd->name || strncasecmp(tok, sd->name, strlen(tok)))
3713			continue;
3714
3715		if (sort__mode != SORT_MODE__MEMORY)
3716			return -EINVAL;
3717
3718		if (sd->entry == &sort_mem_dcacheline && cacheline_size() == 0)
3719			return -EINVAL;
3720
3721		if (sd->entry == &sort_mem_daddr_sym)
3722			list->sym = 1;
3723
3724		__sort_dimension__add(sd, list, level);
3725		return 0;
3726	}
3727
3728	for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
3729		struct hpp_dimension *hd = &hpp_sort_dimensions[i];
3730
3731		if (strncasecmp(tok, hd->name, strlen(tok)))
3732			continue;
3733
3734		return __hpp_dimension__add(hd, list, level);
3735	}
3736
3737	if (!add_dynamic_entry(evlist, tok, level))
3738		return 0;
3739
3740	return -ESRCH;
3741}
3742
3743/* This should match with sort_dimension__add() above */
3744static bool is_hpp_sort_key(const char *key, struct perf_env *env)
3745{
3746	unsigned i;
3747
3748	for (i = 0; i < ARRAY_SIZE(arch_specific_sort_keys); i++) {
3749		if (!strcmp(arch_specific_sort_keys[i], key) &&
3750		    !arch_support_sort_key(key, env)) {
3751			return false;
3752		}
3753	}
3754
3755	for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
3756		struct sort_dimension *sd = &common_sort_dimensions[i];
3757
3758		if (sd->name && !strncasecmp(key, sd->name, strlen(key)))
3759			return false;
3760	}
3761
3762	for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
3763		struct hpp_dimension *hd = &hpp_sort_dimensions[i];
3764
3765		if (!strncasecmp(key, hd->name, strlen(key)))
3766			return true;
3767	}
3768	return false;
3769}
3770
3771static int setup_sort_list(struct perf_hpp_list *list, char *str,
3772			   struct evlist *evlist, struct perf_env *env)
3773{
3774	char *tmp, *tok;
3775	int ret = 0;
3776	int level = 0;
3777	int next_level = 1;
3778	int prev_level = 0;
3779	bool in_group = false;
3780	bool prev_was_hpp = false;
3781
3782	do {
3783		tok = str;
3784		tmp = strpbrk(str, "{}, ");
3785		if (tmp) {
3786			if (in_group)
3787				next_level = level;
3788			else
3789				next_level = level + 1;
3790
3791			if (*tmp == '{')
3792				in_group = true;
3793			else if (*tmp == '}')
3794				in_group = false;
3795
3796			*tmp = '\0';
3797			str = tmp + 1;
3798		}
3799
3800		if (*tok) {
3801			if (is_hpp_sort_key(tok, env)) {
3802				/* keep output (hpp) sort keys in the same level */
3803				if (prev_was_hpp) {
3804					bool next_same = (level == next_level);
3805
3806					level = prev_level;
3807					next_level = next_same ? level : level+1;
3808				}
3809				prev_was_hpp = true;
3810			} else {
3811				prev_was_hpp = false;
3812			}
3813
3814			ret = sort_dimension__add(list, tok, evlist, env, level);
3815			if (ret == -EINVAL) {
3816				if (!cacheline_size() && !strncasecmp(tok, "dcacheline", strlen(tok)))
3817					ui__error("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system");
3818				else
3819					ui__error("Invalid --sort key: `%s'", tok);
3820				break;
3821			} else if (ret == -ESRCH) {
3822				ui__error("Unknown --sort key: `%s'", tok);
3823				break;
3824			}
3825			prev_level = level;
3826		}
3827
3828		level = next_level;
3829	} while (tmp);
3830
3831	return ret;
3832}
3833
3834static const char *get_default_sort_order(struct evlist *evlist)
3835{
3836	const char *default_sort_orders[] = {
3837		default_sort_order,
3838		default_branch_sort_order,
3839		default_mem_sort_order,
3840		default_top_sort_order,
3841		default_diff_sort_order,
3842		default_tracepoint_sort_order,
3843	};
3844	bool use_trace = true;
3845	struct evsel *evsel;
3846
3847	BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
3848
3849	if (evlist == NULL || evlist__empty(evlist))
3850		goto out_no_evlist;
3851
3852	evlist__for_each_entry(evlist, evsel) {
3853		if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) {
3854			use_trace = false;
3855			break;
3856		}
3857	}
3858
3859	if (use_trace) {
3860		sort__mode = SORT_MODE__TRACEPOINT;
3861		if (symbol_conf.raw_trace)
3862			return "trace_fields";
3863	}
3864out_no_evlist:
3865	return default_sort_orders[sort__mode];
3866}
3867
3868static int setup_sort_order(struct evlist *evlist)
3869{
3870	char *new_sort_order;
3871
3872	/*
3873	 * Append '+'-prefixed sort order to the default sort
3874	 * order string.
3875	 */
3876	if (!sort_order || is_strict_order(sort_order))
3877		return 0;
3878
3879	if (sort_order[1] == '\0') {
3880		ui__error("Invalid --sort key: `+'");
3881		return -EINVAL;
3882	}
3883
3884	/*
3885	 * We allocate new sort_order string, but we never free it,
3886	 * because it's checked over the rest of the code.
3887	 */
3888	if (asprintf(&new_sort_order, "%s,%s",
3889		     get_default_sort_order(evlist), sort_order + 1) < 0) {
3890		pr_err("Not enough memory to set up --sort");
3891		return -ENOMEM;
3892	}
3893
3894	sort_order = new_sort_order;
3895	return 0;
3896}
3897
3898/*
3899 * Adds 'pre,' prefix into 'str' is 'pre' is
3900 * not already part of 'str'.
3901 */
3902static char *prefix_if_not_in(const char *pre, char *str)
3903{
3904	char *n;
3905
3906	if (!str || strstr(str, pre))
3907		return str;
3908
3909	if (asprintf(&n, "%s,%s", pre, str) < 0)
3910		n = NULL;
3911
3912	free(str);
3913	return n;
3914}
3915
3916static char *setup_overhead(char *keys)
3917{
3918	if (sort__mode == SORT_MODE__DIFF)
3919		return keys;
3920
3921	if (symbol_conf.prefer_latency) {
3922		keys = prefix_if_not_in("overhead", keys);
3923		keys = prefix_if_not_in("latency", keys);
3924		if (symbol_conf.cumulate_callchain) {
3925			keys = prefix_if_not_in("overhead_children", keys);
3926			keys = prefix_if_not_in("latency_children", keys);
3927		}
3928	} else if (!keys || (!strstr(keys, "overhead") &&
3929			!strstr(keys, "latency"))) {
3930		if (symbol_conf.enable_latency)
3931			keys = prefix_if_not_in("latency", keys);
3932		keys = prefix_if_not_in("overhead", keys);
3933		if (symbol_conf.cumulate_callchain) {
3934			if (symbol_conf.enable_latency)
3935				keys = prefix_if_not_in("latency_children", keys);
3936			keys = prefix_if_not_in("overhead_children", keys);
3937		}
3938	}
3939
3940	return keys;
3941}
3942
3943static int __setup_sorting(struct evlist *evlist, struct perf_env *env)
3944{
3945	char *str;
3946	const char *sort_keys;
3947	int ret = 0;
3948
3949	ret = setup_sort_order(evlist);
3950	if (ret)
3951		return ret;
3952
3953	sort_keys = sort_order;
3954	if (sort_keys == NULL) {
3955		if (is_strict_order(field_order)) {
3956			/*
3957			 * If user specified field order but no sort order,
3958			 * we'll honor it and not add default sort orders.
3959			 */
3960			return 0;
3961		}
3962
3963		sort_keys = get_default_sort_order(evlist);
3964	}
3965
3966	str = strdup(sort_keys);
3967	if (str == NULL) {
3968		pr_err("Not enough memory to setup sort keys");
3969		return -ENOMEM;
3970	}
3971
3972	/*
3973	 * Prepend overhead fields for backward compatibility.
3974	 */
3975	if (!is_strict_order(field_order)) {
3976		str = setup_overhead(str);
3977		if (str == NULL) {
3978			pr_err("Not enough memory to setup overhead keys");
3979			return -ENOMEM;
3980		}
3981	}
3982
3983	ret = setup_sort_list(&perf_hpp_list, str, evlist, env);
3984
3985	free(str);
3986	return ret;
3987}
3988
3989void perf_hpp__set_elide(int idx, bool elide)
3990{
3991	struct perf_hpp_fmt *fmt;
3992	struct hpp_sort_entry *hse;
3993
3994	perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
3995		if (!perf_hpp__is_sort_entry(fmt))
3996			continue;
3997
3998		hse = container_of(fmt, struct hpp_sort_entry, hpp);
3999		if (hse->se->se_width_idx == idx) {
4000			fmt->elide = elide;
4001			break;
4002		}
4003	}
4004}
4005
4006static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
4007{
4008	if (list && strlist__nr_entries(list) == 1) {
4009		if (fp != NULL)
4010			fprintf(fp, "# %s: %s\n", list_name,
4011				strlist__entry(list, 0)->s);
4012		return true;
4013	}
4014	return false;
4015}
4016
4017static bool get_elide(int idx, FILE *output)
4018{
4019	switch (idx) {
4020	case HISTC_SYMBOL:
4021		return __get_elide(symbol_conf.sym_list, "symbol", output);
4022	case HISTC_DSO:
4023		return __get_elide(symbol_conf.dso_list, "dso", output);
4024	case HISTC_COMM:
4025		return __get_elide(symbol_conf.comm_list, "comm", output);
4026	default:
4027		break;
4028	}
4029
4030	if (sort__mode != SORT_MODE__BRANCH)
4031		return false;
4032
4033	switch (idx) {
4034	case HISTC_SYMBOL_FROM:
4035		return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
4036	case HISTC_SYMBOL_TO:
4037		return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
4038	case HISTC_DSO_FROM:
4039		return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
4040	case HISTC_DSO_TO:
4041		return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
4042	case HISTC_ADDR_FROM:
4043		return __get_elide(symbol_conf.sym_from_list, "addr_from", output);
4044	case HISTC_ADDR_TO:
4045		return __get_elide(symbol_conf.sym_to_list, "addr_to", output);
4046	default:
4047		break;
4048	}
4049
4050	return false;
4051}
4052
4053void sort__setup_elide(FILE *output)
4054{
4055	struct perf_hpp_fmt *fmt;
4056	struct hpp_sort_entry *hse;
4057
4058	perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
4059		if (!perf_hpp__is_sort_entry(fmt))
4060			continue;
4061
4062		hse = container_of(fmt, struct hpp_sort_entry, hpp);
4063		fmt->elide = get_elide(hse->se->se_width_idx, output);
4064	}
4065
4066	/*
4067	 * It makes no sense to elide all of sort entries.
4068	 * Just revert them to show up again.
4069	 */
4070	perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
4071		if (!perf_hpp__is_sort_entry(fmt))
4072			continue;
4073
4074		if (!fmt->elide)
4075			return;
4076	}
4077
4078	perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
4079		if (!perf_hpp__is_sort_entry(fmt))
4080			continue;
4081
4082		fmt->elide = false;
4083	}
4084}
4085
4086int output_field_add(struct perf_hpp_list *list, const char *tok, int *level)
4087{
4088	unsigned int i;
4089
4090	for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
4091		struct hpp_dimension *hd = &hpp_sort_dimensions[i];
4092
4093		if (strncasecmp(tok, hd->name, strlen(tok)))
4094			continue;
4095
4096		if (!strcasecmp(tok, "weight"))
4097			ui__warning("--fields weight shows the average value unlike in the --sort key.\n");
4098
4099		if (hd->mem_mode && sort__mode != SORT_MODE__MEMORY)
4100			continue;
4101
4102		return __hpp_dimension__add_output(list, hd, *level);
4103	}
4104
4105	/*
4106	 * A non-output field will increase level so that it can be in a
4107	 * different hierarchy.
4108	 */
4109	(*level)++;
4110
4111	for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
4112		struct sort_dimension *sd = &common_sort_dimensions[i];
4113
4114		if (!sd->name || strncasecmp(tok, sd->name, strlen(tok)))
4115			continue;
4116
4117		return __sort_dimension__add_output(list, sd, *level);
4118	}
4119
4120	for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
4121		struct sort_dimension *sd = &bstack_sort_dimensions[i];
4122
4123		if (!sd->name || strncasecmp(tok, sd->name, strlen(tok)))
4124			continue;
4125
4126		if (sort__mode != SORT_MODE__BRANCH)
4127			return -EINVAL;
4128
4129		return __sort_dimension__add_output(list, sd, *level);
4130	}
4131
4132	for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
4133		struct sort_dimension *sd = &memory_sort_dimensions[i];
4134
4135		if (!sd->name || strncasecmp(tok, sd->name, strlen(tok)))
4136			continue;
4137
4138		if (sort__mode != SORT_MODE__MEMORY)
4139			return -EINVAL;
4140
4141		return __sort_dimension__add_output(list, sd, *level);
4142	}
4143
4144	return -ESRCH;
4145}
4146
4147static int setup_output_list(struct perf_hpp_list *list, char *str)
4148{
4149	char *tmp, *tok;
4150	int ret = 0;
4151	int level = 0;
4152
4153	for (tok = strtok_r(str, ", ", &tmp);
4154			tok; tok = strtok_r(NULL, ", ", &tmp)) {
4155		ret = output_field_add(list, tok, &level);
4156		if (ret == -EINVAL) {
4157			ui__error("Invalid --fields key: `%s'", tok);
4158			break;
4159		} else if (ret == -ESRCH) {
4160			ui__error("Unknown --fields key: `%s'", tok);
4161			break;
4162		}
4163	}
4164
4165	return ret;
4166}
4167
4168void reset_dimensions(void)
4169{
4170	unsigned int i;
4171
4172	for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
4173		common_sort_dimensions[i].taken = 0;
4174
4175	for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
4176		hpp_sort_dimensions[i].taken = 0;
4177
4178	for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
4179		bstack_sort_dimensions[i].taken = 0;
4180
4181	for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
4182		memory_sort_dimensions[i].taken = 0;
4183}
4184
4185bool is_strict_order(const char *order)
4186{
4187	return order && (*order != '+');
4188}
4189
4190static int __setup_output_field(void)
4191{
4192	char *str, *strp;
4193	int ret = -EINVAL;
4194
4195	if (field_order == NULL)
4196		return 0;
4197
4198	strp = str = strdup(field_order);
4199	if (str == NULL) {
4200		pr_err("Not enough memory to setup output fields");
4201		return -ENOMEM;
4202	}
4203
4204	if (!is_strict_order(field_order))
4205		strp++;
4206
4207	if (!strlen(strp)) {
4208		ui__error("Invalid --fields key: `+'");
4209		goto out;
4210	}
4211
4212	ret = setup_output_list(&perf_hpp_list, strp);
4213
4214out:
4215	free(str);
4216	return ret;
4217}
4218
4219int setup_sorting(struct evlist *evlist, struct perf_env *env)
4220{
4221	int err;
4222
4223	err = __setup_sorting(evlist, env);
4224	if (err < 0)
4225		return err;
4226
4227	if (parent_pattern != default_parent_pattern) {
4228		err = sort_dimension__add(&perf_hpp_list, "parent", evlist, env, -1);
4229		if (err < 0)
4230			return err;
4231	}
4232
4233	reset_dimensions();
4234
4235	/*
4236	 * perf diff doesn't use default hpp output fields.
4237	 */
4238	if (sort__mode != SORT_MODE__DIFF)
4239		perf_hpp__init();
4240
4241	err = __setup_output_field();
4242	if (err < 0)
4243		return err;
4244
4245	err = perf_hpp__alloc_mem_stats(&perf_hpp_list, evlist);
4246	if (err < 0)
4247		return err;
4248
4249	/* copy sort keys to output fields */
4250	perf_hpp__setup_output_field(&perf_hpp_list);
4251	/* and then copy output fields to sort keys */
4252	perf_hpp__append_sort_keys(&perf_hpp_list);
4253
4254	/* setup hists-specific output fields */
4255	if (perf_hpp__setup_hists_formats(&perf_hpp_list, evlist) < 0)
4256		return -1;
4257
4258	return 0;
4259}
4260
4261void reset_output_field(void)
4262{
4263	perf_hpp_list.need_collapse = 0;
4264	perf_hpp_list.parent = 0;
4265	perf_hpp_list.sym = 0;
4266	perf_hpp_list.dso = 0;
4267
4268	field_order = NULL;
4269	sort_order = NULL;
4270
4271	reset_dimensions();
4272	perf_hpp__reset_output_field(&perf_hpp_list);
4273}
4274
4275#define INDENT (3*8 + 1)
4276
4277static void add_key(struct strbuf *sb, const char *str, int *llen)
4278{
4279	if (!str)
4280		return;
4281
4282	if (*llen >= 75) {
4283		strbuf_addstr(sb, "\n\t\t\t ");
4284		*llen = INDENT;
4285	}
4286	strbuf_addf(sb, " %s", str);
4287	*llen += strlen(str) + 1;
4288}
4289
4290static void add_sort_string(struct strbuf *sb, struct sort_dimension *s, int n,
4291			    int *llen)
4292{
4293	int i;
4294
4295	for (i = 0; i < n; i++)
4296		add_key(sb, s[i].name, llen);
4297}
4298
4299static void add_hpp_sort_string(struct strbuf *sb, struct hpp_dimension *s, int n,
4300				int *llen)
4301{
4302	int i;
4303
4304	for (i = 0; i < n; i++)
4305		add_key(sb, s[i].name, llen);
4306}
4307
4308char *sort_help(const char *prefix, enum sort_mode mode)
4309{
4310	struct strbuf sb;
4311	char *s;
4312	int len = strlen(prefix) + INDENT;
4313
4314	strbuf_init(&sb, 300);
4315	strbuf_addstr(&sb, prefix);
4316	add_hpp_sort_string(&sb, hpp_sort_dimensions,
4317			    ARRAY_SIZE(hpp_sort_dimensions), &len);
4318	add_sort_string(&sb, common_sort_dimensions,
4319			    ARRAY_SIZE(common_sort_dimensions), &len);
4320	if (mode == SORT_MODE__NORMAL || mode == SORT_MODE__BRANCH)
4321		add_sort_string(&sb, bstack_sort_dimensions,
4322				ARRAY_SIZE(bstack_sort_dimensions), &len);
4323	if (mode == SORT_MODE__NORMAL || mode == SORT_MODE__MEMORY)
4324		add_sort_string(&sb, memory_sort_dimensions,
4325				ARRAY_SIZE(memory_sort_dimensions), &len);
4326	s = strbuf_detach(&sb, NULL);
4327	strbuf_release(&sb);
4328	return s;
4329}
~/ Read-only file preview.