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
);
73 return repsep_snprintf(bf
, size
, "%*s:%5d", width
- 6,
74 comm
?: "", he
->thread
->tid
);
77 struct sort_entry sort_thread
= {
78 .se_header
= "Command: Pid",
79 .se_cmp
= sort__thread_cmp
,
80 .se_snprintf
= hist_entry__thread_snprintf
,
81 .se_width_idx
= HISTC_THREAD
,
87 sort__comm_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
89 /* Compare the addr that should be unique among comm */
90 return comm__str(right
->comm
) - comm__str(left
->comm
);
94 sort__comm_collapse(struct hist_entry
*left
, struct hist_entry
*right
)
96 /* Compare the addr that should be unique among comm */
97 return comm__str(right
->comm
) - comm__str(left
->comm
);
101 sort__comm_sort(struct hist_entry
*left
, struct hist_entry
*right
)
103 return strcmp(comm__str(right
->comm
), comm__str(left
->comm
));
106 static int hist_entry__comm_snprintf(struct hist_entry
*he
, char *bf
,
107 size_t size
, unsigned int width
)
109 return repsep_snprintf(bf
, size
, "%*s", width
, comm__str(he
->comm
));
112 struct sort_entry sort_comm
= {
113 .se_header
= "Command",
114 .se_cmp
= sort__comm_cmp
,
115 .se_collapse
= sort__comm_collapse
,
116 .se_sort
= sort__comm_sort
,
117 .se_snprintf
= hist_entry__comm_snprintf
,
118 .se_width_idx
= HISTC_COMM
,
123 static int64_t _sort__dso_cmp(struct map
*map_l
, struct map
*map_r
)
125 struct dso
*dso_l
= map_l
? map_l
->dso
: NULL
;
126 struct dso
*dso_r
= map_r
? map_r
->dso
: NULL
;
127 const char *dso_name_l
, *dso_name_r
;
129 if (!dso_l
|| !dso_r
)
130 return cmp_null(dso_r
, dso_l
);
133 dso_name_l
= dso_l
->long_name
;
134 dso_name_r
= dso_r
->long_name
;
136 dso_name_l
= dso_l
->short_name
;
137 dso_name_r
= dso_r
->short_name
;
140 return strcmp(dso_name_l
, dso_name_r
);
144 sort__dso_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
146 return _sort__dso_cmp(right
->ms
.map
, left
->ms
.map
);
149 static int _hist_entry__dso_snprintf(struct map
*map
, char *bf
,
150 size_t size
, unsigned int width
)
152 if (map
&& map
->dso
) {
153 const char *dso_name
= !verbose
? map
->dso
->short_name
:
155 return repsep_snprintf(bf
, size
, "%-*s", width
, dso_name
);
158 return repsep_snprintf(bf
, size
, "%-*s", width
, "[unknown]");
161 static int hist_entry__dso_snprintf(struct hist_entry
*he
, char *bf
,
162 size_t size
, unsigned int width
)
164 return _hist_entry__dso_snprintf(he
->ms
.map
, bf
, size
, width
);
167 struct sort_entry sort_dso
= {
168 .se_header
= "Shared Object",
169 .se_cmp
= sort__dso_cmp
,
170 .se_snprintf
= hist_entry__dso_snprintf
,
171 .se_width_idx
= HISTC_DSO
,
176 static int64_t _sort__addr_cmp(u64 left_ip
, u64 right_ip
)
178 return (int64_t)(right_ip
- left_ip
);
181 static int64_t _sort__sym_cmp(struct symbol
*sym_l
, struct symbol
*sym_r
)
185 if (!sym_l
|| !sym_r
)
186 return cmp_null(sym_l
, sym_r
);
194 return (int64_t)(ip_r
- ip_l
);
198 sort__sym_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
202 if (!left
->ms
.sym
&& !right
->ms
.sym
)
203 return _sort__addr_cmp(left
->ip
, right
->ip
);
206 * comparing symbol address alone is not enough since it's a
207 * relative address within a dso.
209 if (!sort__has_dso
) {
210 ret
= sort__dso_cmp(left
, right
);
215 return _sort__sym_cmp(left
->ms
.sym
, right
->ms
.sym
);
219 sort__sym_sort(struct hist_entry
*left
, struct hist_entry
*right
)
221 if (!left
->ms
.sym
|| !right
->ms
.sym
)
222 return cmp_null(left
->ms
.sym
, right
->ms
.sym
);
224 return strcmp(right
->ms
.sym
->name
, left
->ms
.sym
->name
);
227 static int _hist_entry__sym_snprintf(struct map
*map
, struct symbol
*sym
,
228 u64 ip
, char level
, char *bf
, size_t size
,
234 char o
= map
? dso__symtab_origin(map
->dso
) : '!';
235 ret
+= repsep_snprintf(bf
, size
, "%-#*llx %c ",
236 BITS_PER_LONG
/ 4 + 2, ip
, o
);
239 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "[%c] ", level
);
241 if (map
->type
== MAP__VARIABLE
) {
242 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%s", sym
->name
);
243 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "+0x%llx",
244 ip
- map
->unmap_ip(map
, sym
->start
));
245 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-*s",
248 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-*s",
253 size_t len
= BITS_PER_LONG
/ 4;
254 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-#.*llx",
256 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-*s",
263 static int hist_entry__sym_snprintf(struct hist_entry
*he
, char *bf
,
264 size_t size
, unsigned int width
)
266 return _hist_entry__sym_snprintf(he
->ms
.map
, he
->ms
.sym
, he
->ip
,
267 he
->level
, bf
, size
, width
);
270 struct sort_entry sort_sym
= {
271 .se_header
= "Symbol",
272 .se_cmp
= sort__sym_cmp
,
273 .se_sort
= sort__sym_sort
,
274 .se_snprintf
= hist_entry__sym_snprintf
,
275 .se_width_idx
= HISTC_SYMBOL
,
281 sort__srcline_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
283 if (!left
->srcline
) {
285 left
->srcline
= SRCLINE_UNKNOWN
;
287 struct map
*map
= left
->ms
.map
;
288 left
->srcline
= get_srcline(map
->dso
,
289 map__rip_2objdump(map
, left
->ip
));
292 if (!right
->srcline
) {
294 right
->srcline
= SRCLINE_UNKNOWN
;
296 struct map
*map
= right
->ms
.map
;
297 right
->srcline
= get_srcline(map
->dso
,
298 map__rip_2objdump(map
, right
->ip
));
301 return strcmp(right
->srcline
, left
->srcline
);
304 static int hist_entry__srcline_snprintf(struct hist_entry
*he
, char *bf
,
306 unsigned int width __maybe_unused
)
308 return repsep_snprintf(bf
, size
, "%s", he
->srcline
);
311 struct sort_entry sort_srcline
= {
312 .se_header
= "Source:Line",
313 .se_cmp
= sort__srcline_cmp
,
314 .se_snprintf
= hist_entry__srcline_snprintf
,
315 .se_width_idx
= HISTC_SRCLINE
,
321 sort__parent_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
323 struct symbol
*sym_l
= left
->parent
;
324 struct symbol
*sym_r
= right
->parent
;
326 if (!sym_l
|| !sym_r
)
327 return cmp_null(sym_l
, sym_r
);
329 return strcmp(sym_r
->name
, sym_l
->name
);
332 static int hist_entry__parent_snprintf(struct hist_entry
*he
, char *bf
,
333 size_t size
, unsigned int width
)
335 return repsep_snprintf(bf
, size
, "%-*s", width
,
336 he
->parent
? he
->parent
->name
: "[other]");
339 struct sort_entry sort_parent
= {
340 .se_header
= "Parent symbol",
341 .se_cmp
= sort__parent_cmp
,
342 .se_snprintf
= hist_entry__parent_snprintf
,
343 .se_width_idx
= HISTC_PARENT
,
349 sort__cpu_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
351 return right
->cpu
- left
->cpu
;
354 static int hist_entry__cpu_snprintf(struct hist_entry
*he
, char *bf
,
355 size_t size
, unsigned int width
)
357 return repsep_snprintf(bf
, size
, "%*d", width
, he
->cpu
);
360 struct sort_entry sort_cpu
= {
362 .se_cmp
= sort__cpu_cmp
,
363 .se_snprintf
= hist_entry__cpu_snprintf
,
364 .se_width_idx
= HISTC_CPU
,
367 /* sort keys for branch stacks */
370 sort__dso_from_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
372 return _sort__dso_cmp(left
->branch_info
->from
.map
,
373 right
->branch_info
->from
.map
);
376 static int hist_entry__dso_from_snprintf(struct hist_entry
*he
, char *bf
,
377 size_t size
, unsigned int width
)
379 return _hist_entry__dso_snprintf(he
->branch_info
->from
.map
,
384 sort__dso_to_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
386 return _sort__dso_cmp(left
->branch_info
->to
.map
,
387 right
->branch_info
->to
.map
);
390 static int hist_entry__dso_to_snprintf(struct hist_entry
*he
, char *bf
,
391 size_t size
, unsigned int width
)
393 return _hist_entry__dso_snprintf(he
->branch_info
->to
.map
,
398 sort__sym_from_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
400 struct addr_map_symbol
*from_l
= &left
->branch_info
->from
;
401 struct addr_map_symbol
*from_r
= &right
->branch_info
->from
;
403 if (!from_l
->sym
&& !from_r
->sym
)
404 return _sort__addr_cmp(from_l
->addr
, from_r
->addr
);
406 return _sort__sym_cmp(from_l
->sym
, from_r
->sym
);
410 sort__sym_to_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
412 struct addr_map_symbol
*to_l
= &left
->branch_info
->to
;
413 struct addr_map_symbol
*to_r
= &right
->branch_info
->to
;
415 if (!to_l
->sym
&& !to_r
->sym
)
416 return _sort__addr_cmp(to_l
->addr
, to_r
->addr
);
418 return _sort__sym_cmp(to_l
->sym
, to_r
->sym
);
421 static int hist_entry__sym_from_snprintf(struct hist_entry
*he
, char *bf
,
422 size_t size
, unsigned int width
)
424 struct addr_map_symbol
*from
= &he
->branch_info
->from
;
425 return _hist_entry__sym_snprintf(from
->map
, from
->sym
, from
->addr
,
426 he
->level
, bf
, size
, width
);
430 static int hist_entry__sym_to_snprintf(struct hist_entry
*he
, char *bf
,
431 size_t size
, unsigned int width
)
433 struct addr_map_symbol
*to
= &he
->branch_info
->to
;
434 return _hist_entry__sym_snprintf(to
->map
, to
->sym
, to
->addr
,
435 he
->level
, bf
, size
, width
);
439 struct sort_entry sort_dso_from
= {
440 .se_header
= "Source Shared Object",
441 .se_cmp
= sort__dso_from_cmp
,
442 .se_snprintf
= hist_entry__dso_from_snprintf
,
443 .se_width_idx
= HISTC_DSO_FROM
,
446 struct sort_entry sort_dso_to
= {
447 .se_header
= "Target Shared Object",
448 .se_cmp
= sort__dso_to_cmp
,
449 .se_snprintf
= hist_entry__dso_to_snprintf
,
450 .se_width_idx
= HISTC_DSO_TO
,
453 struct sort_entry sort_sym_from
= {
454 .se_header
= "Source Symbol",
455 .se_cmp
= sort__sym_from_cmp
,
456 .se_snprintf
= hist_entry__sym_from_snprintf
,
457 .se_width_idx
= HISTC_SYMBOL_FROM
,
460 struct sort_entry sort_sym_to
= {
461 .se_header
= "Target Symbol",
462 .se_cmp
= sort__sym_to_cmp
,
463 .se_snprintf
= hist_entry__sym_to_snprintf
,
464 .se_width_idx
= HISTC_SYMBOL_TO
,
468 sort__mispredict_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
470 const unsigned char mp
= left
->branch_info
->flags
.mispred
!=
471 right
->branch_info
->flags
.mispred
;
472 const unsigned char p
= left
->branch_info
->flags
.predicted
!=
473 right
->branch_info
->flags
.predicted
;
478 static int hist_entry__mispredict_snprintf(struct hist_entry
*he
, char *bf
,
479 size_t size
, unsigned int width
){
480 static const char *out
= "N/A";
482 if (he
->branch_info
->flags
.predicted
)
484 else if (he
->branch_info
->flags
.mispred
)
487 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
490 /* --sort daddr_sym */
492 sort__daddr_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
494 uint64_t l
= 0, r
= 0;
497 l
= left
->mem_info
->daddr
.addr
;
499 r
= right
->mem_info
->daddr
.addr
;
501 return (int64_t)(r
- l
);
504 static int hist_entry__daddr_snprintf(struct hist_entry
*he
, char *bf
,
505 size_t size
, unsigned int width
)
508 struct map
*map
= NULL
;
509 struct symbol
*sym
= NULL
;
512 addr
= he
->mem_info
->daddr
.addr
;
513 map
= he
->mem_info
->daddr
.map
;
514 sym
= he
->mem_info
->daddr
.sym
;
516 return _hist_entry__sym_snprintf(map
, sym
, addr
, he
->level
, bf
, size
,
521 sort__dso_daddr_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
523 struct map
*map_l
= NULL
;
524 struct map
*map_r
= NULL
;
527 map_l
= left
->mem_info
->daddr
.map
;
529 map_r
= right
->mem_info
->daddr
.map
;
531 return _sort__dso_cmp(map_l
, map_r
);
534 static int hist_entry__dso_daddr_snprintf(struct hist_entry
*he
, char *bf
,
535 size_t size
, unsigned int width
)
537 struct map
*map
= NULL
;
540 map
= he
->mem_info
->daddr
.map
;
542 return _hist_entry__dso_snprintf(map
, bf
, size
, width
);
546 sort__locked_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
548 union perf_mem_data_src data_src_l
;
549 union perf_mem_data_src data_src_r
;
552 data_src_l
= left
->mem_info
->data_src
;
554 data_src_l
.mem_lock
= PERF_MEM_LOCK_NA
;
557 data_src_r
= right
->mem_info
->data_src
;
559 data_src_r
.mem_lock
= PERF_MEM_LOCK_NA
;
561 return (int64_t)(data_src_r
.mem_lock
- data_src_l
.mem_lock
);
564 static int hist_entry__locked_snprintf(struct hist_entry
*he
, char *bf
,
565 size_t size
, unsigned int width
)
568 u64 mask
= PERF_MEM_LOCK_NA
;
571 mask
= he
->mem_info
->data_src
.mem_lock
;
573 if (mask
& PERF_MEM_LOCK_NA
)
575 else if (mask
& PERF_MEM_LOCK_LOCKED
)
580 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
584 sort__tlb_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
586 union perf_mem_data_src data_src_l
;
587 union perf_mem_data_src data_src_r
;
590 data_src_l
= left
->mem_info
->data_src
;
592 data_src_l
.mem_dtlb
= PERF_MEM_TLB_NA
;
595 data_src_r
= right
->mem_info
->data_src
;
597 data_src_r
.mem_dtlb
= PERF_MEM_TLB_NA
;
599 return (int64_t)(data_src_r
.mem_dtlb
- data_src_l
.mem_dtlb
);
602 static const char * const tlb_access
[] = {
611 #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
613 static int hist_entry__tlb_snprintf(struct hist_entry
*he
, char *bf
,
614 size_t size
, unsigned int width
)
617 size_t sz
= sizeof(out
) - 1; /* -1 for null termination */
619 u64 m
= PERF_MEM_TLB_NA
;
625 m
= he
->mem_info
->data_src
.mem_dtlb
;
627 hit
= m
& PERF_MEM_TLB_HIT
;
628 miss
= m
& PERF_MEM_TLB_MISS
;
630 /* already taken care of */
631 m
&= ~(PERF_MEM_TLB_HIT
|PERF_MEM_TLB_MISS
);
633 for (i
= 0; m
&& i
< NUM_TLB_ACCESS
; i
++, m
>>= 1) {
640 strncat(out
, tlb_access
[i
], sz
- l
);
641 l
+= strlen(tlb_access
[i
]);
646 strncat(out
, " hit", sz
- l
);
648 strncat(out
, " miss", sz
- l
);
650 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
654 sort__lvl_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
656 union perf_mem_data_src data_src_l
;
657 union perf_mem_data_src data_src_r
;
660 data_src_l
= left
->mem_info
->data_src
;
662 data_src_l
.mem_lvl
= PERF_MEM_LVL_NA
;
665 data_src_r
= right
->mem_info
->data_src
;
667 data_src_r
.mem_lvl
= PERF_MEM_LVL_NA
;
669 return (int64_t)(data_src_r
.mem_lvl
- data_src_l
.mem_lvl
);
672 static const char * const mem_lvl
[] = {
681 "Remote RAM (1 hop)",
682 "Remote RAM (2 hops)",
683 "Remote Cache (1 hop)",
684 "Remote Cache (2 hops)",
688 #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
690 static int hist_entry__lvl_snprintf(struct hist_entry
*he
, char *bf
,
691 size_t size
, unsigned int width
)
694 size_t sz
= sizeof(out
) - 1; /* -1 for null termination */
696 u64 m
= PERF_MEM_LVL_NA
;
700 m
= he
->mem_info
->data_src
.mem_lvl
;
704 hit
= m
& PERF_MEM_LVL_HIT
;
705 miss
= m
& PERF_MEM_LVL_MISS
;
707 /* already taken care of */
708 m
&= ~(PERF_MEM_LVL_HIT
|PERF_MEM_LVL_MISS
);
710 for (i
= 0; m
&& i
< NUM_MEM_LVL
; i
++, m
>>= 1) {
717 strncat(out
, mem_lvl
[i
], sz
- l
);
718 l
+= strlen(mem_lvl
[i
]);
723 strncat(out
, " hit", sz
- l
);
725 strncat(out
, " miss", sz
- l
);
727 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
731 sort__snoop_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
733 union perf_mem_data_src data_src_l
;
734 union perf_mem_data_src data_src_r
;
737 data_src_l
= left
->mem_info
->data_src
;
739 data_src_l
.mem_snoop
= PERF_MEM_SNOOP_NA
;
742 data_src_r
= right
->mem_info
->data_src
;
744 data_src_r
.mem_snoop
= PERF_MEM_SNOOP_NA
;
746 return (int64_t)(data_src_r
.mem_snoop
- data_src_l
.mem_snoop
);
749 static const char * const snoop_access
[] = {
756 #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
758 static int hist_entry__snoop_snprintf(struct hist_entry
*he
, char *bf
,
759 size_t size
, unsigned int width
)
762 size_t sz
= sizeof(out
) - 1; /* -1 for null termination */
764 u64 m
= PERF_MEM_SNOOP_NA
;
769 m
= he
->mem_info
->data_src
.mem_snoop
;
771 for (i
= 0; m
&& i
< NUM_SNOOP_ACCESS
; i
++, m
>>= 1) {
778 strncat(out
, snoop_access
[i
], sz
- l
);
779 l
+= strlen(snoop_access
[i
]);
785 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
788 static inline u64
cl_address(u64 address
)
790 /* return the cacheline of the address */
791 return (address
& ~(cacheline_size
- 1));
795 sort__dcacheline_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
798 struct map
*l_map
, *r_map
;
800 if (!left
->mem_info
) return -1;
801 if (!right
->mem_info
) return 1;
803 /* group event types together */
804 if (left
->cpumode
> right
->cpumode
) return -1;
805 if (left
->cpumode
< right
->cpumode
) return 1;
807 l_map
= left
->mem_info
->daddr
.map
;
808 r_map
= right
->mem_info
->daddr
.map
;
810 /* if both are NULL, jump to sort on al_addr instead */
811 if (!l_map
&& !r_map
)
814 if (!l_map
) return -1;
815 if (!r_map
) return 1;
817 if (l_map
->maj
> r_map
->maj
) return -1;
818 if (l_map
->maj
< r_map
->maj
) return 1;
820 if (l_map
->min
> r_map
->min
) return -1;
821 if (l_map
->min
< r_map
->min
) return 1;
823 if (l_map
->ino
> r_map
->ino
) return -1;
824 if (l_map
->ino
< r_map
->ino
) return 1;
826 if (l_map
->ino_generation
> r_map
->ino_generation
) return -1;
827 if (l_map
->ino_generation
< r_map
->ino_generation
) return 1;
830 * Addresses with no major/minor numbers are assumed to be
831 * anonymous in userspace. Sort those on pid then address.
833 * The kernel and non-zero major/minor mapped areas are
834 * assumed to be unity mapped. Sort those on address.
837 if ((left
->cpumode
!= PERF_RECORD_MISC_KERNEL
) &&
838 (!(l_map
->flags
& MAP_SHARED
)) &&
839 !l_map
->maj
&& !l_map
->min
&& !l_map
->ino
&&
840 !l_map
->ino_generation
) {
841 /* userspace anonymous */
843 if (left
->thread
->pid_
> right
->thread
->pid_
) return -1;
844 if (left
->thread
->pid_
< right
->thread
->pid_
) return 1;
848 /* al_addr does all the right addr - start + offset calculations */
849 l
= cl_address(left
->mem_info
->daddr
.al_addr
);
850 r
= cl_address(right
->mem_info
->daddr
.al_addr
);
852 if (l
> r
) return -1;
858 static int hist_entry__dcacheline_snprintf(struct hist_entry
*he
, char *bf
,
859 size_t size
, unsigned int width
)
863 struct map
*map
= NULL
;
864 struct symbol
*sym
= NULL
;
865 char level
= he
->level
;
868 addr
= cl_address(he
->mem_info
->daddr
.al_addr
);
869 map
= he
->mem_info
->daddr
.map
;
870 sym
= he
->mem_info
->daddr
.sym
;
872 /* print [s] for shared data mmaps */
873 if ((he
->cpumode
!= PERF_RECORD_MISC_KERNEL
) &&
874 map
&& (map
->type
== MAP__VARIABLE
) &&
875 (map
->flags
& MAP_SHARED
) &&
876 (map
->maj
|| map
->min
|| map
->ino
||
877 map
->ino_generation
))
882 return _hist_entry__sym_snprintf(map
, sym
, addr
, level
, bf
, size
,
886 struct sort_entry sort_mispredict
= {
887 .se_header
= "Branch Mispredicted",
888 .se_cmp
= sort__mispredict_cmp
,
889 .se_snprintf
= hist_entry__mispredict_snprintf
,
890 .se_width_idx
= HISTC_MISPREDICT
,
893 static u64
he_weight(struct hist_entry
*he
)
895 return he
->stat
.nr_events
? he
->stat
.weight
/ he
->stat
.nr_events
: 0;
899 sort__local_weight_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
901 return he_weight(left
) - he_weight(right
);
904 static int hist_entry__local_weight_snprintf(struct hist_entry
*he
, char *bf
,
905 size_t size
, unsigned int width
)
907 return repsep_snprintf(bf
, size
, "%-*llu", width
, he_weight(he
));
910 struct sort_entry sort_local_weight
= {
911 .se_header
= "Local Weight",
912 .se_cmp
= sort__local_weight_cmp
,
913 .se_snprintf
= hist_entry__local_weight_snprintf
,
914 .se_width_idx
= HISTC_LOCAL_WEIGHT
,
918 sort__global_weight_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
920 return left
->stat
.weight
- right
->stat
.weight
;
923 static int hist_entry__global_weight_snprintf(struct hist_entry
*he
, char *bf
,
924 size_t size
, unsigned int width
)
926 return repsep_snprintf(bf
, size
, "%-*llu", width
, he
->stat
.weight
);
929 struct sort_entry sort_global_weight
= {
930 .se_header
= "Weight",
931 .se_cmp
= sort__global_weight_cmp
,
932 .se_snprintf
= hist_entry__global_weight_snprintf
,
933 .se_width_idx
= HISTC_GLOBAL_WEIGHT
,
936 struct sort_entry sort_mem_daddr_sym
= {
937 .se_header
= "Data Symbol",
938 .se_cmp
= sort__daddr_cmp
,
939 .se_snprintf
= hist_entry__daddr_snprintf
,
940 .se_width_idx
= HISTC_MEM_DADDR_SYMBOL
,
943 struct sort_entry sort_mem_daddr_dso
= {
944 .se_header
= "Data Object",
945 .se_cmp
= sort__dso_daddr_cmp
,
946 .se_snprintf
= hist_entry__dso_daddr_snprintf
,
947 .se_width_idx
= HISTC_MEM_DADDR_SYMBOL
,
950 struct sort_entry sort_mem_locked
= {
951 .se_header
= "Locked",
952 .se_cmp
= sort__locked_cmp
,
953 .se_snprintf
= hist_entry__locked_snprintf
,
954 .se_width_idx
= HISTC_MEM_LOCKED
,
957 struct sort_entry sort_mem_tlb
= {
958 .se_header
= "TLB access",
959 .se_cmp
= sort__tlb_cmp
,
960 .se_snprintf
= hist_entry__tlb_snprintf
,
961 .se_width_idx
= HISTC_MEM_TLB
,
964 struct sort_entry sort_mem_lvl
= {
965 .se_header
= "Memory access",
966 .se_cmp
= sort__lvl_cmp
,
967 .se_snprintf
= hist_entry__lvl_snprintf
,
968 .se_width_idx
= HISTC_MEM_LVL
,
971 struct sort_entry sort_mem_snoop
= {
972 .se_header
= "Snoop",
973 .se_cmp
= sort__snoop_cmp
,
974 .se_snprintf
= hist_entry__snoop_snprintf
,
975 .se_width_idx
= HISTC_MEM_SNOOP
,
978 struct sort_entry sort_mem_dcacheline
= {
979 .se_header
= "Data Cacheline",
980 .se_cmp
= sort__dcacheline_cmp
,
981 .se_snprintf
= hist_entry__dcacheline_snprintf
,
982 .se_width_idx
= HISTC_MEM_DCACHELINE
,
986 sort__abort_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
988 return left
->branch_info
->flags
.abort
!=
989 right
->branch_info
->flags
.abort
;
992 static int hist_entry__abort_snprintf(struct hist_entry
*he
, char *bf
,
993 size_t size
, unsigned int width
)
995 static const char *out
= ".";
997 if (he
->branch_info
->flags
.abort
)
999 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
1002 struct sort_entry sort_abort
= {
1003 .se_header
= "Transaction abort",
1004 .se_cmp
= sort__abort_cmp
,
1005 .se_snprintf
= hist_entry__abort_snprintf
,
1006 .se_width_idx
= HISTC_ABORT
,
1010 sort__in_tx_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
1012 return left
->branch_info
->flags
.in_tx
!=
1013 right
->branch_info
->flags
.in_tx
;
1016 static int hist_entry__in_tx_snprintf(struct hist_entry
*he
, char *bf
,
1017 size_t size
, unsigned int width
)
1019 static const char *out
= ".";
1021 if (he
->branch_info
->flags
.in_tx
)
1024 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
1027 struct sort_entry sort_in_tx
= {
1028 .se_header
= "Branch in transaction",
1029 .se_cmp
= sort__in_tx_cmp
,
1030 .se_snprintf
= hist_entry__in_tx_snprintf
,
1031 .se_width_idx
= HISTC_IN_TX
,
1035 sort__transaction_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
1037 return left
->transaction
- right
->transaction
;
1040 static inline char *add_str(char *p
, const char *str
)
1043 return p
+ strlen(str
);
1046 static struct txbit
{
1051 { PERF_TXN_ELISION
, "EL ", 0 },
1052 { PERF_TXN_TRANSACTION
, "TX ", 1 },
1053 { PERF_TXN_SYNC
, "SYNC ", 1 },
1054 { PERF_TXN_ASYNC
, "ASYNC ", 0 },
1055 { PERF_TXN_RETRY
, "RETRY ", 0 },
1056 { PERF_TXN_CONFLICT
, "CON ", 0 },
1057 { PERF_TXN_CAPACITY_WRITE
, "CAP-WRITE ", 1 },
1058 { PERF_TXN_CAPACITY_READ
, "CAP-READ ", 0 },
1062 int hist_entry__transaction_len(void)
1067 for (i
= 0; txbits
[i
].name
; i
++) {
1068 if (!txbits
[i
].skip_for_len
)
1069 len
+= strlen(txbits
[i
].name
);
1071 len
+= 4; /* :XX<space> */
1075 static int hist_entry__transaction_snprintf(struct hist_entry
*he
, char *bf
,
1076 size_t size
, unsigned int width
)
1078 u64 t
= he
->transaction
;
1084 for (i
= 0; txbits
[i
].name
; i
++)
1085 if (txbits
[i
].flag
& t
)
1086 p
= add_str(p
, txbits
[i
].name
);
1087 if (t
&& !(t
& (PERF_TXN_SYNC
|PERF_TXN_ASYNC
)))
1088 p
= add_str(p
, "NEITHER ");
1089 if (t
& PERF_TXN_ABORT_MASK
) {
1090 sprintf(p
, ":%" PRIx64
,
1091 (t
& PERF_TXN_ABORT_MASK
) >>
1092 PERF_TXN_ABORT_SHIFT
);
1096 return repsep_snprintf(bf
, size
, "%-*s", width
, buf
);
1099 struct sort_entry sort_transaction
= {
1100 .se_header
= "Transaction ",
1101 .se_cmp
= sort__transaction_cmp
,
1102 .se_snprintf
= hist_entry__transaction_snprintf
,
1103 .se_width_idx
= HISTC_TRANSACTION
,
1106 struct sort_dimension
{
1108 struct sort_entry
*entry
;
1112 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1114 static struct sort_dimension common_sort_dimensions
[] = {
1115 DIM(SORT_PID
, "pid", sort_thread
),
1116 DIM(SORT_COMM
, "comm", sort_comm
),
1117 DIM(SORT_DSO
, "dso", sort_dso
),
1118 DIM(SORT_SYM
, "symbol", sort_sym
),
1119 DIM(SORT_PARENT
, "parent", sort_parent
),
1120 DIM(SORT_CPU
, "cpu", sort_cpu
),
1121 DIM(SORT_SRCLINE
, "srcline", sort_srcline
),
1122 DIM(SORT_LOCAL_WEIGHT
, "local_weight", sort_local_weight
),
1123 DIM(SORT_GLOBAL_WEIGHT
, "weight", sort_global_weight
),
1124 DIM(SORT_TRANSACTION
, "transaction", sort_transaction
),
1129 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1131 static struct sort_dimension bstack_sort_dimensions
[] = {
1132 DIM(SORT_DSO_FROM
, "dso_from", sort_dso_from
),
1133 DIM(SORT_DSO_TO
, "dso_to", sort_dso_to
),
1134 DIM(SORT_SYM_FROM
, "symbol_from", sort_sym_from
),
1135 DIM(SORT_SYM_TO
, "symbol_to", sort_sym_to
),
1136 DIM(SORT_MISPREDICT
, "mispredict", sort_mispredict
),
1137 DIM(SORT_IN_TX
, "in_tx", sort_in_tx
),
1138 DIM(SORT_ABORT
, "abort", sort_abort
),
1143 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1145 static struct sort_dimension memory_sort_dimensions
[] = {
1146 DIM(SORT_MEM_DADDR_SYMBOL
, "symbol_daddr", sort_mem_daddr_sym
),
1147 DIM(SORT_MEM_DADDR_DSO
, "dso_daddr", sort_mem_daddr_dso
),
1148 DIM(SORT_MEM_LOCKED
, "locked", sort_mem_locked
),
1149 DIM(SORT_MEM_TLB
, "tlb", sort_mem_tlb
),
1150 DIM(SORT_MEM_LVL
, "mem", sort_mem_lvl
),
1151 DIM(SORT_MEM_SNOOP
, "snoop", sort_mem_snoop
),
1152 DIM(SORT_MEM_DCACHELINE
, "dcacheline", sort_mem_dcacheline
),
1157 struct hpp_dimension
{
1159 struct perf_hpp_fmt
*fmt
;
1163 #define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1165 static struct hpp_dimension hpp_sort_dimensions
[] = {
1166 DIM(PERF_HPP__OVERHEAD
, "overhead"),
1167 DIM(PERF_HPP__OVERHEAD_SYS
, "overhead_sys"),
1168 DIM(PERF_HPP__OVERHEAD_US
, "overhead_us"),
1169 DIM(PERF_HPP__OVERHEAD_GUEST_SYS
, "overhead_guest_sys"),
1170 DIM(PERF_HPP__OVERHEAD_GUEST_US
, "overhead_guest_us"),
1171 DIM(PERF_HPP__OVERHEAD_ACC
, "overhead_children"),
1172 DIM(PERF_HPP__SAMPLES
, "sample"),
1173 DIM(PERF_HPP__PERIOD
, "period"),
1178 struct hpp_sort_entry
{
1179 struct perf_hpp_fmt hpp
;
1180 struct sort_entry
*se
;
1183 bool perf_hpp__same_sort_entry(struct perf_hpp_fmt
*a
, struct perf_hpp_fmt
*b
)
1185 struct hpp_sort_entry
*hse_a
;
1186 struct hpp_sort_entry
*hse_b
;
1188 if (!perf_hpp__is_sort_entry(a
) || !perf_hpp__is_sort_entry(b
))
1191 hse_a
= container_of(a
, struct hpp_sort_entry
, hpp
);
1192 hse_b
= container_of(b
, struct hpp_sort_entry
, hpp
);
1194 return hse_a
->se
== hse_b
->se
;
1197 void perf_hpp__reset_width(struct perf_hpp_fmt
*fmt
, struct hists
*hists
)
1199 struct hpp_sort_entry
*hse
;
1201 if (!perf_hpp__is_sort_entry(fmt
))
1204 hse
= container_of(fmt
, struct hpp_sort_entry
, hpp
);
1205 hists__new_col_len(hists
, hse
->se
->se_width_idx
,
1206 strlen(hse
->se
->se_header
));
1209 static int __sort__hpp_header(struct perf_hpp_fmt
*fmt
, struct perf_hpp
*hpp
,
1210 struct perf_evsel
*evsel
)
1212 struct hpp_sort_entry
*hse
;
1215 hse
= container_of(fmt
, struct hpp_sort_entry
, hpp
);
1216 len
= hists__col_len(&evsel
->hists
, hse
->se
->se_width_idx
);
1218 return scnprintf(hpp
->buf
, hpp
->size
, "%*s", len
, hse
->se
->se_header
);
1221 static int __sort__hpp_width(struct perf_hpp_fmt
*fmt
,
1222 struct perf_hpp
*hpp __maybe_unused
,
1223 struct perf_evsel
*evsel
)
1225 struct hpp_sort_entry
*hse
;
1227 hse
= container_of(fmt
, struct hpp_sort_entry
, hpp
);
1229 return hists__col_len(&evsel
->hists
, hse
->se
->se_width_idx
);
1232 static int __sort__hpp_entry(struct perf_hpp_fmt
*fmt
, struct perf_hpp
*hpp
,
1233 struct hist_entry
*he
)
1235 struct hpp_sort_entry
*hse
;
1238 hse
= container_of(fmt
, struct hpp_sort_entry
, hpp
);
1239 len
= hists__col_len(he
->hists
, hse
->se
->se_width_idx
);
1241 return hse
->se
->se_snprintf(he
, hpp
->buf
, hpp
->size
, len
);
1244 static struct hpp_sort_entry
*
1245 __sort_dimension__alloc_hpp(struct sort_dimension
*sd
)
1247 struct hpp_sort_entry
*hse
;
1249 hse
= malloc(sizeof(*hse
));
1251 pr_err("Memory allocation failed\n");
1255 hse
->se
= sd
->entry
;
1256 hse
->hpp
.header
= __sort__hpp_header
;
1257 hse
->hpp
.width
= __sort__hpp_width
;
1258 hse
->hpp
.entry
= __sort__hpp_entry
;
1259 hse
->hpp
.color
= NULL
;
1261 hse
->hpp
.cmp
= sd
->entry
->se_cmp
;
1262 hse
->hpp
.collapse
= sd
->entry
->se_collapse
? : sd
->entry
->se_cmp
;
1263 hse
->hpp
.sort
= sd
->entry
->se_sort
? : hse
->hpp
.collapse
;
1265 INIT_LIST_HEAD(&hse
->hpp
.list
);
1266 INIT_LIST_HEAD(&hse
->hpp
.sort_list
);
1267 hse
->hpp
.elide
= false;
1272 bool perf_hpp__is_sort_entry(struct perf_hpp_fmt
*format
)
1274 return format
->header
== __sort__hpp_header
;
1277 static int __sort_dimension__add_hpp_sort(struct sort_dimension
*sd
)
1279 struct hpp_sort_entry
*hse
= __sort_dimension__alloc_hpp(sd
);
1284 perf_hpp__register_sort_field(&hse
->hpp
);
1288 static int __sort_dimension__add_hpp_output(struct sort_dimension
*sd
)
1290 struct hpp_sort_entry
*hse
= __sort_dimension__alloc_hpp(sd
);
1295 perf_hpp__column_register(&hse
->hpp
);
1299 static int __sort_dimension__add(struct sort_dimension
*sd
)
1304 if (__sort_dimension__add_hpp_sort(sd
) < 0)
1307 if (sd
->entry
->se_collapse
)
1308 sort__need_collapse
= 1;
1315 static int __hpp_dimension__add(struct hpp_dimension
*hd
)
1320 perf_hpp__register_sort_field(hd
->fmt
);
1325 static int __sort_dimension__add_output(struct sort_dimension
*sd
)
1330 if (__sort_dimension__add_hpp_output(sd
) < 0)
1337 static int __hpp_dimension__add_output(struct hpp_dimension
*hd
)
1342 perf_hpp__column_register(hd
->fmt
);
1347 int sort_dimension__add(const char *tok
)
1351 for (i
= 0; i
< ARRAY_SIZE(common_sort_dimensions
); i
++) {
1352 struct sort_dimension
*sd
= &common_sort_dimensions
[i
];
1354 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1357 if (sd
->entry
== &sort_parent
) {
1358 int ret
= regcomp(&parent_regex
, parent_pattern
, REG_EXTENDED
);
1362 regerror(ret
, &parent_regex
, err
, sizeof(err
));
1363 pr_err("Invalid regex: %s\n%s", parent_pattern
, err
);
1366 sort__has_parent
= 1;
1367 } else if (sd
->entry
== &sort_sym
) {
1369 } else if (sd
->entry
== &sort_dso
) {
1373 return __sort_dimension__add(sd
);
1376 for (i
= 0; i
< ARRAY_SIZE(hpp_sort_dimensions
); i
++) {
1377 struct hpp_dimension
*hd
= &hpp_sort_dimensions
[i
];
1379 if (strncasecmp(tok
, hd
->name
, strlen(tok
)))
1382 return __hpp_dimension__add(hd
);
1385 for (i
= 0; i
< ARRAY_SIZE(bstack_sort_dimensions
); i
++) {
1386 struct sort_dimension
*sd
= &bstack_sort_dimensions
[i
];
1388 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1391 if (sort__mode
!= SORT_MODE__BRANCH
)
1394 if (sd
->entry
== &sort_sym_from
|| sd
->entry
== &sort_sym_to
)
1397 __sort_dimension__add(sd
);
1401 for (i
= 0; i
< ARRAY_SIZE(memory_sort_dimensions
); i
++) {
1402 struct sort_dimension
*sd
= &memory_sort_dimensions
[i
];
1404 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1407 if (sort__mode
!= SORT_MODE__MEMORY
)
1410 if (sd
->entry
== &sort_mem_daddr_sym
)
1413 __sort_dimension__add(sd
);
1420 static const char *get_default_sort_order(void)
1422 const char *default_sort_orders
[] = {
1424 default_branch_sort_order
,
1425 default_mem_sort_order
,
1426 default_top_sort_order
,
1427 default_diff_sort_order
,
1430 BUG_ON(sort__mode
>= ARRAY_SIZE(default_sort_orders
));
1432 return default_sort_orders
[sort__mode
];
1435 static int __setup_sorting(void)
1437 char *tmp
, *tok
, *str
;
1438 const char *sort_keys
= sort_order
;
1441 if (sort_keys
== NULL
) {
1444 * If user specified field order but no sort order,
1445 * we'll honor it and not add default sort orders.
1450 sort_keys
= get_default_sort_order();
1453 str
= strdup(sort_keys
);
1455 error("Not enough memory to setup sort keys");
1459 for (tok
= strtok_r(str
, ", ", &tmp
);
1460 tok
; tok
= strtok_r(NULL
, ", ", &tmp
)) {
1461 ret
= sort_dimension__add(tok
);
1462 if (ret
== -EINVAL
) {
1463 error("Invalid --sort key: `%s'", tok
);
1465 } else if (ret
== -ESRCH
) {
1466 error("Unknown --sort key: `%s'", tok
);
1475 void perf_hpp__set_elide(int idx
, bool elide
)
1477 struct perf_hpp_fmt
*fmt
;
1478 struct hpp_sort_entry
*hse
;
1480 perf_hpp__for_each_format(fmt
) {
1481 if (!perf_hpp__is_sort_entry(fmt
))
1484 hse
= container_of(fmt
, struct hpp_sort_entry
, hpp
);
1485 if (hse
->se
->se_width_idx
== idx
) {
1492 static bool __get_elide(struct strlist
*list
, const char *list_name
, FILE *fp
)
1494 if (list
&& strlist__nr_entries(list
) == 1) {
1496 fprintf(fp
, "# %s: %s\n", list_name
,
1497 strlist__entry(list
, 0)->s
);
1503 static bool get_elide(int idx
, FILE *output
)
1507 return __get_elide(symbol_conf
.sym_list
, "symbol", output
);
1509 return __get_elide(symbol_conf
.dso_list
, "dso", output
);
1511 return __get_elide(symbol_conf
.comm_list
, "comm", output
);
1516 if (sort__mode
!= SORT_MODE__BRANCH
)
1520 case HISTC_SYMBOL_FROM
:
1521 return __get_elide(symbol_conf
.sym_from_list
, "sym_from", output
);
1522 case HISTC_SYMBOL_TO
:
1523 return __get_elide(symbol_conf
.sym_to_list
, "sym_to", output
);
1524 case HISTC_DSO_FROM
:
1525 return __get_elide(symbol_conf
.dso_from_list
, "dso_from", output
);
1527 return __get_elide(symbol_conf
.dso_to_list
, "dso_to", output
);
1535 void sort__setup_elide(FILE *output
)
1537 struct perf_hpp_fmt
*fmt
;
1538 struct hpp_sort_entry
*hse
;
1540 perf_hpp__for_each_format(fmt
) {
1541 if (!perf_hpp__is_sort_entry(fmt
))
1544 hse
= container_of(fmt
, struct hpp_sort_entry
, hpp
);
1545 fmt
->elide
= get_elide(hse
->se
->se_width_idx
, output
);
1549 * It makes no sense to elide all of sort entries.
1550 * Just revert them to show up again.
1552 perf_hpp__for_each_format(fmt
) {
1553 if (!perf_hpp__is_sort_entry(fmt
))
1560 perf_hpp__for_each_format(fmt
) {
1561 if (!perf_hpp__is_sort_entry(fmt
))
1568 static int output_field_add(char *tok
)
1572 for (i
= 0; i
< ARRAY_SIZE(common_sort_dimensions
); i
++) {
1573 struct sort_dimension
*sd
= &common_sort_dimensions
[i
];
1575 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1578 return __sort_dimension__add_output(sd
);
1581 for (i
= 0; i
< ARRAY_SIZE(hpp_sort_dimensions
); i
++) {
1582 struct hpp_dimension
*hd
= &hpp_sort_dimensions
[i
];
1584 if (strncasecmp(tok
, hd
->name
, strlen(tok
)))
1587 return __hpp_dimension__add_output(hd
);
1590 for (i
= 0; i
< ARRAY_SIZE(bstack_sort_dimensions
); i
++) {
1591 struct sort_dimension
*sd
= &bstack_sort_dimensions
[i
];
1593 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1596 return __sort_dimension__add_output(sd
);
1599 for (i
= 0; i
< ARRAY_SIZE(memory_sort_dimensions
); i
++) {
1600 struct sort_dimension
*sd
= &memory_sort_dimensions
[i
];
1602 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
1605 return __sort_dimension__add_output(sd
);
1611 static void reset_dimensions(void)
1615 for (i
= 0; i
< ARRAY_SIZE(common_sort_dimensions
); i
++)
1616 common_sort_dimensions
[i
].taken
= 0;
1618 for (i
= 0; i
< ARRAY_SIZE(hpp_sort_dimensions
); i
++)
1619 hpp_sort_dimensions
[i
].taken
= 0;
1621 for (i
= 0; i
< ARRAY_SIZE(bstack_sort_dimensions
); i
++)
1622 bstack_sort_dimensions
[i
].taken
= 0;
1624 for (i
= 0; i
< ARRAY_SIZE(memory_sort_dimensions
); i
++)
1625 memory_sort_dimensions
[i
].taken
= 0;
1628 static int __setup_output_field(void)
1630 char *tmp
, *tok
, *str
;
1633 if (field_order
== NULL
)
1638 str
= strdup(field_order
);
1640 error("Not enough memory to setup output fields");
1644 for (tok
= strtok_r(str
, ", ", &tmp
);
1645 tok
; tok
= strtok_r(NULL
, ", ", &tmp
)) {
1646 ret
= output_field_add(tok
);
1647 if (ret
== -EINVAL
) {
1648 error("Invalid --fields key: `%s'", tok
);
1650 } else if (ret
== -ESRCH
) {
1651 error("Unknown --fields key: `%s'", tok
);
1660 int setup_sorting(void)
1664 err
= __setup_sorting();
1668 if (parent_pattern
!= default_parent_pattern
) {
1669 err
= sort_dimension__add("parent");
1677 * perf diff doesn't use default hpp output fields.
1679 if (sort__mode
!= SORT_MODE__DIFF
)
1682 err
= __setup_output_field();
1686 /* copy sort keys to output fields */
1687 perf_hpp__setup_output_field();
1688 /* and then copy output fields to sort keys */
1689 perf_hpp__append_sort_keys();
1694 void reset_output_field(void)
1696 sort__need_collapse
= 0;
1697 sort__has_parent
= 0;
1705 perf_hpp__reset_output_field();