builtin-report.c 28.2 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 perf_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
	int			max_stack;
53 54 55
	struct perf_read_values	show_threads_values;
	const char		*pretty_printing_style;
	const char		*cpu_list;
56
	const char		*symbol_filter_str;
57
	float			min_percent;
58
	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
59
};
60

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

	return perf_default_config(var, value, cb);
}

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
					   struct addr_location *al,
					   struct perf_sample *sample,
					   struct perf_evsel *evsel,
					   struct machine *machine,
					   union perf_event *event)
{
	struct perf_report *rep = container_of(tool, struct perf_report, tool);
	struct symbol *parent = NULL;
	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
	int err = 0;
	struct hist_entry *he;
	struct mem_info *mi, *mx;
	uint64_t cost;

	if ((sort__has_parent || symbol_conf.use_callchain) &&
	    sample->callchain) {
		err = machine__resolve_callchain(machine, evsel, al->thread,
94 95
						 sample, &parent, al,
						 rep->max_stack);
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
		if (err)
			return err;
	}

	mi = machine__resolve_mem(machine, al->thread, sample, cpumode);
	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.
	 */
118 119
	he = __hists__add_entry(&evsel->hists, al, parent, NULL, mi,
				cost, cost, 0);
120 121 122 123
	if (!he)
		return -ENOMEM;

	/*
124
	 * In the TUI browser, we are doing integrated annotation,
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
	 * so we don't allocate the extra space needed because the stdio
	 * code will not use it.
	 */
	if (sort__has_sym && he->ms.sym && use_browser > 0) {
		struct annotation *notes = symbol__annotation(he->ms.sym);

		assert(evsel != NULL);

		if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
			goto out;

		err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
		if (err)
			goto out;
	}

	if (sort__has_sym && he->mem_info->daddr.sym && use_browser > 0) {
		struct annotation *notes;

		mx = he->mem_info;

		notes = symbol__annotation(mx->daddr.sym);
		if (notes->src == NULL && symbol__alloc_hist(mx->daddr.sym) < 0)
			goto out;

		err = symbol__inc_addr_samples(mx->daddr.sym,
					       mx->daddr.map,
					       evsel->idx,
					       mx->daddr.al_addr);
		if (err)
			goto out;
	}

	evsel->hists.stats.total_period += cost;
	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
	err = 0;

	if (symbol_conf.use_callchain) {
		err = callchain_append(he->callchain,
				       &callchain_cursor,
				       sample->period);
	}
out:
	return err;
}

171 172 173 174 175 176 177 178 179 180 181
static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
					struct addr_location *al,
					struct perf_sample *sample,
					struct perf_evsel *evsel,
				      struct machine *machine)
{
	struct perf_report *rep = container_of(tool, struct perf_report, tool);
	struct symbol *parent = NULL;
	int err = 0;
	unsigned i;
	struct hist_entry *he;
182
	struct branch_info *bi, *bx;
183 184 185

	if ((sort__has_parent || symbol_conf.use_callchain)
	    && sample->callchain) {
186
		err = machine__resolve_callchain(machine, evsel, al->thread,
187 188
						 sample, &parent, al,
						 rep->max_stack);
189 190 191 192 193 194 195 196 197 198 199 200
		if (err)
			return err;
	}

	bi = machine__resolve_bstack(machine, al->thread,
				     sample->branch_stack);
	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;
201 202 203

		err = -ENOMEM;

204 205 206 207
		/* 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;
208 209 210 211
		/*
		 * The report shows the percentage of total branches captured
		 * and not events sampled. Thus we use a pseudo period of 1.
		 */
212 213
		he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
					1, 1, 0);
