4 * Builtin report command: Analyze the perf.data input file,
5 * look up and read DSOs and symbol information and display
6 * a histogram of results, along various sorting keys.
10 #include "util/util.h"
12 #include "util/color.h"
13 #include <linux/list.h>
14 #include "util/cache.h"
15 #include <linux/rbtree.h>
16 #include "util/symbol.h"
17 #include "util/string.h"
18 #include "util/callchain.h"
19 #include "util/strlist.h"
20 #include "util/values.h"
23 #include "util/debug.h"
24 #include "util/header.h"
26 #include "util/parse-options.h"
27 #include "util/parse-events.h"
29 #include "util/thread.h"
31 static char const *input_name
= "perf.data";
33 static char default_sort_order
[] = "comm,dso,symbol";
34 static char *sort_order
= default_sort_order
;
35 static char *dso_list_str
, *comm_list_str
, *sym_list_str
,
37 static struct strlist
*dso_list
, *comm_list
, *sym_list
;
38 static char *field_sep
;
42 static int show_mask
= SHOW_KERNEL
| SHOW_USER
| SHOW_HV
;
44 static int full_paths
;
45 static int show_nr_samples
;
47 static int show_threads
;
48 static struct perf_read_values show_threads_values
;
50 static char default_pretty_printing_style
[] = "normal";
51 static char *pretty_printing_style
= default_pretty_printing_style
;
53 static unsigned long page_size
;
54 static unsigned long mmap_window
= 32;
56 static char default_parent_pattern
[] = "^sys_|^do_page_fault";
57 static char *parent_pattern
= default_parent_pattern
;
58 static regex_t parent_regex
;
60 static int exclude_other
= 1;
62 static char callchain_default_opt
[] = "fractal,0.5";
66 static char __cwd
[PATH_MAX
];
67 static char *cwd
= __cwd
;
70 static struct rb_root threads
;
71 static struct thread
*last_match
;
73 static struct perf_header
*header
;
76 struct callchain_param callchain_param
= {
77 .mode
= CHAIN_GRAPH_REL
,
81 static u64 sample_type
;
83 static int repsep_fprintf(FILE *fp
, const char *fmt
, ...)
90 n
= vfprintf(fp
, fmt
, ap
);
93 n
= vasprintf(&bf
, fmt
, ap
);
98 sep
= strchr(sep
, *field_sep
);
111 static unsigned int dsos__col_width
,
116 * histogram, sorted on item, collects counts
119 static struct rb_root hist
;
122 struct rb_node rb_node
;
124 struct thread
*thread
;
128 struct symbol
*parent
;
131 struct callchain_node callchain
;
132 struct rb_root sorted_chain
;
138 * configurable sorting bits
142 struct list_head list
;
146 int64_t (*cmp
)(struct hist_entry
*, struct hist_entry
*);
147 int64_t (*collapse
)(struct hist_entry
*, struct hist_entry
*);
148 size_t (*print
)(FILE *fp
, struct hist_entry
*, unsigned int width
);
153 static int64_t cmp_null(void *l
, void *r
)
166 sort__thread_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
168 return right
->thread
->pid
- left
->thread
->pid
;
172 sort__thread_print(FILE *fp
, struct hist_entry
*self
, unsigned int width
)
174 return repsep_fprintf(fp
, "%*s:%5d", width
- 6,
175 self
->thread
->comm
?: "", self
->thread
->pid
);
178 static struct sort_entry sort_thread
= {
179 .header
= "Command: Pid",
180 .cmp
= sort__thread_cmp
,
181 .print
= sort__thread_print
,
182 .width
= &threads__col_width
,
188 sort__comm_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
190 return right
->thread
->pid
- left
->thread
->pid
;
194 sort__comm_collapse(struct hist_entry
*left
, struct hist_entry
*right
)
196 char *comm_l
= left
->thread
->comm
;
197 char *comm_r
= right
->thread
->comm
;
199 if (!comm_l
|| !comm_r
)
200 return cmp_null(comm_l
, comm_r
);
202 return strcmp(comm_l
, comm_r
);
206 sort__comm_print(FILE *fp
, struct hist_entry
*self
, unsigned int width
)
208 return repsep_fprintf(fp
, "%*s", width
, self
->thread
->comm
);
211 static struct sort_entry sort_comm
= {
213 .cmp
= sort__comm_cmp
,
214 .collapse
= sort__comm_collapse
,
215 .print
= sort__comm_print
,
216 .width
= &comms__col_width
,
222 sort__dso_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
224 struct dso
*dso_l
= left
->dso
;
225 struct dso
*dso_r
= right
->dso
;
227 if (!dso_l
|| !dso_r
)
228 return cmp_null(dso_l
, dso_r
);
230 return strcmp(dso_l
->name
, dso_r
->name
);
234 sort__dso_print(FILE *fp
, struct hist_entry
*self
, unsigned int width
)
237 return repsep_fprintf(fp
, "%-*s", width
, self
->dso
->name
);
239 return repsep_fprintf(fp
, "%*llx", width
, (u64
)self
->ip
);
242 static struct sort_entry sort_dso
= {
243 .header
= "Shared Object",
244 .cmp
= sort__dso_cmp
,
245 .print
= sort__dso_print
,
246 .width
= &dsos__col_width
,
252 sort__sym_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
256 if (left
->sym
== right
->sym
)
259 ip_l
= left
->sym
? left
->sym
->start
: left
->ip
;
260 ip_r
= right
->sym
? right
->sym
->start
: right
->ip
;
262 return (int64_t)(ip_r
- ip_l
);
266 sort__sym_print(FILE *fp
, struct hist_entry
*self
, unsigned int width __used
)
271 ret
+= repsep_fprintf(fp
, "%#018llx %c ", (u64
)self
->ip
,
272 dso__symtab_origin(self
->dso
));
274 ret
+= repsep_fprintf(fp
, "[%c] ", self
->level
);
276 ret
+= repsep_fprintf(fp
, "%s", self
->sym
->name
);
278 if (self
->sym
->module
)
279 ret
+= repsep_fprintf(fp
, "\t[%s]",
280 self
->sym
->module
->name
);
282 ret
+= repsep_fprintf(fp
, "%#016llx", (u64
)self
->ip
);
288 static struct sort_entry sort_sym
= {
290 .cmp
= sort__sym_cmp
,
291 .print
= sort__sym_print
,
297 sort__parent_cmp(struct hist_entry
*left
, struct hist_entry
*right
)
299 struct symbol
*sym_l
= left
->parent
;
300 struct symbol
*sym_r
= right
->parent
;
302 if (!sym_l
|| !sym_r
)
303 return cmp_null(sym_l
, sym_r
);
305 return strcmp(sym_l
->name
, sym_r
->name
);
309 sort__parent_print(FILE *fp
, struct hist_entry
*self
, unsigned int width
)
311 return repsep_fprintf(fp
, "%-*s", width
,
312 self
->parent
? self
->parent
->name
: "[other]");
315 static unsigned int parent_symbol__col_width
;
317 static struct sort_entry sort_parent
= {
318 .header
= "Parent symbol",
319 .cmp
= sort__parent_cmp
,
320 .print
= sort__parent_print
,
321 .width
= &parent_symbol__col_width
,
324 static int sort__need_collapse
= 0;
325 static int sort__has_parent
= 0;
327 struct sort_dimension
{
329 struct sort_entry
*entry
;
333 static struct sort_dimension sort_dimensions
[] = {
334 { .name
= "pid", .entry
= &sort_thread
, },
335 { .name
= "comm", .entry
= &sort_comm
, },
336 { .name
= "dso", .entry
= &sort_dso
, },
337 { .name
= "symbol", .entry
= &sort_sym
, },
338 { .name
= "parent", .entry
= &sort_parent
, },
341 static LIST_HEAD(hist_entry__sort_list
);
343 static int sort_dimension__add(const char *tok
)
347 for (i
= 0; i
< ARRAY_SIZE(sort_dimensions
); i
++) {
348 struct sort_dimension
*sd
= &sort_dimensions
[i
];
353 if (strncasecmp(tok
, sd
->name
, strlen(tok
)))
356 if (sd
->entry
->collapse
)
357 sort__need_collapse
= 1;
359 if (sd
->entry
== &sort_parent
) {
360 int ret
= regcomp(&parent_regex
, parent_pattern
, REG_EXTENDED
);
364 regerror(ret
, &parent_regex
, err
, sizeof(err
));
365 fprintf(stderr
, "Invalid regex: %s\n%s",
366 parent_pattern
, err
);
369 sort__has_parent
= 1;
372 list_add_tail(&sd
->entry
->list
, &hist_entry__sort_list
);
382 hist_entry__cmp(struct hist_entry
*left
, struct hist_entry
*right
)
384 struct sort_entry
*se
;
387 list_for_each_entry(se
, &hist_entry__sort_list
, list
) {
388 cmp
= se
->cmp(left
, right
);
397 hist_entry__collapse(struct hist_entry
*left
, struct hist_entry
*right
)
399 struct sort_entry
*se
;
402 list_for_each_entry(se
, &hist_entry__sort_list
, list
) {
403 int64_t (*f
)(struct hist_entry
*, struct hist_entry
*);
405 f
= se
->collapse
?: se
->cmp
;
407 cmp
= f(left
, right
);
415 static size_t ipchain__fprintf_graph_line(FILE *fp
, int depth
, int depth_mask
)
420 ret
+= fprintf(fp
, "%s", " ");
422 for (i
= 0; i
< depth
; i
++)
423 if (depth_mask
& (1 << i
))
424 ret
+= fprintf(fp
, "| ");
426 ret
+= fprintf(fp
, " ");
428 ret
+= fprintf(fp
, "\n");
433 ipchain__fprintf_graph(FILE *fp
, struct callchain_list
*chain
, int depth
,
434 int depth_mask
, int count
, u64 total_samples
,
440 ret
+= fprintf(fp
, "%s", " ");
441 for (i
= 0; i
< depth
; i
++) {
442 if (depth_mask
& (1 << i
))
443 ret
+= fprintf(fp
, "|");
445 ret
+= fprintf(fp
, " ");
446 if (!count
&& i
== depth
- 1) {
449 percent
= hits
* 100.0 / total_samples
;
450 ret
+= percent_color_fprintf(fp
, "--%2.2f%%-- ", percent
);
452 ret
+= fprintf(fp
, "%s", " ");
455 ret
+= fprintf(fp
, "%s\n", chain
->sym
->name
);
457 ret
+= fprintf(fp
, "%p\n", (void *)(long)chain
->ip
);
462 static struct symbol
*rem_sq_bracket
;
463 static struct callchain_list rem_hits
;
465 static void init_rem_hits(void)
467 rem_sq_bracket
= malloc(sizeof(*rem_sq_bracket
) + 6);
468 if (!rem_sq_bracket
) {
469 fprintf(stderr
, "Not enough memory to display remaining hits\n");
473 strcpy(rem_sq_bracket
->name
, "[...]");
474 rem_hits
.sym
= rem_sq_bracket
;
478 callchain__fprintf_graph(FILE *fp
, struct callchain_node
*self
,
479 u64 total_samples
, int depth
, int depth_mask
)
481 struct rb_node
*node
, *next
;
482 struct callchain_node
*child
;
483 struct callchain_list
*chain
;
484 int new_depth_mask
= depth_mask
;
490 if (callchain_param
.mode
== CHAIN_GRAPH_REL
)
491 new_total
= self
->children_hit
;
493 new_total
= total_samples
;
495 remaining
= new_total
;
497 node
= rb_first(&self
->rb_root
);
501 child
= rb_entry(node
, struct callchain_node
, rb_node
);
502 cumul
= cumul_hits(child
);
506 * The depth mask manages the output of pipes that show
507 * the depth. We don't want to keep the pipes of the current
508 * level for the last child of this depth.
509 * Except if we have remaining filtered hits. They will
510 * supersede the last child
512 next
= rb_next(node
);
513 if (!next
&& (callchain_param
.mode
!= CHAIN_GRAPH_REL
|| !remaining
))
514 new_depth_mask
&= ~(1 << (depth
- 1));
517 * But we keep the older depth mask for the line seperator
518 * to keep the level link until we reach the last child
520 ret
+= ipchain__fprintf_graph_line(fp
, depth
, depth_mask
);
522 list_for_each_entry(chain
, &child
->val
, list
) {
523 if (chain
->ip
>= PERF_CONTEXT_MAX
)
525 ret
+= ipchain__fprintf_graph(fp
, chain
, depth
,
530 ret
+= callchain__fprintf_graph(fp
, child
, new_total
,
532 new_depth_mask
| (1 << depth
));
536 if (callchain_param
.mode
== CHAIN_GRAPH_REL
&&
537 remaining
&& remaining
!= new_total
) {
542 new_depth_mask
&= ~(1 << (depth
- 1));
544 ret
+= ipchain__fprintf_graph(fp
, &rem_hits
, depth
,
545 new_depth_mask
, 0, new_total
,
553 callchain__fprintf_flat(FILE *fp
, struct callchain_node
*self
,
556 struct callchain_list
*chain
;
562 ret
+= callchain__fprintf_flat(fp
, self
->parent
, total_samples
);
565 list_for_each_entry(chain
, &self
->val
, list
) {
566 if (chain
->ip
>= PERF_CONTEXT_MAX
)
569 ret
+= fprintf(fp
, " %s\n", chain
->sym
->name
);
571 ret
+= fprintf(fp
, " %p\n",
572 (void *)(long)chain
->ip
);
579 hist_entry_callchain__fprintf(FILE *fp
, struct hist_entry
*self
,
582 struct rb_node
*rb_node
;
583 struct callchain_node
*chain
;
586 rb_node
= rb_first(&self
->sorted_chain
);
590 chain
= rb_entry(rb_node
, struct callchain_node
, rb_node
);
591 percent
= chain
->hit
* 100.0 / total_samples
;
592 switch (callchain_param
.mode
) {
594 ret
+= percent_color_fprintf(fp
, " %6.2f%%\n",
596 ret
+= callchain__fprintf_flat(fp
, chain
, total_samples
);
598 case CHAIN_GRAPH_ABS
: /* Falldown */
599 case CHAIN_GRAPH_REL
:
600 ret
+= callchain__fprintf_graph(fp
, chain
,
601 total_samples
, 1, 1);
606 ret
+= fprintf(fp
, "\n");
607 rb_node
= rb_next(rb_node
);
615 hist_entry__fprintf(FILE *fp
, struct hist_entry
*self
, u64 total_samples
)
617 struct sort_entry
*se
;
620 if (exclude_other
&& !self
->parent
)
624 ret
= percent_color_fprintf(fp
,
625 field_sep
? "%.2f" : " %6.2f%%",
626 (self
->count
* 100.0) / total_samples
);
628 ret
= fprintf(fp
, field_sep
? "%lld" : "%12lld ", self
->count
);
630 if (show_nr_samples
) {
632 fprintf(fp
, "%c%lld", *field_sep
, self
->count
);
634 fprintf(fp
, "%11lld", self
->count
);
637 list_for_each_entry(se
, &hist_entry__sort_list
, list
) {
641 fprintf(fp
, "%s", field_sep
?: " ");
642 ret
+= se
->print(fp
, self
, se
->width
? *se
->width
: 0);
645 ret
+= fprintf(fp
, "\n");
648 hist_entry_callchain__fprintf(fp
, self
, total_samples
);
657 static void dso__calc_col_width(struct dso
*self
)
659 if (!col_width_list_str
&& !field_sep
&&
660 (!dso_list
|| strlist__has_entry(dso_list
, self
->name
))) {
661 unsigned int slen
= strlen(self
->name
);
662 if (slen
> dsos__col_width
)
663 dsos__col_width
= slen
;
666 self
->slen_calculated
= 1;
669 static void thread__comm_adjust(struct thread
*self
)
671 char *comm
= self
->comm
;
673 if (!col_width_list_str
&& !field_sep
&&
674 (!comm_list
|| strlist__has_entry(comm_list
, comm
))) {
675 unsigned int slen
= strlen(comm
);
677 if (slen
> comms__col_width
) {
678 comms__col_width
= slen
;
679 threads__col_width
= slen
+ 6;
684 static int thread__set_comm_adjust(struct thread
*self
, const char *comm
)
686 int ret
= thread__set_comm(self
, comm
);
691 thread__comm_adjust(self
);
697 static struct symbol
*
698 resolve_symbol(struct thread
*thread
, struct map
**mapp
,
699 struct dso
**dsop
, u64
*ipp
)
701 struct dso
*dso
= dsop
? *dsop
: NULL
;
702 struct map
*map
= mapp
? *mapp
: NULL
;
714 map
= thread__find_map(thread
, ip
);
717 * We have to do this here as we may have a dso
718 * with no symbol hit that has a name longer than
719 * the ones with symbols sampled.
721 if (!sort_dso
.elide
&& !map
->dso
->slen_calculated
)
722 dso__calc_col_width(map
->dso
);
727 ip
= map
->map_ip(map
, ip
);
732 * If this is outside of all known maps,
733 * and is a negative address, try to look it
734 * up in the kernel dso, as it might be a
735 * vsyscall (which executes in user-mode):
737 if ((long long)ip
< 0)
740 dump_printf(" ...... dso: %s\n", dso
? dso
->name
: "<not found>");
741 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp
, ip
);
750 return dso
->find_symbol(dso
, ip
);
753 static int call__match(struct symbol
*sym
)
755 if (sym
->name
&& !regexec(&parent_regex
, sym
->name
, 0, NULL
, 0))
761 static struct symbol
**
762 resolve_callchain(struct thread
*thread
, struct map
*map __used
,
763 struct ip_callchain
*chain
, struct hist_entry
*entry
)
765 u64 context
= PERF_CONTEXT_MAX
;
766 struct symbol
**syms
= NULL
;
770 syms
= calloc(chain
->nr
, sizeof(*syms
));
772 fprintf(stderr
, "Can't allocate memory for symbols\n");
777 for (i
= 0; i
< chain
->nr
; i
++) {
778 u64 ip
= chain
->ips
[i
];
779 struct dso
*dso
= NULL
;
782 if (ip
>= PERF_CONTEXT_MAX
) {
788 case PERF_CONTEXT_HV
:
789 dso
= hypervisor_dso
;
791 case PERF_CONTEXT_KERNEL
:
798 sym
= resolve_symbol(thread
, NULL
, &dso
, &ip
);
801 if (sort__has_parent
&& call__match(sym
) &&
814 * collect histogram counts
818 hist_entry__add(struct thread
*thread
, struct map
*map
, struct dso
*dso
,
819 struct symbol
*sym
, u64 ip
, struct ip_callchain
*chain
,
820 char level
, u64 count
)
822 struct rb_node
**p
= &hist
.rb_node
;
823 struct rb_node
*parent
= NULL
;
824 struct hist_entry
*he
;
825 struct symbol
**syms
= NULL
;
826 struct hist_entry entry
= {
835 .sorted_chain
= RB_ROOT
839 if ((sort__has_parent
|| callchain
) && chain
)
840 syms
= resolve_callchain(thread
, map
, chain
, &entry
);
844 he
= rb_entry(parent
, struct hist_entry
, rb_node
);
846 cmp
= hist_entry__cmp(&entry
, he
);
851 append_chain(&he
->callchain
, chain
, syms
);
863 he
= malloc(sizeof(*he
));
868 callchain_init(&he
->callchain
);
869 append_chain(&he
->callchain
, chain
, syms
);
872 rb_link_node(&he
->rb_node
, parent
, p
);
873 rb_insert_color(&he
->rb_node
, &hist
);
878 static void hist_entry__free(struct hist_entry
*he
)
884 * collapse the histogram
887 static struct rb_root collapse_hists
;
889 static void collapse__insert_entry(struct hist_entry
*he
)
891 struct rb_node
**p
= &collapse_hists
.rb_node
;
892 struct rb_node
*parent
= NULL
;
893 struct hist_entry
*iter
;
898 iter
= rb_entry(parent
, struct hist_entry
, rb_node
);
900 cmp
= hist_entry__collapse(iter
, he
);
903 iter
->count
+= he
->count
;
904 hist_entry__free(he
);
914 rb_link_node(&he
->rb_node
, parent
, p
);
915 rb_insert_color(&he
->rb_node
, &collapse_hists
);
918 static void collapse__resort(void)
920 struct rb_node
*next
;
921 struct hist_entry
*n
;
923 if (!sort__need_collapse
)
926 next
= rb_first(&hist
);
928 n
= rb_entry(next
, struct hist_entry
, rb_node
);
929 next
= rb_next(&n
->rb_node
);
931 rb_erase(&n
->rb_node
, &hist
);
932 collapse__insert_entry(n
);
937 * reverse the map, sort on count.
940 static struct rb_root output_hists
;
942 static void output__insert_entry(struct hist_entry
*he
, u64 min_callchain_hits
)
944 struct rb_node
**p
= &output_hists
.rb_node
;
945 struct rb_node
*parent
= NULL
;
946 struct hist_entry
*iter
;
949 callchain_param
.sort(&he
->sorted_chain
, &he
->callchain
,
950 min_callchain_hits
, &callchain_param
);
954 iter
= rb_entry(parent
, struct hist_entry
, rb_node
);
956 if (he
->count
> iter
->count
)
962 rb_link_node(&he
->rb_node
, parent
, p
);
963 rb_insert_color(&he
->rb_node
, &output_hists
);
966 static void output__resort(u64 total_samples
)
968 struct rb_node
*next
;
969 struct hist_entry
*n
;
970 struct rb_root
*tree
= &hist
;
971 u64 min_callchain_hits
;
973 min_callchain_hits
= total_samples
* (callchain_param
.min_percent
/ 100);
975 if (sort__need_collapse
)
976 tree
= &collapse_hists
;
978 next
= rb_first(tree
);
981 n
= rb_entry(next
, struct hist_entry
, rb_node
);
982 next
= rb_next(&n
->rb_node
);
984 rb_erase(&n
->rb_node
, tree
);
985 output__insert_entry(n
, min_callchain_hits
);
989 static size_t output__fprintf(FILE *fp
, u64 total_samples
)
991 struct hist_entry
*pos
;
992 struct sort_entry
*se
;
996 char *col_width
= col_width_list_str
;
997 int raw_printing_style
;
999 raw_printing_style
= !strcmp(pretty_printing_style
, "raw");
1003 fprintf(fp
, "# Samples: %Ld\n", (u64
)total_samples
);
1006 fprintf(fp
, "# Overhead");
1007 if (show_nr_samples
) {
1009 fprintf(fp
, "%cSamples", *field_sep
);
1011 fputs(" Samples ", fp
);
1013 list_for_each_entry(se
, &hist_entry__sort_list
, list
) {
1017 fprintf(fp
, "%c%s", *field_sep
, se
->header
);
1020 width
= strlen(se
->header
);
1022 if (col_width_list_str
) {
1024 *se
->width
= atoi(col_width
);
1025 col_width
= strchr(col_width
, ',');
1030 width
= *se
->width
= max(*se
->width
, width
);
1032 fprintf(fp
, " %*s", width
, se
->header
);
1039 fprintf(fp
, "# ........");
1040 if (show_nr_samples
)
1041 fprintf(fp
, " ..........");
1042 list_for_each_entry(se
, &hist_entry__sort_list
, list
) {
1052 width
= strlen(se
->header
);
1053 for (i
= 0; i
< width
; i
++)
1061 for (nd
= rb_first(&output_hists
); nd
; nd
= rb_next(nd
)) {
1062 pos
= rb_entry(nd
, struct hist_entry
, rb_node
);
1063 ret
+= hist_entry__fprintf(fp
, pos
, total_samples
);
1066 if (sort_order
== default_sort_order
&&
1067 parent_pattern
== default_parent_pattern
) {
1069 fprintf(fp
, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
1074 free(rem_sq_bracket
);
1077 perf_read_values_display(fp
, &show_threads_values
,
1078 raw_printing_style
);
1083 static unsigned long total
= 0,
1090 static int validate_chain(struct ip_callchain
*chain
, event_t
*event
)
1092 unsigned int chain_size
;
1094 chain_size
= event
->header
.size
;
1095 chain_size
-= (unsigned long)&event
->ip
.__more_data
- (unsigned long)event
;
1097 if (chain
->nr
*sizeof(u64
) > chain_size
)
1104 process_sample_event(event_t
*event
, unsigned long offset
, unsigned long head
)
1108 struct dso
*dso
= NULL
;
1109 struct thread
*thread
;
1110 u64 ip
= event
->ip
.ip
;
1112 struct map
*map
= NULL
;
1113 void *more_data
= event
->ip
.__more_data
;
1114 struct ip_callchain
*chain
= NULL
;
1117 thread
= threads__findnew(event
->ip
.pid
, &threads
, &last_match
);
1119 if (sample_type
& PERF_SAMPLE_PERIOD
) {
1120 period
= *(u64
*)more_data
;
1121 more_data
+= sizeof(u64
);
1124 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
1125 (void *)(offset
+ head
),
1126 (void *)(long)(event
->header
.size
),
1128 event
->ip
.pid
, event
->ip
.tid
,
1132 if (sample_type
& PERF_SAMPLE_CALLCHAIN
) {
1135 chain
= (void *)more_data
;
1137 dump_printf("... chain: nr:%Lu\n", chain
->nr
);
1139 if (validate_chain(chain
, event
) < 0) {
1140 eprintf("call-chain problem with event, skipping it.\n");
1145 for (i
= 0; i
< chain
->nr
; i
++)
1146 dump_printf("..... %2d: %016Lx\n", i
, chain
->ips
[i
]);
1150 dump_printf(" ... thread: %s:%d\n", thread
->comm
, thread
->pid
);
1152 if (thread
== NULL
) {
1153 eprintf("problem processing %d event, skipping it.\n",
1154 event
->header
.type
);
1158 if (comm_list
&& !strlist__has_entry(comm_list
, thread
->comm
))
1161 cpumode
= event
->header
.misc
& PERF_RECORD_MISC_CPUMODE_MASK
;
1163 if (cpumode
== PERF_RECORD_MISC_KERNEL
) {
1169 dump_printf(" ...... dso: %s\n", dso
->name
);
1171 } else if (cpumode
== PERF_RECORD_MISC_USER
) {
1180 dso
= hypervisor_dso
;
1182 dump_printf(" ...... dso: [hypervisor]\n");
1185 if (show
& show_mask
) {
1186 struct symbol
*sym
= resolve_symbol(thread
, &map
, &dso
, &ip
);
1188 if (dso_list
&& (!dso
|| !dso
->name
||
1189 !strlist__has_entry(dso_list
, dso
->name
)))
1192 if (sym_list
&& (!sym
|| !strlist__has_entry(sym_list
, sym
->name
)))
1195 if (hist_entry__add(thread
, map
, dso
, sym
, ip
, chain
, level
, period
)) {
1196 eprintf("problem incrementing symbol count, skipping event\n");
1206 process_mmap_event(event_t
*event
, unsigned long offset
, unsigned long head
)
1208 struct thread
*thread
;
1209 struct map
*map
= map__new(&event
->mmap
, cwd
, cwdlen
);
1211 thread
= threads__findnew(event
->mmap
.pid
, &threads
, &last_match
);
1213 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
1214 (void *)(offset
+ head
),
1215 (void *)(long)(event
->header
.size
),
1218 (void *)(long)event
->mmap
.start
,
1219 (void *)(long)event
->mmap
.len
,
1220 (void *)(long)event
->mmap
.pgoff
,
1221 event
->mmap
.filename
);
1223 if (thread
== NULL
|| map
== NULL
) {
1224 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
1228 thread__insert_map(thread
, map
);
1235 process_comm_event(event_t
*event
, unsigned long offset
, unsigned long head
)
1237 struct thread
*thread
;
1239 thread
= threads__findnew(event
->comm
.pid
, &threads
, &last_match
);
1241 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
1242 (void *)(offset
+ head
),
1243 (void *)(long)(event
->header
.size
),
1244 event
->comm
.comm
, event
->comm
.pid
);
1246 if (thread
== NULL
||
1247 thread__set_comm_adjust(thread
, event
->comm
.comm
)) {
1248 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
1257 process_task_event(event_t
*event
, unsigned long offset
, unsigned long head
)
1259 struct thread
*thread
;
1260 struct thread
*parent
;
1262 thread
= threads__findnew(event
->fork
.pid
, &threads
, &last_match
);
1263 parent
= threads__findnew(event
->fork
.ppid
, &threads
, &last_match
);
1265 dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
1266 (void *)(offset
+ head
),
1267 (void *)(long)(event
->header
.size
),
1268 event
->header
.type
== PERF_RECORD_FORK
? "FORK" : "EXIT",
1269 event
->fork
.pid
, event
->fork
.tid
,
1270 event
->fork
.ppid
, event
->fork
.ptid
);
1273 * A thread clone will have the same PID for both
1276 if (thread
== parent
)
1279 if (event
->header
.type
== PERF_RECORD_EXIT
)
1282 if (!thread
|| !parent
|| thread__fork(thread
, parent
)) {
1283 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
1292 process_lost_event(event_t
*event
, unsigned long offset
, unsigned long head
)
1294 dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
1295 (void *)(offset
+ head
),
1296 (void *)(long)(event
->header
.size
),
1300 total_lost
+= event
->lost
.lost
;
1306 process_read_event(event_t
*event
, unsigned long offset
, unsigned long head
)
1308 struct perf_event_attr
*attr
;
1310 attr
= perf_header__find_attr(event
->read
.id
, header
);
1313 const char *name
= attr
? __event_name(attr
->type
, attr
->config
)
1315 perf_read_values_add_value(&show_threads_values
,
1316 event
->read
.pid
, event
->read
.tid
,
1322 dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n",
1323 (void *)(offset
+ head
),
1324 (void *)(long)(event
->header
.size
),
1327 attr
? __event_name(attr
->type
, attr
->config
)
1335 process_event(event_t
*event
, unsigned long offset
, unsigned long head
)
1339 switch (event
->header
.type
) {
1340 case PERF_RECORD_SAMPLE
:
1341 return process_sample_event(event
, offset
, head
);
1343 case PERF_RECORD_MMAP
:
1344 return process_mmap_event(event
, offset
, head
);
1346 case PERF_RECORD_COMM
:
1347 return process_comm_event(event
, offset
, head
);
1349 case PERF_RECORD_FORK
:
1350 case PERF_RECORD_EXIT
:
1351 return process_task_event(event
, offset
, head
);
1353 case PERF_RECORD_LOST
:
1354 return process_lost_event(event
, offset
, head
);
1356 case PERF_RECORD_READ
:
1357 return process_read_event(event
, offset
, head
);
1360 * We dont process them right now but they are fine:
1363 case PERF_RECORD_THROTTLE
:
1364 case PERF_RECORD_UNTHROTTLE
:
1374 static int __cmd_report(void)
1376 int ret
, rc
= EXIT_FAILURE
;
1377 unsigned long offset
= 0;
1378 unsigned long head
, shift
;
1379 struct stat input_stat
;
1380 struct thread
*idle
;
1385 idle
= register_idle_thread(&threads
, &last_match
);
1386 thread__comm_adjust(idle
);
1389 perf_read_values_init(&show_threads_values
);
1391 input
= open(input_name
, O_RDONLY
);
1393 fprintf(stderr
, " failed to open file: %s", input_name
);
1394 if (!strcmp(input_name
, "perf.data"))
1395 fprintf(stderr
, " (try 'perf record' first)");
1396 fprintf(stderr
, "\n");
1400 ret
= fstat(input
, &input_stat
);
1402 perror("failed to stat file");
1406 if (!force
&& input_stat
.st_uid
&& (input_stat
.st_uid
!= geteuid())) {
1407 fprintf(stderr
, "file: %s not owned by current user or root\n", input_name
);
1411 if (!input_stat
.st_size
) {
1412 fprintf(stderr
, "zero-sized file, nothing to do!\n");
1416 header
= perf_header__read(input
);
1417 head
= header
->data_offset
;
1419 sample_type
= perf_header__sample_type(header
);
1421 if (!(sample_type
& PERF_SAMPLE_CALLCHAIN
)) {
1422 if (sort__has_parent
) {
1423 fprintf(stderr
, "selected --sort parent, but no"
1424 " callchain data. Did you call"
1425 " perf record without -g?\n");
1429 fprintf(stderr
, "selected -g but no callchain data."
1430 " Did you call perf record without"
1434 } else if (callchain_param
.mode
!= CHAIN_NONE
&& !callchain
) {
1436 if (register_callchain_param(&callchain_param
) < 0) {
1437 fprintf(stderr
, "Can't register callchain"
1443 if (load_kernel() < 0) {
1444 perror("failed to load kernel symbols");
1445 return EXIT_FAILURE
;
1449 if (getcwd(__cwd
, sizeof(__cwd
)) == NULL
) {
1450 perror("failed to get the current directory");
1451 return EXIT_FAILURE
;
1453 cwdlen
= strlen(cwd
);
1459 shift
= page_size
* (head
/ page_size
);
1464 buf
= (char *)mmap(NULL
, page_size
* mmap_window
, PROT_READ
,
1465 MAP_SHARED
, input
, offset
);
1466 if (buf
== MAP_FAILED
) {
1467 perror("failed to mmap file");
1472 event
= (event_t
*)(buf
+ head
);
1474 size
= event
->header
.size
;
1478 if (head
+ event
->header
.size
>= page_size
* mmap_window
) {
1481 shift
= page_size
* (head
/ page_size
);
1483 munmap_ret
= munmap(buf
, page_size
* mmap_window
);
1484 assert(munmap_ret
== 0);
1491 size
= event
->header
.size
;
1493 dump_printf("\n%p [%p]: event: %d\n",
1494 (void *)(offset
+ head
),
1495 (void *)(long)event
->header
.size
,
1496 event
->header
.type
);
1498 if (!size
|| process_event(event
, offset
, head
) < 0) {
1500 dump_printf("%p [%p]: skipping unknown header type: %d\n",
1501 (void *)(offset
+ head
),
1502 (void *)(long)(event
->header
.size
),
1503 event
->header
.type
);
1508 * assume we lost track of the stream, check alignment, and
1509 * increment a single u64 in the hope to catch on again 'soon'.
1512 if (unlikely(head
& 7))
1520 if (offset
+ head
>= header
->data_offset
+ header
->data_size
)
1523 if (offset
+ head
< (unsigned long)input_stat
.st_size
)
1530 dump_printf(" IP events: %10ld\n", total
);
1531 dump_printf(" mmap events: %10ld\n", total_mmap
);
1532 dump_printf(" comm events: %10ld\n", total_comm
);
1533 dump_printf(" fork events: %10ld\n", total_fork
);
1534 dump_printf(" lost events: %10ld\n", total_lost
);
1535 dump_printf(" unknown events: %10ld\n", total_unknown
);
1541 threads__fprintf(stdout
, &threads
);
1544 dsos__fprintf(stdout
);
1547 output__resort(total
);
1548 output__fprintf(stdout
, total
);
1551 perf_read_values_destroy(&show_threads_values
);
1557 parse_callchain_opt(const struct option
*opt __used
, const char *arg
,
1568 tok
= strtok((char *)arg
, ",");
1572 /* get the output mode */
1573 if (!strncmp(tok
, "graph", strlen(arg
)))
1574 callchain_param
.mode
= CHAIN_GRAPH_ABS
;
1576 else if (!strncmp(tok
, "flat", strlen(arg
)))
1577 callchain_param
.mode
= CHAIN_FLAT
;
1579 else if (!strncmp(tok
, "fractal", strlen(arg
)))
1580 callchain_param
.mode
= CHAIN_GRAPH_REL
;
1582 else if (!strncmp(tok
, "none", strlen(arg
))) {
1583 callchain_param
.mode
= CHAIN_NONE
;
1592 /* get the min percentage */
1593 tok
= strtok(NULL
, ",");
1597 callchain_param
.min_percent
= strtod(tok
, &endptr
);
1602 if (register_callchain_param(&callchain_param
) < 0) {
1603 fprintf(stderr
, "Can't register callchain params\n");
1609 static const char * const report_usage
[] = {
1610 "perf report [<options>] <command>",
1614 static const struct option options
[] = {
1615 OPT_STRING('i', "input", &input_name
, "file",
1617 OPT_BOOLEAN('v', "verbose", &verbose
,
1618 "be more verbose (show symbol address, etc)"),
1619 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace
,
1620 "dump raw trace in ASCII"),
1621 OPT_STRING('k', "vmlinux", &vmlinux_name
, "file", "vmlinux pathname"),
1622 OPT_BOOLEAN('f', "force", &force
, "don't complain, do it"),
1623 OPT_BOOLEAN('m', "modules", &modules
,
1624 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1625 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples
,
1626 "Show a column with the number of samples"),
1627 OPT_BOOLEAN('T', "threads", &show_threads
,
1628 "Show per-thread event counters"),
1629 OPT_STRING(0, "pretty", &pretty_printing_style
, "key",
1630 "pretty printing style key: normal raw"),
1631 OPT_STRING('s', "sort", &sort_order
, "key[,key2...]",
1632 "sort by key(s): pid, comm, dso, symbol, parent"),
1633 OPT_BOOLEAN('P', "full-paths", &full_paths
,
1634 "Don't shorten the pathnames taking into account the cwd"),
1635 OPT_STRING('p', "parent", &parent_pattern
, "regex",
1636 "regex filter to identify parent, see: '--sort parent'"),
1637 OPT_BOOLEAN('x', "exclude-other", &exclude_other
,
1638 "Only display entries with parent-match"),
1639 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL
, "output_type,min_percent",
1640 "Display callchains using output_type and min percent threshold. "
1641 "Default: fractal,0.5", &parse_callchain_opt
, callchain_default_opt
),
1642 OPT_STRING('d', "dsos", &dso_list_str
, "dso[,dso...]",
1643 "only consider symbols in these dsos"),
1644 OPT_STRING('C', "comms", &comm_list_str
, "comm[,comm...]",
1645 "only consider symbols in these comms"),
1646 OPT_STRING('S', "symbols", &sym_list_str
, "symbol[,symbol...]",
1647 "only consider these symbols"),
1648 OPT_STRING('w', "column-widths", &col_width_list_str
,
1650 "don't try to adjust column width, use these fixed values"),
1651 OPT_STRING('t', "field-separator", &field_sep
, "separator",
1652 "separator for columns, no spaces will be added between "
1653 "columns '.' is reserved."),
1657 static void setup_sorting(void)
1659 char *tmp
, *tok
, *str
= strdup(sort_order
);
1661 for (tok
= strtok_r(str
, ", ", &tmp
);
1662 tok
; tok
= strtok_r(NULL
, ", ", &tmp
)) {
1663 if (sort_dimension__add(tok
) < 0) {
1664 error("Unknown --sort key: `%s'", tok
);
1665 usage_with_options(report_usage
, options
);
1672 static void setup_list(struct strlist
**list
, const char *list_str
,
1673 struct sort_entry
*se
, const char *list_name
,
1677 *list
= strlist__new(true, list_str
);
1679 fprintf(stderr
, "problems parsing %s list\n",
1683 if (strlist__nr_entries(*list
) == 1) {
1684 fprintf(fp
, "# %s: %s\n", list_name
,
1685 strlist__entry(*list
, 0)->s
);
1691 int cmd_report(int argc
, const char **argv
, const char *prefix __used
)
1695 page_size
= getpagesize();
1697 argc
= parse_options(argc
, argv
, options
, report_usage
, 0);
1701 if (parent_pattern
!= default_parent_pattern
) {
1702 sort_dimension__add("parent");
1703 sort_parent
.elide
= 1;
1708 * Any (unrecognized) arguments left?
1711 usage_with_options(report_usage
, options
);
1715 setup_list(&dso_list
, dso_list_str
, &sort_dso
, "dso", stdout
);
1716 setup_list(&comm_list
, comm_list_str
, &sort_comm
, "comm", stdout
);
1717 setup_list(&sym_list
, sym_list_str
, &sort_sym
, "symbol", stdout
);
1719 if (field_sep
&& *field_sep
== '.') {
1720 fputs("'.' is the only non valid --field-separator argument\n",
1725 return __cmd_report();