perf sort: Reorder HISTC_SRCLINE index
[deliverable/linux.git] / tools / perf / util / sort.c
CommitLineData
dd68ada2 1#include "sort.h"
8a6c5b26 2#include "hist.h"
08e71542 3#include "symbol.h"
dd68ada2
JK
4
5regex_t parent_regex;
edb7c60e
ACM
6const char default_parent_pattern[] = "^sys_|^do_page_fault";
7const char *parent_pattern = default_parent_pattern;
8const char default_sort_order[] = "comm,dso,symbol";
9const char *sort_order = default_sort_order;
af0a6fa4
FW
10int sort__need_collapse = 0;
11int sort__has_parent = 0;
1af55640 12int sort__has_sym = 0;
55369fc1 13enum sort_mode sort__mode = SORT_MODE__NORMAL;
a4fb581b
FW
14
15enum sort_type sort__first_dimension;
dd68ada2 16
dd68ada2
JK
17LIST_HEAD(hist_entry__sort_list);
18
a4e3b956 19static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
dd68ada2
JK
20{
21 int n;
22 va_list ap;
23
24 va_start(ap, fmt);
a4e3b956 25 n = vsnprintf(bf, size, fmt, ap);
0ca0c130 26 if (symbol_conf.field_sep && n > 0) {
a4e3b956
ACM
27 char *sep = bf;
28
29 while (1) {
0ca0c130 30 sep = strchr(sep, *symbol_conf.field_sep);
a4e3b956
ACM
31 if (sep == NULL)
32 break;
33 *sep = '.';
dd68ada2 34 }
dd68ada2
JK
35 }
36 va_end(ap);
b832796c
AB
37
38 if (n >= (int)size)
39 return size - 1;
dd68ada2
JK
40 return n;
41}
42
872a878f
FW
43static int64_t cmp_null(void *l, void *r)
44{
45 if (!l && !r)
46 return 0;
47 else if (!l)
48 return -1;
49 else
50 return 1;
51}
52
53/* --sort pid */
54
55static int64_t
56sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
57{
58 return right->thread->pid - left->thread->pid;
59}
60
a4e3b956
ACM
61static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
62 size_t size, unsigned int width)
dd68ada2 63{
fb29a338 64 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
dd68ada2
JK
65 self->thread->comm ?: "", self->thread->pid);
66}
67
872a878f
FW
68struct sort_entry sort_thread = {
69 .se_header = "Command: Pid",
70 .se_cmp = sort__thread_cmp,
71 .se_snprintf = hist_entry__thread_snprintf,
72 .se_width_idx = HISTC_THREAD,
73};
74
75/* --sort comm */
76
77static int64_t
78sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
79{
80 return right->thread->pid - left->thread->pid;
81}
82
83static int64_t
84sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
85{
86 char *comm_l = left->thread->comm;
87 char *comm_r = right->thread->comm;
88
89 if (!comm_l || !comm_r)
90 return cmp_null(comm_l, comm_r);
91
92 return strcmp(comm_l, comm_r);
93}
94
a4e3b956
ACM
95static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
96 size_t size, unsigned int width)
dd68ada2 97{
a4e3b956 98 return repsep_snprintf(bf, size, "%*s", width, self->thread->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
149static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
150 size_t size, unsigned int width)
151{
152 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
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{
14d1ac74
NK
183 if (!left->ms.sym && !right->ms.sym)
184 return right->level - left->level;
dd68ada2 185
51f27d14 186 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
b5387528
RAV
187}
188
189static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
190 u64 ip, char level, char *bf, size_t size,
43355522 191 unsigned int width)
b5387528
RAV
192{
193 size_t ret = 0;
194
195 if (verbose) {
196 char o = map ? dso__symtab_origin(map->dso) : '!';
197 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
ded19d57 198 BITS_PER_LONG / 4 + 2, ip, o);
439d473b 199 }
dd68ada2 200
b5387528 201 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
98a3b32c
SE
202 if (sym && map) {
203 if (map->type == MAP__VARIABLE) {
204 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
205 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
62667746 206 ip - map->unmap_ip(map, sym->start));
98a3b32c
SE
207 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
208 width - ret, "");
209 } else {
210 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
211 width - ret,
212 sym->name);
213 }
214 } else {
b5387528
RAV
215 size_t len = BITS_PER_LONG / 4;
216 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
217 len, ip);
218 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
219 width - ret, "");
220 }
221
222 return ret;
dd68ada2
JK
223}
224
b5387528 225static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
43355522 226 size_t size, unsigned int width)
b5387528
RAV
227{
228 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
229 self->level, bf, size, width);
230}
dd68ada2 231
872a878f
FW
232struct sort_entry sort_sym = {
233 .se_header = "Symbol",
234 .se_cmp = sort__sym_cmp,
235 .se_snprintf = hist_entry__sym_snprintf,
236 .se_width_idx = HISTC_SYMBOL,
237};
dd68ada2 238
409a8be6
ACM
239/* --sort srcline */
240
241static int64_t
242sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
243{
244 return (int64_t)(right->ip - left->ip);
245}
246
247static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
1d037ca1
IT
248 size_t size,
249 unsigned int width __maybe_unused)
409a8be6 250{
8eb44dd7 251 FILE *fp = NULL;
409a8be6
ACM
252 char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
253 size_t line_len;
254
255 if (path != NULL)
256 goto out_path;
257
ffe10c6f
NK
258 if (!self->ms.map)
259 goto out_ip;
260
88481b6b
NK
261 if (!strncmp(self->ms.map->dso->long_name, "/tmp/perf-", 10))
262 goto out_ip;
263
409a8be6
ACM
264 snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64,
265 self->ms.map->dso->long_name, self->ip);
266 fp = popen(cmd, "r");
267 if (!fp)
268 goto out_ip;
269
270 if (getline(&path, &line_len, fp) < 0 || !line_len)
271 goto out_ip;
409a8be6
ACM
272 self->srcline = strdup(path);
273 if (self->srcline == NULL)
274 goto out_ip;
275
276 nl = strchr(self->srcline, '\n');
277 if (nl != NULL)
278 *nl = '\0';
279 path = self->srcline;
280out_path:
8eb44dd7
TJ
281 if (fp)
282 pclose(fp);
409a8be6
ACM
283 return repsep_snprintf(bf, size, "%s", path);
284out_ip:
8eb44dd7
TJ
285 if (fp)
286 pclose(fp);
409a8be6
ACM
287 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
288}
289
290struct sort_entry sort_srcline = {
291 .se_header = "Source:Line",
292 .se_cmp = sort__srcline_cmp,
293 .se_snprintf = hist_entry__srcline_snprintf,
294 .se_width_idx = HISTC_SRCLINE,
295};
296
dd68ada2
JK
297/* --sort parent */
298
872a878f 299static int64_t
dd68ada2
JK
300sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
301{
302 struct symbol *sym_l = left->parent;
303 struct symbol *sym_r = right->parent;
304
305 if (!sym_l || !sym_r)
306 return cmp_null(sym_l, sym_r);
307
308 return strcmp(sym_l->name, sym_r->name);
309}
310
a4e3b956
ACM
311static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
312 size_t size, unsigned int width)
dd68ada2 313{
a4e3b956 314 return repsep_snprintf(bf, size, "%-*s", width,
dd68ada2
JK
315 self->parent ? self->parent->name : "[other]");
316}
317
872a878f
FW
318struct sort_entry sort_parent = {
319 .se_header = "Parent symbol",
320 .se_cmp = sort__parent_cmp,
321 .se_snprintf = hist_entry__parent_snprintf,
322 .se_width_idx = HISTC_PARENT,
323};
324
f60f3593
AS
325/* --sort cpu */
326
872a878f 327static int64_t
f60f3593
AS
328sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
329{
330 return right->cpu - left->cpu;
331}
332
333static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
334 size_t size, unsigned int width)
335{
dccf1805 336 return repsep_snprintf(bf, size, "%*d", width, self->cpu);
f60f3593
AS
337}
338
872a878f
FW
339struct sort_entry sort_cpu = {
340 .se_header = "CPU",
341 .se_cmp = sort__cpu_cmp,
342 .se_snprintf = hist_entry__cpu_snprintf,
343 .se_width_idx = HISTC_CPU,
344};
345
14d1ac74
NK
346/* sort keys for branch stacks */
347
b5387528
RAV
348static int64_t
349sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
350{
351 return _sort__dso_cmp(left->branch_info->from.map,
352 right->branch_info->from.map);
353}
354
355static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
356 size_t size, unsigned int width)
357{
358 return _hist_entry__dso_snprintf(self->branch_info->from.map,
359 bf, size, width);
360}
361
b5387528
RAV
362static int64_t
363sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
364{
365 return _sort__dso_cmp(left->branch_info->to.map,
366 right->branch_info->to.map);
367}
368
369static int hist_entry__dso_to_snprintf(struct hist_entry *self, char *bf,
370 size_t size, unsigned int width)
371{
372 return _hist_entry__dso_snprintf(self->branch_info->to.map,
373 bf, size, width);
374}
375
376static int64_t
377sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
378{
379 struct addr_map_symbol *from_l = &left->branch_info->from;
380 struct addr_map_symbol *from_r = &right->branch_info->from;
381
382 if (!from_l->sym && !from_r->sym)
383 return right->level - left->level;
384
51f27d14 385 return _sort__sym_cmp(from_l->sym, from_r->sym);
b5387528
RAV
386}
387
388static int64_t
389sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
390{
391 struct addr_map_symbol *to_l = &left->branch_info->to;
392 struct addr_map_symbol *to_r = &right->branch_info->to;
393
394 if (!to_l->sym && !to_r->sym)
395 return right->level - left->level;
396
51f27d14 397 return _sort__sym_cmp(to_l->sym, to_r->sym);
b5387528
RAV
398}
399
400static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
43355522 401 size_t size, unsigned int width)
b5387528
RAV
402{
403 struct addr_map_symbol *from = &self->branch_info->from;
404 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
405 self->level, bf, size, width);
406
407}
408
409static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
43355522 410 size_t size, unsigned int width)
b5387528
RAV
411{
412 struct addr_map_symbol *to = &self->branch_info->to;
413 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
414 self->level, bf, size, width);
415
416}
417
14d1ac74
NK
418struct sort_entry sort_dso_from = {
419 .se_header = "Source Shared Object",
420 .se_cmp = sort__dso_from_cmp,
421 .se_snprintf = hist_entry__dso_from_snprintf,
422 .se_width_idx = HISTC_DSO_FROM,
423};
424
b5387528
RAV
425struct sort_entry sort_dso_to = {
426 .se_header = "Target Shared Object",
427 .se_cmp = sort__dso_to_cmp,
428 .se_snprintf = hist_entry__dso_to_snprintf,
429 .se_width_idx = HISTC_DSO_TO,
430};
431
432struct sort_entry sort_sym_from = {
433 .se_header = "Source Symbol",
434 .se_cmp = sort__sym_from_cmp,
435 .se_snprintf = hist_entry__sym_from_snprintf,
436 .se_width_idx = HISTC_SYMBOL_FROM,
437};
438
439struct sort_entry sort_sym_to = {
440 .se_header = "Target Symbol",
441 .se_cmp = sort__sym_to_cmp,
442 .se_snprintf = hist_entry__sym_to_snprintf,
443 .se_width_idx = HISTC_SYMBOL_TO,
444};
445
446static int64_t
447sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
448{
449 const unsigned char mp = left->branch_info->flags.mispred !=
450 right->branch_info->flags.mispred;
451 const unsigned char p = left->branch_info->flags.predicted !=
452 right->branch_info->flags.predicted;
453
454 return mp || p;
455}
456
457static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf,
458 size_t size, unsigned int width){
459 static const char *out = "N/A";
460
461 if (self->branch_info->flags.predicted)
462 out = "N";
463 else if (self->branch_info->flags.mispred)
464 out = "Y";
465
466 return repsep_snprintf(bf, size, "%-*s", width, out);
467}
468
98a3b32c
SE
469/* --sort daddr_sym */
470static int64_t
471sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
472{
473 uint64_t l = 0, r = 0;
474
475 if (left->mem_info)
476 l = left->mem_info->daddr.addr;
477 if (right->mem_info)
478 r = right->mem_info->daddr.addr;
479
480 return (int64_t)(r - l);
481}
482
483static int hist_entry__daddr_snprintf(struct hist_entry *self, char *bf,
484 size_t size, unsigned int width)
485{
486 uint64_t addr = 0;
487 struct map *map = NULL;
488 struct symbol *sym = NULL;
489
490 if (self->mem_info) {
491 addr = self->mem_info->daddr.addr;
492 map = self->mem_info->daddr.map;
493 sym = self->mem_info->daddr.sym;
494 }
495 return _hist_entry__sym_snprintf(map, sym, addr, self->level, bf, size,
496 width);
497}
498
499static int64_t
500sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
501{
502 struct map *map_l = NULL;
503 struct map *map_r = NULL;
504
505 if (left->mem_info)
506 map_l = left->mem_info->daddr.map;
507 if (right->mem_info)
508 map_r = right->mem_info->daddr.map;
509
510 return _sort__dso_cmp(map_l, map_r);
511}
512
513static int hist_entry__dso_daddr_snprintf(struct hist_entry *self, char *bf,
514 size_t size, unsigned int width)
515{
516 struct map *map = NULL;
517
518 if (self->mem_info)
519 map = self->mem_info->daddr.map;
520
521 return _hist_entry__dso_snprintf(map, bf, size, width);
522}
523
524static int64_t
525sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
526{
527 union perf_mem_data_src data_src_l;
528 union perf_mem_data_src data_src_r;
529
530 if (left->mem_info)
531 data_src_l = left->mem_info->data_src;
532 else
533 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
534
535 if (right->mem_info)
536 data_src_r = right->mem_info->data_src;
537 else
538 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
539
540 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
541}
542
543static int hist_entry__locked_snprintf(struct hist_entry *self, char *bf,
544 size_t size, unsigned int width)
545{
546 const char *out;
547 u64 mask = PERF_MEM_LOCK_NA;
548
549 if (self->mem_info)
550 mask = self->mem_info->data_src.mem_lock;
551
552 if (mask & PERF_MEM_LOCK_NA)
553 out = "N/A";
554 else if (mask & PERF_MEM_LOCK_LOCKED)
555 out = "Yes";
556 else
557 out = "No";
558
559 return repsep_snprintf(bf, size, "%-*s", width, out);
560}
561
562static int64_t
563sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
564{
565 union perf_mem_data_src data_src_l;
566 union perf_mem_data_src data_src_r;
567
568 if (left->mem_info)
569 data_src_l = left->mem_info->data_src;
570 else
571 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
572
573 if (right->mem_info)
574 data_src_r = right->mem_info->data_src;
575 else
576 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
577
578 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
579}
580
581static const char * const tlb_access[] = {
582 "N/A",
583 "HIT",
584 "MISS",
585 "L1",
586 "L2",
587 "Walker",
588 "Fault",
589};
590#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
591
592static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf,
593 size_t size, unsigned int width)
594{
595 char out[64];
596 size_t sz = sizeof(out) - 1; /* -1 for null termination */
597 size_t l = 0, i;
598 u64 m = PERF_MEM_TLB_NA;
599 u64 hit, miss;
600
601 out[0] = '\0';
602
603 if (self->mem_info)
604 m = self->mem_info->data_src.mem_dtlb;
605
606 hit = m & PERF_MEM_TLB_HIT;
607 miss = m & PERF_MEM_TLB_MISS;
608
609 /* already taken care of */
610 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
611
612 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
613 if (!(m & 0x1))
614 continue;
615 if (l) {
616 strcat(out, " or ");
617 l += 4;
618 }
619 strncat(out, tlb_access[i], sz - l);
620 l += strlen(tlb_access[i]);
621 }
622 if (*out == '\0')
623 strcpy(out, "N/A");
624 if (hit)
625 strncat(out, " hit", sz - l);
626 if (miss)
627 strncat(out, " miss", sz - l);
628
629 return repsep_snprintf(bf, size, "%-*s", width, out);
630}
631
632static int64_t
633sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
634{
635 union perf_mem_data_src data_src_l;
636 union perf_mem_data_src data_src_r;
637
638 if (left->mem_info)
639 data_src_l = left->mem_info->data_src;
640 else
641 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
642
643 if (right->mem_info)
644 data_src_r = right->mem_info->data_src;
645 else
646 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
647
648 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
649}
650
651static const char * const mem_lvl[] = {
652 "N/A",
653 "HIT",
654 "MISS",
655 "L1",
656 "LFB",
657 "L2",
658 "L3",
659 "Local RAM",
660 "Remote RAM (1 hop)",
661 "Remote RAM (2 hops)",
662 "Remote Cache (1 hop)",
663 "Remote Cache (2 hops)",
664 "I/O",
665 "Uncached",
666};
667#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
668
669static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf,
670 size_t size, unsigned int width)
671{
672 char out[64];
673 size_t sz = sizeof(out) - 1; /* -1 for null termination */
674 size_t i, l = 0;
675 u64 m = PERF_MEM_LVL_NA;
676 u64 hit, miss;
677
678 if (self->mem_info)
679 m = self->mem_info->data_src.mem_lvl;
680
681 out[0] = '\0';
682
683 hit = m & PERF_MEM_LVL_HIT;
684 miss = m & PERF_MEM_LVL_MISS;
685
686 /* already taken care of */
687 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
688
689 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
690 if (!(m & 0x1))
691 continue;
692 if (l) {
693 strcat(out, " or ");
694 l += 4;
695 }
696 strncat(out, mem_lvl[i], sz - l);
697 l += strlen(mem_lvl[i]);
698 }
699 if (*out == '\0')
700 strcpy(out, "N/A");
701 if (hit)
702 strncat(out, " hit", sz - l);
703 if (miss)
704 strncat(out, " miss", sz - l);
705
706 return repsep_snprintf(bf, size, "%-*s", width, out);
707}
708
709static int64_t
710sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
711{
712 union perf_mem_data_src data_src_l;
713 union perf_mem_data_src data_src_r;
714
715 if (left->mem_info)
716 data_src_l = left->mem_info->data_src;
717 else
718 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
719
720 if (right->mem_info)
721 data_src_r = right->mem_info->data_src;
722 else
723 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
724
725 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
726}
727
728static const char * const snoop_access[] = {
729 "N/A",
730 "None",
731 "Miss",
732 "Hit",
733 "HitM",
734};
735#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
736
737static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf,
738 size_t size, unsigned int width)
739{
740 char out[64];
741 size_t sz = sizeof(out) - 1; /* -1 for null termination */
742 size_t i, l = 0;
743 u64 m = PERF_MEM_SNOOP_NA;
744
745 out[0] = '\0';
746
747 if (self->mem_info)
748 m = self->mem_info->data_src.mem_snoop;
749
750 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
751 if (!(m & 0x1))
752 continue;
753 if (l) {
754 strcat(out, " or ");
755 l += 4;
756 }
757 strncat(out, snoop_access[i], sz - l);
758 l += strlen(snoop_access[i]);
759 }
760
761 if (*out == '\0')
762 strcpy(out, "N/A");
763
764 return repsep_snprintf(bf, size, "%-*s", width, out);
765}
766
b5387528
RAV
767struct sort_entry sort_mispredict = {
768 .se_header = "Branch Mispredicted",
769 .se_cmp = sort__mispredict_cmp,
770 .se_snprintf = hist_entry__mispredict_snprintf,
771 .se_width_idx = HISTC_MISPREDICT,
772};
773
05484298
AK
774static u64 he_weight(struct hist_entry *he)
775{
776 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
777}
778
779static int64_t
780sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
781{
782 return he_weight(left) - he_weight(right);
783}
784
785static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf,
786 size_t size, unsigned int width)
787{
788 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self));
789}
790
791struct sort_entry sort_local_weight = {
792 .se_header = "Local Weight",
793 .se_cmp = sort__local_weight_cmp,
794 .se_snprintf = hist_entry__local_weight_snprintf,
795 .se_width_idx = HISTC_LOCAL_WEIGHT,
796};
797
798static int64_t
799sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
800{
801 return left->stat.weight - right->stat.weight;
802}
803
804static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf,
805 size_t size, unsigned int width)
806{
807 return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight);
808}
809
810struct sort_entry sort_global_weight = {
811 .se_header = "Weight",
812 .se_cmp = sort__global_weight_cmp,
813 .se_snprintf = hist_entry__global_weight_snprintf,
814 .se_width_idx = HISTC_GLOBAL_WEIGHT,
815};
816
98a3b32c
SE
817struct sort_entry sort_mem_daddr_sym = {
818 .se_header = "Data Symbol",
819 .se_cmp = sort__daddr_cmp,
820 .se_snprintf = hist_entry__daddr_snprintf,
821 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
822};
823
824struct sort_entry sort_mem_daddr_dso = {
825 .se_header = "Data Object",
826 .se_cmp = sort__dso_daddr_cmp,
827 .se_snprintf = hist_entry__dso_daddr_snprintf,
828 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
829};
830
831struct sort_entry sort_mem_locked = {
832 .se_header = "Locked",
833 .se_cmp = sort__locked_cmp,
834 .se_snprintf = hist_entry__locked_snprintf,
835 .se_width_idx = HISTC_MEM_LOCKED,
836};
837
838struct sort_entry sort_mem_tlb = {
839 .se_header = "TLB access",
840 .se_cmp = sort__tlb_cmp,
841 .se_snprintf = hist_entry__tlb_snprintf,
842 .se_width_idx = HISTC_MEM_TLB,
843};
844
845struct sort_entry sort_mem_lvl = {
846 .se_header = "Memory access",
847 .se_cmp = sort__lvl_cmp,
848 .se_snprintf = hist_entry__lvl_snprintf,
849 .se_width_idx = HISTC_MEM_LVL,
850};
851
852struct sort_entry sort_mem_snoop = {
853 .se_header = "Snoop",
854 .se_cmp = sort__snoop_cmp,
855 .se_snprintf = hist_entry__snoop_snprintf,
856 .se_width_idx = HISTC_MEM_SNOOP,
857};
858
872a878f
FW
859struct sort_dimension {
860 const char *name;
861 struct sort_entry *entry;
862 int taken;
863};
864
b5387528
RAV
865#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
866
fc5871ed 867static struct sort_dimension common_sort_dimensions[] = {
b5387528
RAV
868 DIM(SORT_PID, "pid", sort_thread),
869 DIM(SORT_COMM, "comm", sort_comm),
870 DIM(SORT_DSO, "dso", sort_dso),
b5387528 871 DIM(SORT_SYM, "symbol", sort_sym),
b5387528
RAV
872 DIM(SORT_PARENT, "parent", sort_parent),
873 DIM(SORT_CPU, "cpu", sort_cpu),
409a8be6 874 DIM(SORT_SRCLINE, "srcline", sort_srcline),
872a878f
FW
875};
876
fc5871ed
NK
877#undef DIM
878
879#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
880
881static struct sort_dimension bstack_sort_dimensions[] = {
882 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
883 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
884 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
885 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
886 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
887};
888
889#undef DIM
890
afab87b9
NK
891#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
892
893static struct sort_dimension memory_sort_dimensions[] = {
894 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
895 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
896 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
897 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
898 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
899 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
900 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
901 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
902};
903
904#undef DIM
905
2f532d09
NK
906static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
907{
908 if (sd->taken)
909 return;
910
911 if (sd->entry->se_collapse)
912 sort__need_collapse = 1;
913
914 if (list_empty(&hist_entry__sort_list))
915 sort__first_dimension = idx;
916
917 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
918 sd->taken = 1;
919}
920
dd68ada2
JK
921int sort_dimension__add(const char *tok)
922{
923 unsigned int i;
924
fc5871ed
NK
925 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
926 struct sort_dimension *sd = &common_sort_dimensions[i];
dd68ada2 927
dd68ada2
JK
928 if (strncasecmp(tok, sd->name, strlen(tok)))
929 continue;
fc5871ed 930
dd68ada2
JK
931 if (sd->entry == &sort_parent) {
932 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
933 if (ret) {
934 char err[BUFSIZ];
935
936 regerror(ret, &parent_regex, err, sizeof(err));
2aefa4f7
ACM
937 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
938 return -EINVAL;
dd68ada2
JK
939 }
940 sort__has_parent = 1;
98a3b32c
SE
941 } else if (sd->entry == &sort_sym ||
942 sd->entry == &sort_sym_from ||
943 sd->entry == &sort_sym_to ||
944 sd->entry == &sort_mem_daddr_sym) {
1af55640 945 sort__has_sym = 1;
dd68ada2
JK
946 }
947
2f532d09 948 __sort_dimension__add(sd, i);
dd68ada2
JK
949 return 0;
950 }
fc5871ed
NK
951
952 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
953 struct sort_dimension *sd = &bstack_sort_dimensions[i];
954
955 if (strncasecmp(tok, sd->name, strlen(tok)))
956 continue;
957
55369fc1 958 if (sort__mode != SORT_MODE__BRANCH)
fc5871ed
NK
959 return -EINVAL;
960
961 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
962 sort__has_sym = 1;
963
2f532d09 964 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
fc5871ed
NK
965 return 0;
966 }
967
afab87b9
NK
968 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
969 struct sort_dimension *sd = &memory_sort_dimensions[i];
970
971 if (strncasecmp(tok, sd->name, strlen(tok)))
972 continue;
973
974 if (sort__mode != SORT_MODE__MEMORY)
975 return -EINVAL;
976
977 if (sd->entry == &sort_mem_daddr_sym)
978 sort__has_sym = 1;
979
980 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
981 return 0;
982 }
983
dd68ada2
JK
984 return -ESRCH;
985}
c8829c7a 986
55309985 987int setup_sorting(void)
c8829c7a
ACM
988{
989 char *tmp, *tok, *str = strdup(sort_order);
55309985 990 int ret = 0;
c8829c7a 991
5936f54d
NK
992 if (str == NULL) {
993 error("Not enough memory to setup sort keys");
994 return -ENOMEM;
995 }
996
c8829c7a
ACM
997 for (tok = strtok_r(str, ", ", &tmp);
998 tok; tok = strtok_r(NULL, ", ", &tmp)) {
55309985 999 ret = sort_dimension__add(tok);
fc5871ed
NK
1000 if (ret == -EINVAL) {
1001 error("Invalid --sort key: `%s'", tok);
55309985 1002 break;
fc5871ed 1003 } else if (ret == -ESRCH) {
c8829c7a 1004 error("Unknown --sort key: `%s'", tok);
55309985 1005 break;
c8829c7a
ACM
1006 }
1007 }
1008
1009 free(str);
55309985 1010 return ret;
c8829c7a 1011}
c351c281 1012
08e71542
NK
1013static void sort_entry__setup_elide(struct sort_entry *self,
1014 struct strlist *list,
1015 const char *list_name, FILE *fp)
c351c281
ACM
1016{
1017 if (list && strlist__nr_entries(list) == 1) {
1018 if (fp != NULL)
1019 fprintf(fp, "# %s: %s\n", list_name,
1020 strlist__entry(list, 0)->s);
1021 self->elide = true;
1022 }
1023}
08e71542
NK
1024
1025void sort__setup_elide(FILE *output)
1026{
1027 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1028 "dso", output);
1029 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1030 "comm", output);
1031 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1032 "symbol", output);
1033
1034 if (sort__mode == SORT_MODE__BRANCH) {
1035 sort_entry__setup_elide(&sort_dso_from,
1036 symbol_conf.dso_from_list,
1037 "dso_from", output);
1038 sort_entry__setup_elide(&sort_dso_to,
1039 symbol_conf.dso_to_list,
1040 "dso_to", output);
1041 sort_entry__setup_elide(&sort_sym_from,
1042 symbol_conf.sym_from_list,
1043 "sym_from", output);
1044 sort_entry__setup_elide(&sort_sym_to,
1045 symbol_conf.sym_to_list,
1046 "sym_to", output);
1047 } else if (sort__mode == SORT_MODE__MEMORY) {
1048 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1049 "symbol_daddr", output);
1050 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1051 "dso_daddr", output);
1052 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1053 "mem", output);
1054 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1055 "local_weight", output);
1056 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1057 "tlb", output);
1058 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1059 "snoop", output);
1060 }
1061
1062}
This page took 0.211922 seconds and 5 git commands to generate.