214
		if (he) {
215 216
			struct annotation *notes;
			bx = he->branch_info;
217
			if (bx->from.sym && use_browser == 1 && sort__has_sym) {
218 219 220 221 222 223 224 225 226 227 228 229 230
				notes = symbol__annotation(bx->from.sym);
				if (!notes->src
				    && symbol__alloc_hist(bx->from.sym) < 0)
					goto out;

				err = symbol__inc_addr_samples(bx->from.sym,
							       bx->from.map,
							       evsel->idx,
							       bx->from.al_addr);
				if (err)
					goto out;
			}

231
			if (bx->to.sym && use_browser == 1 && sort__has_sym) {
232 233 234 235 236 237 238 239 240 241 242 243
				notes = symbol__annotation(bx->to.sym);
				if (!notes->src
				    && symbol__alloc_hist(bx->to.sym) < 0)
					goto out;

				err = symbol__inc_addr_samples(bx->to.sym,
							       bx->to.map,
							       evsel->idx,
							       bx->to.al_addr);
				if (err)
					goto out;
			}
244 245 246
			evsel->hists.stats.total_period += 1;
			hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
		} else
247
			goto out;
248
	}
249
	err = 0;
250
out:
251
	free(bi);
252 253 254
	return err;
}

255 256
static int perf_evsel__add_hist_entry(struct perf_tool *tool,
				      struct perf_evsel *evsel,
257 258 259
				      struct addr_location *al,
				      struct perf_sample *sample,
				      struct machine *machine)
260
{
261
	struct perf_report *rep = container_of(tool, struct perf_report, tool);
262
	struct symbol *parent = NULL;
263
	int err = 0;
264 265
	struct hist_entry *he;

266
	if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
267
		err = machine__resolve_callchain(machine, evsel, al->thread,
268 269
						 sample, &parent, al,
						 rep->max_stack);
270 271
		if (err)
			return err;
272
	}
273

274 275 276
	he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL,
				sample->period, sample->weight,
				sample->transaction);
277
	if (he == NULL)
278 279
		return -ENOMEM;

280
	if (symbol_conf.use_callchain) {
281
		err = callchain_append(he->callchain,
282
				       &callchain_cursor,
283
				       sample->period);
284
		if (err)
285
			return err;
286 287
	}
	/*
288
	 * Only in the TUI browser we are doing integrated annotation,
289 290 291
	 * so we don't allocated the extra space needed because the stdio
	 * code will not use it.
	 */
292
	if (he->ms.sym != NULL && use_browser == 1 && sort__has_sym) {
293
		struct annotation *notes = symbol__annotation(he->ms.sym);
294 295 296 297

		assert(evsel != NULL);

		err = -ENOMEM;
298
		if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
299 300 301
			goto out;

		err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
302
	}
303

304 305 306
	evsel->hists.stats.total_period += sample->period;
	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
out:
307
	return err;
308 309
}

310

311
static int process_sample_event(struct perf_tool *tool,
312
				union perf_event *event,
313
				struct perf_sample *sample,
314
				struct perf_evsel *evsel,
315
				struct machine *machine)
316
{
317
	struct perf_report *rep = container_of(tool, struct perf_report, tool);
318
	struct addr_location al;
319
	int ret;
320

321
	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
322
		fprintf(stderr, "problem processing %d event, skipping it.\n",
323 324 325
			event->header.type);
		return -1;
	}
326

327
	if (al.filtered || (rep->hide_unresolved && al.sym == NULL))
328
		return 0;
329

330
	if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
331 332
		return 0;

333
	if (sort__mode == SORT_MODE__BRANCH) {
334 335 336
		ret = perf_report__add_branch_hist_entry(tool, &al, sample,
							 evsel, machine);
		if (ret < 0)
337
			pr_debug("problem adding lbr entry, skipping event\n");
338
	} else if (rep->mem_mode == 1) {
339 340 341
		ret = perf_report__add_mem_hist_entry(tool, &al, sample,
						      evsel, machine, event);
		if (ret < 0)
342
			pr_debug("problem adding mem entry, skipping event\n");
343 344 345
	} else {
		if (al.map != NULL)
			al.map->dso->hit = 1;
346

347 348
		ret = perf_evsel__add_hist_entry(tool, evsel, &al, sample,
						 machine);
349
		if (ret < 0)
350
			pr_debug("problem incrementing symbol period, skipping event\n");
351
	}
352
	return ret;
353
}
I
Ingo Molnar 已提交
354

355
static int process_read_event(struct perf_tool *tool,
356
			      union perf_event *event,
357
			      struct perf_sample *sample __maybe_unused,
358
			      struct perf_evsel *evsel,
359
			      struct machine *machine __maybe_unused)
