builtin-report.c 27.4 KB
Newer Older
1 2 3 4 5 6 7
/*
 * builtin-report.c
 *
 * Builtin report command: Analyze the perf.data input file,
 * look up and read DSOs and symbol information and display
 * a histogram of results, along various sorting keys.
 */
8
#include "builtin.h"
9

10
#include "util/util.h"
11
#include "util/cache.h"
12

13
#include "util/annotate.h"
14
#include "util/color.h"
15
#include <linux/list.h>
16
#include <linux/rbtree.h>
17
#include "util/symbol.h"
18
#include "util/callchain.h"
19
#include "util/strlist.h"
20
#include "util/values.h"
21

22
#include "perf.h"
23
#include "util/debug.h"
24 25
#include "util/evlist.h"
#include "util/evsel.h"
26
#include "util/header.h"
27
#include "util/session.h"
28
#include "util/tool.h"
29 30 31 32

#include "util/parse-options.h"
#include "util/parse-events.h"

33
#include "util/thread.h"
34
#include "util/sort.h"
35
#include "util/hist.h"
36
#include "util/data.h"
37
#include "arch/common.h"
38

39
#include <dlfcn.h>
40 41
#include <linux/bitmap.h>

42
struct report {
43
	struct perf_tool	tool;
44
	struct perf_session	*session;
45
	bool			force, use_tui, use_gtk, use_stdio;
46 47 48 49 50
	bool			hide_unresolved;
	bool			dont_use_callchains;
	bool			show_full_info;
	bool			show_threads;
	bool			inverted_callchain;
51
	bool			mem_mode;
52 53
	bool			header;
	bool			header_only;
54
	int			max_stack;
55 56 57
	struct perf_read_values	show_threads_values;
	const char		*pretty_printing_style;
	const char		*cpu_list;
58
	const char		*symbol_filter_str;
59
	float			min_percent;
60
	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
61
};
62

63
static int report__config(const char *var, const char *value, void *cb)
64 65 66 67 68
{
	if (!strcmp(var, "report.group")) {
		symbol_conf.event_group = perf_config_bool(var, value);
		return 0;
	}
69
	if (!strcmp(var, "report.percent-limit")) {
70
		struct report *rep = cb;
71 72 73
		rep->min_percent = strtof(value, NULL);
		return 0;
	}
74 75 76 77

	return perf_default_config(var, value, cb);
}

78
static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al,
79
				      struct perf_sample *sample, struct perf_evsel *evsel)
80 81 82 83 84
{
	struct symbol *parent = NULL;
	struct hist_entry *he;
	struct mem_info *mi, *mx;
	uint64_t cost;
85
	int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
86

87 88
	if (err)
		return err;
89

90
	mi = sample__resolve_mem(sample, al);
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
	if (!mi)
		return -ENOMEM;

	if (rep->hide_unresolved && !al->sym)
		return 0;

	cost = sample->weight;
	if (!cost)
		cost = 1;

	/*
	 * must pass period=weight in order to get the correct
	 * sorting from hists__collapse_resort() which is solely
	 * based on periods. We want sorting be done on nr_events * weight
	 * and this is indirectly achieved by passing period=weight here
	 * and the he_stat__add_period() function.
	 */
108 109
	he = __hists__add_entry(&evsel->hists, al, parent, NULL, mi,
				cost, cost, 0);
110 111 112
	if (!he)
		return -ENOMEM;

113 114 115 116
	if (ui__has_annotation()) {
		err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
		if (err)
			goto out;
117

118 119 120 121 122
		mx = he->mem_info;
		err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
		if (err)
			goto out;
	}
123 124 125

	evsel->hists.stats.total_period += cost;
	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
126 127
	if (!he->filtered)
		evsel->hists.stats.nr_non_filtered_samples++;
128
	err = hist_entry__append_callchain(he, sample);
129 130 131 132
out:
	return err;
}

133
static int report__add_branch_hist_entry(struct report *rep, struct addr_location *al,
134
					 struct perf_sample *sample, struct perf_evsel *evsel)
