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