builtin-record.c 24.7 KB
Newer Older
I
Ingo Molnar 已提交
1
/*
2 3 4 5 6
 * builtin-record.c
 *
 * Builtin record command: Record the profile of a workload
 * (or a CPU, or a PID) into the perf.data output file - for
 * later analysis via perf report.
I
Ingo Molnar 已提交
7
 */
8
#include "builtin.h"
9 10 11

#include "perf.h"

12
#include "util/build-id.h"
13
#include "util/util.h"
14
#include "util/parse-options.h"
15
#include "util/parse-events.h"
16

17
#include "util/header.h"
18
#include "util/event.h"
19
#include "util/evlist.h"
20
#include "util/evsel.h"
21
#include "util/debug.h"
22
#include "util/session.h"
23
#include "util/tool.h"
24
#include "util/symbol.h"
25
#include "util/cpumap.h"
26
#include "util/thread_map.h"
27
#include "util/data.h"
28

29
#include <unistd.h>
30
#include <sched.h>
31
#include <sys/mman.h>
32

33
#ifndef HAVE_ON_EXIT_SUPPORT
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
#ifndef ATEXIT_MAX
#define ATEXIT_MAX 32
#endif
static int __on_exit_count = 0;
typedef void (*on_exit_func_t) (int, void *);
static on_exit_func_t __on_exit_funcs[ATEXIT_MAX];
static void *__on_exit_args[ATEXIT_MAX];
static int __exitcode = 0;
static void __handle_on_exit_funcs(void);
static int on_exit(on_exit_func_t function, void *arg);
#define exit(x) (exit)(__exitcode = (x))

static int on_exit(on_exit_func_t function, void *arg)
{
	if (__on_exit_count == ATEXIT_MAX)
		return -ENOMEM;
	else if (__on_exit_count == 0)
		atexit(__handle_on_exit_funcs);
	__on_exit_funcs[__on_exit_count] = function;
	__on_exit_args[__on_exit_count++] = arg;
	return 0;
}

static void __handle_on_exit_funcs(void)
{
	int i;
	for (i = 0; i < __on_exit_count; i++)
		__on_exit_funcs[i] (__exitcode, __on_exit_args[i]);
}
#endif

65
struct perf_record {
66
	struct perf_tool	tool;
67 68
	struct perf_record_opts	opts;
	u64			bytes_written;
69
	struct perf_data_file	file;
70 71 72 73 74 75 76
	struct perf_evlist	*evlist;
	struct perf_session	*session;
	const char		*progname;
	int			realtime_prio;
	bool			no_buildid;
	bool			no_buildid_cache;
	long			samples;
77
};
78

79
static int perf_record__write(struct perf_record *rec, void *bf, size_t size)
80
{
81
	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
82 83
		pr_err("failed to write perf data, error: %m\n");
		return -1;
84
	}
85

86
	rec->bytes_written += size;
87
	return 0;
88 89
}

90
static int process_synthesized_event(struct perf_tool *tool,
91
				     union perf_event *event,
92 93
				     struct perf_sample *sample __maybe_unused,
				     struct machine *machine __maybe_unused)
94
{
95
	struct perf_record *rec = container_of(tool, struct perf_record, tool);
96
	return perf_record__write(rec, event, event->header.size);
97 98
}

99
static int perf_record__mmap_read(struct perf_record *rec,
100
				   struct perf_mmap *md)
101
{
102
	unsigned int head = perf_mmap__read_head(md);
103
	unsigned int old = md->prev;
J
Jiri Olsa 已提交
104
	unsigned char *data = md->base + page_size;
105 106
	unsigned long size;
	void *buf;
107
	int rc = 0;
108

109
	if (old == head)
110
		return 0;
111

112
	rec->samples++;
113 114 115 116 117 118 119

	size = head - old;

	if ((old & md->mask) + size != (head & md->mask)) {
		buf = &data[old & md->mask];
		size = md->mask + 1 - (old & md->mask);
		old += size;
120

121
		if (perf_record__write(rec, buf, size) < 0) {
122 123 124
			rc = -1;
			goto out;
		}
125 126 127 128 129
	}

	buf = &data[old & md->mask];
	size = head - old;
	old += size;
130

131
	if (perf_record__write(rec, buf, size) < 0) {
132 133 134
		rc = -1;
		goto out;
	}
135 136

	md->prev = old;
137
	perf_mmap__write_tail(md, old);
138 139 140

out:
	return rc;
141 142 143
}

