xref: /openbmc/linux/tools/perf/util/sort.c (revision d3597236)
1 #include <sys/mman.h>
2 #include "sort.h"
3 #include "hist.h"
4 #include "comm.h"
5 #include "symbol.h"
6 #include "evsel.h"
7 
8 regex_t		parent_regex;
9 const char	default_parent_pattern[] = "^sys_|^do_page_fault";
10 const char	*parent_pattern = default_parent_pattern;
11 const char	default_sort_order[] = "comm,dso,symbol";
12 const char	default_branch_sort_order[] = "comm,dso_from,symbol_from,dso_to,symbol_to";
13 const char	default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
14 const char	default_top_sort_order[] = "dso,symbol";
15 const char	default_diff_sort_order[] = "dso,symbol";
16 const char	*sort_order;
17 const char	*field_order;
18 regex_t		ignore_callees_regex;
19 int		have_ignore_callees = 0;
20 int		sort__need_collapse = 0;
21 int		sort__has_parent = 0;
22 int		sort__has_sym = 0;
23 int		sort__has_dso = 0;
24 enum sort_mode	sort__mode = SORT_MODE__NORMAL;
25 
26 
27 static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
28 {
29 	int n;
30 	va_list ap;
31 
32 	va_start(ap, fmt);
33 	n = vsnprintf(bf, size, fmt, ap);
34 	if (symbol_conf.field_sep && n > 0) {
35 		char *sep = bf;
36 
37 		while (1) {
38 			sep = strchr(sep, *symbol_conf.field_sep);
39 			if (sep == NULL)
40 				break;
41 			*sep = '.';
42 		}
43 	}
44 	va_end(ap);
45 
46 	if (n >= (int)size)
47 		return size - 1;
48 	return n;
49 }
50 
51 static int64_t cmp_null(const void *l, const void *r)
52 {
53 	if (!l && !r)
54 		return 0;
55 	else if (!l)
56 		return -1;
57 	else
58 		return 1;
59 }
60 
61 /* --sort pid */
62 
63 static int64_t
64 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
65 {
66 	return right->thread->tid - left->thread->tid;
67 }
68 
69 static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
70 				       size_t size, unsigned int width)
71 {
72 	const char *comm = thread__comm_str(he->thread);
73 
74 	width = max(7U, width) - 6;
75 	return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
76 			       width, width, comm ?: "");
77 }
78 
79 struct sort_entry sort_thread = {
80 	.se_header	= "  Pid:Command",
81 	.se_cmp		= sort__thread_cmp,
82 	.se_snprintf	= hist_entry__thread_snprintf,
83 	.se_width_idx	= HISTC_THREAD,
84 };
85 
86 /* --sort comm */
87 
88 static int64_t
89 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
90 {
91 	/* Compare the addr that should be unique among comm */
92 	return strcmp(comm__str(right->comm), comm__str(left->comm));
93 }
94 
95 static int64_t
96 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
97 {
98 	/* Compare the addr that should be unique among comm */
99 	return strcmp(comm__str(right->comm), comm__str(left->comm));
100 }
101 
102 static int64_t
103 sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
104 {
105 	return strcmp(comm__str(right->comm), comm__str(left->comm));
106 }
107 
108 static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
109 				     size_t size, unsigned int width)
110 {
111 	return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
112 }
113 
114 struct sort_entry sort_comm = {
115 	.se_header	= "Command",
116 	.se_cmp		= sort__comm_cmp,
117 	.se_collapse	= sort__comm_collapse,
118 	.se_sort	= sort__comm_sort,
119 	.se_snprintf	= hist_entry__comm_snprintf,
120 	.se_width_idx	= HISTC_COMM,
121 };
122 
123 /* --sort dso */
124 
125 static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
126 {
127 	struct dso *dso_l = map_l ? map_l->dso : NULL;
128 	struct dso *dso_r = map_r ? map_r->dso : NULL;
129 	const char *dso_name_l, *dso_name_r;
130 
131 	if (!dso_l || !dso_r)
132 		return cmp_null(dso_r, dso_l);
133 
134 	if (verbose) {
135 		dso_name_l = dso_l->long_name;
136 		dso_name_r = dso_r->long_name;
137 	} else {
138 		dso_name_l = dso_l->short_name;
139 		dso_name_r = dso_r->short_name;
140 	}
141 
142 	return strcmp(dso_name_l, dso_name_r);
143 }
144 
145 static int64_t
146 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
147 {
148 	return _sort__dso_cmp(right->ms.map, left->ms.map);
149 }
150 
151 static int _hist_entry__dso_snprintf(struct map *map, char *bf,
152 				     size_t size, unsigned int width)
153 {
154 	if (map && map->dso) {
155 		const char *dso_name = !verbose ? map->dso->short_name :
156 			map->dso->long_name;
157 		return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
158 	}
159 
160 	return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
161 }
162 
163 static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
164 				    size_t size, unsigned int width)
165 {
166 	return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
167 }
168 
169 struct sort_entry sort_dso = {
170 	.se_header	= "Shared Object",
171 	.se_cmp		= sort__dso_cmp,
172 	.se_snprintf	= hist_entry__dso_snprintf,
173 	.se_width_idx	= HISTC_DSO,
174 };
175 
176 /* --sort symbol */
177 
178 static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
179 {
180 	return (int64_t)(right_ip - left_ip);
181 }
182 
183 static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
184 {
185 	if (!sym_l || !sym_r)
186 		return cmp_null(sym_l, sym_r);
187 
188 	if (sym_l == sym_r)
189 		return 0;
190 
191 	if (sym_l->start != sym_r->start)
192 		return (int64_t)(sym_r->start - sym_l->start);
193 
194 	return (int64_t)(sym_r->end - sym_l->end);
195 }
196 
197 static int64_t
198 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
199 {
200 	int64_t ret;
201 
202 	if (!left->ms.sym && !right->ms.sym)
203 		return _sort__addr_cmp(left->ip, right->ip);
204 
205 	/*
206 	 * comparing symbol address alone is not enough since it's a
207 	 * relative address within a dso.
208 	 */
209 	if (!sort__has_dso) {
210 		ret = sort__dso_cmp(left, right);
211 		if (ret != 0)
212 			return ret;
213 	}
214 
215 	return _sort__sym_cmp(left->ms.sym, right->ms.sym);
216 }
217 
218 static int64_t
219 sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
220 {
221 	if (!left->ms.sym || !right->ms.sym)
222 		return cmp_null(left->ms.sym, right->ms.sym);
223 
224 	return strcmp(right->ms.sym->name, left->ms.sym->name);
225 }
226 
227 static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
228 				     u64 ip, char level, char *bf, size_t size,
229 				     unsigned int width)
230 {
231 	size_t ret = 0;
232 
233 	if (verbose) {
234 		char o = map ? dso__symtab_origin(map->dso) : '!';
235 		ret += repsep_snprintf(bf, size, "%-#*llx %c ",
236 				       BITS_PER_LONG / 4 + 2, ip, o);
237 	}
238 
239 	ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
240 	if (sym && map) {
241 		if (map->type == MAP__VARIABLE) {
242 			ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
243 			ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
244 					ip - map->unmap_ip(map, sym->start));
245 			ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
246 				       width - ret, "");
247 		} else {
248 			ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
249 					       width - ret,
250 					       sym->name);
251 		}
252 	} else {
253 		size_t len = BITS_PER_LONG / 4;
254 		ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
255 				       len, ip);
256 		ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
257 				       width - ret, "");
258 	}
259 
260 	if (ret > width)
261 		bf[width] = '\0';
262 
263 	return width;
264 }
265 
266 static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
267 				    size_t size, unsigned int width)
268 {
269 	return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
270 					 he->level, bf, size, width);
271 }
272 
273 struct sort_entry sort_sym = {
274 	.se_header	= "Symbol",
275 	.se_cmp		= sort__sym_cmp,
276 	.se_sort	= sort__sym_sort,
277 	.se_snprintf	= hist_entry__sym_snprintf,
278 	.se_width_idx	= HISTC_SYMBOL,
279 };
280 
281 /* --sort srcline */
282 
283 static int64_t
284 sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
285 {
286 	if (!left->srcline) {
287 		if (!left->ms.map)
288 			left->srcline = SRCLINE_UNKNOWN;
289 		else {
290 			struct map *map = left->ms.map;
291 			left->srcline = get_srcline(map->dso,
292 					   map__rip_2objdump(map, left->ip),
293 						    left->ms.sym, true);
294 		}
295 	}
296 	if (!right->srcline) {
297 		if (!right->ms.map)
298 			right->srcline = SRCLINE_UNKNOWN;
299 		else {
300 			struct map *map = right->ms.map;
301 			right->srcline = get_srcline(map->dso,
302 					     map__rip_2objdump(map, right->ip),
303 						     right->ms.sym, true);
304 		}
305 	}
306 	return strcmp(right->srcline, left->srcline);
307 }
308 
309 static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
310 					size_t size, unsigned int width)
311 {
312 	return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline);
313 }
314 
315 struct sort_entry sort_srcline = {
316 	.se_header	= "Source:Line",
317 	.se_cmp		= sort__srcline_cmp,
318 	.se_snprintf	= hist_entry__srcline_snprintf,
319 	.se_width_idx	= HISTC_SRCLINE,
320 };
321 
322 /* --sort parent */
323 
324 static int64_t
325 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
326 {
327 	struct symbol *sym_l = left->parent;
328 	struct symbol *sym_r = right->parent;
329 
330 	if (!sym_l || !sym_r)
331 		return cmp_null(sym_l, sym_r);
332 
333 	return strcmp(sym_r->name, sym_l->name);
334 }
335 
336 static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
337 				       size_t size, unsigned int width)
338 {
339 	return repsep_snprintf(bf, size, "%-*.*s", width, width,
340 			      he->parent ? he->parent->name : "[other]");
341 }
342 
343 struct sort_entry sort_parent = {
344 	.se_header	= "Parent symbol",
345 	.se_cmp		= sort__parent_cmp,
346 	.se_snprintf	= hist_entry__parent_snprintf,
347 	.se_width_idx	= HISTC_PARENT,
348 };
349 
350 /* --sort cpu */
351 
352 static int64_t
353 sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
354 {
355 	return right->cpu - left->cpu;
356 }
357 
358 static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
359 				    size_t size, unsigned int width)
360 {
361 	return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
362 }
363 
364 struct sort_entry sort_cpu = {
365 	.se_header      = "CPU",
366 	.se_cmp	        = sort__cpu_cmp,
367 	.se_snprintf    = hist_entry__cpu_snprintf,
368 	.se_width_idx	= HISTC_CPU,
369 };
370 
371 /* sort keys for branch stacks */
372 
373 static int64_t
374 sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
375 {
376 	if (!left->branch_info || !right->branch_info)
377 		return cmp_null(left->branch_info, right->branch_info);
378 
379 	return _sort__dso_cmp(left->branch_info->from.map,
380 			      right->branch_info->from.map);
381 }
382 
383 static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
384 				    size_t size, unsigned int width)
385 {
386 	if (he->branch_info)
387 		return _hist_entry__dso_snprintf(he->branch_info->from.map,
388 						 bf, size, width);
389 	else
390 		return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
391 }
392 
393 static int64_t
394 sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
395 {
396 	if (!left->branch_info || !right->branch_info)
397 		return cmp_null(left->branch_info, right->branch_info);
398 
399 	return _sort__dso_cmp(left->branch_info->to.map,
400 			      right->branch_info->to.map);
401 }
402 
403 static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
404 				       size_t size, unsigned int width)
405 {
406 	if (he->branch_info)
407 		return _hist_entry__dso_snprintf(he->branch_info->to.map,
408 						 bf, size, width);
409 	else
410 		return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
411 }
412 
413 static int64_t
414 sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
415 {
416 	struct addr_map_symbol *from_l = &left->branch_info->from;
417 	struct addr_map_symbol *from_r = &right->branch_info->from;
418 
419 	if (!left->branch_info || !right->branch_info)
420 		return cmp_null(left->branch_info, right->branch_info);
421 
422 	from_l = &left->branch_info->from;
423 	from_r = &right->branch_info->from;
424 
425 	if (!from_l->sym && !from_r->sym)
426 		return _sort__addr_cmp(from_l->addr, from_r->addr);
427 
428 	return _sort__sym_cmp(from_l->sym, from_r->sym);
429 }
430 
431 static int64_t
432 sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
433 {
434 	struct addr_map_symbol *to_l, *to_r;
435 
436 	if (!left->branch_info || !right->branch_info)
437 		return cmp_null(left->branch_info, right->branch_info);
438 
439 	to_l = &left->branch_info->to;
440 	to_r = &right->branch_info->to;
441 
442 	if (!to_l->sym && !to_r->sym)
443 		return _sort__addr_cmp(to_l->addr, to_r->addr);
444 
445 	return _sort__sym_cmp(to_l->sym, to_r->sym);
446 }
447 
448 static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
449 					 size_t size, unsigned int width)
450 {
451 	if (he->branch_info) {
452 		struct addr_map_symbol *from = &he->branch_info->from;
453 
454 		return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
455 						 he->level, bf, size, width);
456 	}
457 
458 	return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
459 }
460 
461 static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
462 				       size_t size, unsigned int width)
463 {
464 	if (he->branch_info) {
465 		struct addr_map_symbol *to = &he->branch_info->to;
466 
467 		return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
468 						 he->level, bf, size, width);
469 	}
470 
471 	return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
472 }
473 
474 struct sort_entry sort_dso_from = {
475 	.se_header	= "Source Shared Object",
476 	.se_cmp		= sort__dso_from_cmp,
477 	.se_snprintf	= hist_entry__dso_from_snprintf,
478 	.se_width_idx	= HISTC_DSO_FROM,
479 };
480 
481 struct sort_entry sort_dso_to = {
482 	.se_header	= "Target Shared Object",
483 	.se_cmp		= sort__dso_to_cmp,
484 	.se_snprintf	= hist_entry__dso_to_snprintf,
485 	.se_width_idx	= HISTC_DSO_TO,
486 };
487 
488 struct sort_entry sort_sym_from = {
489 	.se_header	= "Source Symbol",
490 	.se_cmp		= sort__sym_from_cmp,
491 	.se_snprintf	= hist_entry__sym_from_snprintf,
492 	.se_width_idx	= HISTC_SYMBOL_FROM,
493 };
494 
495 struct sort_entry sort_sym_to = {
496 	.se_header	= "Target Symbol",
497 	.se_cmp		= sort__sym_to_cmp,
498 	.se_snprintf	= hist_entry__sym_to_snprintf,
499 	.se_width_idx	= HISTC_SYMBOL_TO,
500 };
501 
502 static int64_t
503 sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
504 {
505 	unsigned char mp, p;
506 
507 	if (!left->branch_info || !right->branch_info)
508 		return cmp_null(left->branch_info, right->branch_info);
509 
510 	mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
511 	p  = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
512 	return mp || p;
513 }
514 
515 static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
516 				    size_t size, unsigned int width){
517 	static const char *out = "N/A";
518 
519 	if (he->branch_info) {
520 		if (he->branch_info->flags.predicted)
521 			out = "N";
522 		else if (he->branch_info->flags.mispred)
523 			out = "Y";
524 	}
525 
526 	return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
527 }
528 
529 /* --sort daddr_sym */
530 static int64_t
531 sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
532 {
533 	uint64_t l = 0, r = 0;
534 
535 	if (left->mem_info)
536 		l = left->mem_info->daddr.addr;
537 	if (right->mem_info)
538 		r = right->mem_info->daddr.addr;
539 
540 	return (int64_t)(r - l);
541 }
542 
543 static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
544 				    size_t size, unsigned int width)
545 {
546 	uint64_t addr = 0;
547 	struct map *map = NULL;
548 	struct symbol *sym = NULL;
549 
550 	if (he->mem_info) {
551 		addr = he->mem_info->daddr.addr;
552 		map = he->mem_info->daddr.map;
553 		sym = he->mem_info->daddr.sym;
554 	}
555 	return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
556 					 width);
557 }
558 
559 static int64_t
560 sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
561 {
562 	struct map *map_l = NULL;
563 	struct map *map_r = NULL;
564 
565 	if (left->mem_info)
566 		map_l = left->mem_info->daddr.map;
567 	if (right->mem_info)
568 		map_r = right->mem_info->daddr.map;
569 
570 	return _sort__dso_cmp(map_l, map_r);
571 }
572 
573 static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
574 				    size_t size, unsigned int width)
575 {
576 	struct map *map = NULL;
577 
578 	if (he->mem_info)
579 		map = he->mem_info->daddr.map;
580 
581 	return _hist_entry__dso_snprintf(map, bf, size, width);
582 }
583 
584 static int64_t
585 sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
586 {
587 	union perf_mem_data_src data_src_l;
588 	union perf_mem_data_src data_src_r;
589 
590 	if (left->mem_info)
591 		data_src_l = left->mem_info->data_src;
592 	else
593 		data_src_l.mem_lock = PERF_MEM_LOCK_NA;
594 
595 	if (right->mem_info)
596 		data_src_r = right->mem_info->data_src;
597 	else
598 		data_src_r.mem_lock = PERF_MEM_LOCK_NA;
599 
600 	return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
601 }
602 
603 static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
604 				    size_t size, unsigned int width)
605 {
606 	const char *out;
607 	u64 mask = PERF_MEM_LOCK_NA;
608 
609 	if (he->mem_info)
610 		mask = he->mem_info->data_src.mem_lock;
611 
612 	if (mask & PERF_MEM_LOCK_NA)
613 		out = "N/A";
614 	else if (mask & PERF_MEM_LOCK_LOCKED)
615 		out = "Yes";
616 	else
617 		out = "No";
618 
619 	return repsep_snprintf(bf, size, "%-*s", width, out);
620 }
621 
622 static int64_t
623 sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
624 {
625 	union perf_mem_data_src data_src_l;
626 	union perf_mem_data_src data_src_r;
627 
628 	if (left->mem_info)
629 		data_src_l = left->mem_info->data_src;
630 	else
631 		data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
632 
633 	if (right->mem_info)
634 		data_src_r = right->mem_info->data_src;
635 	else
636 		data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
637 
638 	return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
639 }
640 
641 static const char * const tlb_access[] = {
642 	"N/A",
643 	"HIT",
644 	"MISS",
645 	"L1",
646 	"L2",
647 	"Walker",
648 	"Fault",
649 };
650 #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
651 
652 static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
653 				    size_t size, unsigned int width)
654 {
655 	char out[64];
656 	size_t sz = sizeof(out) - 1; /* -1 for null termination */
657 	size_t l = 0, i;
658 	u64 m = PERF_MEM_TLB_NA;
659 	u64 hit, miss;
660 
661 	out[0] = '\0';
662 
663 	if (he->mem_info)
664 		m = he->mem_info->data_src.mem_dtlb;
665 
666 	hit = m & PERF_MEM_TLB_HIT;
667 	miss = m & PERF_MEM_TLB_MISS;
668 
669 	/* already taken care of */
670 	m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
671 
672 	for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
673 		if (!(m & 0x1))
674 			continue;
675 		if (l) {
676 			strcat(out, " or ");
677 			l += 4;
678 		}
679 		strncat(out, tlb_access[i], sz - l);
680 		l += strlen(tlb_access[i]);
681 	}
682 	if (*out == '\0')
683 		strcpy(out, "N/A");
684 	if (hit)
685 		strncat(out, " hit", sz - l);
686 	if (miss)
687 		strncat(out, " miss", sz - l);
688 
689 	return repsep_snprintf(bf, size, "%-*s", width, out);
690 }
691 
692 static int64_t
693 sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
694 {
695 	union perf_mem_data_src data_src_l;
696 	union perf_mem_data_src data_src_r;
697 
698 	if (left->mem_info)
699 		data_src_l = left->mem_info->data_src;
700 	else
701 		data_src_l.mem_lvl = PERF_MEM_LVL_NA;
702 
703 	if (right->mem_info)
704 		data_src_r = right->mem_info->data_src;
705 	else
706 		data_src_r.mem_lvl = PERF_MEM_LVL_NA;
707 
708 	return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
709 }
710 
711 static const char * const mem_lvl[] = {
712 	"N/A",
713 	"HIT",
714 	"MISS",
715 	"L1",
716 	"LFB",
717 	"L2",
718 	"L3",
719 	"Local RAM",
720 	"Remote RAM (1 hop)",
721 	"Remote RAM (2 hops)",
722 	"Remote Cache (1 hop)",
723 	"Remote Cache (2 hops)",
724 	"I/O",
725 	"Uncached",
726 };
727 #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
728 
729 static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
730 				    size_t size, unsigned int width)
731 {
732 	char out[64];
733 	size_t sz = sizeof(out) - 1; /* -1 for null termination */
734 	size_t i, l = 0;
735 	u64 m =  PERF_MEM_LVL_NA;
736 	u64 hit, miss;
737 
738 	if (he->mem_info)
739 		m  = he->mem_info->data_src.mem_lvl;
740 
741 	out[0] = '\0';
742 
743 	hit = m & PERF_MEM_LVL_HIT;
744 	miss = m & PERF_MEM_LVL_MISS;
745 
746 	/* already taken care of */
747 	m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
748 
749 	for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
750 		if (!(m & 0x1))
751 			continue;
752 		if (l) {
753 			strcat(out, " or ");
754 			l += 4;
755 		}
756 		strncat(out, mem_lvl[i], sz - l);
757 		l += strlen(mem_lvl[i]);
758 	}
759 	if (*out == '\0')
760 		strcpy(out, "N/A");
761 	if (hit)
762 		strncat(out, " hit", sz - l);
763 	if (miss)
764 		strncat(out, " miss", sz - l);
765 
766 	return repsep_snprintf(bf, size, "%-*s", width, out);
767 }
768 
769 static int64_t
770 sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
771 {
772 	union perf_mem_data_src data_src_l;
773 	union perf_mem_data_src data_src_r;
774 
775 	if (left->mem_info)
776 		data_src_l = left->mem_info->data_src;
777 	else
778 		data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
779 
780 	if (right->mem_info)
781 		data_src_r = right->mem_info->data_src;
782 	else
783 		data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
784 
785 	return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
786 }
787 
788 static const char * const snoop_access[] = {
789 	"N/A",
790 	"None",
791 	"Miss",
792 	"Hit",
793 	"HitM",
794 };
795 #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
796 
797 static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
798 				    size_t size, unsigned int width)
799 {
800 	char out[64];
801 	size_t sz = sizeof(out) - 1; /* -1 for null termination */
802 	size_t i, l = 0;
803 	u64 m = PERF_MEM_SNOOP_NA;
804 
805 	out[0] = '\0';
806 
807 	if (he->mem_info)
808 		m = he->mem_info->data_src.mem_snoop;
809 
810 	for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
811 		if (!(m & 0x1))
812 			continue;
813 		if (l) {
814 			strcat(out, " or ");
815 			l += 4;
816 		}
817 		strncat(out, snoop_access[i], sz - l);
818 		l += strlen(snoop_access[i]);
819 	}
820 
821 	if (*out == '\0')
822 		strcpy(out, "N/A");
823 
824 	return repsep_snprintf(bf, size, "%-*s", width, out);
825 }
826 
827 static inline  u64 cl_address(u64 address)
828 {
829 	/* return the cacheline of the address */
830 	return (address & ~(cacheline_size - 1));
831 }
832 
833 static int64_t
834 sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
835 {
836 	u64 l, r;
837 	struct map *l_map, *r_map;
838 
839 	if (!left->mem_info)  return -1;
840 	if (!right->mem_info) return 1;
841 
842 	/* group event types together */
843 	if (left->cpumode > right->cpumode) return -1;
844 	if (left->cpumode < right->cpumode) return 1;
845 
846 	l_map = left->mem_info->daddr.map;
847 	r_map = right->mem_info->daddr.map;
848 
849 	/* if both are NULL, jump to sort on al_addr instead */
850 	if (!l_map && !r_map)
851 		goto addr;
852 
853 	if (!l_map) return -1;
854 	if (!r_map) return 1;
855 
856 	if (l_map->maj > r_map->maj) return -1;
857 	if (l_map->maj < r_map->maj) return 1;
858 
859 	if (l_map->min > r_map->min) return -1;
860 	if (l_map->min < r_map->min) return 1;
861 
862 	if (l_map->ino > r_map->ino) return -1;
863 	if (l_map->ino < r_map->ino) return 1;
864 
865 	if (l_map->ino_generation > r_map->ino_generation) return -1;
866 	if (l_map->ino_generation < r_map->ino_generation) return 1;
867 
868 	/*
869 	 * Addresses with no major/minor numbers are assumed to be
870 	 * anonymous in userspace.  Sort those on pid then address.
871 	 *
872 	 * The kernel and non-zero major/minor mapped areas are
873 	 * assumed to be unity mapped.  Sort those on address.
874 	 */
875 
876 	if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
877 	    (!(l_map->flags & MAP_SHARED)) &&
878 	    !l_map->maj && !l_map->min && !l_map->ino &&
879 	    !l_map->ino_generation) {
880 		/* userspace anonymous */
881 
882 		if (left->thread->pid_ > right->thread->pid_) return -1;
883 		if (left->thread->pid_ < right->thread->pid_) return 1;
884 	}
885 
886 addr:
887 	/* al_addr does all the right addr - start + offset calculations */
888 	l = cl_address(left->mem_info->daddr.al_addr);
889 	r = cl_address(right->mem_info->daddr.al_addr);
890 
891 	if (l > r) return -1;
892 	if (l < r) return 1;
893 
894 	return 0;
895 }
896 
897 static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
898 					  size_t size, unsigned int width)
899 {
900 
901 	uint64_t addr = 0;
902 	struct map *map = NULL;
903 	struct symbol *sym = NULL;
904 	char level = he->level;
905 
906 	if (he->mem_info) {
907 		addr = cl_address(he->mem_info->daddr.al_addr);
908 		map = he->mem_info->daddr.map;
909 		sym = he->mem_info->daddr.sym;
910 
911 		/* print [s] for shared data mmaps */
912 		if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
913 		     map && (map->type == MAP__VARIABLE) &&
914 		    (map->flags & MAP_SHARED) &&
915 		    (map->maj || map->min || map->ino ||
916 		     map->ino_generation))
917 			level = 's';
918 		else if (!map)
919 			level = 'X';
920 	}
921 	return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
922 					 width);
923 }
924 
925 struct sort_entry sort_mispredict = {
926 	.se_header	= "Branch Mispredicted",
927 	.se_cmp		= sort__mispredict_cmp,
928 	.se_snprintf	= hist_entry__mispredict_snprintf,
929 	.se_width_idx	= HISTC_MISPREDICT,
930 };
931 
932 static u64 he_weight(struct hist_entry *he)
933 {
934 	return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
935 }
936 
937 static int64_t
938 sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
939 {
940 	return he_weight(left) - he_weight(right);
941 }
942 
943 static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
944 				    size_t size, unsigned int width)
945 {
946 	return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
947 }
948 
949 struct sort_entry sort_local_weight = {
950 	.se_header	= "Local Weight",
951 	.se_cmp		= sort__local_weight_cmp,
952 	.se_snprintf	= hist_entry__local_weight_snprintf,
953 	.se_width_idx	= HISTC_LOCAL_WEIGHT,
954 };
955 
956 static int64_t
957 sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
958 {
959 	return left->stat.weight - right->stat.weight;
960 }
961 
962 static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
963 					      size_t size, unsigned int width)
964 {
965 	return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
966 }
967 
968 struct sort_entry sort_global_weight = {
969 	.se_header	= "Weight",
970 	.se_cmp		= sort__global_weight_cmp,
971 	.se_snprintf	= hist_entry__global_weight_snprintf,
972 	.se_width_idx	= HISTC_GLOBAL_WEIGHT,
973 };
974 
975 struct sort_entry sort_mem_daddr_sym = {
976 	.se_header	= "Data Symbol",
977 	.se_cmp		= sort__daddr_cmp,
978 	.se_snprintf	= hist_entry__daddr_snprintf,
979 	.se_width_idx	= HISTC_MEM_DADDR_SYMBOL,
980 };
981 
982 struct sort_entry sort_mem_daddr_dso = {
983 	.se_header	= "Data Object",
984 	.se_cmp		= sort__dso_daddr_cmp,
985 	.se_snprintf	= hist_entry__dso_daddr_snprintf,
986 	.se_width_idx	= HISTC_MEM_DADDR_SYMBOL,
987 };
988 
989 struct sort_entry sort_mem_locked = {
990 	.se_header	= "Locked",
991 	.se_cmp		= sort__locked_cmp,
992 	.se_snprintf	= hist_entry__locked_snprintf,
993 	.se_width_idx	= HISTC_MEM_LOCKED,
994 };
995 
996 struct sort_entry sort_mem_tlb = {
997 	.se_header	= "TLB access",
998 	.se_cmp		= sort__tlb_cmp,
999 	.se_snprintf	= hist_entry__tlb_snprintf,
1000 	.se_width_idx	= HISTC_MEM_TLB,
1001 };
1002 
1003 struct sort_entry sort_mem_lvl = {
1004 	.se_header	= "Memory access",
1005 	.se_cmp		= sort__lvl_cmp,
1006 	.se_snprintf	= hist_entry__lvl_snprintf,
1007 	.se_width_idx	= HISTC_MEM_LVL,
1008 };
1009 
1010 struct sort_entry sort_mem_snoop = {
1011 	.se_header	= "Snoop",
1012 	.se_cmp		= sort__snoop_cmp,
1013 	.se_snprintf	= hist_entry__snoop_snprintf,
1014 	.se_width_idx	= HISTC_MEM_SNOOP,
1015 };
1016 
1017 struct sort_entry sort_mem_dcacheline = {
1018 	.se_header	= "Data Cacheline",
1019 	.se_cmp		= sort__dcacheline_cmp,
1020 	.se_snprintf	= hist_entry__dcacheline_snprintf,
1021 	.se_width_idx	= HISTC_MEM_DCACHELINE,
1022 };
1023 
1024 static int64_t
1025 sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1026 {
1027 	if (!left->branch_info || !right->branch_info)
1028 		return cmp_null(left->branch_info, right->branch_info);
1029 
1030 	return left->branch_info->flags.abort !=
1031 		right->branch_info->flags.abort;
1032 }
1033 
1034 static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
1035 				    size_t size, unsigned int width)
1036 {
1037 	static const char *out = "N/A";
1038 
1039 	if (he->branch_info) {
1040 		if (he->branch_info->flags.abort)
1041 			out = "A";
1042 		else
1043 			out = ".";
1044 	}
1045 
1046 	return repsep_snprintf(bf, size, "%-*s", width, out);
1047 }
1048 
1049 struct sort_entry sort_abort = {
1050 	.se_header	= "Transaction abort",
1051 	.se_cmp		= sort__abort_cmp,
1052 	.se_snprintf	= hist_entry__abort_snprintf,
1053 	.se_width_idx	= HISTC_ABORT,
1054 };
1055 
1056 static int64_t
1057 sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1058 {
1059 	if (!left->branch_info || !right->branch_info)
1060 		return cmp_null(left->branch_info, right->branch_info);
1061 
1062 	return left->branch_info->flags.in_tx !=
1063 		right->branch_info->flags.in_tx;
1064 }
1065 
1066 static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
1067 				    size_t size, unsigned int width)
1068 {
1069 	static const char *out = "N/A";
1070 
1071 	if (he->branch_info) {
1072 		if (he->branch_info->flags.in_tx)
1073 			out = "T";
1074 		else
1075 			out = ".";
1076 	}
1077 
1078 	return repsep_snprintf(bf, size, "%-*s", width, out);
1079 }
1080 
1081 struct sort_entry sort_in_tx = {
1082 	.se_header	= "Branch in transaction",
1083 	.se_cmp		= sort__in_tx_cmp,
1084 	.se_snprintf	= hist_entry__in_tx_snprintf,
1085 	.se_width_idx	= HISTC_IN_TX,
1086 };
1087 
1088 static int64_t
1089 sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1090 {
1091 	return left->transaction - right->transaction;
1092 }
1093 
1094 static inline char *add_str(char *p, const char *str)
1095 {
1096 	strcpy(p, str);
1097 	return p + strlen(str);
1098 }
1099 
1100 static struct txbit {
1101 	unsigned flag;
1102 	const char *name;
1103 	int skip_for_len;
1104 } txbits[] = {
1105 	{ PERF_TXN_ELISION,        "EL ",        0 },
1106 	{ PERF_TXN_TRANSACTION,    "TX ",        1 },
1107 	{ PERF_TXN_SYNC,           "SYNC ",      1 },
1108 	{ PERF_TXN_ASYNC,          "ASYNC ",     0 },
1109 	{ PERF_TXN_RETRY,          "RETRY ",     0 },
1110 	{ PERF_TXN_CONFLICT,       "CON ",       0 },
1111 	{ PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1112 	{ PERF_TXN_CAPACITY_READ,  "CAP-READ ",  0 },
1113 	{ 0, NULL, 0 }
1114 };
1115 
1116 int hist_entry__transaction_len(void)
1117 {
1118 	int i;
1119 	int len = 0;
1120 
1121 	for (i = 0; txbits[i].name; i++) {
1122 		if (!txbits[i].skip_for_len)
1123 			len += strlen(txbits[i].name);
1124 	}
1125 	len += 4; /* :XX<space> */
1126 	return len;
1127 }
1128 
1129 static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
1130 					    size_t size, unsigned int width)
1131 {
1132 	u64 t = he->transaction;
1133 	char buf[128];
1134 	char *p = buf;
1135 	int i;
1136 
1137 	buf[0] = 0;
1138 	for (i = 0; txbits[i].name; i++)
1139 		if (txbits[i].flag & t)
1140 			p = add_str(p, txbits[i].name);
1141 	if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1142 		p = add_str(p, "NEITHER ");
1143 	if (t & PERF_TXN_ABORT_MASK) {
1144 		sprintf(p, ":%" PRIx64,
1145 			(t & PERF_TXN_ABORT_MASK) >>
1146 			PERF_TXN_ABORT_SHIFT);
1147 		p += strlen(p);
1148 	}
1149 
1150 	return repsep_snprintf(bf, size, "%-*s", width, buf);
1151 }
1152 
1153 struct sort_entry sort_transaction = {
1154 	.se_header	= "Transaction                ",
1155 	.se_cmp		= sort__transaction_cmp,
1156 	.se_snprintf	= hist_entry__transaction_snprintf,
1157 	.se_width_idx	= HISTC_TRANSACTION,
1158 };
1159 
1160 struct sort_dimension {
1161 	const char		*name;
1162 	struct sort_entry	*entry;
1163 	int			taken;
1164 };
1165 
1166 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1167 
1168 static struct sort_dimension common_sort_dimensions[] = {
1169 	DIM(SORT_PID, "pid", sort_thread),
1170 	DIM(SORT_COMM, "comm", sort_comm),
1171 	DIM(SORT_DSO, "dso", sort_dso),
1172 	DIM(SORT_SYM, "symbol", sort_sym),
1173 	DIM(SORT_PARENT, "parent", sort_parent),
1174 	DIM(SORT_CPU, "cpu", sort_cpu),
1175 	DIM(SORT_SRCLINE, "srcline", sort_srcline),
1176 	DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1177 	DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
1178 	DIM(SORT_TRANSACTION, "transaction", sort_transaction),
1179 };
1180 
1181 #undef DIM
1182 
1183 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1184 
1185 static struct sort_dimension bstack_sort_dimensions[] = {
1186 	DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1187 	DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1188 	DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1189 	DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1190 	DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
1191 	DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1192 	DIM(SORT_ABORT, "abort", sort_abort),
1193 };
1194 
1195 #undef DIM
1196 
1197 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1198 
1199 static struct sort_dimension memory_sort_dimensions[] = {
1200 	DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1201 	DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1202 	DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1203 	DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1204 	DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1205 	DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1206 	DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
1207 };
1208 
1209 #undef DIM
1210 
1211 struct hpp_dimension {
1212 	const char		*name;
1213 	struct perf_hpp_fmt	*fmt;
1214 	int			taken;
1215 };
1216 
1217 #define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1218 
1219 static struct hpp_dimension hpp_sort_dimensions[] = {
1220 	DIM(PERF_HPP__OVERHEAD, "overhead"),
1221 	DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1222 	DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1223 	DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1224 	DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1225 	DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
1226 	DIM(PERF_HPP__SAMPLES, "sample"),
1227 	DIM(PERF_HPP__PERIOD, "period"),
1228 };
1229 
1230 #undef DIM
1231 
1232 struct hpp_sort_entry {
1233 	struct perf_hpp_fmt hpp;
1234 	struct sort_entry *se;
1235 };
1236 
1237 bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1238 {
1239 	struct hpp_sort_entry *hse_a;
1240 	struct hpp_sort_entry *hse_b;
1241 
1242 	if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1243 		return false;
1244 
1245 	hse_a = container_of(a, struct hpp_sort_entry, hpp);
1246 	hse_b = container_of(b, struct hpp_sort_entry, hpp);
1247 
1248 	return hse_a->se == hse_b->se;
1249 }
1250 
1251 void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1252 {
1253 	struct hpp_sort_entry *hse;
1254 
1255 	if (!perf_hpp__is_sort_entry(fmt))
1256 		return;
1257 
1258 	hse = container_of(fmt, struct hpp_sort_entry, hpp);
1259 	hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
1260 }
1261 
1262 static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1263 			      struct perf_evsel *evsel)
1264 {
1265 	struct hpp_sort_entry *hse;
1266 	size_t len = fmt->user_len;
1267 
1268 	hse = container_of(fmt, struct hpp_sort_entry, hpp);
1269 
1270 	if (!len)
1271 		len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
1272 
1273 	return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
1274 }
1275 
1276 static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1277 			     struct perf_hpp *hpp __maybe_unused,
1278 			     struct perf_evsel *evsel)
1279 {
1280 	struct hpp_sort_entry *hse;
1281 	size_t len = fmt->user_len;
1282 
1283 	hse = container_of(fmt, struct hpp_sort_entry, hpp);
1284 
1285 	if (!len)
1286 		len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
1287 
1288 	return len;
1289 }
1290 
1291 static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1292 			     struct hist_entry *he)
1293 {
1294 	struct hpp_sort_entry *hse;
1295 	size_t len = fmt->user_len;
1296 
1297 	hse = container_of(fmt, struct hpp_sort_entry, hpp);
1298 
1299 	if (!len)
1300 		len = hists__col_len(he->hists, hse->se->se_width_idx);
1301 
1302 	return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1303 }
1304 
1305 static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1306 			       struct hist_entry *a, struct hist_entry *b)
1307 {
1308 	struct hpp_sort_entry *hse;
1309 
1310 	hse = container_of(fmt, struct hpp_sort_entry, hpp);
1311 	return hse->se->se_cmp(a, b);
1312 }
1313 
1314 static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1315 				    struct hist_entry *a, struct hist_entry *b)
1316 {
1317 	struct hpp_sort_entry *hse;
1318 	int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1319 
1320 	hse = container_of(fmt, struct hpp_sort_entry, hpp);
1321 	collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1322 	return collapse_fn(a, b);
1323 }
1324 
1325 static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1326 				struct hist_entry *a, struct hist_entry *b)
1327 {
1328 	struct hpp_sort_entry *hse;
1329 	int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1330 
1331 	hse = container_of(fmt, struct hpp_sort_entry, hpp);
1332 	sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1333 	return sort_fn(a, b);
1334 }
1335 
1336 static struct hpp_sort_entry *
1337 __sort_dimension__alloc_hpp(struct sort_dimension *sd)
1338 {
1339 	struct hpp_sort_entry *hse;
1340 
1341 	hse = malloc(sizeof(*hse));
1342 	if (hse == NULL) {
1343 		pr_err("Memory allocation failed\n");
1344 		return NULL;
1345 	}
1346 
1347 	hse->se = sd->entry;
1348 	hse->hpp.name = sd->entry->se_header;
1349 	hse->hpp.header = __sort__hpp_header;
1350 	hse->hpp.width = __sort__hpp_width;
1351 	hse->hpp.entry = __sort__hpp_entry;
1352 	hse->hpp.color = NULL;
1353 
1354 	hse->hpp.cmp = __sort__hpp_cmp;
1355 	hse->hpp.collapse = __sort__hpp_collapse;
1356 	hse->hpp.sort = __sort__hpp_sort;
1357 
1358 	INIT_LIST_HEAD(&hse->hpp.list);
1359 	INIT_LIST_HEAD(&hse->hpp.sort_list);
1360 	hse->hpp.elide = false;
1361 	hse->hpp.len = 0;
1362 	hse->hpp.user_len = 0;
1363 
1364 	return hse;
1365 }
1366 
1367 bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1368 {
1369 	return format->header == __sort__hpp_header;
1370 }
1371 
1372 static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1373 {
1374 	struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1375 
1376 	if (hse == NULL)
1377 		return -1;
1378 
1379 	perf_hpp__register_sort_field(&hse->hpp);
1380 	return 0;
1381 }
1382 
1383 static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1384 {
1385 	struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1386 
1387 	if (hse == NULL)
1388 		return -1;
1389 
1390 	perf_hpp__column_register(&hse->hpp);
1391 	return 0;
1392 }
1393 
1394 static int __sort_dimension__add(struct sort_dimension *sd)
1395 {
1396 	if (sd->taken)
1397 		return 0;
1398 
1399 	if (__sort_dimension__add_hpp_sort(sd) < 0)
1400 		return -1;
1401 
1402 	if (sd->entry->se_collapse)
1403 		sort__need_collapse = 1;
1404 
1405 	sd->taken = 1;
1406 
1407 	return 0;
1408 }
1409 
1410 static int __hpp_dimension__add(struct hpp_dimension *hd)
1411 {
1412 	if (!hd->taken) {
1413 		hd->taken = 1;
1414 
1415 		perf_hpp__register_sort_field(hd->fmt);
1416 	}
1417 	return 0;
1418 }
1419 
1420 static int __sort_dimension__add_output(struct sort_dimension *sd)
1421 {
1422 	if (sd->taken)
1423 		return 0;
1424 
1425 	if (__sort_dimension__add_hpp_output(sd) < 0)
1426 		return -1;
1427 
1428 	sd->taken = 1;
1429 	return 0;
1430 }
1431 
1432 static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1433 {
1434 	if (!hd->taken) {
1435 		hd->taken = 1;
1436 
1437 		perf_hpp__column_register(hd->fmt);
1438 	}
1439 	return 0;
1440 }
1441 
1442 int sort_dimension__add(const char *tok)
1443 {
1444 	unsigned int i;
1445 
1446 	for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1447 		struct sort_dimension *sd = &common_sort_dimensions[i];
1448 
1449 		if (strncasecmp(tok, sd->name, strlen(tok)))
1450 			continue;
1451 
1452 		if (sd->entry == &sort_parent) {
1453 			int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1454 			if (ret) {
1455 				char err[BUFSIZ];
1456 
1457 				regerror(ret, &parent_regex, err, sizeof(err));
1458 				pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1459 				return -EINVAL;
1460 			}
1461 			sort__has_parent = 1;
1462 		} else if (sd->entry == &sort_sym) {
1463 			sort__has_sym = 1;
1464 			/*
1465 			 * perf diff displays the performance difference amongst
1466 			 * two or more perf.data files. Those files could come
1467 			 * from different binaries. So we should not compare
1468 			 * their ips, but the name of symbol.
1469 			 */
1470 			if (sort__mode == SORT_MODE__DIFF)
1471 				sd->entry->se_collapse = sort__sym_sort;
1472 
1473 		} else if (sd->entry == &sort_dso) {
1474 			sort__has_dso = 1;
1475 		}
1476 
1477 		return __sort_dimension__add(sd);
1478 	}
1479 
1480 	for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1481 		struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1482 
1483 		if (strncasecmp(tok, hd->name, strlen(tok)))
1484 			continue;
1485 
1486 		return __hpp_dimension__add(hd);
1487 	}
1488 
1489 	for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1490 		struct sort_dimension *sd = &bstack_sort_dimensions[i];
1491 
1492 		if (strncasecmp(tok, sd->name, strlen(tok)))
1493 			continue;
1494 
1495 		if (sort__mode != SORT_MODE__BRANCH)
1496 			return -EINVAL;
1497 
1498 		if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1499 			sort__has_sym = 1;
1500 
1501 		__sort_dimension__add(sd);
1502 		return 0;
1503 	}
1504 
1505 	for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1506 		struct sort_dimension *sd = &memory_sort_dimensions[i];
1507 
1508 		if (strncasecmp(tok, sd->name, strlen(tok)))
1509 			continue;
1510 
1511 		if (sort__mode != SORT_MODE__MEMORY)
1512 			return -EINVAL;
1513 
1514 		if (sd->entry == &sort_mem_daddr_sym)
1515 			sort__has_sym = 1;
1516 
1517 		__sort_dimension__add(sd);
1518 		return 0;
1519 	}
1520 
1521 	return -ESRCH;
1522 }
1523 
1524 static const char *get_default_sort_order(void)
1525 {
1526 	const char *default_sort_orders[] = {
1527 		default_sort_order,
1528 		default_branch_sort_order,
1529 		default_mem_sort_order,
1530 		default_top_sort_order,
1531 		default_diff_sort_order,
1532 	};
1533 
1534 	BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1535 
1536 	return default_sort_orders[sort__mode];
1537 }
1538 
1539 static int setup_sort_order(void)
1540 {
1541 	char *new_sort_order;
1542 
1543 	/*
1544 	 * Append '+'-prefixed sort order to the default sort
1545 	 * order string.
1546 	 */
1547 	if (!sort_order || is_strict_order(sort_order))
1548 		return 0;
1549 
1550 	if (sort_order[1] == '\0') {
1551 		error("Invalid --sort key: `+'");
1552 		return -EINVAL;
1553 	}
1554 
1555 	/*
1556 	 * We allocate new sort_order string, but we never free it,
1557 	 * because it's checked over the rest of the code.
1558 	 */
1559 	if (asprintf(&new_sort_order, "%s,%s",
1560 		     get_default_sort_order(), sort_order + 1) < 0) {
1561 		error("Not enough memory to set up --sort");
1562 		return -ENOMEM;
1563 	}
1564 
1565 	sort_order = new_sort_order;
1566 	return 0;
1567 }
1568 
1569 static int __setup_sorting(void)
1570 {
1571 	char *tmp, *tok, *str;
1572 	const char *sort_keys;
1573 	int ret = 0;
1574 
1575 	ret = setup_sort_order();
1576 	if (ret)
1577 		return ret;
1578 
1579 	sort_keys = sort_order;
1580 	if (sort_keys == NULL) {
1581 		if (is_strict_order(field_order)) {
1582 			/*
1583 			 * If user specified field order but no sort order,
1584 			 * we'll honor it and not add default sort orders.
1585 			 */
1586 			return 0;
1587 		}
1588 
1589 		sort_keys = get_default_sort_order();
1590 	}
1591 
1592 	str = strdup(sort_keys);
1593 	if (str == NULL) {
1594 		error("Not enough memory to setup sort keys");
1595 		return -ENOMEM;
1596 	}
1597 
1598 	for (tok = strtok_r(str, ", ", &tmp);
1599 			tok; tok = strtok_r(NULL, ", ", &tmp)) {
1600 		ret = sort_dimension__add(tok);
1601 		if (ret == -EINVAL) {
1602 			error("Invalid --sort key: `%s'", tok);
1603 			break;
1604 		} else if (ret == -ESRCH) {
1605 			error("Unknown --sort key: `%s'", tok);
1606 			break;
1607 		}
1608 	}
1609 
1610 	free(str);
1611 	return ret;
1612 }
1613 
1614 void perf_hpp__set_elide(int idx, bool elide)
1615 {
1616 	struct perf_hpp_fmt *fmt;
1617 	struct hpp_sort_entry *hse;
1618 
1619 	perf_hpp__for_each_format(fmt) {
1620 		if (!perf_hpp__is_sort_entry(fmt))
1621 			continue;
1622 
1623 		hse = container_of(fmt, struct hpp_sort_entry, hpp);
1624 		if (hse->se->se_width_idx == idx) {
1625 			fmt->elide = elide;
1626 			break;
1627 		}
1628 	}
1629 }
1630 
1631 static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
1632 {
1633 	if (list && strlist__nr_entries(list) == 1) {
1634 		if (fp != NULL)
1635 			fprintf(fp, "# %s: %s\n", list_name,
1636 				strlist__entry(list, 0)->s);
1637 		return true;
1638 	}
1639 	return false;
1640 }
1641 
1642 static bool get_elide(int idx, FILE *output)
1643 {
1644 	switch (idx) {
1645 	case HISTC_SYMBOL:
1646 		return __get_elide(symbol_conf.sym_list, "symbol", output);
1647 	case HISTC_DSO:
1648 		return __get_elide(symbol_conf.dso_list, "dso", output);
1649 	case HISTC_COMM:
1650 		return __get_elide(symbol_conf.comm_list, "comm", output);
1651 	default:
1652 		break;
1653 	}
1654 
1655 	if (sort__mode != SORT_MODE__BRANCH)
1656 		return false;
1657 
1658 	switch (idx) {
1659 	case HISTC_SYMBOL_FROM:
1660 		return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1661 	case HISTC_SYMBOL_TO:
1662 		return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1663 	case HISTC_DSO_FROM:
1664 		return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1665 	case HISTC_DSO_TO:
1666 		return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1667 	default:
1668 		break;
1669 	}
1670 
1671 	return false;
1672 }
1673 
1674 void sort__setup_elide(FILE *output)
1675 {
1676 	struct perf_hpp_fmt *fmt;
1677 	struct hpp_sort_entry *hse;
1678 
1679 	perf_hpp__for_each_format(fmt) {
1680 		if (!perf_hpp__is_sort_entry(fmt))
1681 			continue;
1682 
1683 		hse = container_of(fmt, struct hpp_sort_entry, hpp);
1684 		fmt->elide = get_elide(hse->se->se_width_idx, output);
1685 	}
1686 
1687 	/*
1688 	 * It makes no sense to elide all of sort entries.
1689 	 * Just revert them to show up again.
1690 	 */
1691 	perf_hpp__for_each_format(fmt) {
1692 		if (!perf_hpp__is_sort_entry(fmt))
1693 			continue;
1694 
1695 		if (!fmt->elide)
1696 			return;
1697 	}
1698 
1699 	perf_hpp__for_each_format(fmt) {
1700 		if (!perf_hpp__is_sort_entry(fmt))
1701 			continue;
1702 
1703 		fmt->elide = false;
1704 	}
1705 }
1706 
1707 static int output_field_add(char *tok)
1708 {
1709 	unsigned int i;
1710 
1711 	for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1712 		struct sort_dimension *sd = &common_sort_dimensions[i];
1713 
1714 		if (strncasecmp(tok, sd->name, strlen(tok)))
1715 			continue;
1716 
1717 		return __sort_dimension__add_output(sd);
1718 	}
1719 
1720 	for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1721 		struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1722 
1723 		if (strncasecmp(tok, hd->name, strlen(tok)))
1724 			continue;
1725 
1726 		return __hpp_dimension__add_output(hd);
1727 	}
1728 
1729 	for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1730 		struct sort_dimension *sd = &bstack_sort_dimensions[i];
1731 
1732 		if (strncasecmp(tok, sd->name, strlen(tok)))
1733 			continue;
1734 
1735 		return __sort_dimension__add_output(sd);
1736 	}
1737 
1738 	for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1739 		struct sort_dimension *sd = &memory_sort_dimensions[i];
1740 
1741 		if (strncasecmp(tok, sd->name, strlen(tok)))
1742 			continue;
1743 
1744 		return __sort_dimension__add_output(sd);
1745 	}
1746 
1747 	return -ESRCH;
1748 }
1749 
1750 static void reset_dimensions(void)
1751 {
1752 	unsigned int i;
1753 
1754 	for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1755 		common_sort_dimensions[i].taken = 0;
1756 
1757 	for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1758 		hpp_sort_dimensions[i].taken = 0;
1759 
1760 	for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1761 		bstack_sort_dimensions[i].taken = 0;
1762 
1763 	for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1764 		memory_sort_dimensions[i].taken = 0;
1765 }
1766 
1767 bool is_strict_order(const char *order)
1768 {
1769 	return order && (*order != '+');
1770 }
1771 
1772 static int __setup_output_field(void)
1773 {
1774 	char *tmp, *tok, *str, *strp;
1775 	int ret = -EINVAL;
1776 
1777 	if (field_order == NULL)
1778 		return 0;
1779 
1780 	reset_dimensions();
1781 
1782 	strp = str = strdup(field_order);
1783 	if (str == NULL) {
1784 		error("Not enough memory to setup output fields");
1785 		return -ENOMEM;
1786 	}
1787 
1788 	if (!is_strict_order(field_order))
1789 		strp++;
1790 
1791 	if (!strlen(strp)) {
1792 		error("Invalid --fields key: `+'");
1793 		goto out;
1794 	}
1795 
1796 	for (tok = strtok_r(strp, ", ", &tmp);
1797 			tok; tok = strtok_r(NULL, ", ", &tmp)) {
1798 		ret = output_field_add(tok);
1799 		if (ret == -EINVAL) {
1800 			error("Invalid --fields key: `%s'", tok);
1801 			break;
1802 		} else if (ret == -ESRCH) {
1803 			error("Unknown --fields key: `%s'", tok);
1804 			break;
1805 		}
1806 	}
1807 
1808 out:
1809 	free(str);
1810 	return ret;
1811 }
1812 
1813 int setup_sorting(void)
1814 {
1815 	int err;
1816 
1817 	err = __setup_sorting();
1818 	if (err < 0)
1819 		return err;
1820 
1821 	if (parent_pattern != default_parent_pattern) {
1822 		err = sort_dimension__add("parent");
1823 		if (err < 0)
1824 			return err;
1825 	}
1826 
1827 	reset_dimensions();
1828 
1829 	/*
1830 	 * perf diff doesn't use default hpp output fields.
1831 	 */
1832 	if (sort__mode != SORT_MODE__DIFF)
1833 		perf_hpp__init();
1834 
1835 	err = __setup_output_field();
1836 	if (err < 0)
1837 		return err;
1838 
1839 	/* copy sort keys to output fields */
1840 	perf_hpp__setup_output_field();
1841 	/* and then copy output fields to sort keys */
1842 	perf_hpp__append_sort_keys();
1843 
1844 	return 0;
1845 }
1846 
1847 void reset_output_field(void)
1848 {
1849 	sort__need_collapse = 0;
1850 	sort__has_parent = 0;
1851 	sort__has_sym = 0;
1852 	sort__has_dso = 0;
1853 
1854 	field_order = NULL;
1855 	sort_order = NULL;
1856 
1857 	reset_dimensions();
1858 	perf_hpp__reset_output_field();
1859 }
1860