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