builtin-record.c 25.1 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 9
#define _FILE_OFFSET_BITS 64

10
#include "builtin.h"
11 12 13

#include "perf.h"

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

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

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

34 35 36 37 38
enum write_mode_t {
	WRITE_FORCE,
	WRITE_APPEND
};

39
struct perf_record {
40
	struct perf_tool	tool;
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
	struct perf_record_opts	opts;
	u64			bytes_written;
	const char		*output_name;
	struct perf_evlist	*evlist;
	struct perf_session	*session;
	const char		*progname;
	int			output;
	unsigned int		page_size;
	int			realtime_prio;
	enum write_mode_t	write_mode;
	bool			no_buildid;
	bool			no_buildid_cache;
	bool			force;
	bool			file_new;
	bool			append_file;
	long			samples;
	off_t			post_processing_offset;
58
};
59

60
static void advance_output(struct perf_record *rec, size_t size)
61
{
62
	rec->bytes_written += size;
63 64
}

65
static void write_output(struct perf_record *rec, void *buf, size_t size)
66 67
{
	while (size) {
68
		int ret = write(rec->output, buf, size);
69 70 71 72 73 74 75

		if (ret < 0)
			die("failed to write");

		size -= ret;
		buf += ret;

76
		rec->bytes_written += ret;
77 78 79
	}
}

80
static int process_synthesized_event(struct perf_tool *tool,
81
				     union perf_event *event,
82
				     struct perf_sample *sample __used,
83
				     struct machine *machine __used)
84
{
85
	struct perf_record *rec = container_of(tool, struct perf_record, tool);
86
	write_output(rec, event, event->header.size);
87 88 89
	return 0;
}

90 91
static void perf_record__mmap_read(struct perf_record *rec,
				   struct perf_mmap *md)
92
{
93
	unsigned int head = perf_mmap__read_head(md);
94
	unsigned int old = md->prev;
95
	unsigned char *data = md->base + rec->page_size;
96 97 98
	unsigned long size;
	void *buf;

99 100 101
	if (old == head)
		return;

102
	rec->samples++;
103 104 105 106 107 108 109

	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;
110

111
		write_output(rec, buf, size);
112 113 114 115 116
	}

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

118
	write_output(rec, buf, size);
119 120

	md->prev = old;
121
	perf_mmap__write_tail(md, old);
122 123 124
}

static volatile int done = 0;
125
static volatile int signr = -1;
126
static volatile int child_finished = 0;
127

128
static void sig_handler(int sig)
129
{
130 131 132
	if (sig == SIGCHLD)
		child_finished = 1;

133
	done = 1;
134 135 136
	signr = sig;
}

137
static void perf_record__sig_exit(int exit_status __used, void *arg)
138
{
139
	struct perf_record *rec = arg;
140 141
	int status;

142
	if (rec->evlist->workload.pid > 0) {
143
		if (!child_finished)
144
			kill(rec->evlist->workload.pid, SIGTERM);
145 146 147

		wait(&status);
		if (WIFSIGNALED(status))
148
			psignal(WTERMSIG(status), rec->progname);
149
	}
150

151
	if (signr == -1 || signr == SIGUSR1)
152 153 154 155
		return;

	signal(signr, SIG_DFL);
	kill(getpid(), signr);
156 157
}

158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
static bool perf_evlist__equal(struct perf_evlist *evlist,
			       struct perf_evlist *other)
{
	struct perf_evsel *pos, *pair;

	if (evlist->nr_entries != other->nr_entries)
		return false;

	pair = list_entry(other->entries.next, struct perf_evsel, node);

	list_for_each_entry(pos, &evlist->entries, node) {
		if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
			return false;
		pair = list_entry(pair->node.next, struct perf_evsel, node);
	}

	return true;
}