static volatile int done = 0;
144
static volatile int signr = -1;
145
static volatile int child_finished = 0;
146

147
static void sig_handler(int sig)
148
{
149 150 151
	if (sig == SIGCHLD)
		child_finished = 1;

152
	done = 1;
153 154 155
	signr = sig;
}

156
static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
157
{
158
	struct perf_record *rec = arg;
159 160
	int status;

161
	if (rec->evlist->workload.pid > 0) {
162
		if (!child_finished)
163
			kill(rec->evlist->workload.pid, SIGTERM);
164 165 166

		wait(&status);
		if (WIFSIGNALED(status))
167
			psignal(WTERMSIG(status), rec->progname);
168
	}
169

170
	if (signr == -1 || signr == SIGUSR1)
171 172 173
		return;

	signal(signr, SIG_DFL);
174 175
}

176
static int perf_record__open(struct perf_record *rec)
177
{
178
	char msg[512];
179
	struct perf_evsel *pos;
180 181 182
	struct perf_evlist *evlist = rec->evlist;
	struct perf_session *session = rec->session;
	struct perf_record_opts *opts = &rec->opts;
183
	int rc = 0;
184

185
	perf_evlist__config(evlist, opts);
186

187 188
	list_for_each_entry(pos, &evlist->entries, node) {
try_again:
189
		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
190
			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
191
				if (verbose)
192
					ui__warning("%s\n", msg);
193 194
				goto try_again;
			}
195

196 197 198 199
			rc = -errno;
			perf_evsel__open_strerror(pos, &opts->target,
						  errno, msg, sizeof(msg));
			ui__error("%s\n", msg);
200
			goto out;
L
Li Zefan 已提交
201 202
		}
	}
203

204
	if (perf_evlist__apply_filters(evlist)) {
205 206
		error("failed to set filter with %d (%s)\n", errno,
			strerror(errno));
207 208
		rc = -1;
		goto out;
209 210
	}

211
	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
212 213 214 215 216
		if (errno == EPERM) {
			pr_err("Permission error mapping pages.\n"
			       "Consider increasing "
			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
			       "or try again with a smaller value of -m/--mmap_pages.\n"
217
			       "(current value: %u)\n", opts->mmap_pages);
218 219 220 221 222 223
			rc = -errno;
		} else {
			pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
			rc = -errno;
		}
		goto out;
224
	}
225

226
	session->evlist = evlist;
227
	perf_session__set_id_hdr_size(session);
228 229
out:
	return rc;
230 231
}

232
static int process_buildids(struct perf_record *rec)
233
{
234 235
	struct perf_data_file *file  = &rec->file;
	struct perf_session *session = rec->session;
236
	u64 start = session->header.data_offset;
237

238
	u64 size = lseek(file->fd, 0, SEEK_CUR);
239 240 241
	if (size == 0)
		return 0;

242 243
	return __perf_session__process_events(session, start,
					      size - start,
244 245 246
					      size, &build_id__mark_dso_hit_ops);
}

247
static void perf_record__exit(int status, void *arg)
248
{
249
	struct perf_record *rec = arg;
250
	struct perf_data_file *file = &rec->file;
251

252 253 254
	if (status != 0)
		return;

255
	if (!file->is_pipe) {
256 257 258 259 260
		rec->session->header.data_size += rec->bytes_written;

		if (!rec->no_buildid)
			process_buildids(rec);
		perf_session__write_header(rec->session, rec->evlist,
261
					   file->fd, true);
262 263
		perf_session__delete(rec->session);
		perf_evlist__delete(rec->evlist);
264
		symbol__exit();
265
	}
266 267
}

