aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-report.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r--tools/perf/builtin-report.c178
1 files changed, 156 insertions, 22 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 25d34d483e49..8e91c6eba18a 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -53,6 +53,82 @@ struct perf_report {
53 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 53 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
54}; 54};
55 55
56static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
57 struct addr_location *al,
58 struct perf_sample *sample,
59 struct perf_evsel *evsel,
60 struct machine *machine)
61{
62 struct perf_report *rep = container_of(tool, struct perf_report, tool);
63 struct symbol *parent = NULL;
64 int err = 0;
65 unsigned i;
66 struct hist_entry *he;
67 struct branch_info *bi, *bx;
68
69 if ((sort__has_parent || symbol_conf.use_callchain)
70 && sample->callchain) {
71 err = machine__resolve_callchain(machine, evsel, al->thread,
72 sample->callchain, &parent);
73 if (err)
74 return err;
75 }
76
77 bi = machine__resolve_bstack(machine, al->thread,
78 sample->branch_stack);
79 if (!bi)
80 return -ENOMEM;
81
82 for (i = 0; i < sample->branch_stack->nr; i++) {
83 if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
84 continue;
85 /*
86 * The report shows the percentage of total branches captured
87 * and not events sampled. Thus we use a pseudo period of 1.
88 */
89 he = __hists__add_branch_entry(&evsel->hists, al, parent,
90 &bi[i], 1);
91 if (he) {
92 struct annotation *notes;
93 err = -ENOMEM;
94 bx = he->branch_info;
95 if (bx->from.sym && use_browser > 0) {
96 notes = symbol__annotation(bx->from.sym);
97 if (!notes->src
98 && symbol__alloc_hist(bx->from.sym) < 0)
99 goto out;
100
101 err = symbol__inc_addr_samples(bx->from.sym,
102 bx->from.map,
103 evsel->idx,
104 bx->from.al_addr);
105 if (err)
106 goto out;
107 }
108
109 if (bx->to.sym && use_browser > 0) {
110 notes = symbol__annotation(bx->to.sym);
111 if (!notes->src
112 && symbol__alloc_hist(bx->to.sym) < 0)
113 goto out;
114
115 err = symbol__inc_addr_samples(bx->to.sym,
116 bx->to.map,
117 evsel->idx,
118 bx->to.al_addr);
119 if (err)
120 goto out;
121 }
122 evsel->hists.stats.total_period += 1;
123 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
124 err = 0;
125 } else
126 return -ENOMEM;
127 }
128out:
129 return err;
130}
131
56static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, 132static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
57 struct addr_location *al, 133 struct addr_location *al,
58 struct perf_sample *sample, 134 struct perf_sample *sample,
@@ -126,14 +202,21 @@ static int process_sample_event(struct perf_tool *tool,
126 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) 202 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
127 return 0; 203 return 0;
128 204
129 if (al.map != NULL) 205 if (sort__branch_mode == 1) {
130 al.map->dso->hit = 1; 206 if (perf_report__add_branch_hist_entry(tool, &al, sample,
207 evsel, machine)) {
208 pr_debug("problem adding lbr entry, skipping event\n");
209 return -1;
210 }
211 } else {
212 if (al.map != NULL)
213 al.map->dso->hit = 1;
131 214
132 if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) { 215 if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
133 pr_debug("problem incrementing symbol period, skipping event\n"); 216 pr_debug("problem incrementing symbol period, skipping event\n");
134 return -1; 217 return -1;
218 }
135 } 219 }
136
137 return 0; 220 return 0;
138} 221}
139 222
@@ -188,6 +271,15 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
188 } 271 }
189 } 272 }
190 273
274 if (sort__branch_mode == 1) {
275 if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
276 fprintf(stderr, "selected -b but no branch data."
277 " Did you call perf record without"
278 " -b?\n");
279 return -1;
280 }
281 }
282
191 return 0; 283 return 0;
192} 284}
193 285
@@ -246,7 +338,7 @@ static int __cmd_report(struct perf_report *rep)
246{ 338{
247 int ret = -EINVAL; 339 int ret = -EINVAL;
248 u64 nr_samples; 340 u64 nr_samples;
249 struct perf_session *session; 341 struct perf_session *session = rep->session;
250 struct perf_evsel *pos; 342 struct perf_evsel *pos;
251 struct map *kernel_map; 343 struct map *kernel_map;
252 struct kmap *kernel_kmap; 344 struct kmap *kernel_kmap;
@@ -254,13 +346,6 @@ static int __cmd_report(struct perf_report *rep)
254 346
255 signal(SIGINT, sig_handler); 347 signal(SIGINT, sig_handler);
256 348
257 session = perf_session__new(rep->input_name, O_RDONLY,
258 rep->force, false, &rep->tool);
259 if (session == NULL)
260 return -ENOMEM;
261
262 rep->session = session;
263
264 if (rep->cpu_list) { 349 if (rep->cpu_list) {
265 ret = perf_session__cpu_bitmap(session, rep->cpu_list, 350 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
266 rep->cpu_bitmap); 351 rep->cpu_bitmap);
@@ -427,9 +512,19 @@ setup:
427 return 0; 512 return 0;
428} 513}
429 514
515static int
516parse_branch_mode(const struct option *opt __used, const char *str __used, int unset)
517{
518 sort__branch_mode = !unset;
519 return 0;
520}
521
430int cmd_report(int argc, const char **argv, const char *prefix __used) 522int cmd_report(int argc, const char **argv, const char *prefix __used)
431{ 523{
524 struct perf_session *session;
432 struct stat st; 525 struct stat st;
526 bool has_br_stack = false;
527 int ret = -1;
433 char callchain_default_opt[] = "fractal,0.5,callee"; 528 char callchain_default_opt[] = "fractal,0.5,callee";
434 const char * const report_usage[] = { 529 const char * const report_usage[] = {
435 "perf report [<options>]", 530 "perf report [<options>]",
@@ -477,7 +572,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
477 OPT_BOOLEAN(0, "stdio", &report.use_stdio, 572 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
478 "Use the stdio interface"), 573 "Use the stdio interface"),
479 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 574 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
480 "sort by key(s): pid, comm, dso, symbol, parent"), 575 "sort by key(s): pid, comm, dso, symbol, parent, dso_to,"
576 " dso_from, symbol_to, symbol_from, mispredict"),
481 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 577 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
482 "Show sample percentage for different cpu modes"), 578 "Show sample percentage for different cpu modes"),
483 OPT_STRING('p', "parent", &parent_pattern, "regex", 579 OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -517,6 +613,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
517 "Specify disassembler style (e.g. -M intel for intel syntax)"), 613 "Specify disassembler style (e.g. -M intel for intel syntax)"),
518 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 614 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
519 "Show a column with the sum of periods"), 615 "Show a column with the sum of periods"),
616 OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
617 "use branch records for histogram filling", parse_branch_mode),
520 OPT_END() 618 OPT_END()
521 }; 619 };
522 620
@@ -536,11 +634,36 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
536 else 634 else
537 report.input_name = "perf.data"; 635 report.input_name = "perf.data";
538 } 636 }
637 session = perf_session__new(report.input_name, O_RDONLY,
638 report.force, false, &report.tool);
639 if (session == NULL)
640 return -ENOMEM;
539 641
540 if (strcmp(report.input_name, "-") != 0) 642 report.session = session;
643
644 has_br_stack = perf_header__has_feat(&session->header,
645 HEADER_BRANCH_STACK);
646
647 if (sort__branch_mode == -1 && has_br_stack)
648 sort__branch_mode = 1;
649
650 /* sort__branch_mode could be 0 if --no-branch-stack */
651 if (sort__branch_mode == 1) {
652 /*
653 * if no sort_order is provided, then specify
654 * branch-mode specific order
655 */
656 if (sort_order == default_sort_order)
657 sort_order = "comm,dso_from,symbol_from,"
658 "dso_to,symbol_to";
659
660 }
661
662 if (strcmp(report.input_name, "-") != 0) {
541 setup_browser(true); 663 setup_browser(true);
542 else 664 } else {
543 use_browser = 0; 665 use_browser = 0;
666 }
544 667
545 /* 668 /*
546 * Only in the newt browser we are doing integrated annotation, 669 * Only in the newt browser we are doing integrated annotation,
@@ -568,13 +691,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
568 } 691 }
569 692
570 if (symbol__init() < 0) 693 if (symbol__init() < 0)
571 return -1; 694 goto error;
572 695
573 setup_sorting(report_usage, options); 696 setup_sorting(report_usage, options);
574 697
575 if (parent_pattern != default_parent_pattern) { 698 if (parent_pattern != default_parent_pattern) {
576 if (sort_dimension__add("parent") < 0) 699 if (sort_dimension__add("parent") < 0)
577 return -1; 700 goto error;
578 701
579 /* 702 /*
580 * Only show the parent fields if we explicitly 703 * Only show the parent fields if we explicitly
@@ -592,9 +715,20 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
592 if (argc) 715 if (argc)
593 usage_with_options(report_usage, options); 716 usage_with_options(report_usage, options);
594 717
595 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
596 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); 718 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
597 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
598 719
599 return __cmd_report(&report); 720 if (sort__branch_mode == 1) {
721 sort_entry__setup_elide(&sort_dso_from, symbol_conf.dso_from_list, "dso_from", stdout);
722 sort_entry__setup_elide(&sort_dso_to, symbol_conf.dso_to_list, "dso_to", stdout);
723 sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout);
724 sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout);
725 } else {
726 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
727 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
728 }
729
730 ret = __cmd_report(&report);
731error:
732 perf_session__delete(session);
733 return ret;
600} 734}