135 136 137 138
{
	struct symbol *parent = NULL;
	unsigned i;
	struct hist_entry *he;
139
	struct branch_info *bi, *bx;
140
	int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
141

142 143
	if (err)
		return err;
144

145
	bi = sample__resolve_bstack(sample, al);
146 147 148 149 150 151
	if (!bi)
		return -ENOMEM;

	for (i = 0; i < sample->branch_stack->nr; i++) {
		if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
			continue;
152 153 154

		err = -ENOMEM;

155 156 157 158
		/* overwrite the 'al' to branch-to info */
		al->map = bi[i].to.map;
		al->sym = bi[i].to.sym;
		al->addr = bi[i].to.addr;
159 160 161 162
		/*
		 * The report shows the percentage of total branches captured
		 * and not events sampled. Thus we use a pseudo period of 1.
		 */
163 164
		he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
					1, 1, 0);
165
		if (he) {
166 167 168 169 170 171 172 173 174 175 176 177
			if (ui__has_annotation()) {
				bx = he->branch_info;
				err = addr_map_symbol__inc_samples(&bx->from,
								   evsel->idx);
				if (err)
					goto out;

				err = addr_map_symbol__inc_samples(&bx->to,
								   evsel->idx);
				if (err)
					goto out;
			}
178

179 180
			evsel->hists.stats.total_period += 1;
			hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
181 182
			if (!he->filtered)
				evsel->hists.stats.nr_non_filtered_samples++;
183
		} else
184
			goto out;
185
	}
186
	err = 0;
187
out:
188
	free(bi);
189 190 191
	return err;
}

192
static int report__add_hist_entry(struct report *rep, struct perf_evsel *evsel,
193
				  struct addr_location *al, struct perf_sample *sample)
194
{
195
	struct symbol *parent = NULL;
196
	struct hist_entry *he;
197
	int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
198

199 200
	if (err)
		return err;
201

202 203 204
	he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL,
				sample->period, sample->weight,
				sample->transaction);
205
	if (he == NULL)
206 207
		return -ENOMEM;

208 209 210
	err = hist_entry__append_callchain(he, sample);
	if (err)
		goto out;
211

212 213 214
	if (ui__has_annotation())
		err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);

215
	evsel->hists.stats.total_period += sample->period;
216 217
	if (!he->filtered)
		evsel->hists.stats.nr_non_filtered_samples++;
218
	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
219
out:
220
	return err;
221 222
}

223

224
static int process_sample_event(struct perf_tool *tool,
225
				union perf_event *event,
226
				struct perf_sample *sample,
227
				struct perf_evsel *evsel,
228
				struct machine *machine)
229
{
230
	struct report *rep = container_of(tool, struct report, tool);
231
	struct addr_location al;
232
	int ret;
233

234
	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
235 236
		pr_debug("problem processing %d event, skipping it.\n",
			 event->header.type);
237 238
		return -1;
	}
239

240
	if (rep->hide_unresolved && al.sym == NULL)
241
		return 0;
242

243
	if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
244 245
		return 0;

246
	if (sort__mode == SORT_MODE__BRANCH) {
247
		ret = report__add_branch_hist_entry(rep, &al, sample, evsel);
248
		if (ret < 0)
249
			pr_debug("problem adding lbr entry, skipping event\n");
250
	} else if (rep->mem_mode == 1) {
251
		ret = report__add_mem_hist_entry(rep, &al, sample, evsel);
252
		if (ret < 0)
253
			pr_debug("problem adding mem entry, skipping event\n");
254 255 256
	} else {
		if (al.map != NULL)
			al.map->dso->hit = 1;
257

258
		ret = report__add_hist_entry(rep, evsel, &al, sample);
259
		if (ret < 0)
260
			pr_debug("problem incrementing symbol period, skipping event\n");
261
	}
262
	return ret;
263
}
I
Ingo Molnar 已提交
264

