builtin-record.c 23.3 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
	struct perf_record_opts	opts;
	u64			bytes_written;
	const char		*output_name;
	struct perf_evlist	*evlist;
	struct perf_session	*session;
	const char		*progname;
47
	const char		*uid_str;
48 49 50 51 52 53 54 55 56 57 58
	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;
59
};
60

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

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

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

		size -= ret;
		buf += ret;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
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;
}

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

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

187
	perf_evlist__config_attrs(evlist, opts);
188

189 190
	list_for_each_entry(pos, &evlist->entries, node) {
		struct perf_event_attr *attr = &pos->attr;
191
		struct xyarray *group_fd = NULL;
192 193 194 195 196 197 198 199 200 201 202 203 204
		/*
		 * 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;
205

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

215
			if (err == EPERM || err == EACCES) {
216
				ui__error_paranoid();
217
				exit(EXIT_FAILURE);
218
			} else if (err ==  ENODEV && opts->cpu_list) {
219 220
				die("No such device - did you specify"
					" an out-of-range profile CPU?\n");
221
			} else if (err == EINVAL && opts->sample_id_all_avail) {
222 223 224
				/*
				 * Old kernel, no attr->sample_id_type_all field
				 */
225 226
				opts->sample_id_all_avail = false;
				if (!opts->sample_time && !opts->raw_samples && !time_needed)
227 228
					attr->sample_type &= ~PERF_SAMPLE_TIME;

229
				goto retry_sample_id;
230
			}
231

232 233 234 235 236 237 238 239 240
			/*
			 * If it's cycles then fall back to hrtimer
			 * based cpu-clock-tick sw counter, which
			 * is always available even if no PMU support:
			 */
			if (attr->type == PERF_TYPE_HARDWARE
					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {

				if (verbose)
241 242
					ui__warning("The cycles event is not supported, "
						    "trying to fall back to cpu-clock-ticks\n");
243 244 245 246
				attr->type = PERF_TYPE_SOFTWARE;
				attr->config = PERF_COUNT_SW_CPU_CLOCK;
				goto try_again;
			}
247 248 249 250 251 252 253

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

254
			printf("\n");
255
			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
256
			      err, strerror(err));
257 258

#if defined(__i386__) || defined(__x86_64__)
259 260 261 262 263
			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");
264 265
#endif

266
			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
L
Li Zefan 已提交
267 268
		}
	}
269

270 271 272 273 274 275
	if (perf_evlist__set_filters(evlist)) {
		error("failed to set filter with %d (%s)\n", errno,
			strerror(errno));
		exit(-1);
	}

276 277 278 279 280 281 282
	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);
283 284 285
		else if (!is_power_of_2(opts->mmap_pages))
			die("--mmap_pages/-m value must be a power of two.");

286
		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
287
	}
288

289
	if (rec->file_new)
290 291 292 293 294 295 296 297 298
		session->evlist = evlist;
	else {
		if (!perf_evlist__equal(session->evlist, evlist)) {
			fprintf(stderr, "incompatible append\n");
			exit(-1);
		}
 	}

	perf_session__update_sample_type(session);
299 300
}

301
static int process_buildids(struct perf_record *rec)
302
{
303
	u64 size = lseek(rec->output, 0, SEEK_CUR);
304

305 306 307
	if (size == 0)
		return 0;

308 309 310
	rec->session->fd = rec->output;
	return __perf_session__process_events(rec->session, rec->post_processing_offset,
					      size - rec->post_processing_offset,
311 312 313
					      size, &build_id__mark_dso_hit_ops);
}

314
static void perf_record__exit(int status __used, void *arg)
315
{
316 317 318 319 320 321 322 323 324 325 326
	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);
327
		symbol__exit();
328
	}
329 330
}

