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