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"
30 #include "util/sort.h"
32 static char const *input_name
= "perf.data";
34 static char *dso_list_str
, *comm_list_str
, *sym_list_str
,
36 static struct strlist
*dso_list
, *comm_list
, *sym_list
;
40 static int show_mask
= SHOW_KERNEL
| SHOW_USER
| SHOW_HV
;
42 static int full_paths
;
43 static int show_nr_samples
;
45 static int show_threads
;
46 static struct perf_read_values show_threads_values
;
48 static char default_pretty_printing_style
[] = "normal";
49 static char *pretty_printing_style
= default_pretty_printing_style
;
51 static unsigned long page_size
;
52 static unsigned long mmap_window
= 32;
54 static int exclude_other
= 1;
56 static char callchain_default_opt
[] = "fractal,0.5";
60 static char __cwd
[PATH_MAX
];
61 static char *cwd
= __cwd
;
64 static struct rb_root threads
;
65 static struct thread
*last_match
;
67 static struct perf_header
*header
;
70 struct callchain_param callchain_param
= {
71 .mode
= CHAIN_GRAPH_REL
,
75 static u64 sample_type
;
77 static struct rb_root hist
;
80 hist_entry__cmp(struct hist_entry
*left
, struct hist_entry
*right
)
82 struct sort_entry
*se
;
85 list_for_each_entry(se
, &hist_entry__sort_list
, list
) {
86 cmp
= se
->cmp(left
, right
);
95 hist_entry__collapse(struct hist_entry
*left
, struct hist_entry
*right
)
97 struct sort_entry
*se
;
100 list_for_each_entry(se
, &hist_entry__sort_list
, list
) {
101 int64_t (*f
)(struct hist_entry
*, struct hist_entry
*);
103 f
= se
->collapse
?: se
->cmp
;
105 cmp
= f(left
, right
);
113 static size_t ipchain__fprintf_graph_line(FILE *fp
, int depth
, int depth_mask
)
118 ret
+= fprintf(fp
, "%s", " ");
120 for (i
= 0; i
< depth
; i
++)
121 if (depth_mask
& (1 << i
))
122 ret
+= fprintf(fp
, "| ");
124 ret
+= fprintf(fp
, " ");
126 ret
+= fprintf(fp
, "\n");
131 ipchain__fprintf_graph(FILE *fp
, struct callchain_list
*chain
, int depth
,
132 int depth_mask
, int count
, u64 total_samples
,
138 ret
+= fprintf(fp
, "%s", " ");
139 for (i
= 0; i
< depth
; i
++) {
140 if (depth_mask
& (1 << i
))
141 ret
+= fprintf(fp
, "|");
143 ret
+= fprintf(fp
, " ");
144 if (!count
&& i
== depth
- 1) {
147 percent
= hits
* 100.0 / total_samples
;
148 ret
+= percent_color_fprintf(fp
, "--%2.2f%%-- ", percent
);
150 ret
+= fprintf(fp
, "%s", " ");
153 ret
+= fprintf(fp
, "%s\n", chain
->sym
->name
);
155 ret
+= fprintf(fp
, "%p\n", (void *)(long)chain
->ip
);
160 static struct symbol
*rem_sq_bracket
;
161 static struct callchain_list rem_hits
;
163 static void init_rem_hits(void)
165 rem_sq_bracket
= malloc(sizeof(*rem_sq_bracket
) + 6);
166 if (!rem_sq_bracket
) {
167 fprintf(stderr
, "Not enough memory to display remaining hits\n");
171 strcpy(rem_sq_bracket
->name
, "[...]");
172 rem_hits
.sym
= rem_sq_bracket
;
176 callchain__fprintf_graph(FILE *fp
, struct callchain_node
*self
,
177 u64 total_samples
, int depth
, int depth_mask
)
179 struct rb_node
*node
, *next
;
180 struct callchain_node
*child
;
181 struct callchain_list
*chain
;
182 int new_depth_mask
= depth_mask
;
188 if (callchain_param
.mode
== CHAIN_GRAPH_REL
)
189 new_total
= self
->children_hit
;
191 new_total
= total_samples
;
193 remaining
= new_total
;
195 node
= rb_first(&self
->rb_root
);
199 child
= rb_entry(node
, struct callchain_node
, rb_node
);
200 cumul
= cumul_hits(child
);
204 * The depth mask manages the output of pipes that show
205 * the depth. We don't want to keep the pipes of the current
206 * level for the last child of this depth.
207 * Except if we have remaining filtered hits. They will
208 * supersede the last child
210 next
= rb_next(node
);
211 if (!next
&& (callchain_param
.mode
!= CHAIN_GRAPH_REL
|| !remaining
))
212 new_depth_mask
&= ~(1 << (depth
- 1));
215 * But we keep the older depth mask for the line seperator
216 * to keep the level link until we reach the last child
218 ret
+= ipchain__fprintf_graph_line(fp
, depth
, depth_mask
);
220 list_for_each_entry(chain
, &child
->val
, list
) {
221 if (chain
->ip
>= PERF_CONTEXT_MAX
)
223 ret
+= ipchain__fprintf_graph(fp
, chain
, depth
,
228 ret
+= callchain__fprintf_graph(fp
, child
, new_total
,
230 new_depth_mask
| (1 << depth
));
234 if (callchain_param
.mode
== CHAIN_GRAPH_REL
&&
235 remaining
&& remaining
!= new_total
) {
240 new_depth_mask
&= ~(1 << (depth
- 1));
242 ret
+= ipchain__fprintf_graph(fp
, &rem_hits
, depth
,
243 new_depth_mask
, 0, new_total
,
251 callchain__fprintf_flat(FILE *fp
, struct callchain_node
*self
,
254 struct callchain_list
*chain
;
260 ret
+= callchain__fprintf_flat(fp
, self
->parent
, total_samples
);
263 list_for_each_entry(chain
, &self
->val
, list
) {
264 if (chain
->ip
>= PERF_CONTEXT_MAX
)
267 ret
+= fprintf(fp
, " %s\n", chain
->sym
->name
);
269 ret
+= fprintf(fp
, " %p\n",
270 (void *)(long)chain
->ip
);
277 hist_entry_callchain__fprintf(FILE *fp
, struct hist_entry
*self
,
280 struct rb_node
*rb_node
;
281 struct callchain_node
*chain
;
284 rb_node
= rb_first(&self
->sorted_chain
);
288 chain
= rb_entry(rb_node
, struct callchain_node
, rb_node
);
289 percent
= chain
->hit
* 100.0 / total_samples
;
290 switch (callchain_param
.mode
) {
292 ret
+= percent_color_fprintf(fp
, " %6.2f%%\n",
294 ret
+= callchain__fprintf_flat(fp
, chain
, total_samples
);
296 case CHAIN_GRAPH_ABS
: /* Falldown */
297 case CHAIN_GRAPH_REL
:
298 ret
+= callchain__fprintf_graph(fp
, chain
,
299 total_samples
, 1, 1);
304 ret
+= fprintf(fp
, "\n");
305 rb_node
= rb_next(rb_node
);
313 hist_entry__fprintf(FILE *fp
, struct hist_entry
*self
, u64 total_samples
)
315 struct sort_entry
*se
;
318 if (exclude_other
&& !self
->parent
)
322 ret
= percent_color_fprintf(fp
,
323 field_sep
? "%.2f" : " %6.2f%%",
324 (self
->count
* 100.0) / total_samples
);
326 ret
= fprintf(fp
, field_sep
? "%lld" : "%12lld ", self
->count
);
328 if (show_nr_samples
) {
330 fprintf(fp
, "%c%lld", *field_sep
, self
->count
);
332 fprintf(fp
, "%11lld", self
->count
);
335 list_for_each_entry(se
, &hist_entry__sort_list
, list
) {
339 fprintf(fp
, "%s", field_sep
?: " ");
340 ret
+= se
->print(fp
, self
, se
->width
? *se
->width
: 0);
343 ret
+= fprintf(fp
, "\n");
346 hist_entry_callchain__fprintf(fp
, self
, total_samples
);
355 static void dso__calc_col_width(struct dso
*self
)
357 if (!col_width_list_str
&& !field_sep
&&
358 (!dso_list
|| strlist__has_entry(dso_list
, self
->name
))) {
359 unsigned int slen
= strlen(self
->name
);
360 if (slen
> dsos__col_width
)
361 dsos__col_width
= slen
;
364 self
->slen_calculated
= 1;
367 static void thread__comm_adjust(struct thread
*self
)
369 char *comm
= self
->comm
;
371 if (!col_width_list_str
&& !field_sep
&&
372 (!comm_list
|| strlist__has_entry(comm_list
, comm
))) {
373 unsigned int slen
= strlen(comm
);
375 if (slen
> comms__col_width
) {
376 comms__col_width
= slen
;
377 threads__col_width
= slen
+ 6;
382 static int thread__set_comm_adjust(struct thread
*self
, const char *comm
)
384 int ret
= thread__set_comm(self
, comm
);
389 thread__comm_adjust(self
);
395 static struct symbol
*
396 resolve_symbol(struct thread
*thread
, struct map
**mapp
,
397 struct dso
**dsop
, u64
*ipp
)
399 struct dso
*dso
= dsop
? *dsop
: NULL
;
400 struct map
*map
= mapp
? *mapp
: NULL
;
412 map
= thread__find_map(thread
, ip
);
415 * We have to do this here as we may have a dso
416 * with no symbol hit that has a name longer than
417 * the ones with symbols sampled.
419 if (!sort_dso
.elide
&& !map
->dso
->slen_calculated
)
420 dso__calc_col_width(map
->dso
);
425 ip
= map
->map_ip(map
, ip
);
430 * If this is outside of all known maps,
431 * and is a negative address, try to look it
432 * up in the kernel dso, as it might be a
433 * vsyscall (which executes in user-mode):
435 if ((long long)ip
< 0)
438 dump_printf(" ...... dso: %s\n", dso
? dso
->name
: "<not found>");
439 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp
, ip
);
448 return dso
->find_symbol(dso
, ip
);
451 static int call__match(struct symbol
*sym
)
453 if (sym
->name
&& !regexec(&parent_regex
, sym
->name
, 0, NULL
, 0))
459 static struct symbol
**
460 resolve_callchain(struct thread
*thread
, struct map
*map __used
,
461 struct ip_callchain
*chain
, struct hist_entry
*entry
)
463 u64 context
= PERF_CONTEXT_MAX
;
464 struct symbol
**syms
= NULL
;
468 syms
= calloc(chain
->nr
, sizeof(*syms
));
470 fprintf(stderr
, "Can't allocate memory for symbols\n");
475 for (i
= 0; i
< chain
->nr
; i
++) {
476 u64 ip
= chain
->ips
[i
];
477 struct dso
*dso
= NULL
;
480 if (ip
>= PERF_CONTEXT_MAX
) {
486 case PERF_CONTEXT_HV
:
487 dso
= hypervisor_dso
;
489 case PERF_CONTEXT_KERNEL
:
496 sym
= resolve_symbol(thread
, NULL
, &dso
, &ip
);
499 if (sort__has_parent
&& call__match(sym
) &&
512 * collect histogram counts
516 hist_entry__add(struct thread
*thread
, struct map
*map
, struct dso
*dso
,
517 struct symbol
*sym
, u64 ip
, struct ip_callchain
*chain
,
518 char level
, u64 count
)
520 struct rb_node
**p
= &hist
.rb_node
;
521 struct rb_node
*parent
= NULL
;
522 struct hist_entry
*he
;
523 struct symbol
**syms
= NULL
;
524 struct hist_entry entry
= {
533 .sorted_chain
= RB_ROOT
537 if ((sort__has_parent
|| callchain
) && chain
)
538 syms
= resolve_callchain(thread
, map
, chain
, &entry
);
542 he
= rb_entry(parent
, struct hist_entry
, rb_node
);
544 cmp
= hist_entry__cmp(&entry
, he
);
549 append_chain(&he
->callchain
, chain
, syms
);
561 he
= malloc(sizeof(*he
));
566 callchain_init(&he
->callchain
);
567 append_chain(&he
->callchain
, chain
, syms
);
570 rb_link_node(&he
->rb_node
, parent
, p
);
571 rb_insert_color(&he
->rb_node
, &hist
);
576 static void hist_entry__free(struct hist_entry
*he
)
582 * collapse the histogram
585 static struct rb_root collapse_hists
;
587 static void collapse__insert_entry(struct hist_entry
*he
)
589 struct rb_node
**p
= &collapse_hists
.rb_node
;
590 struct rb_node
*parent
= NULL
;
591 struct hist_entry
*iter
;
596 iter
= rb_entry(parent
, struct hist_entry
, rb_node
);
598 cmp
= hist_entry__collapse(iter
, he
);
601 iter
->count
+= he
->count
;
602 hist_entry__free(he
);
612 rb_link_node(&he
->rb_node
, parent
, p
);
613 rb_insert_color(&he
->rb_node
, &collapse_hists
);
616 static void collapse__resort(void)
618 struct rb_node
*next
;
619 struct hist_entry
*n
;
621 if (!sort__need_collapse
)
624 next
= rb_first(&hist
);
626 n
= rb_entry(next
, struct hist_entry
, rb_node
);
627 next
= rb_next(&n
->rb_node
);
629 rb_erase(&n
->rb_node
, &hist
);
630 collapse__insert_entry(n
);
635 * reverse the map, sort on count.
638 static struct rb_root output_hists
;
640 static void output__insert_entry(struct hist_entry
*he
, u64 min_callchain_hits
)
642 struct rb_node
**p
= &output_hists
.rb_node
;
643 struct rb_node
*parent
= NULL
;
644 struct hist_entry
*iter
;
647 callchain_param
.sort(&he
->sorted_chain
, &he
->callchain
,
648 min_callchain_hits
, &callchain_param
);
652 iter
= rb_entry(parent
, struct hist_entry
, rb_node
);
654 if (he
->count
> iter
->count
)
660 rb_link_node(&he
->rb_node
, parent
, p
);
661 rb_insert_color(&he
->rb_node
, &output_hists
);
664 static void output__resort(u64 total_samples
)
666 struct rb_node
*next
;
667 struct hist_entry
*n
;
668 struct rb_root
*tree
= &hist
;
669 u64 min_callchain_hits
;
671 min_callchain_hits
= total_samples
* (callchain_param
.min_percent
/ 100);
673 if (sort__need_collapse
)
674 tree
= &collapse_hists
;
676 next
= rb_first(tree
);
679 n
= rb_entry(next
, struct hist_entry
, rb_node
);
680 next
= rb_next(&n
->rb_node
);
682 rb_erase(&n
->rb_node
, tree
);
683 output__insert_entry(n
, min_callchain_hits
);
687 static size_t output__fprintf(FILE *fp
, u64 total_samples
)
689 struct hist_entry
*pos
;
690 struct sort_entry
*se
;
694 char *col_width
= col_width_list_str
;
695 int raw_printing_style
;
697 raw_printing_style
= !strcmp(pretty_printing_style
, "raw");
701 fprintf(fp
, "# Samples: %Ld\n", (u64
)total_samples
);
704 fprintf(fp
, "# Overhead");
705 if (show_nr_samples
) {
707 fprintf(fp
, "%cSamples", *field_sep
);
709 fputs(" Samples ", fp
);
711 list_for_each_entry(se
, &hist_entry__sort_list
, list
) {
715 fprintf(fp
, "%c%s", *field_sep
, se
->header
);
718 width
= strlen(se
->header
);
720 if (col_width_list_str
) {
722 *se
->width
= atoi(col_width
);
723 col_width
= strchr(col_width
, ',');
728 width
= *se
->width
= max(*se
->width
, width
);
730 fprintf(fp
, " %*s", width
, se
->header
);
737 fprintf(fp
, "# ........");
739 fprintf(fp
, " ..........");
740 list_for_each_entry(se
, &hist_entry__sort_list
, list
) {
750 width
= strlen(se
->header
);
751 for (i
= 0; i
< width
; i
++)
759 for (nd
= rb_first(&output_hists
); nd
; nd
= rb_next(nd
)) {
760 pos
= rb_entry(nd
, struct hist_entry
, rb_node
);
761 ret
+= hist_entry__fprintf(fp
, pos
, total_samples
);
764 if (sort_order
== default_sort_order
&&
765 parent_pattern
== default_parent_pattern
) {
767 fprintf(fp
, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
772 free(rem_sq_bracket
);
775 perf_read_values_display(fp
, &show_threads_values
,
781 static unsigned long total
= 0,
788 static int validate_chain(struct ip_callchain
*chain
, event_t
*event
)
790 unsigned int chain_size
;
792 chain_size
= event
->header
.size
;
793 chain_size
-= (unsigned long)&event
->ip
.__more_data
- (unsigned long)event
;
795 if (chain
->nr
*sizeof(u64
) > chain_size
)
802 process_sample_event(event_t
*event
, unsigned long offset
, unsigned long head
)
806 struct dso
*dso
= NULL
;
807 struct thread
*thread
;
808 u64 ip
= event
->ip
.ip
;
810 struct map
*map
= NULL
;
811 void *more_data
= event
->ip
.__more_data
;
812 struct ip_callchain
*chain
= NULL
;
815 thread
= threads__findnew(event
->ip
.pid
, &threads
, &last_match
);
817 if (sample_type
& PERF_SAMPLE_PERIOD
) {
818 period
= *(u64
*)more_data
;
819 more_data
+= sizeof(u64
);
822 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
823 (void *)(offset
+ head
),
824 (void *)(long)(event
->header
.size
),
826 event
->ip
.pid
, event
->ip
.tid
,
830 if (sample_type
& PERF_SAMPLE_CALLCHAIN
) {
833 chain
= (void *)more_data
;
835 dump_printf("... chain: nr:%Lu\n", chain
->nr
);
837 if (validate_chain(chain
, event
) < 0) {
838 eprintf("call-chain problem with event, skipping it.\n");
843 for (i
= 0; i
< chain
->nr
; i
++)
844 dump_printf("..... %2d: %016Lx\n", i
, chain
->ips
[i
]);
848 dump_printf(" ... thread: %s:%d\n", thread
->comm
, thread
->pid
);
850 if (thread
== NULL
) {
851 eprintf("problem processing %d event, skipping it.\n",
856 if (comm_list
&& !strlist__has_entry(comm_list
, thread
->comm
))
859 cpumode
= event
->header
.misc
& PERF_RECORD_MISC_CPUMODE_MASK
;
861 if (cpumode
== PERF_RECORD_MISC_KERNEL
) {
867 dump_printf(" ...... dso: %s\n", dso
->name
);
869 } else if (cpumode
== PERF_RECORD_MISC_USER
) {
878 dso
= hypervisor_dso
;
880 dump_printf(" ...... dso: [hypervisor]\n");
883 if (show
& show_mask
) {
884 struct symbol
*sym
= resolve_symbol(thread
, &map
, &dso
, &ip
);
886 if (dso_list
&& (!dso
|| !dso
->name
||
887 !strlist__has_entry(dso_list
, dso
->name
)))
890 if (sym_list
&& (!sym
|| !strlist__has_entry(sym_list
, sym
->name
)))
893 if (hist_entry__add(thread
, map
, dso
, sym
, ip
, chain
, level
, period
)) {
894 eprintf("problem incrementing symbol count, skipping event\n");
904 process_mmap_event(event_t
*event
, unsigned long offset
, unsigned long head
)
906 struct thread
*thread
;
907 struct map
*map
= map__new(&event
->mmap
, cwd
, cwdlen
);
909 thread
= threads__findnew(event
->mmap
.pid
, &threads
, &last_match
);
911 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
912 (void *)(offset
+ head
),
913 (void *)(long)(event
->header
.size
),
916 (void *)(long)event
->mmap
.start
,
917 (void *)(long)event
->mmap
.len
,
918 (void *)(long)event
->mmap
.pgoff
,
919 event
->mmap
.filename
);
921 if (thread
== NULL
|| map
== NULL
) {
922 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
926 thread__insert_map(thread
, map
);
933 process_comm_event(event_t
*event
, unsigned long offset
, unsigned long head
)
935 struct thread
*thread
;
937 thread
= threads__findnew(event
->comm
.pid
, &threads
, &last_match
);
939 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
940 (void *)(offset
+ head
),
941 (void *)(long)(event
->header
.size
),
942 event
->comm
.comm
, event
->comm
.pid
);
944 if (thread
== NULL
||
945 thread__set_comm_adjust(thread
, event
->comm
.comm
)) {
946 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
955 process_task_event(event_t
*event
, unsigned long offset
, unsigned long head
)
957 struct thread
*thread
;
958 struct thread
*parent
;
960 thread
= threads__findnew(event
->fork
.pid
, &threads
, &last_match
);
961 parent
= threads__findnew(event
->fork
.ppid
, &threads
, &last_match
);
963 dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
964 (void *)(offset
+ head
),
965 (void *)(long)(event
->header
.size
),
966 event
->header
.type
== PERF_RECORD_FORK
? "FORK" : "EXIT",
967 event
->fork
.pid
, event
->fork
.tid
,
968 event
->fork
.ppid
, event
->fork
.ptid
);
971 * A thread clone will have the same PID for both
974 if (thread
== parent
)
977 if (event
->header
.type
== PERF_RECORD_EXIT
)
980 if (!thread
|| !parent
|| thread__fork(thread
, parent
)) {
981 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
990 process_lost_event(event_t
*event
, unsigned long offset
, unsigned long head
)
992 dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
993 (void *)(offset
+ head
),
994 (void *)(long)(event
->header
.size
),
998 total_lost
+= event
->lost
.lost
;
1004 process_read_event(event_t
*event
, unsigned long offset
, unsigned long head
)
1006 struct perf_event_attr
*attr
;
1008 attr
= perf_header__find_attr(event
->read
.id
, header
);
1011 const char *name
= attr
? __event_name(attr
->type
, attr
->config
)
1013 perf_read_values_add_value(&show_threads_values
,
1014 event
->read
.pid
, event
->read
.tid
,
1020 dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n",
1021 (void *)(offset
+ head
),
1022 (void *)(long)(event
->header
.size
),
1025 attr
? __event_name(attr
->type
, attr
->config
)
1033 process_event(event_t
*event
, unsigned long offset
, unsigned long head
)
1037 switch (event
->header
.type
) {
1038 case PERF_RECORD_SAMPLE
:
1039 return process_sample_event(event
, offset
, head
);
1041 case PERF_RECORD_MMAP
:
1042 return process_mmap_event(event
, offset
, head
);
1044 case PERF_RECORD_COMM
:
1045 return process_comm_event(event
, offset
, head
);
1047 case PERF_RECORD_FORK
:
1048 case PERF_RECORD_EXIT
:
1049 return process_task_event(event
, offset
, head
);
1051 case PERF_RECORD_LOST
:
1052 return process_lost_event(event
, offset
, head
);
1054 case PERF_RECORD_READ
:
1055 return process_read_event(event
, offset
, head
);
1058 * We dont process them right now but they are fine:
1061 case PERF_RECORD_THROTTLE
:
1062 case PERF_RECORD_UNTHROTTLE
:
1072 static int __cmd_report(void)
1074 int ret
, rc
= EXIT_FAILURE
;
1075 unsigned long offset
= 0;
1076 unsigned long head
, shift
;
1077 struct stat input_stat
;
1078 struct thread
*idle
;
1083 idle
= register_idle_thread(&threads
, &last_match
);
1084 thread__comm_adjust(idle
);
1087 perf_read_values_init(&show_threads_values
);
1089 input
= open(input_name
, O_RDONLY
);
1091 fprintf(stderr
, " failed to open file: %s", input_name
);
1092 if (!strcmp(input_name
, "perf.data"))
1093 fprintf(stderr
, " (try 'perf record' first)");
1094 fprintf(stderr
, "\n");
1098 ret
= fstat(input
, &input_stat
);
1100 perror("failed to stat file");
1104 if (!force
&& input_stat
.st_uid
&& (input_stat
.st_uid
!= geteuid())) {
1105 fprintf(stderr
, "file: %s not owned by current user or root\n", input_name
);
1109 if (!input_stat
.st_size
) {
1110 fprintf(stderr
, "zero-sized file, nothing to do!\n");
1114 header
= perf_header__read(input
);
1115 head
= header
->data_offset
;
1117 sample_type
= perf_header__sample_type(header
);
1119 if (!(sample_type
& PERF_SAMPLE_CALLCHAIN
)) {
1120 if (sort__has_parent
) {
1121 fprintf(stderr
, "selected --sort parent, but no"
1122 " callchain data. Did you call"
1123 " perf record without -g?\n");
1127 fprintf(stderr
, "selected -g but no callchain data."
1128 " Did you call perf record without"
1132 } else if (callchain_param
.mode
!= CHAIN_NONE
&& !callchain
) {
1134 if (register_callchain_param(&callchain_param
) < 0) {
1135 fprintf(stderr
, "Can't register callchain"
1141 if (load_kernel() < 0) {
1142 perror("failed to load kernel symbols");
1143 return EXIT_FAILURE
;
1147 if (getcwd(__cwd
, sizeof(__cwd
)) == NULL
) {
1148 perror("failed to get the current directory");
1149 return EXIT_FAILURE
;
1151 cwdlen
= strlen(cwd
);
1157 shift
= page_size
* (head
/ page_size
);
1162 buf
= (char *)mmap(NULL
, page_size
* mmap_window
, PROT_READ
,
1163 MAP_SHARED
, input
, offset
);
1164 if (buf
== MAP_FAILED
) {
1165 perror("failed to mmap file");
1170 event
= (event_t
*)(buf
+ head
);
1172 size
= event
->header
.size
;
1176 if (head
+ event
->header
.size
>= page_size
* mmap_window
) {
1179 shift
= page_size
* (head
/ page_size
);
1181 munmap_ret
= munmap(buf
, page_size
* mmap_window
);
1182 assert(munmap_ret
== 0);
1189 size
= event
->header
.size
;
1191 dump_printf("\n%p [%p]: event: %d\n",
1192 (void *)(offset
+ head
),
1193 (void *)(long)event
->header
.size
,
1194 event
->header
.type
);
1196 if (!size
|| process_event(event
, offset
, head
) < 0) {
1198 dump_printf("%p [%p]: skipping unknown header type: %d\n",
1199 (void *)(offset
+ head
),
1200 (void *)(long)(event
->header
.size
),
1201 event
->header
.type
);
1206 * assume we lost track of the stream, check alignment, and
1207 * increment a single u64 in the hope to catch on again 'soon'.
1210 if (unlikely(head
& 7))
1218 if (offset
+ head
>= header
->data_offset
+ header
->data_size
)
1221 if (offset
+ head
< (unsigned long)input_stat
.st_size
)
1228 dump_printf(" IP events: %10ld\n", total
);
1229 dump_printf(" mmap events: %10ld\n", total_mmap
);
1230 dump_printf(" comm events: %10ld\n", total_comm
);
1231 dump_printf(" fork events: %10ld\n", total_fork
);
1232 dump_printf(" lost events: %10ld\n", total_lost
);
1233 dump_printf(" unknown events: %10ld\n", total_unknown
);
1239 threads__fprintf(stdout
, &threads
);
1242 dsos__fprintf(stdout
);
1245 output__resort(total
);
1246 output__fprintf(stdout
, total
);
1249 perf_read_values_destroy(&show_threads_values
);
1255 parse_callchain_opt(const struct option
*opt __used
, const char *arg
,
1266 tok
= strtok((char *)arg
, ",");
1270 /* get the output mode */
1271 if (!strncmp(tok
, "graph", strlen(arg
)))
1272 callchain_param
.mode
= CHAIN_GRAPH_ABS
;
1274 else if (!strncmp(tok
, "flat", strlen(arg
)))
1275 callchain_param
.mode
= CHAIN_FLAT
;
1277 else if (!strncmp(tok
, "fractal", strlen(arg
)))
1278 callchain_param
.mode
= CHAIN_GRAPH_REL
;
1280 else if (!strncmp(tok
, "none", strlen(arg
))) {
1281 callchain_param
.mode
= CHAIN_NONE
;
1290 /* get the min percentage */
1291 tok
= strtok(NULL
, ",");
1295 callchain_param
.min_percent
= strtod(tok
, &endptr
);
1300 if (register_callchain_param(&callchain_param
) < 0) {
1301 fprintf(stderr
, "Can't register callchain params\n");
1307 //static const char * const report_usage[] = {
1308 const char * const report_usage
[] = {
1309 "perf report [<options>] <command>",
1313 static const struct option options
[] = {
1314 OPT_STRING('i', "input", &input_name
, "file",
1316 OPT_BOOLEAN('v', "verbose", &verbose
,
1317 "be more verbose (show symbol address, etc)"),
1318 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace
,
1319 "dump raw trace in ASCII"),
1320 OPT_STRING('k', "vmlinux", &vmlinux_name
, "file", "vmlinux pathname"),
1321 OPT_BOOLEAN('f', "force", &force
, "don't complain, do it"),
1322 OPT_BOOLEAN('m', "modules", &modules
,
1323 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1324 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples
,
1325 "Show a column with the number of samples"),
1326 OPT_BOOLEAN('T', "threads", &show_threads
,
1327 "Show per-thread event counters"),
1328 OPT_STRING(0, "pretty", &pretty_printing_style
, "key",
1329 "pretty printing style key: normal raw"),
1330 OPT_STRING('s', "sort", &sort_order
, "key[,key2...]",
1331 "sort by key(s): pid, comm, dso, symbol, parent"),
1332 OPT_BOOLEAN('P', "full-paths", &full_paths
,
1333 "Don't shorten the pathnames taking into account the cwd"),
1334 OPT_STRING('p', "parent", &parent_pattern
, "regex",
1335 "regex filter to identify parent, see: '--sort parent'"),
1336 OPT_BOOLEAN('x', "exclude-other", &exclude_other
,
1337 "Only display entries with parent-match"),
1338 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL
, "output_type,min_percent",
1339 "Display callchains using output_type and min percent threshold. "
1340 "Default: fractal,0.5", &parse_callchain_opt
, callchain_default_opt
),
1341 OPT_STRING('d', "dsos", &dso_list_str
, "dso[,dso...]",
1342 "only consider symbols in these dsos"),
1343 OPT_STRING('C', "comms", &comm_list_str
, "comm[,comm...]",
1344 "only consider symbols in these comms"),
1345 OPT_STRING('S', "symbols", &sym_list_str
, "symbol[,symbol...]",
1346 "only consider these symbols"),
1347 OPT_STRING('w', "column-widths", &col_width_list_str
,
1349 "don't try to adjust column width, use these fixed values"),
1350 OPT_STRING('t', "field-separator", &field_sep
, "separator",
1351 "separator for columns, no spaces will be added between "
1352 "columns '.' is reserved."),
1356 static void setup_sorting(void)
1358 char *tmp
, *tok
, *str
= strdup(sort_order
);
1360 for (tok
= strtok_r(str
, ", ", &tmp
);
1361 tok
; tok
= strtok_r(NULL
, ", ", &tmp
)) {
1362 if (sort_dimension__add(tok
) < 0) {
1363 error("Unknown --sort key: `%s'", tok
);
1364 usage_with_options(report_usage
, options
);
1371 static void setup_list(struct strlist
**list
, const char *list_str
,
1372 struct sort_entry
*se
, const char *list_name
,
1376 *list
= strlist__new(true, list_str
);
1378 fprintf(stderr
, "problems parsing %s list\n",
1382 if (strlist__nr_entries(*list
) == 1) {
1383 fprintf(fp
, "# %s: %s\n", list_name
,
1384 strlist__entry(*list
, 0)->s
);
1390 int cmd_report(int argc
, const char **argv
, const char *prefix __used
)
1394 page_size
= getpagesize();
1396 argc
= parse_options(argc
, argv
, options
, report_usage
, 0);
1400 if (parent_pattern
!= default_parent_pattern
) {
1401 sort_dimension__add("parent");
1402 sort_parent
.elide
= 1;
1407 * Any (unrecognized) arguments left?
1410 usage_with_options(report_usage
, options
);
1414 setup_list(&dso_list
, dso_list_str
, &sort_dso
, "dso", stdout
);
1415 setup_list(&comm_list
, comm_list_str
, &sort_comm
, "comm", stdout
);
1416 setup_list(&sym_list
, sym_list_str
, &sort_sym
, "symbol", stdout
);
1418 if (field_sep
&& *field_sep
== '.') {
1419 fputs("'.' is the only non valid --field-separator argument\n",
1424 return __cmd_report();