Merge remote-tracking branch 'regulator/fix/act8865' into regulator-act8865
[cascardo/linux.git] / tools / perf / util / sort.c
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 }