177
static void perf_record__open(struct perf_record *rec)
178
{
179
	struct perf_evsel *pos, *first;
180 181 182
	struct perf_evlist *evlist = rec->evlist;
	struct perf_session *session = rec->session;
	struct perf_record_opts *opts = &rec->opts;
183

184 185
	first = list_entry(evlist->entries.next, struct perf_evsel, node);

186
	perf_evlist__config_attrs(evlist, opts);
187

188 189
	list_for_each_entry(pos, &evlist->entries, node) {
		struct perf_event_attr *attr = &pos->attr;
190
		struct xyarray *group_fd = NULL;
191 192 193 194 195 196 197 198 199 200 201 202 203
		/*
		 * Check if parse_single_tracepoint_event has already asked for
		 * PERF_SAMPLE_TIME.
		 *
		 * XXX this is kludgy but short term fix for problems introduced by
		 * eac23d1c that broke 'perf script' by having different sample_types
		 * when using multiple tracepoint events when we use a perf binary
		 * that tries to use sample_id_all on an older kernel.
		 *
		 * We need to move counter creation to perf_session, support
		 * different sample_types, etc.
		 */
		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
204

205
		if (opts->group && pos != first)
206
			group_fd = first->fd;
207 208 209
fallback_missing_features:
		if (opts->exclude_guest_missing)
			attr->exclude_guest = attr->exclude_host = 0;
210
retry_sample_id:
211
		attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
212
try_again:
213
		if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
214
				     opts->group, group_fd) < 0) {
215 216
			int err = errno;

217
			if (err == EPERM || err == EACCES) {
218
				ui__error_paranoid();
219
				exit(EXIT_FAILURE);
220
			} else if (err ==  ENODEV && opts->target.cpu_list) {
221 222
				die("No such device - did you specify"
					" an out-of-range profile CPU?\n");
223 224 225 226 227 228 229
			} else if (err == EINVAL) {
				if (!opts->exclude_guest_missing &&
				    (attr->exclude_guest || attr->exclude_host)) {
					pr_debug("Old kernel, cannot exclude "
						 "guest or host samples.\n");
					opts->exclude_guest_missing = true;
					goto fallback_missing_features;
230
				} else if (!opts->sample_id_all_missing) {
231 232 233
					/*
					 * Old kernel, no attr->sample_id_type_all field
					 */
234
					opts->sample_id_all_missing = true;
235 236 237 238 239
					if (!opts->sample_time && !opts->raw_samples && !time_needed)
						attr->sample_type &= ~PERF_SAMPLE_TIME;

					goto retry_sample_id;
				}
240
			}
241

242 243 244 245 246
			/*
			 * If it's cycles then fall back to hrtimer
			 * based cpu-clock-tick sw counter, which
			 * is always available even if no PMU support:
			 */
247
			if (err == ENOENT && attr->type == PERF_TYPE_HARDWARE
248 249 250
					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {

				if (verbose)
251 252
					ui__warning("The cycles event is not supported, "
						    "trying to fall back to cpu-clock-ticks\n");
253 254 255 256
				attr->type = PERF_TYPE_SOFTWARE;
				attr->config = PERF_COUNT_SW_CPU_CLOCK;
				goto try_again;
			}
257 258 259 260 261 262 263

			if (err == ENOENT) {
				ui__warning("The %s event is not supported.\n",
					    event_name(pos));
				exit(EXIT_FAILURE);
			}

264
			printf("\n");
265
			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
266
			      err, strerror(err));
267 268

#if defined(__i386__) || defined(__x86_64__)
269 270 271 272 273
			if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
				die("No hardware sampling interrupt available."
				    " No APIC? If so then you can boot the kernel"
				    " with the \"lapic\" boot parameter to"
				    " force-enable it.\n");
274 275
#endif

276
			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
L
Li Zefan 已提交
277 278
		}
	}
279

280 281 282 283 284 285
	if (perf_evlist__set_filters(evlist)) {
		error("failed to set filter with %d (%s)\n", errno,
			strerror(errno));
		exit(-1);
	}

286 287 288 289 290 291 292
	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
		if (errno == EPERM)
			die("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"
			    "(current value: %d)\n", opts->mmap_pages);
293 294 295
		else if (!is_power_of_2(opts->mmap_pages))
			die("--mmap_pages/-m value must be a power of two.");

296
		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
297
	}
298

299
	if (rec->file_new)
300 301 302 303 304 305 306 307 308
		session->evlist = evlist;
	else {
		if (!perf_evlist__equal(session->evlist, evlist)) {
			fprintf(stderr, "incompatible append\n");
			exit(-1);
		}
 	}

	perf_session__update_sample_type(session);
