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