5 const char default_parent_pattern
[] = "^sys_|^do_page_fault";
6 const char *parent_pattern
= default_parent_pattern
;
7 const char default_sort_order
[] = "comm,dso,symbol";
8 const char *sort_order
= default_sort_order
;
9 int sort__need_collapse
= 0;
10 int sort__has_parent
= 0;
11 int sort__has_sym
= 0;
12 int sort__branch_mode
= -1; /* -1 = means not set */
14 enum sort_type sort__first_dimension
;
16 LIST_HEAD(hist_entry__sort_list
);
18 static int repsep_snprintf(char *bf
, size_t size
, const char *fmt
, ...)
24 n
= vsnprintf(bf
, size
, fmt
, ap
);
25 if (symbol_conf
.field_sep
&& n
> 0) {
29 sep
= strchr(sep
, *symbol_conf
.field_sep
);
42 static int64_t cmp_null(void *l
, void *r
)
55 sort__thread_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
57 return right
->thread
->pid
- left
->thread
->pid
;
60 static int hist_entry__thread_snprintf(struct hist_entry
*self
, char *bf
,
61 size_t size
, unsigned int width
)
63 return repsep_snprintf(bf
, size
, "%*s:%5d", width
- 6,
64 self
->thread
->comm
?: "", self
->thread
->pid
);
67 struct sort_entry sort_thread
= {
68 .se_header
= "Command: Pid",
69 .se_cmp
= sort__thread_cmp
,
70 .se_snprintf
= hist_entry__thread_snprintf
,
71 .se_width_idx
= HISTC_THREAD
,
77 sort__comm_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
79 return right
->thread
->pid
- left
->thread
->pid
;
83 sort__comm_collapse(struct hist_entry
*left
, struct hist_entry
*right
)
85 char *comm_l
= left
->thread
->comm
;
86 char *comm_r
= right
->thread
->comm
;
88 if (!comm_l
|| !comm_r
)
89 return cmp_null(comm_l
, comm_r
);
91 return strcmp(comm_l
, comm_r
);
94 static int hist_entry__comm_snprintf(struct hist_entry
*self
, char *bf
,
95 size_t size
, unsigned int width
)
97 return repsep_snprintf(bf
, size
, "%*s", width
, self
->thread
->comm
);
100 struct sort_entry sort_comm
= {
101 .se_header
= "Command",
102 .se_cmp
= sort__comm_cmp
,
103 .se_collapse
= sort__comm_collapse
,
104 .se_snprintf
= hist_entry__comm_snprintf
,
105 .se_width_idx
= HISTC_COMM
,
110 static int64_t _sort__dso_cmp(struct map
*map_l
, struct map
*map_r
)
112 struct dso
*dso_l
= map_l
? map_l
->dso
: NULL
;
113 struct dso
*dso_r
= map_r
? map_r
->dso
: NULL
;
114 const char *dso_name_l
, *dso_name_r
;
116 if (!dso_l
|| !dso_r
)
117 return cmp_null(dso_l
, dso_r
);
120 dso_name_l
= dso_l
->long_name
;
121 dso_name_r
= dso_r
->long_name
;
123 dso_name_l
= dso_l
->short_name
;
124 dso_name_r
= dso_r
->short_name
;
127 return strcmp(dso_name_l
, dso_name_r
);
131 sort__dso_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
133 return _sort__dso_cmp(left
->ms
.map
, right
->ms
.map
);
136 static int _hist_entry__dso_snprintf(struct map
*map
, char *bf
,
137 size_t size
, unsigned int width
)
139 if (map
&& map
->dso
) {
140 const char *dso_name
= !verbose
? map
->dso
->short_name
:
142 return repsep_snprintf(bf
, size
, "%-*s", width
, dso_name
);
145 return repsep_snprintf(bf
, size
, "%-*s", width
, "[unknown]");
148 static int hist_entry__dso_snprintf(struct hist_entry
*self
, char *bf
,
149 size_t size
, unsigned int width
)
151 return _hist_entry__dso_snprintf(self
->ms
.map
, bf
, size
, width
);
154 struct sort_entry sort_dso
= {
155 .se_header
= "Shared Object",
156 .se_cmp
= sort__dso_cmp
,
157 .se_snprintf
= hist_entry__dso_snprintf
,
158 .se_width_idx
= HISTC_DSO
,
163 static int64_t _sort__sym_cmp(struct symbol
*sym_l
, struct symbol
*sym_r
)
167 if (!sym_l
|| !sym_r
)
168 return cmp_null(sym_l
, sym_r
);
176 return (int64_t)(ip_r
- ip_l
);
180 sort__sym_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
182 if (!left
->ms
.sym
&& !right
->ms
.sym
)
183 return right
->level
- left
->level
;
185 return _sort__sym_cmp(left
->ms
.sym
, right
->ms
.sym
);
188 static int _hist_entry__sym_snprintf(struct map
*map
, struct symbol
*sym
,
189 u64 ip
, char level
, char *bf
, size_t size
,
195 char o
= map
? dso__symtab_origin(map
->dso
) : '!';
196 ret
+= repsep_snprintf(bf
, size
, "%-#*llx %c ",
197 BITS_PER_LONG
/ 4, ip
, o
);
200 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "[%c] ", level
);
202 if (map
->type
== MAP__VARIABLE
) {
203 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%s", sym
->name
);
204 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "+0x%llx",
206 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-*s",
209 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-*s",
214 size_t len
= BITS_PER_LONG
/ 4;
215 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-#.*llx",
217 ret
+= repsep_snprintf(bf
+ ret
, size
- ret
, "%-*s",
224 static int hist_entry__sym_snprintf(struct hist_entry
*self
, char *bf
,
225 size_t size
, unsigned int width
)
227 return _hist_entry__sym_snprintf(self
->ms
.map
, self
->ms
.sym
, self
->ip
,
228 self
->level
, bf
, size
, width
);
231 struct sort_entry sort_sym
= {
232 .se_header
= "Symbol",
233 .se_cmp
= sort__sym_cmp
,
234 .se_snprintf
= hist_entry__sym_snprintf
,
235 .se_width_idx
= HISTC_SYMBOL
,
241 sort__srcline_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
243 return (int64_t)(right
->ip
- left
->ip
);
246 static int hist_entry__srcline_snprintf(struct hist_entry
*self
, char *bf
,
248 unsigned int width __maybe_unused
)
251 char cmd
[PATH_MAX
+ 2], *path
= self
->srcline
, *nl
;
260 if (!strncmp(self
->ms
.map
->dso
->long_name
, "/tmp/perf-", 10))
263 snprintf(cmd
, sizeof(cmd
), "addr2line -e %s %016" PRIx64
,
264 self
->ms
.map
->dso
->long_name
, self
->ip
);
265 fp
= popen(cmd
, "r");
269 if (getline(&path
, &line_len
, fp
) < 0 || !line_len
)
271 self
->srcline
= strdup(path
);
272 if (self
->srcline
== NULL
)
275 nl
= strchr(self
->srcline
, '\n');
278 path
= self
->srcline
;
282 return repsep_snprintf(bf
, size
, "%s", path
);
286 return repsep_snprintf(bf
, size
, "%-#*llx", BITS_PER_LONG
/ 4, self
->ip
);
289 struct sort_entry sort_srcline
= {
290 .se_header
= "Source:Line",
291 .se_cmp
= sort__srcline_cmp
,
292 .se_snprintf
= hist_entry__srcline_snprintf
,
293 .se_width_idx
= HISTC_SRCLINE
,
299 sort__parent_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
301 struct symbol
*sym_l
= left
->parent
;
302 struct symbol
*sym_r
= right
->parent
;
304 if (!sym_l
|| !sym_r
)
305 return cmp_null(sym_l
, sym_r
);
307 return strcmp(sym_l
->name
, sym_r
->name
);
310 static int hist_entry__parent_snprintf(struct hist_entry
*self
, char *bf
,
311 size_t size
, unsigned int width
)
313 return repsep_snprintf(bf
, size
, "%-*s", width
,
314 self
->parent
? self
->parent
->name
: "[other]");
317 struct sort_entry sort_parent
= {
318 .se_header
= "Parent symbol",
319 .se_cmp
= sort__parent_cmp
,
320 .se_snprintf
= hist_entry__parent_snprintf
,
321 .se_width_idx
= HISTC_PARENT
,
327 sort__cpu_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
329 return right
->cpu
- left
->cpu
;
332 static int hist_entry__cpu_snprintf(struct hist_entry
*self
, char *bf
,
333 size_t size
, unsigned int width
)
335 return repsep_snprintf(bf
, size
, "%*d", width
, self
->cpu
);
338 struct sort_entry sort_cpu
= {
340 .se_cmp
= sort__cpu_cmp
,
341 .se_snprintf
= hist_entry__cpu_snprintf
,
342 .se_width_idx
= HISTC_CPU
,
345 /* sort keys for branch stacks */
348 sort__dso_from_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
350 return _sort__dso_cmp(left
->branch_info
->from
.map
,
351 right
->branch_info
->from
.map
);
354 static int hist_entry__dso_from_snprintf(struct hist_entry
*self
, char *bf
,
355 size_t size
, unsigned int width
)
357 return _hist_entry__dso_snprintf(self
->branch_info
->from
.map
,
362 sort__dso_to_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
364 return _sort__dso_cmp(left
->branch_info
->to
.map
,
365 right
->branch_info
->to
.map
);
368 static int hist_entry__dso_to_snprintf(struct hist_entry
*self
, char *bf
,
369 size_t size
, unsigned int width
)
371 return _hist_entry__dso_snprintf(self
->branch_info
->to
.map
,
376 sort__sym_from_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
378 struct addr_map_symbol
*from_l
= &left
->branch_info
->from
;
379 struct addr_map_symbol
*from_r
= &right
->branch_info
->from
;
381 if (!from_l
->sym
&& !from_r
->sym
)
382 return right
->level
- left
->level
;
384 return _sort__sym_cmp(from_l
->sym
, from_r
->sym
);
388 sort__sym_to_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
390 struct addr_map_symbol
*to_l
= &left
->branch_info
->to
;
391 struct addr_map_symbol
*to_r
= &right
->branch_info
->to
;
393 if (!to_l
->sym
&& !to_r
->sym
)
394 return right
->level
- left
->level
;
396 return _sort__sym_cmp(to_l
->sym
, to_r
->sym
);
399 static int hist_entry__sym_from_snprintf(struct hist_entry
*self
, char *bf
,
400 size_t size
, unsigned int width
)
402 struct addr_map_symbol
*from
= &self
->branch_info
->from
;
403 return _hist_entry__sym_snprintf(from
->map
, from
->sym
, from
->addr
,
404 self
->level
, bf
, size
, width
);
408 static int hist_entry__sym_to_snprintf(struct hist_entry
*self
, char *bf
,
409 size_t size
, unsigned int width
)
411 struct addr_map_symbol
*to
= &self
->branch_info
->to
;
412 return _hist_entry__sym_snprintf(to
->map
, to
->sym
, to
->addr
,
413 self
->level
, bf
, size
, width
);
417 struct sort_entry sort_dso_from
= {
418 .se_header
= "Source Shared Object",
419 .se_cmp
= sort__dso_from_cmp
,
420 .se_snprintf
= hist_entry__dso_from_snprintf
,
421 .se_width_idx
= HISTC_DSO_FROM
,
424 struct sort_entry sort_dso_to
= {
425 .se_header
= "Target Shared Object",
426 .se_cmp
= sort__dso_to_cmp
,
427 .se_snprintf
= hist_entry__dso_to_snprintf
,
428 .se_width_idx
= HISTC_DSO_TO
,
431 struct sort_entry sort_sym_from
= {
432 .se_header
= "Source Symbol",
433 .se_cmp
= sort__sym_from_cmp
,
434 .se_snprintf
= hist_entry__sym_from_snprintf
,
435 .se_width_idx
= HISTC_SYMBOL_FROM
,
438 struct sort_entry sort_sym_to
= {
439 .se_header
= "Target Symbol",
440 .se_cmp
= sort__sym_to_cmp
,
441 .se_snprintf
= hist_entry__sym_to_snprintf
,
442 .se_width_idx
= HISTC_SYMBOL_TO
,
446 sort__mispredict_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
448 const unsigned char mp
= left
->branch_info
->flags
.mispred
!=
449 right
->branch_info
->flags
.mispred
;
450 const unsigned char p
= left
->branch_info
->flags
.predicted
!=
451 right
->branch_info
->flags
.predicted
;
456 static int hist_entry__mispredict_snprintf(struct hist_entry
*self
, char *bf
,
457 size_t size
, unsigned int width
){
458 static const char *out
= "N/A";
460 if (self
->branch_info
->flags
.predicted
)
462 else if (self
->branch_info
->flags
.mispred
)
465 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
468 /* --sort daddr_sym */
470 sort__daddr_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
472 uint64_t l
= 0, r
= 0;
475 l
= left
->mem_info
->daddr
.addr
;
477 r
= right
->mem_info
->daddr
.addr
;
479 return (int64_t)(r
- l
);
482 static int hist_entry__daddr_snprintf(struct hist_entry
*self
, char *bf
,
483 size_t size
, unsigned int width
)
486 struct map
*map
= NULL
;
487 struct symbol
*sym
= NULL
;
489 if (self
->mem_info
) {
490 addr
= self
->mem_info
->daddr
.addr
;
491 map
= self
->mem_info
->daddr
.map
;
492 sym
= self
->mem_info
->daddr
.sym
;
494 return _hist_entry__sym_snprintf(map
, sym
, addr
, self
->level
, bf
, size
,
499 sort__dso_daddr_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
501 struct map
*map_l
= NULL
;
502 struct map
*map_r
= NULL
;
505 map_l
= left
->mem_info
->daddr
.map
;
507 map_r
= right
->mem_info
->daddr
.map
;
509 return _sort__dso_cmp(map_l
, map_r
);
512 static int hist_entry__dso_daddr_snprintf(struct hist_entry
*self
, char *bf
,
513 size_t size
, unsigned int width
)
515 struct map
*map
= NULL
;
518 map
= self
->mem_info
->daddr
.map
;
520 return _hist_entry__dso_snprintf(map
, bf
, size
, width
);
524 sort__locked_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
526 union perf_mem_data_src data_src_l
;
527 union perf_mem_data_src data_src_r
;
530 data_src_l
= left
->mem_info
->data_src
;
532 data_src_l
.mem_lock
= PERF_MEM_LOCK_NA
;
535 data_src_r
= right
->mem_info
->data_src
;
537 data_src_r
.mem_lock
= PERF_MEM_LOCK_NA
;
539 return (int64_t)(data_src_r
.mem_lock
- data_src_l
.mem_lock
);
542 static int hist_entry__locked_snprintf(struct hist_entry
*self
, char *bf
,
543 size_t size
, unsigned int width
)
546 u64 mask
= PERF_MEM_LOCK_NA
;
549 mask
= self
->mem_info
->data_src
.mem_lock
;
551 if (mask
& PERF_MEM_LOCK_NA
)
553 else if (mask
& PERF_MEM_LOCK_LOCKED
)
558 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
562 sort__tlb_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
564 union perf_mem_data_src data_src_l
;
565 union perf_mem_data_src data_src_r
;
568 data_src_l
= left
->mem_info
->data_src
;
570 data_src_l
.mem_dtlb
= PERF_MEM_TLB_NA
;
573 data_src_r
= right
->mem_info
->data_src
;
575 data_src_r
.mem_dtlb
= PERF_MEM_TLB_NA
;
577 return (int64_t)(data_src_r
.mem_dtlb
- data_src_l
.mem_dtlb
);
580 static const char * const tlb_access
[] = {
589 #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
591 static int hist_entry__tlb_snprintf(struct hist_entry
*self
, char *bf
,
592 size_t size
, unsigned int width
)
595 size_t sz
= sizeof(out
) - 1; /* -1 for null termination */
597 u64 m
= PERF_MEM_TLB_NA
;
603 m
= self
->mem_info
->data_src
.mem_dtlb
;
605 hit
= m
& PERF_MEM_TLB_HIT
;
606 miss
= m
& PERF_MEM_TLB_MISS
;
608 /* already taken care of */
609 m
&= ~(PERF_MEM_TLB_HIT
|PERF_MEM_TLB_MISS
);
611 for (i
= 0; m
&& i
< NUM_TLB_ACCESS
; i
++, m
>>= 1) {
618 strncat(out
, tlb_access
[i
], sz
- l
);
619 l
+= strlen(tlb_access
[i
]);
624 strncat(out
, " hit", sz
- l
);
626 strncat(out
, " miss", sz
- l
);
628 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
632 sort__lvl_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
634 union perf_mem_data_src data_src_l
;
635 union perf_mem_data_src data_src_r
;
638 data_src_l
= left
->mem_info
->data_src
;
640 data_src_l
.mem_lvl
= PERF_MEM_LVL_NA
;
643 data_src_r
= right
->mem_info
->data_src
;
645 data_src_r
.mem_lvl
= PERF_MEM_LVL_NA
;
647 return (int64_t)(data_src_r
.mem_lvl
- data_src_l
.mem_lvl
);
650 static const char * const mem_lvl
[] = {
659 "Remote RAM (1 hop)",
660 "Remote RAM (2 hops)",
661 "Remote Cache (1 hop)",
662 "Remote Cache (2 hops)",
666 #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
668 static int hist_entry__lvl_snprintf(struct hist_entry
*self
, char *bf
,
669 size_t size
, unsigned int width
)
672 size_t sz
= sizeof(out
) - 1; /* -1 for null termination */
674 u64 m
= PERF_MEM_LVL_NA
;
678 m
= self
->mem_info
->data_src
.mem_lvl
;
682 hit
= m
& PERF_MEM_LVL_HIT
;
683 miss
= m
& PERF_MEM_LVL_MISS
;
685 /* already taken care of */
686 m
&= ~(PERF_MEM_LVL_HIT
|PERF_MEM_LVL_MISS
);
688 for (i
= 0; m
&& i
< NUM_MEM_LVL
; i
++, m
>>= 1) {
695 strncat(out
, mem_lvl
[i
], sz
- l
);
696 l
+= strlen(mem_lvl
[i
]);
701 strncat(out
, " hit", sz
- l
);
703 strncat(out
, " miss", sz
- l
);
705 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
709 sort__snoop_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
711 union perf_mem_data_src data_src_l
;
712 union perf_mem_data_src data_src_r
;
715 data_src_l
= left
->mem_info
->data_src
;
717 data_src_l
.mem_snoop
= PERF_MEM_SNOOP_NA
;
720 data_src_r
= right
->mem_info
->data_src
;
722 data_src_r
.mem_snoop
= PERF_MEM_SNOOP_NA
;
724 return (int64_t)(data_src_r
.mem_snoop
- data_src_l
.mem_snoop
);
727 static const char * const snoop_access
[] = {
734 #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
736 static int hist_entry__snoop_snprintf(struct hist_entry
*self
, char *bf
,
737 size_t size
, unsigned int width
)
740 size_t sz
= sizeof(out
) - 1; /* -1 for null termination */
742 u64 m
= PERF_MEM_SNOOP_NA
;
747 m
= self
->mem_info
->data_src
.mem_snoop
;
749 for (i
= 0; m
&& i
< NUM_SNOOP_ACCESS
; i
++, m
>>= 1) {
756 strncat(out
, snoop_access
[i
], sz
- l
);
757 l
+= strlen(snoop_access
[i
]);
763 return repsep_snprintf(bf
, size
, "%-*s", width
, out
);
766 struct sort_entry sort_mispredict
= {
767 .se_header
= "Branch Mispredicted",
768 .se_cmp
= sort__mispredict_cmp
,
769 .se_snprintf
= hist_entry__mispredict_snprintf
,
770 .se_width_idx
= HISTC_MISPREDICT
,
773 static u64
he_weight(struct hist_entry
*he
)
775 return he
->stat
.nr_events
? he
->stat
.weight
/ he
->stat
.nr_events
: 0;
779 sort__local_weight_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
781 return he_weight(left
) - he_weight(right
);
784 static int hist_entry__local_weight_snprintf(struct hist_entry
*self
, char *bf
,
785 size_t size
, unsigned int width
)
787 return repsep_snprintf(bf
, size
, "%-*llu", width
, he_weight(self
));
790 struct sort_entry sort_local_weight
= {
791 .se_header
= "Local Weight",
792 .se_cmp
= sort__local_weight_cmp
,
793 .se_snprintf
= hist_entry__local_weight_snprintf
,
794 .se_width_idx
= HISTC_LOCAL_WEIGHT
,
798 sort__global_weight_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
800 return left
->stat
.weight
- right
->stat
.weight
;
803 static int hist_entry__global_weight_snprintf(struct hist_entry
*self
, char *bf
,
804 size_t size
, unsigned int width
)
806 return repsep_snprintf(bf
, size
, "%-*llu", width
, self
->stat
.weight
);
809 struct sort_entry sort_global_weight
= {
810 .se_header
= "Weight",
811 .se_cmp
= sort__global_weight_cmp
,
812 .se_snprintf
= hist_entry__global_weight_snprintf
,
813 .se_width_idx
= HISTC_GLOBAL_WEIGHT
,
816 struct sort_entry sort_mem_daddr_sym
= {
817 .se_header
= "Data Symbol",
818 .se_cmp
= sort__daddr_cmp
,
819 .se_snprintf
= hist_entry__daddr_snprintf
,
820 .se_width_idx
= HISTC_MEM_DADDR_SYMBOL
,
823 struct sort_entry sort_mem_daddr_dso
= {
824 .se_header
= "Data Object",
825 .se_cmp
= sort__dso_daddr_cmp
,
826 .se_snprintf
= hist_entry__dso_daddr_snprintf
,
827 .se_width_idx
= HISTC_MEM_DADDR_SYMBOL
,
830 struct sort_entry sort_mem_locked
= {
831 .se_header
= "Locked",
832 .se_cmp
= sort__locked_cmp
,
833 .se_snprintf
= hist_entry__locked_snprintf
,
834 .se_width_idx
= HISTC_MEM_LOCKED
,
837 struct sort_entry sort_mem_tlb
= {
838 .se_header
= "TLB access",
839 .se_cmp
= sort__tlb_cmp
,
840 .se_snprintf
= hist_entry__tlb_snprintf
,
841 .se_width_idx
= HISTC_MEM_TLB
,
844 struct sort_entry sort_mem_lvl
= {
845 .se_header
= "Memory access",
846 .se_cmp
= sort__lvl_cmp
,
847 .se_snprintf
= hist_entry__lvl_snprintf
,
848 .se_width_idx
= HISTC_MEM_LVL
,
851 struct sort_entry sort_mem_snoop
= {
852 .se_header
= "Snoop",
853 .se_cmp
= sort__snoop_cmp
,
854 .se_snprintf
= hist_entry__snoop_snprintf
,
855 .se_width_idx
= HISTC_MEM_SNOOP
,
858 struct sort_dimension
{
860 struct sort_entry
*entry
;
864 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
866 static struct sort_dimension common_sort_dimensions
[] = {
867 DIM(SORT_PID
, "pid", sort_thread
),
868 DIM(SORT_COMM
, "comm", sort_comm
),
869 DIM(SORT_DSO
, "dso", sort_dso
),
870 DIM(SORT_SYM
, "symbol", sort_sym
),
871 DIM(SORT_PARENT
, "parent", sort_parent
),
872 DIM(SORT_CPU
, "cpu", sort_cpu
),
873 DIM(SORT_SRCLINE
, "srcline", sort_srcline
),
874 DIM(SORT_LOCAL_WEIGHT
, "local_weight", sort_local_weight
),
875 DIM(SORT_GLOBAL_WEIGHT
, "weight", sort_global_weight
),
876 DIM(SORT_MEM_DADDR_SYMBOL
, "symbol_daddr", sort_mem_daddr_sym
),
877 DIM(SORT_MEM_DADDR_DSO
, "dso_daddr", sort_mem_daddr_dso
),
878 DIM(SORT_MEM_LOCKED
, "locked", sort_mem_locked
),
879 DIM(SORT_MEM_TLB
, "tlb", sort_mem_tlb
),
880 DIM(SORT_MEM_LVL
, "mem", sort_mem_lvl
),
881 DIM(SORT_MEM_SNOOP
, "snoop", sort_mem_snoop
),
886 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
888 static struct sort_dimension bstack_sort_dimensions
[] = {
889 DIM(SORT_DSO_FROM
, "dso_from", sort_dso_from
),
890 DIM(SORT_DSO_TO
, "dso_to", sort_dso_to
),
891 DIM(SORT_SYM_FROM
, "symbol_from", sort_sym_from
),
892 DIM(SORT_SYM_TO
, "symbol_to", sort_sym_to
),
893 DIM(SORT_MISPREDICT
, "mispredict", sort_mispredict
),
898 int sort_dimension__add(const char *tok
)
902 for (i
= 0; i
< ARRAY_SIZE(common_sort_dimensions
); i
++) {
903 struct sort_dimension
*sd
= &common_sort_dimensions
[i
];
905 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
908 if (sd
->entry
== &sort_parent
) {
909 int ret
= regcomp(&parent_regex
, parent_pattern
, REG_EXTENDED
);
913 regerror(ret
, &parent_regex
, err
, sizeof(err
));
914 pr_err("Invalid regex: %s\n%s", parent_pattern
, err
);
917 sort__has_parent
= 1;
918 } else if (sd
->entry
== &sort_sym
||
919 sd
->entry
== &sort_sym_from
||
920 sd
->entry
== &sort_sym_to
||
921 sd
->entry
== &sort_mem_daddr_sym
) {
928 if (sd
->entry
->se_collapse
)
929 sort__need_collapse
= 1;
931 if (list_empty(&hist_entry__sort_list
))
932 sort__first_dimension
= i
;
934 list_add_tail(&sd
->entry
->list
, &hist_entry__sort_list
);
940 for (i
= 0; i
< ARRAY_SIZE(bstack_sort_dimensions
); i
++) {
941 struct sort_dimension
*sd
= &bstack_sort_dimensions
[i
];
943 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
946 if (sort__branch_mode
!= 1)
949 if (sd
->entry
== &sort_sym_from
|| sd
->entry
== &sort_sym_to
)
955 if (sd
->entry
->se_collapse
)
956 sort__need_collapse
= 1;
958 if (list_empty(&hist_entry__sort_list
))
959 sort__first_dimension
= i
+ __SORT_BRANCH_STACK
;
961 list_add_tail(&sd
->entry
->list
, &hist_entry__sort_list
);
970 int setup_sorting(void)
972 char *tmp
, *tok
, *str
= strdup(sort_order
);
976 error("Not enough memory to setup sort keys");
980 for (tok
= strtok_r(str
, ", ", &tmp
);
981 tok
; tok
= strtok_r(NULL
, ", ", &tmp
)) {
982 ret
= sort_dimension__add(tok
);
983 if (ret
== -EINVAL
) {
984 error("Invalid --sort key: `%s'", tok
);
986 } else if (ret
== -ESRCH
) {
987 error("Unknown --sort key: `%s'", tok
);
996 void sort_entry__setup_elide(struct sort_entry
*self
, struct strlist
*list
,
997 const char *list_name
, FILE *fp
)
999 if (list
&& strlist__nr_entries(list
) == 1) {
1001 fprintf(fp
, "# %s: %s\n", list_name
,
1002 strlist__entry(list
, 0)->s
);