265
static int process_read_event(struct perf_tool *tool,
266
			      union perf_event *event,
267
			      struct perf_sample *sample __maybe_unused,
268
			      struct perf_evsel *evsel,
269
			      struct machine *machine __maybe_unused)
270
{
271
	struct report *rep = container_of(tool, struct report, tool);
272

273
	if (rep->show_threads) {
274
		const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
275
		perf_read_values_add_value(&rep->show_threads_values,
276 277 278 279 280 281
					   event->read.pid, event->read.tid,
					   event->read.id,
					   name,
					   event->read.value);
	}

282
	dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
283
		    evsel ? perf_evsel__name(evsel) : "FAIL",
284
		    event->read.value);
285 286 287 288

	return 0;
}

289
/* For pipe mode, sample_type is not currently set */
290
static int report__setup_sample_type(struct report *rep)
291
{
292 293 294
	struct perf_session *session = rep->session;
	u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
	bool is_pipe = perf_data_file__is_pipe(session->file);
295

296
	if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
297
		if (sort__has_parent) {
298
			ui__error("Selected --sort parent, but no "
299 300
				    "callchain data. Did you call "
				    "'perf record' without -g?\n");
301
			return -EINVAL;
302
		}
303
		if (symbol_conf.use_callchain) {
304
			ui__error("Selected -g but no callchain data. Did "
305
				    "you call 'perf record' without -g?\n");
306
			return -1;
307
		}
308 309
	} else if (!rep->dont_use_callchains &&
		   callchain_param.mode != CHAIN_NONE &&
310
		   !symbol_conf.use_callchain) {
311
			symbol_conf.use_callchain = true;
312
			if (callchain_register_param(&callchain_param) < 0) {
313
				ui__error("Can't register callchain params.\n");
314
				return -EINVAL;
315
			}
316 317
	}

318
	if (sort__mode == SORT_MODE__BRANCH) {
319
		if (!is_pipe &&
320
		    !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
321 322
			ui__error("Selected -b but no branch data. "
				  "Did you call perf record without -b?\n");
323 324 325 326
			return -1;
		}
	}

327 328
	return 0;
}
329

330
static void sig_handler(int sig __maybe_unused)
331 332 333 334
{
	session_done = 1;
}

335
static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep,
336 337 338 339
					      const char *evname, FILE *fp)
{
	size_t ret;
	char unit;
340 341 342
	unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
	u64 nr_events = hists->stats.total_period;
	struct perf_evsel *evsel = hists_to_evsel(hists);
343 344 345
	char buf[512];
	size_t size = sizeof(buf);

346 347 348 349 350
	if (symbol_conf.filter_relative) {
		nr_samples = hists->stats.nr_non_filtered_samples;
		nr_events = hists->stats.total_non_filtered_period;
	}

351
	if (perf_evsel__is_group_event(evsel)) {
352 353 354 355 356 357
		struct perf_evsel *pos;

		perf_evsel__group_desc(evsel, buf, size);
		evname = buf;

		for_each_group_member(pos, evsel) {
358 359 360 361 362 363 364
			if (symbol_conf.filter_relative) {
				nr_samples += pos->hists.stats.nr_non_filtered_samples;
				nr_events += pos->hists.stats.total_non_filtered_period;
			} else {
				nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
				nr_events += pos->hists.stats.total_period;
			}
365 366
		}
	}
367

368 369
	nr_samples = convert_unit(nr_samples, &unit);
	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
370
	if (evname != NULL)
371 372
		ret += fprintf(fp, " of event '%s'", evname);

373 374 375 376 377
	if (rep->mem_mode) {
		ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events);
		ret += fprintf(fp, "\n# Sort order   : %s", sort_order);
	} else
		ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
378 379 380
	return ret + fprintf(fp, "\n#\n");
}

381
static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
382
					 struct report *rep,
383
					 const char *help)
384
{
385
	struct perf_evsel *pos;
386

387
	evlist__for_each(evlist, pos) {
388
		struct hists *hists = &pos->hists;
389
		const char *evname = perf_evsel__name(pos);
390

391 392 393 394
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos))
			continue;

