]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - tools/perf/util/sort.c
Merge tag 'master-2014-12-01' of git://git.kernel.org/pub/scm/linux/kernel/git/linvil...
[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 comm__str(right->comm) - comm__str(left->comm);
93 }
94
95 static int64_t
96 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
97 {
98         /* Compare the addr that should be unique among comm */
99         return comm__str(right->comm) - comm__str(left->comm);
100 }
101
102 static int64_t
103 sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
104 {
105         return strcmp(comm__str(right->comm), comm__str(left->comm));
106 }
107
108 static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
109                                      size_t size, unsigned int width)
110 {
111         return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
112 }
113
114 struct sort_entry sort_comm = {
115         .se_header      = "Command",
116         .se_cmp         = sort__comm_cmp,
117         .se_collapse    = sort__comm_collapse,
118         .se_sort        = sort__comm_sort,
119         .se_snprintf    = hist_entry__comm_snprintf,
120         .se_width_idx   = HISTC_COMM,
121 };
122
123 /* --sort dso */
124
125 static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
126 {
127         struct dso *dso_l = map_l ? map_l->dso : NULL;
128         struct dso *dso_r = map_r ? map_r->dso : NULL;
129         const char *dso_name_l, *dso_name_r;
130
131         if (!dso_l || !dso_r)
132                 return cmp_null(dso_r, dso_l);
133
134         if (verbose) {
135                 dso_name_l = dso_l->long_name;
136                 dso_name_r = dso_r->long_name;
137         } else {
138                 dso_name_l = dso_l->short_name;
139                 dso_name_r = dso_r->short_name;
140         }
141
142         return strcmp(dso_name_l, dso_name_r);
143 }
144
145 static int64_t
146 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
147 {
148         return _sort__dso_cmp(right->ms.map, left->ms.map);
149 }
150
151 static int _hist_entry__dso_snprintf(struct map *map, char *bf,
152                                      size_t size, unsigned int width)
153 {
154         if (map && map->dso) {
155                 const char *dso_name = !verbose ? map->dso->short_name :
156                         map->dso->long_name;
157                 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
158         }
159
160         return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
161 }
162
163 static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
164                                     size_t size, unsigned int width)
165 {
166         return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
167 }
168
169 struct sort_entry sort_dso = {
170         .se_header      = "Shared Object",
171         .se_cmp         = sort__dso_cmp,
172         .se_snprintf    = hist_entry__dso_snprintf,
173         .se_width_idx   = HISTC_DSO,
174 };
175
176 /* --sort symbol */
177
178 static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
179 {
180         return (int64_t)(right_ip - left_ip);
181 }
182
183 static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
184 {
185         u64 ip_l, ip_r;
186
187         if (!sym_l || !sym_r)
188                 return cmp_null(sym_l, sym_r);
189
190         if (sym_l == sym_r)
191                 return 0;
192
193         ip_l = sym_l->start;
194         ip_r = sym_r->start;
195
196         return (int64_t)(ip_r - ip_l);
197 }
198
199 static int64_t
200 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
201 {
202         int64_t ret;
203
204         if (!left->ms.sym && !right->ms.sym)
205                 return _sort__addr_cmp(left->ip, right->ip);
206
207         /*
208          * comparing symbol address alone is not enough since it's a
209          * relative address within a dso.
210          */
211         if (!sort__has_dso) {
212                 ret = sort__dso_cmp(left, right);
213                 if (ret != 0)
214                         return ret;
215         }
216
217         return _sort__sym_cmp(left->ms.sym, right->ms.sym);
218 }
219
220 static int64_t
221 sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
222 {
223         if (!left->ms.sym || !right->ms.sym)
224                 return cmp_null(left->ms.sym, right->ms.sym);
225
226         return strcmp(right->ms.sym->name, left->ms.sym->name);
227 }
228
229 static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
230                                      u64 ip, char level, char *bf, size_t size,
231                                      unsigned int width)
232 {
233         size_t ret = 0;
234
235         if (verbose) {
236                 char o = map ? dso__symtab_origin(map->dso) : '!';
237                 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
238                                        BITS_PER_LONG / 4 + 2, ip, o);
239         }
240
241         ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
242         if (sym && map) {
243                 if (map->type == MAP__VARIABLE) {
244                         ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
245                         ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
246                                         ip - map->unmap_ip(map, sym->start));
247                         ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
248                                        width - ret, "");
249                 } else {
250                         ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
251                                                width - ret,
252                                                sym->name);
253                 }
254         } else {
255                 size_t len = BITS_PER_LONG / 4;
256                 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
257                                        len, ip);
258                 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
259                                        width - ret, "");
260         }
261
262         if (ret > width)
263                 bf[width] = '\0';
264
265         return width;
266 }
267
268 static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
269                                     size_t size, unsigned int width)
270 {
271         return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
272                                          he->level, bf, size, width);
273 }
274
275 struct sort_entry sort_sym = {
276         .se_header      = "Symbol",
277         .se_cmp         = sort__sym_cmp,
278         .se_sort        = sort__sym_sort,
279         .se_snprintf    = hist_entry__sym_snprintf,
280         .se_width_idx   = HISTC_SYMBOL,
281 };
282
283 /* --sort srcline */
284
285 static int64_t
286 sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
287 {
288         if (!left->srcline) {
289                 if (!left->ms.map)
290                         left->srcline = SRCLINE_UNKNOWN;
291                 else {
292                         struct map *map = left->ms.map;
293                         left->srcline = get_srcline(map->dso,
294                                             map__rip_2objdump(map, left->ip));
295                 }
296         }
297         if (!right->srcline) {
298                 if (!right->ms.map)
299                         right->srcline = SRCLINE_UNKNOWN;
300                 else {
301                         struct map *map = right->ms.map;
302                         right->srcline = get_srcline(map->dso,
303                                             map__rip_2objdump(map, right->ip));
304                 }
305         }
306         return strcmp(right->srcline, left->srcline);
307 }
308
309 static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
310                                         size_t size, unsigned int width)
311 {
312         return repsep_snprintf(bf, size, "%*.*-s", width, width, he->srcline);
313 }
314
315 struct sort_entry sort_srcline = {
316         .se_header      = "Source:Line",
317         .se_cmp         = sort__srcline_cmp,
318         .se_snprintf    = hist_entry__srcline_snprintf,
319         .se_width_idx   = HISTC_SRCLINE,
320 };
321
322 /* --sort parent */
323
324 static int64_t
325 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
326 {
327         struct symbol *sym_l = left->parent;
328         struct symbol *sym_r = right->parent;
329
330         if (!sym_l || !sym_r)
331                 return cmp_null(sym_l, sym_r);
332
333         return strcmp(sym_r->name, sym_l->name);
334 }
335
336 static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
337                                        size_t size, unsigned int width)
338 {
339         return repsep_snprintf(bf, size, "%-*.*s", width, width,
340                               he->parent ? he->parent->name : "[other]");
341 }
342
343 struct sort_entry sort_parent = {
344         .se_header      = "Parent symbol",
345         .se_cmp         = sort__parent_cmp,
346         .se_snprintf    = hist_entry__parent_snprintf,
347         .se_width_idx   = HISTC_PARENT,
348 };
349
350 /* --sort cpu */
351
352 static int64_t
353 sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
354 {
355         return right->cpu - left->cpu;
356 }
357
358 static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
359                                     size_t size, unsigned int width)
360 {
361         return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
362 }
363
364 struct sort_entry sort_cpu = {
365         .se_header      = "CPU",
366         .se_cmp         = sort__cpu_cmp,
367         .se_snprintf    = hist_entry__cpu_snprintf,
368         .se_width_idx   = HISTC_CPU,
369 };
370
371 /* sort keys for branch stacks */
372
373 static int64_t
374 sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
375 {
376         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 struct hpp_sort_entry *
1306 __sort_dimension__alloc_hpp(struct sort_dimension *sd)
1307 {
1308         struct hpp_sort_entry *hse;
1309
1310         hse = malloc(sizeof(*hse));
1311         if (hse == NULL) {
1312                 pr_err("Memory allocation failed\n");
1313                 return NULL;
1314         }
1315
1316         hse->se = sd->entry;
1317         hse->hpp.name = sd->entry->se_header;
1318         hse->hpp.header = __sort__hpp_header;
1319         hse->hpp.width = __sort__hpp_width;
1320         hse->hpp.entry = __sort__hpp_entry;
1321         hse->hpp.color = NULL;
1322
1323         hse->hpp.cmp = sd->entry->se_cmp;
1324         hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
1325         hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
1326
1327         INIT_LIST_HEAD(&hse->hpp.list);
1328         INIT_LIST_HEAD(&hse->hpp.sort_list);
1329         hse->hpp.elide = false;
1330         hse->hpp.len = 0;
1331         hse->hpp.user_len = 0;
1332
1333         return hse;
1334 }
1335
1336 bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1337 {
1338         return format->header == __sort__hpp_header;
1339 }
1340
1341 static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1342 {
1343         struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1344
1345         if (hse == NULL)
1346                 return -1;
1347
1348         perf_hpp__register_sort_field(&hse->hpp);
1349         return 0;
1350 }
1351
1352 static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1353 {
1354         struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1355
1356         if (hse == NULL)
1357                 return -1;
1358
1359         perf_hpp__column_register(&hse->hpp);
1360         return 0;
1361 }
1362
1363 static int __sort_dimension__add(struct sort_dimension *sd)
1364 {
1365         if (sd->taken)
1366                 return 0;
1367
1368         if (__sort_dimension__add_hpp_sort(sd) < 0)
1369                 return -1;
1370
1371         if (sd->entry->se_collapse)
1372                 sort__need_collapse = 1;
1373
1374         sd->taken = 1;
1375
1376         return 0;
1377 }
1378
1379 static int __hpp_dimension__add(struct hpp_dimension *hd)
1380 {
1381         if (!hd->taken) {
1382                 hd->taken = 1;
1383
1384                 perf_hpp__register_sort_field(hd->fmt);
1385         }
1386         return 0;
1387 }
1388
1389 static int __sort_dimension__add_output(struct sort_dimension *sd)
1390 {
1391         if (sd->taken)
1392                 return 0;
1393
1394         if (__sort_dimension__add_hpp_output(sd) < 0)
1395                 return -1;
1396
1397         sd->taken = 1;
1398         return 0;
1399 }
1400
1401 static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1402 {
1403         if (!hd->taken) {
1404                 hd->taken = 1;
1405
1406                 perf_hpp__column_register(hd->fmt);
1407         }
1408         return 0;
1409 }
1410
1411 int sort_dimension__add(const char *tok)
1412 {
1413         unsigned int i;
1414
1415         for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1416                 struct sort_dimension *sd = &common_sort_dimensions[i];
1417
1418                 if (strncasecmp(tok, sd->name, strlen(tok)))
1419                         continue;
1420
1421                 if (sd->entry == &sort_parent) {
1422                         int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1423                         if (ret) {
1424                                 char err[BUFSIZ];
1425
1426                                 regerror(ret, &parent_regex, err, sizeof(err));
1427                                 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1428                                 return -EINVAL;
1429                         }
1430                         sort__has_parent = 1;
1431                 } else if (sd->entry == &sort_sym) {
1432                         sort__has_sym = 1;
1433                 } else if (sd->entry == &sort_dso) {
1434                         sort__has_dso = 1;
1435                 }
1436
1437                 return __sort_dimension__add(sd);
1438         }
1439
1440         for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1441                 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1442
1443                 if (strncasecmp(tok, hd->name, strlen(tok)))
1444                         continue;
1445
1446                 return __hpp_dimension__add(hd);
1447         }
1448
1449         for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1450                 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1451
1452                 if (strncasecmp(tok, sd->name, strlen(tok)))
1453                         continue;
1454
1455                 if (sort__mode != SORT_MODE__BRANCH)
1456                         return -EINVAL;
1457
1458                 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1459                         sort__has_sym = 1;
1460
1461                 __sort_dimension__add(sd);
1462                 return 0;
1463         }
1464
1465         for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1466                 struct sort_dimension *sd = &memory_sort_dimensions[i];
1467
1468                 if (strncasecmp(tok, sd->name, strlen(tok)))
1469                         continue;
1470
1471                 if (sort__mode != SORT_MODE__MEMORY)
1472                         return -EINVAL;
1473
1474                 if (sd->entry == &sort_mem_daddr_sym)
1475                         sort__has_sym = 1;
1476
1477                 __sort_dimension__add(sd);
1478                 return 0;
1479         }
1480
1481         return -ESRCH;
1482 }
1483
1484 static const char *get_default_sort_order(void)
1485 {
1486         const char *default_sort_orders[] = {
1487                 default_sort_order,
1488                 default_branch_sort_order,
1489                 default_mem_sort_order,
1490                 default_top_sort_order,
1491                 default_diff_sort_order,
1492         };
1493
1494         BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1495
1496         return default_sort_orders[sort__mode];
1497 }
1498
1499 static int setup_sort_order(void)
1500 {
1501         char *new_sort_order;
1502
1503         /*
1504          * Append '+'-prefixed sort order to the default sort
1505          * order string.
1506          */
1507         if (!sort_order || is_strict_order(sort_order))
1508                 return 0;
1509
1510         if (sort_order[1] == '\0') {
1511                 error("Invalid --sort key: `+'");
1512                 return -EINVAL;
1513         }
1514
1515         /*
1516          * We allocate new sort_order string, but we never free it,
1517          * because it's checked over the rest of the code.
1518          */
1519         if (asprintf(&new_sort_order, "%s,%s",
1520                      get_default_sort_order(), sort_order + 1) < 0) {
1521                 error("Not enough memory to set up --sort");
1522                 return -ENOMEM;
1523         }
1524
1525         sort_order = new_sort_order;
1526         return 0;
1527 }
1528
1529 static int __setup_sorting(void)
1530 {
1531         char *tmp, *tok, *str;
1532         const char *sort_keys;
1533         int ret = 0;
1534
1535         ret = setup_sort_order();
1536         if (ret)
1537                 return ret;
1538
1539         sort_keys = sort_order;
1540         if (sort_keys == NULL) {
1541                 if (is_strict_order(field_order)) {
1542                         /*
1543                          * If user specified field order but no sort order,
1544                          * we'll honor it and not add default sort orders.
1545                          */
1546                         return 0;
1547                 }
1548
1549                 sort_keys = get_default_sort_order();
1550         }
1551
1552         str = strdup(sort_keys);
1553         if (str == NULL) {
1554                 error("Not enough memory to setup sort keys");
1555                 return -ENOMEM;
1556         }
1557
1558         for (tok = strtok_r(str, ", ", &tmp);
1559                         tok; tok = strtok_r(NULL, ", ", &tmp)) {
1560                 ret = sort_dimension__add(tok);
1561                 if (ret == -EINVAL) {
1562                         error("Invalid --sort key: `%s'", tok);
1563                         break;
1564                 } else if (ret == -ESRCH) {
1565                         error("Unknown --sort key: `%s'", tok);
1566                         break;
1567                 }
1568         }
1569
1570         free(str);
1571         return ret;
1572 }
1573
1574 void perf_hpp__set_elide(int idx, bool elide)
1575 {
1576         struct perf_hpp_fmt *fmt;
1577         struct hpp_sort_entry *hse;
1578
1579         perf_hpp__for_each_format(fmt) {
1580                 if (!perf_hpp__is_sort_entry(fmt))
1581                         continue;
1582
1583                 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1584                 if (hse->se->se_width_idx == idx) {
1585                         fmt->elide = elide;
1586                         break;
1587                 }
1588         }
1589 }
1590
1591 static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
1592 {
1593         if (list && strlist__nr_entries(list) == 1) {
1594                 if (fp != NULL)
1595                         fprintf(fp, "# %s: %s\n", list_name,
1596                                 strlist__entry(list, 0)->s);
1597                 return true;
1598         }
1599         return false;
1600 }
1601
1602 static bool get_elide(int idx, FILE *output)
1603 {
1604         switch (idx) {
1605         case HISTC_SYMBOL:
1606                 return __get_elide(symbol_conf.sym_list, "symbol", output);
1607         case HISTC_DSO:
1608                 return __get_elide(symbol_conf.dso_list, "dso", output);
1609         case HISTC_COMM:
1610                 return __get_elide(symbol_conf.comm_list, "comm", output);
1611         default:
1612                 break;
1613         }
1614
1615         if (sort__mode != SORT_MODE__BRANCH)
1616                 return false;
1617
1618         switch (idx) {
1619         case HISTC_SYMBOL_FROM:
1620                 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1621         case HISTC_SYMBOL_TO:
1622                 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1623         case HISTC_DSO_FROM:
1624                 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1625         case HISTC_DSO_TO:
1626                 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1627         default:
1628                 break;
1629         }
1630
1631         return false;
1632 }
1633
1634 void sort__setup_elide(FILE *output)
1635 {
1636         struct perf_hpp_fmt *fmt;
1637         struct hpp_sort_entry *hse;
1638
1639         perf_hpp__for_each_format(fmt) {
1640                 if (!perf_hpp__is_sort_entry(fmt))
1641                         continue;
1642
1643                 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1644                 fmt->elide = get_elide(hse->se->se_width_idx, output);
1645         }
1646
1647         /*
1648          * It makes no sense to elide all of sort entries.
1649          * Just revert them to show up again.
1650          */
1651         perf_hpp__for_each_format(fmt) {
1652                 if (!perf_hpp__is_sort_entry(fmt))
1653                         continue;
1654
1655                 if (!fmt->elide)
1656                         return;
1657         }
1658
1659         perf_hpp__for_each_format(fmt) {
1660                 if (!perf_hpp__is_sort_entry(fmt))
1661                         continue;
1662
1663                 fmt->elide = false;
1664         }
1665 }
1666
1667 static int output_field_add(char *tok)
1668 {
1669         unsigned int i;
1670
1671         for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1672                 struct sort_dimension *sd = &common_sort_dimensions[i];
1673
1674                 if (strncasecmp(tok, sd->name, strlen(tok)))
1675                         continue;
1676
1677                 return __sort_dimension__add_output(sd);
1678         }
1679
1680         for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1681                 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1682
1683                 if (strncasecmp(tok, hd->name, strlen(tok)))
1684                         continue;
1685
1686                 return __hpp_dimension__add_output(hd);
1687         }
1688
1689         for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1690                 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1691
1692                 if (strncasecmp(tok, sd->name, strlen(tok)))
1693                         continue;
1694
1695                 return __sort_dimension__add_output(sd);
1696         }
1697
1698         for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1699                 struct sort_dimension *sd = &memory_sort_dimensions[i];
1700
1701                 if (strncasecmp(tok, sd->name, strlen(tok)))
1702                         continue;
1703
1704                 return __sort_dimension__add_output(sd);
1705         }
1706
1707         return -ESRCH;
1708 }
1709
1710 static void reset_dimensions(void)
1711 {
1712         unsigned int i;
1713
1714         for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1715                 common_sort_dimensions[i].taken = 0;
1716
1717         for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1718                 hpp_sort_dimensions[i].taken = 0;
1719
1720         for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1721                 bstack_sort_dimensions[i].taken = 0;
1722
1723         for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1724                 memory_sort_dimensions[i].taken = 0;
1725 }
1726
1727 bool is_strict_order(const char *order)
1728 {
1729         return order && (*order != '+');
1730 }
1731
1732 static int __setup_output_field(void)
1733 {
1734         char *tmp, *tok, *str, *strp;
1735         int ret = -EINVAL;
1736
1737         if (field_order == NULL)
1738                 return 0;
1739
1740         reset_dimensions();
1741
1742         strp = str = strdup(field_order);
1743         if (str == NULL) {
1744                 error("Not enough memory to setup output fields");
1745                 return -ENOMEM;
1746         }
1747
1748         if (!is_strict_order(field_order))
1749                 strp++;
1750
1751         if (!strlen(strp)) {
1752                 error("Invalid --fields key: `+'");
1753                 goto out;
1754         }
1755
1756         for (tok = strtok_r(strp, ", ", &tmp);
1757                         tok; tok = strtok_r(NULL, ", ", &tmp)) {
1758                 ret = output_field_add(tok);
1759                 if (ret == -EINVAL) {
1760                         error("Invalid --fields key: `%s'", tok);
1761                         break;
1762                 } else if (ret == -ESRCH) {
1763                         error("Unknown --fields key: `%s'", tok);
1764                         break;
1765                 }
1766         }
1767
1768 out:
1769         free(str);
1770         return ret;
1771 }
1772
1773 int setup_sorting(void)
1774 {
1775         int err;
1776
1777         err = __setup_sorting();
1778         if (err < 0)
1779                 return err;
1780
1781         if (parent_pattern != default_parent_pattern) {
1782                 err = sort_dimension__add("parent");
1783                 if (err < 0)
1784                         return err;
1785         }
1786
1787         reset_dimensions();
1788
1789         /*
1790          * perf diff doesn't use default hpp output fields.
1791          */
1792         if (sort__mode != SORT_MODE__DIFF)
1793                 perf_hpp__init();
1794
1795         err = __setup_output_field();
1796         if (err < 0)
1797                 return err;
1798
1799         /* copy sort keys to output fields */
1800         perf_hpp__setup_output_field();
1801         /* and then copy output fields to sort keys */
1802         perf_hpp__append_sort_keys();
1803
1804         return 0;
1805 }
1806
1807 void reset_output_field(void)
1808 {
1809         sort__need_collapse = 0;
1810         sort__has_parent = 0;
1811         sort__has_sym = 0;
1812         sort__has_dso = 0;
1813
1814         field_order = NULL;
1815         sort_order = NULL;
1816
1817         reset_dimensions();
1818         perf_hpp__reset_output_field();
1819 }