268
static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
269 270
{
	int err;
271
	struct perf_tool *tool = data;
272 273 274 275 276 277 278 279
	/*
	 *As for guest kernel when processing subcommand record&report,
	 *we arrange module mmap prior to guest kernel mmap and trigger
	 *a preload dso because default guest module symbols are loaded
	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
	 *method is used to avoid symbol missing when the first addr is
	 *in module instead of in guest kernel.
	 */
280
	err = perf_event__synthesize_modules(tool, process_synthesized_event,
281
					     machine);
282 283
	if (err < 0)
		pr_err("Couldn't record guest kernel [%d]'s reference"
284
		       " relocation symbol.\n", machine->pid);
285 286 287 288 289

	/*
	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
	 * have no _text sometimes.
	 */
290
	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
291
						 machine, "_text");
292
	if (err < 0)
293
		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
294
							 machine, "_stext");
295 296
	if (err < 0)
		pr_err("Couldn't record guest kernel [%d]'s reference"
297
		       " relocation symbol.\n", machine->pid);
298 299
}

300 301 302 303 304
static struct perf_event_header finished_round_event = {
	.size = sizeof(struct perf_event_header),
	.type = PERF_RECORD_FINISHED_ROUND,
};

305
static int perf_record__mmap_read_all(struct perf_record *rec)
306
{
307
	int i;
308
	int rc = 0;
309

310
	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
311 312 313 314 315 316
		if (rec->evlist->mmap[i].base) {
			if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
				rc = -1;
				goto out;
			}
		}
317 318
	}

319
	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
320 321
		rc = perf_record__write(rec, &finished_round_event,
					sizeof(finished_round_event));
322 323 324

out:
	return rc;
325 326
}

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
static void perf_record__init_features(struct perf_record *rec)
{
	struct perf_evlist *evsel_list = rec->evlist;
	struct perf_session *session = rec->session;
	int feat;

	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
		perf_header__set_feat(&session->header, feat);

	if (rec->no_buildid)
		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);

	if (!have_tracepoints(&evsel_list->entries))
		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);

	if (!rec->opts.branch_stack)
		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
}

346
static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
347
{
348
	int err;
349
	unsigned long waking = 0;
350
	const bool forks = argc > 0;
351
	struct machine *machine;
352
	struct perf_tool *tool = &rec->tool;
353 354
	struct perf_record_opts *opts = &rec->opts;
	struct perf_evlist *evsel_list = rec->evlist;
355
	struct perf_data_file *file = &rec->file;
356
	struct perf_session *session;
357
	bool disabled = false;
358

359
	rec->progname = argv[0];
360

361
	on_exit(perf_record__sig_exit, rec);
362 363
	signal(SIGCHLD, sig_handler);
	signal(SIGINT, sig_handler);
364
	signal(SIGUSR1, sig_handler);
365
	signal(SIGTERM, sig_handler);
366

367
	session = perf_session__new(file, false, NULL);
368
	if (session == NULL) {
369 370 371 372
		pr_err("Not enough memory for reading perf file header\n");
		return -1;
	}

373 374
	rec->session = session;

375
	perf_record__init_features(rec);
376

377
	if (forks) {
378
		err = perf_evlist__prepare_workload(evsel_list, &opts->target,
379
						    argv, file->is_pipe,
380
						    true);
381 382 383
		if (err < 0) {
			pr_err("Couldn't run the workload!\n");
			goto out_delete_session;
384 385 386
		}
	}

387 388 389 390
	if (perf_record__open(rec) != 0) {
		err = -1;
		goto out_delete_session;
	}
391

392 393 394
	if (!evsel_list->nr_groups)
		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);

395
	/*
396
	 * perf_session__delete(session) will be called at perf_record__exit()
397
	 */
398
	on_exit(perf_record__exit, rec);
399

400 401
	if (file->is_pipe) {
		err = perf_header__write_pipe(file->fd);
402
		if (err < 0)
403
			goto out_delete_session;
404
	} else {
405
		err = perf_session__write_header(session, evsel_list,
406
						 file->fd, false);
407
		if (err < 0)
408
			goto out_delete_session;
409 410
	}