309 310
}

311
static int process_buildids(struct perf_record *rec)
312
{
313
	u64 size = lseek(rec->output, 0, SEEK_CUR);
314

315 316 317
	if (size == 0)
		return 0;

318 319 320
	rec->session->fd = rec->output;
	return __perf_session__process_events(rec->session, rec->post_processing_offset,
					      size - rec->post_processing_offset,
321 322 323
					      size, &build_id__mark_dso_hit_ops);
}

324
static void perf_record__exit(int status __used, void *arg)
325
{
326 327 328 329 330 331 332 333 334 335 336
	struct perf_record *rec = arg;

	if (!rec->opts.pipe_output) {
		rec->session->header.data_size += rec->bytes_written;

		if (!rec->no_buildid)
			process_buildids(rec);
		perf_session__write_header(rec->session, rec->evlist,
					   rec->output, true);
		perf_session__delete(rec->session);
		perf_evlist__delete(rec->evlist);
337
		symbol__exit();
338
	}
339 340
}

341
static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
342 343
{
	int err;
344
	struct perf_tool *tool = data;
345

346
	if (machine__is_host(machine))
347 348 349 350 351 352 353 354 355 356
		return;

	/*
	 *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.
	 */
357
	err = perf_event__synthesize_modules(tool, process_synthesized_event,
358
					     machine);
359 360
	if (err < 0)
		pr_err("Couldn't record guest kernel [%d]'s reference"
361
		       " relocation symbol.\n", machine->pid);
362 363 364 365 366

	/*
	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
	 * have no _text sometimes.
	 */
367
	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
368
						 machine, "_text");
369
	if (err < 0)
370
		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
371
							 machine, "_stext");
372 373
	if (err < 0)
		pr_err("Couldn't record guest kernel [%d]'s reference"
374
		       " relocation symbol.\n", machine->pid);
375 376
}

377 378 379 380 381
static struct perf_event_header finished_round_event = {
	.size = sizeof(struct perf_event_header),
	.type = PERF_RECORD_FINISHED_ROUND,
};

382
static void perf_record__mmap_read_all(struct perf_record *rec)
383
{
384
	int i;
385

386 387 388
	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
		if (rec->evlist->mmap[i].base)
			perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
389 390
	}

391 392
	if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
		write_output(rec, &finished_round_event, sizeof(finished_round_event));
393 394
}

395
static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
396
{
I
Ingo Molnar 已提交
397 398
	struct stat st;
	int flags;
399
	int err, output, feat;
400
	unsigned long waking = 0;
401
	const bool forks = argc > 0;
402
	struct machine *machine;
403
	struct perf_tool *tool = &rec->tool;
404 405 406 407
	struct perf_record_opts *opts = &rec->opts;
	struct perf_evlist *evsel_list = rec->evlist;
	const char *output_name = rec->output_name;
	struct perf_session *session;
408

409
	rec->progname = argv[0];
410

411
	rec->page_size = sysconf(_SC_PAGE_SIZE);
412

413
	on_exit(perf_record__sig_exit, rec);
414 415
	signal(SIGCHLD, sig_handler);
	signal(SIGINT, sig_handler);
416
	signal(SIGUSR1, sig_handler);
417

418 419
	if (!output_name) {
		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
420
			opts->pipe_output = true;
421
		else
422
			rec->output_name = output_name = "perf.data";
423 424 425
	}
	if (output_name) {
		if (!strcmp(output_name, "-"))
426
			opts->pipe_output = true;
427
		else if (!stat(output_name, &st) && st.st_size) {
428
			if (rec->write_mode == WRITE_FORCE) {
429 430 431 432 433 434
				char oldname[PATH_MAX];
				snprintf(oldname, sizeof(oldname), "%s.old",
					 output_name);
				unlink(oldname);
				rename(output_name, oldname);
			}
435 436
		} else if (rec->write_mode == WRITE_APPEND) {
			rec->write_mode = WRITE_FORCE;
437
		}
438 439
	}

440
	flags = O_CREAT|O_RDWR;
441 442
	if (rec->write_mode == WRITE_APPEND)
		rec->file_new = 0;
I
Ingo Molnar 已提交
443 444 445
	else
		flags |= O_TRUNC;

446
	if (opts->pipe_output)
447 448 449
		output = STDOUT_FILENO;
	else
		output = open(output_name, flags, S_IRUSR | S_IWUSR);
450 451 452 453 454
	if (output < 0) {
		perror("failed to create output file");
		exit(-1);
	}

455 456
	rec->output = output;

457
	session = perf_session__new(output_name, O_WRONLY,
458
				    rec->write_mode == WRITE_FORCE, false, NULL);
459
	if (session == NULL) {
460 461 462 463
		pr_err("Not enough memory for reading perf file header\n");
		return -1;
	}

464 465
	rec->session = session;

466 467 468 469 470 471 472 473
	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_TRACE_INFO);
