Merge tag 'locks-v3.16-2' of git://git.samba.org/jlayton/linux
[linux/fpc-iii.git] / tools / perf / util / sort.c
blob1ec57dd822847cd90c562615deac6c0226a7a416
1 #include <sys/mman.h>
2 #include "sort.h"
3 #include "hist.h"
4 #include "comm.h"
5 #include "symbol.h"
6 #include "evsel.h"
8 regex_t parent_regex;
9 const char default_parent_pattern[] = "^sys_|^do_page_fault";
10 const char *parent_pattern = default_parent_pattern;
11 const char default_sort_order[] = "comm,dso,symbol";
12 const char default_branch_sort_order[] = "comm,dso_from,symbol_from,dso_to,symbol_to";
13 const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
14 const char default_top_sort_order[] = "dso,symbol";
15 const char default_diff_sort_order[] = "dso,symbol";
16 const char *sort_order;
17 const char *field_order;
18 regex_t ignore_callees_regex;
19 int have_ignore_callees = 0;
20 int sort__need_collapse = 0;
21 int sort__has_parent = 0;
22 int sort__has_sym = 0;
23 int sort__has_dso = 0;
24 enum sort_mode sort__mode = SORT_MODE__NORMAL;
27 static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
29 int n;
30 va_list ap;
32 va_start(ap, fmt);
33 n = vsnprintf(bf, size, fmt, ap);
34 if (symbol_conf.field_sep && n > 0) {
35 char *sep = bf;
37 while (1) {
38 sep = strchr(sep, *symbol_conf.field_sep);
39 if (sep == NULL)
40 break;
41 *sep = '.';
44 va_end(ap);
46 if (n >= (int)size)
47 return size - 1;
48 return n;
51 static int64_t cmp_null(const void *l, const void *r)
53 if (!l && !r)
54 return 0;
55 else if (!l)
56 return -1;
57 else
58 return 1;
61 /* --sort pid */
63 static int64_t
64 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
66 return right->thread->tid - left->thread->tid;
69 static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
70 size_t size, unsigned int width)
72 const char *comm = thread__comm_str(he->thread);
73 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
74 comm ?: "", he->thread->tid);
77 struct sort_entry sort_thread = {
78 .se_header = "Command: Pid",
79 .se_cmp = sort__thread_cmp,
80 .se_snprintf = hist_entry__thread_snprintf,
81 .se_width_idx = HISTC_THREAD,
84 /* --sort comm */
86 static int64_t
87 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
89 /* Compare the addr that should be unique among comm */
90 return comm__str(right->comm) - comm__str(left->comm);
93 static int64_t
94 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
96 /* Compare the addr that should be unique among comm */
97 return comm__str(right->comm) - comm__str(left->comm);
100 static int64_t
101 sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
103 return strcmp(comm__str(right->comm), comm__str(left->comm));
106 static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
107 size_t size, unsigned int width)
109 return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
112 struct sort_entry sort_comm = {
113 .se_header = "Command",
114 .se_cmp = sort__comm_cmp,
115 .se_collapse = sort__comm_collapse,
116 .se_sort = sort__comm_sort,
117 .se_snprintf = hist_entry__comm_snprintf,
118 .se_width_idx = HISTC_COMM,
121 /* --sort dso */
123 static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
125 struct dso *dso_l = map_l ? map_l->dso : NULL;
126 struct dso *dso_r = map_r ? map_r->dso : NULL;
127 const char *dso_name_l, *dso_name_r;
129 if (!dso_l || !dso_r)
130 return cmp_null(dso_r, dso_l);
132 if (verbose) {
133 dso_name_l = dso_l->long_name;
134 dso_name_r = dso_r->long_name;
135 } else {
136 dso_name_l = dso_l->short_name;
137 dso_name_r = dso_r->short_name;
140 return strcmp(dso_name_l, dso_name_r);
143 static int64_t
144 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
146 return _sort__dso_cmp(right->ms.map, left->ms.map);
149 static int _hist_entry__dso_snprintf(struct map *map, char *bf,
150 size_t size, unsigned int width)
152 if (map && map->dso) {
153 const char *dso_name = !verbose ? map->dso->short_name :
154 map->dso->long_name;
155 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
158 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
161 static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
162 size_t size, unsigned int width)
164 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
167 struct sort_entry sort_dso = {
168 .se_header = "Shared Object",
169 .se_cmp = sort__dso_cmp,
170 .se_snprintf = hist_entry__dso_snprintf,
171 .se_width_idx = HISTC_DSO,
174 /* --sort symbol */
176 static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
178 return (int64_t)(right_ip - left_ip);
181 static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
183 u64 ip_l, ip_r;
185 if (!sym_l || !sym_r)
186 return cmp_null(sym_l, sym_r);
188 if (sym_l == sym_r)
189 return 0;
191 ip_l = sym_l->start;
192 ip_r = sym_r->start;
194 return (int64_t)(ip_r - ip_l);
197 static int64_t
198 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
200 int64_t ret;
202 if (!left->ms.sym && !right->ms.sym)
203 return _sort__addr_cmp(left->ip, right->ip);
206 * comparing symbol address alone is not enough since it's a
207 * relative address within a dso.
209 if (!sort__has_dso) {
210 ret = sort__dso_cmp(left, right);
211 if (ret != 0)
212 return ret;
215 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
218 static int64_t
219 sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
221 if (!left->ms.sym || !right->ms.sym)
222 return cmp_null(left->ms.sym, right->ms.sym);
224 return strcmp(right->ms.sym->name, left->ms.sym->name);
227 static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
228 u64 ip, char level, char *bf, size_t size,
229 unsigned int width)
231 size_t ret = 0;
233 if (verbose) {
234 char o = map ? dso__symtab_origin(map->dso) : '!';
235 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
236 BITS_PER_LONG / 4 + 2, ip, o);
239 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
240 if (sym && map) {
241 if (map->type == MAP__VARIABLE) {
242 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
243 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
244 ip - map->unmap_ip(map, sym->start));
245 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
246 width - ret, "");
247 } else {
248 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
249 width - ret,
250 sym->name);
252 } else {
253 size_t len = BITS_PER_LONG / 4;
254 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
255 len, ip);
256 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
257 width - ret, "");
260 return ret;
263 static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
264 size_t size, unsigned int width)
266 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
267 he->level, bf, size, width);
270 struct sort_entry sort_sym = {
271 .se_header = "Symbol",
272 .se_cmp = sort__sym_cmp,
273 .se_sort = sort__sym_sort,
274 .se_snprintf = hist_entry__sym_snprintf,
275 .se_width_idx = HISTC_SYMBOL,
278 /* --sort srcline */
280 static int64_t
281 sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
283 if (!left->srcline) {
284 if (!left->ms.map)
285 left->srcline = SRCLINE_UNKNOWN;
286 else {
287 struct map *map = left->ms.map;
288 left->srcline = get_srcline(map->dso,
289 map__rip_2objdump(map, left->ip));
292 if (!right->srcline) {
293 if (!right->ms.map)
294 right->srcline = SRCLINE_UNKNOWN;
295 else {
296 struct map *map = right->ms.map;
297 right->srcline = get_srcline(map->dso,
298 map__rip_2objdump(map, right->ip));
301 return strcmp(right->srcline, left->srcline);
304 static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
305 size_t size,
306 unsigned int width __maybe_unused)
308 return repsep_snprintf(bf, size, "%s", he->srcline);
311 struct sort_entry sort_srcline = {
312 .se_header = "Source:Line",
313 .se_cmp = sort__srcline_cmp,
314 .se_snprintf = hist_entry__srcline_snprintf,
315 .se_width_idx = HISTC_SRCLINE,
318 /* --sort parent */
320 static int64_t
321 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
323 struct symbol *sym_l = left->parent;
324 struct symbol *sym_r = right->parent;
326 if (!sym_l || !sym_r)
327 return cmp_null(sym_l, sym_r);
329 return strcmp(sym_r->name, sym_l->name);
332 static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
333 size_t size, unsigned int width)
335 return repsep_snprintf(bf, size, "%-*s", width,
336 he->parent ? he->parent->name : "[other]");
339 struct sort_entry sort_parent = {
340 .se_header = "Parent symbol",
341 .se_cmp = sort__parent_cmp,
342 .se_snprintf = hist_entry__parent_snprintf,
343 .se_width_idx = HISTC_PARENT,
346 /* --sort cpu */
348 static int64_t
349 sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
351 return right->cpu - left->cpu;
354 static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
355 size_t size, unsigned int width)
357 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
360 struct sort_entry sort_cpu = {
361 .se_header = "CPU",
362 .se_cmp = sort__cpu_cmp,
363 .se_snprintf = hist_entry__cpu_snprintf,
364 .se_width_idx = HISTC_CPU,
367 /* sort keys for branch stacks */
369 static int64_t
370 sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
372 return _sort__dso_cmp(left->branch_info->from.map,
373 right->branch_info->from.map);
376 static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
377 size_t size, unsigned int width)
379 return _hist_entry__dso_snprintf(he->branch_info->from.map,
380 bf, size, width);
383 static int64_t
384 sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
386 return _sort__dso_cmp(left->branch_info->to.map,
387 right->branch_info->to.map);
390 static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
391 size_t size, unsigned int width)
393 return _hist_entry__dso_snprintf(he->branch_info->to.map,
394 bf, size, width);
397 static int64_t
398 sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
400 struct addr_map_symbol *from_l = &left->branch_info->from;
401 struct addr_map_symbol *from_r = &right->branch_info->from;
403 if (!from_l->sym && !from_r->sym)
404 return _sort__addr_cmp(from_l->addr, from_r->addr);
406 return _sort__sym_cmp(from_l->sym, from_r->sym);
409 static int64_t
410 sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
412 struct addr_map_symbol *to_l = &left->branch_info->to;
413 struct addr_map_symbol *to_r = &right->branch_info->to;
415 if (!to_l->sym && !to_r->sym)
416 return _sort__addr_cmp(to_l->addr, to_r->addr);
418 return _sort__sym_cmp(to_l->sym, to_r->sym);
421 static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
422 size_t size, unsigned int width)
424 struct addr_map_symbol *from = &he->branch_info->from;
425 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
426 he->level, bf, size, width);
430 static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
431 size_t size, unsigned int width)
433 struct addr_map_symbol *to = &he->branch_info->to;
434 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
435 he->level, bf, size, width);
439 struct sort_entry sort_dso_from = {
440 .se_header = "Source Shared Object",
441 .se_cmp = sort__dso_from_cmp,
442 .se_snprintf = hist_entry__dso_from_snprintf,
443 .se_width_idx = HISTC_DSO_FROM,
446 struct sort_entry sort_dso_to = {
447 .se_header = "Target Shared Object",
448 .se_cmp = sort__dso_to_cmp,
449 .se_snprintf = hist_entry__dso_to_snprintf,
450 .se_width_idx = HISTC_DSO_TO,
453 struct sort_entry sort_sym_from = {
454 .se_header = "Source Symbol",
455 .se_cmp = sort__sym_from_cmp,
456 .se_snprintf = hist_entry__sym_from_snprintf,
457 .se_width_idx = HISTC_SYMBOL_FROM,
460 struct sort_entry sort_sym_to = {
461 .se_header = "Target Symbol",
462 .se_cmp = sort__sym_to_cmp,
463 .se_snprintf = hist_entry__sym_to_snprintf,
464 .se_width_idx = HISTC_SYMBOL_TO,
467 static int64_t
468 sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
470 const unsigned char mp = left->branch_info->flags.mispred !=
471 right->branch_info->flags.mispred;
472 const unsigned char p = left->branch_info->flags.predicted !=
473 right->branch_info->flags.predicted;
475 return mp || p;
478 static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
479 size_t size, unsigned int width){
480 static const char *out = "N/A";
482 if (he->branch_info->flags.predicted)
483 out = "N";
484 else if (he->branch_info->flags.mispred)
485 out = "Y";
487 return repsep_snprintf(bf, size, "%-*s", width, out);
490 /* --sort daddr_sym */
491 static int64_t
492 sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
494 uint64_t l = 0, r = 0;
496 if (left->mem_info)
497 l = left->mem_info->daddr.addr;
498 if (right->mem_info)
499 r = right->mem_info->daddr.addr;
501 return (int64_t)(r - l);
504 static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
505 size_t size, unsigned int width)
507 uint64_t addr = 0;
508 struct map *map = NULL;
509 struct symbol *sym = NULL;
511 if (he->mem_info) {
512 addr = he->mem_info->daddr.addr;
513 map = he->mem_info->daddr.map;
514 sym = he->mem_info->daddr.sym;
516 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
517 width);
520 static int64_t
521 sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
523 struct map *map_l = NULL;
524 struct map *map_r = NULL;
526 if (left->mem_info)
527 map_l = left->mem_info->daddr.map;
528 if (right->mem_info)
529 map_r = right->mem_info->daddr.map;
531 return _sort__dso_cmp(map_l, map_r);
534 static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
535 size_t size, unsigned int width)
537 struct map *map = NULL;
539 if (he->mem_info)
540 map = he->mem_info->daddr.map;
542 return _hist_entry__dso_snprintf(map, bf, size, width);
545 static int64_t
546 sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
548 union perf_mem_data_src data_src_l;
549 union perf_mem_data_src data_src_r;
551 if (left->mem_info)
552 data_src_l = left->mem_info->data_src;
553 else
554 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
556 if (right->mem_info)
557 data_src_r = right->mem_info->data_src;
558 else
559 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
561 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
564 static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
565 size_t size, unsigned int width)
567 const char *out;
568 u64 mask = PERF_MEM_LOCK_NA;
570 if (he->mem_info)
571 mask = he->mem_info->data_src.mem_lock;
573 if (mask & PERF_MEM_LOCK_NA)
574 out = "N/A";
575 else if (mask & PERF_MEM_LOCK_LOCKED)
576 out = "Yes";
577 else
578 out = "No";
580 return repsep_snprintf(bf, size, "%-*s", width, out);
583 static int64_t
584 sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
586 union perf_mem_data_src data_src_l;
587 union perf_mem_data_src data_src_r;
589 if (left->mem_info)
590 data_src_l = left->mem_info->data_src;
591 else
592 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
594 if (right->mem_info)
595 data_src_r = right->mem_info->data_src;
596 else
597 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
599 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
602 static const char * const tlb_access[] = {
603 "N/A",
604 "HIT",
605 "MISS",
606 "L1",
607 "L2",
608 "Walker",
609 "Fault",
611 #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
613 static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
614 size_t size, unsigned int width)
616 char out[64];
617 size_t sz = sizeof(out) - 1; /* -1 for null termination */
618 size_t l = 0, i;
619 u64 m = PERF_MEM_TLB_NA;
620 u64 hit, miss;
622 out[0] = '\0';
624 if (he->mem_info)
625 m = he->mem_info->data_src.mem_dtlb;
627 hit = m & PERF_MEM_TLB_HIT;
628 miss = m & PERF_MEM_TLB_MISS;
630 /* already taken care of */
631 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
633 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
634 if (!(m & 0x1))
635 continue;
636 if (l) {
637 strcat(out, " or ");
638 l += 4;
640 strncat(out, tlb_access[i], sz - l);
641 l += strlen(tlb_access[i]);
643 if (*out == '\0')
644 strcpy(out, "N/A");
645 if (hit)
646 strncat(out, " hit", sz - l);
647 if (miss)
648 strncat(out, " miss", sz - l);
650 return repsep_snprintf(bf, size, "%-*s", width, out);
653 static int64_t
654 sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
656 union perf_mem_data_src data_src_l;
657 union perf_mem_data_src data_src_r;
659 if (left->mem_info)
660 data_src_l = left->mem_info->data_src;
661 else
662 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
664 if (right->mem_info)
665 data_src_r = right->mem_info->data_src;
666 else
667 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
669 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
672 static const char * const mem_lvl[] = {
673 "N/A",
674 "HIT",
675 "MISS",
676 "L1",
677 "LFB",
678 "L2",
679 "L3",
680 "Local RAM",
681 "Remote RAM (1 hop)",
682 "Remote RAM (2 hops)",
683 "Remote Cache (1 hop)",
684 "Remote Cache (2 hops)",
685 "I/O",
686 "Uncached",
688 #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
690 static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
691 size_t size, unsigned int width)
693 char out[64];
694 size_t sz = sizeof(out) - 1; /* -1 for null termination */
695 size_t i, l = 0;
696 u64 m = PERF_MEM_LVL_NA;
697 u64 hit, miss;
699 if (he->mem_info)
700 m = he->mem_info->data_src.mem_lvl;
702 out[0] = '\0';
704 hit = m & PERF_MEM_LVL_HIT;
705 miss = m & PERF_MEM_LVL_MISS;
707 /* already taken care of */
708 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
710 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
711 if (!(m & 0x1))
712 continue;
713 if (l) {
714 strcat(out, " or ");
715 l += 4;
717 strncat(out, mem_lvl[i], sz - l);
718 l += strlen(mem_lvl[i]);
720 if (*out == '\0')
721 strcpy(out, "N/A");
722 if (hit)
723 strncat(out, " hit", sz - l);
724 if (miss)
725 strncat(out, " miss", sz - l);
727 return repsep_snprintf(bf, size, "%-*s", width, out);
730 static int64_t
731 sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
733 union perf_mem_data_src data_src_l;
734 union perf_mem_data_src data_src_r;
736 if (left->mem_info)
737 data_src_l = left->mem_info->data_src;
738 else
739 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
741 if (right->mem_info)
742 data_src_r = right->mem_info->data_src;
743 else
744 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
746 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
749 static const char * const snoop_access[] = {
750 "N/A",
751 "None",
752 "Miss",
753 "Hit",
754 "HitM",
756 #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
758 static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
759 size_t size, unsigned int width)
761 char out[64];
762 size_t sz = sizeof(out) - 1; /* -1 for null termination */
763 size_t i, l = 0;
764 u64 m = PERF_MEM_SNOOP_NA;
766 out[0] = '\0';
768 if (he->mem_info)
769 m = he->mem_info->data_src.mem_snoop;
771 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
772 if (!(m & 0x1))
773 continue;
774 if (l) {
775 strcat(out, " or ");
776 l += 4;
778 strncat(out, snoop_access[i], sz - l);
779 l += strlen(snoop_access[i]);
782 if (*out == '\0')
783 strcpy(out, "N/A");
785 return repsep_snprintf(bf, size, "%-*s", width, out);
788 static inline u64 cl_address(u64 address)
790 /* return the cacheline of the address */
791 return (address & ~(cacheline_size - 1));
794 static int64_t
795 sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
797 u64 l, r;
798 struct map *l_map, *r_map;
800 if (!left->mem_info) return -1;
801 if (!right->mem_info) return 1;
803 /* group event types together */
804 if (left->cpumode > right->cpumode) return -1;
805 if (left->cpumode < right->cpumode) return 1;
807 l_map = left->mem_info->daddr.map;
808 r_map = right->mem_info->daddr.map;
810 /* if both are NULL, jump to sort on al_addr instead */
811 if (!l_map && !r_map)
812 goto addr;
814 if (!l_map) return -1;
815 if (!r_map) return 1;
817 if (l_map->maj > r_map->maj) return -1;
818 if (l_map->maj < r_map->maj) return 1;
820 if (l_map->min > r_map->min) return -1;
821 if (l_map->min < r_map->min) return 1;
823 if (l_map->ino > r_map->ino) return -1;
824 if (l_map->ino < r_map->ino) return 1;
826 if (l_map->ino_generation > r_map->ino_generation) return -1;
827 if (l_map->ino_generation < r_map->ino_generation) return 1;
830 * Addresses with no major/minor numbers are assumed to be
831 * anonymous in userspace. Sort those on pid then address.
833 * The kernel and non-zero major/minor mapped areas are
834 * assumed to be unity mapped. Sort those on address.
837 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
838 (!(l_map->flags & MAP_SHARED)) &&
839 !l_map->maj && !l_map->min && !l_map->ino &&
840 !l_map->ino_generation) {
841 /* userspace anonymous */
843 if (left->thread->pid_ > right->thread->pid_) return -1;
844 if (left->thread->pid_ < right->thread->pid_) return 1;
847 addr:
848 /* al_addr does all the right addr - start + offset calculations */
849 l = cl_address(left->mem_info->daddr.al_addr);
850 r = cl_address(right->mem_info->daddr.al_addr);
852 if (l > r) return -1;
853 if (l < r) return 1;
855 return 0;
858 static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
859 size_t size, unsigned int width)
862 uint64_t addr = 0;
863 struct map *map = NULL;
864 struct symbol *sym = NULL;
865 char level = he->level;
867 if (he->mem_info) {
868 addr = cl_address(he->mem_info->daddr.al_addr);
869 map = he->mem_info->daddr.map;
870 sym = he->mem_info->daddr.sym;
872 /* print [s] for shared data mmaps */
873 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
874 map && (map->type == MAP__VARIABLE) &&
875 (map->flags & MAP_SHARED) &&
876 (map->maj || map->min || map->ino ||
877 map->ino_generation))
878 level = 's';
879 else if (!map)
880 level = 'X';
882 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
883 width);
886 struct sort_entry sort_mispredict = {
887 .se_header = "Branch Mispredicted",
888 .se_cmp = sort__mispredict_cmp,
889 .se_snprintf = hist_entry__mispredict_snprintf,
890 .se_width_idx = HISTC_MISPREDICT,
893 static u64 he_weight(struct hist_entry *he)
895 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
898 static int64_t
899 sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
901 return he_weight(left) - he_weight(right);
904 static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
905 size_t size, unsigned int width)
907 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
910 struct sort_entry sort_local_weight = {
911 .se_header = "Local Weight",
912 .se_cmp = sort__local_weight_cmp,
913 .se_snprintf = hist_entry__local_weight_snprintf,
914 .se_width_idx = HISTC_LOCAL_WEIGHT,
917 static int64_t
918 sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
920 return left->stat.weight - right->stat.weight;
923 static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
924 size_t size, unsigned int width)
926 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
929 struct sort_entry sort_global_weight = {
930 .se_header = "Weight",
931 .se_cmp = sort__global_weight_cmp,
932 .se_snprintf = hist_entry__global_weight_snprintf,
933 .se_width_idx = HISTC_GLOBAL_WEIGHT,
936 struct sort_entry sort_mem_daddr_sym = {
937 .se_header = "Data Symbol",
938 .se_cmp = sort__daddr_cmp,
939 .se_snprintf = hist_entry__daddr_snprintf,
940 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
943 struct sort_entry sort_mem_daddr_dso = {
944 .se_header = "Data Object",
945 .se_cmp = sort__dso_daddr_cmp,
946 .se_snprintf = hist_entry__dso_daddr_snprintf,
947 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
950 struct sort_entry sort_mem_locked = {
951 .se_header = "Locked",
952 .se_cmp = sort__locked_cmp,
953 .se_snprintf = hist_entry__locked_snprintf,
954 .se_width_idx = HISTC_MEM_LOCKED,
957 struct sort_entry sort_mem_tlb = {
958 .se_header = "TLB access",
959 .se_cmp = sort__tlb_cmp,
960 .se_snprintf = hist_entry__tlb_snprintf,
961 .se_width_idx = HISTC_MEM_TLB,
964 struct sort_entry sort_mem_lvl = {
965 .se_header = "Memory access",
966 .se_cmp = sort__lvl_cmp,
967 .se_snprintf = hist_entry__lvl_snprintf,
968 .se_width_idx = HISTC_MEM_LVL,
971 struct sort_entry sort_mem_snoop = {
972 .se_header = "Snoop",
973 .se_cmp = sort__snoop_cmp,
974 .se_snprintf = hist_entry__snoop_snprintf,
975 .se_width_idx = HISTC_MEM_SNOOP,
978 struct sort_entry sort_mem_dcacheline = {
979 .se_header = "Data Cacheline",
980 .se_cmp = sort__dcacheline_cmp,
981 .se_snprintf = hist_entry__dcacheline_snprintf,
982 .se_width_idx = HISTC_MEM_DCACHELINE,
985 static int64_t
986 sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
988 return left->branch_info->flags.abort !=
989 right->branch_info->flags.abort;
992 static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
993 size_t size, unsigned int width)
995 static const char *out = ".";
997 if (he->branch_info->flags.abort)
998 out = "A";
999 return repsep_snprintf(bf, size, "%-*s", width, out);
1002 struct sort_entry sort_abort = {
1003 .se_header = "Transaction abort",
1004 .se_cmp = sort__abort_cmp,
1005 .se_snprintf = hist_entry__abort_snprintf,
1006 .se_width_idx = HISTC_ABORT,
1009 static int64_t
1010 sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1012 return left->branch_info->flags.in_tx !=
1013 right->branch_info->flags.in_tx;
1016 static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
1017 size_t size, unsigned int width)
1019 static const char *out = ".";
1021 if (he->branch_info->flags.in_tx)
1022 out = "T";
1024 return repsep_snprintf(bf, size, "%-*s", width, out);
1027 struct sort_entry sort_in_tx = {
1028 .se_header = "Branch in transaction",
1029 .se_cmp = sort__in_tx_cmp,
1030 .se_snprintf = hist_entry__in_tx_snprintf,
1031 .se_width_idx = HISTC_IN_TX,
1034 static int64_t
1035 sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1037 return left->transaction - right->transaction;
1040 static inline char *add_str(char *p, const char *str)
1042 strcpy(p, str);
1043 return p + strlen(str);
1046 static struct txbit {
1047 unsigned flag;
1048 const char *name;
1049 int skip_for_len;
1050 } txbits[] = {
1051 { PERF_TXN_ELISION, "EL ", 0 },
1052 { PERF_TXN_TRANSACTION, "TX ", 1 },
1053 { PERF_TXN_SYNC, "SYNC ", 1 },
1054 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1055 { PERF_TXN_RETRY, "RETRY ", 0 },
1056 { PERF_TXN_CONFLICT, "CON ", 0 },
1057 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1058 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1059 { 0, NULL, 0 }
1062 int hist_entry__transaction_len(void)
1064 int i;
1065 int len = 0;
1067 for (i = 0; txbits[i].name; i++) {
1068 if (!txbits[i].skip_for_len)
1069 len += strlen(txbits[i].name);
1071 len += 4; /* :XX<space> */
1072 return len;
1075 static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
1076 size_t size, unsigned int width)
1078 u64 t = he->transaction;
1079 char buf[128];
1080 char *p = buf;
1081 int i;
1083 buf[0] = 0;
1084 for (i = 0; txbits[i].name; i++)
1085 if (txbits[i].flag & t)
1086 p = add_str(p, txbits[i].name);
1087 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1088 p = add_str(p, "NEITHER ");
1089 if (t & PERF_TXN_ABORT_MASK) {
1090 sprintf(p, ":%" PRIx64,
1091 (t & PERF_TXN_ABORT_MASK) >>
1092 PERF_TXN_ABORT_SHIFT);
1093 p += strlen(p);
1096 return repsep_snprintf(bf, size, "%-*s", width, buf);
1099 struct sort_entry sort_transaction = {
1100 .se_header = "Transaction ",
1101 .se_cmp = sort__transaction_cmp,
1102 .se_snprintf = hist_entry__transaction_snprintf,
1103 .se_width_idx = HISTC_TRANSACTION,
1106 struct sort_dimension {
1107 const char *name;
1108 struct sort_entry *entry;
1109 int taken;
1112 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1114 static struct sort_dimension common_sort_dimensions[] = {
1115 DIM(SORT_PID, "pid", sort_thread),
1116 DIM(SORT_COMM, "comm", sort_comm),
1117 DIM(SORT_DSO, "dso", sort_dso),
1118 DIM(SORT_SYM, "symbol", sort_sym),
1119 DIM(SORT_PARENT, "parent", sort_parent),
1120 DIM(SORT_CPU, "cpu", sort_cpu),
1121 DIM(SORT_SRCLINE, "srcline", sort_srcline),
1122 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1123 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
1124 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
1127 #undef DIM
1129 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1131 static struct sort_dimension bstack_sort_dimensions[] = {
1132 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1133 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1134 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1135 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1136 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
1137 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1138 DIM(SORT_ABORT, "abort", sort_abort),
1141 #undef DIM
1143 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1145 static struct sort_dimension memory_sort_dimensions[] = {
1146 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1147 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1148 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1149 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1150 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1151 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1152 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
1155 #undef DIM
1157 struct hpp_dimension {
1158 const char *name;
1159 struct perf_hpp_fmt *fmt;
1160 int taken;
1163 #define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1165 static struct hpp_dimension hpp_sort_dimensions[] = {
1166 DIM(PERF_HPP__OVERHEAD, "overhead"),
1167 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1168 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1169 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1170 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1171 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
1172 DIM(PERF_HPP__SAMPLES, "sample"),
1173 DIM(PERF_HPP__PERIOD, "period"),
1176 #undef DIM
1178 struct hpp_sort_entry {
1179 struct perf_hpp_fmt hpp;
1180 struct sort_entry *se;
1183 bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1185 struct hpp_sort_entry *hse_a;
1186 struct hpp_sort_entry *hse_b;
1188 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1189 return false;
1191 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1192 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1194 return hse_a->se == hse_b->se;
1197 void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1199 struct hpp_sort_entry *hse;
1201 if (!perf_hpp__is_sort_entry(fmt))
1202 return;
1204 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1205 hists__new_col_len(hists, hse->se->se_width_idx,
1206 strlen(hse->se->se_header));
1209 static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1210 struct perf_evsel *evsel)
1212 struct hpp_sort_entry *hse;
1213 size_t len;
1215 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1216 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1218 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header);
1221 static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1222 struct perf_hpp *hpp __maybe_unused,
1223 struct perf_evsel *evsel)
1225 struct hpp_sort_entry *hse;
1227 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1229 return hists__col_len(&evsel->hists, hse->se->se_width_idx);
1232 static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1233 struct hist_entry *he)
1235 struct hpp_sort_entry *hse;
1236 size_t len;
1238 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1239 len = hists__col_len(he->hists, hse->se->se_width_idx);
1241 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1244 static struct hpp_sort_entry *
1245 __sort_dimension__alloc_hpp(struct sort_dimension *sd)
1247 struct hpp_sort_entry *hse;
1249 hse = malloc(sizeof(*hse));
1250 if (hse == NULL) {
1251 pr_err("Memory allocation failed\n");
1252 return NULL;
1255 hse->se = sd->entry;
1256 hse->hpp.header = __sort__hpp_header;
1257 hse->hpp.width = __sort__hpp_width;
1258 hse->hpp.entry = __sort__hpp_entry;
1259 hse->hpp.color = NULL;
1261 hse->hpp.cmp = sd->entry->se_cmp;
1262 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
1263 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
1265 INIT_LIST_HEAD(&hse->hpp.list);
1266 INIT_LIST_HEAD(&hse->hpp.sort_list);
1267 hse->hpp.elide = false;
1269 return hse;
1272 bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1274 return format->header == __sort__hpp_header;
1277 static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1279 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1281 if (hse == NULL)
1282 return -1;
1284 perf_hpp__register_sort_field(&hse->hpp);
1285 return 0;
1288 static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1290 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1292 if (hse == NULL)
1293 return -1;
1295 perf_hpp__column_register(&hse->hpp);
1296 return 0;
1299 static int __sort_dimension__add(struct sort_dimension *sd)
1301 if (sd->taken)
1302 return 0;
1304 if (__sort_dimension__add_hpp_sort(sd) < 0)
1305 return -1;
1307 if (sd->entry->se_collapse)
1308 sort__need_collapse = 1;
1310 sd->taken = 1;
1312 return 0;
1315 static int __hpp_dimension__add(struct hpp_dimension *hd)
1317 if (!hd->taken) {
1318 hd->taken = 1;
1320 perf_hpp__register_sort_field(hd->fmt);
1322 return 0;
1325 static int __sort_dimension__add_output(struct sort_dimension *sd)
1327 if (sd->taken)
1328 return 0;
1330 if (__sort_dimension__add_hpp_output(sd) < 0)
1331 return -1;
1333 sd->taken = 1;
1334 return 0;
1337 static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1339 if (!hd->taken) {
1340 hd->taken = 1;
1342 perf_hpp__column_register(hd->fmt);
1344 return 0;
1347 int sort_dimension__add(const char *tok)
1349 unsigned int i;
1351 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1352 struct sort_dimension *sd = &common_sort_dimensions[i];
1354 if (strncasecmp(tok, sd->name, strlen(tok)))
1355 continue;
1357 if (sd->entry == &sort_parent) {
1358 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1359 if (ret) {
1360 char err[BUFSIZ];
1362 regerror(ret, &parent_regex, err, sizeof(err));
1363 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1364 return -EINVAL;
1366 sort__has_parent = 1;
1367 } else if (sd->entry == &sort_sym) {
1368 sort__has_sym = 1;
1369 } else if (sd->entry == &sort_dso) {
1370 sort__has_dso = 1;
1373 return __sort_dimension__add(sd);
1376 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1377 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1379 if (strncasecmp(tok, hd->name, strlen(tok)))
1380 continue;
1382 return __hpp_dimension__add(hd);
1385 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1386 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1388 if (strncasecmp(tok, sd->name, strlen(tok)))
1389 continue;
1391 if (sort__mode != SORT_MODE__BRANCH)
1392 return -EINVAL;
1394 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1395 sort__has_sym = 1;
1397 __sort_dimension__add(sd);
1398 return 0;
1401 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1402 struct sort_dimension *sd = &memory_sort_dimensions[i];
1404 if (strncasecmp(tok, sd->name, strlen(tok)))
1405 continue;
1407 if (sort__mode != SORT_MODE__MEMORY)
1408 return -EINVAL;
1410 if (sd->entry == &sort_mem_daddr_sym)
1411 sort__has_sym = 1;
1413 __sort_dimension__add(sd);
1414 return 0;
1417 return -ESRCH;
1420 static const char *get_default_sort_order(void)
1422 const char *default_sort_orders[] = {
1423 default_sort_order,
1424 default_branch_sort_order,
1425 default_mem_sort_order,
1426 default_top_sort_order,
1427 default_diff_sort_order,
1430 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1432 return default_sort_orders[sort__mode];
1435 static int __setup_sorting(void)
1437 char *tmp, *tok, *str;
1438 const char *sort_keys = sort_order;
1439 int ret = 0;
1441 if (sort_keys == NULL) {
1442 if (field_order) {
1444 * If user specified field order but no sort order,
1445 * we'll honor it and not add default sort orders.
1447 return 0;
1450 sort_keys = get_default_sort_order();
1453 str = strdup(sort_keys);
1454 if (str == NULL) {
1455 error("Not enough memory to setup sort keys");
1456 return -ENOMEM;
1459 for (tok = strtok_r(str, ", ", &tmp);
1460 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1461 ret = sort_dimension__add(tok);
1462 if (ret == -EINVAL) {
1463 error("Invalid --sort key: `%s'", tok);
1464 break;
1465 } else if (ret == -ESRCH) {
1466 error("Unknown --sort key: `%s'", tok);
1467 break;
1471 free(str);
1472 return ret;
1475 void perf_hpp__set_elide(int idx, bool elide)
1477 struct perf_hpp_fmt *fmt;
1478 struct hpp_sort_entry *hse;
1480 perf_hpp__for_each_format(fmt) {
1481 if (!perf_hpp__is_sort_entry(fmt))
1482 continue;
1484 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1485 if (hse->se->se_width_idx == idx) {
1486 fmt->elide = elide;
1487 break;
1492 static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
1494 if (list && strlist__nr_entries(list) == 1) {
1495 if (fp != NULL)
1496 fprintf(fp, "# %s: %s\n", list_name,
1497 strlist__entry(list, 0)->s);
1498 return true;
1500 return false;
1503 static bool get_elide(int idx, FILE *output)
1505 switch (idx) {
1506 case HISTC_SYMBOL:
1507 return __get_elide(symbol_conf.sym_list, "symbol", output);
1508 case HISTC_DSO:
1509 return __get_elide(symbol_conf.dso_list, "dso", output);
1510 case HISTC_COMM:
1511 return __get_elide(symbol_conf.comm_list, "comm", output);
1512 default:
1513 break;
1516 if (sort__mode != SORT_MODE__BRANCH)
1517 return false;
1519 switch (idx) {
1520 case HISTC_SYMBOL_FROM:
1521 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1522 case HISTC_SYMBOL_TO:
1523 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1524 case HISTC_DSO_FROM:
1525 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1526 case HISTC_DSO_TO:
1527 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1528 default:
1529 break;
1532 return false;
1535 void sort__setup_elide(FILE *output)
1537 struct perf_hpp_fmt *fmt;
1538 struct hpp_sort_entry *hse;
1540 perf_hpp__for_each_format(fmt) {
1541 if (!perf_hpp__is_sort_entry(fmt))
1542 continue;
1544 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1545 fmt->elide = get_elide(hse->se->se_width_idx, output);
1549 * It makes no sense to elide all of sort entries.
1550 * Just revert them to show up again.
1552 perf_hpp__for_each_format(fmt) {
1553 if (!perf_hpp__is_sort_entry(fmt))
1554 continue;
1556 if (!fmt->elide)
1557 return;
1560 perf_hpp__for_each_format(fmt) {
1561 if (!perf_hpp__is_sort_entry(fmt))
1562 continue;
1564 fmt->elide = false;
1568 static int output_field_add(char *tok)
1570 unsigned int i;
1572 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1573 struct sort_dimension *sd = &common_sort_dimensions[i];
1575 if (strncasecmp(tok, sd->name, strlen(tok)))
1576 continue;
1578 return __sort_dimension__add_output(sd);
1581 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1582 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1584 if (strncasecmp(tok, hd->name, strlen(tok)))
1585 continue;
1587 return __hpp_dimension__add_output(hd);
1590 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1591 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1593 if (strncasecmp(tok, sd->name, strlen(tok)))
1594 continue;
1596 return __sort_dimension__add_output(sd);
1599 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1600 struct sort_dimension *sd = &memory_sort_dimensions[i];
1602 if (strncasecmp(tok, sd->name, strlen(tok)))
1603 continue;
1605 return __sort_dimension__add_output(sd);
1608 return -ESRCH;
1611 static void reset_dimensions(void)
1613 unsigned int i;
1615 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1616 common_sort_dimensions[i].taken = 0;
1618 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1619 hpp_sort_dimensions[i].taken = 0;
1621 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1622 bstack_sort_dimensions[i].taken = 0;
1624 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1625 memory_sort_dimensions[i].taken = 0;
1628 static int __setup_output_field(void)
1630 char *tmp, *tok, *str;
1631 int ret = 0;
1633 if (field_order == NULL)
1634 return 0;
1636 reset_dimensions();
1638 str = strdup(field_order);
1639 if (str == NULL) {
1640 error("Not enough memory to setup output fields");
1641 return -ENOMEM;
1644 for (tok = strtok_r(str, ", ", &tmp);
1645 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1646 ret = output_field_add(tok);
1647 if (ret == -EINVAL) {
1648 error("Invalid --fields key: `%s'", tok);
1649 break;
1650 } else if (ret == -ESRCH) {
1651 error("Unknown --fields key: `%s'", tok);
1652 break;
1656 free(str);
1657 return ret;
1660 int setup_sorting(void)
1662 int err;
1664 err = __setup_sorting();
1665 if (err < 0)
1666 return err;
1668 if (parent_pattern != default_parent_pattern) {
1669 err = sort_dimension__add("parent");
1670 if (err < 0)
1671 return err;
1674 reset_dimensions();
1677 * perf diff doesn't use default hpp output fields.
1679 if (sort__mode != SORT_MODE__DIFF)
1680 perf_hpp__init();
1682 err = __setup_output_field();
1683 if (err < 0)
1684 return err;
1686 /* copy sort keys to output fields */
1687 perf_hpp__setup_output_field();
1688 /* and then copy output fields to sort keys */
1689 perf_hpp__append_sort_keys();
1691 return 0;
1694 void reset_output_field(void)
1696 sort__need_collapse = 0;
1697 sort__has_parent = 0;
1698 sort__has_sym = 0;
1699 sort__has_dso = 0;
1701 field_order = NULL;
1702 sort_order = NULL;
1704 reset_dimensions();
1705 perf_hpp__reset_output_field();