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