474

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

478
	if (!rec->file_new) {
479
		err = perf_session__read_header(session, output);
480
		if (err < 0)
481
			goto out_delete_session;
482 483
	}

484
	if (forks) {
485
		err = perf_evlist__prepare_workload(evsel_list, opts, argv);
486 487 488
		if (err < 0) {
			pr_err("Couldn't run the workload!\n");
			goto out_delete_session;
489 490 491
		}
	}

492
	perf_record__open(rec);
493

494
	/*
495
	 * perf_session__delete(session) will be called at perf_record__exit()
496
	 */
497
	on_exit(perf_record__exit, rec);
498

499
	if (opts->pipe_output) {
500 501 502
		err = perf_header__write_pipe(output);
		if (err < 0)
			return err;
503
	} else if (rec->file_new) {
504 505
		err = perf_session__write_header(session, evsel_list,
						 output, false);
506 507
		if (err < 0)
			return err;
508 509
	}

510
	if (!rec->no_buildid
511
	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
512
		pr_err("Couldn't generate buildids. "
513 514 515 516
		       "Use --no-buildid to profile anyway.\n");
		return -1;
	}

517
	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
518

519 520 521 522 523 524
	machine = perf_session__find_host_machine(session);
	if (!machine) {
		pr_err("Couldn't find native kernel information.\n");
		return -1;
	}

525
	if (opts->pipe_output) {
526
		err = perf_event__synthesize_attrs(tool, session,
527
						   process_synthesized_event);
528 529 530 531
		if (err < 0) {
			pr_err("Couldn't synthesize attrs.\n");
			return err;
		}
532

533
		err = perf_event__synthesize_event_types(tool, process_synthesized_event,
534
							 machine);
535 536 537 538
		if (err < 0) {
			pr_err("Couldn't synthesize event_types.\n");
			return err;
		}
539

540
		if (have_tracepoints(&evsel_list->entries)) {
541 542 543 544 545 546 547 548
			/*
			 * 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()
			 */
549
			err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
550
								  process_synthesized_event);
551 552 553 554
			if (err <= 0) {
				pr_err("Couldn't record tracing data.\n");
				return err;
			}
555
			advance_output(rec, err);
556
		}
557 558
	}

559
	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
560
						 machine, "_text");
561
	if (err < 0)
562
		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
563
							 machine, "_stext");
564 565 566 567
	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");
568

569
	err = perf_event__synthesize_modules(tool, process_synthesized_event,
570
					     machine);
571 572 573 574 575
	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");

576
	if (perf_guest)
577
		perf_session__process_machines(session, tool,
578
					       perf_event__synthesize_guest_os);
579

580
	if (!opts->target.system_wide)
581
		perf_event__synthesize_thread_map(tool, evsel_list->threads,
582
						  process_synthesized_event,
583
						  machine);
584
	else
585
		perf_event__synthesize_threads(tool, process_synthesized_event,
586
					       machine);
587

588
	if (rec->realtime_prio) {
589 590
		struct sched_param param;

591
		param.sched_priority = rec->realtime_prio;
592
		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
593
			pr_err("Could not set realtime priority.\n");
594 595 596 597
			exit(-1);
		}
	}

598 599
	perf_evlist__enable(evsel_list);

600 601 602
	/*
	 * Let the child rip
	 */
603
	if (forks)
