builtin-record.c 25.0 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 209 210
fallback_missing_features:
		if (opts->exclude_guest_missing)
			attr->exclude_guest = attr->exclude_host = 0;
211
retry_sample_id:
212
		attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
213
try_again:
214
		if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
215
				     opts->group, group_fd) < 0) {
216 217
			int err = errno;

218
			if (err == EPERM || err == EACCES) {
219
				ui__error_paranoid();
220
				exit(EXIT_FAILURE);
221
			} else if (err ==  ENODEV && opts->cpu_list) {
222 223
				die("No such device - did you specify"
					" an out-of-range profile CPU?\n");
224 225 226 227 228 229 230
			} 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;
231
				} else if (!opts->sample_id_all_missing) {
232 233 234
					/*
					 * Old kernel, no attr->sample_id_type_all field
					 */
235
					opts->sample_id_all_missing = true;
236 237 238 239 240
					if (!opts->sample_time && !opts->raw_samples && !time_needed)
						attr->sample_type &= ~PERF_SAMPLE_TIME;

					goto retry_sample_id;
				}
241
			}
242

243 244 245 246 247 248 249 250 251
			/*
			 * 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)
252 253
					ui__warning("The cycles event is not supported, "
						    "trying to fall back to cpu-clock-ticks\n");
254 255 256 257
				attr->type = PERF_TYPE_SOFTWARE;
				attr->config = PERF_COUNT_SW_CPU_CLOCK;
				goto try_again;
			}
258 259 260 261 262 263 264

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

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

#if defined(__i386__) || defined(__x86_64__)
270 271 272 273 274
			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");
275 276
#endif

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

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

287 288 289 290 291 292 293
	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);
294 295 296
		else if (!is_power_of_2(opts->mmap_pages))
			die("--mmap_pages/-m value must be a power of two.");

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

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

	perf_session__update_sample_type(session);
310 311
}

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

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

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

325
static void perf_record__exit(int status __used, void *arg)
326
{
327 328 329 330 331 332 333 334 335 336 337
	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);
338
		symbol__exit();
339
	}
340 341
}

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

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

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

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

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

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

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

396
static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
397
{
I
Ingo Molnar 已提交
398 399
	struct stat st;
	int flags;
400
	int err, output, feat;
401
	unsigned long waking = 0;
402
	const bool forks = argc > 0;
403
	struct machine *machine;
404
	struct perf_tool *tool = &rec->tool;
405 406 407 408
	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;
409

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

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

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

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

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

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

456 457
	rec->output = output;

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

465 466
	rec->session = session;

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

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

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

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

493
	perf_record__open(rec);
494

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

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

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

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

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

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

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

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

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

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

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

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

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

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

599 600
	perf_evlist__enable(evsel_list);

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

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

610
		perf_record__mmap_read_all(rec);
611

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

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

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

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

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

637
	return 0;
638 639 640 641

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

644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
#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
666
parse_branch_stack(const struct option *opt, const char *str, int unset)
667 668 669 670 671 672 673 674
{
#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;
675
	char *s, *os = NULL, *p;
676 677
	int ret = -1;

678 679
	if (unset)
		return 0;
680

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

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

709
			*mode |= br->mode;
710

711 712
			if (!p)
				break;
713

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

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

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

734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
/*
 * 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,
};
754

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

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

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

865
	symbol__init();
866

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

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

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

886 887 888 889 890
	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;

891
	if (rec->opts.target_pid)
892
		rec->opts.target_tid = rec->opts.target_pid;
893

894
	if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
895 896
				     rec->opts.target_tid, rec->opts.uid,
				     rec->opts.cpu_list) < 0)
897
		usage_with_options(record_usage, record_options);
898

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

904 905 906 907
	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;
908

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

922
	err = __cmd_record(&record, argc, argv);
923
out_free_fd:
924
	perf_evlist__delete_maps(evsel_list);
925 926
out_symbol_exit:
	symbol__exit();
927
	return err;
928
}