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