604
		perf_evlist__start_workload(evsel_list);
605

606
	for (;;) {
607
		int hits = rec->samples;
608

609
		perf_record__mmap_read_all(rec);
610

611
		if (hits == rec->samples) {
612 613
			if (done)
				break;
614
			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
615 616 617
			waking++;
		}

618 619
		if (done)
			perf_evlist__disable(evsel_list);
620 621
	}

622
	if (quiet || signr == SIGUSR1)
623 624
		return 0;

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

627 628 629 630
	/*
	 * Approximate RIP event size: 24 bytes.
	 */
	fprintf(stderr,
631
		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
632
		(double)rec->bytes_written / 1024.0 / 1024.0,
633
		output_name,
634
		rec->bytes_written / 24);
635

636
	return 0;
637 638 639 640

out_delete_session:
	perf_session__delete(session);
	return err;
641
}
642

643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
#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),
	BRANCH_END
};

static int
665
parse_branch_stack(const struct option *opt, const char *str, int unset)
666 667 668 669 670 671 672 673
{
#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;
674
	char *s, *os = NULL, *p;
675 676
	int ret = -1;

677 678
	if (unset)
		return 0;
679

680 681 682 683
	/*
	 * cannot set it twice, -b + --branch-filter for instance
	 */
	if (*mode)
684 685
		return -1;

686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
	/* 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;
			}
707

708
			*mode |= br->mode;
709

710 711
			if (!p)
				break;
712

713 714
			s = p + 1;
		}
715 716 717
	}
	ret = 0;

718
	/* default to any branch */
719
	if ((*mode & ~ONLY_PLM) == 0) {
720
		*mode = PERF_SAMPLE_BRANCH_ANY;
721 722 723 724 725 726
	}
error:
	free(os);
	return ret;
}

727
static const char * const record_usage[] = {
728 729
	"perf record [<options>] [<command>]",
	"perf record [<options>] -- <command> [<options>]",
730 731 732
	NULL
};

733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
/*
 * 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,
		.freq		     = 1000,
	},
	.write_mode = WRITE_FORCE,
	.file_new   = true,
};
753

754 755 756 757 758 759 760
/*
 * 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.
 */
761
const struct option record_options[] = {
762
	OPT_CALLBACK('e', "event", &record.evlist, "event",
763
		     "event selector. use 'perf list' to list available events",
764
		     parse_events_option),
765
	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
L
Li Zefan 已提交
766
		     "event filter", parse_filter),
767
	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
768
		    "record events on existing process id"),
769
	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
770
		    "record events on existing thread id"),
771
	OPT_INTEGER('r', "realtime", &record.realtime_prio,
772
		    "collect data with this RT SCHED_FIFO priority"),
773
	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
774
		    "collect data without buffering"),
775
	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
776
		    "collect raw sample records from all opened counters"),
777
	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
778
			    "system-wide collection from all CPUs"),
779
	OPT_BOOLEAN('A', "append", &record.append_file,
I
Ingo Molnar 已提交
780
			    "append to the output file to do incremental profiling"),
781
	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
782
		    "list of cpus to monitor"),
783
	OPT_BOOLEAN('f', "force", &record.force,
784
			"overwrite existing data file (deprecated)"),
785 786
	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
	OPT_STRING('o', "output", &record.output_name, "file",
I
Ingo Molnar 已提交
787
		    "output file name"),
788
	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
789
		    "child tasks do not inherit counters"),
790 791
	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
792
		     "number of mmap data pages"),
793
	OPT_BOOLEAN(0, "group", &record.opts.group,
794
		    "put the counters into a counter group"),
795
	OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
796
		    "do call-graph (stack chain/backtrace) recording"),
797
	OPT_INCR('v', "verbose", &verbose,
798
		    "be more verbose (show counter open errors, etc)"),
799
	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
800
	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
801
		    "per thread counts"),
802
	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
803
		    "Sample addresses"),
804
	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
805
	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
806
	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
807
		    "don't sample"),
808
	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
809
		    "do not update the buildid cache"),
810
	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
811
		    "do not collect buildids in perf.data"),
812
	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