411
	if (!rec->no_buildid
412
	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
413
		pr_err("Couldn't generate buildids. "
414
		       "Use --no-buildid to profile anyway.\n");
415 416
		err = -1;
		goto out_delete_session;
417 418
	}

419
	machine = &session->machines.host;
420

421
	if (file->is_pipe) {
422
		err = perf_event__synthesize_attrs(tool, session,
423
						   process_synthesized_event);
424 425
		if (err < 0) {
			pr_err("Couldn't synthesize attrs.\n");
426
			goto out_delete_session;
427
		}
428

429
		if (have_tracepoints(&evsel_list->entries)) {
430 431 432 433 434 435 436 437
			/*
			 * FIXME err <= 0 here actually means that
			 * there were no tracepoints so its not really
			 * an error, just that we don't need to
			 * synthesize anything.  We really have to
			 * return this more properly and also
			 * propagate errors that now are calling die()
			 */
438
			err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list,
439
								  process_synthesized_event);
440 441
			if (err <= 0) {
				pr_err("Couldn't record tracing data.\n");
442
				goto out_delete_session;
443
			}
444
			rec->bytes_written += err;
445
		}
446 447
	}

448
	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
449
						 machine, "_text");
450
	if (err < 0)
451
		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
452
							 machine, "_stext");
453 454 455 456
	if (err < 0)
		pr_err("Couldn't record kernel reference relocation symbol\n"
		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
		       "Check /proc/kallsyms permission or run as root.\n");
457

458
	err = perf_event__synthesize_modules(tool, process_synthesized_event,
459
					     machine);
460 461 462 463 464
	if (err < 0)
		pr_err("Couldn't record kernel module information.\n"
		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
		       "Check /proc/modules permission or run as root.\n");

465
	if (perf_guest) {
466 467
		machines__process_guests(&session->machines,
					 perf_event__synthesize_guest_os, tool);
468
	}
469

470 471
	err = __machine__synthesize_threads(machine, tool, &opts->target, evsel_list->threads,
					    process_synthesized_event, opts->sample_address);
472 473 474
	if (err != 0)
		goto out_delete_session;

475
	if (rec->realtime_prio) {
476 477
		struct sched_param param;

478
		param.sched_priority = rec->realtime_prio;
479
		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
480
			pr_err("Could not set realtime priority.\n");
481 482
			err = -1;
			goto out_delete_session;
483 484 485
		}
	}

486 487 488 489 490
	/*
	 * When perf is starting the traced process, all the events
	 * (apart from group members) have enable_on_exec=1 set,
	 * so don't spoil it by prematurely enabling them.
	 */
491
	if (!target__none(&opts->target))
492
		perf_evlist__enable(evsel_list);
493

494 495 496
	/*
	 * Let the child rip
	 */
497
	if (forks)
498
		perf_evlist__start_workload(evsel_list);
499

500
	for (;;) {
501
		int hits = rec->samples;
502

503 504 505 506
		if (perf_record__mmap_read_all(rec) < 0) {
			err = -1;
			goto out_delete_session;
		}
507

508
		if (hits == rec->samples) {
509 510
			if (done)
				break;
511
			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
512 513 514
			waking++;
		}

515 516 517 518 519
		/*
		 * When perf is starting the traced process, at the end events
		 * die with the process and we wait for that. Thus no need to
		 * disable events in this case.
		 */
520
		if (done && !disabled && !target__none(&opts->target)) {
521
			perf_evlist__disable(evsel_list);
522 523
			disabled = true;
		}
524 525
	}

526
	if (quiet || signr == SIGUSR1)
527 528
		return 0;

529 530
	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);

531 532 533 534
	/*
	 * Approximate RIP event size: 24 bytes.
	 */
	fprintf(stderr,
535
		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
536
		(double)rec->bytes_written / 1024.0 / 1024.0,
537
		file->path,
538
		rec->bytes_written / 24);
539

540
	return 0;
541 542 543 544

out_delete_session:
	perf_session__delete(session);
	return err;
545
}
546

547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
#define BRANCH_OPT(n, m) \
	{ .name = n, .mode = (m) }

#define BRANCH_END { .name = NULL }

struct branch_mode {
	const char *name;
	int mode;
};

