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