S
Stephane Eranian 已提交
813 814
		     "monitor event in cgroup name only",
		     parse_cgroups),
815 816
	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
		   "user to profile"),
817 818 819 820 821 822 823

	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",
824
		     parse_branch_stack),
825 826 827
	OPT_END()
};

828
int cmd_record(int argc, const char **argv, const char *prefix __used)
829
{
830 831
	int err = -ENOMEM;
	struct perf_evsel *pos;
832 833
	struct perf_evlist *evsel_list;
	struct perf_record *rec = &record;
834

835 836
	perf_header__set_cmdline(argc, argv);

837
	evsel_list = perf_evlist__new(NULL, NULL);
838 839 840
	if (evsel_list == NULL)
		return -ENOMEM;

841 842
	rec->evlist = evsel_list;

843
	argc = parse_options(argc, argv, record_options, record_usage,
844
			    PARSE_OPT_STOP_AT_NON_OPTION);
845 846 847
	if (!argc && !rec->opts.target.pid && !rec->opts.target.tid &&
	    !rec->opts.target.system_wide && !rec->opts.target.cpu_list &&
	    !rec->opts.target.uid_str)
848
		usage_with_options(record_usage, record_options);
849

850
	if (rec->force && rec->append_file) {
851 852
		fprintf(stderr, "Can't overwrite and append at the same time."
				" You need to choose between -f and -A");
853
		usage_with_options(record_usage, record_options);
854 855
	} else if (rec->append_file) {
		rec->write_mode = WRITE_APPEND;
856
	} else {
857
		rec->write_mode = WRITE_FORCE;
858 859
	}

860
	if (nr_cgroups && !rec->opts.target.system_wide) {
S
Stephane Eranian 已提交
861 862 863 864 865
		fprintf(stderr, "cgroup monitoring only available in"
			" system-wide mode\n");
		usage_with_options(record_usage, record_options);
	}

866
	symbol__init();
867

868
	if (symbol_conf.kptr_restrict)
869 870 871 872 873 874 875 876
		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");
877

878
	if (rec->no_buildid_cache || rec->no_buildid)
879
		disable_buildid_cache();
880

881 882
	if (evsel_list->nr_entries == 0 &&
	    perf_evlist__add_default(evsel_list) < 0) {
883 884
		pr_err("Not enough memory for event selector list\n");
		goto out_symbol_exit;
885
	}
886

887 888 889 890 891
	rec->opts.target.uid = parse_target_uid(rec->opts.target.uid_str,
						rec->opts.target.tid,
						rec->opts.target.pid);
	if (rec->opts.target.uid_str != NULL &&
	    rec->opts.target.uid == UINT_MAX - 1)
892 893
		goto out_free_fd;

894 895
	if (rec->opts.target.pid)
		rec->opts.target.tid = rec->opts.target.pid;
896

897 898 899
	if (perf_evlist__create_maps(evsel_list, rec->opts.target.pid,
				     rec->opts.target.tid, rec->opts.target.uid,
				     rec->opts.target.cpu_list) < 0)
900
		usage_with_options(record_usage, record_options);
901

902
	list_for_each_entry(pos, &evsel_list->entries, node) {
903 904
		if (perf_header__push_event(pos->attr.config, event_name(pos)))
			goto out_free_fd;
905
	}
906

907 908 909 910
	if (rec->opts.user_interval != ULLONG_MAX)
		rec->opts.default_interval = rec->opts.user_interval;
	if (rec->opts.user_freq != UINT_MAX)
		rec->opts.freq = rec->opts.user_freq;
911

912 913 914
	/*
	 * User specified count overrides default frequency.
	 */
915 916 917 918
	if (rec->opts.default_interval)
		rec->opts.freq = 0;
	else if (rec->opts.freq) {
		rec->opts.default_interval = rec->opts.freq;
919 920
	} else {
		fprintf(stderr, "frequency and count are zero, aborting\n");
921
		err = -EINVAL;
922
		goto out_free_fd;
923 924
	}

925
	err = __cmd_record(&record, argc, argv);
926
out_free_fd:
927
	perf_evlist__delete_maps(evsel_list);
928 929
out_symbol_exit:
	symbol__exit();
930
	return err;
931
}