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