395
		hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
396
		hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
397 398 399 400 401 402 403
		fprintf(stdout, "\n\n");
	}

	if (sort_order == default_sort_order &&
	    parent_pattern == default_parent_pattern) {
		fprintf(stdout, "#\n# (%s)\n#\n", help);

404 405 406
		if (rep->show_threads) {
			bool style = !strcmp(rep->pretty_printing_style, "raw");
			perf_read_values_display(stdout, &rep->show_threads_values,
407
						 style);
408
			perf_read_values_destroy(&rep->show_threads_values);
409 410 411 412 413 414
		}
	}

	return 0;
}

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
static void report__warn_kptr_restrict(const struct report *rep)
{
	struct map *kernel_map = rep->session->machines.host.vmlinux_maps[MAP__FUNCTION];
	struct kmap *kernel_kmap = map__kmap(kernel_map);

	if (kernel_map == NULL ||
	    (kernel_map->dso->hit &&
	     (kernel_kmap->ref_reloc_sym == NULL ||
	      kernel_kmap->ref_reloc_sym->addr == 0))) {
		const char *desc =
		    "As no suitable kallsyms nor vmlinux was found, kernel samples\n"
		    "can't be resolved.";

		if (kernel_map) {
			const struct dso *kdso = kernel_map->dso;
			if (!RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION])) {
				desc = "If some relocation was applied (e.g. "
				       "kexec) symbols may be misresolved.";
			}
		}

		ui__warning(
"Kernel address maps (/proc/{kallsyms,modules}) were restricted.\n\n"
"Check /proc/sys/kernel/kptr_restrict before running 'perf record'.\n\n%s\n\n"
"Samples in kernel modules can't be resolved as well.\n\n",
		desc);
	}
}

444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
static int report__gtk_browse_hists(struct report *rep, const char *help)
{
	int (*hist_browser)(struct perf_evlist *evlist, const char *help,
			    struct hist_browser_timer *timer, float min_pcnt);

	hist_browser = dlsym(perf_gtk_handle, "perf_evlist__gtk_browse_hists");

	if (hist_browser == NULL) {
		ui__error("GTK browser not found!\n");
		return -1;
	}

	return hist_browser(rep->session->evlist, help, NULL, rep->min_percent);
}

static int report__browse_hists(struct report *rep)
{
	int ret;
	struct perf_session *session = rep->session;
	struct perf_evlist *evlist = session->evlist;
	const char *help = "For a higher level overview, try: perf report --sort comm,dso";

	switch (use_browser) {
	case 1:
		ret = perf_evlist__tui_browse_hists(evlist, help, NULL,
						    rep->min_percent,
						    &session->header.env);
		/*
		 * Usually "ret" is the last pressed key, and we only
		 * care if the key notifies us to switch data file.
		 */
		if (ret != K_SWITCH_INPUT_DATA)
			ret = 0;
		break;
	case 2:
		ret = report__gtk_browse_hists(rep, help);
		break;
	default:
		ret = perf_evlist__tty_browse_hists(evlist, rep, help);
		break;
	}

	return ret;
}

489 490 491 492 493 494 495 496 497
static u64 report__collapse_hists(struct report *rep)
{
	struct ui_progress prog;
	struct perf_evsel *pos;
	u64 nr_samples = 0;
	/*
 	 * Count number of histogram entries to use when showing progress,
 	 * reusing nr_samples variable.
 	 */
498
	evlist__for_each(rep->session->evlist, pos)
499 500 501 502 503 504 505 506 507
		nr_samples += pos->hists.nr_entries;

	ui_progress__init(&prog, nr_samples, "Merging related events...");
	/*
	 * Count total number of samples, will be used to check if this
 	 * session had any.
 	 */
	nr_samples = 0;

508
	evlist__for_each(rep->session->evlist, pos) {
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
		struct hists *hists = &pos->hists;

		if (pos->idx == 0)
			hists->symbol_filter_str = rep->symbol_filter_str;

		hists__collapse_resort(hists, &prog);
		nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];

		/* Non-group events are considered as leader */
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos)) {
			struct hists *leader_hists = &pos->leader->hists;

			hists__match(leader_hists, hists);
			hists__link(leader_hists, hists);
		}
	}

	ui_progress__finish();

	return nr_samples;
}

