mm: rename alloc_pages_exact_node() to __alloc_pages_node()
[linux/fpc-iii.git] / tools / perf / util / sort.c
blob7e3871606df3a9911fe150105942d61e4c2a5848
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,symbol_to,cycles";
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);
74 width = max(7U, width) - 6;
75 return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
76 width, width, comm ?: "");
79 struct sort_entry sort_thread = {
80 .se_header = " Pid:Command",
81 .se_cmp = sort__thread_cmp,
82 .se_snprintf = hist_entry__thread_snprintf,
83 .se_width_idx = HISTC_THREAD,
86 /* --sort comm */
88 static int64_t
89 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
91 /* Compare the addr that should be unique among comm */
92 return strcmp(comm__str(right->comm), comm__str(left->comm));
95 static int64_t
96 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
98 /* Compare the addr that should be unique among comm */
99 return strcmp(comm__str(right->comm), comm__str(left->comm));
102 static int64_t
103 sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
105 return strcmp(comm__str(right->comm), comm__str(left->comm));
108 static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
109 size_t size, unsigned int width)
111 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
114 struct sort_entry sort_comm = {
115 .se_header = "Command",
116 .se_cmp = sort__comm_cmp,
117 .se_collapse = sort__comm_collapse,
118 .se_sort = sort__comm_sort,
119 .se_snprintf = hist_entry__comm_snprintf,
120 .se_width_idx = HISTC_COMM,
123 /* --sort dso */
125 static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
127 struct dso *dso_l = map_l ? map_l->dso : NULL;
128 struct dso *dso_r = map_r ? map_r->dso : NULL;
129 const char *dso_name_l, *dso_name_r;
131 if (!dso_l || !dso_r)
132 return cmp_null(dso_r, dso_l);
134 if (verbose) {
135 dso_name_l = dso_l->long_name;
136 dso_name_r = dso_r->long_name;
137 } else {
138 dso_name_l = dso_l->short_name;
139 dso_name_r = dso_r->short_name;
142 return strcmp(dso_name_l, dso_name_r);
145 static int64_t
146 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
148 return _sort__dso_cmp(right->ms.map, left->ms.map);
151 static int _hist_entry__dso_snprintf(struct map *map, char *bf,
152 size_t size, unsigned int width)
154 if (map && map->dso) {
155 const char *dso_name = !verbose ? map->dso->short_name :
156 map->dso->long_name;
157 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
160 return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
163 static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
164 size_t size, unsigned int width)
166 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
169 struct sort_entry sort_dso = {
170 .se_header = "Shared Object",
171 .se_cmp = sort__dso_cmp,
172 .se_snprintf = hist_entry__dso_snprintf,
173 .se_width_idx = HISTC_DSO,
176 /* --sort symbol */
178 static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
180 return (int64_t)(right_ip - left_ip);
183 static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_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 if (sym_l->start != sym_r->start)
192 return (int64_t)(sym_r->start - sym_l->start);
194 return (int64_t)(sym_r->end - sym_l->end);
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 if (ret > width)
261 bf[width] = '\0';
263 return width;
266 static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
267 size_t size, unsigned int width)
269 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
270 he->level, bf, size, width);
273 struct sort_entry sort_sym = {
274 .se_header = "Symbol",
275 .se_cmp = sort__sym_cmp,
276 .se_sort = sort__sym_sort,
277 .se_snprintf = hist_entry__sym_snprintf,
278 .se_width_idx = HISTC_SYMBOL,
281 /* --sort srcline */
283 static int64_t
284 sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
286 if (!left->srcline) {
287 if (!left->ms.map)
288 left->srcline = SRCLINE_UNKNOWN;
289 else {
290 struct map *map = left->ms.map;
291 left->srcline = get_srcline(map->dso,
292 map__rip_2objdump(map, left->ip),
293 left->ms.sym, true);
296 if (!right->srcline) {
297 if (!right->ms.map)
298 right->srcline = SRCLINE_UNKNOWN;
299 else {
300 struct map *map = right->ms.map;
301 right->srcline = get_srcline(map->dso,
302 map__rip_2objdump(map, right->ip),
303 right->ms.sym, true);
306 return strcmp(right->srcline, left->srcline);
309 static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
310 size_t size, unsigned int width)
312 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline);
315 struct sort_entry sort_srcline = {
316 .se_header = "Source:Line",
317 .se_cmp = sort__srcline_cmp,
318 .se_snprintf = hist_entry__srcline_snprintf,
319 .se_width_idx = HISTC_SRCLINE,
322 /* --sort srcfile */
324 static char no_srcfile[1];
326 static char *get_srcfile(struct hist_entry *e)
328 char *sf, *p;
329 struct map *map = e->ms.map;
331 sf = get_srcline(map->dso, map__rip_2objdump(map, e->ip),
332 e->ms.sym, true);
333 if (!strcmp(sf, SRCLINE_UNKNOWN))
334 return no_srcfile;
335 p = strchr(sf, ':');
336 if (p && *sf) {
337 *p = 0;
338 return sf;
340 free(sf);
341 return no_srcfile;
344 static int64_t
345 sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
347 if (!left->srcfile) {
348 if (!left->ms.map)
349 left->srcfile = no_srcfile;
350 else
351 left->srcfile = get_srcfile(left);
353 if (!right->srcfile) {
354 if (!right->ms.map)
355 right->srcfile = no_srcfile;
356 else
357 right->srcfile = get_srcfile(right);
359 return strcmp(right->srcfile, left->srcfile);
362 static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
363 size_t size, unsigned int width)
365 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile);
368 struct sort_entry sort_srcfile = {
369 .se_header = "Source File",
370 .se_cmp = sort__srcfile_cmp,
371 .se_snprintf = hist_entry__srcfile_snprintf,
372 .se_width_idx = HISTC_SRCFILE,
375 /* --sort parent */
377 static int64_t
378 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
380 struct symbol *sym_l = left->parent;
381 struct symbol *sym_r = right->parent;
383 if (!sym_l || !sym_r)
384 return cmp_null(sym_l, sym_r);
386 return strcmp(sym_r->name, sym_l->name);
389 static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
390 size_t size, unsigned int width)
392 return repsep_snprintf(bf, size, "%-*.*s", width, width,
393 he->parent ? he->parent->name : "[other]");
396 struct sort_entry sort_parent = {
397 .se_header = "Parent symbol",
398 .se_cmp = sort__parent_cmp,
399 .se_snprintf = hist_entry__parent_snprintf,
400 .se_width_idx = HISTC_PARENT,
403 /* --sort cpu */
405 static int64_t
406 sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
408 return right->cpu - left->cpu;
411 static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
412 size_t size, unsigned int width)
414 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
417 struct sort_entry sort_cpu = {
418 .se_header = "CPU",
419 .se_cmp = sort__cpu_cmp,
420 .se_snprintf = hist_entry__cpu_snprintf,
421 .se_width_idx = HISTC_CPU,
424 /* sort keys for branch stacks */
426 static int64_t
427 sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
429 if (!left->branch_info || !right->branch_info)
430 return cmp_null(left->branch_info, right->branch_info);
432 return _sort__dso_cmp(left->branch_info->from.map,
433 right->branch_info->from.map);
436 static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
437 size_t size, unsigned int width)
439 if (he->branch_info)
440 return _hist_entry__dso_snprintf(he->branch_info->from.map,
441 bf, size, width);
442 else
443 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
446 static int64_t
447 sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
449 if (!left->branch_info || !right->branch_info)
450 return cmp_null(left->branch_info, right->branch_info);
452 return _sort__dso_cmp(left->branch_info->to.map,
453 right->branch_info->to.map);
456 static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
457 size_t size, unsigned int width)
459 if (he->branch_info)
460 return _hist_entry__dso_snprintf(he->branch_info->to.map,
461 bf, size, width);
462 else
463 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
466 static int64_t
467 sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
469 struct addr_map_symbol *from_l = &left->branch_info->from;
470 struct addr_map_symbol *from_r = &right->branch_info->from;
472 if (!left->branch_info || !right->branch_info)
473 return cmp_null(left->branch_info, right->branch_info);
475 from_l = &left->branch_info->from;
476 from_r = &right->branch_info->from;
478 if (!from_l->sym && !from_r->sym)
479 return _sort__addr_cmp(from_l->addr, from_r->addr);
481 return _sort__sym_cmp(from_l->sym, from_r->sym);
484 static int64_t
485 sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
487 struct addr_map_symbol *to_l, *to_r;
489 if (!left->branch_info || !right->branch_info)
490 return cmp_null(left->branch_info, right->branch_info);
492 to_l = &left->branch_info->to;
493 to_r = &right->branch_info->to;
495 if (!to_l->sym && !to_r->sym)
496 return _sort__addr_cmp(to_l->addr, to_r->addr);
498 return _sort__sym_cmp(to_l->sym, to_r->sym);
501 static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
502 size_t size, unsigned int width)
504 if (he->branch_info) {
505 struct addr_map_symbol *from = &he->branch_info->from;
507 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
508 he->level, bf, size, width);
511 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
514 static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
515 size_t size, unsigned int width)
517 if (he->branch_info) {
518 struct addr_map_symbol *to = &he->branch_info->to;
520 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
521 he->level, bf, size, width);
524 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
527 struct sort_entry sort_dso_from = {
528 .se_header = "Source Shared Object",
529 .se_cmp = sort__dso_from_cmp,
530 .se_snprintf = hist_entry__dso_from_snprintf,
531 .se_width_idx = HISTC_DSO_FROM,
534 struct sort_entry sort_dso_to = {
535 .se_header = "Target Shared Object",
536 .se_cmp = sort__dso_to_cmp,
537 .se_snprintf = hist_entry__dso_to_snprintf,
538 .se_width_idx = HISTC_DSO_TO,
541 struct sort_entry sort_sym_from = {
542 .se_header = "Source Symbol",
543 .se_cmp = sort__sym_from_cmp,
544 .se_snprintf = hist_entry__sym_from_snprintf,
545 .se_width_idx = HISTC_SYMBOL_FROM,
548 struct sort_entry sort_sym_to = {
549 .se_header = "Target Symbol",
550 .se_cmp = sort__sym_to_cmp,
551 .se_snprintf = hist_entry__sym_to_snprintf,
552 .se_width_idx = HISTC_SYMBOL_TO,
555 static int64_t
556 sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
558 unsigned char mp, p;
560 if (!left->branch_info || !right->branch_info)
561 return cmp_null(left->branch_info, right->branch_info);
563 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
564 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
565 return mp || p;
568 static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
569 size_t size, unsigned int width){
570 static const char *out = "N/A";
572 if (he->branch_info) {
573 if (he->branch_info->flags.predicted)
574 out = "N";
575 else if (he->branch_info->flags.mispred)
576 out = "Y";
579 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
582 static int64_t
583 sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
585 return left->branch_info->flags.cycles -
586 right->branch_info->flags.cycles;
589 static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
590 size_t size, unsigned int width)
592 if (he->branch_info->flags.cycles == 0)
593 return repsep_snprintf(bf, size, "%-*s", width, "-");
594 return repsep_snprintf(bf, size, "%-*hd", width,
595 he->branch_info->flags.cycles);
598 struct sort_entry sort_cycles = {
599 .se_header = "Basic Block Cycles",
600 .se_cmp = sort__cycles_cmp,
601 .se_snprintf = hist_entry__cycles_snprintf,
602 .se_width_idx = HISTC_CYCLES,
605 /* --sort daddr_sym */
606 static int64_t
607 sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
609 uint64_t l = 0, r = 0;
611 if (left->mem_info)
612 l = left->mem_info->daddr.addr;
613 if (right->mem_info)
614 r = right->mem_info->daddr.addr;
616 return (int64_t)(r - l);
619 static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
620 size_t size, unsigned int width)
622 uint64_t addr = 0;
623 struct map *map = NULL;
624 struct symbol *sym = NULL;
626 if (he->mem_info) {
627 addr = he->mem_info->daddr.addr;
628 map = he->mem_info->daddr.map;
629 sym = he->mem_info->daddr.sym;
631 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
632 width);
635 static int64_t
636 sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
638 struct map *map_l = NULL;
639 struct map *map_r = NULL;
641 if (left->mem_info)
642 map_l = left->mem_info->daddr.map;
643 if (right->mem_info)
644 map_r = right->mem_info->daddr.map;
646 return _sort__dso_cmp(map_l, map_r);
649 static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
650 size_t size, unsigned int width)
652 struct map *map = NULL;
654 if (he->mem_info)
655 map = he->mem_info->daddr.map;
657 return _hist_entry__dso_snprintf(map, bf, size, width);
660 static int64_t
661 sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
663 union perf_mem_data_src data_src_l;
664 union perf_mem_data_src data_src_r;
666 if (left->mem_info)
667 data_src_l = left->mem_info->data_src;
668 else
669 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
671 if (right->mem_info)
672 data_src_r = right->mem_info->data_src;
673 else
674 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
676 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
679 static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
680 size_t size, unsigned int width)
682 const char *out;
683 u64 mask = PERF_MEM_LOCK_NA;
685 if (he->mem_info)
686 mask = he->mem_info->data_src.mem_lock;
688 if (mask & PERF_MEM_LOCK_NA)
689 out = "N/A";
690 else if (mask & PERF_MEM_LOCK_LOCKED)
691 out = "Yes";
692 else
693 out = "No";
695 return repsep_snprintf(bf, size, "%-*s", width, out);
698 static int64_t
699 sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
701 union perf_mem_data_src data_src_l;
702 union perf_mem_data_src data_src_r;
704 if (left->mem_info)
705 data_src_l = left->mem_info->data_src;
706 else
707 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
709 if (right->mem_info)
710 data_src_r = right->mem_info->data_src;
711 else
712 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
714 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
717 static const char * const tlb_access[] = {
718 "N/A",
719 "HIT",
720 "MISS",
721 "L1",
722 "L2",
723 "Walker",
724 "Fault",
726 #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
728 static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
729 size_t size, unsigned int width)
731 char out[64];
732 size_t sz = sizeof(out) - 1; /* -1 for null termination */
733 size_t l = 0, i;
734 u64 m = PERF_MEM_TLB_NA;
735 u64 hit, miss;
737 out[0] = '\0';
739 if (he->mem_info)
740 m = he->mem_info->data_src.mem_dtlb;
742 hit = m & PERF_MEM_TLB_HIT;
743 miss = m & PERF_MEM_TLB_MISS;
745 /* already taken care of */
746 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
748 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
749 if (!(m & 0x1))
750 continue;
751 if (l) {
752 strcat(out, " or ");
753 l += 4;
755 strncat(out, tlb_access[i], sz - l);
756 l += strlen(tlb_access[i]);
758 if (*out == '\0')
759 strcpy(out, "N/A");
760 if (hit)
761 strncat(out, " hit", sz - l);
762 if (miss)
763 strncat(out, " miss", sz - l);
765 return repsep_snprintf(bf, size, "%-*s", width, out);
768 static int64_t
769 sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
771 union perf_mem_data_src data_src_l;
772 union perf_mem_data_src data_src_r;
774 if (left->mem_info)
775 data_src_l = left->mem_info->data_src;
776 else
777 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
779 if (right->mem_info)
780 data_src_r = right->mem_info->data_src;
781 else
782 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
784 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
787 static const char * const mem_lvl[] = {
788 "N/A",
789 "HIT",
790 "MISS",
791 "L1",
792 "LFB",
793 "L2",
794 "L3",
795 "Local RAM",
796 "Remote RAM (1 hop)",
797 "Remote RAM (2 hops)",
798 "Remote Cache (1 hop)",
799 "Remote Cache (2 hops)",
800 "I/O",
801 "Uncached",
803 #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
805 static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
806 size_t size, unsigned int width)
808 char out[64];
809 size_t sz = sizeof(out) - 1; /* -1 for null termination */
810 size_t i, l = 0;
811 u64 m = PERF_MEM_LVL_NA;
812 u64 hit, miss;
814 if (he->mem_info)
815 m = he->mem_info->data_src.mem_lvl;
817 out[0] = '\0';
819 hit = m & PERF_MEM_LVL_HIT;
820 miss = m & PERF_MEM_LVL_MISS;
822 /* already taken care of */
823 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
825 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
826 if (!(m & 0x1))
827 continue;
828 if (l) {
829 strcat(out, " or ");
830 l += 4;
832 strncat(out, mem_lvl[i], sz - l);
833 l += strlen(mem_lvl[i]);
835 if (*out == '\0')
836 strcpy(out, "N/A");
837 if (hit)
838 strncat(out, " hit", sz - l);
839 if (miss)
840 strncat(out, " miss", sz - l);
842 return repsep_snprintf(bf, size, "%-*s", width, out);
845 static int64_t
846 sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
848 union perf_mem_data_src data_src_l;
849 union perf_mem_data_src data_src_r;
851 if (left->mem_info)
852 data_src_l = left->mem_info->data_src;
853 else
854 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
856 if (right->mem_info)
857 data_src_r = right->mem_info->data_src;
858 else
859 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
861 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
864 static const char * const snoop_access[] = {
865 "N/A",
866 "None",
867 "Miss",
868 "Hit",
869 "HitM",
871 #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
873 static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
874 size_t size, unsigned int width)
876 char out[64];
877 size_t sz = sizeof(out) - 1; /* -1 for null termination */
878 size_t i, l = 0;
879 u64 m = PERF_MEM_SNOOP_NA;
881 out[0] = '\0';
883 if (he->mem_info)
884 m = he->mem_info->data_src.mem_snoop;
886 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
887 if (!(m & 0x1))
888 continue;
889 if (l) {
890 strcat(out, " or ");
891 l += 4;
893 strncat(out, snoop_access[i], sz - l);
894 l += strlen(snoop_access[i]);
897 if (*out == '\0')
898 strcpy(out, "N/A");
900 return repsep_snprintf(bf, size, "%-*s", width, out);
903 static inline u64 cl_address(u64 address)
905 /* return the cacheline of the address */
906 return (address & ~(cacheline_size - 1));
909 static int64_t
910 sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
912 u64 l, r;
913 struct map *l_map, *r_map;
915 if (!left->mem_info) return -1;
916 if (!right->mem_info) return 1;
918 /* group event types together */
919 if (left->cpumode > right->cpumode) return -1;
920 if (left->cpumode < right->cpumode) return 1;
922 l_map = left->mem_info->daddr.map;
923 r_map = right->mem_info->daddr.map;
925 /* if both are NULL, jump to sort on al_addr instead */
926 if (!l_map && !r_map)
927 goto addr;
929 if (!l_map) return -1;
930 if (!r_map) return 1;
932 if (l_map->maj > r_map->maj) return -1;
933 if (l_map->maj < r_map->maj) return 1;
935 if (l_map->min > r_map->min) return -1;
936 if (l_map->min < r_map->min) return 1;
938 if (l_map->ino > r_map->ino) return -1;
939 if (l_map->ino < r_map->ino) return 1;
941 if (l_map->ino_generation > r_map->ino_generation) return -1;
942 if (l_map->ino_generation < r_map->ino_generation) return 1;
945 * Addresses with no major/minor numbers are assumed to be
946 * anonymous in userspace. Sort those on pid then address.
948 * The kernel and non-zero major/minor mapped areas are
949 * assumed to be unity mapped. Sort those on address.
952 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
953 (!(l_map->flags & MAP_SHARED)) &&
954 !l_map->maj && !l_map->min && !l_map->ino &&
955 !l_map->ino_generation) {
956 /* userspace anonymous */
958 if (left->thread->pid_ > right->thread->pid_) return -1;
959 if (left->thread->pid_ < right->thread->pid_) return 1;
962 addr:
963 /* al_addr does all the right addr - start + offset calculations */
964 l = cl_address(left->mem_info->daddr.al_addr);
965 r = cl_address(right->mem_info->daddr.al_addr);
967 if (l > r) return -1;
968 if (l < r) return 1;
970 return 0;
973 static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
974 size_t size, unsigned int width)
977 uint64_t addr = 0;
978 struct map *map = NULL;
979 struct symbol *sym = NULL;
980 char level = he->level;
982 if (he->mem_info) {
983 addr = cl_address(he->mem_info->daddr.al_addr);
984 map = he->mem_info->daddr.map;
985 sym = he->mem_info->daddr.sym;
987 /* print [s] for shared data mmaps */
988 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
989 map && (map->type == MAP__VARIABLE) &&
990 (map->flags & MAP_SHARED) &&
991 (map->maj || map->min || map->ino ||
992 map->ino_generation))
993 level = 's';
994 else if (!map)
995 level = 'X';
997 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
998 width);
1001 struct sort_entry sort_mispredict = {
1002 .se_header = "Branch Mispredicted",
1003 .se_cmp = sort__mispredict_cmp,
1004 .se_snprintf = hist_entry__mispredict_snprintf,
1005 .se_width_idx = HISTC_MISPREDICT,
1008 static u64 he_weight(struct hist_entry *he)
1010 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
1013 static int64_t
1014 sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1016 return he_weight(left) - he_weight(right);
1019 static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
1020 size_t size, unsigned int width)
1022 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
1025 struct sort_entry sort_local_weight = {
1026 .se_header = "Local Weight",
1027 .se_cmp = sort__local_weight_cmp,
1028 .se_snprintf = hist_entry__local_weight_snprintf,
1029 .se_width_idx = HISTC_LOCAL_WEIGHT,
1032 static int64_t
1033 sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1035 return left->stat.weight - right->stat.weight;
1038 static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
1039 size_t size, unsigned int width)
1041 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
1044 struct sort_entry sort_global_weight = {
1045 .se_header = "Weight",
1046 .se_cmp = sort__global_weight_cmp,
1047 .se_snprintf = hist_entry__global_weight_snprintf,
1048 .se_width_idx = HISTC_GLOBAL_WEIGHT,
1051 struct sort_entry sort_mem_daddr_sym = {
1052 .se_header = "Data Symbol",
1053 .se_cmp = sort__daddr_cmp,
1054 .se_snprintf = hist_entry__daddr_snprintf,
1055 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1058 struct sort_entry sort_mem_daddr_dso = {
1059 .se_header = "Data Object",
1060 .se_cmp = sort__dso_daddr_cmp,
1061 .se_snprintf = hist_entry__dso_daddr_snprintf,
1062 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1065 struct sort_entry sort_mem_locked = {
1066 .se_header = "Locked",
1067 .se_cmp = sort__locked_cmp,
1068 .se_snprintf = hist_entry__locked_snprintf,
1069 .se_width_idx = HISTC_MEM_LOCKED,
1072 struct sort_entry sort_mem_tlb = {
1073 .se_header = "TLB access",
1074 .se_cmp = sort__tlb_cmp,
1075 .se_snprintf = hist_entry__tlb_snprintf,
1076 .se_width_idx = HISTC_MEM_TLB,
1079 struct sort_entry sort_mem_lvl = {
1080 .se_header = "Memory access",
1081 .se_cmp = sort__lvl_cmp,
1082 .se_snprintf = hist_entry__lvl_snprintf,
1083 .se_width_idx = HISTC_MEM_LVL,
1086 struct sort_entry sort_mem_snoop = {
1087 .se_header = "Snoop",
1088 .se_cmp = sort__snoop_cmp,
1089 .se_snprintf = hist_entry__snoop_snprintf,
1090 .se_width_idx = HISTC_MEM_SNOOP,
1093 struct sort_entry sort_mem_dcacheline = {
1094 .se_header = "Data Cacheline",
1095 .se_cmp = sort__dcacheline_cmp,
1096 .se_snprintf = hist_entry__dcacheline_snprintf,
1097 .se_width_idx = HISTC_MEM_DCACHELINE,
1100 static int64_t
1101 sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1103 if (!left->branch_info || !right->branch_info)
1104 return cmp_null(left->branch_info, right->branch_info);
1106 return left->branch_info->flags.abort !=
1107 right->branch_info->flags.abort;
1110 static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
1111 size_t size, unsigned int width)
1113 static const char *out = "N/A";
1115 if (he->branch_info) {
1116 if (he->branch_info->flags.abort)
1117 out = "A";
1118 else
1119 out = ".";
1122 return repsep_snprintf(bf, size, "%-*s", width, out);
1125 struct sort_entry sort_abort = {
1126 .se_header = "Transaction abort",
1127 .se_cmp = sort__abort_cmp,
1128 .se_snprintf = hist_entry__abort_snprintf,
1129 .se_width_idx = HISTC_ABORT,
1132 static int64_t
1133 sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1135 if (!left->branch_info || !right->branch_info)
1136 return cmp_null(left->branch_info, right->branch_info);
1138 return left->branch_info->flags.in_tx !=
1139 right->branch_info->flags.in_tx;
1142 static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
1143 size_t size, unsigned int width)
1145 static const char *out = "N/A";
1147 if (he->branch_info) {
1148 if (he->branch_info->flags.in_tx)
1149 out = "T";
1150 else
1151 out = ".";
1154 return repsep_snprintf(bf, size, "%-*s", width, out);
1157 struct sort_entry sort_in_tx = {
1158 .se_header = "Branch in transaction",
1159 .se_cmp = sort__in_tx_cmp,
1160 .se_snprintf = hist_entry__in_tx_snprintf,
1161 .se_width_idx = HISTC_IN_TX,
1164 static int64_t
1165 sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1167 return left->transaction - right->transaction;
1170 static inline char *add_str(char *p, const char *str)
1172 strcpy(p, str);
1173 return p + strlen(str);
1176 static struct txbit {
1177 unsigned flag;
1178 const char *name;
1179 int skip_for_len;
1180 } txbits[] = {
1181 { PERF_TXN_ELISION, "EL ", 0 },
1182 { PERF_TXN_TRANSACTION, "TX ", 1 },
1183 { PERF_TXN_SYNC, "SYNC ", 1 },
1184 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1185 { PERF_TXN_RETRY, "RETRY ", 0 },
1186 { PERF_TXN_CONFLICT, "CON ", 0 },
1187 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1188 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1189 { 0, NULL, 0 }
1192 int hist_entry__transaction_len(void)
1194 int i;
1195 int len = 0;
1197 for (i = 0; txbits[i].name; i++) {
1198 if (!txbits[i].skip_for_len)
1199 len += strlen(txbits[i].name);
1201 len += 4; /* :XX<space> */
1202 return len;
1205 static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
1206 size_t size, unsigned int width)
1208 u64 t = he->transaction;
1209 char buf[128];
1210 char *p = buf;
1211 int i;
1213 buf[0] = 0;
1214 for (i = 0; txbits[i].name; i++)
1215 if (txbits[i].flag & t)
1216 p = add_str(p, txbits[i].name);
1217 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1218 p = add_str(p, "NEITHER ");
1219 if (t & PERF_TXN_ABORT_MASK) {
1220 sprintf(p, ":%" PRIx64,
1221 (t & PERF_TXN_ABORT_MASK) >>
1222 PERF_TXN_ABORT_SHIFT);
1223 p += strlen(p);
1226 return repsep_snprintf(bf, size, "%-*s", width, buf);
1229 struct sort_entry sort_transaction = {
1230 .se_header = "Transaction ",
1231 .se_cmp = sort__transaction_cmp,
1232 .se_snprintf = hist_entry__transaction_snprintf,
1233 .se_width_idx = HISTC_TRANSACTION,
1236 struct sort_dimension {
1237 const char *name;
1238 struct sort_entry *entry;
1239 int taken;
1242 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1244 static struct sort_dimension common_sort_dimensions[] = {
1245 DIM(SORT_PID, "pid", sort_thread),
1246 DIM(SORT_COMM, "comm", sort_comm),
1247 DIM(SORT_DSO, "dso", sort_dso),
1248 DIM(SORT_SYM, "symbol", sort_sym),
1249 DIM(SORT_PARENT, "parent", sort_parent),
1250 DIM(SORT_CPU, "cpu", sort_cpu),
1251 DIM(SORT_SRCLINE, "srcline", sort_srcline),
1252 DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
1253 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1254 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
1255 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
1258 #undef DIM
1260 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1262 static struct sort_dimension bstack_sort_dimensions[] = {
1263 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1264 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1265 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1266 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1267 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
1268 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1269 DIM(SORT_ABORT, "abort", sort_abort),
1270 DIM(SORT_CYCLES, "cycles", sort_cycles),
1273 #undef DIM
1275 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1277 static struct sort_dimension memory_sort_dimensions[] = {
1278 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1279 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1280 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1281 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1282 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1283 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1284 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
1287 #undef DIM
1289 struct hpp_dimension {
1290 const char *name;
1291 struct perf_hpp_fmt *fmt;
1292 int taken;
1295 #define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1297 static struct hpp_dimension hpp_sort_dimensions[] = {
1298 DIM(PERF_HPP__OVERHEAD, "overhead"),
1299 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1300 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1301 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1302 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1303 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
1304 DIM(PERF_HPP__SAMPLES, "sample"),
1305 DIM(PERF_HPP__PERIOD, "period"),
1308 #undef DIM
1310 struct hpp_sort_entry {
1311 struct perf_hpp_fmt hpp;
1312 struct sort_entry *se;
1315 bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1317 struct hpp_sort_entry *hse_a;
1318 struct hpp_sort_entry *hse_b;
1320 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1321 return false;
1323 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1324 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1326 return hse_a->se == hse_b->se;
1329 void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1331 struct hpp_sort_entry *hse;
1333 if (!perf_hpp__is_sort_entry(fmt))
1334 return;
1336 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1337 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
1340 static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1341 struct perf_evsel *evsel)
1343 struct hpp_sort_entry *hse;
1344 size_t len = fmt->user_len;
1346 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1348 if (!len)
1349 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
1351 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
1354 static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1355 struct perf_hpp *hpp __maybe_unused,
1356 struct perf_evsel *evsel)
1358 struct hpp_sort_entry *hse;
1359 size_t len = fmt->user_len;
1361 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1363 if (!len)
1364 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
1366 return len;
1369 static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1370 struct hist_entry *he)
1372 struct hpp_sort_entry *hse;
1373 size_t len = fmt->user_len;
1375 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1377 if (!len)
1378 len = hists__col_len(he->hists, hse->se->se_width_idx);
1380 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1383 static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1384 struct hist_entry *a, struct hist_entry *b)
1386 struct hpp_sort_entry *hse;
1388 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1389 return hse->se->se_cmp(a, b);
1392 static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1393 struct hist_entry *a, struct hist_entry *b)
1395 struct hpp_sort_entry *hse;
1396 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1398 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1399 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1400 return collapse_fn(a, b);
1403 static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1404 struct hist_entry *a, struct hist_entry *b)
1406 struct hpp_sort_entry *hse;
1407 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1409 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1410 sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1411 return sort_fn(a, b);
1414 static struct hpp_sort_entry *
1415 __sort_dimension__alloc_hpp(struct sort_dimension *sd)
1417 struct hpp_sort_entry *hse;
1419 hse = malloc(sizeof(*hse));
1420 if (hse == NULL) {
1421 pr_err("Memory allocation failed\n");
1422 return NULL;
1425 hse->se = sd->entry;
1426 hse->hpp.name = sd->entry->se_header;
1427 hse->hpp.header = __sort__hpp_header;
1428 hse->hpp.width = __sort__hpp_width;
1429 hse->hpp.entry = __sort__hpp_entry;
1430 hse->hpp.color = NULL;
1432 hse->hpp.cmp = __sort__hpp_cmp;
1433 hse->hpp.collapse = __sort__hpp_collapse;
1434 hse->hpp.sort = __sort__hpp_sort;
1436 INIT_LIST_HEAD(&hse->hpp.list);
1437 INIT_LIST_HEAD(&hse->hpp.sort_list);
1438 hse->hpp.elide = false;
1439 hse->hpp.len = 0;
1440 hse->hpp.user_len = 0;
1442 return hse;
1445 bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1447 return format->header == __sort__hpp_header;
1450 static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1452 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1454 if (hse == NULL)
1455 return -1;
1457 perf_hpp__register_sort_field(&hse->hpp);
1458 return 0;
1461 static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1463 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1465 if (hse == NULL)
1466 return -1;
1468 perf_hpp__column_register(&hse->hpp);
1469 return 0;
1472 static int __sort_dimension__add(struct sort_dimension *sd)
1474 if (sd->taken)
1475 return 0;
1477 if (__sort_dimension__add_hpp_sort(sd) < 0)
1478 return -1;
1480 if (sd->entry->se_collapse)
1481 sort__need_collapse = 1;
1483 sd->taken = 1;
1485 return 0;
1488 static int __hpp_dimension__add(struct hpp_dimension *hd)
1490 if (!hd->taken) {
1491 hd->taken = 1;
1493 perf_hpp__register_sort_field(hd->fmt);
1495 return 0;
1498 static int __sort_dimension__add_output(struct sort_dimension *sd)
1500 if (sd->taken)
1501 return 0;
1503 if (__sort_dimension__add_hpp_output(sd) < 0)
1504 return -1;
1506 sd->taken = 1;
1507 return 0;
1510 static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1512 if (!hd->taken) {
1513 hd->taken = 1;
1515 perf_hpp__column_register(hd->fmt);
1517 return 0;
1520 int sort_dimension__add(const char *tok)
1522 unsigned int i;
1524 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1525 struct sort_dimension *sd = &common_sort_dimensions[i];
1527 if (strncasecmp(tok, sd->name, strlen(tok)))
1528 continue;
1530 if (sd->entry == &sort_parent) {
1531 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1532 if (ret) {
1533 char err[BUFSIZ];
1535 regerror(ret, &parent_regex, err, sizeof(err));
1536 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1537 return -EINVAL;
1539 sort__has_parent = 1;
1540 } else if (sd->entry == &sort_sym) {
1541 sort__has_sym = 1;
1543 * perf diff displays the performance difference amongst
1544 * two or more perf.data files. Those files could come
1545 * from different binaries. So we should not compare
1546 * their ips, but the name of symbol.
1548 if (sort__mode == SORT_MODE__DIFF)
1549 sd->entry->se_collapse = sort__sym_sort;
1551 } else if (sd->entry == &sort_dso) {
1552 sort__has_dso = 1;
1555 return __sort_dimension__add(sd);
1558 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1559 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1561 if (strncasecmp(tok, hd->name, strlen(tok)))
1562 continue;
1564 return __hpp_dimension__add(hd);
1567 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1568 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1570 if (strncasecmp(tok, sd->name, strlen(tok)))
1571 continue;
1573 if (sort__mode != SORT_MODE__BRANCH)
1574 return -EINVAL;
1576 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1577 sort__has_sym = 1;
1579 __sort_dimension__add(sd);
1580 return 0;
1583 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1584 struct sort_dimension *sd = &memory_sort_dimensions[i];
1586 if (strncasecmp(tok, sd->name, strlen(tok)))
1587 continue;
1589 if (sort__mode != SORT_MODE__MEMORY)
1590 return -EINVAL;
1592 if (sd->entry == &sort_mem_daddr_sym)
1593 sort__has_sym = 1;
1595 __sort_dimension__add(sd);
1596 return 0;
1599 return -ESRCH;
1602 static const char *get_default_sort_order(void)
1604 const char *default_sort_orders[] = {
1605 default_sort_order,
1606 default_branch_sort_order,
1607 default_mem_sort_order,
1608 default_top_sort_order,
1609 default_diff_sort_order,
1612 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1614 return default_sort_orders[sort__mode];
1617 static int setup_sort_order(void)
1619 char *new_sort_order;
1622 * Append '+'-prefixed sort order to the default sort
1623 * order string.
1625 if (!sort_order || is_strict_order(sort_order))
1626 return 0;
1628 if (sort_order[1] == '\0') {
1629 error("Invalid --sort key: `+'");
1630 return -EINVAL;
1634 * We allocate new sort_order string, but we never free it,
1635 * because it's checked over the rest of the code.
1637 if (asprintf(&new_sort_order, "%s,%s",
1638 get_default_sort_order(), sort_order + 1) < 0) {
1639 error("Not enough memory to set up --sort");
1640 return -ENOMEM;
1643 sort_order = new_sort_order;
1644 return 0;
1647 static int __setup_sorting(void)
1649 char *tmp, *tok, *str;
1650 const char *sort_keys;
1651 int ret = 0;
1653 ret = setup_sort_order();
1654 if (ret)
1655 return ret;
1657 sort_keys = sort_order;
1658 if (sort_keys == NULL) {
1659 if (is_strict_order(field_order)) {
1661 * If user specified field order but no sort order,
1662 * we'll honor it and not add default sort orders.
1664 return 0;
1667 sort_keys = get_default_sort_order();
1670 str = strdup(sort_keys);
1671 if (str == NULL) {
1672 error("Not enough memory to setup sort keys");
1673 return -ENOMEM;
1676 for (tok = strtok_r(str, ", ", &tmp);
1677 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1678 ret = sort_dimension__add(tok);
1679 if (ret == -EINVAL) {
1680 error("Invalid --sort key: `%s'", tok);
1681 break;
1682 } else if (ret == -ESRCH) {
1683 error("Unknown --sort key: `%s'", tok);
1684 break;
1688 free(str);
1689 return ret;
1692 void perf_hpp__set_elide(int idx, bool elide)
1694 struct perf_hpp_fmt *fmt;
1695 struct hpp_sort_entry *hse;
1697 perf_hpp__for_each_format(fmt) {
1698 if (!perf_hpp__is_sort_entry(fmt))
1699 continue;
1701 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1702 if (hse->se->se_width_idx == idx) {
1703 fmt->elide = elide;
1704 break;
1709 static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
1711 if (list && strlist__nr_entries(list) == 1) {
1712 if (fp != NULL)
1713 fprintf(fp, "# %s: %s\n", list_name,
1714 strlist__entry(list, 0)->s);
1715 return true;
1717 return false;
1720 static bool get_elide(int idx, FILE *output)
1722 switch (idx) {
1723 case HISTC_SYMBOL:
1724 return __get_elide(symbol_conf.sym_list, "symbol", output);
1725 case HISTC_DSO:
1726 return __get_elide(symbol_conf.dso_list, "dso", output);
1727 case HISTC_COMM:
1728 return __get_elide(symbol_conf.comm_list, "comm", output);
1729 default:
1730 break;
1733 if (sort__mode != SORT_MODE__BRANCH)
1734 return false;
1736 switch (idx) {
1737 case HISTC_SYMBOL_FROM:
1738 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1739 case HISTC_SYMBOL_TO:
1740 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1741 case HISTC_DSO_FROM:
1742 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1743 case HISTC_DSO_TO:
1744 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1745 default:
1746 break;
1749 return false;
1752 void sort__setup_elide(FILE *output)
1754 struct perf_hpp_fmt *fmt;
1755 struct hpp_sort_entry *hse;
1757 perf_hpp__for_each_format(fmt) {
1758 if (!perf_hpp__is_sort_entry(fmt))
1759 continue;
1761 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1762 fmt->elide = get_elide(hse->se->se_width_idx, output);
1766 * It makes no sense to elide all of sort entries.
1767 * Just revert them to show up again.
1769 perf_hpp__for_each_format(fmt) {
1770 if (!perf_hpp__is_sort_entry(fmt))
1771 continue;
1773 if (!fmt->elide)
1774 return;
1777 perf_hpp__for_each_format(fmt) {
1778 if (!perf_hpp__is_sort_entry(fmt))
1779 continue;
1781 fmt->elide = false;
1785 static int output_field_add(char *tok)
1787 unsigned int i;
1789 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1790 struct sort_dimension *sd = &common_sort_dimensions[i];
1792 if (strncasecmp(tok, sd->name, strlen(tok)))
1793 continue;
1795 return __sort_dimension__add_output(sd);
1798 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1799 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1801 if (strncasecmp(tok, hd->name, strlen(tok)))
1802 continue;
1804 return __hpp_dimension__add_output(hd);
1807 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1808 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1810 if (strncasecmp(tok, sd->name, strlen(tok)))
1811 continue;
1813 return __sort_dimension__add_output(sd);
1816 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1817 struct sort_dimension *sd = &memory_sort_dimensions[i];
1819 if (strncasecmp(tok, sd->name, strlen(tok)))
1820 continue;
1822 return __sort_dimension__add_output(sd);
1825 return -ESRCH;
1828 static void reset_dimensions(void)
1830 unsigned int i;
1832 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1833 common_sort_dimensions[i].taken = 0;
1835 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1836 hpp_sort_dimensions[i].taken = 0;
1838 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1839 bstack_sort_dimensions[i].taken = 0;
1841 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1842 memory_sort_dimensions[i].taken = 0;
1845 bool is_strict_order(const char *order)
1847 return order && (*order != '+');
1850 static int __setup_output_field(void)
1852 char *tmp, *tok, *str, *strp;
1853 int ret = -EINVAL;
1855 if (field_order == NULL)
1856 return 0;
1858 reset_dimensions();
1860 strp = str = strdup(field_order);
1861 if (str == NULL) {
1862 error("Not enough memory to setup output fields");
1863 return -ENOMEM;
1866 if (!is_strict_order(field_order))
1867 strp++;
1869 if (!strlen(strp)) {
1870 error("Invalid --fields key: `+'");
1871 goto out;
1874 for (tok = strtok_r(strp, ", ", &tmp);
1875 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1876 ret = output_field_add(tok);
1877 if (ret == -EINVAL) {
1878 error("Invalid --fields key: `%s'", tok);
1879 break;
1880 } else if (ret == -ESRCH) {
1881 error("Unknown --fields key: `%s'", tok);
1882 break;
1886 out:
1887 free(str);
1888 return ret;
1891 int setup_sorting(void)
1893 int err;
1895 err = __setup_sorting();
1896 if (err < 0)
1897 return err;
1899 if (parent_pattern != default_parent_pattern) {
1900 err = sort_dimension__add("parent");
1901 if (err < 0)
1902 return err;
1905 reset_dimensions();
1908 * perf diff doesn't use default hpp output fields.
1910 if (sort__mode != SORT_MODE__DIFF)
1911 perf_hpp__init();
1913 err = __setup_output_field();
1914 if (err < 0)
1915 return err;
1917 /* copy sort keys to output fields */
1918 perf_hpp__setup_output_field();
1919 /* and then copy output fields to sort keys */
1920 perf_hpp__append_sort_keys();
1922 return 0;
1925 void reset_output_field(void)
1927 sort__need_collapse = 0;
1928 sort__has_parent = 0;
1929 sort__has_sym = 0;
1930 sort__has_dso = 0;
1932 field_order = NULL;
1933 sort_order = NULL;
1935 reset_dimensions();
1936 perf_hpp__reset_output_field();