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