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