static const struct branch_mode branch_modes[] = {
	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
565 566 567
	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
568 569 570 571
	BRANCH_END
};

static int
572
parse_branch_stack(const struct option *opt, const char *str, int unset)
573 574 575 576 577 578 579 580
{
#define ONLY_PLM \
	(PERF_SAMPLE_BRANCH_USER	|\
	 PERF_SAMPLE_BRANCH_KERNEL	|\
	 PERF_SAMPLE_BRANCH_HV)

	uint64_t *mode = (uint64_t *)opt->value;
	const struct branch_mode *br;
581
	char *s, *os = NULL, *p;
582 583
	int ret = -1;

584 585
	if (unset)
		return 0;
586

587 588 589 590
	/*
	 * cannot set it twice, -b + --branch-filter for instance
	 */
	if (*mode)
591 592
		return -1;

593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
	/* str may be NULL in case no arg is passed to -b */
	if (str) {
		/* because str is read-only */
		s = os = strdup(str);
		if (!s)
			return -1;

		for (;;) {
			p = strchr(s, ',');
			if (p)
				*p = '\0';

			for (br = branch_modes; br->name; br++) {
				if (!strcasecmp(s, br->name))
					break;
			}
			if (!br->name) {
				ui__warning("unknown branch filter %s,"
					    " check man page\n", s);
				goto error;
			}
614

615
			*mode |= br->mode;
616

617 618
			if (!p)
				break;
619

620 621
			s = p + 1;
		}
622 623 624
	}
	ret = 0;

625
	/* default to any branch */
626
	if ((*mode & ~ONLY_PLM) == 0) {
627
		*mode = PERF_SAMPLE_BRANCH_ANY;
628 629 630 631 632 633
	}
error:
	free(os);
	return ret;
}

634
#ifdef HAVE_LIBUNWIND_SUPPORT
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
static int get_stack_size(char *str, unsigned long *_size)
{
	char *endptr;
	unsigned long size;
	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));

	size = strtoul(str, &endptr, 0);

	do {
		if (*endptr)
			break;

		size = round_up(size, sizeof(u64));
		if (!size || size > max_size)
			break;

		*_size = size;
		return 0;

	} while (0);

	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
	       max_size, str);
	return -1;
}
660
#endif /* HAVE_LIBUNWIND_SUPPORT */
661

J
Jiri Olsa 已提交
662
int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
{
	char *tok, *name, *saveptr = NULL;
	char *buf;
	int ret = -1;

	/* We need buffer that we know we can write to. */
	buf = malloc(strlen(arg) + 1);
	if (!buf)
		return -ENOMEM;

	strcpy(buf, arg);

	tok = strtok_r((char *)buf, ",", &saveptr);
	name = tok ? : (char *)buf;

	do {
		/* Framepointer style */
		if (!strncmp(name, "fp", sizeof("fp"))) {
			if (!strtok_r(NULL, ",", &saveptr)) {
682
				opts->call_graph = CALLCHAIN_FP;
683 684 685 686 687 688
				ret = 0;
			} else
				pr_err("callchain: No more arguments "
				       "needed for -g fp\n");
			break;

689
#ifdef HAVE_LIBUNWIND_SUPPORT
690 691
		/* Dwarf style */
		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
692 693
			const unsigned long default_stack_dump_size = 8192;

694
			ret = 0;
695 696
			opts->call_graph = CALLCHAIN_DWARF;
			opts->stack_dump_size = default_stack_dump_size;
697 698 699 700 701 702

			tok = strtok_r(NULL, ",", &saveptr);
			if (tok) {
				unsigned long size = 0;

				ret = get_stack_size(tok, &size);
703
				opts->stack_dump_size = size;
704
			}
705
#endif /* HAVE_LIBUNWIND_SUPPORT */
706
		} else {
J
Jiri Olsa 已提交
707
			pr_err("callchain: Unknown --call-graph option "
708 709 710 711 712 713 714
			       "value: %s\n", arg);
			break;
		}

	} while (0);

	free(buf);
J
Jiri Olsa 已提交
715 716 717 718 719 720
	return ret;
}

