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