6 const char default_parent_pattern
[] = "^sys_|^do_page_fault";
7 const char *parent_pattern
= default_parent_pattern
;
8 const char default_sort_order
[] = "comm,dso,symbol";
9 const char *sort_order
= default_sort_order
;
10 regex_t ignore_callees_regex
;
11 int have_ignore_callees
= 0;
12 int sort__need_collapse
= 0;
13 int sort__has_parent
= 0;
14 int sort__has_sym
= 0;
15 enum sort_mode sort__mode
= SORT_MODE__NORMAL
;
17 enum sort_type sort__first_dimension
;
19 LIST_HEAD(hist_entry__sort_list
);
21 static int repsep_snprintf(char *bf
, size_t size
, const char *fmt
, ...)
27 n
= vsnprintf(bf
, size
, fmt
, ap
);
28 if (symbol_conf
.field_sep
&& n
> 0) {
32 sep
= strchr(sep
, *symbol_conf
.field_sep
);
45 static int64_t cmp_null(const void *l
, const void *r
)
58 sort__thread_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
60 return right
->thread
->tid
- left
->thread
->tid
;
63 static int hist_entry__thread_snprintf(struct hist_entry
*he
, char *bf
,
64 size_t size
, unsigned int width
)
66 const char *comm
= thread__comm_str(he
->thread
);
67 return repsep_snprintf(bf
, size
, "%*s:%5d", width
- 6,
68 comm
?: "", he
->thread
->tid
);
71 struct sort_entry sort_thread
= {
72 .se_header
= "Command: Pid",
73 .se_cmp
= sort__thread_cmp
,
74 .se_snprintf
= hist_entry__thread_snprintf
,
75 .se_width_idx
= HISTC_THREAD
,
81 sort__comm_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
83 /* Compare the addr that should be unique among comm */
84 return thread__comm_str(right
->thread
) - thread__comm_str(left
->thread
);
88 sort__comm_collapse(struct hist_entry
*left
, struct hist_entry
*right
)
90 const char *comm_l
= thread__comm_str(left
->thread
);
91 const char *comm_r
= thread__comm_str(right
->thread
);
93 if (!comm_l
|| !comm_r
)
94 return cmp_null(comm_l
, comm_r
);
96 return strcmp(comm_l
, comm_r
);
99 static int hist_entry__comm_snprintf(struct hist_entry
*he
, char *bf
,
100 size_t size
, unsigned int width
)
102 return repsep_snprintf(bf
, size
, "%*s", width
, thread__comm_str(he
->thread
));
105 struct sort_entry sort_comm
= {
106 .se_header
= "Command",
107 .se_cmp
= sort__comm_cmp
,
108 .se_collapse
= sort__comm_collapse
,
109 .se_snprintf
= hist_entry__comm_snprintf
,
110 .se_width_idx
= HISTC_COMM
,
115 static int64_t _sort__dso_cmp(struct map
*map_l
, struct map
*map_r
)
117 struct dso
*dso_l
= map_l
? map_l
->dso
: NULL
;
118 struct dso
*dso_r
= map_r
? map_r
->dso
: NULL
;
119 const char *dso_name_l
, *dso_name_r
;
121 if (!dso_l
|| !dso_r
)
122 return cmp_null(dso_l
, dso_r
);
125 dso_name_l
= dso_l
->long_name
;
126 dso_name_r
= dso_r
->long_name
;
128 dso_name_l
= dso_l
->short_name
;
129 dso_name_r
= dso_r
->short_name
;
132 return strcmp(dso_name_l
, dso_name_r
);
136 sort__dso_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
138 return _sort__dso_cmp(left
->ms
.map
, right
->ms
.map
);
141 static int _hist_entry__dso_snprintf(struct map
*map
, char *bf
,
142 size_t size
, unsigned int width
)
144 if (map
&& map
->dso
) {
145 const char *dso_name
= !verbose
? map
->dso
->short_name
:
147 return repsep_snprintf(bf
, size
, "%-*s", width
, dso_name
);
150 return repsep_snprintf(bf
, size
, "%-*s", width
, "[unknown]");
153 static int hist_entry__dso_snprintf(struct hist_entry
*he
, char *bf
,
154 size_t size
, unsigned int width
)
156 return _hist_entry__dso_snprintf(he
->ms
.map
, bf
, size
, width
);
159 struct sort_entry sort_dso
= {
160 .se_header
= "Shared Object",
161 .se_cmp
= sort__dso_cmp
,
162 .se_snprintf
= hist_entry__dso_snprintf
,
163 .se_width_idx
= HISTC_DSO
,
168 static int64_t _sort__sym_cmp(struct symbol
*sym_l
, struct symbol
*sym_r
)
172 if (!sym_l
|| !sym_r
)
173 return cmp_null(sym_l
, sym_r
);
181 return (int64_t)(ip_r
- ip_l
);
185 sort__sym_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
189 if (!left
->ms
.sym
&& !right
->ms
.sym
)
190 return right
->level
- left
->level
;
193 * comparing symbol address alone is not enough since it's a
194 * relative address within a dso.
196 ret
= sort__dso_cmp(left
, right
);
200 return _sort__sym_cmp(left
->ms
.sym
, right
->ms
.sym
);
203 static int _hist_entry__sym_snprintf(struct map
*map
, struct symbol
*sym
,
204 u64 ip
, char level
, char *bf
, size_t size
,
210 char o
= map
? dso__symtab_origin(map
->dso
) : '!';
211 ret
+= repsep_snprintf(bf
, size
, "%-#*llx %c ",
212 BITS_PER_LONG
/ 4 + 2, ip
, o
);
215 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "[%c] ", level
);
217 if (map
->type
== MAP__VARIABLE
) {
218 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%s", sym
->name
);
219 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "+0x%llx",
220 ip
- map
->unmap_ip(map
, sym
->start
));
221 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-*s",
224 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-*s",
229 size_t len
= BITS_PER_LONG
/ 4;
230 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-#.*llx",
232 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-*s",
239 static int hist_entry__sym_snprintf(struct hist_entry
*he
, char *bf
,
240 size_t size
, unsigned int width
)
242 return _hist_entry__sym_snprintf(he
->ms
.map
, he
->ms
.sym
, he
->ip
,
243 he
->level
, bf
, size
, width
);
246 struct sort_entry sort_sym
= {
247 .se_header
= "Symbol",
248 .se_cmp
= sort__sym_cmp
,
249 .se_snprintf
= hist_entry__sym_snprintf
,
250 .se_width_idx
= HISTC_SYMBOL
,
256 sort__srcline_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
258 if (!left
->srcline
) {
260 left
->srcline
= SRCLINE_UNKNOWN
;
262 struct map
*map
= left
->ms
.map
;
263 left
->srcline
= get_srcline(map
->dso
,
264 map__rip_2objdump(map
, left
->ip
));
267 if (!right
->srcline
) {
269 right
->srcline
= SRCLINE_UNKNOWN
;
271 struct map
*map
= right
->ms
.map
;
272 right
->srcline
= get_srcline(map
->dso
,
273 map__rip_2objdump(map
, right
->ip
));
276 return strcmp(left
->srcline
, right
->srcline
);
279 static int hist_entry__srcline_snprintf(struct hist_entry
*he
, char *bf
,
281 unsigned int width __maybe_unused
)
283 return repsep_snprintf(bf
, size
, "%s", he
->srcline
);
286 struct sort_entry sort_srcline
= {
287 .se_header
= "Source:Line",
288 .se_cmp
= sort__srcline_cmp
,
289 .se_snprintf
= hist_entry__srcline_snprintf
,
290 .se_width_idx
= HISTC_SRCLINE
,
296 sort__parent_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
298 struct symbol
*sym_l
= left
->parent
;
299 struct symbol
*sym_r
= right
->parent
;
301 if (!sym_l
|| !sym_r
)
302 return cmp_null(sym_l
, sym_r
);
304 return strcmp(sym_l
->name
, sym_r
->name
);
307 static int hist_entry__parent_snprintf(struct hist_entry
*he
, char *bf
,
308 size_t size
, unsigned int width
)
310 return repsep_snprintf(bf
, size
, "%-*s", width
,
311 he
->parent
? he
->parent
->name
: "[other]");
314 struct sort_entry sort_parent
= {
315 .se_header
= "Parent symbol",
316 .se_cmp
= sort__parent_cmp
,
317 .se_snprintf
= hist_entry__parent_snprintf
,
318 .se_width_idx
= HISTC_PARENT
,
324 sort__cpu_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
326 return right
->cpu
- left
->cpu
;
329 static int hist_entry__cpu_snprintf(struct hist_entry
*he
, char *bf
,
330 size_t size
, unsigned int width
)
332 return repsep_snprintf(bf
, size
, "%*d", width
, he
->cpu
);
335 struct sort_entry sort_cpu
= {
337 .se_cmp
= sort__cpu_cmp
,
338 .se_snprintf
= hist_entry__cpu_snprintf
,
339 .se_width_idx
= HISTC_CPU
,
342 /* sort keys for branch stacks */
345 sort__dso_from_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
347 return _sort__dso_cmp(left
->branch_info
->from
.map
,
348 right
->branch_info
->from
.map
);
351 static int hist_entry__dso_from_snprintf(struct hist_entry
*he
, char *bf
,
352 size_t size
, unsigned int width
)
354 return _hist_entry__dso_snprintf(he
->branch_info
->from
.map
,
359 sort__dso_to_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
361 return _sort__dso_cmp(left
->branch_info
->to
.map
,
362 right
->branch_info
->to
.map
);
365 static int hist_entry__dso_to_snprintf(struct hist_entry
*he
, char *bf
,
366 size_t size
, unsigned int width
)
368 return _hist_entry__dso_snprintf(he
->branch_info
->to
.map
,
373 sort__sym_from_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
375 struct addr_map_symbol
*from_l
= &left
->branch_info
->from
;
376 struct addr_map_symbol
*from_r
= &right
->branch_info
->from
;
378 if (!from_l
->sym
&& !from_r
->sym
)
379 return right
->level
- left
->level
;
381 return _sort__sym_cmp(from_l
->sym
, from_r
->sym
);
385 sort__sym_to_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
387 struct addr_map_symbol
*to_l
= &left
->branch_info
->to
;
388 struct addr_map_symbol
*to_r
= &right
->branch_info
->to
;
390 if (!to_l
->sym
&& !to_r
->sym
)
391 return right
->level
- left
->level
;
393 return _sort__sym_cmp(to_l
->sym
, to_r
->sym
);
396 static int hist_entry__sym_from_snprintf(struct hist_entry
*he
, char *bf
,
397 size_t size
, unsigned int width
)
399 struct addr_map_symbol
*from
= &he
->branch_info
->from
;
400 return _hist_entry__sym_snprintf(from
->map
, from
->sym
, from
->addr
,
401 he
->level
, bf
, size
, width
);
405 static int hist_entry__sym_to_snprintf(struct hist_entry
*he
, char *bf
,
406 size_t size
, unsigned int width
)
408 struct addr_map_symbol
*to
= &he
->branch_info
->to
;
409 return _hist_entry__sym_snprintf(to
->map
, to
->sym
, to
->addr
,
410 he
->level
, bf
, size
, width
);
414 struct sort_entry sort_dso_from
= {
415 .se_header
= "Source Shared Object",
416 .se_cmp
= sort__dso_from_cmp
,
417 .se_snprintf
= hist_entry__dso_from_snprintf
,
418 .se_width_idx
= HISTC_DSO_FROM
,
421 struct sort_entry sort_dso_to
= {
422 .se_header
= "Target Shared Object",
423 .se_cmp
= sort__dso_to_cmp
,
424 .se_snprintf
= hist_entry__dso_to_snprintf
,
425 .se_width_idx
= HISTC_DSO_TO
,
428 struct sort_entry sort_sym_from
= {
429 .se_header
= "Source Symbol",
430 .se_cmp
= sort__sym_from_cmp
,
431 .se_snprintf
= hist_entry__sym_from_snprintf
,
432 .se_width_idx
= HISTC_SYMBOL_FROM
,
435 struct sort_entry sort_sym_to
= {
436 .se_header
= "Target Symbol",
437 .se_cmp
= sort__sym_to_cmp
,
438 .se_snprintf
= hist_entry__sym_to_snprintf
,
439 .se_width_idx
= HISTC_SYMBOL_TO
,
443 sort__mispredict_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
445 const unsigned char mp
= left
->branch_info
->flags
.mispred
!=
446 right
->branch_info
->flags
.mispred
;
447 const unsigned char p
= left
->branch_info
->flags
.predicted
!=
448 right
->branch_info
->flags
.predicted
;
453 static int hist_entry__mispredict_snprintf(struct hist_entry
*he
, char *bf
,
454 size_t size
, unsigned int width
){
455 static const char *out
= "N/A";
457 if (he
->branch_info
->flags
.predicted
)
459 else if (he
->branch_info
->flags
.mispred
)
462 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
465 /* --sort daddr_sym */
467 sort__daddr_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
469 uint64_t l
= 0, r
= 0;
472 l
= left
->mem_info
->daddr
.addr
;
474 r
= right
->mem_info
->daddr
.addr
;
476 return (int64_t)(r
- l
);
479 static int hist_entry__daddr_snprintf(struct hist_entry
*he
, char *bf
,
480 size_t size
, unsigned int width
)
483 struct map
*map
= NULL
;
484 struct symbol
*sym
= NULL
;
487 addr
= he
->mem_info
->daddr
.addr
;
488 map
= he
->mem_info
->daddr
.map
;
489 sym
= he
->mem_info
->daddr
.sym
;
491 return _hist_entry__sym_snprintf(map
, sym
, addr
, he
->level
, bf
, size
,
496 sort__dso_daddr_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
498 struct map
*map_l
= NULL
;
499 struct map
*map_r
= NULL
;
502 map_l
= left
->mem_info
->daddr
.map
;
504 map_r
= right
->mem_info
->daddr
.map
;
506 return _sort__dso_cmp(map_l
, map_r
);
509 static int hist_entry__dso_daddr_snprintf(struct hist_entry
*he
, char *bf
,
510 size_t size
, unsigned int width
)
512 struct map
*map
= NULL
;
515 map
= he
->mem_info
->daddr
.map
;
517 return _hist_entry__dso_snprintf(map
, bf
, size
, width
);
521 sort__locked_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
523 union perf_mem_data_src data_src_l
;
524 union perf_mem_data_src data_src_r
;
527 data_src_l
= left
->mem_info
->data_src
;
529 data_src_l
.mem_lock
= PERF_MEM_LOCK_NA
;
532 data_src_r
= right
->mem_info
->data_src
;
534 data_src_r
.mem_lock
= PERF_MEM_LOCK_NA
;
536 return (int64_t)(data_src_r
.mem_lock
- data_src_l
.mem_lock
);
539 static int hist_entry__locked_snprintf(struct hist_entry
*he
, char *bf
,
540 size_t size
, unsigned int width
)
543 u64 mask
= PERF_MEM_LOCK_NA
;
546 mask
= he
->mem_info
->data_src
.mem_lock
;
548 if (mask
& PERF_MEM_LOCK_NA
)
550 else if (mask
& PERF_MEM_LOCK_LOCKED
)
555 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
559 sort__tlb_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
561 union perf_mem_data_src data_src_l
;
562 union perf_mem_data_src data_src_r
;
565 data_src_l
= left
->mem_info
->data_src
;
567 data_src_l
.mem_dtlb
= PERF_MEM_TLB_NA
;
570 data_src_r
= right
->mem_info
->data_src
;
572 data_src_r
.mem_dtlb
= PERF_MEM_TLB_NA
;
574 return (int64_t)(data_src_r
.mem_dtlb
- data_src_l
.mem_dtlb
);
577 static const char * const tlb_access
[] = {
586 #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
588 static int hist_entry__tlb_snprintf(struct hist_entry
*he
, char *bf
,
589 size_t size
, unsigned int width
)
592 size_t sz
= sizeof(out
) - 1; /* -1 for null termination */
594 u64 m
= PERF_MEM_TLB_NA
;
600 m
= he
->mem_info
->data_src
.mem_dtlb
;
602 hit
= m
& PERF_MEM_TLB_HIT
;
603 miss
= m
& PERF_MEM_TLB_MISS
;
605 /* already taken care of */
606 m
&= ~(PERF_MEM_TLB_HIT
|PERF_MEM_TLB_MISS
);
608 for (i
= 0; m
&& i
< NUM_TLB_ACCESS
; i
++, m
>>= 1) {
615 strncat(out
, tlb_access
[i
], sz
- l
);
616 l
+= strlen(tlb_access
[i
]);
621 strncat(out
, " hit", sz
- l
);
623 strncat(out
, " miss", sz
- l
);
625 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
629 sort__lvl_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
631 union perf_mem_data_src data_src_l
;
632 union perf_mem_data_src data_src_r
;
635 data_src_l
= left
->mem_info
->data_src
;
637 data_src_l
.mem_lvl
= PERF_MEM_LVL_NA
;
640 data_src_r
= right
->mem_info
->data_src
;
642 data_src_r
.mem_lvl
= PERF_MEM_LVL_NA
;
644 return (int64_t)(data_src_r
.mem_lvl
- data_src_l
.mem_lvl
);
647 static const char * const mem_lvl
[] = {
656 "Remote RAM (1 hop)",
657 "Remote RAM (2 hops)",
658 "Remote Cache (1 hop)",
659 "Remote Cache (2 hops)",
663 #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
665 static int hist_entry__lvl_snprintf(struct hist_entry
*he
, char *bf
,
666 size_t size
, unsigned int width
)
669 size_t sz
= sizeof(out
) - 1; /* -1 for null termination */
671 u64 m
= PERF_MEM_LVL_NA
;
675 m
= he
->mem_info
->data_src
.mem_lvl
;
679 hit
= m
& PERF_MEM_LVL_HIT
;
680 miss
= m
& PERF_MEM_LVL_MISS
;
682 /* already taken care of */
683 m
&= ~(PERF_MEM_LVL_HIT
|PERF_MEM_LVL_MISS
);
685 for (i
= 0; m
&& i
< NUM_MEM_LVL
; i
++, m
>>= 1) {
692 strncat(out
, mem_lvl
[i
], sz
- l
);
693 l
+= strlen(mem_lvl
[i
]);
698 strncat(out
, " hit", sz
- l
);
700 strncat(out
, " miss", sz
- l
);
702 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
706 sort__snoop_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
708 union perf_mem_data_src data_src_l
;
709 union perf_mem_data_src data_src_r
;
712 data_src_l
= left
->mem_info
->data_src
;
714 data_src_l
.mem_snoop
= PERF_MEM_SNOOP_NA
;
717 data_src_r
= right
->mem_info
->data_src
;
719 data_src_r
.mem_snoop
= PERF_MEM_SNOOP_NA
;
721 return (int64_t)(data_src_r
.mem_snoop
- data_src_l
.mem_snoop
);
724 static const char * const snoop_access
[] = {
731 #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
733 static int hist_entry__snoop_snprintf(struct hist_entry
*he
, char *bf
,
734 size_t size
, unsigned int width
)
737 size_t sz
= sizeof(out
) - 1; /* -1 for null termination */
739 u64 m
= PERF_MEM_SNOOP_NA
;
744 m
= he
->mem_info
->data_src
.mem_snoop
;
746 for (i
= 0; m
&& i
< NUM_SNOOP_ACCESS
; i
++, m
>>= 1) {
753 strncat(out
, snoop_access
[i
], sz
- l
);
754 l
+= strlen(snoop_access
[i
]);
760 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
763 struct sort_entry sort_mispredict
= {
764 .se_header
= "Branch Mispredicted",
765 .se_cmp
= sort__mispredict_cmp
,
766 .se_snprintf
= hist_entry__mispredict_snprintf
,
767 .se_width_idx
= HISTC_MISPREDICT
,
770 static u64
he_weight(struct hist_entry
*he
)
772 return he
->stat
.nr_events
? he
->stat
.weight
/ he
->stat
.nr_events
: 0;
776 sort__local_weight_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
778 return he_weight(left
) - he_weight(right
);
781 static int hist_entry__local_weight_snprintf(struct hist_entry
*he
, char *bf
,
782 size_t size
, unsigned int width
)
784 return repsep_snprintf(bf
, size
, "%-*llu", width
, he_weight(he
));
787 struct sort_entry sort_local_weight
= {
788 .se_header
= "Local Weight",
789 .se_cmp
= sort__local_weight_cmp
,
790 .se_snprintf
= hist_entry__local_weight_snprintf
,
791 .se_width_idx
= HISTC_LOCAL_WEIGHT
,
795 sort__global_weight_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
797 return left
->stat
.weight
- right
->stat
.weight
;
800 static int hist_entry__global_weight_snprintf(struct hist_entry
*he
, char *bf
,
801 size_t size
, unsigned int width
)
803 return repsep_snprintf(bf
, size
, "%-*llu", width
, he
->stat
.weight
);
806 struct sort_entry sort_global_weight
= {
807 .se_header
= "Weight",
808 .se_cmp
= sort__global_weight_cmp
,
809 .se_snprintf
= hist_entry__global_weight_snprintf
,
810 .se_width_idx
= HISTC_GLOBAL_WEIGHT
,
813 struct sort_entry sort_mem_daddr_sym
= {
814 .se_header
= "Data Symbol",
815 .se_cmp
= sort__daddr_cmp
,
816 .se_snprintf
= hist_entry__daddr_snprintf
,
817 .se_width_idx
= HISTC_MEM_DADDR_SYMBOL
,
820 struct sort_entry sort_mem_daddr_dso
= {
821 .se_header
= "Data Object",
822 .se_cmp
= sort__dso_daddr_cmp
,
823 .se_snprintf
= hist_entry__dso_daddr_snprintf
,
824 .se_width_idx
= HISTC_MEM_DADDR_SYMBOL
,
827 struct sort_entry sort_mem_locked
= {
828 .se_header
= "Locked",
829 .se_cmp
= sort__locked_cmp
,
830 .se_snprintf
= hist_entry__locked_snprintf
,
831 .se_width_idx
= HISTC_MEM_LOCKED
,
834 struct sort_entry sort_mem_tlb
= {
835 .se_header
= "TLB access",
836 .se_cmp
= sort__tlb_cmp
,
837 .se_snprintf
= hist_entry__tlb_snprintf
,
838 .se_width_idx
= HISTC_MEM_TLB
,
841 struct sort_entry sort_mem_lvl
= {
842 .se_header
= "Memory access",
843 .se_cmp
= sort__lvl_cmp
,
844 .se_snprintf
= hist_entry__lvl_snprintf
,
845 .se_width_idx
= HISTC_MEM_LVL
,
848 struct sort_entry sort_mem_snoop
= {
849 .se_header
= "Snoop",
850 .se_cmp
= sort__snoop_cmp
,
851 .se_snprintf
= hist_entry__snoop_snprintf
,
852 .se_width_idx
= HISTC_MEM_SNOOP
,
856 sort__abort_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
858 return left
->branch_info
->flags
.abort
!=
859 right
->branch_info
->flags
.abort
;
862 static int hist_entry__abort_snprintf(struct hist_entry
*he
, char *bf
,
863 size_t size
, unsigned int width
)
865 static const char *out
= ".";
867 if (he
->branch_info
->flags
.abort
)
869 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
872 struct sort_entry sort_abort
= {
873 .se_header
= "Transaction abort",
874 .se_cmp
= sort__abort_cmp
,
875 .se_snprintf
= hist_entry__abort_snprintf
,
876 .se_width_idx
= HISTC_ABORT
,
880 sort__in_tx_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
882 return left
->branch_info
->flags
.in_tx
!=
883 right
->branch_info
->flags
.in_tx
;
886 static int hist_entry__in_tx_snprintf(struct hist_entry
*he
, char *bf
,
887 size_t size
, unsigned int width
)
889 static const char *out
= ".";
891 if (he
->branch_info
->flags
.in_tx
)
894 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
897 struct sort_entry sort_in_tx
= {
898 .se_header
= "Branch in transaction",
899 .se_cmp
= sort__in_tx_cmp
,
900 .se_snprintf
= hist_entry__in_tx_snprintf
,
901 .se_width_idx
= HISTC_IN_TX
,
905 sort__transaction_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
907 return left
->transaction
- right
->transaction
;
910 static inline char *add_str(char *p
, const char *str
)
913 return p
+ strlen(str
);
916 static struct txbit
{
921 { PERF_TXN_ELISION
, "EL ", 0 },
922 { PERF_TXN_TRANSACTION
, "TX ", 1 },
923 { PERF_TXN_SYNC
, "SYNC ", 1 },
924 { PERF_TXN_ASYNC
, "ASYNC ", 0 },
925 { PERF_TXN_RETRY
, "RETRY ", 0 },
926 { PERF_TXN_CONFLICT
, "CON ", 0 },
927 { PERF_TXN_CAPACITY_WRITE
, "CAP-WRITE ", 1 },
928 { PERF_TXN_CAPACITY_READ
, "CAP-READ ", 0 },
932 int hist_entry__transaction_len(void)
937 for (i
= 0; txbits
[i
].name
; i
++) {
938 if (!txbits
[i
].skip_for_len
)
939 len
+= strlen(txbits
[i
].name
);
941 len
+= 4; /* :XX<space> */
945 static int hist_entry__transaction_snprintf(struct hist_entry
*he
, char *bf
,
946 size_t size
, unsigned int width
)
948 u64 t
= he
->transaction
;
954 for (i
= 0; txbits
[i
].name
; i
++)
955 if (txbits
[i
].flag
& t
)
956 p
= add_str(p
, txbits
[i
].name
);
957 if (t
&& !(t
& (PERF_TXN_SYNC
|PERF_TXN_ASYNC
)))
958 p
= add_str(p
, "NEITHER ");
959 if (t
& PERF_TXN_ABORT_MASK
) {
960 sprintf(p
, ":%" PRIx64
,
961 (t
& PERF_TXN_ABORT_MASK
) >>
962 PERF_TXN_ABORT_SHIFT
);
966 return repsep_snprintf(bf
, size
, "%-*s", width
, buf
);
969 struct sort_entry sort_transaction
= {
970 .se_header
= "Transaction ",
971 .se_cmp
= sort__transaction_cmp
,
972 .se_snprintf
= hist_entry__transaction_snprintf
,
973 .se_width_idx
= HISTC_TRANSACTION
,
976 struct sort_dimension
{
978 struct sort_entry
*entry
;
982 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
984 static struct sort_dimension common_sort_dimensions
[] = {
985 DIM(SORT_PID
, "pid", sort_thread
),
986 DIM(SORT_COMM
, "comm", sort_comm
),
987 DIM(SORT_DSO
, "dso", sort_dso
),
988 DIM(SORT_SYM
, "symbol", sort_sym
),
989 DIM(SORT_PARENT
, "parent", sort_parent
),
990 DIM(SORT_CPU
, "cpu", sort_cpu
),
991 DIM(SORT_SRCLINE
, "srcline", sort_srcline
),
992 DIM(SORT_LOCAL_WEIGHT
, "local_weight", sort_local_weight
),
993 DIM(SORT_GLOBAL_WEIGHT
, "weight", sort_global_weight
),
994 DIM(SORT_TRANSACTION
, "transaction", sort_transaction
),
999 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1001 static struct sort_dimension bstack_sort_dimensions
[] = {
1002 DIM(SORT_DSO_FROM
, "dso_from", sort_dso_from
),
1003 DIM(SORT_DSO_TO
, "dso_to", sort_dso_to
),
1004 DIM(SORT_SYM_FROM
, "symbol_from", sort_sym_from
),
1005 DIM(SORT_SYM_TO
, "symbol_to", sort_sym_to
),
1006 DIM(SORT_MISPREDICT
, "mispredict", sort_mispredict
),
1007 DIM(SORT_IN_TX
, "in_tx", sort_in_tx
),
1008 DIM(SORT_ABORT
, "abort", sort_abort
),
1013 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1015 static struct sort_dimension memory_sort_dimensions
[] = {
1016 DIM(SORT_MEM_DADDR_SYMBOL
, "symbol_daddr", sort_mem_daddr_sym
),
1017 DIM(SORT_MEM_DADDR_DSO
, "dso_daddr", sort_mem_daddr_dso
),
1018 DIM(SORT_MEM_LOCKED
, "locked", sort_mem_locked
),
1019 DIM(SORT_MEM_TLB
, "tlb", sort_mem_tlb
),
1020 DIM(SORT_MEM_LVL
, "mem", sort_mem_lvl
),
1021 DIM(SORT_MEM_SNOOP
, "snoop", sort_mem_snoop
),
1026 static void __sort_dimension__add(struct sort_dimension
*sd
, enum sort_type idx
)
1031 if (sd
->entry
->se_collapse
)
1032 sort__need_collapse
= 1;
1034 if (list_empty(&hist_entry__sort_list
))
1035 sort__first_dimension
= idx
;
1037 list_add_tail(&sd
->entry
->list
, &hist_entry__sort_list
);
1041 int sort_dimension__add(const char *tok
)
1045 for (i
= 0; i
< ARRAY_SIZE(common_sort_dimensions
); i
++) {
1046 struct sort_dimension
*sd
= &common_sort_dimensions
[i
];
1048 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1051 if (sd
->entry
== &sort_parent
) {
1052 int ret
= regcomp(&parent_regex
, parent_pattern
, REG_EXTENDED
);
1056 regerror(ret
, &parent_regex
, err
, sizeof(err
));
1057 pr_err("Invalid regex: %s\n%s", parent_pattern
, err
);
1060 sort__has_parent
= 1;
1061 } else if (sd
->entry
== &sort_sym
) {
1065 __sort_dimension__add(sd
, i
);
1069 for (i
= 0; i
< ARRAY_SIZE(bstack_sort_dimensions
); i
++) {
1070 struct sort_dimension
*sd
= &bstack_sort_dimensions
[i
];
1072 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1075 if (sort__mode
!= SORT_MODE__BRANCH
)
1078 if (sd
->entry
== &sort_sym_from
|| sd
->entry
== &sort_sym_to
)
1081 __sort_dimension__add(sd
, i
+ __SORT_BRANCH_STACK
);
1085 for (i
= 0; i
< ARRAY_SIZE(memory_sort_dimensions
); i
++) {
1086 struct sort_dimension
*sd
= &memory_sort_dimensions
[i
];
1088 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1091 if (sort__mode
!= SORT_MODE__MEMORY
)
1094 if (sd
->entry
== &sort_mem_daddr_sym
)
1097 __sort_dimension__add(sd
, i
+ __SORT_MEMORY_MODE
);
1104 int setup_sorting(void)
1106 char *tmp
, *tok
, *str
= strdup(sort_order
);
1110 error("Not enough memory to setup sort keys");
1114 for (tok
= strtok_r(str
, ", ", &tmp
);
1115 tok
; tok
= strtok_r(NULL
, ", ", &tmp
)) {
1116 ret
= sort_dimension__add(tok
);
1117 if (ret
== -EINVAL
) {
1118 error("Invalid --sort key: `%s'", tok
);
1120 } else if (ret
== -ESRCH
) {
1121 error("Unknown --sort key: `%s'", tok
);
1130 static void sort_entry__setup_elide(struct sort_entry
*se
,
1131 struct strlist
*list
,
1132 const char *list_name
, FILE *fp
)
1134 if (list
&& strlist__nr_entries(list
) == 1) {
1136 fprintf(fp
, "# %s: %s\n", list_name
,
1137 strlist__entry(list
, 0)->s
);
1142 void sort__setup_elide(FILE *output
)
1144 sort_entry__setup_elide(&sort_dso
, symbol_conf
.dso_list
,
1146 sort_entry__setup_elide(&sort_comm
, symbol_conf
.comm_list
,
1148 sort_entry__setup_elide(&sort_sym
, symbol_conf
.sym_list
,
1151 if (sort__mode
== SORT_MODE__BRANCH
) {
1152 sort_entry__setup_elide(&sort_dso_from
,
1153 symbol_conf
.dso_from_list
,
1154 "dso_from", output
);
1155 sort_entry__setup_elide(&sort_dso_to
,
1156 symbol_conf
.dso_to_list
,
1158 sort_entry__setup_elide(&sort_sym_from
,
1159 symbol_conf
.sym_from_list
,
1160 "sym_from", output
);
1161 sort_entry__setup_elide(&sort_sym_to
,
1162 symbol_conf
.sym_to_list
,
1164 } else if (sort__mode
== SORT_MODE__MEMORY
) {
1165 sort_entry__setup_elide(&sort_dso
, symbol_conf
.dso_list
,
1166 "symbol_daddr", output
);
1167 sort_entry__setup_elide(&sort_dso
, symbol_conf
.dso_list
,
1168 "dso_daddr", output
);
1169 sort_entry__setup_elide(&sort_dso
, symbol_conf
.dso_list
,
1171 sort_entry__setup_elide(&sort_dso
, symbol_conf
.dso_list
,
1172 "local_weight", output
);
1173 sort_entry__setup_elide(&sort_dso
, symbol_conf
.dso_list
,
1175 sort_entry__setup_elide(&sort_dso
, symbol_conf
.dso_list
,