360
{
361
	struct perf_report *rep = container_of(tool, struct perf_report, tool);
362

363
	if (rep->show_threads) {
364
		const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
365
		perf_read_values_add_value(&rep->show_threads_values,
366 367 368 369 370 371
					   event->read.pid, event->read.tid,
					   event->read.id,
					   name,
					   event->read.value);
	}

372
	dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
373
		    evsel ? perf_evsel__name(evsel) : "FAIL",
374
		    event->read.value);
375 376 377 378

	return 0;
}

379
/* For pipe mode, sample_type is not currently set */
380
static int perf_report__setup_sample_type(struct perf_report *rep)
381
{
382 383 384
	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);
385

386
	if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
387
		if (sort__has_parent) {
388
			ui__error("Selected --sort parent, but no "
389 390
				    "callchain data. Did you call "
				    "'perf record' without -g?\n");
391
			return -EINVAL;
392
		}
393
		if (symbol_conf.use_callchain) {
394
			ui__error("Selected -g but no callchain data. Did "
395
				    "you call 'perf record' without -g?\n");
396
			return -1;
397
		}
398 399
	} else if (!rep->dont_use_callchains &&
		   callchain_param.mode != CHAIN_NONE &&
400
		   !symbol_conf.use_callchain) {
401
			symbol_conf.use_callchain = true;
402
			if (callchain_register_param(&callchain_param) < 0) {
403
				ui__error("Can't register callchain params.\n");
404
				return -EINVAL;
405
			}
406 407
	}

408
	if (sort__mode == SORT_MODE__BRANCH) {
409
		if (!is_pipe &&
410
		    !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
411 412
			ui__error("Selected -b but no branch data. "
				  "Did you call perf record without -b?\n");
413 414 415 416
			return -1;
		}
	}

417 418
	return 0;
}
419

420
static void sig_handler(int sig __maybe_unused)
421 422 423 424
{
	session_done = 1;
}

425
static size_t hists__fprintf_nr_sample_events(struct perf_report *rep,
426
					      struct hists *hists,
427 428 429 430
					      const char *evname, FILE *fp)
{
	size_t ret;
	char unit;
431 432 433
	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);
434 435 436
	char buf[512];
	size_t size = sizeof(buf);

437
	if (perf_evsel__is_group_event(evsel)) {
438 439 440 441 442 443 444 445 446 447
		struct perf_evsel *pos;

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

		for_each_group_member(pos, evsel) {
			nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
			nr_events += pos->hists.stats.total_period;
		}
	}
448

449 450
	nr_samples = convert_unit(nr_samples, &unit);
	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
451
	if (evname != NULL)
452 453
		ret += fprintf(fp, " of event '%s'", evname);

454 455 456 457 458
	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);
459 460 461
	return ret + fprintf(fp, "\n#\n");
}

462
static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
463
					 struct perf_report *rep,
464
					 const char *help)
465
{
466
	struct perf_evsel *pos;
467

468 469
	list_for_each_entry(pos, &evlist->entries, node) {
		struct hists *hists = &pos->hists;
470
		const char *evname = perf_evsel__name(pos);
471

472 473 474 475
		if (symbol_conf.event_group &&
		    !perf_evsel__is_group_leader(pos))
			continue;

476
		hists__fprintf_nr_sample_events(rep, hists, evname, stdout);
477
		hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
478 479 480 481 482 483 484
		fprintf(stdout, "\n\n");
	}

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

485 486 487
		if (rep->show_threads) {
			bool style = !strcmp(rep->pretty_printing_style, "raw");
			perf_read_values_display(stdout, &rep->show_threads_values,
488
						 style);
489
			perf_read_values_destroy(&rep->show_threads_values);
490 491 492 493 494 495
		}
	}

	return 0;
}

496
static int __cmd_report(struct perf_report *rep)
497
{
498
	int ret = -EINVAL;
499
	u64 nr_samples;
500
	struct perf_session *session = rep->session;
501
	struct perf_evsel *pos;
502 503
	struct map *kernel_map;
	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 509
	signal(SIGINT, sig_handler);

510 511 512
	if (rep->cpu_list) {
		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
					       rep->cpu_bitmap);
513
		if (ret)
514
			return ret;
515 516
	}

