8 const char default_parent_pattern[] = "^sys_|^do_page_fault";
9 const char *parent_pattern = default_parent_pattern;
10 const char default_sort_order[] = "comm,dso,symbol";
11 const char *sort_order = default_sort_order;
12 regex_t ignore_callees_regex;
13 int have_ignore_callees = 0;
14 int sort__need_collapse = 0;
15 int sort__has_parent = 0;
16 int sort__has_sym = 0;
17 int sort__has_dso = 0;
18 enum sort_mode sort__mode = SORT_MODE__NORMAL;
20 enum sort_type sort__first_dimension;
22 LIST_HEAD(hist_entry__sort_list);
24 static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
30 n = vsnprintf(bf, size, fmt, ap);
31 if (symbol_conf.field_sep && n > 0) {
35 sep = strchr(sep, *symbol_conf.field_sep);
48 static int64_t cmp_null(const void *l, const void *r)
61 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
63 return right->thread->tid - left->thread->tid;
66 static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
67 size_t size, unsigned int width)
69 const char *comm = thread__comm_str(he->thread);
70 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
71 comm ?: "", he->thread->tid);
74 struct sort_entry sort_thread = {
75 .se_header = "Command: Pid",
76 .se_cmp = sort__thread_cmp,
77 .se_snprintf = hist_entry__thread_snprintf,
78 .se_width_idx = HISTC_THREAD,
84 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
86 /* Compare the addr that should be unique among comm */
87 return comm__str(right->comm) - comm__str(left->comm);
91 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
93 /* Compare the addr that should be unique among comm */
94 return comm__str(right->comm) - comm__str(left->comm);
97 static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
98 size_t size, unsigned int width)
100 return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
103 struct sort_entry sort_comm = {
104 .se_header = "Command",
105 .se_cmp = sort__comm_cmp,
106 .se_collapse = sort__comm_collapse,
107 .se_snprintf = hist_entry__comm_snprintf,
108 .se_width_idx = HISTC_COMM,
113 static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
115 struct dso *dso_l = map_l ? map_l->dso : NULL;
116 struct dso *dso_r = map_r ? map_r->dso : NULL;
117 const char *dso_name_l, *dso_name_r;
119 if (!dso_l || !dso_r)
120 return cmp_null(dso_l, dso_r);
123 dso_name_l = dso_l->long_name;
124 dso_name_r = dso_r->long_name;
126 dso_name_l = dso_l->short_name;
127 dso_name_r = dso_r->short_name;
130 return strcmp(dso_name_l, dso_name_r);
134 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
136 return _sort__dso_cmp(left->ms.map, right->ms.map);
139 static int _hist_entry__dso_snprintf(struct map *map, char *bf,
140 size_t size, unsigned int width)
142 if (map && map->dso) {
143 const char *dso_name = !verbose ? map->dso->short_name :
145 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
148 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
151 static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
152 size_t size, unsigned int width)
154 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
157 struct sort_entry sort_dso = {
158 .se_header = "Shared Object",
159 .se_cmp = sort__dso_cmp,
160 .se_snprintf = hist_entry__dso_snprintf,
161 .se_width_idx = HISTC_DSO,
166 static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
168 return (int64_t)(right_ip - left_ip);
171 static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
175 if (!sym_l || !sym_r)
176 return cmp_null(sym_l, sym_r);
184 return (int64_t)(ip_r - ip_l);
188 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
192 if (!left->ms.sym && !right->ms.sym)
193 return _sort__addr_cmp(left->ip, right->ip);
196 * comparing symbol address alone is not enough since it's a
197 * relative address within a dso.
199 if (!sort__has_dso) {
200 ret = sort__dso_cmp(left, right);
205 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
208 static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
209 u64 ip, char level, char *bf, size_t size,
215 char o = map ? dso__symtab_origin(map->dso) : '!';
216 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
217 BITS_PER_LONG / 4 + 2, ip, o);
220 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
222 if (map->type == MAP__VARIABLE) {
223 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
224 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
225 ip - map->unmap_ip(map, sym->start));
226 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
229 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
234 size_t len = BITS_PER_LONG / 4;
235 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
237 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
244 static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
245 size_t size, unsigned int width)
247 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
248 he->level, bf, size, width);
251 struct sort_entry sort_sym = {
252 .se_header = "Symbol",
253 .se_cmp = sort__sym_cmp,
254 .se_snprintf = hist_entry__sym_snprintf,
255 .se_width_idx = HISTC_SYMBOL,
261 sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
263 if (!left->srcline) {
265 left->srcline = SRCLINE_UNKNOWN;
267 struct map *map = left->ms.map;
268 left->srcline = get_srcline(map->dso,
269 map__rip_2objdump(map, left->ip));
272 if (!right->srcline) {
274 right->srcline = SRCLINE_UNKNOWN;
276 struct map *map = right->ms.map;
277 right->srcline = get_srcline(map->dso,
278 map__rip_2objdump(map, right->ip));
281 return strcmp(left->srcline, right->srcline);
284 static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
286 unsigned int width __maybe_unused)
288 return repsep_snprintf(bf, size, "%s", he->srcline);
291 struct sort_entry sort_srcline = {
292 .se_header = "Source:Line",
293 .se_cmp = sort__srcline_cmp,
294 .se_snprintf = hist_entry__srcline_snprintf,
295 .se_width_idx = HISTC_SRCLINE,
301 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
303 struct symbol *sym_l = left->parent;
304 struct symbol *sym_r = right->parent;
306 if (!sym_l || !sym_r)
307 return cmp_null(sym_l, sym_r);
309 return strcmp(sym_l->name, sym_r->name);
312 static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
313 size_t size, unsigned int width)
315 return repsep_snprintf(bf, size, "%-*s", width,
316 he->parent ? he->parent->name : "[other]");
319 struct sort_entry sort_parent = {
320 .se_header = "Parent symbol",
321 .se_cmp = sort__parent_cmp,
322 .se_snprintf = hist_entry__parent_snprintf,
323 .se_width_idx = HISTC_PARENT,
329 sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
331 return right->cpu - left->cpu;
334 static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
335 size_t size, unsigned int width)
337 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
340 struct sort_entry sort_cpu = {
342 .se_cmp = sort__cpu_cmp,
343 .se_snprintf = hist_entry__cpu_snprintf,
344 .se_width_idx = HISTC_CPU,
347 /* sort keys for branch stacks */
350 sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
352 return _sort__dso_cmp(left->branch_info->from.map,
353 right->branch_info->from.map);
356 static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
357 size_t size, unsigned int width)
359 return _hist_entry__dso_snprintf(he->branch_info->from.map,
364 sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
366 return _sort__dso_cmp(left->branch_info->to.map,
367 right->branch_info->to.map);
370 static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
371 size_t size, unsigned int width)
373 return _hist_entry__dso_snprintf(he->branch_info->to.map,
378 sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
380 struct addr_map_symbol *from_l = &left->branch_info->from;
381 struct addr_map_symbol *from_r = &right->branch_info->from;
383 if (!from_l->sym && !from_r->sym)
384 return _sort__addr_cmp(from_l->addr, from_r->addr);
386 return _sort__sym_cmp(from_l->sym, from_r->sym);
390 sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
392 struct addr_map_symbol *to_l = &left->branch_info->to;
393 struct addr_map_symbol *to_r = &right->branch_info->to;
395 if (!to_l->sym && !to_r->sym)
396 return _sort__addr_cmp(to_l->addr, to_r->addr);
398 return _sort__sym_cmp(to_l->sym, to_r->sym);
401 static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
402 size_t size, unsigned int width)
404 struct addr_map_symbol *from = &he->branch_info->from;
405 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
406 he->level, bf, size, width);
410 static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
411 size_t size, unsigned int width)
413 struct addr_map_symbol *to = &he->branch_info->to;
414 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
415 he->level, bf, size, width);
419 struct sort_entry sort_dso_from = {
420 .se_header = "Source Shared Object",
421 .se_cmp = sort__dso_from_cmp,
422 .se_snprintf = hist_entry__dso_from_snprintf,
423 .se_width_idx = HISTC_DSO_FROM,
426 struct sort_entry sort_dso_to = {
427 .se_header = "Target Shared Object",
428 .se_cmp = sort__dso_to_cmp,
429 .se_snprintf = hist_entry__dso_to_snprintf,
430 .se_width_idx = HISTC_DSO_TO,
433 struct sort_entry sort_sym_from = {
434 .se_header = "Source Symbol",
435 .se_cmp = sort__sym_from_cmp,
436 .se_snprintf = hist_entry__sym_from_snprintf,
437 .se_width_idx = HISTC_SYMBOL_FROM,
440 struct sort_entry sort_sym_to = {
441 .se_header = "Target Symbol",
442 .se_cmp = sort__sym_to_cmp,
443 .se_snprintf = hist_entry__sym_to_snprintf,
444 .se_width_idx = HISTC_SYMBOL_TO,
448 sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
450 const unsigned char mp = left->branch_info->flags.mispred !=
451 right->branch_info->flags.mispred;
452 const unsigned char p = left->branch_info->flags.predicted !=
453 right->branch_info->flags.predicted;
458 static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
459 size_t size, unsigned int width){
460 static const char *out = "N/A";
462 if (he->branch_info->flags.predicted)
464 else if (he->branch_info->flags.mispred)
467 return repsep_snprintf(bf, size, "%-*s", width, out);
470 /* --sort daddr_sym */
472 sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
474 uint64_t l = 0, r = 0;
477 l = left->mem_info->daddr.addr;
479 r = right->mem_info->daddr.addr;
481 return (int64_t)(r - l);
484 static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
485 size_t size, unsigned int width)
488 struct map *map = NULL;
489 struct symbol *sym = NULL;
492 addr = he->mem_info->daddr.addr;
493 map = he->mem_info->daddr.map;
494 sym = he->mem_info->daddr.sym;
496 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
501 sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
503 struct map *map_l = NULL;
504 struct map *map_r = NULL;
507 map_l = left->mem_info->daddr.map;
509 map_r = right->mem_info->daddr.map;
511 return _sort__dso_cmp(map_l, map_r);
514 static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
515 size_t size, unsigned int width)
517 struct map *map = NULL;
520 map = he->mem_info->daddr.map;
522 return _hist_entry__dso_snprintf(map, bf, size, width);
526 sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
528 union perf_mem_data_src data_src_l;
529 union perf_mem_data_src data_src_r;
532 data_src_l = left->mem_info->data_src;
534 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
537 data_src_r = right->mem_info->data_src;
539 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
541 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
544 static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
545 size_t size, unsigned int width)
548 u64 mask = PERF_MEM_LOCK_NA;
551 mask = he->mem_info->data_src.mem_lock;
553 if (mask & PERF_MEM_LOCK_NA)
555 else if (mask & PERF_MEM_LOCK_LOCKED)
560 return repsep_snprintf(bf, size, "%-*s", width, out);
564 sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
566 union perf_mem_data_src data_src_l;
567 union perf_mem_data_src data_src_r;
570 data_src_l = left->mem_info->data_src;
572 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
575 data_src_r = right->mem_info->data_src;
577 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
579 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
582 static const char * const tlb_access[] = {
591 #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
593 static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
594 size_t size, unsigned int width)
597 size_t sz = sizeof(out) - 1; /* -1 for null termination */
599 u64 m = PERF_MEM_TLB_NA;
605 m = he->mem_info->data_src.mem_dtlb;
607 hit = m & PERF_MEM_TLB_HIT;
608 miss = m & PERF_MEM_TLB_MISS;
610 /* already taken care of */
611 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
613 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
620 strncat(out, tlb_access[i], sz - l);
621 l += strlen(tlb_access[i]);
626 strncat(out, " hit", sz - l);
628 strncat(out, " miss", sz - l);
630 return repsep_snprintf(bf, size, "%-*s", width, out);
634 sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
636 union perf_mem_data_src data_src_l;
637 union perf_mem_data_src data_src_r;
640 data_src_l = left->mem_info->data_src;
642 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
645 data_src_r = right->mem_info->data_src;
647 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
649 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
652 static const char * const mem_lvl[] = {
661 "Remote RAM (1 hop)",
662 "Remote RAM (2 hops)",
663 "Remote Cache (1 hop)",
664 "Remote Cache (2 hops)",
668 #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
670 static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
671 size_t size, unsigned int width)
674 size_t sz = sizeof(out) - 1; /* -1 for null termination */
676 u64 m = PERF_MEM_LVL_NA;
680 m = he->mem_info->data_src.mem_lvl;
684 hit = m & PERF_MEM_LVL_HIT;
685 miss = m & PERF_MEM_LVL_MISS;
687 /* already taken care of */
688 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
690 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
697 strncat(out, mem_lvl[i], sz - l);
698 l += strlen(mem_lvl[i]);
703 strncat(out, " hit", sz - l);
705 strncat(out, " miss", sz - l);
707 return repsep_snprintf(bf, size, "%-*s", width, out);
711 sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
713 union perf_mem_data_src data_src_l;
714 union perf_mem_data_src data_src_r;
717 data_src_l = left->mem_info->data_src;
719 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
722 data_src_r = right->mem_info->data_src;
724 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
726 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
729 static const char * const snoop_access[] = {
736 #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
738 static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
739 size_t size, unsigned int width)
742 size_t sz = sizeof(out) - 1; /* -1 for null termination */
744 u64 m = PERF_MEM_SNOOP_NA;
749 m = he->mem_info->data_src.mem_snoop;
751 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
758 strncat(out, snoop_access[i], sz - l);
759 l += strlen(snoop_access[i]);
765 return repsep_snprintf(bf, size, "%-*s", width, out);
768 struct sort_entry sort_mispredict = {
769 .se_header = "Branch Mispredicted",
770 .se_cmp = sort__mispredict_cmp,
771 .se_snprintf = hist_entry__mispredict_snprintf,
772 .se_width_idx = HISTC_MISPREDICT,
775 static u64 he_weight(struct hist_entry *he)
777 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
781 sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
783 return he_weight(left) - he_weight(right);
786 static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
787 size_t size, unsigned int width)
789 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
792 struct sort_entry sort_local_weight = {
793 .se_header = "Local Weight",
794 .se_cmp = sort__local_weight_cmp,
795 .se_snprintf = hist_entry__local_weight_snprintf,
796 .se_width_idx = HISTC_LOCAL_WEIGHT,
800 sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
802 return left->stat.weight - right->stat.weight;
805 static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
806 size_t size, unsigned int width)
808 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
811 struct sort_entry sort_global_weight = {
812 .se_header = "Weight",
813 .se_cmp = sort__global_weight_cmp,
814 .se_snprintf = hist_entry__global_weight_snprintf,
815 .se_width_idx = HISTC_GLOBAL_WEIGHT,
818 struct sort_entry sort_mem_daddr_sym = {
819 .se_header = "Data Symbol",
820 .se_cmp = sort__daddr_cmp,
821 .se_snprintf = hist_entry__daddr_snprintf,
822 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
825 struct sort_entry sort_mem_daddr_dso = {
826 .se_header = "Data Object",
827 .se_cmp = sort__dso_daddr_cmp,
828 .se_snprintf = hist_entry__dso_daddr_snprintf,
829 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
832 struct sort_entry sort_mem_locked = {
833 .se_header = "Locked",
834 .se_cmp = sort__locked_cmp,
835 .se_snprintf = hist_entry__locked_snprintf,
836 .se_width_idx = HISTC_MEM_LOCKED,
839 struct sort_entry sort_mem_tlb = {
840 .se_header = "TLB access",
841 .se_cmp = sort__tlb_cmp,
842 .se_snprintf = hist_entry__tlb_snprintf,
843 .se_width_idx = HISTC_MEM_TLB,
846 struct sort_entry sort_mem_lvl = {
847 .se_header = "Memory access",
848 .se_cmp = sort__lvl_cmp,
849 .se_snprintf = hist_entry__lvl_snprintf,
850 .se_width_idx = HISTC_MEM_LVL,
853 struct sort_entry sort_mem_snoop = {
854 .se_header = "Snoop",
855 .se_cmp = sort__snoop_cmp,
856 .se_snprintf = hist_entry__snoop_snprintf,
857 .se_width_idx = HISTC_MEM_SNOOP,
861 sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
863 return left->branch_info->flags.abort !=
864 right->branch_info->flags.abort;
867 static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
868 size_t size, unsigned int width)
870 static const char *out = ".";
872 if (he->branch_info->flags.abort)
874 return repsep_snprintf(bf, size, "%-*s", width, out);
877 struct sort_entry sort_abort = {
878 .se_header = "Transaction abort",
879 .se_cmp = sort__abort_cmp,
880 .se_snprintf = hist_entry__abort_snprintf,
881 .se_width_idx = HISTC_ABORT,
885 sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
887 return left->branch_info->flags.in_tx !=
888 right->branch_info->flags.in_tx;
891 static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
892 size_t size, unsigned int width)
894 static const char *out = ".";
896 if (he->branch_info->flags.in_tx)
899 return repsep_snprintf(bf, size, "%-*s", width, out);
902 struct sort_entry sort_in_tx = {
903 .se_header = "Branch in transaction",
904 .se_cmp = sort__in_tx_cmp,
905 .se_snprintf = hist_entry__in_tx_snprintf,
906 .se_width_idx = HISTC_IN_TX,
910 sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
912 return left->transaction - right->transaction;
915 static inline char *add_str(char *p, const char *str)
918 return p + strlen(str);
921 static struct txbit {
926 { PERF_TXN_ELISION, "EL ", 0 },
927 { PERF_TXN_TRANSACTION, "TX ", 1 },
928 { PERF_TXN_SYNC, "SYNC ", 1 },
929 { PERF_TXN_ASYNC, "ASYNC ", 0 },
930 { PERF_TXN_RETRY, "RETRY ", 0 },
931 { PERF_TXN_CONFLICT, "CON ", 0 },
932 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
933 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
937 int hist_entry__transaction_len(void)
942 for (i = 0; txbits[i].name; i++) {
943 if (!txbits[i].skip_for_len)
944 len += strlen(txbits[i].name);
946 len += 4; /* :XX<space> */
950 static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
951 size_t size, unsigned int width)
953 u64 t = he->transaction;
959 for (i = 0; txbits[i].name; i++)
960 if (txbits[i].flag & t)
961 p = add_str(p, txbits[i].name);
962 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
963 p = add_str(p, "NEITHER ");
964 if (t & PERF_TXN_ABORT_MASK) {
965 sprintf(p, ":%" PRIx64,
966 (t & PERF_TXN_ABORT_MASK) >>
967 PERF_TXN_ABORT_SHIFT);
971 return repsep_snprintf(bf, size, "%-*s", width, buf);
974 struct sort_entry sort_transaction = {
975 .se_header = "Transaction ",
976 .se_cmp = sort__transaction_cmp,
977 .se_snprintf = hist_entry__transaction_snprintf,
978 .se_width_idx = HISTC_TRANSACTION,
981 struct sort_dimension {
983 struct sort_entry *entry;
987 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
989 static struct sort_dimension common_sort_dimensions[] = {
990 DIM(SORT_PID, "pid", sort_thread),
991 DIM(SORT_COMM, "comm", sort_comm),
992 DIM(SORT_DSO, "dso", sort_dso),
993 DIM(SORT_SYM, "symbol", sort_sym),
994 DIM(SORT_PARENT, "parent", sort_parent),
995 DIM(SORT_CPU, "cpu", sort_cpu),
996 DIM(SORT_SRCLINE, "srcline", sort_srcline),
997 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
998 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
999 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
1004 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1006 static struct sort_dimension bstack_sort_dimensions[] = {
1007 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1008 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1009 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1010 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1011 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
1012 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1013 DIM(SORT_ABORT, "abort", sort_abort),
1018 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1020 static struct sort_dimension memory_sort_dimensions[] = {
1021 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1022 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1023 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1024 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1025 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1026 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1031 struct hpp_dimension {
1033 struct perf_hpp_fmt *fmt;
1037 #define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1039 static struct hpp_dimension hpp_sort_dimensions[] = {
1040 DIM(PERF_HPP__OVERHEAD, "overhead"),
1041 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1042 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1043 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1044 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1045 DIM(PERF_HPP__SAMPLES, "sample"),
1046 DIM(PERF_HPP__PERIOD, "period"),
1051 struct hpp_sort_entry {
1052 struct perf_hpp_fmt hpp;
1053 struct sort_entry *se;
1056 static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1057 struct perf_evsel *evsel)
1059 struct hpp_sort_entry *hse;
1062 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1063 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1065 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header);
1068 static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1069 struct perf_hpp *hpp __maybe_unused,
1070 struct perf_evsel *evsel)
1072 struct hpp_sort_entry *hse;
1074 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1076 return hists__col_len(&evsel->hists, hse->se->se_width_idx);
1079 static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1080 struct hist_entry *he)
1082 struct hpp_sort_entry *hse;
1085 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1086 len = hists__col_len(he->hists, hse->se->se_width_idx);
1088 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1091 static int __sort_dimension__add_hpp(struct sort_dimension *sd)
1093 struct hpp_sort_entry *hse;
1095 hse = malloc(sizeof(*hse));
1097 pr_err("Memory allocation failed\n");
1101 hse->se = sd->entry;
1102 hse->hpp.header = __sort__hpp_header;
1103 hse->hpp.width = __sort__hpp_width;
1104 hse->hpp.entry = __sort__hpp_entry;
1105 hse->hpp.color = NULL;
1107 hse->hpp.cmp = sd->entry->se_cmp;
1108 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
1109 hse->hpp.sort = hse->hpp.collapse;
1111 INIT_LIST_HEAD(&hse->hpp.list);
1112 INIT_LIST_HEAD(&hse->hpp.sort_list);
1114 perf_hpp__register_sort_field(&hse->hpp);
1118 static int __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
1123 if (__sort_dimension__add_hpp(sd) < 0)
1126 if (sd->entry->se_collapse)
1127 sort__need_collapse = 1;
1129 if (list_empty(&hist_entry__sort_list))
1130 sort__first_dimension = idx;
1132 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1138 static int __hpp_dimension__add(struct hpp_dimension *hd)
1143 perf_hpp__register_sort_field(hd->fmt);
1148 int sort_dimension__add(const char *tok)
1152 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1153 struct sort_dimension *sd = &common_sort_dimensions[i];
1155 if (strncasecmp(tok, sd->name, strlen(tok)))
1158 if (sd->entry == &sort_parent) {
1159 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1163 regerror(ret, &parent_regex, err, sizeof(err));
1164 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1167 sort__has_parent = 1;
1168 } else if (sd->entry == &sort_sym) {
1170 } else if (sd->entry == &sort_dso) {
1174 return __sort_dimension__add(sd, i);
1177 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1178 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1180 if (strncasecmp(tok, hd->name, strlen(tok)))
1183 return __hpp_dimension__add(hd);
1186 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1187 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1189 if (strncasecmp(tok, sd->name, strlen(tok)))
1192 if (sort__mode != SORT_MODE__BRANCH)
1195 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1198 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
1202 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1203 struct sort_dimension *sd = &memory_sort_dimensions[i];
1205 if (strncasecmp(tok, sd->name, strlen(tok)))
1208 if (sort__mode != SORT_MODE__MEMORY)
1211 if (sd->entry == &sort_mem_daddr_sym)
1214 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
1221 int setup_sorting(void)
1223 char *tmp, *tok, *str = strdup(sort_order);
1227 error("Not enough memory to setup sort keys");
1231 for (tok = strtok_r(str, ", ", &tmp);
1232 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1233 ret = sort_dimension__add(tok);
1234 if (ret == -EINVAL) {
1235 error("Invalid --sort key: `%s'", tok);
1237 } else if (ret == -ESRCH) {
1238 error("Unknown --sort key: `%s'", tok);
1247 static void sort_entry__setup_elide(struct sort_entry *se,
1248 struct strlist *list,
1249 const char *list_name, FILE *fp)
1251 if (list && strlist__nr_entries(list) == 1) {
1253 fprintf(fp, "# %s: %s\n", list_name,
1254 strlist__entry(list, 0)->s);
1259 void sort__setup_elide(FILE *output)
1261 struct sort_entry *se;
1263 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1265 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1267 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1270 if (sort__mode == SORT_MODE__BRANCH) {
1271 sort_entry__setup_elide(&sort_dso_from,
1272 symbol_conf.dso_from_list,
1273 "dso_from", output);
1274 sort_entry__setup_elide(&sort_dso_to,
1275 symbol_conf.dso_to_list,
1277 sort_entry__setup_elide(&sort_sym_from,
1278 symbol_conf.sym_from_list,
1279 "sym_from", output);
1280 sort_entry__setup_elide(&sort_sym_to,
1281 symbol_conf.sym_to_list,
1283 } else if (sort__mode == SORT_MODE__MEMORY) {
1284 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1285 "symbol_daddr", output);
1286 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1287 "dso_daddr", output);
1288 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1290 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1291 "local_weight", output);
1292 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1294 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1299 * It makes no sense to elide all of sort entries.
1300 * Just revert them to show up again.
1302 list_for_each_entry(se, &hist_entry__sort_list, list) {
1307 list_for_each_entry(se, &hist_entry__sort_list, list)