532
static int __cmd_report(struct report *rep)
533
{
534
	int ret;
535
	u64 nr_samples;
536
	struct perf_session *session = rep->session;
537
	struct perf_evsel *pos;
538
	struct perf_data_file *file = session->file;
539

540 541
	signal(SIGINT, sig_handler);

542 543 544
	if (rep->cpu_list) {
		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
					       rep->cpu_bitmap);
545
		if (ret)
546
			return ret;
547 548
	}

549 550
	if (rep->show_threads)
		perf_read_values_init(&rep->show_threads_values);
551

552
	ret = report__setup_sample_type(rep);
553
	if (ret)
554
		return ret;
555

556
	ret = perf_session__process_events(session, &rep->tool);
557
	if (ret)
558
		return ret;
559

560
	report__warn_kptr_restrict(rep);
561

562 563 564
	if (use_browser == 0) {
		if (verbose > 3)
			perf_session__fprintf(session, stdout);
565

566 567
		if (verbose > 2)
			perf_session__fprintf_dsos(session, stdout);
568

569 570 571 572
		if (dump_trace) {
			perf_session__fprintf_nr_events(session, stdout);
			return 0;
		}
573 574
	}

575
	nr_samples = report__collapse_hists(rep);
576

577 578 579
	if (session_done())
		return 0;

580
	if (nr_samples == 0) {
581
		ui__error("The %s file has no samples!\n", file->path);
582
		return 0;
583 584
	}

585
	evlist__for_each(session->evlist, pos)
586 587
		hists__output_resort(&pos->hists);

588
	return report__browse_hists(rep);
589 590
}

591
static int
592
parse_callchain_opt(const struct option *opt, const char *arg, int unset)
593
{
594
	struct report *rep = (struct report *)opt->value;
595
	char *tok, *tok2;
596 597
	char *endptr;

598 599 600 601
	/*
	 * --no-call-graph
	 */
	if (unset) {
602
		rep->dont_use_callchains = true;
603 604 605
		return 0;
	}

606
	symbol_conf.use_callchain = true;
607 608 609 610

	if (!arg)
		return 0;

611 612 613 614 615 616
	tok = strtok((char *)arg, ",");
	if (!tok)
		return -1;

	/* get the output mode */
	if (!strncmp(tok, "graph", strlen(arg)))
617
		callchain_param.mode = CHAIN_GRAPH_ABS;
618

619
	else if (!strncmp(tok, "flat", strlen(arg)))
620 621 622 623 624
		callchain_param.mode = CHAIN_FLAT;

	else if (!strncmp(tok, "fractal", strlen(arg)))
		callchain_param.mode = CHAIN_GRAPH_REL;

625 626
	else if (!strncmp(tok, "none", strlen(arg))) {
		callchain_param.mode = CHAIN_NONE;
627
		symbol_conf.use_callchain = false;
628 629 630 631

		return 0;
	}

632 633 634
	else
		return -1;

635 636 637
	/* get the min percentage */
	tok = strtok(NULL, ",");
	if (!tok)
638
		goto setup;
639

640
	callchain_param.min_percent = strtod(tok, &endptr);
641 642 643
	if (tok == endptr)
		return -1;

644 645 646 647 648 649
	/* get the print limit */
	tok2 = strtok(NULL, ",");
	if (!tok2)
		goto setup;

	if (tok2[0] != 'c') {
650
		callchain_param.print_limit = strtoul(tok2, &endptr, 0);
651 652 653 654 655 656
		tok2 = strtok(NULL, ",");
		if (!tok2)
			goto setup;
	}

	/* get the call chain order */
657
	if (!strncmp(tok2, "caller", strlen("caller")))
658
		callchain_param.order = ORDER_CALLER;
659
	else if (!strncmp(tok2, "callee", strlen("callee")))
660 661 662
		callchain_param.order = ORDER_CALLEE;
	else
		return -1;
663 664 665 666 667 668 669 670 671 672 673

	/* Get the sort key */
	tok2 = strtok(NULL, ",");
	if (!tok2)
		goto setup;
	if (!strncmp(tok2, "function", strlen("function")))
		callchain_param.key = CCKEY_FUNCTION;
	else if (!strncmp(tok2, "address", strlen("address")))
		callchain_param.key = CCKEY_ADDRESS;
	else
		return -1;
674
setup:
675
	if (callchain_register_param(&callchain_param) < 0) {
676
		pr_err("Can't register callchain params\n");
677 678
		return -1;
	}
679 680 681
	return 0;
}

