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.c415
1 files changed, 187 insertions, 228 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 8cf8e66ba594..02f985f3a396 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -39,7 +39,7 @@
39#include <dlfcn.h> 39#include <dlfcn.h>
40#include <linux/bitmap.h> 40#include <linux/bitmap.h>
41 41
42struct perf_report { 42struct report {
43 struct perf_tool tool; 43 struct perf_tool tool;
44 struct perf_session *session; 44 struct perf_session *session;
45 bool force, use_tui, use_gtk, use_stdio; 45 bool force, use_tui, use_gtk, use_stdio;
@@ -49,6 +49,8 @@ struct perf_report {
49 bool show_threads; 49 bool show_threads;
50 bool inverted_callchain; 50 bool inverted_callchain;
51 bool mem_mode; 51 bool mem_mode;
52 bool header;
53 bool header_only;
52 int max_stack; 54 int max_stack;
53 struct perf_read_values show_threads_values; 55 struct perf_read_values show_threads_values;
54 const char *pretty_printing_style; 56 const char *pretty_printing_style;
@@ -58,14 +60,14 @@ struct perf_report {
58 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 60 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
59}; 61};
60 62
61static int perf_report_config(const char *var, const char *value, void *cb) 63static int report__config(const char *var, const char *value, void *cb)
62{ 64{
63 if (!strcmp(var, "report.group")) { 65 if (!strcmp(var, "report.group")) {
64 symbol_conf.event_group = perf_config_bool(var, value); 66 symbol_conf.event_group = perf_config_bool(var, value);
65 return 0; 67 return 0;
66 } 68 }
67 if (!strcmp(var, "report.percent-limit")) { 69 if (!strcmp(var, "report.percent-limit")) {
68 struct perf_report *rep = cb; 70 struct report *rep = cb;
69 rep->min_percent = strtof(value, NULL); 71 rep->min_percent = strtof(value, NULL);
70 return 0; 72 return 0;
71 } 73 }
@@ -73,31 +75,22 @@ static int perf_report_config(const char *var, const char *value, void *cb)
73 return perf_default_config(var, value, cb); 75 return perf_default_config(var, value, cb);
74} 76}
75 77
76static int perf_report__add_mem_hist_entry(struct perf_tool *tool, 78static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_location *al,
77 struct addr_location *al, 79 struct perf_sample *sample, struct perf_evsel *evsel,
78 struct perf_sample *sample, 80 union perf_event *event)
79 struct perf_evsel *evsel,
80 struct machine *machine,
81 union perf_event *event)
82{ 81{
83 struct perf_report *rep = container_of(tool, struct perf_report, tool); 82 struct report *rep = container_of(tool, struct report, tool);
84 struct symbol *parent = NULL; 83 struct symbol *parent = NULL;
85 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 84 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
86 int err = 0;
87 struct hist_entry *he; 85 struct hist_entry *he;
88 struct mem_info *mi, *mx; 86 struct mem_info *mi, *mx;
89 uint64_t cost; 87 uint64_t cost;
88 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
90 89
91 if ((sort__has_parent || symbol_conf.use_callchain) && 90 if (err)
92 sample->callchain) { 91 return err;
93 err = machine__resolve_callchain(machine, evsel, al->thread,
94 sample, &parent, al,
95 rep->max_stack);
96 if (err)
97 return err;
98 }
99 92
100 mi = machine__resolve_mem(machine, al->thread, sample, cpumode); 93 mi = machine__resolve_mem(al->machine, al->thread, sample, cpumode);
101 if (!mi) 94 if (!mi)
102 return -ENOMEM; 95 return -ENOMEM;
103 96
@@ -120,77 +113,38 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
120 if (!he) 113 if (!he)
121 return -ENOMEM; 114 return -ENOMEM;
122 115
123 /* 116 if (ui__has_annotation()) {
124 * In the TUI browser, we are doing integrated annotation,
125 * so we don't allocate the extra space needed because the stdio
126 * code will not use it.
127 */
128 if (sort__has_sym && he->ms.sym && use_browser > 0) {
129 struct annotation *notes = symbol__annotation(he->ms.sym);
130
131 assert(evsel != NULL);
132
133 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
134 goto out;
135
136 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 117 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
137 if (err) 118 if (err)
138 goto out; 119 goto out;
139 }
140
141 if (sort__has_sym && he->mem_info->daddr.sym && use_browser > 0) {
142 struct annotation *notes;
143 120
144 mx = he->mem_info; 121 mx = he->mem_info;
145 122 err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
146 notes = symbol__annotation(mx->daddr.sym);
147 if (notes->src == NULL && symbol__alloc_hist(mx->daddr.sym) < 0)
148 goto out;
149
150 err = symbol__inc_addr_samples(mx->daddr.sym,
151 mx->daddr.map,
152 evsel->idx,
153 mx->daddr.al_addr);
154 if (err) 123 if (err)
155 goto out; 124 goto out;
156 } 125 }
157 126
158 evsel->hists.stats.total_period += cost; 127 evsel->hists.stats.total_period += cost;
159 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 128 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
160 err = 0; 129 err = hist_entry__append_callchain(he, sample);
161
162 if (symbol_conf.use_callchain) {
163 err = callchain_append(he->callchain,
164 &callchain_cursor,
165 sample->period);
166 }
167out: 130out:
168 return err; 131 return err;
169} 132}
170 133
171static int perf_report__add_branch_hist_entry(struct perf_tool *tool, 134static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_location *al,
172 struct addr_location *al, 135 struct perf_sample *sample, struct perf_evsel *evsel)
173 struct perf_sample *sample,
174 struct perf_evsel *evsel,
175 struct machine *machine)
176{ 136{
177 struct perf_report *rep = container_of(tool, struct perf_report, tool); 137 struct report *rep = container_of(tool, struct report, tool);
178 struct symbol *parent = NULL; 138 struct symbol *parent = NULL;
179 int err = 0;
180 unsigned i; 139 unsigned i;
181 struct hist_entry *he; 140 struct hist_entry *he;
182 struct branch_info *bi, *bx; 141 struct branch_info *bi, *bx;
142 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
183 143
184 if ((sort__has_parent || symbol_conf.use_callchain) 144 if (err)
185 && sample->callchain) { 145 return err;
186 err = machine__resolve_callchain(machine, evsel, al->thread,
187 sample, &parent, al,
188 rep->max_stack);
189 if (err)
190 return err;
191 }
192 146
193 bi = machine__resolve_bstack(machine, al->thread, 147 bi = machine__resolve_bstack(al->machine, al->thread,
194 sample->branch_stack); 148 sample->branch_stack);
195 if (!bi) 149 if (!bi)
196 return -ENOMEM; 150 return -ENOMEM;
@@ -212,35 +166,19 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
212 he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL, 166 he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
213 1, 1, 0); 167 1, 1, 0);
214 if (he) { 168 if (he) {
215 struct annotation *notes; 169 if (ui__has_annotation()) {
216 bx = he->branch_info; 170 bx = he->branch_info;
217 if (bx->from.sym && use_browser == 1 && sort__has_sym) { 171 err = addr_map_symbol__inc_samples(&bx->from,
218 notes = symbol__annotation(bx->from.sym); 172 evsel->idx);
219 if (!notes->src
220 && symbol__alloc_hist(bx->from.sym) < 0)
221 goto out;
222
223 err = symbol__inc_addr_samples(bx->from.sym,
224 bx->from.map,
225 evsel->idx,
226 bx->from.al_addr);
227 if (err) 173 if (err)
228 goto out; 174 goto out;
229 }
230 175
231 if (bx->to.sym && use_browser == 1 && sort__has_sym) { 176 err = addr_map_symbol__inc_samples(&bx->to,
232 notes = symbol__annotation(bx->to.sym); 177 evsel->idx);
233 if (!notes->src
234 && symbol__alloc_hist(bx->to.sym) < 0)
235 goto out;
236
237 err = symbol__inc_addr_samples(bx->to.sym,
238 bx->to.map,
239 evsel->idx,
240 bx->to.al_addr);
241 if (err) 178 if (err)
242 goto out; 179 goto out;
243 } 180 }
181
244 evsel->hists.stats.total_period += 1; 182 evsel->hists.stats.total_period += 1;
245 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 183 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
246 } else 184 } else
@@ -252,24 +190,16 @@ out:
252 return err; 190 return err;
253} 191}
254 192
255static int perf_evsel__add_hist_entry(struct perf_tool *tool, 193static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evsel,
256 struct perf_evsel *evsel, 194 struct addr_location *al, struct perf_sample *sample)
257 struct addr_location *al,
258 struct perf_sample *sample,
259 struct machine *machine)
260{ 195{
261 struct perf_report *rep = container_of(tool, struct perf_report, tool); 196 struct report *rep = container_of(tool, struct report, tool);
262 struct symbol *parent = NULL; 197 struct symbol *parent = NULL;
263 int err = 0;
264 struct hist_entry *he; 198 struct hist_entry *he;
199 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
265 200
266 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 201 if (err)
267 err = machine__resolve_callchain(machine, evsel, al->thread, 202 return err;
268 sample, &parent, al,
269 rep->max_stack);
270 if (err)
271 return err;
272 }
273 203
274 he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL, 204 he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL,
275 sample->period, sample->weight, 205 sample->period, sample->weight,
@@ -277,29 +207,12 @@ static int perf_evsel__add_hist_entry(struct perf_tool *tool,
277 if (he == NULL) 207 if (he == NULL)
278 return -ENOMEM; 208 return -ENOMEM;
279 209
280 if (symbol_conf.use_callchain) { 210 err = hist_entry__append_callchain(he, sample);
281 err = callchain_append(he->callchain, 211 if (err)
282 &callchain_cursor, 212 goto out;
283 sample->period);
284 if (err)
285 return err;
286 }
287 /*
288 * Only in the TUI browser we are doing integrated annotation,
289 * so we don't allocated the extra space needed because the stdio
290 * code will not use it.
291 */
292 if (he->ms.sym != NULL && use_browser == 1 && sort__has_sym) {
293 struct annotation *notes = symbol__annotation(he->ms.sym);
294
295 assert(evsel != NULL);
296
297 err = -ENOMEM;
298 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
299 goto out;
300 213
214 if (ui__has_annotation())
301 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 215 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
302 }
303 216
304 evsel->hists.stats.total_period += sample->period; 217 evsel->hists.stats.total_period += sample->period;
305 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 218 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
@@ -314,13 +227,13 @@ static int process_sample_event(struct perf_tool *tool,
314 struct perf_evsel *evsel, 227 struct perf_evsel *evsel,
315 struct machine *machine) 228 struct machine *machine)
316{ 229{
317 struct perf_report *rep = container_of(tool, struct perf_report, tool); 230 struct report *rep = container_of(tool, struct report, tool);
318 struct addr_location al; 231 struct addr_location al;
319 int ret; 232 int ret;
320 233
321 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 234 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
322 fprintf(stderr, "problem processing %d event, skipping it.\n", 235 pr_debug("problem processing %d event, skipping it.\n",
323 event->header.type); 236 event->header.type);
324 return -1; 237 return -1;
325 } 238 }
326 239
@@ -331,21 +244,18 @@ static int process_sample_event(struct perf_tool *tool,
331 return 0; 244 return 0;
332 245
333 if (sort__mode == SORT_MODE__BRANCH) { 246 if (sort__mode == SORT_MODE__BRANCH) {
334 ret = perf_report__add_branch_hist_entry(tool, &al, sample, 247 ret = report__add_branch_hist_entry(tool, &al, sample, evsel);
335 evsel, machine);
336 if (ret < 0) 248 if (ret < 0)
337 pr_debug("problem adding lbr entry, skipping event\n"); 249 pr_debug("problem adding lbr entry, skipping event\n");
338 } else if (rep->mem_mode == 1) { 250 } else if (rep->mem_mode == 1) {
339 ret = perf_report__add_mem_hist_entry(tool, &al, sample, 251 ret = report__add_mem_hist_entry(tool, &al, sample, evsel, event);
340 evsel, machine, event);
341 if (ret < 0) 252 if (ret < 0)
342 pr_debug("problem adding mem entry, skipping event\n"); 253 pr_debug("problem adding mem entry, skipping event\n");
343 } else { 254 } else {
344 if (al.map != NULL) 255 if (al.map != NULL)
345 al.map->dso->hit = 1; 256 al.map->dso->hit = 1;
346 257
347 ret = perf_evsel__add_hist_entry(tool, evsel, &al, sample, 258 ret = report__add_hist_entry(tool, evsel, &al, sample);
348 machine);
349 if (ret < 0) 259 if (ret < 0)
350 pr_debug("problem incrementing symbol period, skipping event\n"); 260 pr_debug("problem incrementing symbol period, skipping event\n");
351 } 261 }
@@ -358,7 +268,7 @@ static int process_read_event(struct perf_tool *tool,
358 struct perf_evsel *evsel, 268 struct perf_evsel *evsel,
359 struct machine *machine __maybe_unused) 269 struct machine *machine __maybe_unused)
360{ 270{
361 struct perf_report *rep = container_of(tool, struct perf_report, tool); 271 struct report *rep = container_of(tool, struct report, tool);
362 272
363 if (rep->show_threads) { 273 if (rep->show_threads) {
364 const char *name = evsel ? perf_evsel__name(evsel) : "unknown"; 274 const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
@@ -377,7 +287,7 @@ static int process_read_event(struct perf_tool *tool,
377} 287}
378 288
379/* For pipe mode, sample_type is not currently set */ 289/* For pipe mode, sample_type is not currently set */
380static int perf_report__setup_sample_type(struct perf_report *rep) 290static int report__setup_sample_type(struct report *rep)
381{ 291{
382 struct perf_session *session = rep->session; 292 struct perf_session *session = rep->session;
383 u64 sample_type = perf_evlist__combined_sample_type(session->evlist); 293 u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
@@ -422,8 +332,7 @@ static void sig_handler(int sig __maybe_unused)
422 session_done = 1; 332 session_done = 1;
423} 333}
424 334
425static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, 335static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep,
426 struct hists *hists,
427 const char *evname, FILE *fp) 336 const char *evname, FILE *fp)
428{ 337{
429 size_t ret; 338 size_t ret;
@@ -460,12 +369,12 @@ static size_t hists__fprintf_nr_sample_events(struct perf_report *rep,
460} 369}
461 370
462static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, 371static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
463 struct perf_report *rep, 372 struct report *rep,
464 const char *help) 373 const char *help)
465{ 374{
466 struct perf_evsel *pos; 375 struct perf_evsel *pos;
467 376
468 list_for_each_entry(pos, &evlist->entries, node) { 377 evlist__for_each(evlist, pos) {
469 struct hists *hists = &pos->hists; 378 struct hists *hists = &pos->hists;
470 const char *evname = perf_evsel__name(pos); 379 const char *evname = perf_evsel__name(pos);
471 380
@@ -473,7 +382,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
473 !perf_evsel__is_group_leader(pos)) 382 !perf_evsel__is_group_leader(pos))
474 continue; 383 continue;
475 384
476 hists__fprintf_nr_sample_events(rep, hists, evname, stdout); 385 hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
477 hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout); 386 hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
478 fprintf(stdout, "\n\n"); 387 fprintf(stdout, "\n\n");
479 } 388 }
@@ -493,43 +402,11 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
493 return 0; 402 return 0;
494} 403}
495 404
496static int __cmd_report(struct perf_report *rep) 405static void report__warn_kptr_restrict(const struct report *rep)
497{ 406{
498 int ret = -EINVAL; 407 struct map *kernel_map = rep->session->machines.host.vmlinux_maps[MAP__FUNCTION];
499 u64 nr_samples; 408 struct kmap *kernel_kmap = map__kmap(kernel_map);
500 struct perf_session *session = rep->session;
501 struct perf_evsel *pos;
502 struct map *kernel_map;
503 struct kmap *kernel_kmap;
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;
507
508 signal(SIGINT, sig_handler);
509
510 if (rep->cpu_list) {
511 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
512 rep->cpu_bitmap);
513 if (ret)
514 return ret;
515 }
516 409
517 if (use_browser <= 0)
518 perf_session__fprintf_info(session, stdout, rep->show_full_info);
519
520 if (rep->show_threads)
521 perf_read_values_init(&rep->show_threads_values);
522
523 ret = perf_report__setup_sample_type(rep);
524 if (ret)
525 return ret;
526
527 ret = perf_session__process_events(session, &rep->tool);
528 if (ret)
529 return ret;
530
531 kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
532 kernel_kmap = map__kmap(kernel_map);
533 if (kernel_map == NULL || 410 if (kernel_map == NULL ||
534 (kernel_map->dso->hit && 411 (kernel_map->dso->hit &&
535 (kernel_kmap->ref_reloc_sym == NULL || 412 (kernel_kmap->ref_reloc_sym == NULL ||
@@ -552,26 +429,73 @@ static int __cmd_report(struct perf_report *rep)
552"Samples in kernel modules can't be resolved as well.\n\n", 429"Samples in kernel modules can't be resolved as well.\n\n",
553 desc); 430 desc);
554 } 431 }
432}
555 433
556 if (verbose > 3) 434static int report__gtk_browse_hists(struct report *rep, const char *help)
557 perf_session__fprintf(session, stdout); 435{
436 int (*hist_browser)(struct perf_evlist *evlist, const char *help,
437 struct hist_browser_timer *timer, float min_pcnt);
558 438
559 if (verbose > 2) 439 hist_browser = dlsym(perf_gtk_handle, "perf_evlist__gtk_browse_hists");
560 perf_session__fprintf_dsos(session, stdout);
561 440
562 if (dump_trace) { 441 if (hist_browser == NULL) {
563 perf_session__fprintf_nr_events(session, stdout); 442 ui__error("GTK browser not found!\n");
564 return 0; 443 return -1;
565 } 444 }
566 445
567 nr_samples = 0; 446 return hist_browser(rep->session->evlist, help, NULL, rep->min_percent);
568 list_for_each_entry(pos, &session->evlist->entries, node) 447}
448
449static int report__browse_hists(struct report *rep)
450{
451 int ret;
452 struct perf_session *session = rep->session;
453 struct perf_evlist *evlist = session->evlist;
454 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
455
456 switch (use_browser) {
457 case 1:
458 ret = perf_evlist__tui_browse_hists(evlist, help, NULL,
459 rep->min_percent,
460 &session->header.env);
461 /*
462 * Usually "ret" is the last pressed key, and we only
463 * care if the key notifies us to switch data file.
464 */
465 if (ret != K_SWITCH_INPUT_DATA)
466 ret = 0;
467 break;
468 case 2:
469 ret = report__gtk_browse_hists(rep, help);
470 break;
471 default:
472 ret = perf_evlist__tty_browse_hists(evlist, rep, help);
473 break;
474 }
475
476 return ret;
477}
478
479static u64 report__collapse_hists(struct report *rep)
480{
481 struct ui_progress prog;
482 struct perf_evsel *pos;
483 u64 nr_samples = 0;
484 /*
485 * Count number of histogram entries to use when showing progress,
486 * reusing nr_samples variable.
487 */
488 evlist__for_each(rep->session->evlist, pos)
569 nr_samples += pos->hists.nr_entries; 489 nr_samples += pos->hists.nr_entries;
570 490
571 ui_progress__init(&prog, nr_samples, "Merging related events..."); 491 ui_progress__init(&prog, nr_samples, "Merging related events...");
572 492 /*
493 * Count total number of samples, will be used to check if this
494 * session had any.
495 */
573 nr_samples = 0; 496 nr_samples = 0;
574 list_for_each_entry(pos, &session->evlist->entries, node) { 497
498 evlist__for_each(rep->session->evlist, pos) {
575 struct hists *hists = &pos->hists; 499 struct hists *hists = &pos->hists;
576 500
577 if (pos->idx == 0) 501 if (pos->idx == 0)
@@ -589,8 +513,57 @@ static int __cmd_report(struct perf_report *rep)
589 hists__link(leader_hists, hists); 513 hists__link(leader_hists, hists);
590 } 514 }
591 } 515 }
516
592 ui_progress__finish(); 517 ui_progress__finish();
593 518
519 return nr_samples;
520}
521
522static int __cmd_report(struct report *rep)
523{
524 int ret;
525 u64 nr_samples;
526 struct perf_session *session = rep->session;
527 struct perf_evsel *pos;
528 struct perf_data_file *file = session->file;
529
530 signal(SIGINT, sig_handler);
531
532 if (rep->cpu_list) {
533 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
534 rep->cpu_bitmap);
535 if (ret)
536 return ret;
537 }
538
539 if (rep->show_threads)
540 perf_read_values_init(&rep->show_threads_values);
541
542 ret = report__setup_sample_type(rep);
543 if (ret)
544 return ret;
545
546 ret = perf_session__process_events(session, &rep->tool);
547 if (ret)
548 return ret;
549
550 report__warn_kptr_restrict(rep);
551
552 if (use_browser == 0) {
553 if (verbose > 3)
554 perf_session__fprintf(session, stdout);
555
556 if (verbose > 2)
557 perf_session__fprintf_dsos(session, stdout);
558
559 if (dump_trace) {
560 perf_session__fprintf_nr_events(session, stdout);
561 return 0;
562 }
563 }
564
565 nr_samples = report__collapse_hists(rep);
566
594 if (session_done()) 567 if (session_done())
595 return 0; 568 return 0;
596 569
@@ -599,47 +572,16 @@ static int __cmd_report(struct perf_report *rep)
599 return 0; 572 return 0;
600 } 573 }
601 574
602 list_for_each_entry(pos, &session->evlist->entries, node) 575 evlist__for_each(session->evlist, pos)
603 hists__output_resort(&pos->hists); 576 hists__output_resort(&pos->hists);
604 577
605 if (use_browser > 0) { 578 return report__browse_hists(rep);
606 if (use_browser == 1) {
607 ret = perf_evlist__tui_browse_hists(session->evlist,
608 help, NULL,
609 rep->min_percent,
610 &session->header.env);
611 /*
612 * Usually "ret" is the last pressed key, and we only
613 * care if the key notifies us to switch data file.
614 */
615 if (ret != K_SWITCH_INPUT_DATA)
616 ret = 0;
617
618 } else if (use_browser == 2) {
619 int (*hist_browser)(struct perf_evlist *,
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);
632 }
633 } else
634 perf_evlist__tty_browse_hists(session->evlist, rep, help);
635
636 return ret;
637} 579}
638 580
639static int 581static int
640parse_callchain_opt(const struct option *opt, const char *arg, int unset) 582parse_callchain_opt(const struct option *opt, const char *arg, int unset)
641{ 583{
642 struct perf_report *rep = (struct perf_report *)opt->value; 584 struct report *rep = (struct report *)opt->value;
643 char *tok, *tok2; 585 char *tok, *tok2;
644 char *endptr; 586 char *endptr;
645 587
@@ -721,7 +663,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
721 return -1; 663 return -1;
722setup: 664setup:
723 if (callchain_register_param(&callchain_param) < 0) { 665 if (callchain_register_param(&callchain_param) < 0) {
724 fprintf(stderr, "Can't register callchain params\n"); 666 pr_err("Can't register callchain params\n");
725 return -1; 667 return -1;
726 } 668 }
727 return 0; 669 return 0;
@@ -759,7 +701,7 @@ static int
759parse_percent_limit(const struct option *opt, const char *str, 701parse_percent_limit(const struct option *opt, const char *str,
760 int unset __maybe_unused) 702 int unset __maybe_unused)
761{ 703{
762 struct perf_report *rep = opt->value; 704 struct report *rep = opt->value;
763 705
764 rep->min_percent = strtof(str, NULL); 706 rep->min_percent = strtof(str, NULL);
765 return 0; 707 return 0;
@@ -777,7 +719,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
777 "perf report [<options>]", 719 "perf report [<options>]",
778 NULL 720 NULL
779 }; 721 };
780 struct perf_report report = { 722 struct report report = {
781 .tool = { 723 .tool = {
782 .sample = process_sample_event, 724 .sample = process_sample_event,
783 .mmap = perf_event__process_mmap, 725 .mmap = perf_event__process_mmap,
@@ -820,6 +762,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
820 OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"), 762 OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
821 OPT_BOOLEAN(0, "stdio", &report.use_stdio, 763 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
822 "Use the stdio interface"), 764 "Use the stdio interface"),
765 OPT_BOOLEAN(0, "header", &report.header, "Show data header."),
766 OPT_BOOLEAN(0, "header-only", &report.header_only,
767 "Show only data header."),
823 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 768 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
824 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," 769 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
825 " dso_to, dso_from, symbol_to, symbol_from, mispredict," 770 " dso_to, dso_from, symbol_to, symbol_from, mispredict,"
@@ -890,7 +835,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
890 .mode = PERF_DATA_MODE_READ, 835 .mode = PERF_DATA_MODE_READ,
891 }; 836 };
892 837
893 perf_config(perf_report_config, &report); 838 perf_config(report__config, &report);
894 839
895 argc = parse_options(argc, argv, options, report_usage, 0); 840 argc = parse_options(argc, argv, options, report_usage, 0);
896 841
@@ -940,7 +885,7 @@ repeat:
940 } 885 }
941 if (report.mem_mode) { 886 if (report.mem_mode) {
942 if (sort__mode == SORT_MODE__BRANCH) { 887 if (sort__mode == SORT_MODE__BRANCH) {
943 fprintf(stderr, "branch and mem mode incompatible\n"); 888 pr_err("branch and mem mode incompatible\n");
944 goto error; 889 goto error;
945 } 890 }
946 sort__mode = SORT_MODE__MEMORY; 891 sort__mode = SORT_MODE__MEMORY;
@@ -963,6 +908,10 @@ repeat:
963 goto error; 908 goto error;
964 } 909 }
965 910
911 /* Force tty output for header output. */
912 if (report.header || report.header_only)
913 use_browser = 0;
914
966 if (strcmp(input_name, "-") != 0) 915 if (strcmp(input_name, "-") != 0)
967 setup_browser(true); 916 setup_browser(true);
968 else { 917 else {
@@ -970,6 +919,16 @@ repeat:
970 perf_hpp__init(); 919 perf_hpp__init();
971 } 920 }
972 921
922 if (report.header || report.header_only) {
923 perf_session__fprintf_info(session, stdout,
924 report.show_full_info);
925 if (report.header_only)
926 return 0;
927 } else if (use_browser == 0) {
928 fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
929 stdout);
930 }
931
973 /* 932 /*
974 * Only in the TUI browser we are doing integrated annotation, 933 * Only in the TUI browser we are doing integrated annotation,
975 * so don't allocate extra space that won't be used in the stdio 934 * so don't allocate extra space that won't be used in the stdio