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