fix a kmap leak in virtio_console
[linux/fpc-iii.git] / tools / perf / util / sort.c
blob635cd8f8b22ed14463fe4f7fd9357f9e663da41f
1 #include "sort.h"
2 #include "hist.h"
3 #include "comm.h"
4 #include "symbol.h"
6 regex_t parent_regex;
7 const char default_parent_pattern[] = "^sys_|^do_page_fault";
8 const char *parent_pattern = default_parent_pattern;
9 const char default_sort_order[] = "comm,dso,symbol";
10 const char *sort_order = default_sort_order;
11 regex_t ignore_callees_regex;
12 int have_ignore_callees = 0;
13 int sort__need_collapse = 0;
14 int sort__has_parent = 0;
15 int sort__has_sym = 0;
16 int sort__has_dso = 0;
17 enum sort_mode sort__mode = SORT_MODE__NORMAL;
19 enum sort_type sort__first_dimension;
21 LIST_HEAD(hist_entry__sort_list);
23 static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
25 int n;
26 va_list ap;
28 va_start(ap, fmt);
29 n = vsnprintf(bf, size, fmt, ap);
30 if (symbol_conf.field_sep && n > 0) {
31 char *sep = bf;
33 while (1) {
34 sep = strchr(sep, *symbol_conf.field_sep);
35 if (sep == NULL)
36 break;
37 *sep = '.';
40 va_end(ap);
42 if (n >= (int)size)
43 return size - 1;
44 return n;
47 static int64_t cmp_null(const void *l, const void *r)
49 if (!l && !r)
50 return 0;
51 else if (!l)
52 return -1;
53 else
54 return 1;
57 /* --sort pid */
59 static int64_t
60 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
62 return right->thread->tid - left->thread->tid;
65 static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
66 size_t size, unsigned int width)
68 const char *comm = thread__comm_str(he->thread);
69 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
70 comm ?: "", he->thread->tid);
73 struct sort_entry sort_thread = {
74 .se_header = "Command: Pid",
75 .se_cmp = sort__thread_cmp,
76 .se_snprintf = hist_entry__thread_snprintf,
77 .se_width_idx = HISTC_THREAD,
80 /* --sort comm */
82 static int64_t
83 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
85 /* Compare the addr that should be unique among comm */
86 return comm__str(right->comm) - comm__str(left->comm);
89 static int64_t
90 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
92 /* Compare the addr that should be unique among comm */
93 return comm__str(right->comm) - comm__str(left->comm);
96 static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
97 size_t size, unsigned int width)
99 return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
102 struct sort_entry sort_comm = {
103 .se_header = "Command",
104 .se_cmp = sort__comm_cmp,
105 .se_collapse = sort__comm_collapse,
106 .se_snprintf = hist_entry__comm_snprintf,
107 .se_width_idx = HISTC_COMM,
110 /* --sort dso */
112 static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
114 struct dso *dso_l = map_l ? map_l->dso : NULL;
115 struct dso *dso_r = map_r ? map_r->dso : NULL;
116 const char *dso_name_l, *dso_name_r;
118 if (!dso_l || !dso_r)
119 return cmp_null(dso_l, dso_r);
121 if (verbose) {
122 dso_name_l = dso_l->long_name;
123 dso_name_r = dso_r->long_name;
124 } else {
125 dso_name_l = dso_l->short_name;
126 dso_name_r = dso_r->short_name;
129 return strcmp(dso_name_l, dso_name_r);
132 static int64_t
133 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
135 return _sort__dso_cmp(left->ms.map, right->ms.map);
138 static int _hist_entry__dso_snprintf(struct map *map, char *bf,
139 size_t size, unsigned int width)
141 if (map && map->dso) {
142 const char *dso_name = !verbose ? map->dso->short_name :
143 map->dso->long_name;
144 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
147 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
150 static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
151 size_t size, unsigned int width)
153 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
156 struct sort_entry sort_dso = {
157 .se_header = "Shared Object",
158 .se_cmp = sort__dso_cmp,
159 .se_snprintf = hist_entry__dso_snprintf,
160 .se_width_idx = HISTC_DSO,
163 /* --sort symbol */
165 static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
167 return (int64_t)(right_ip - left_ip);
170 static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
172 u64 ip_l, ip_r;
174 if (!sym_l || !sym_r)
175 return cmp_null(sym_l, sym_r);
177 if (sym_l == sym_r)
178 return 0;
180 ip_l = sym_l->start;
181 ip_r = sym_r->start;
183 return (int64_t)(ip_r - ip_l);
186 static int64_t
187 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
189 int64_t ret;
191 if (!left->ms.sym && !right->ms.sym)
192 return _sort__addr_cmp(left->ip, right->ip);
195 * comparing symbol address alone is not enough since it's a
196 * relative address within a dso.
198 if (!sort__has_dso) {
199 ret = sort__dso_cmp(left, right);
200 if (ret != 0)
201 return ret;
204 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
207 static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
208 u64 ip, char level, char *bf, size_t size,
209 unsigned int width)
211 size_t ret = 0;
213 if (verbose) {
214 char o = map ? dso__symtab_origin(map->dso) : '!';
215 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
216 BITS_PER_LONG / 4 + 2, ip, o);
219 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
220 if (sym && map) {
221 if (map->type == MAP__VARIABLE) {
222 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
223 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
224 ip - map->unmap_ip(map, sym->start));
225 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
226 width - ret, "");
227 } else {
228 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
229 width - ret,
230 sym->name);
232 } else {
233 size_t len = BITS_PER_LONG / 4;
234 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
235 len, ip);
236 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
237 width - ret, "");
240 return ret;
243 static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
244 size_t size, unsigned int width)
246 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
247 he->level, bf, size, width);
250 struct sort_entry sort_sym = {
251 .se_header = "Symbol",
252 .se_cmp = sort__sym_cmp,
253 .se_snprintf = hist_entry__sym_snprintf,
254 .se_width_idx = HISTC_SYMBOL,
257 /* --sort srcline */
259 static int64_t
260 sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
262 if (!left->srcline) {
263 if (!left->ms.map)
264 left->srcline = SRCLINE_UNKNOWN;
265 else {
266 struct map *map = left->ms.map;
267 left->srcline = get_srcline(map->dso,
268 map__rip_2objdump(map, left->ip));
271 if (!right->srcline) {
272 if (!right->ms.map)
273 right->srcline = SRCLINE_UNKNOWN;
274 else {
275 struct map *map = right->ms.map;
276 right->srcline = get_srcline(map->dso,
277 map__rip_2objdump(map, right->ip));
280 return strcmp(left->srcline, right->srcline);
283 static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
284 size_t size,
285 unsigned int width __maybe_unused)
287 return repsep_snprintf(bf, size, "%s", he->srcline);
290 struct 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,
297 /* --sort parent */
299 static int64_t
300 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
302 struct symbol *sym_l = left->parent;
303 struct symbol *sym_r = right->parent;
305 if (!sym_l || !sym_r)
306 return cmp_null(sym_l, sym_r);
308 return strcmp(sym_l->name, sym_r->name);
311 static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
312 size_t size, unsigned int width)
314 return repsep_snprintf(bf, size, "%-*s", width,
315 he->parent ? he->parent->name : "[other]");
318 struct 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,
325 /* --sort cpu */
327 static int64_t
328 sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
330 return right->cpu - left->cpu;
333 static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
334 size_t size, unsigned int width)
336 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
339 struct 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,
346 /* sort keys for branch stacks */
348 static int64_t
349 sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
351 return _sort__dso_cmp(left->branch_info->from.map,
352 right->branch_info->from.map);
355 static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
356 size_t size, unsigned int width)
358 return _hist_entry__dso_snprintf(he->branch_info->from.map,
359 bf, size, width);
362 static int64_t
363 sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
365 return _sort__dso_cmp(left->branch_info->to.map,
366 right->branch_info->to.map);
369 static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
370 size_t size, unsigned int width)
372 return _hist_entry__dso_snprintf(he->branch_info->to.map,
373 bf, size, width);
376 static int64_t
377 sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
379 struct addr_map_symbol *from_l = &left->branch_info->from;
380 struct addr_map_symbol *from_r = &right->branch_info->from;
382 if (!from_l->sym && !from_r->sym)
383 return _sort__addr_cmp(from_l->addr, from_r->addr);
385 return _sort__sym_cmp(from_l->sym, from_r->sym);
388 static int64_t
389 sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
391 struct addr_map_symbol *to_l = &left->branch_info->to;
392 struct addr_map_symbol *to_r = &right->branch_info->to;
394 if (!to_l->sym && !to_r->sym)
395 return _sort__addr_cmp(to_l->addr, to_r->addr);
397 return _sort__sym_cmp(to_l->sym, to_r->sym);
400 static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
401 size_t size, unsigned int width)
403 struct addr_map_symbol *from = &he->branch_info->from;
404 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
405 he->level, bf, size, width);
409 static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
410 size_t size, unsigned int width)
412 struct addr_map_symbol *to = &he->branch_info->to;
413 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
414 he->level, bf, size, width);
418 struct 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,
425 struct 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,
432 struct 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,
439 struct 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,
446 static int64_t
447 sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
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;
454 return mp || p;
457 static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
458 size_t size, unsigned int width){
459 static const char *out = "N/A";
461 if (he->branch_info->flags.predicted)
462 out = "N";
463 else if (he->branch_info->flags.mispred)
464 out = "Y";
466 return repsep_snprintf(bf, size, "%-*s", width, out);
469 /* --sort daddr_sym */
470 static int64_t
471 sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
473 uint64_t l = 0, r = 0;
475 if (left->mem_info)
476 l = left->mem_info->daddr.addr;
477 if (right->mem_info)
478 r = right->mem_info->daddr.addr;
480 return (int64_t)(r - l);
483 static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
484 size_t size, unsigned int width)
486 uint64_t addr = 0;
487 struct map *map = NULL;
488 struct symbol *sym = NULL;
490 if (he->mem_info) {
491 addr = he->mem_info->daddr.addr;
492 map = he->mem_info->daddr.map;
493 sym = he->mem_info->daddr.sym;
495 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
496 width);
499 static int64_t
500 sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
502 struct map *map_l = NULL;
503 struct map *map_r = NULL;
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;
510 return _sort__dso_cmp(map_l, map_r);
513 static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
514 size_t size, unsigned int width)
516 struct map *map = NULL;
518 if (he->mem_info)
519 map = he->mem_info->daddr.map;
521 return _hist_entry__dso_snprintf(map, bf, size, width);
524 static int64_t
525 sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
527 union perf_mem_data_src data_src_l;
528 union perf_mem_data_src data_src_r;
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;
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;
540 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
543 static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
544 size_t size, unsigned int width)
546 const char *out;
547 u64 mask = PERF_MEM_LOCK_NA;
549 if (he->mem_info)
550 mask = he->mem_info->data_src.mem_lock;
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";
559 return repsep_snprintf(bf, size, "%-*s", width, out);
562 static int64_t
563 sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
565 union perf_mem_data_src data_src_l;
566 union perf_mem_data_src data_src_r;
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;
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;
578 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
581 static const char * const tlb_access[] = {
582 "N/A",
583 "HIT",
584 "MISS",
585 "L1",
586 "L2",
587 "Walker",
588 "Fault",
590 #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
592 static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
593 size_t size, unsigned int width)
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;
601 out[0] = '\0';
603 if (he->mem_info)
604 m = he->mem_info->data_src.mem_dtlb;
606 hit = m & PERF_MEM_TLB_HIT;
607 miss = m & PERF_MEM_TLB_MISS;
609 /* already taken care of */
610 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
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;
619 strncat(out, tlb_access[i], sz - l);
620 l += strlen(tlb_access[i]);
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);
629 return repsep_snprintf(bf, size, "%-*s", width, out);
632 static int64_t
633 sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
635 union perf_mem_data_src data_src_l;
636 union perf_mem_data_src data_src_r;
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;
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;
648 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
651 static 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",
667 #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
669 static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
670 size_t size, unsigned int width)
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;
678 if (he->mem_info)
679 m = he->mem_info->data_src.mem_lvl;
681 out[0] = '\0';
683 hit = m & PERF_MEM_LVL_HIT;
684 miss = m & PERF_MEM_LVL_MISS;
686 /* already taken care of */
687 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
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;
696 strncat(out, mem_lvl[i], sz - l);
697 l += strlen(mem_lvl[i]);
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);
706 return repsep_snprintf(bf, size, "%-*s", width, out);
709 static int64_t
710 sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
712 union perf_mem_data_src data_src_l;
713 union perf_mem_data_src data_src_r;
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;
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;
725 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
728 static const char * const snoop_access[] = {
729 "N/A",
730 "None",
731 "Miss",
732 "Hit",
733 "HitM",
735 #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
737 static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
738 size_t size, unsigned int width)
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;
745 out[0] = '\0';
747 if (he->mem_info)
748 m = he->mem_info->data_src.mem_snoop;
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;
757 strncat(out, snoop_access[i], sz - l);
758 l += strlen(snoop_access[i]);
761 if (*out == '\0')
762 strcpy(out, "N/A");
764 return repsep_snprintf(bf, size, "%-*s", width, out);
767 struct 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,
774 static u64 he_weight(struct hist_entry *he)
776 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
779 static int64_t
780 sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
782 return he_weight(left) - he_weight(right);
785 static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
786 size_t size, unsigned int width)
788 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
791 struct 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,
798 static int64_t
799 sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
801 return left->stat.weight - right->stat.weight;
804 static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
805 size_t size, unsigned int width)
807 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
810 struct 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,
817 struct 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,
824 struct 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,
831 struct 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,
838 struct 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,
845 struct 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,
852 struct 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,
859 static int64_t
860 sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
862 return left->branch_info->flags.abort !=
863 right->branch_info->flags.abort;
866 static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
867 size_t size, unsigned int width)
869 static const char *out = ".";
871 if (he->branch_info->flags.abort)
872 out = "A";
873 return repsep_snprintf(bf, size, "%-*s", width, out);
876 struct sort_entry sort_abort = {
877 .se_header = "Transaction abort",
878 .se_cmp = sort__abort_cmp,
879 .se_snprintf = hist_entry__abort_snprintf,
880 .se_width_idx = HISTC_ABORT,
883 static int64_t
884 sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
886 return left->branch_info->flags.in_tx !=
887 right->branch_info->flags.in_tx;
890 static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
891 size_t size, unsigned int width)
893 static const char *out = ".";
895 if (he->branch_info->flags.in_tx)
896 out = "T";
898 return repsep_snprintf(bf, size, "%-*s", width, out);
901 struct sort_entry sort_in_tx = {
902 .se_header = "Branch in transaction",
903 .se_cmp = sort__in_tx_cmp,
904 .se_snprintf = hist_entry__in_tx_snprintf,
905 .se_width_idx = HISTC_IN_TX,
908 static int64_t
909 sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
911 return left->transaction - right->transaction;
914 static inline char *add_str(char *p, const char *str)
916 strcpy(p, str);
917 return p + strlen(str);
920 static struct txbit {
921 unsigned flag;
922 const char *name;
923 int skip_for_len;
924 } txbits[] = {
925 { PERF_TXN_ELISION, "EL ", 0 },
926 { PERF_TXN_TRANSACTION, "TX ", 1 },
927 { PERF_TXN_SYNC, "SYNC ", 1 },
928 { PERF_TXN_ASYNC, "ASYNC ", 0 },
929 { PERF_TXN_RETRY, "RETRY ", 0 },
930 { PERF_TXN_CONFLICT, "CON ", 0 },
931 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
932 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
933 { 0, NULL, 0 }
936 int hist_entry__transaction_len(void)
938 int i;
939 int len = 0;
941 for (i = 0; txbits[i].name; i++) {
942 if (!txbits[i].skip_for_len)
943 len += strlen(txbits[i].name);
945 len += 4; /* :XX<space> */
946 return len;
949 static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
950 size_t size, unsigned int width)
952 u64 t = he->transaction;
953 char buf[128];
954 char *p = buf;
955 int i;
957 buf[0] = 0;
958 for (i = 0; txbits[i].name; i++)
959 if (txbits[i].flag & t)
960 p = add_str(p, txbits[i].name);
961 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
962 p = add_str(p, "NEITHER ");
963 if (t & PERF_TXN_ABORT_MASK) {
964 sprintf(p, ":%" PRIx64,
965 (t & PERF_TXN_ABORT_MASK) >>
966 PERF_TXN_ABORT_SHIFT);
967 p += strlen(p);
970 return repsep_snprintf(bf, size, "%-*s", width, buf);
973 struct sort_entry sort_transaction = {
974 .se_header = "Transaction ",
975 .se_cmp = sort__transaction_cmp,
976 .se_snprintf = hist_entry__transaction_snprintf,
977 .se_width_idx = HISTC_TRANSACTION,
980 struct sort_dimension {
981 const char *name;
982 struct sort_entry *entry;
983 int taken;
986 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
988 static struct sort_dimension common_sort_dimensions[] = {
989 DIM(SORT_PID, "pid", sort_thread),
990 DIM(SORT_COMM, "comm", sort_comm),
991 DIM(SORT_DSO, "dso", sort_dso),
992 DIM(SORT_SYM, "symbol", sort_sym),
993 DIM(SORT_PARENT, "parent", sort_parent),
994 DIM(SORT_CPU, "cpu", sort_cpu),
995 DIM(SORT_SRCLINE, "srcline", sort_srcline),
996 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
997 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
998 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
1001 #undef DIM
1003 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1005 static struct sort_dimension bstack_sort_dimensions[] = {
1006 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1007 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1008 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1009 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1010 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
1011 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1012 DIM(SORT_ABORT, "abort", sort_abort),
1015 #undef DIM
1017 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1019 static struct sort_dimension memory_sort_dimensions[] = {
1020 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1021 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1022 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1023 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1024 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1025 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1028 #undef DIM
1030 static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
1032 if (sd->taken)
1033 return;
1035 if (sd->entry->se_collapse)
1036 sort__need_collapse = 1;
1038 if (list_empty(&hist_entry__sort_list))
1039 sort__first_dimension = idx;
1041 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1042 sd->taken = 1;
1045 int sort_dimension__add(const char *tok)
1047 unsigned int i;
1049 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1050 struct sort_dimension *sd = &common_sort_dimensions[i];
1052 if (strncasecmp(tok, sd->name, strlen(tok)))
1053 continue;
1055 if (sd->entry == &sort_parent) {
1056 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1057 if (ret) {
1058 char err[BUFSIZ];
1060 regerror(ret, &parent_regex, err, sizeof(err));
1061 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1062 return -EINVAL;
1064 sort__has_parent = 1;
1065 } else if (sd->entry == &sort_sym) {
1066 sort__has_sym = 1;
1067 } else if (sd->entry == &sort_dso) {
1068 sort__has_dso = 1;
1071 __sort_dimension__add(sd, i);
1072 return 0;
1075 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1076 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1078 if (strncasecmp(tok, sd->name, strlen(tok)))
1079 continue;
1081 if (sort__mode != SORT_MODE__BRANCH)
1082 return -EINVAL;
1084 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1085 sort__has_sym = 1;
1087 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
1088 return 0;
1091 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1092 struct sort_dimension *sd = &memory_sort_dimensions[i];
1094 if (strncasecmp(tok, sd->name, strlen(tok)))
1095 continue;
1097 if (sort__mode != SORT_MODE__MEMORY)
1098 return -EINVAL;
1100 if (sd->entry == &sort_mem_daddr_sym)
1101 sort__has_sym = 1;
1103 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
1104 return 0;
1107 return -ESRCH;
1110 int setup_sorting(void)
1112 char *tmp, *tok, *str = strdup(sort_order);
1113 int ret = 0;
1115 if (str == NULL) {
1116 error("Not enough memory to setup sort keys");
1117 return -ENOMEM;
1120 for (tok = strtok_r(str, ", ", &tmp);
1121 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1122 ret = sort_dimension__add(tok);
1123 if (ret == -EINVAL) {
1124 error("Invalid --sort key: `%s'", tok);
1125 break;
1126 } else if (ret == -ESRCH) {
1127 error("Unknown --sort key: `%s'", tok);
1128 break;
1132 free(str);
1133 return ret;
1136 static void sort_entry__setup_elide(struct sort_entry *se,
1137 struct strlist *list,
1138 const char *list_name, FILE *fp)
1140 if (list && strlist__nr_entries(list) == 1) {
1141 if (fp != NULL)
1142 fprintf(fp, "# %s: %s\n", list_name,
1143 strlist__entry(list, 0)->s);
1144 se->elide = true;
1148 void sort__setup_elide(FILE *output)
1150 struct sort_entry *se;
1152 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1153 "dso", output);
1154 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1155 "comm", output);
1156 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1157 "symbol", output);
1159 if (sort__mode == SORT_MODE__BRANCH) {
1160 sort_entry__setup_elide(&sort_dso_from,
1161 symbol_conf.dso_from_list,
1162 "dso_from", output);
1163 sort_entry__setup_elide(&sort_dso_to,
1164 symbol_conf.dso_to_list,
1165 "dso_to", output);
1166 sort_entry__setup_elide(&sort_sym_from,
1167 symbol_conf.sym_from_list,
1168 "sym_from", output);
1169 sort_entry__setup_elide(&sort_sym_to,
1170 symbol_conf.sym_to_list,
1171 "sym_to", output);
1172 } else if (sort__mode == SORT_MODE__MEMORY) {
1173 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1174 "symbol_daddr", output);
1175 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1176 "dso_daddr", output);
1177 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1178 "mem", output);
1179 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1180 "local_weight", output);
1181 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1182 "tlb", output);
1183 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1184 "snoop", output);
1188 * It makes no sense to elide all of sort entries.
1189 * Just revert them to show up again.
1191 list_for_each_entry(se, &hist_entry__sort_list, list) {
1192 if (!se->elide)
1193 return;
1196 list_for_each_entry(se, &hist_entry__sort_list, list)
1197 se->elide = false;