517
	if (use_browser <= 0)
518
		perf_session__fprintf_info(session, stdout, rep->show_full_info);
519

520 521
	if (rep->show_threads)
		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 533 534 535 536
	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))) {
537 538 539 540 541 542 543 544 545 546 547
		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.";
			}
		}
548

549 550 551 552
		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",
553
		desc);
554 555
	}

556
	if (verbose > 3)
557
		perf_session__fprintf(session, stdout);
558

559
	if (verbose > 2)
560
		perf_session__fprintf_dsos(session, stdout);
561

562 563
	if (dump_trace) {
		perf_session__fprintf_nr_events(session, stdout);
564
		return 0;
565 566
	}

567 568 569 570 571 572
	nr_samples = 0;
	list_for_each_entry(pos, &session->evlist->entries, node)
		nr_samples += pos->hists.nr_entries;

	ui_progress__init(&prog, nr_samples, "Merging related events...");

573 574 575
	nr_samples = 0;
	list_for_each_entry(pos, &session->evlist->entries, node) {
		struct hists *hists = &pos->hists;
576

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

580
		hists__collapse_resort(hists, &prog);
581
		nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
582 583 584 585 586 587 588 589 590

		/* 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);
		}
591
	}
592
	ui_progress__finish();
593

594 595 596
	if (session_done())
		return 0;

597
	if (nr_samples == 0) {
598
		ui__error("The %s file has no samples!\n", file->path);
599
		return 0;
600 601
	}

602 603 604
	list_for_each_entry(pos, &session->evlist->entries, node)
		hists__output_resort(&pos->hists);

605
	if (use_browser > 0) {
606
		if (use_browser == 1) {
607
			ret = perf_evlist__tui_browse_hists(session->evlist,
608 609
							help, NULL,
							rep->min_percent,
610 611 612 613 614 615 616 617
							&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;

618
		} else if (use_browser == 2) {
619 620 621 622 623 624 625 626 627 628 629 630 631
			int (*hist_browser)(struct perf_evlist *,
					    const char *,
					    struct hist_browser_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 ret;
			}
			hist_browser(session->evlist, help, NULL,
				     rep->min_percent);
632
		}
633
	} else
634
		perf_evlist__tty_browse_hists(session->evlist, rep, help);
635

636
	return ret;
637 638
}

639
static int
640
parse_callchain_opt(const struct option *opt, const char *arg, int unset)
641
{
642
	struct perf_report *rep = (struct perf_report *)opt->value;
643
	char *tok, *tok2;
644 645
	char *endptr;

646 647 648 649
	/*
	 * --no-call-graph
	 */
	if (unset) {
650
		rep->dont_use_callchains = true;
651 652 653
		return 0;
	}

654
	symbol_conf.use_callchain = true;
655 656 657 658

	if (!arg)
		return 0;

659 660 661 662 663 664
	tok = strtok((char *)arg, ",");
	if (!tok)
		return -1;

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

667
	else if (!strncmp(tok, "flat", strlen(arg)))
668 669 670 671 672
		callchain_param.mode = CHAIN_FLAT;

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

673 674
	else if (!strncmp(tok, "none", strlen(arg))) {
		callchain_param.mode = CHAIN_NONE;
675
		symbol_conf.use_callchain = false;
676 677 678 679

		return 0;
	}

680 681 682
	else
		return -1;

683 684 685
	/* get the min percentage */
	tok = strtok(NULL, ",");
	if (!tok)
686
		goto setup;
687

688
	callchain_param.min_percent = strtod(tok, &endptr);
689 690 691
	if (tok == endptr)
		return -1;

692 693 694 695 696 697
	/* get the print limit */
	tok2 = strtok(NULL, ",");
	if (!tok2)
		goto setup;

	if (tok2[0] != 'c') {
698
		callchain_param.print_limit = strtoul(tok2, &endptr, 0);
699 700 701 702 703 704
		tok2 = strtok(NULL, ",");
		if (!tok2)
			goto setup;
	}

	/* get the call chain order */
705
	if (!strncmp(tok2, "caller", strlen("caller")))
706
		callchain_param.order = ORDER_CALLER;
707
	else if (!strncmp(tok2, "callee", strlen("callee")))
708 709 710
		callchain_param.order = ORDER_CALLEE;
	else
		return -1;
711 712 713 714 715 716 717 718 719 720 721

	/* 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;
722
setup:
723
	if (callchain_register_param(&callchain_param) < 0) {
724 725 726
		fprintf(stderr, "Can't register callchain params\n");
		return -1;
	}
727 728 729
	return 0;
}

730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
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;
}

748
static int
749 750
parse_branch_mode(const struct option *opt __maybe_unused,
		  const char *str __maybe_unused, int unset)
751
{
752 753 754
	int *branch_mode = opt->value;

	*branch_mode = !unset;
755 756 757
	return 0;
}

758 759 760 761 762 763 764 765 766 767
static int
parse_percent_limit(const struct option *opt, const char *str,
		    int unset __maybe_unused)
{
	struct perf_report *rep = opt->value;

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

768
int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
769
{
770
	struct perf_session *session;
771
	struct stat st;
772
	bool has_br_stack = false;
773
	int branch_mode = -1;
774
	int ret = -1;
775 776
	char callchain_default_opt[] = "fractal,0.5,callee";
	const char * const report_usage[] = {
N
Namhyung Kim 已提交
777
		"perf report [<options>]",
778 779 780
		NULL
	};
	struct perf_report report = {
781
		.tool = {
782 783
			.sample		 = process_sample_event,
			.mmap		 = perf_event__process_mmap,
784
			.mmap2		 = perf_event__process_mmap2,
785
			.comm		 = perf_event__process_comm,
786 787
			.exit		 = perf_event__process_exit,
			.fork		 = perf_event__process_fork,
788 789 790 791 792 793 794 795
			.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,
		},
796
		.max_stack		 = PERF_MAX_STACK_DEPTH,
797 798 799
		.pretty_printing_style	 = "normal",
	};
	const struct option options[] = {
800
	OPT_STRING('i', "input", &input_name, "file",
801
		    "input file name"),
802
	OPT_INCR('v', "verbose", &verbose,
803
		    "be more verbose (show symbol address, etc)"),
804 805
	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
		    "dump raw trace in ASCII"),
806 807
	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
		   "file", "vmlinux pathname"),
808 809
	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
		   "file", "kallsyms pathname"),
810
	OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"),
811
	OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
812
		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
813
	OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
814
		    "Show a column with the number of samples"),
815
	OPT_BOOLEAN('T', "threads", &report.show_threads,
816
		    "Show per-thread event counters"),
817
	OPT_STRING(0, "pretty", &report.pretty_printing_style, "key",
818
		   "pretty printing style key: normal raw"),
819
	OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
820
	OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
821 822
	OPT_BOOLEAN(0, "stdio", &report.use_stdio,
		    "Use the stdio interface"),
823
	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
824
		   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
825
		   " dso_to, dso_from, symbol_to, symbol_from, mispredict,"
826
		   " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, "
827
		   "snoop, locked, abort, in_tx, transaction"),
828 829
	OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
		    "Show sample percentage for different cpu modes"),
830 831
	OPT_STRING('p', "parent", &parent_pattern, "regex",
		   "regex filter to identify parent, see: '--sort parent'"),
832
	OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
833
		    "Only display entries with parent-match"),
834
	OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
835 836
		     "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),
837 838 839 840
	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)),
841 842
	OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
		    "alias for inverted call graph"),
843 844 845
	OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
		   "ignore callees of these functions in call graphs",
		   report_parse_ignore_callees_opt),
846
	OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
847
		   "only consider symbols in these dsos"),
848
	OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
849
		   "only consider symbols in these comms"),
850
	OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
851
		   "only consider these symbols"),
852 853
	OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter",
		   "only show symbols that (partially) match with this filter"),
854
	OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
855 856
		   "width[,width...]",
		   "don't try to adjust column width, use these fixed values"),
857
	OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
858 859
		   "separator for columns, no spaces will be added between "
		   "columns '.' is reserved."),
860
	OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved,
861
		    "Only display entries resolved to a symbol"),
862 863
	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
		    "Look for files with symbols relative to this directory"),
864
	OPT_STRING('C', "cpu", &report.cpu_list, "cpu",
865 866
		   "list of cpus to profile"),
	OPT_BOOLEAN('I', "show-info", &report.show_full_info,
867
		    "Display extended information about perf.data file"),
868 869 870 871
	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)"),
872 873
	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
874 875
	OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
		    "Show a column with the sum of periods"),
N
Namhyung Kim 已提交
876 877
	OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
		    "Show event group information together"),
878
	OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
879
		    "use branch records for histogram filling", parse_branch_mode),
880 881
	OPT_STRING(0, "objdump", &objdump_path, "path",
		   "objdump binary to use for disassembly and annotations"),
882 883
	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
		    "Disable symbol demangling"),
884
	OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
885 886
	OPT_CALLBACK(0, "percent-limit", &report, "percent",
		     "Don't show entries under that percent", parse_percent_limit),
887
	OPT_END()
888
	};
889 890 891
	struct perf_data_file file = {
		.mode  = PERF_DATA_MODE_READ,
	};
892

893
	perf_config(perf_report_config, &report);
894

895 896
	argc = parse_options(argc, argv, options, report_usage, 0);

897
	if (report.use_stdio)
898
		use_browser = 0;
899
	else if (report.use_tui)
900
		use_browser = 1;
901 902
	else if (report.use_gtk)
		use_browser = 2;
903

904
	if (report.inverted_callchain)
905 906
		callchain_param.order = ORDER_CALLER;

907
	if (!input_name || !strlen(input_name)) {
908
		if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
909
			input_name = "-";
910
		else
911
			input_name = "perf.data";
912
	}
913

914 915 916
	file.path  = input_name;
	file.force = report.force;

917
repeat:
918
	session = perf_session__new(&file, false, &report.tool);
919 920 921 922 923 924 925
	if (session == NULL)
		return -ENOMEM;

	report.session = session;

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

927 928
	if (branch_mode == -1 && has_br_stack)
		sort__mode = SORT_MODE__BRANCH;
929

930 931
	/* sort__mode could be NORMAL if --no-branch-stack */
	if (sort__mode == SORT_MODE__BRANCH) {
932
		/*
933 934
		 * if no sort_order is provided, then specify
		 * branch-mode specific order
935 936 937 938 939
		 */
		if (sort_order == default_sort_order)
			sort_order = "comm,dso_from,symbol_from,"
				     "dso_to,symbol_to";

940
	}
941
	if (report.mem_mode) {
942
		if (sort__mode == SORT_MODE__BRANCH) {
943 944 945
			fprintf(stderr, "branch and mem mode incompatible\n");
			goto error;
		}
946 947
		sort__mode = SORT_MODE__MEMORY;

948 949 950 951 952 953 954
		/*
		 * 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";
	}
955

956 957 958 959
	if (setup_sorting() < 0) {
		parse_options_usage(report_usage, options, "s", 1);
		goto error;
	}
960

961 962 963 964 965 966 967 968 969 970 971 972
	if (parent_pattern != default_parent_pattern) {
		if (sort_dimension__add("parent") < 0)
			goto error;
	}

	if (strcmp(input_name, "-") != 0)
		setup_browser(true);
	else {
		use_browser = 0;
		perf_hpp__init();
	}

973
	/*
974
	 * Only in the TUI browser we are doing integrated annotation,
975 976 977
	 * so don't allocate extra space that won't be used in the stdio
	 * implementation.
	 */
978
	if (use_browser == 1 && sort__has_sym) {
979
		symbol_conf.priv_size = sizeof(struct annotation);
980 981
		machines__set_symbol_filter(&session->machines,
					    symbol__annotate_init);
982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997
		/*
 		 * 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;
		}
	}
998

999
	if (symbol__init() < 0)
1000
		goto error;
1001

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
	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];
	}
1012

1013
	sort__setup_elide(stdout);
1014

1015
	ret = __cmd_report(&report);
1016 1017 1018 1019 1020 1021
	if (ret == K_SWITCH_INPUT_DATA) {
		perf_session__delete(session);
		goto repeat;
	} else
		ret = 0;

1022 1023 1024
error:
	perf_session__delete(session);
	return ret;
1025
}