f732120e8bc69eeb6e31608aa559e577a0f14c71
[platform/adaptation/renesas_rcar/renesas_kernel.git] / tools / perf / util / sort.c
1 #include "sort.h"
2 #include "hist.h"
3 #include "symbol.h"
4
5 regex_t         parent_regex;
6 const char      default_parent_pattern[] = "^sys_|^do_page_fault";
7 const char      *parent_pattern = default_parent_pattern;
8 const char      default_sort_order[] = "comm,dso,symbol";
9 const char      *sort_order = default_sort_order;
10 regex_t         ignore_callees_regex;
11 int             have_ignore_callees = 0;
12 int             sort__need_collapse = 0;
13 int             sort__has_parent = 0;
14 int             sort__has_sym = 0;
15 enum sort_mode  sort__mode = SORT_MODE__NORMAL;
16
17 enum sort_type  sort__first_dimension;
18
19 LIST_HEAD(hist_entry__sort_list);
20
21 static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
22 {
23         int n;
24         va_list ap;
25
26         va_start(ap, fmt);
27         n = vsnprintf(bf, size, fmt, ap);
28         if (symbol_conf.field_sep && n > 0) {
29                 char *sep = bf;
30
31                 while (1) {
32                         sep = strchr(sep, *symbol_conf.field_sep);
33                         if (sep == NULL)
34                                 break;
35                         *sep = '.';
36                 }
37         }
38         va_end(ap);
39
40         if (n >= (int)size)
41                 return size - 1;
42         return n;
43 }
44
45 static int64_t cmp_null(void *l, void *r)
46 {
47         if (!l && !r)
48                 return 0;
49         else if (!l)
50                 return -1;
51         else
52                 return 1;
53 }
54
55 /* --sort pid */
56
57 static int64_t
58 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
59 {
60         return right->thread->tid - left->thread->tid;
61 }
62
63 static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
64                                        size_t size, unsigned int width)
65 {
66         return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
67                               self->thread->comm ?: "", self->thread->tid);
68 }
69
70 struct sort_entry sort_thread = {
71         .se_header      = "Command:  Pid",
72         .se_cmp         = sort__thread_cmp,
73         .se_snprintf    = hist_entry__thread_snprintf,
74         .se_width_idx   = HISTC_THREAD,
75 };
76
77 /* --sort comm */
78
79 static int64_t
80 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
81 {
82         return right->thread->tid - left->thread->tid;
83 }
84
85 static int64_t
86 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
87 {
88         char *comm_l = left->thread->comm;
89         char *comm_r = right->thread->comm;
90
91         if (!comm_l || !comm_r)
92                 return cmp_null(comm_l, comm_r);
93
94         return strcmp(comm_l, comm_r);
95 }
96
97 static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
98                                      size_t size, unsigned int width)
99 {
100         return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
101 }
102
103 struct sort_entry sort_comm = {
104         .se_header      = "Command",
105         .se_cmp         = sort__comm_cmp,
106         .se_collapse    = sort__comm_collapse,
107         .se_snprintf    = hist_entry__comm_snprintf,
108         .se_width_idx   = HISTC_COMM,
109 };
110
111 /* --sort dso */
112
113 static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
114 {
115         struct dso *dso_l = map_l ? map_l->dso : NULL;
116         struct dso *dso_r = map_r ? map_r->dso : NULL;
117         const char *dso_name_l, *dso_name_r;
118
119         if (!dso_l || !dso_r)
120                 return cmp_null(dso_l, dso_r);
121
122         if (verbose) {
123                 dso_name_l = dso_l->long_name;
124                 dso_name_r = dso_r->long_name;
125         } else {
126                 dso_name_l = dso_l->short_name;
127                 dso_name_r = dso_r->short_name;
128         }
129
130         return strcmp(dso_name_l, dso_name_r);
131 }
132
133 static int64_t
134 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
135 {
136         return _sort__dso_cmp(left->ms.map, right->ms.map);
137 }
138
139 static int _hist_entry__dso_snprintf(struct map *map, char *bf,
140                                      size_t size, unsigned int width)
141 {
142         if (map && map->dso) {
143                 const char *dso_name = !verbose ? map->dso->short_name :
144                         map->dso->long_name;
145                 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
146         }
147
148         return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
149 }
150
151 static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
152                                     size_t size, unsigned int width)
153 {
154         return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
155 }
156
157 struct sort_entry sort_dso = {
158         .se_header      = "Shared Object",
159         .se_cmp         = sort__dso_cmp,
160         .se_snprintf    = hist_entry__dso_snprintf,
161         .se_width_idx   = HISTC_DSO,
162 };
163
164 /* --sort symbol */
165
166 static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
167 {
168         u64 ip_l, ip_r;
169
170         if (!sym_l || !sym_r)
171                 return cmp_null(sym_l, sym_r);
172
173         if (sym_l == sym_r)
174                 return 0;
175
176         ip_l = sym_l->start;
177         ip_r = sym_r->start;
178
179         return (int64_t)(ip_r - ip_l);
180 }
181
182 static int64_t
183 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
184 {
185         if (!left->ms.sym && !right->ms.sym)
186                 return right->level - left->level;
187
188         return _sort__sym_cmp(left->ms.sym, right->ms.sym);
189 }
190
191 static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
192                                      u64 ip, char level, char *bf, size_t size,
193                                      unsigned int width)
194 {
195         size_t ret = 0;
196
197         if (verbose) {
198                 char o = map ? dso__symtab_origin(map->dso) : '!';
199                 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
200                                        BITS_PER_LONG / 4 + 2, ip, o);
201         }
202
203         ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
204         if (sym && map) {
205                 if (map->type == MAP__VARIABLE) {
206                         ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
207                         ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
208                                         ip - map->unmap_ip(map, sym->start));
209                         ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
210                                        width - ret, "");
211                 } else {
212                         ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
213                                                width - ret,
214                                                sym->name);
215                 }
216         } else {
217                 size_t len = BITS_PER_LONG / 4;
218                 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
219                                        len, ip);
220                 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
221                                        width - ret, "");
222         }
223
224         return ret;
225 }
226
227 static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
228                                     size_t size, unsigned int width)
229 {
230         return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
231                                          self->level, bf, size, width);
232 }
233
234 struct sort_entry sort_sym = {
235         .se_header      = "Symbol",
236         .se_cmp         = sort__sym_cmp,
237         .se_snprintf    = hist_entry__sym_snprintf,
238         .se_width_idx   = HISTC_SYMBOL,
239 };
240
241 /* --sort srcline */
242
243 static int64_t
244 sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
245 {
246         return (int64_t)(right->ip - left->ip);
247 }
248
249 static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
250                                         size_t size,
251                                         unsigned int width __maybe_unused)
252 {
253         FILE *fp = NULL;
254         char *path = self->srcline;
255
256         if (path != NULL)
257                 goto out_path;
258
259         if (!self->ms.map)
260                 goto out_ip;
261
262         path = get_srcline(self->ms.map->dso, self->ip);
263         self->srcline = path;
264
265 out_path:
266         if (fp)
267                 pclose(fp);
268         return repsep_snprintf(bf, size, "%s", path);
269 out_ip:
270         if (fp)
271                 pclose(fp);
272         return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
273 }
274
275 struct sort_entry sort_srcline = {
276         .se_header      = "Source:Line",
277         .se_cmp         = sort__srcline_cmp,
278         .se_snprintf    = hist_entry__srcline_snprintf,
279         .se_width_idx   = HISTC_SRCLINE,
280 };
281
282 /* --sort parent */
283
284 static int64_t
285 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
286 {
287         struct symbol *sym_l = left->parent;
288         struct symbol *sym_r = right->parent;
289
290         if (!sym_l || !sym_r)
291                 return cmp_null(sym_l, sym_r);
292
293         return strcmp(sym_l->name, sym_r->name);
294 }
295
296 static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
297                                        size_t size, unsigned int width)
298 {
299         return repsep_snprintf(bf, size, "%-*s", width,
300                               self->parent ? self->parent->name : "[other]");
301 }
302
303 struct sort_entry sort_parent = {
304         .se_header      = "Parent symbol",
305         .se_cmp         = sort__parent_cmp,
306         .se_snprintf    = hist_entry__parent_snprintf,
307         .se_width_idx   = HISTC_PARENT,
308 };
309
310 /* --sort cpu */
311
312 static int64_t
313 sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
314 {
315         return right->cpu - left->cpu;
316 }
317
318 static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
319                                        size_t size, unsigned int width)
320 {
321         return repsep_snprintf(bf, size, "%*d", width, self->cpu);
322 }
323
324 struct sort_entry sort_cpu = {
325         .se_header      = "CPU",
326         .se_cmp         = sort__cpu_cmp,
327         .se_snprintf    = hist_entry__cpu_snprintf,
328         .se_width_idx   = HISTC_CPU,
329 };
330
331 /* sort keys for branch stacks */
332
333 static int64_t
334 sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
335 {
336         return _sort__dso_cmp(left->branch_info->from.map,
337                               right->branch_info->from.map);
338 }
339
340 static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
341                                     size_t size, unsigned int width)
342 {
343         return _hist_entry__dso_snprintf(self->branch_info->from.map,
344                                          bf, size, width);
345 }
346
347 static int64_t
348 sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
349 {
350         return _sort__dso_cmp(left->branch_info->to.map,
351                               right->branch_info->to.map);
352 }
353
354 static int hist_entry__dso_to_snprintf(struct hist_entry *self, char *bf,
355                                        size_t size, unsigned int width)
356 {
357         return _hist_entry__dso_snprintf(self->branch_info->to.map,
358                                          bf, size, width);
359 }
360
361 static int64_t
362 sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
363 {
364         struct addr_map_symbol *from_l = &left->branch_info->from;
365         struct addr_map_symbol *from_r = &right->branch_info->from;
366
367         if (!from_l->sym && !from_r->sym)
368                 return right->level - left->level;
369
370         return _sort__sym_cmp(from_l->sym, from_r->sym);
371 }
372
373 static int64_t
374 sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
375 {
376         struct addr_map_symbol *to_l = &left->branch_info->to;
377         struct addr_map_symbol *to_r = &right->branch_info->to;
378
379         if (!to_l->sym && !to_r->sym)
380                 return right->level - left->level;
381
382         return _sort__sym_cmp(to_l->sym, to_r->sym);
383 }
384
385 static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
386                                          size_t size, unsigned int width)
387 {
388         struct addr_map_symbol *from = &self->branch_info->from;
389         return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
390                                          self->level, bf, size, width);
391
392 }
393
394 static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
395                                        size_t size, unsigned int width)
396 {
397         struct addr_map_symbol *to = &self->branch_info->to;
398         return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
399                                          self->level, bf, size, width);
400
401 }
402
403 struct sort_entry sort_dso_from = {
404         .se_header      = "Source Shared Object",
405         .se_cmp         = sort__dso_from_cmp,
406         .se_snprintf    = hist_entry__dso_from_snprintf,
407         .se_width_idx   = HISTC_DSO_FROM,
408 };
409
410 struct sort_entry sort_dso_to = {
411         .se_header      = "Target Shared Object",
412         .se_cmp         = sort__dso_to_cmp,
413         .se_snprintf    = hist_entry__dso_to_snprintf,
414         .se_width_idx   = HISTC_DSO_TO,
415 };
416
417 struct sort_entry sort_sym_from = {
418         .se_header      = "Source Symbol",
419         .se_cmp         = sort__sym_from_cmp,
420         .se_snprintf    = hist_entry__sym_from_snprintf,
421         .se_width_idx   = HISTC_SYMBOL_FROM,
422 };
423
424 struct sort_entry sort_sym_to = {
425         .se_header      = "Target Symbol",
426         .se_cmp         = sort__sym_to_cmp,
427         .se_snprintf    = hist_entry__sym_to_snprintf,
428         .se_width_idx   = HISTC_SYMBOL_TO,
429 };
430
431 static int64_t
432 sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
433 {
434         const unsigned char mp = left->branch_info->flags.mispred !=
435                                         right->branch_info->flags.mispred;
436         const unsigned char p = left->branch_info->flags.predicted !=
437                                         right->branch_info->flags.predicted;
438
439         return mp || p;
440 }
441
442 static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf,
443                                     size_t size, unsigned int width){
444         static const char *out = "N/A";
445
446         if (self->branch_info->flags.predicted)
447                 out = "N";
448         else if (self->branch_info->flags.mispred)
449                 out = "Y";
450
451         return repsep_snprintf(bf, size, "%-*s", width, out);
452 }
453
454 /* --sort daddr_sym */
455 static int64_t
456 sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
457 {
458         uint64_t l = 0, r = 0;
459
460         if (left->mem_info)
461                 l = left->mem_info->daddr.addr;
462         if (right->mem_info)
463                 r = right->mem_info->daddr.addr;
464
465         return (int64_t)(r - l);
466 }
467
468 static int hist_entry__daddr_snprintf(struct hist_entry *self, char *bf,
469                                     size_t size, unsigned int width)
470 {
471         uint64_t addr = 0;
472         struct map *map = NULL;
473         struct symbol *sym = NULL;
474
475         if (self->mem_info) {
476                 addr = self->mem_info->daddr.addr;
477                 map = self->mem_info->daddr.map;
478                 sym = self->mem_info->daddr.sym;
479         }
480         return _hist_entry__sym_snprintf(map, sym, addr, self->level, bf, size,
481                                          width);
482 }
483
484 static int64_t
485 sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
486 {
487         struct map *map_l = NULL;
488         struct map *map_r = NULL;
489
490         if (left->mem_info)
491                 map_l = left->mem_info->daddr.map;
492         if (right->mem_info)
493                 map_r = right->mem_info->daddr.map;
494
495         return _sort__dso_cmp(map_l, map_r);
496 }
497
498 static int hist_entry__dso_daddr_snprintf(struct hist_entry *self, char *bf,
499                                     size_t size, unsigned int width)
500 {
501         struct map *map = NULL;
502
503         if (self->mem_info)
504                 map = self->mem_info->daddr.map;
505
506         return _hist_entry__dso_snprintf(map, bf, size, width);
507 }
508
509 static int64_t
510 sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
511 {
512         union perf_mem_data_src data_src_l;
513         union perf_mem_data_src data_src_r;
514
515         if (left->mem_info)
516                 data_src_l = left->mem_info->data_src;
517         else
518                 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
519
520         if (right->mem_info)
521                 data_src_r = right->mem_info->data_src;
522         else
523                 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
524
525         return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
526 }
527
528 static int hist_entry__locked_snprintf(struct hist_entry *self, char *bf,
529                                     size_t size, unsigned int width)
530 {
531         const char *out;
532         u64 mask = PERF_MEM_LOCK_NA;
533
534         if (self->mem_info)
535                 mask = self->mem_info->data_src.mem_lock;
536
537         if (mask & PERF_MEM_LOCK_NA)
538                 out = "N/A";
539         else if (mask & PERF_MEM_LOCK_LOCKED)
540                 out = "Yes";
541         else
542                 out = "No";
543
544         return repsep_snprintf(bf, size, "%-*s", width, out);
545 }
546
547 static int64_t
548 sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
549 {
550         union perf_mem_data_src data_src_l;
551         union perf_mem_data_src data_src_r;
552
553         if (left->mem_info)
554                 data_src_l = left->mem_info->data_src;
555         else
556                 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
557
558         if (right->mem_info)
559                 data_src_r = right->mem_info->data_src;
560         else
561                 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
562
563         return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
564 }
565
566 static const char * const tlb_access[] = {
567         "N/A",
568         "HIT",
569         "MISS",
570         "L1",
571         "L2",
572         "Walker",
573         "Fault",
574 };
575 #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
576
577 static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf,
578                                     size_t size, unsigned int width)
579 {
580         char out[64];
581         size_t sz = sizeof(out) - 1; /* -1 for null termination */
582         size_t l = 0, i;
583         u64 m = PERF_MEM_TLB_NA;
584         u64 hit, miss;
585
586         out[0] = '\0';
587
588         if (self->mem_info)
589                 m = self->mem_info->data_src.mem_dtlb;
590
591         hit = m & PERF_MEM_TLB_HIT;
592         miss = m & PERF_MEM_TLB_MISS;
593
594         /* already taken care of */
595         m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
596
597         for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
598                 if (!(m & 0x1))
599                         continue;
600                 if (l) {
601                         strcat(out, " or ");
602                         l += 4;
603                 }
604                 strncat(out, tlb_access[i], sz - l);
605                 l += strlen(tlb_access[i]);
606         }
607         if (*out == '\0')
608                 strcpy(out, "N/A");
609         if (hit)
610                 strncat(out, " hit", sz - l);
611         if (miss)
612                 strncat(out, " miss", sz - l);
613
614         return repsep_snprintf(bf, size, "%-*s", width, out);
615 }
616
617 static int64_t
618 sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
619 {
620         union perf_mem_data_src data_src_l;
621         union perf_mem_data_src data_src_r;
622
623         if (left->mem_info)
624                 data_src_l = left->mem_info->data_src;
625         else
626                 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
627
628         if (right->mem_info)
629                 data_src_r = right->mem_info->data_src;
630         else
631                 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
632
633         return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
634 }
635
636 static const char * const mem_lvl[] = {
637         "N/A",
638         "HIT",
639         "MISS",
640         "L1",
641         "LFB",
642         "L2",
643         "L3",
644         "Local RAM",
645         "Remote RAM (1 hop)",
646         "Remote RAM (2 hops)",
647         "Remote Cache (1 hop)",
648         "Remote Cache (2 hops)",
649         "I/O",
650         "Uncached",
651 };
652 #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
653
654 static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf,
655                                     size_t size, unsigned int width)
656 {
657         char out[64];
658         size_t sz = sizeof(out) - 1; /* -1 for null termination */
659         size_t i, l = 0;
660         u64 m =  PERF_MEM_LVL_NA;
661         u64 hit, miss;
662
663         if (self->mem_info)
664                 m  = self->mem_info->data_src.mem_lvl;
665
666         out[0] = '\0';
667
668         hit = m & PERF_MEM_LVL_HIT;
669         miss = m & PERF_MEM_LVL_MISS;
670
671         /* already taken care of */
672         m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
673
674         for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
675                 if (!(m & 0x1))
676                         continue;
677                 if (l) {
678                         strcat(out, " or ");
679                         l += 4;
680                 }
681                 strncat(out, mem_lvl[i], sz - l);
682                 l += strlen(mem_lvl[i]);
683         }
684         if (*out == '\0')
685                 strcpy(out, "N/A");
686         if (hit)
687                 strncat(out, " hit", sz - l);
688         if (miss)
689                 strncat(out, " miss", sz - l);
690
691         return repsep_snprintf(bf, size, "%-*s", width, out);
692 }
693
694 static int64_t
695 sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
696 {
697         union perf_mem_data_src data_src_l;
698         union perf_mem_data_src data_src_r;
699
700         if (left->mem_info)
701                 data_src_l = left->mem_info->data_src;
702         else
703                 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
704
705         if (right->mem_info)
706                 data_src_r = right->mem_info->data_src;
707         else
708                 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
709
710         return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
711 }
712
713 static const char * const snoop_access[] = {
714         "N/A",
715         "None",
716         "Miss",
717         "Hit",
718         "HitM",
719 };
720 #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
721
722 static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf,
723                                     size_t size, unsigned int width)
724 {
725         char out[64];
726         size_t sz = sizeof(out) - 1; /* -1 for null termination */
727         size_t i, l = 0;
728         u64 m = PERF_MEM_SNOOP_NA;
729
730         out[0] = '\0';
731
732         if (self->mem_info)
733                 m = self->mem_info->data_src.mem_snoop;
734
735         for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
736                 if (!(m & 0x1))
737                         continue;
738                 if (l) {
739                         strcat(out, " or ");
740                         l += 4;
741                 }
742                 strncat(out, snoop_access[i], sz - l);
743                 l += strlen(snoop_access[i]);
744         }
745
746         if (*out == '\0')
747                 strcpy(out, "N/A");
748
749         return repsep_snprintf(bf, size, "%-*s", width, out);
750 }
751
752 struct sort_entry sort_mispredict = {
753         .se_header      = "Branch Mispredicted",
754         .se_cmp         = sort__mispredict_cmp,
755         .se_snprintf    = hist_entry__mispredict_snprintf,
756         .se_width_idx   = HISTC_MISPREDICT,
757 };
758
759 static u64 he_weight(struct hist_entry *he)
760 {
761         return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
762 }
763
764 static int64_t
765 sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
766 {
767         return he_weight(left) - he_weight(right);
768 }
769
770 static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf,
771                                     size_t size, unsigned int width)
772 {
773         return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self));
774 }
775
776 struct sort_entry sort_local_weight = {
777         .se_header      = "Local Weight",
778         .se_cmp         = sort__local_weight_cmp,
779         .se_snprintf    = hist_entry__local_weight_snprintf,
780         .se_width_idx   = HISTC_LOCAL_WEIGHT,
781 };
782
783 static int64_t
784 sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
785 {
786         return left->stat.weight - right->stat.weight;
787 }
788
789 static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf,
790                                               size_t size, unsigned int width)
791 {
792         return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight);
793 }
794
795 struct sort_entry sort_global_weight = {
796         .se_header      = "Weight",
797         .se_cmp         = sort__global_weight_cmp,
798         .se_snprintf    = hist_entry__global_weight_snprintf,
799         .se_width_idx   = HISTC_GLOBAL_WEIGHT,
800 };
801
802 struct sort_entry sort_mem_daddr_sym = {
803         .se_header      = "Data Symbol",
804         .se_cmp         = sort__daddr_cmp,
805         .se_snprintf    = hist_entry__daddr_snprintf,
806         .se_width_idx   = HISTC_MEM_DADDR_SYMBOL,
807 };
808
809 struct sort_entry sort_mem_daddr_dso = {
810         .se_header      = "Data Object",
811         .se_cmp         = sort__dso_daddr_cmp,
812         .se_snprintf    = hist_entry__dso_daddr_snprintf,
813         .se_width_idx   = HISTC_MEM_DADDR_SYMBOL,
814 };
815
816 struct sort_entry sort_mem_locked = {
817         .se_header      = "Locked",
818         .se_cmp         = sort__locked_cmp,
819         .se_snprintf    = hist_entry__locked_snprintf,
820         .se_width_idx   = HISTC_MEM_LOCKED,
821 };
822
823 struct sort_entry sort_mem_tlb = {
824         .se_header      = "TLB access",
825         .se_cmp         = sort__tlb_cmp,
826         .se_snprintf    = hist_entry__tlb_snprintf,
827         .se_width_idx   = HISTC_MEM_TLB,
828 };
829
830 struct sort_entry sort_mem_lvl = {
831         .se_header      = "Memory access",
832         .se_cmp         = sort__lvl_cmp,
833         .se_snprintf    = hist_entry__lvl_snprintf,
834         .se_width_idx   = HISTC_MEM_LVL,
835 };
836
837 struct sort_entry sort_mem_snoop = {
838         .se_header      = "Snoop",
839         .se_cmp         = sort__snoop_cmp,
840         .se_snprintf    = hist_entry__snoop_snprintf,
841         .se_width_idx   = HISTC_MEM_SNOOP,
842 };
843
844 static int64_t
845 sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
846 {
847         return left->branch_info->flags.abort !=
848                 right->branch_info->flags.abort;
849 }
850
851 static int hist_entry__abort_snprintf(struct hist_entry *self, char *bf,
852                                     size_t size, unsigned int width)
853 {
854         static const char *out = ".";
855
856         if (self->branch_info->flags.abort)
857                 out = "A";
858         return repsep_snprintf(bf, size, "%-*s", width, out);
859 }
860
861 struct sort_entry sort_abort = {
862         .se_header      = "Transaction abort",
863         .se_cmp         = sort__abort_cmp,
864         .se_snprintf    = hist_entry__abort_snprintf,
865         .se_width_idx   = HISTC_ABORT,
866 };
867
868 static int64_t
869 sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
870 {
871         return left->branch_info->flags.in_tx !=
872                 right->branch_info->flags.in_tx;
873 }
874
875 static int hist_entry__in_tx_snprintf(struct hist_entry *self, char *bf,
876                                     size_t size, unsigned int width)
877 {
878         static const char *out = ".";
879
880         if (self->branch_info->flags.in_tx)
881                 out = "T";
882
883         return repsep_snprintf(bf, size, "%-*s", width, out);
884 }
885
886 struct sort_entry sort_in_tx = {
887         .se_header      = "Branch in transaction",
888         .se_cmp         = sort__in_tx_cmp,
889         .se_snprintf    = hist_entry__in_tx_snprintf,
890         .se_width_idx   = HISTC_IN_TX,
891 };
892
893 static int64_t
894 sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
895 {
896         return left->transaction - right->transaction;
897 }
898
899 static inline char *add_str(char *p, const char *str)
900 {
901         strcpy(p, str);
902         return p + strlen(str);
903 }
904
905 static struct txbit {
906         unsigned flag;
907         const char *name;
908         int skip_for_len;
909 } txbits[] = {
910         { PERF_TXN_ELISION,        "EL ",        0 },
911         { PERF_TXN_TRANSACTION,    "TX ",        1 },
912         { PERF_TXN_SYNC,           "SYNC ",      1 },
913         { PERF_TXN_ASYNC,          "ASYNC ",     0 },
914         { PERF_TXN_RETRY,          "RETRY ",     0 },
915         { PERF_TXN_CONFLICT,       "CON ",       0 },
916         { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
917         { PERF_TXN_CAPACITY_READ,  "CAP-READ ",  0 },
918         { 0, NULL, 0 }
919 };
920
921 int hist_entry__transaction_len(void)
922 {
923         int i;
924         int len = 0;
925
926         for (i = 0; txbits[i].name; i++) {
927                 if (!txbits[i].skip_for_len)
928                         len += strlen(txbits[i].name);
929         }
930         len += 4; /* :XX<space> */
931         return len;
932 }
933
934 static int hist_entry__transaction_snprintf(struct hist_entry *self, char *bf,
935                                             size_t size, unsigned int width)
936 {
937         u64 t = self->transaction;
938         char buf[128];
939         char *p = buf;
940         int i;
941
942         buf[0] = 0;
943         for (i = 0; txbits[i].name; i++)
944                 if (txbits[i].flag & t)
945                         p = add_str(p, txbits[i].name);
946         if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
947                 p = add_str(p, "NEITHER ");
948         if (t & PERF_TXN_ABORT_MASK) {
949                 sprintf(p, ":%" PRIx64,
950                         (t & PERF_TXN_ABORT_MASK) >>
951                         PERF_TXN_ABORT_SHIFT);
952                 p += strlen(p);
953         }
954
955         return repsep_snprintf(bf, size, "%-*s", width, buf);
956 }
957
958 struct sort_entry sort_transaction = {
959         .se_header      = "Transaction                ",
960         .se_cmp         = sort__transaction_cmp,
961         .se_snprintf    = hist_entry__transaction_snprintf,
962         .se_width_idx   = HISTC_TRANSACTION,
963 };
964
965 struct sort_dimension {
966         const char              *name;
967         struct sort_entry       *entry;
968         int                     taken;
969 };
970
971 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
972
973 static struct sort_dimension common_sort_dimensions[] = {
974         DIM(SORT_PID, "pid", sort_thread),
975         DIM(SORT_COMM, "comm", sort_comm),
976         DIM(SORT_DSO, "dso", sort_dso),
977         DIM(SORT_SYM, "symbol", sort_sym),
978         DIM(SORT_PARENT, "parent", sort_parent),
979         DIM(SORT_CPU, "cpu", sort_cpu),
980         DIM(SORT_SRCLINE, "srcline", sort_srcline),
981         DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
982         DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
983         DIM(SORT_TRANSACTION, "transaction", sort_transaction),
984 };
985
986 #undef DIM
987
988 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
989
990 static struct sort_dimension bstack_sort_dimensions[] = {
991         DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
992         DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
993         DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
994         DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
995         DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
996         DIM(SORT_IN_TX, "in_tx", sort_in_tx),
997         DIM(SORT_ABORT, "abort", sort_abort),
998 };
999
1000 #undef DIM
1001
1002 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1003
1004 static struct sort_dimension memory_sort_dimensions[] = {
1005         DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1006         DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1007         DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1008         DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1009         DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1010         DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1011 };
1012
1013 #undef DIM
1014
1015 static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
1016 {
1017         if (sd->taken)
1018                 return;
1019
1020         if (sd->entry->se_collapse)
1021                 sort__need_collapse = 1;
1022
1023         if (list_empty(&hist_entry__sort_list))
1024                 sort__first_dimension = idx;
1025
1026         list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1027         sd->taken = 1;
1028 }
1029
1030 int sort_dimension__add(const char *tok)
1031 {
1032         unsigned int i;
1033
1034         for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1035                 struct sort_dimension *sd = &common_sort_dimensions[i];
1036
1037                 if (strncasecmp(tok, sd->name, strlen(tok)))
1038                         continue;
1039
1040                 if (sd->entry == &sort_parent) {
1041                         int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1042                         if (ret) {
1043                                 char err[BUFSIZ];
1044
1045                                 regerror(ret, &parent_regex, err, sizeof(err));
1046                                 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1047                                 return -EINVAL;
1048                         }
1049                         sort__has_parent = 1;
1050                 } else if (sd->entry == &sort_sym) {
1051                         sort__has_sym = 1;
1052                 }
1053
1054                 __sort_dimension__add(sd, i);
1055                 return 0;
1056         }
1057
1058         for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1059                 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1060
1061                 if (strncasecmp(tok, sd->name, strlen(tok)))
1062                         continue;
1063
1064                 if (sort__mode != SORT_MODE__BRANCH)
1065                         return -EINVAL;
1066
1067                 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1068                         sort__has_sym = 1;
1069
1070                 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
1071                 return 0;
1072         }
1073
1074         for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1075                 struct sort_dimension *sd = &memory_sort_dimensions[i];
1076
1077                 if (strncasecmp(tok, sd->name, strlen(tok)))
1078                         continue;
1079
1080                 if (sort__mode != SORT_MODE__MEMORY)
1081                         return -EINVAL;
1082
1083                 if (sd->entry == &sort_mem_daddr_sym)
1084                         sort__has_sym = 1;
1085
1086                 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
1087                 return 0;
1088         }
1089
1090         return -ESRCH;
1091 }
1092
1093 int setup_sorting(void)
1094 {
1095         char *tmp, *tok, *str = strdup(sort_order);
1096         int ret = 0;
1097
1098         if (str == NULL) {
1099                 error("Not enough memory to setup sort keys");
1100                 return -ENOMEM;
1101         }
1102
1103         for (tok = strtok_r(str, ", ", &tmp);
1104                         tok; tok = strtok_r(NULL, ", ", &tmp)) {
1105                 ret = sort_dimension__add(tok);
1106                 if (ret == -EINVAL) {
1107                         error("Invalid --sort key: `%s'", tok);
1108                         break;
1109                 } else if (ret == -ESRCH) {
1110                         error("Unknown --sort key: `%s'", tok);
1111                         break;
1112                 }
1113         }
1114
1115         free(str);
1116         return ret;
1117 }
1118
1119 static void sort_entry__setup_elide(struct sort_entry *self,
1120                                     struct strlist *list,
1121                                     const char *list_name, FILE *fp)
1122 {
1123         if (list && strlist__nr_entries(list) == 1) {
1124                 if (fp != NULL)
1125                         fprintf(fp, "# %s: %s\n", list_name,
1126                                 strlist__entry(list, 0)->s);
1127                 self->elide = true;
1128         }
1129 }
1130
1131 void sort__setup_elide(FILE *output)
1132 {
1133         sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1134                                 "dso", output);
1135         sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1136                                 "comm", output);
1137         sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1138                                 "symbol", output);
1139
1140         if (sort__mode == SORT_MODE__BRANCH) {
1141                 sort_entry__setup_elide(&sort_dso_from,
1142                                         symbol_conf.dso_from_list,
1143                                         "dso_from", output);
1144                 sort_entry__setup_elide(&sort_dso_to,
1145                                         symbol_conf.dso_to_list,
1146                                         "dso_to", output);
1147                 sort_entry__setup_elide(&sort_sym_from,
1148                                         symbol_conf.sym_from_list,
1149                                         "sym_from", output);
1150                 sort_entry__setup_elide(&sort_sym_to,
1151                                         symbol_conf.sym_to_list,
1152                                         "sym_to", output);
1153         } else if (sort__mode == SORT_MODE__MEMORY) {
1154                 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1155                                         "symbol_daddr", output);
1156                 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1157                                         "dso_daddr", output);
1158                 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1159                                         "mem", output);
1160                 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1161                                         "local_weight", output);
1162                 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1163                                         "tlb", output);
1164                 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1165                                         "snoop", output);
1166         }
1167
1168 }