331
static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
332 333
{
	int err;
334
	struct perf_tool *tool = data;
335

336
	if (machine__is_host(machine))
337 338 339 340 341 342 343 344 345 346
		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.
	 */
347
	err = perf_event__synthesize_modules(tool, process_synthesized_event,
348
					     machine);
349 350
	if (err < 0)
		pr_err("Couldn't record guest kernel [%d]'s reference"
351
		       " relocation symbol.\n", machine->pid);
352 353 354 355 356

	/*
	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
	 * have no _text sometimes.
	 */
357
	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
358
						 machine, "_text");
359
	if (err < 0)
360
		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
361
							 machine, "_stext");
362 363
	if (err < 0)
		pr_err("Couldn't record guest kernel [%d]'s reference"
364
		       " relocation symbol.\n", machine->pid);
365 366
}

367 368 369 370 371
static struct perf_event_header finished_round_event = {
	.size = sizeof(struct perf_event_header),
	.type = PERF_RECORD_FINISHED_ROUND,
};

372
static void perf_record__mmap_read_all(struct perf_record *rec)
373
{
374
	int i;
375

376 377 378
	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
		if (rec->evlist->mmap[i].base)
			perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
379 380
	}

381 382
	if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
		write_output(rec, &finished_round_event, sizeof(finished_round_event));
383 384
}

