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