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