385
static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
386
{
I
Ingo Molnar 已提交
387 388
	struct stat st;
	int flags;
389
	int err, output;
390
	unsigned long waking = 0;
391
	const bool forks = argc > 0;
392
	struct machine *machine;
393
	struct perf_tool *tool = &rec->tool;
394 395 396 397
	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;
398

399
	rec->progname = argv[0];
400

401
	rec->page_size = sysconf(_SC_PAGE_SIZE);
402

403
	on_exit(perf_record__sig_exit, rec);
404 405
	signal(SIGCHLD, sig_handler);
	signal(SIGINT, sig_handler);
406
	signal(SIGUSR1, sig_handler);
407

408 409
	if (!output_name) {
		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
410
			opts->pipe_output = true;
411
		else
412
			rec->output_name = output_name = "perf.data";
413 414 415
	}
	if (output_name) {
		if (!strcmp(output_name, "-"))
416
			opts->pipe_output = true;
417
		else if (!stat(output_name, &st) && st.st_size) {
418
			if (rec->write_mode == WRITE_FORCE) {
419 420 421 422 423 424
				char oldname[PATH_MAX];
				snprintf(oldname, sizeof(oldname), "%s.old",
					 output_name);
				unlink(oldname);
				rename(output_name, oldname);
			}
425 426
		} else if (rec->write_mode == WRITE_APPEND) {
			rec->write_mode = WRITE_FORCE;
427
		}
428 429
	}

430
	flags = O_CREAT|O_RDWR;
431 432
	if (rec->write_mode == WRITE_APPEND)
		rec->file_new = 0;
I
Ingo Molnar 已提交
433 434 435
	else
		flags |= O_TRUNC;

436
	if (opts->pipe_output)
437 438 439
		output = STDOUT_FILENO;
	else
		output = open(output_name, flags, S_IRUSR | S_IWUSR);
440 441 442 443 444
	if (output < 0) {
		perror("failed to create output file");
		exit(-1);
	}

445 446
	rec->output = output;

447
	session = perf_session__new(output_name, O_WRONLY,
448
				    rec->write_mode == WRITE_FORCE, false, NULL);
449
	if (session == NULL) {
450 451 452 453
		pr_err("Not enough memory for reading perf file header\n");
		return -1;
	}

454 455 456
	rec->session = session;

	if (!rec->no_buildid)
457 458
		perf_header__set_feat(&session->header, HEADER_BUILD_ID);

459
	if (!rec->file_new) {
460
		err = perf_session__read_header(session, output);
461
		if (err < 0)
462
			goto out_delete_session;
463 464
	}

465
	if (have_tracepoints(&evsel_list->entries))
466
		perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
467

468 469 470 471 472 473 474 475 476 477 478 479 480
	perf_header__set_feat(&session->header, HEADER_HOSTNAME);
	perf_header__set_feat(&session->header, HEADER_OSRELEASE);
	perf_header__set_feat(&session->header, HEADER_ARCH);
	perf_header__set_feat(&session->header, HEADER_CPUDESC);
	perf_header__set_feat(&session->header, HEADER_NRCPUS);
	perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
	perf_header__set_feat(&session->header, HEADER_CMDLINE);
	perf_header__set_feat(&session->header, HEADER_VERSION);
	perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
	perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
	perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
	perf_header__set_feat(&session->header, HEADER_CPUID);

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

489
	perf_record__open(rec);
490

491
	/*
492
	 * perf_session__delete(session) will be called at perf_record__exit()
493
	 */
494
	on_exit(perf_record__exit, rec);
495

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

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

514
	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
515

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

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

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

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

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

566
	err = perf_event__synthesize_modules(tool, process_synthesized_event,
567
					     machine);
568 569 570 571 572
	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");

573
	if (perf_guest)
574
		perf_session__process_machines(session, tool,
575
					       perf_event__synthesize_guest_os);
576

577
	if (!opts->system_wide)
578
		perf_event__synthesize_thread_map(tool, evsel_list->threads,
579
						  process_synthesized_event,
580
						  machine);
581
	else
582
		perf_event__synthesize_threads(tool, process_synthesized_event,
583
					       machine);
584

585
	if (rec->realtime_prio) {
586 587
		struct sched_param param;

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

595 596
	perf_evlist__enable(evsel_list);

597 598 599
	/*
	 * Let the child rip
	 */
600
	if (forks)
601
		perf_evlist__start_workload(evsel_list);
602

603
	for (;;) {
604
		int hits = rec->samples;
605

606
		perf_record__mmap_read_all(rec);
607

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

615 616
		if (done)
			perf_evlist__disable(evsel_list);
617 618
	}

619
	if (quiet || signr == SIGUSR1)
620 621
		return 0;

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

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

633
	return 0;
634 635 636 637

out_delete_session:
	perf_session__delete(session);
	return err;
638
}
639 640

static const char * const record_usage[] = {
641 642
	"perf record [<options>] [<command>]",
	"perf record [<options>] -- <command> [<options>]",
643 644 645
	NULL
};

646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
/*
 * 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 = {
		.target_pid	     = -1,
		.target_tid	     = -1,
		.mmap_pages	     = UINT_MAX,
		.user_freq	     = UINT_MAX,
		.user_interval	     = ULLONG_MAX,
		.freq		     = 1000,
		.sample_id_all_avail = true,
	},
	.write_mode = WRITE_FORCE,
	.file_new   = true,
};
669

670 671 672 673 674 675 676
/*
 * 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.
 */
677
const struct option record_options[] = {
678
	OPT_CALLBACK('e', "event", &record.evlist, "event",
679
		     "event selector. use 'perf list' to list available events",
680
		     parse_events_option),
681
	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
L
Li Zefan 已提交
682
		     "event filter", parse_filter),
683
	OPT_INTEGER('p', "pid", &record.opts.target_pid,
684
		    "record events on existing process id"),
685
	OPT_INTEGER('t', "tid", &record.opts.target_tid,
686
		    "record events on existing thread id"),
687
	OPT_INTEGER('r', "realtime", &record.realtime_prio,
688
		    "collect data with this RT SCHED_FIFO priority"),
689
	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
690
		    "collect data without buffering"),
691
	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
692
		    "collect raw sample records from all opened counters"),
693
	OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
694
			    "system-wide collection from all CPUs"),
695
	OPT_BOOLEAN('A', "append", &record.append_file,
I
Ingo Molnar 已提交
696
			    "append to the output file to do incremental profiling"),
697
	OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
698
		    "list of cpus to monitor"),
699
	OPT_BOOLEAN('f', "force", &record.force,
700
			"overwrite existing data file (deprecated)"),
701 702
	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
	OPT_STRING('o', "output", &record.output_name, "file",
I
Ingo Molnar 已提交
703
		    "output file name"),
704
	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
705
		    "child tasks do not inherit counters"),
706 707
	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
708
		     "number of mmap data pages"),