static void callchain_debug(struct perf_record_opts *opts)
{
	pr_debug("callchain: type %d\n", opts->call_graph);
721

J
Jiri Olsa 已提交
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
	if (opts->call_graph == CALLCHAIN_DWARF)
		pr_debug("callchain: stack dump size %d\n",
			 opts->stack_dump_size);
}

int record_parse_callchain_opt(const struct option *opt,
			       const char *arg,
			       int unset)
{
	struct perf_record_opts *opts = opt->value;
	int ret;

	/* --no-call-graph */
	if (unset) {
		opts->call_graph = CALLCHAIN_NONE;
		pr_debug("callchain: disabled\n");
		return 0;
	}

	ret = record_parse_callchain(arg, opts);
742
	if (!ret)
J
Jiri Olsa 已提交
743
		callchain_debug(opts);
744 745 746 747

	return ret;
}

J
Jiri Olsa 已提交
748 749 750 751 752 753 754 755 756 757 758 759 760
int record_callchain_opt(const struct option *opt,
			 const char *arg __maybe_unused,
			 int unset __maybe_unused)
{
	struct perf_record_opts *opts = opt->value;

	if (opts->call_graph == CALLCHAIN_NONE)
		opts->call_graph = CALLCHAIN_FP;

	callchain_debug(opts);
	return 0;
}

761
static const char * const record_usage[] = {
762 763
	"perf record [<options>] [<command>]",
	"perf record [<options>] -- <command> [<options>]",
764 765 766
	NULL
};

767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
/*
 * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
 * because we need to have access to it in perf_record__exit, that is called
 * after cmd_record() exits, but since record_options need to be accessible to
 * builtin-script, leave it here.
 *
 * At least we don't ouch it in all the other functions here directly.
 *
 * Just say no to tons of global variables, sigh.
 */
static struct perf_record record = {
	.opts = {
		.mmap_pages	     = UINT_MAX,
		.user_freq	     = UINT_MAX,
		.user_interval	     = ULLONG_MAX,
782
		.freq		     = 4000,
N
Namhyung Kim 已提交
783 784
		.target		     = {
			.uses_mmap   = true,
785
			.default_per_cpu = true,
N
Namhyung Kim 已提交
786
		},
787 788
	},
};
789

J
Jiri Olsa 已提交
790
#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
791

792
#ifdef HAVE_LIBUNWIND_SUPPORT
J
Jiri Olsa 已提交
793
const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
794
#else
J
Jiri Olsa 已提交
795
const char record_callchain_help[] = CALLCHAIN_HELP "fp";
796 797
#endif

798 799 800 801 802 803 804
/*
 * XXX Will stay a global variable till we fix builtin-script.c to stop messing
 * with it and switch to use the library functions in perf_evlist that came
 * from builtin-record.c, i.e. use perf_record_opts,
 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
 * using pipes, etc.
 */
805
const struct option record_options[] = {
806
	OPT_CALLBACK('e', "event", &record.evlist, "event",
807
		     "event selector. use 'perf list' to list available events",
808
		     parse_events_option),
809
	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
L
Li Zefan 已提交
810
		     "event filter", parse_filter),
811
	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
812
		    "record events on existing process id"),
813
	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
814
		    "record events on existing thread id"),
815
	OPT_INTEGER('r', "realtime", &record.realtime_prio,
816
		    "collect data with this RT SCHED_FIFO priority"),
817
	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
818
		    "collect data without buffering"),
819
	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
820
		    "collect raw sample records from all opened counters"),
821
	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
822
			    "system-wide collection from all CPUs"),
823
	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
824
		    "list of cpus to monitor"),
825
	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
826
	OPT_STRING('o', "output", &record.file.path, "file",
I
Ingo Molnar 已提交
827
		    "output file name"),
828 829 830
	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
			&record.opts.no_inherit_set,
			"child tasks do not inherit counters"),
831
	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
832 833 834
	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
		     "number of mmap data pages",
		     perf_evlist__parse_mmap_pages),
835
	OPT_BOOLEAN(0, "group", &record.opts.group,
836
		    "put the counters into a counter group"),