682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
int
report_parse_ignore_callees_opt(const struct option *opt __maybe_unused,
				const char *arg, int unset __maybe_unused)
{
	if (arg) {
		int err = regcomp(&ignore_callees_regex, arg, REG_EXTENDED);
		if (err) {
			char buf[BUFSIZ];
			regerror(err, &ignore_callees_regex, buf, sizeof(buf));
			pr_err("Invalid --ignore-callees regex: %s\n%s", arg, buf);
			return -1;
		}
		have_ignore_callees = 1;
	}

	return 0;
}

700
static int
701 702
parse_branch_mode(const struct option *opt __maybe_unused,
		  const char *str __maybe_unused, int unset)
703
{
704 705 706
	int *branch_mode = opt->value;

	*branch_mode = !unset;
707 708 709
	return 0;
}

710 711 712 713
static int
parse_percent_limit(const struct option *opt, const char *str,
		    int unset __maybe_unused)
{
714
	struct report *rep = opt->value;
715 716 717 718 719

	rep->min_percent = strtof(str, NULL);
	return 0;
}

720 721 722 723 724 725 726 727 728 729 730 731 732 733
static int
parse_percentage(const struct option *opt __maybe_unused, const char *str,
		 int unset __maybe_unused)
{
	if (!strcmp(str, "relative"))
		symbol_conf.filter_relative = true;
	else if (!strcmp(str, "absolute"))
		symbol_conf.filter_relative = false;
	else
		return -1;

	return 0;
}

734
int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
735
{
736
	struct perf_session *session;
737
	struct stat st;
738
	bool has_br_stack = false;
739
	int branch_mode = -1;
740
	int ret = -1;
741 742
	char callchain_default_opt[] = "fractal,0.5,callee";
	const char * const report_usage[] = {
N
Namhyung Kim 已提交
743
		"perf report [<options>]",
744 745
		NULL
	};
746
	struct report report = {
747
		.tool = {
748 749
			.sample		 = process_sample_event,
			.mmap		 = perf_event__process_mmap,
750
			.mmap2		 = perf_event__process_mmap2,
751
			.comm		 = perf_event__process_comm,
752 753
			.exit		 = perf_event__process_exit,
			.fork		 = perf_event__process_fork,
754 755 756 757 758 759 760 761
			.lost		 = perf_event__process_lost,
			.read		 = process_read_event,
			.attr		 = perf_event__process_attr,
			.tracing_data	 = perf_event__process_tracing_data,
			.build_id	 = perf_event__process_build_id,
			.ordered_samples = true,
			.ordering_requires_timestamps = true,
		},
762
		.max_stack		 = PERF_MAX_STACK_DEPTH,
763 764 765
		.pretty_printing_style	 = "normal",
	};
	const struct option options[] = {
766
	OPT_STRING('i', "input", &input_name, "file",
767
		    "input file name"),
768
	OPT_INCR('v', "verbose", &verbose,
769
		    "be more verbose (show symbol address, etc)"),
770 771
	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
		    "dump raw trace in ASCII"),
772 773
	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
		   "file", "vmlinux pathname"),