709
	OPT_BOOLEAN(0, "group", &record.opts.group,
710
		    "put the counters into a counter group"),
711
	OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
712
		    "do call-graph (stack chain/backtrace) recording"),
713
	OPT_INCR('v', "verbose", &verbose,
714
		    "be more verbose (show counter open errors, etc)"),
715
	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
716
	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
717
		    "per thread counts"),
718
	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
719
		    "Sample addresses"),
720
	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
721
	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
722
	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
723
		    "don't sample"),
724
	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
725
		    "do not update the buildid cache"),
726
	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
727
		    "do not collect buildids in perf.data"),
728
	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
S
Stephane Eranian 已提交
729 730
		     "monitor event in cgroup name only",
		     parse_cgroups),
731
	OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
732 733 734
	OPT_END()
};

735
int cmd_record(int argc, const char **argv, const char *prefix __used)
736
{
737 738
	int err = -ENOMEM;
	struct perf_evsel *pos;
739 740
	struct perf_evlist *evsel_list;
	struct perf_record *rec = &record;
741

742 743
	perf_header__set_cmdline(argc, argv);

744
	evsel_list = perf_evlist__new(NULL, NULL);
745 746 747
	if (evsel_list == NULL)
		return -ENOMEM;

748 749
	rec->evlist = evsel_list;

750
	argc = parse_options(argc, argv, record_options, record_usage,
751
			    PARSE_OPT_STOP_AT_NON_OPTION);
752
	if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
753
		!rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
754
		usage_with_options(record_usage, record_options);
755

756
	if (rec->force && rec->append_file) {
757 758
		fprintf(stderr, "Can't overwrite and append at the same time."
				" You need to choose between -f and -A");
759
		usage_with_options(record_usage, record_options);
760 761
	} else if (rec->append_file) {
		rec->write_mode = WRITE_APPEND;
762
	} else {
763
		rec->write_mode = WRITE_FORCE;
764 765
	}

766
	if (nr_cgroups && !rec->opts.system_wide) {
S
Stephane Eranian 已提交
767 768 769 770 771
		fprintf(stderr, "cgroup monitoring only available in"
			" system-wide mode\n");
		usage_with_options(record_usage, record_options);
	}

772
	symbol__init();
773

774
	if (symbol_conf.kptr_restrict)
775 776 777 778 779 780 781 782
		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");
783

784
	if (rec->no_buildid_cache || rec->no_buildid)
785
		disable_buildid_cache();
786

787 788
	if (evsel_list->nr_entries == 0 &&
	    perf_evlist__add_default(evsel_list) < 0) {
789 790
		pr_err("Not enough memory for event selector list\n");
		goto out_symbol_exit;
791
	}
792

793 794 795 796 797
	rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
					 rec->opts.target_pid);
	if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
		goto out_free_fd;

798 799
	if (rec->opts.target_pid != -1)
		rec->opts.target_tid = rec->opts.target_pid;
800

801
	if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
802 803
				     rec->opts.target_tid, rec->opts.uid,
				     rec->opts.cpu_list) < 0)
804
		usage_with_options(record_usage, record_options);
805

806
	list_for_each_entry(pos, &evsel_list->entries, node) {
807 808
		if (perf_header__push_event(pos->attr.config, event_name(pos)))
			goto out_free_fd;
809
	}
810

811 812 813 814
	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;
815

816 817 818
	/*
	 * User specified count overrides default frequency.
	 */
819 820 821 822
	if (rec->opts.default_interval)
		rec->opts.freq = 0;
	else if (rec->opts.freq) {
		rec->opts.default_interval = rec->opts.freq;
823 824
	} else {
		fprintf(stderr, "frequency and count are zero, aborting\n");
825
		err = -EINVAL;
826
		goto out_free_fd;
827 828
	}

829
	err = __cmd_record(&record, argc, argv);
830
out_free_fd:
831
	perf_evlist__delete_maps(evsel_list);
832 833
out_symbol_exit:
	symbol__exit();
834
	return err;
835
}