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