774 775
	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
		   "file", "kallsyms pathname"),
776
	OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"),
777
	OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
778
		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
779
	OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
780
		    "Show a column with the number of samples"),
781
	OPT_BOOLEAN('T', "threads", &report.show_threads,
782
		    "Show per-thread event counters"),
783
	OPT_STRING(0, "pretty", &report.pretty_printing_style, "key",
784
		   "pretty printing style key: normal raw"),
785
	OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
786
	OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
787 788
	OPT_BOOLEAN(0, "stdio", &report.use_stdio,
		    "Use the stdio interface"),
789 790 791
	OPT_BOOLEAN(0, "header", &report.header, "Show data header."),
	OPT_BOOLEAN(0, "header-only", &report.header_only,
		    "Show only data header."),
792
	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
793
		   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
794
		   " dso_to, dso_from, symbol_to, symbol_from, mispredict,"
795
		   " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, "
796
		   "snoop, locked, abort, in_tx, transaction"),
797 798
	OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
		    "Show sample percentage for different cpu modes"),
799 800
	OPT_STRING('p', "parent", &parent_pattern, "regex",
		   "regex filter to identify parent, see: '--sort parent'"),
801
	OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
802
		    "Only display entries with parent-match"),
803
	OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
804 805
		     "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
		     "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt),
806 807 808 809
	OPT_INTEGER(0, "max-stack", &report.max_stack,
		    "Set the maximum stack depth when parsing the callchain, "
		    "anything beyond the specified depth will be ignored. "
		    "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
810 811
	OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
		    "alias for inverted call graph"),
812 813 814
	OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
		   "ignore callees of these functions in call graphs",
		   report_parse_ignore_callees_opt),
815
	OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
816
		   "only consider symbols in these dsos"),
817
	OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
818
		   "only consider symbols in these comms"),
819
	OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
820
		   "only consider these symbols"),
821 822
	OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter",
		   "only show symbols that (partially) match with this filter"),
823
	OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
824 825
		   "width[,width...]",
		   "don't try to adjust column width, use these fixed values"),
826
	OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
827 828
		   "separator for columns, no spaces will be added between "
		   "columns '.' is reserved."),
829
	OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved,
830
		    "Only display entries resolved to a symbol"),
831 832
	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
		    "Look for files with symbols relative to this directory"),
833
	OPT_STRING('C', "cpu", &report.cpu_list, "cpu",
834 835
		   "list of cpus to profile"),
	OPT_BOOLEAN('I', "show-info", &report.show_full_info,
836
		    "Display extended information about perf.data file"),
837 838 839 840
	OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
		    "Interleave source code with assembly code (default)"),
	OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
		    "Display raw encoding of assembly instructions (default)"),
841 842
	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
843 844
	OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
		    "Show a column with the sum of periods"),
N
Namhyung Kim 已提交
845 846
	OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
		    "Show event group information together"),
847
	OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
848
		    "use branch records for histogram filling", parse_branch_mode),
849 850
	OPT_STRING(0, "objdump", &objdump_path, "path",
		   "objdump binary to use for disassembly and annotations"),
851 852
	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
		    "Disable symbol demangling"),
853
	OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
854 855
	OPT_CALLBACK(0, "percent-limit", &report, "percent",
		     "Don't show entries under that percent", parse_percent_limit),
856 857
	OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
		     "how to display percentage of filtered entries", parse_percentage),
858
	OPT_END()
859
	};
860 861 862
	struct perf_data_file file = {
		.mode  = PERF_DATA_MODE_READ,
	};
863

864
	perf_config(report__config, &report);
865

866 867
	argc = parse_options(argc, argv, options, report_usage, 0);

868
	if (report.use_stdio)
869
		use_browser = 0;
870
	else if (report.use_tui)
871
		use_browser = 1;
872 873
	else if (report.use_gtk)
		use_browser = 2;
874

875
	if (report.inverted_callchain)
876 877
		callchain_param.order = ORDER_CALLER;