J
Jiri Olsa 已提交
837 838 839 840 841 842
	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
			   NULL, "enables call-graph recording" ,
			   &record_callchain_opt),
	OPT_CALLBACK(0, "call-graph", &record.opts,
		     "mode[,dump_size]", record_callchain_help,
		     &record_parse_callchain_opt),
843
	OPT_INCR('v', "verbose", &verbose,
844
		    "be more verbose (show counter open errors, etc)"),
845
	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
846
	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
847
		    "per thread counts"),
848
	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
849
		    "Sample addresses"),
850
	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
851
	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
852
	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
853
		    "don't sample"),
854
	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
855
		    "do not update the buildid cache"),
856
	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
857
		    "do not collect buildids in perf.data"),
858
	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
S
Stephane Eranian 已提交
859 860
		     "monitor event in cgroup name only",
		     parse_cgroups),
861 862
	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
		   "user to profile"),
863 864 865 866 867 868 869

	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
		     "branch any", "sample any taken branches",
		     parse_branch_stack),

	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
		     "branch filter mask", "branch stack filter modes",
870
		     parse_branch_stack),
871 872
	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
		    "sample by weight (on special events only)"),
873 874
	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
		    "sample transaction flags (special events only)"),
875 876
	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
		    "use per-thread mmaps"),
877 878 879
	OPT_END()
};

880
int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
881
{
882
	int err = -ENOMEM;
883 884
	struct perf_evlist *evsel_list;
	struct perf_record *rec = &record;
885
	char errbuf[BUFSIZ];
886

887
	evsel_list = perf_evlist__new();
888 889 890
	if (evsel_list == NULL)
		return -ENOMEM;

891 892
	rec->evlist = evsel_list;

893
	argc = parse_options(argc, argv, record_options, record_usage,
894
			    PARSE_OPT_STOP_AT_NON_OPTION);
895
	if (!argc && target__none(&rec->opts.target))
896
		usage_with_options(record_usage, record_options);
897

898
	if (nr_cgroups && !rec->opts.target.system_wide) {
899 900
		ui__error("cgroup monitoring only available in"
			  " system-wide mode\n");
S
Stephane Eranian 已提交
901 902 903
		usage_with_options(record_usage, record_options);
	}

904
	symbol__init();
905

906
	if (symbol_conf.kptr_restrict)
907 908 909 910 911 912 913 914
		pr_warning(
"WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
"check /proc/sys/kernel/kptr_restrict.\n\n"
"Samples in kernel functions may not be resolved if a suitable vmlinux\n"
"file is not found in the buildid cache or in the vmlinux path.\n\n"
"Samples in kernel modules won't be resolved at all.\n\n"
"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
"even with a suitable vmlinux or kallsyms file.\n\n");
915

916
	if (rec->no_buildid_cache || rec->no_buildid)
917
		disable_buildid_cache();
918

919 920
	if (evsel_list->nr_entries == 0 &&
	    perf_evlist__add_default(evsel_list) < 0) {
921 922
		pr_err("Not enough memory for event selector list\n");
		goto out_symbol_exit;
923
	}
924

925 926 927
	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
		rec->opts.no_inherit = true;

928
	err = target__validate(&rec->opts.target);
929
	if (err) {
930
		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
931 932 933
		ui__warning("%s", errbuf);
	}

934
	err = target__parse_uid(&rec->opts.target);
935 936
	if (err) {
		int saved_errno = errno;
937

938
		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
939
		ui__error("%s", errbuf);
940 941

		err = -saved_errno;
942
		goto out_symbol_exit;
943
	}
944

945
	err = -ENOMEM;
946
	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
947
		usage_with_options(record_usage, record_options);
948

949
	if (perf_record_opts__config(&rec->opts)) {
950
		err = -EINVAL;
951
		goto out_free_fd;
952 953
	}

954
	err = __cmd_record(&record, argc, argv);
955 956 957

	perf_evlist__munmap(evsel_list);
	perf_evlist__close(evsel_list);
958
out_free_fd:
959
	perf_evlist__delete_maps(evsel_list);
960 961
out_symbol_exit:
	symbol__exit();
962
	return err;
963
}