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.c124
1 files changed, 86 insertions, 38 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 72eae7498c09..8cf8e66ba594 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -33,8 +33,10 @@
33#include "util/thread.h" 33#include "util/thread.h"
34#include "util/sort.h" 34#include "util/sort.h"
35#include "util/hist.h" 35#include "util/hist.h"
36#include "util/data.h"
36#include "arch/common.h" 37#include "arch/common.h"
37 38
39#include <dlfcn.h>
38#include <linux/bitmap.h> 40#include <linux/bitmap.h>
39 41
40struct perf_report { 42struct perf_report {
@@ -47,6 +49,7 @@ struct perf_report {
47 bool show_threads; 49 bool show_threads;
48 bool inverted_callchain; 50 bool inverted_callchain;
49 bool mem_mode; 51 bool mem_mode;
52 int max_stack;
50 struct perf_read_values show_threads_values; 53 struct perf_read_values show_threads_values;
51 const char *pretty_printing_style; 54 const char *pretty_printing_style;
52 const char *cpu_list; 55 const char *cpu_list;
@@ -88,7 +91,8 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
88 if ((sort__has_parent || symbol_conf.use_callchain) && 91 if ((sort__has_parent || symbol_conf.use_callchain) &&
89 sample->callchain) { 92 sample->callchain) {
90 err = machine__resolve_callchain(machine, evsel, al->thread, 93 err = machine__resolve_callchain(machine, evsel, al->thread,
91 sample, &parent, al); 94 sample, &parent, al,
95 rep->max_stack);
92 if (err) 96 if (err)
93 return err; 97 return err;
94 } 98 }
@@ -111,7 +115,8 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
111 * and this is indirectly achieved by passing period=weight here 115 * and this is indirectly achieved by passing period=weight here
112 * and the he_stat__add_period() function. 116 * and the he_stat__add_period() function.
113 */ 117 */
114 he = __hists__add_mem_entry(&evsel->hists, al, parent, mi, cost, cost); 118 he = __hists__add_entry(&evsel->hists, al, parent, NULL, mi,
119 cost, cost, 0);
115 if (!he) 120 if (!he)
116 return -ENOMEM; 121 return -ENOMEM;
117 122
@@ -179,7 +184,8 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
179 if ((sort__has_parent || symbol_conf.use_callchain) 184 if ((sort__has_parent || symbol_conf.use_callchain)
180 && sample->callchain) { 185 && sample->callchain) {
181 err = machine__resolve_callchain(machine, evsel, al->thread, 186 err = machine__resolve_callchain(machine, evsel, al->thread,
182 sample, &parent, al); 187 sample, &parent, al,
188 rep->max_stack);
183 if (err) 189 if (err)
184 return err; 190 return err;
185 } 191 }
@@ -195,12 +201,16 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
195 201
196 err = -ENOMEM; 202 err = -ENOMEM;
197 203
204 /* overwrite the 'al' to branch-to info */
205 al->map = bi[i].to.map;
206 al->sym = bi[i].to.sym;
207 al->addr = bi[i].to.addr;
198 /* 208 /*
199 * The report shows the percentage of total branches captured 209 * The report shows the percentage of total branches captured
200 * and not events sampled. Thus we use a pseudo period of 1. 210 * and not events sampled. Thus we use a pseudo period of 1.
201 */ 211 */
202 he = __hists__add_branch_entry(&evsel->hists, al, parent, 212 he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
203 &bi[i], 1, 1); 213 1, 1, 0);
204 if (he) { 214 if (he) {
205 struct annotation *notes; 215 struct annotation *notes;
206 bx = he->branch_info; 216 bx = he->branch_info;
@@ -242,24 +252,28 @@ out:
242 return err; 252 return err;
243} 253}
244 254
245static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, 255static int perf_evsel__add_hist_entry(struct perf_tool *tool,
256 struct perf_evsel *evsel,
246 struct addr_location *al, 257 struct addr_location *al,
247 struct perf_sample *sample, 258 struct perf_sample *sample,
248 struct machine *machine) 259 struct machine *machine)
249{ 260{
261 struct perf_report *rep = container_of(tool, struct perf_report, tool);
250 struct symbol *parent = NULL; 262 struct symbol *parent = NULL;
251 int err = 0; 263 int err = 0;
252 struct hist_entry *he; 264 struct hist_entry *he;
253 265
254 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 266 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
255 err = machine__resolve_callchain(machine, evsel, al->thread, 267 err = machine__resolve_callchain(machine, evsel, al->thread,
256 sample, &parent, al); 268 sample, &parent, al,
269 rep->max_stack);
257 if (err) 270 if (err)
258 return err; 271 return err;
259 } 272 }
260 273
261 he = __hists__add_entry(&evsel->hists, al, parent, sample->period, 274 he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL,
262 sample->weight); 275 sample->period, sample->weight,
276 sample->transaction);
263 if (he == NULL) 277 if (he == NULL)
264 return -ENOMEM; 278 return -ENOMEM;
265 279
@@ -330,7 +344,8 @@ static int process_sample_event(struct perf_tool *tool,
330 if (al.map != NULL) 344 if (al.map != NULL)
331 al.map->dso->hit = 1; 345 al.map->dso->hit = 1;
332 346
333 ret = perf_evsel__add_hist_entry(evsel, &al, sample, machine); 347 ret = perf_evsel__add_hist_entry(tool, evsel, &al, sample,
348 machine);
334 if (ret < 0) 349 if (ret < 0)
335 pr_debug("problem incrementing symbol period, skipping event\n"); 350 pr_debug("problem incrementing symbol period, skipping event\n");
336 } 351 }
@@ -364,10 +379,11 @@ static int process_read_event(struct perf_tool *tool,
364/* For pipe mode, sample_type is not currently set */ 379/* For pipe mode, sample_type is not currently set */
365static int perf_report__setup_sample_type(struct perf_report *rep) 380static int perf_report__setup_sample_type(struct perf_report *rep)
366{ 381{
367 struct perf_session *self = rep->session; 382 struct perf_session *session = rep->session;
368 u64 sample_type = perf_evlist__combined_sample_type(self->evlist); 383 u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
384 bool is_pipe = perf_data_file__is_pipe(session->file);
369 385
370 if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { 386 if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
371 if (sort__has_parent) { 387 if (sort__has_parent) {
372 ui__error("Selected --sort parent, but no " 388 ui__error("Selected --sort parent, but no "
373 "callchain data. Did you call " 389 "callchain data. Did you call "
@@ -390,7 +406,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
390 } 406 }
391 407
392 if (sort__mode == SORT_MODE__BRANCH) { 408 if (sort__mode == SORT_MODE__BRANCH) {
393 if (!self->fd_pipe && 409 if (!is_pipe &&
394 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) { 410 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
395 ui__error("Selected -b but no branch data. " 411 ui__error("Selected -b but no branch data. "
396 "Did you call perf record without -b?\n"); 412 "Did you call perf record without -b?\n");
@@ -407,14 +423,14 @@ static void sig_handler(int sig __maybe_unused)
407} 423}
408 424
409static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, 425static size_t hists__fprintf_nr_sample_events(struct perf_report *rep,
410 struct hists *self, 426 struct hists *hists,
411 const char *evname, FILE *fp) 427 const char *evname, FILE *fp)
412{ 428{
413 size_t ret; 429 size_t ret;
414 char unit; 430 char unit;
415 unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE]; 431 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
416 u64 nr_events = self->stats.total_period; 432 u64 nr_events = hists->stats.total_period;
417 struct perf_evsel *evsel = hists_to_evsel(self); 433 struct perf_evsel *evsel = hists_to_evsel(hists);
418 char buf[512]; 434 char buf[512];
419 size_t size = sizeof(buf); 435 size_t size = sizeof(buf);
420 436
@@ -486,6 +502,8 @@ static int __cmd_report(struct perf_report *rep)
486 struct map *kernel_map; 502 struct map *kernel_map;
487 struct kmap *kernel_kmap; 503 struct kmap *kernel_kmap;
488 const char *help = "For a higher level overview, try: perf report --sort comm,dso"; 504 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
505 struct ui_progress prog;
506 struct perf_data_file *file = session->file;
489 507
490 signal(SIGINT, sig_handler); 508 signal(SIGINT, sig_handler);
491 509
@@ -547,13 +565,19 @@ static int __cmd_report(struct perf_report *rep)
547 } 565 }
548 566
549 nr_samples = 0; 567 nr_samples = 0;
568 list_for_each_entry(pos, &session->evlist->entries, node)
569 nr_samples += pos->hists.nr_entries;
570
571 ui_progress__init(&prog, nr_samples, "Merging related events...");
572
573 nr_samples = 0;
550 list_for_each_entry(pos, &session->evlist->entries, node) { 574 list_for_each_entry(pos, &session->evlist->entries, node) {
551 struct hists *hists = &pos->hists; 575 struct hists *hists = &pos->hists;
552 576
553 if (pos->idx == 0) 577 if (pos->idx == 0)
554 hists->symbol_filter_str = rep->symbol_filter_str; 578 hists->symbol_filter_str = rep->symbol_filter_str;
555 579
556 hists__collapse_resort(hists); 580 hists__collapse_resort(hists, &prog);
557 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; 581 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
558 582
559 /* Non-group events are considered as leader */ 583 /* Non-group events are considered as leader */
@@ -565,12 +589,13 @@ static int __cmd_report(struct perf_report *rep)
565 hists__link(leader_hists, hists); 589 hists__link(leader_hists, hists);
566 } 590 }
567 } 591 }
592 ui_progress__finish();
568 593
569 if (session_done()) 594 if (session_done())
570 return 0; 595 return 0;
571 596
572 if (nr_samples == 0) { 597 if (nr_samples == 0) {
573 ui__error("The %s file has no samples!\n", session->filename); 598 ui__error("The %s file has no samples!\n", file->path);
574 return 0; 599 return 0;
575 } 600 }
576 601
@@ -591,8 +616,19 @@ static int __cmd_report(struct perf_report *rep)
591 ret = 0; 616 ret = 0;
592 617
593 } else if (use_browser == 2) { 618 } else if (use_browser == 2) {
594 perf_evlist__gtk_browse_hists(session->evlist, help, 619 int (*hist_browser)(struct perf_evlist *,
595 NULL, rep->min_percent); 620 const char *,
621 struct hist_browser_timer *,
622 float min_pcnt);
623
624 hist_browser = dlsym(perf_gtk_handle,
625 "perf_evlist__gtk_browse_hists");
626 if (hist_browser == NULL) {
627 ui__error("GTK browser not found!\n");
628 return ret;
629 }
630 hist_browser(session->evlist, help, NULL,
631 rep->min_percent);
596 } 632 }
597 } else 633 } else
598 perf_evlist__tty_browse_hists(session->evlist, rep, help); 634 perf_evlist__tty_browse_hists(session->evlist, rep, help);
@@ -757,6 +793,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
757 .ordered_samples = true, 793 .ordered_samples = true,
758 .ordering_requires_timestamps = true, 794 .ordering_requires_timestamps = true,
759 }, 795 },
796 .max_stack = PERF_MAX_STACK_DEPTH,
760 .pretty_printing_style = "normal", 797 .pretty_printing_style = "normal",
761 }; 798 };
762 const struct option options[] = { 799 const struct option options[] = {
@@ -787,7 +824,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
787 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," 824 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
788 " dso_to, dso_from, symbol_to, symbol_from, mispredict," 825 " dso_to, dso_from, symbol_to, symbol_from, mispredict,"
789 " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, " 826 " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, "
790 "snoop, locked"), 827 "snoop, locked, abort, in_tx, transaction"),
791 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 828 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
792 "Show sample percentage for different cpu modes"), 829 "Show sample percentage for different cpu modes"),
793 OPT_STRING('p', "parent", &parent_pattern, "regex", 830 OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -797,6 +834,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
797 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", 834 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
798 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). " 835 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
799 "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt), 836 "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt),
837 OPT_INTEGER(0, "max-stack", &report.max_stack,
838 "Set the maximum stack depth when parsing the callchain, "
839 "anything beyond the specified depth will be ignored. "
840 "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
800 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, 841 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
801 "alias for inverted call graph"), 842 "alias for inverted call graph"),
802 OPT_CALLBACK(0, "ignore-callees", NULL, "regex", 843 OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
@@ -845,6 +886,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
845 "Don't show entries under that percent", parse_percent_limit), 886 "Don't show entries under that percent", parse_percent_limit),
846 OPT_END() 887 OPT_END()
847 }; 888 };
889 struct perf_data_file file = {
890 .mode = PERF_DATA_MODE_READ,
891 };
848 892
849 perf_config(perf_report_config, &report); 893 perf_config(perf_report_config, &report);
850 894
@@ -867,16 +911,11 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
867 input_name = "perf.data"; 911 input_name = "perf.data";
868 } 912 }
869 913
870 if (strcmp(input_name, "-") != 0) 914 file.path = input_name;
871 setup_browser(true); 915 file.force = report.force;
872 else {
873 use_browser = 0;
874 perf_hpp__init();
875 }
876 916
877repeat: 917repeat:
878 session = perf_session__new(input_name, O_RDONLY, 918 session = perf_session__new(&file, false, &report.tool);
879 report.force, false, &report.tool);
880 if (session == NULL) 919 if (session == NULL)
881 return -ENOMEM; 920 return -ENOMEM;
882 921
@@ -914,8 +953,22 @@ repeat:
914 sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; 953 sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
915 } 954 }
916 955
917 if (setup_sorting() < 0) 956 if (setup_sorting() < 0) {
918 usage_with_options(report_usage, options); 957 parse_options_usage(report_usage, options, "s", 1);
958 goto error;
959 }
960
961 if (parent_pattern != default_parent_pattern) {
962 if (sort_dimension__add("parent") < 0)
963 goto error;
964 }
965
966 if (strcmp(input_name, "-") != 0)
967 setup_browser(true);
968 else {
969 use_browser = 0;
970 perf_hpp__init();
971 }
919 972
920 /* 973 /*
921 * Only in the TUI browser we are doing integrated annotation, 974 * Only in the TUI browser we are doing integrated annotation,
@@ -946,11 +999,6 @@ repeat:
946 if (symbol__init() < 0) 999 if (symbol__init() < 0)
947 goto error; 1000 goto error;
948 1001
949 if (parent_pattern != default_parent_pattern) {
950 if (sort_dimension__add("parent") < 0)
951 goto error;
952 }
953
954 if (argc) { 1002 if (argc) {
955 /* 1003 /*
956 * Special case: if there's an argument left then assume that 1004 * Special case: if there's an argument left then assume that