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