878
	if (!input_name || !strlen(input_name)) {
879
		if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
880
			input_name = "-";
881
		else
882
			input_name = "perf.data";
883
	}
884

885 886 887
	file.path  = input_name;
	file.force = report.force;

888
repeat:
889
	session = perf_session__new(&file, false, &report.tool);
890 891 892 893 894 895 896
	if (session == NULL)
		return -ENOMEM;

	report.session = session;

	has_br_stack = perf_header__has_feat(&session->header,
					     HEADER_BRANCH_STACK);
897

898 899
	if (branch_mode == -1 && has_br_stack)
		sort__mode = SORT_MODE__BRANCH;
900

901 902
	/* sort__mode could be NORMAL if --no-branch-stack */
	if (sort__mode == SORT_MODE__BRANCH) {
903
		/*
904 905
		 * if no sort_order is provided, then specify
		 * branch-mode specific order
906 907 908 909 910
		 */
		if (sort_order == default_sort_order)
			sort_order = "comm,dso_from,symbol_from,"
				     "dso_to,symbol_to";

911
	}
912
	if (report.mem_mode) {
913
		if (sort__mode == SORT_MODE__BRANCH) {
914
			pr_err("branch and mem mode incompatible\n");
915 916
			goto error;
		}
917 918
		sort__mode = SORT_MODE__MEMORY;

919 920 921 922 923 924 925
		/*
		 * if no sort_order is provided, then specify
		 * branch-mode specific order
		 */
		if (sort_order == default_sort_order)
			sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
	}
926

927 928 929 930
	if (setup_sorting() < 0) {
		parse_options_usage(report_usage, options, "s", 1);
		goto error;
	}
931

932 933 934 935 936
	if (parent_pattern != default_parent_pattern) {
		if (sort_dimension__add("parent") < 0)
			goto error;
	}

937 938 939 940
	/* Force tty output for header output. */
	if (report.header || report.header_only)
		use_browser = 0;

941 942 943 944 945 946 947
	if (strcmp(input_name, "-") != 0)
		setup_browser(true);
	else {
		use_browser = 0;
		perf_hpp__init();
	}

948 949 950 951 952 953 954 955 956 957
	if (report.header || report.header_only) {
		perf_session__fprintf_info(session, stdout,
					   report.show_full_info);
		if (report.header_only)
			return 0;
	} else if (use_browser == 0) {
		fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
		      stdout);
	}

958
	/*
959
	 * Only in the TUI browser we are doing integrated annotation,
960 961 962
	 * so don't allocate extra space that won't be used in the stdio
	 * implementation.
	 */
963
	if (ui__has_annotation()) {
964
		symbol_conf.priv_size = sizeof(struct annotation);
965 966
		machines__set_symbol_filter(&session->machines,
					    symbol__annotate_init);
967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
		/*
 		 * For searching by name on the "Browse map details".
 		 * providing it only in verbose mode not to bloat too
 		 * much struct symbol.
 		 */
		if (verbose) {
			/*
			 * XXX: Need to provide a less kludgy way to ask for
			 * more space per symbol, the u32 is for the index on
			 * the ui browser.
			 * See symbol__browser_index.
			 */
			symbol_conf.priv_size += sizeof(u32);
			symbol_conf.sort_by_name = true;
		}
	}
983

984
	if (symbol__init() < 0)
985
		goto error;
986

987 988 989 990 991 992 993 994 995 996
	if (argc) {
		/*
		 * Special case: if there's an argument left then assume that
		 * it's a symbol filter:
		 */
		if (argc > 1)
			usage_with_options(report_usage, options);

		report.symbol_filter_str = argv[0];
	}
997

998
	sort__setup_elide(stdout);
999

1000
	ret = __cmd_report(&report);
1001 1002 1003 1004 1005 1006
	if (ret == K_SWITCH_INPUT_DATA) {
		perf_session__delete(session);
		goto repeat;
	} else
		ret = 0;

1007 1008 1009
error:
	perf_session__delete(session);
	return ret;
1010
}