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