9 const char default_parent_pattern
[] = "^sys_|^do_page_fault";
10 const char *parent_pattern
= default_parent_pattern
;
11 const char default_sort_order
[] = "comm,dso,symbol";
12 const char default_branch_sort_order
[] = "comm,dso_from,symbol_from,dso_to,symbol_to";
13 const char default_mem_sort_order
[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
14 const char default_top_sort_order
[] = "dso,symbol";
15 const char default_diff_sort_order
[] = "dso,symbol";
16 const char *sort_order
;
17 const char *field_order
;
18 regex_t ignore_callees_regex
;
19 int have_ignore_callees
= 0;
20 int sort__need_collapse
= 0;
21 int sort__has_parent
= 0;
22 int sort__has_sym
= 0;
23 int sort__has_dso
= 0;
24 enum sort_mode sort__mode
= SORT_MODE__NORMAL
;
27 static int repsep_snprintf(char *bf
, size_t size
, const char *fmt
, ...)
33 n
= vsnprintf(bf
, size
, fmt
, ap
);
34 if (symbol_conf
.field_sep
&& n
> 0) {
38 sep
= strchr(sep
, *symbol_conf
.field_sep
);
51 static int64_t cmp_null(const void *l
, const void *r
)
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
,
89 sort__comm_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
91 /* Compare the addr that should be unique among comm */
92 return comm__str(right
->comm
) - comm__str(left
->comm
);
96 sort__comm_collapse(struct hist_entry
*left
, struct hist_entry
*right
)
98 /* Compare the addr that should be unique among comm */
99 return comm__str(right
->comm
) - comm__str(left
->comm
);
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
,
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
);
135 dso_name_l
= dso_l
->long_name
;
136 dso_name_r
= dso_r
->long_name
;
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
);
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
:
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
,
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
)
187 if (!sym_l
|| !sym_r
)
188 return cmp_null(sym_l
, sym_r
);
196 return (int64_t)(ip_r
- ip_l
);
200 sort__sym_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
204 if (!left
->ms
.sym
&& !right
->ms
.sym
)
205 return _sort__addr_cmp(left
->ip
, right
->ip
);
208 * comparing symbol address alone is not enough since it's a
209 * relative address within a dso.
211 if (!sort__has_dso
) {
212 ret
= sort__dso_cmp(left
, right
);
217 return _sort__sym_cmp(left
->ms
.sym
, right
->ms
.sym
);
221 sort__sym_sort(struct hist_entry
*left
, struct hist_entry
*right
)
223 if (!left
->ms
.sym
|| !right
->ms
.sym
)
224 return cmp_null(left
->ms
.sym
, right
->ms
.sym
);
226 return strcmp(right
->ms
.sym
->name
, left
->ms
.sym
->name
);
229 static int _hist_entry__sym_snprintf(struct map
*map
, struct symbol
*sym
,
230 u64 ip
, char level
, char *bf
, size_t size
,
236 char o
= map
? dso__symtab_origin(map
->dso
) : '!';
237 ret
+= repsep_snprintf(bf
, size
, "%-#*llx %c ",
238 BITS_PER_LONG
/ 4 + 2, ip
, o
);
241 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "[%c] ", level
);
243 if (map
->type
== MAP__VARIABLE
) {
244 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%s", sym
->name
);
245 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "+0x%llx",
246 ip
- map
->unmap_ip(map
, sym
->start
));
247 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-*s",
250 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-*s",
255 size_t len
= BITS_PER_LONG
/ 4;
256 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-#.*llx",
258 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-*s",
268 static int hist_entry__sym_snprintf(struct hist_entry
*he
, char *bf
,
269 size_t size
, unsigned int width
)
271 return _hist_entry__sym_snprintf(he
->ms
.map
, he
->ms
.sym
, he
->ip
,
272 he
->level
, bf
, size
, width
);
275 struct sort_entry sort_sym
= {
276 .se_header
= "Symbol",
277 .se_cmp
= sort__sym_cmp
,
278 .se_sort
= sort__sym_sort
,
279 .se_snprintf
= hist_entry__sym_snprintf
,
280 .se_width_idx
= HISTC_SYMBOL
,
286 sort__srcline_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
288 if (!left
->srcline
) {
290 left
->srcline
= SRCLINE_UNKNOWN
;
292 struct map
*map
= left
->ms
.map
;
293 left
->srcline
= get_srcline(map
->dso
,
294 map__rip_2objdump(map
, left
->ip
),
298 if (!right
->srcline
) {
300 right
->srcline
= SRCLINE_UNKNOWN
;
302 struct map
*map
= right
->ms
.map
;
303 right
->srcline
= get_srcline(map
->dso
,
304 map__rip_2objdump(map
, right
->ip
),
305 right
->ms
.sym
, true);
308 return strcmp(right
->srcline
, left
->srcline
);
311 static int hist_entry__srcline_snprintf(struct hist_entry
*he
, char *bf
,
312 size_t size
, unsigned int width
)
314 return repsep_snprintf(bf
, size
, "%-*.*s", width
, width
, he
->srcline
);
317 struct sort_entry sort_srcline
= {
318 .se_header
= "Source:Line",
319 .se_cmp
= sort__srcline_cmp
,
320 .se_snprintf
= hist_entry__srcline_snprintf
,
321 .se_width_idx
= HISTC_SRCLINE
,
327 sort__parent_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
329 struct symbol
*sym_l
= left
->parent
;
330 struct symbol
*sym_r
= right
->parent
;
332 if (!sym_l
|| !sym_r
)
333 return cmp_null(sym_l
, sym_r
);
335 return strcmp(sym_r
->name
, sym_l
->name
);
338 static int hist_entry__parent_snprintf(struct hist_entry
*he
, char *bf
,
339 size_t size
, unsigned int width
)
341 return repsep_snprintf(bf
, size
, "%-*.*s", width
, width
,
342 he
->parent
? he
->parent
->name
: "[other]");
345 struct sort_entry sort_parent
= {
346 .se_header
= "Parent symbol",
347 .se_cmp
= sort__parent_cmp
,
348 .se_snprintf
= hist_entry__parent_snprintf
,
349 .se_width_idx
= HISTC_PARENT
,
355 sort__cpu_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
357 return right
->cpu
- left
->cpu
;
360 static int hist_entry__cpu_snprintf(struct hist_entry
*he
, char *bf
,
361 size_t size
, unsigned int width
)
363 return repsep_snprintf(bf
, size
, "%*.*d", width
, width
, he
->cpu
);
366 struct sort_entry sort_cpu
= {
368 .se_cmp
= sort__cpu_cmp
,
369 .se_snprintf
= hist_entry__cpu_snprintf
,
370 .se_width_idx
= HISTC_CPU
,
373 /* sort keys for branch stacks */
376 sort__dso_from_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
378 if (!left
->branch_info
|| !right
->branch_info
)
379 return cmp_null(left
->branch_info
, right
->branch_info
);
381 return _sort__dso_cmp(left
->branch_info
->from
.map
,
382 right
->branch_info
->from
.map
);
385 static int hist_entry__dso_from_snprintf(struct hist_entry
*he
, char *bf
,
386 size_t size
, unsigned int width
)
389 return _hist_entry__dso_snprintf(he
->branch_info
->from
.map
,
392 return repsep_snprintf(bf
, size
, "%-*.*s", width
, width
, "N/A");
396 sort__dso_to_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
398 if (!left
->branch_info
|| !right
->branch_info
)
399 return cmp_null(left
->branch_info
, right
->branch_info
);
401 return _sort__dso_cmp(left
->branch_info
->to
.map
,
402 right
->branch_info
->to
.map
);
405 static int hist_entry__dso_to_snprintf(struct hist_entry
*he
, char *bf
,
406 size_t size
, unsigned int width
)
409 return _hist_entry__dso_snprintf(he
->branch_info
->to
.map
,
412 return repsep_snprintf(bf
, size
, "%-*.*s", width
, width
, "N/A");
416 sort__sym_from_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
418 struct addr_map_symbol
*from_l
= &left
->branch_info
->from
;
419 struct addr_map_symbol
*from_r
= &right
->branch_info
->from
;
421 if (!left
->branch_info
|| !right
->branch_info
)
422 return cmp_null(left
->branch_info
, right
->branch_info
);
424 from_l
= &left
->branch_info
->from
;
425 from_r
= &right
->branch_info
->from
;
427 if (!from_l
->sym
&& !from_r
->sym
)
428 return _sort__addr_cmp(from_l
->addr
, from_r
->addr
);
430 return _sort__sym_cmp(from_l
->sym
, from_r
->sym
);
434 sort__sym_to_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
436 struct addr_map_symbol
*to_l
, *to_r
;
438 if (!left
->branch_info
|| !right
->branch_info
)
439 return cmp_null(left
->branch_info
, right
->branch_info
);
441 to_l
= &left
->branch_info
->to
;
442 to_r
= &right
->branch_info
->to
;
444 if (!to_l
->sym
&& !to_r
->sym
)
445 return _sort__addr_cmp(to_l
->addr
, to_r
->addr
);
447 return _sort__sym_cmp(to_l
->sym
, to_r
->sym
);
450 static int hist_entry__sym_from_snprintf(struct hist_entry
*he
, char *bf
,
451 size_t size
, unsigned int width
)
453 if (he
->branch_info
) {
454 struct addr_map_symbol
*from
= &he
->branch_info
->from
;
456 return _hist_entry__sym_snprintf(from
->map
, from
->sym
, from
->addr
,
457 he
->level
, bf
, size
, width
);
460 return repsep_snprintf(bf
, size
, "%-*.*s", width
, width
, "N/A");
463 static int hist_entry__sym_to_snprintf(struct hist_entry
*he
, char *bf
,
464 size_t size
, unsigned int width
)
466 if (he
->branch_info
) {
467 struct addr_map_symbol
*to
= &he
->branch_info
->to
;
469 return _hist_entry__sym_snprintf(to
->map
, to
->sym
, to
->addr
,
470 he
->level
, bf
, size
, width
);
473 return repsep_snprintf(bf
, size
, "%-*.*s", width
, width
, "N/A");
476 struct sort_entry sort_dso_from
= {
477 .se_header
= "Source Shared Object",
478 .se_cmp
= sort__dso_from_cmp
,
479 .se_snprintf
= hist_entry__dso_from_snprintf
,
480 .se_width_idx
= HISTC_DSO_FROM
,
483 struct sort_entry sort_dso_to
= {
484 .se_header
= "Target Shared Object",
485 .se_cmp
= sort__dso_to_cmp
,
486 .se_snprintf
= hist_entry__dso_to_snprintf
,
487 .se_width_idx
= HISTC_DSO_TO
,
490 struct sort_entry sort_sym_from
= {
491 .se_header
= "Source Symbol",
492 .se_cmp
= sort__sym_from_cmp
,
493 .se_snprintf
= hist_entry__sym_from_snprintf
,
494 .se_width_idx
= HISTC_SYMBOL_FROM
,
497 struct sort_entry sort_sym_to
= {
498 .se_header
= "Target Symbol",
499 .se_cmp
= sort__sym_to_cmp
,
500 .se_snprintf
= hist_entry__sym_to_snprintf
,
501 .se_width_idx
= HISTC_SYMBOL_TO
,
505 sort__mispredict_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
509 if (!left
->branch_info
|| !right
->branch_info
)
510 return cmp_null(left
->branch_info
, right
->branch_info
);
512 mp
= left
->branch_info
->flags
.mispred
!= right
->branch_info
->flags
.mispred
;
513 p
= left
->branch_info
->flags
.predicted
!= right
->branch_info
->flags
.predicted
;
517 static int hist_entry__mispredict_snprintf(struct hist_entry
*he
, char *bf
,
518 size_t size
, unsigned int width
){
519 static const char *out
= "N/A";
521 if (he
->branch_info
) {
522 if (he
->branch_info
->flags
.predicted
)
524 else if (he
->branch_info
->flags
.mispred
)
528 return repsep_snprintf(bf
, size
, "%-*.*s", width
, width
, out
);
531 /* --sort daddr_sym */
533 sort__daddr_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
535 uint64_t l
= 0, r
= 0;
538 l
= left
->mem_info
->daddr
.addr
;
540 r
= right
->mem_info
->daddr
.addr
;
542 return (int64_t)(r
- l
);
545 static int hist_entry__daddr_snprintf(struct hist_entry
*he
, char *bf
,
546 size_t size
, unsigned int width
)
549 struct map
*map
= NULL
;
550 struct symbol
*sym
= NULL
;
553 addr
= he
->mem_info
->daddr
.addr
;
554 map
= he
->mem_info
->daddr
.map
;
555 sym
= he
->mem_info
->daddr
.sym
;
557 return _hist_entry__sym_snprintf(map
, sym
, addr
, he
->level
, bf
, size
,
562 sort__dso_daddr_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
564 struct map
*map_l
= NULL
;
565 struct map
*map_r
= NULL
;
568 map_l
= left
->mem_info
->daddr
.map
;
570 map_r
= right
->mem_info
->daddr
.map
;
572 return _sort__dso_cmp(map_l
, map_r
);
575 static int hist_entry__dso_daddr_snprintf(struct hist_entry
*he
, char *bf
,
576 size_t size
, unsigned int width
)
578 struct map
*map
= NULL
;
581 map
= he
->mem_info
->daddr
.map
;
583 return _hist_entry__dso_snprintf(map
, bf
, size
, width
);
587 sort__locked_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
589 union perf_mem_data_src data_src_l
;
590 union perf_mem_data_src data_src_r
;
593 data_src_l
= left
->mem_info
->data_src
;
595 data_src_l
.mem_lock
= PERF_MEM_LOCK_NA
;
598 data_src_r
= right
->mem_info
->data_src
;
600 data_src_r
.mem_lock
= PERF_MEM_LOCK_NA
;
602 return (int64_t)(data_src_r
.mem_lock
- data_src_l
.mem_lock
);
605 static int hist_entry__locked_snprintf(struct hist_entry
*he
, char *bf
,
606 size_t size
, unsigned int width
)
609 u64 mask
= PERF_MEM_LOCK_NA
;
612 mask
= he
->mem_info
->data_src
.mem_lock
;
614 if (mask
& PERF_MEM_LOCK_NA
)
616 else if (mask
& PERF_MEM_LOCK_LOCKED
)
621 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
625 sort__tlb_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
627 union perf_mem_data_src data_src_l
;
628 union perf_mem_data_src data_src_r
;
631 data_src_l
= left
->mem_info
->data_src
;
633 data_src_l
.mem_dtlb
= PERF_MEM_TLB_NA
;
636 data_src_r
= right
->mem_info
->data_src
;
638 data_src_r
.mem_dtlb
= PERF_MEM_TLB_NA
;
640 return (int64_t)(data_src_r
.mem_dtlb
- data_src_l
.mem_dtlb
);
643 static const char * const tlb_access
[] = {
652 #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
654 static int hist_entry__tlb_snprintf(struct hist_entry
*he
, char *bf
,
655 size_t size
, unsigned int width
)
658 size_t sz
= sizeof(out
) - 1; /* -1 for null termination */
660 u64 m
= PERF_MEM_TLB_NA
;
666 m
= he
->mem_info
->data_src
.mem_dtlb
;
668 hit
= m
& PERF_MEM_TLB_HIT
;
669 miss
= m
& PERF_MEM_TLB_MISS
;
671 /* already taken care of */
672 m
&= ~(PERF_MEM_TLB_HIT
|PERF_MEM_TLB_MISS
);
674 for (i
= 0; m
&& i
< NUM_TLB_ACCESS
; i
++, m
>>= 1) {
681 strncat(out
, tlb_access
[i
], sz
- l
);
682 l
+= strlen(tlb_access
[i
]);
687 strncat(out
, " hit", sz
- l
);
689 strncat(out
, " miss", sz
- l
);
691 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
695 sort__lvl_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
697 union perf_mem_data_src data_src_l
;
698 union perf_mem_data_src data_src_r
;
701 data_src_l
= left
->mem_info
->data_src
;
703 data_src_l
.mem_lvl
= PERF_MEM_LVL_NA
;
706 data_src_r
= right
->mem_info
->data_src
;
708 data_src_r
.mem_lvl
= PERF_MEM_LVL_NA
;
710 return (int64_t)(data_src_r
.mem_lvl
- data_src_l
.mem_lvl
);
713 static const char * const mem_lvl
[] = {
722 "Remote RAM (1 hop)",
723 "Remote RAM (2 hops)",
724 "Remote Cache (1 hop)",
725 "Remote Cache (2 hops)",
729 #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
731 static int hist_entry__lvl_snprintf(struct hist_entry
*he
, char *bf
,
732 size_t size
, unsigned int width
)
735 size_t sz
= sizeof(out
) - 1; /* -1 for null termination */
737 u64 m
= PERF_MEM_LVL_NA
;
741 m
= he
->mem_info
->data_src
.mem_lvl
;
745 hit
= m
& PERF_MEM_LVL_HIT
;
746 miss
= m
& PERF_MEM_LVL_MISS
;
748 /* already taken care of */
749 m
&= ~(PERF_MEM_LVL_HIT
|PERF_MEM_LVL_MISS
);
751 for (i
= 0; m
&& i
< NUM_MEM_LVL
; i
++, m
>>= 1) {
758 strncat(out
, mem_lvl
[i
], sz
- l
);
759 l
+= strlen(mem_lvl
[i
]);
764 strncat(out
, " hit", sz
- l
);
766 strncat(out
, " miss", sz
- l
);
768 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
772 sort__snoop_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
774 union perf_mem_data_src data_src_l
;
775 union perf_mem_data_src data_src_r
;
778 data_src_l
= left
->mem_info
->data_src
;
780 data_src_l
.mem_snoop
= PERF_MEM_SNOOP_NA
;
783 data_src_r
= right
->mem_info
->data_src
;
785 data_src_r
.mem_snoop
= PERF_MEM_SNOOP_NA
;
787 return (int64_t)(data_src_r
.mem_snoop
- data_src_l
.mem_snoop
);
790 static const char * const snoop_access
[] = {
797 #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
799 static int hist_entry__snoop_snprintf(struct hist_entry
*he
, char *bf
,
800 size_t size
, unsigned int width
)
803 size_t sz
= sizeof(out
) - 1; /* -1 for null termination */
805 u64 m
= PERF_MEM_SNOOP_NA
;
810 m
= he
->mem_info
->data_src
.mem_snoop
;
812 for (i
= 0; m
&& i
< NUM_SNOOP_ACCESS
; i
++, m
>>= 1) {
819 strncat(out
, snoop_access
[i
], sz
- l
);
820 l
+= strlen(snoop_access
[i
]);
826 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
829 static inline u64
cl_address(u64 address
)
831 /* return the cacheline of the address */
832 return (address
& ~(cacheline_size
- 1));
836 sort__dcacheline_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
839 struct map
*l_map
, *r_map
;
841 if (!left
->mem_info
) return -1;
842 if (!right
->mem_info
) return 1;
844 /* group event types together */
845 if (left
->cpumode
> right
->cpumode
) return -1;
846 if (left
->cpumode
< right
->cpumode
) return 1;
848 l_map
= left
->mem_info
->daddr
.map
;
849 r_map
= right
->mem_info
->daddr
.map
;
851 /* if both are NULL, jump to sort on al_addr instead */
852 if (!l_map
&& !r_map
)
855 if (!l_map
) return -1;
856 if (!r_map
) return 1;
858 if (l_map
->maj
> r_map
->maj
) return -1;
859 if (l_map
->maj
< r_map
->maj
) return 1;
861 if (l_map
->min
> r_map
->min
) return -1;
862 if (l_map
->min
< r_map
->min
) return 1;
864 if (l_map
->ino
> r_map
->ino
) return -1;
865 if (l_map
->ino
< r_map
->ino
) return 1;
867 if (l_map
->ino_generation
> r_map
->ino_generation
) return -1;
868 if (l_map
->ino_generation
< r_map
->ino_generation
) return 1;
871 * Addresses with no major/minor numbers are assumed to be
872 * anonymous in userspace. Sort those on pid then address.
874 * The kernel and non-zero major/minor mapped areas are
875 * assumed to be unity mapped. Sort those on address.
878 if ((left
->cpumode
!= PERF_RECORD_MISC_KERNEL
) &&
879 (!(l_map
->flags
& MAP_SHARED
)) &&
880 !l_map
->maj
&& !l_map
->min
&& !l_map
->ino
&&
881 !l_map
->ino_generation
) {
882 /* userspace anonymous */
884 if (left
->thread
->pid_
> right
->thread
->pid_
) return -1;
885 if (left
->thread
->pid_
< right
->thread
->pid_
) return 1;
889 /* al_addr does all the right addr - start + offset calculations */
890 l
= cl_address(left
->mem_info
->daddr
.al_addr
);
891 r
= cl_address(right
->mem_info
->daddr
.al_addr
);
893 if (l
> r
) return -1;
899 static int hist_entry__dcacheline_snprintf(struct hist_entry
*he
, char *bf
,
900 size_t size
, unsigned int width
)
904 struct map
*map
= NULL
;
905 struct symbol
*sym
= NULL
;
906 char level
= he
->level
;
909 addr
= cl_address(he
->mem_info
->daddr
.al_addr
);
910 map
= he
->mem_info
->daddr
.map
;
911 sym
= he
->mem_info
->daddr
.sym
;
913 /* print [s] for shared data mmaps */
914 if ((he
->cpumode
!= PERF_RECORD_MISC_KERNEL
) &&
915 map
&& (map
->type
== MAP__VARIABLE
) &&
916 (map
->flags
& MAP_SHARED
) &&
917 (map
->maj
|| map
->min
|| map
->ino
||
918 map
->ino_generation
))
923 return _hist_entry__sym_snprintf(map
, sym
, addr
, level
, bf
, size
,
927 struct sort_entry sort_mispredict
= {
928 .se_header
= "Branch Mispredicted",
929 .se_cmp
= sort__mispredict_cmp
,
930 .se_snprintf
= hist_entry__mispredict_snprintf
,
931 .se_width_idx
= HISTC_MISPREDICT
,
934 static u64
he_weight(struct hist_entry
*he
)
936 return he
->stat
.nr_events
? he
->stat
.weight
/ he
->stat
.nr_events
: 0;
940 sort__local_weight_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
942 return he_weight(left
) - he_weight(right
);
945 static int hist_entry__local_weight_snprintf(struct hist_entry
*he
, char *bf
,
946 size_t size
, unsigned int width
)
948 return repsep_snprintf(bf
, size
, "%-*llu", width
, he_weight(he
));
951 struct sort_entry sort_local_weight
= {
952 .se_header
= "Local Weight",
953 .se_cmp
= sort__local_weight_cmp
,
954 .se_snprintf
= hist_entry__local_weight_snprintf
,
955 .se_width_idx
= HISTC_LOCAL_WEIGHT
,
959 sort__global_weight_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
961 return left
->stat
.weight
- right
->stat
.weight
;
964 static int hist_entry__global_weight_snprintf(struct hist_entry
*he
, char *bf
,
965 size_t size
, unsigned int width
)
967 return repsep_snprintf(bf
, size
, "%-*llu", width
, he
->stat
.weight
);
970 struct sort_entry sort_global_weight
= {
971 .se_header
= "Weight",
972 .se_cmp
= sort__global_weight_cmp
,
973 .se_snprintf
= hist_entry__global_weight_snprintf
,
974 .se_width_idx
= HISTC_GLOBAL_WEIGHT
,
977 struct sort_entry sort_mem_daddr_sym
= {
978 .se_header
= "Data Symbol",
979 .se_cmp
= sort__daddr_cmp
,
980 .se_snprintf
= hist_entry__daddr_snprintf
,
981 .se_width_idx
= HISTC_MEM_DADDR_SYMBOL
,
984 struct sort_entry sort_mem_daddr_dso
= {
985 .se_header
= "Data Object",
986 .se_cmp
= sort__dso_daddr_cmp
,
987 .se_snprintf
= hist_entry__dso_daddr_snprintf
,
988 .se_width_idx
= HISTC_MEM_DADDR_SYMBOL
,
991 struct sort_entry sort_mem_locked
= {
992 .se_header
= "Locked",
993 .se_cmp
= sort__locked_cmp
,
994 .se_snprintf
= hist_entry__locked_snprintf
,
995 .se_width_idx
= HISTC_MEM_LOCKED
,
998 struct sort_entry sort_mem_tlb
= {
999 .se_header
= "TLB access",
1000 .se_cmp
= sort__tlb_cmp
,
1001 .se_snprintf
= hist_entry__tlb_snprintf
,
1002 .se_width_idx
= HISTC_MEM_TLB
,
1005 struct sort_entry sort_mem_lvl
= {
1006 .se_header
= "Memory access",
1007 .se_cmp
= sort__lvl_cmp
,
1008 .se_snprintf
= hist_entry__lvl_snprintf
,
1009 .se_width_idx
= HISTC_MEM_LVL
,
1012 struct sort_entry sort_mem_snoop
= {
1013 .se_header
= "Snoop",
1014 .se_cmp
= sort__snoop_cmp
,
1015 .se_snprintf
= hist_entry__snoop_snprintf
,
1016 .se_width_idx
= HISTC_MEM_SNOOP
,
1019 struct sort_entry sort_mem_dcacheline
= {
1020 .se_header
= "Data Cacheline",
1021 .se_cmp
= sort__dcacheline_cmp
,
1022 .se_snprintf
= hist_entry__dcacheline_snprintf
,
1023 .se_width_idx
= HISTC_MEM_DCACHELINE
,
1027 sort__abort_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
1029 if (!left
->branch_info
|| !right
->branch_info
)
1030 return cmp_null(left
->branch_info
, right
->branch_info
);
1032 return left
->branch_info
->flags
.abort
!=
1033 right
->branch_info
->flags
.abort
;
1036 static int hist_entry__abort_snprintf(struct hist_entry
*he
, char *bf
,
1037 size_t size
, unsigned int width
)
1039 static const char *out
= "N/A";
1041 if (he
->branch_info
) {
1042 if (he
->branch_info
->flags
.abort
)
1048 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
1051 struct sort_entry sort_abort
= {
1052 .se_header
= "Transaction abort",
1053 .se_cmp
= sort__abort_cmp
,
1054 .se_snprintf
= hist_entry__abort_snprintf
,
1055 .se_width_idx
= HISTC_ABORT
,
1059 sort__in_tx_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
1061 if (!left
->branch_info
|| !right
->branch_info
)
1062 return cmp_null(left
->branch_info
, right
->branch_info
);
1064 return left
->branch_info
->flags
.in_tx
!=
1065 right
->branch_info
->flags
.in_tx
;
1068 static int hist_entry__in_tx_snprintf(struct hist_entry
*he
, char *bf
,
1069 size_t size
, unsigned int width
)
1071 static const char *out
= "N/A";
1073 if (he
->branch_info
) {
1074 if (he
->branch_info
->flags
.in_tx
)
1080 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
1083 struct sort_entry sort_in_tx
= {
1084 .se_header
= "Branch in transaction",
1085 .se_cmp
= sort__in_tx_cmp
,
1086 .se_snprintf
= hist_entry__in_tx_snprintf
,
1087 .se_width_idx
= HISTC_IN_TX
,
1091 sort__transaction_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
1093 return left
->transaction
- right
->transaction
;
1096 static inline char *add_str(char *p
, const char *str
)
1099 return p
+ strlen(str
);
1102 static struct txbit
{
1107 { PERF_TXN_ELISION
, "EL ", 0 },
1108 { PERF_TXN_TRANSACTION
, "TX ", 1 },
1109 { PERF_TXN_SYNC
, "SYNC ", 1 },
1110 { PERF_TXN_ASYNC
, "ASYNC ", 0 },
1111 { PERF_TXN_RETRY
, "RETRY ", 0 },
1112 { PERF_TXN_CONFLICT
, "CON ", 0 },
1113 { PERF_TXN_CAPACITY_WRITE
, "CAP-WRITE ", 1 },
1114 { PERF_TXN_CAPACITY_READ
, "CAP-READ ", 0 },
1118 int hist_entry__transaction_len(void)
1123 for (i
= 0; txbits
[i
].name
; i
++) {
1124 if (!txbits
[i
].skip_for_len
)
1125 len
+= strlen(txbits
[i
].name
);
1127 len
+= 4; /* :XX<space> */
1131 static int hist_entry__transaction_snprintf(struct hist_entry
*he
, char *bf
,
1132 size_t size
, unsigned int width
)
1134 u64 t
= he
->transaction
;
1140 for (i
= 0; txbits
[i
].name
; i
++)
1141 if (txbits
[i
].flag
& t
)
1142 p
= add_str(p
, txbits
[i
].name
);
1143 if (t
&& !(t
& (PERF_TXN_SYNC
|PERF_TXN_ASYNC
)))
1144 p
= add_str(p
, "NEITHER ");
1145 if (t
& PERF_TXN_ABORT_MASK
) {
1146 sprintf(p
, ":%" PRIx64
,
1147 (t
& PERF_TXN_ABORT_MASK
) >>
1148 PERF_TXN_ABORT_SHIFT
);
1152 return repsep_snprintf(bf
, size
, "%-*s", width
, buf
);
1155 struct sort_entry sort_transaction
= {
1156 .se_header
= "Transaction ",
1157 .se_cmp
= sort__transaction_cmp
,
1158 .se_snprintf
= hist_entry__transaction_snprintf
,
1159 .se_width_idx
= HISTC_TRANSACTION
,
1162 struct sort_dimension
{
1164 struct sort_entry
*entry
;
1168 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1170 static struct sort_dimension common_sort_dimensions
[] = {
1171 DIM(SORT_PID
, "pid", sort_thread
),
1172 DIM(SORT_COMM
, "comm", sort_comm
),
1173 DIM(SORT_DSO
, "dso", sort_dso
),
1174 DIM(SORT_SYM
, "symbol", sort_sym
),
1175 DIM(SORT_PARENT
, "parent", sort_parent
),
1176 DIM(SORT_CPU
, "cpu", sort_cpu
),
1177 DIM(SORT_SRCLINE
, "srcline", sort_srcline
),
1178 DIM(SORT_LOCAL_WEIGHT
, "local_weight", sort_local_weight
),
1179 DIM(SORT_GLOBAL_WEIGHT
, "weight", sort_global_weight
),
1180 DIM(SORT_TRANSACTION
, "transaction", sort_transaction
),
1185 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1187 static struct sort_dimension bstack_sort_dimensions
[] = {
1188 DIM(SORT_DSO_FROM
, "dso_from", sort_dso_from
),
1189 DIM(SORT_DSO_TO
, "dso_to", sort_dso_to
),
1190 DIM(SORT_SYM_FROM
, "symbol_from", sort_sym_from
),
1191 DIM(SORT_SYM_TO
, "symbol_to", sort_sym_to
),
1192 DIM(SORT_MISPREDICT
, "mispredict", sort_mispredict
),
1193 DIM(SORT_IN_TX
, "in_tx", sort_in_tx
),
1194 DIM(SORT_ABORT
, "abort", sort_abort
),
1199 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1201 static struct sort_dimension memory_sort_dimensions
[] = {
1202 DIM(SORT_MEM_DADDR_SYMBOL
, "symbol_daddr", sort_mem_daddr_sym
),
1203 DIM(SORT_MEM_DADDR_DSO
, "dso_daddr", sort_mem_daddr_dso
),
1204 DIM(SORT_MEM_LOCKED
, "locked", sort_mem_locked
),
1205 DIM(SORT_MEM_TLB
, "tlb", sort_mem_tlb
),
1206 DIM(SORT_MEM_LVL
, "mem", sort_mem_lvl
),
1207 DIM(SORT_MEM_SNOOP
, "snoop", sort_mem_snoop
),
1208 DIM(SORT_MEM_DCACHELINE
, "dcacheline", sort_mem_dcacheline
),
1213 struct hpp_dimension
{
1215 struct perf_hpp_fmt
*fmt
;
1219 #define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1221 static struct hpp_dimension hpp_sort_dimensions
[] = {
1222 DIM(PERF_HPP__OVERHEAD
, "overhead"),
1223 DIM(PERF_HPP__OVERHEAD_SYS
, "overhead_sys"),
1224 DIM(PERF_HPP__OVERHEAD_US
, "overhead_us"),
1225 DIM(PERF_HPP__OVERHEAD_GUEST_SYS
, "overhead_guest_sys"),
1226 DIM(PERF_HPP__OVERHEAD_GUEST_US
, "overhead_guest_us"),
1227 DIM(PERF_HPP__OVERHEAD_ACC
, "overhead_children"),
1228 DIM(PERF_HPP__SAMPLES
, "sample"),
1229 DIM(PERF_HPP__PERIOD
, "period"),
1234 struct hpp_sort_entry
{
1235 struct perf_hpp_fmt hpp
;
1236 struct sort_entry
*se
;
1239 bool perf_hpp__same_sort_entry(struct perf_hpp_fmt
*a
, struct perf_hpp_fmt
*b
)
1241 struct hpp_sort_entry
*hse_a
;
1242 struct hpp_sort_entry
*hse_b
;
1244 if (!perf_hpp__is_sort_entry(a
) || !perf_hpp__is_sort_entry(b
))
1247 hse_a
= container_of(a
, struct hpp_sort_entry
, hpp
);
1248 hse_b
= container_of(b
, struct hpp_sort_entry
, hpp
);
1250 return hse_a
->se
== hse_b
->se
;
1253 void perf_hpp__reset_sort_width(struct perf_hpp_fmt
*fmt
, struct hists
*hists
)
1255 struct hpp_sort_entry
*hse
;
1257 if (!perf_hpp__is_sort_entry(fmt
))
1260 hse
= container_of(fmt
, struct hpp_sort_entry
, hpp
);
1261 hists__new_col_len(hists
, hse
->se
->se_width_idx
, strlen(fmt
->name
));
1264 static int __sort__hpp_header(struct perf_hpp_fmt
*fmt
, struct perf_hpp
*hpp
,
1265 struct perf_evsel
*evsel
)
1267 struct hpp_sort_entry
*hse
;
1268 size_t len
= fmt
->user_len
;
1270 hse
= container_of(fmt
, struct hpp_sort_entry
, hpp
);
1273 len
= hists__col_len(evsel__hists(evsel
), hse
->se
->se_width_idx
);
1275 return scnprintf(hpp
->buf
, hpp
->size
, "%-*.*s", len
, len
, fmt
->name
);
1278 static int __sort__hpp_width(struct perf_hpp_fmt
*fmt
,
1279 struct perf_hpp
*hpp __maybe_unused
,
1280 struct perf_evsel
*evsel
)
1282 struct hpp_sort_entry
*hse
;
1283 size_t len
= fmt
->user_len
;
1285 hse
= container_of(fmt
, struct hpp_sort_entry
, hpp
);
1288 len
= hists__col_len(evsel__hists(evsel
), hse
->se
->se_width_idx
);
1293 static int __sort__hpp_entry(struct perf_hpp_fmt
*fmt
, struct perf_hpp
*hpp
,
1294 struct hist_entry
*he
)
1296 struct hpp_sort_entry
*hse
;
1297 size_t len
= fmt
->user_len
;
1299 hse
= container_of(fmt
, struct hpp_sort_entry
, hpp
);
1302 len
= hists__col_len(he
->hists
, hse
->se
->se_width_idx
);
1304 return hse
->se
->se_snprintf(he
, hpp
->buf
, hpp
->size
, len
);
1307 static struct hpp_sort_entry
*
1308 __sort_dimension__alloc_hpp(struct sort_dimension
*sd
)
1310 struct hpp_sort_entry
*hse
;
1312 hse
= malloc(sizeof(*hse
));
1314 pr_err("Memory allocation failed\n");
1318 hse
->se
= sd
->entry
;
1319 hse
->hpp
.name
= sd
->entry
->se_header
;
1320 hse
->hpp
.header
= __sort__hpp_header
;
1321 hse
->hpp
.width
= __sort__hpp_width
;
1322 hse
->hpp
.entry
= __sort__hpp_entry
;
1323 hse
->hpp
.color
= NULL
;
1325 hse
->hpp
.cmp
= sd
->entry
->se_cmp
;
1326 hse
->hpp
.collapse
= sd
->entry
->se_collapse
? : sd
->entry
->se_cmp
;
1327 hse
->hpp
.sort
= sd
->entry
->se_sort
? : hse
->hpp
.collapse
;
1329 INIT_LIST_HEAD(&hse
->hpp
.list
);
1330 INIT_LIST_HEAD(&hse
->hpp
.sort_list
);
1331 hse
->hpp
.elide
= false;
1333 hse
->hpp
.user_len
= 0;
1338 bool perf_hpp__is_sort_entry(struct perf_hpp_fmt
*format
)
1340 return format
->header
== __sort__hpp_header
;
1343 static int __sort_dimension__add_hpp_sort(struct sort_dimension
*sd
)
1345 struct hpp_sort_entry
*hse
= __sort_dimension__alloc_hpp(sd
);
1350 perf_hpp__register_sort_field(&hse
->hpp
);
1354 static int __sort_dimension__add_hpp_output(struct sort_dimension
*sd
)
1356 struct hpp_sort_entry
*hse
= __sort_dimension__alloc_hpp(sd
);
1361 perf_hpp__column_register(&hse
->hpp
);
1365 static int __sort_dimension__add(struct sort_dimension
*sd
)
1370 if (__sort_dimension__add_hpp_sort(sd
) < 0)
1373 if (sd
->entry
->se_collapse
)
1374 sort__need_collapse
= 1;
1381 static int __hpp_dimension__add(struct hpp_dimension
*hd
)
1386 perf_hpp__register_sort_field(hd
->fmt
);
1391 static int __sort_dimension__add_output(struct sort_dimension
*sd
)
1396 if (__sort_dimension__add_hpp_output(sd
) < 0)
1403 static int __hpp_dimension__add_output(struct hpp_dimension
*hd
)
1408 perf_hpp__column_register(hd
->fmt
);
1413 int sort_dimension__add(const char *tok
)
1417 for (i
= 0; i
< ARRAY_SIZE(common_sort_dimensions
); i
++) {
1418 struct sort_dimension
*sd
= &common_sort_dimensions
[i
];
1420 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1423 if (sd
->entry
== &sort_parent
) {
1424 int ret
= regcomp(&parent_regex
, parent_pattern
, REG_EXTENDED
);
1428 regerror(ret
, &parent_regex
, err
, sizeof(err
));
1429 pr_err("Invalid regex: %s\n%s", parent_pattern
, err
);
1432 sort__has_parent
= 1;
1433 } else if (sd
->entry
== &sort_sym
) {
1435 } else if (sd
->entry
== &sort_dso
) {
1439 return __sort_dimension__add(sd
);
1442 for (i
= 0; i
< ARRAY_SIZE(hpp_sort_dimensions
); i
++) {
1443 struct hpp_dimension
*hd
= &hpp_sort_dimensions
[i
];
1445 if (strncasecmp(tok
, hd
->name
, strlen(tok
)))
1448 return __hpp_dimension__add(hd
);
1451 for (i
= 0; i
< ARRAY_SIZE(bstack_sort_dimensions
); i
++) {
1452 struct sort_dimension
*sd
= &bstack_sort_dimensions
[i
];
1454 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1457 if (sort__mode
!= SORT_MODE__BRANCH
)
1460 if (sd
->entry
== &sort_sym_from
|| sd
->entry
== &sort_sym_to
)
1463 __sort_dimension__add(sd
);
1467 for (i
= 0; i
< ARRAY_SIZE(memory_sort_dimensions
); i
++) {
1468 struct sort_dimension
*sd
= &memory_sort_dimensions
[i
];
1470 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1473 if (sort__mode
!= SORT_MODE__MEMORY
)
1476 if (sd
->entry
== &sort_mem_daddr_sym
)
1479 __sort_dimension__add(sd
);
1486 static const char *get_default_sort_order(void)
1488 const char *default_sort_orders
[] = {
1490 default_branch_sort_order
,
1491 default_mem_sort_order
,
1492 default_top_sort_order
,
1493 default_diff_sort_order
,
1496 BUG_ON(sort__mode
>= ARRAY_SIZE(default_sort_orders
));
1498 return default_sort_orders
[sort__mode
];
1501 static int setup_sort_order(void)
1503 char *new_sort_order
;
1506 * Append '+'-prefixed sort order to the default sort
1509 if (!sort_order
|| is_strict_order(sort_order
))
1512 if (sort_order
[1] == '\0') {
1513 error("Invalid --sort key: `+'");
1518 * We allocate new sort_order string, but we never free it,
1519 * because it's checked over the rest of the code.
1521 if (asprintf(&new_sort_order
, "%s,%s",
1522 get_default_sort_order(), sort_order
+ 1) < 0) {
1523 error("Not enough memory to set up --sort");
1527 sort_order
= new_sort_order
;
1531 static int __setup_sorting(void)
1533 char *tmp
, *tok
, *str
;
1534 const char *sort_keys
;
1537 ret
= setup_sort_order();
1541 sort_keys
= sort_order
;
1542 if (sort_keys
== NULL
) {
1543 if (is_strict_order(field_order
)) {
1545 * If user specified field order but no sort order,
1546 * we'll honor it and not add default sort orders.
1551 sort_keys
= get_default_sort_order();
1554 str
= strdup(sort_keys
);
1556 error("Not enough memory to setup sort keys");
1560 for (tok
= strtok_r(str
, ", ", &tmp
);
1561 tok
; tok
= strtok_r(NULL
, ", ", &tmp
)) {
1562 ret
= sort_dimension__add(tok
);
1563 if (ret
== -EINVAL
) {
1564 error("Invalid --sort key: `%s'", tok
);
1566 } else if (ret
== -ESRCH
) {
1567 error("Unknown --sort key: `%s'", tok
);
1576 void perf_hpp__set_elide(int idx
, bool elide
)
1578 struct perf_hpp_fmt
*fmt
;
1579 struct hpp_sort_entry
*hse
;
1581 perf_hpp__for_each_format(fmt
) {
1582 if (!perf_hpp__is_sort_entry(fmt
))
1585 hse
= container_of(fmt
, struct hpp_sort_entry
, hpp
);
1586 if (hse
->se
->se_width_idx
== idx
) {
1593 static bool __get_elide(struct strlist
*list
, const char *list_name
, FILE *fp
)
1595 if (list
&& strlist__nr_entries(list
) == 1) {
1597 fprintf(fp
, "# %s: %s\n", list_name
,
1598 strlist__entry(list
, 0)->s
);
1604 static bool get_elide(int idx
, FILE *output
)
1608 return __get_elide(symbol_conf
.sym_list
, "symbol", output
);
1610 return __get_elide(symbol_conf
.dso_list
, "dso", output
);
1612 return __get_elide(symbol_conf
.comm_list
, "comm", output
);
1617 if (sort__mode
!= SORT_MODE__BRANCH
)
1621 case HISTC_SYMBOL_FROM
:
1622 return __get_elide(symbol_conf
.sym_from_list
, "sym_from", output
);
1623 case HISTC_SYMBOL_TO
:
1624 return __get_elide(symbol_conf
.sym_to_list
, "sym_to", output
);
1625 case HISTC_DSO_FROM
:
1626 return __get_elide(symbol_conf
.dso_from_list
, "dso_from", output
);
1628 return __get_elide(symbol_conf
.dso_to_list
, "dso_to", output
);
1636 void sort__setup_elide(FILE *output
)
1638 struct perf_hpp_fmt
*fmt
;
1639 struct hpp_sort_entry
*hse
;
1641 perf_hpp__for_each_format(fmt
) {
1642 if (!perf_hpp__is_sort_entry(fmt
))
1645 hse
= container_of(fmt
, struct hpp_sort_entry
, hpp
);
1646 fmt
->elide
= get_elide(hse
->se
->se_width_idx
, output
);
1650 * It makes no sense to elide all of sort entries.
1651 * Just revert them to show up again.
1653 perf_hpp__for_each_format(fmt
) {
1654 if (!perf_hpp__is_sort_entry(fmt
))
1661 perf_hpp__for_each_format(fmt
) {
1662 if (!perf_hpp__is_sort_entry(fmt
))
1669 static int output_field_add(char *tok
)
1673 for (i
= 0; i
< ARRAY_SIZE(common_sort_dimensions
); i
++) {
1674 struct sort_dimension
*sd
= &common_sort_dimensions
[i
];
1676 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1679 return __sort_dimension__add_output(sd
);
1682 for (i
= 0; i
< ARRAY_SIZE(hpp_sort_dimensions
); i
++) {
1683 struct hpp_dimension
*hd
= &hpp_sort_dimensions
[i
];
1685 if (strncasecmp(tok
, hd
->name
, strlen(tok
)))
1688 return __hpp_dimension__add_output(hd
);
1691 for (i
= 0; i
< ARRAY_SIZE(bstack_sort_dimensions
); i
++) {
1692 struct sort_dimension
*sd
= &bstack_sort_dimensions
[i
];
1694 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1697 return __sort_dimension__add_output(sd
);
1700 for (i
= 0; i
< ARRAY_SIZE(memory_sort_dimensions
); i
++) {
1701 struct sort_dimension
*sd
= &memory_sort_dimensions
[i
];
1703 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1706 return __sort_dimension__add_output(sd
);
1712 static void reset_dimensions(void)
1716 for (i
= 0; i
< ARRAY_SIZE(common_sort_dimensions
); i
++)
1717 common_sort_dimensions
[i
].taken
= 0;
1719 for (i
= 0; i
< ARRAY_SIZE(hpp_sort_dimensions
); i
++)
1720 hpp_sort_dimensions
[i
].taken
= 0;
1722 for (i
= 0; i
< ARRAY_SIZE(bstack_sort_dimensions
); i
++)
1723 bstack_sort_dimensions
[i
].taken
= 0;
1725 for (i
= 0; i
< ARRAY_SIZE(memory_sort_dimensions
); i
++)
1726 memory_sort_dimensions
[i
].taken
= 0;
1729 bool is_strict_order(const char *order
)
1731 return order
&& (*order
!= '+');
1734 static int __setup_output_field(void)
1736 char *tmp
, *tok
, *str
, *strp
;
1739 if (field_order
== NULL
)
1744 strp
= str
= strdup(field_order
);
1746 error("Not enough memory to setup output fields");
1750 if (!is_strict_order(field_order
))
1753 if (!strlen(strp
)) {
1754 error("Invalid --fields key: `+'");
1758 for (tok
= strtok_r(strp
, ", ", &tmp
);
1759 tok
; tok
= strtok_r(NULL
, ", ", &tmp
)) {
1760 ret
= output_field_add(tok
);
1761 if (ret
== -EINVAL
) {
1762 error("Invalid --fields key: `%s'", tok
);
1764 } else if (ret
== -ESRCH
) {
1765 error("Unknown --fields key: `%s'", tok
);
1775 int setup_sorting(void)
1779 err
= __setup_sorting();
1783 if (parent_pattern
!= default_parent_pattern
) {
1784 err
= sort_dimension__add("parent");
1792 * perf diff doesn't use default hpp output fields.
1794 if (sort__mode
!= SORT_MODE__DIFF
)
1797 err
= __setup_output_field();
1801 /* copy sort keys to output fields */
1802 perf_hpp__setup_output_field();
1803 /* and then copy output fields to sort keys */
1804 perf_hpp__append_sort_keys();
1809 void reset_output_field(void)
1811 sort__need_collapse
= 0;
1812 sort__has_parent
= 0;
1820 perf_hpp__reset_output_field();