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