xref: /openbmc/linux/tools/perf/builtin-record.c (revision e5b2c20755d37d781bb6e1e733faec5c39bd087a)
186470930SIngo Molnar /*
286470930SIngo Molnar  * builtin-record.c
386470930SIngo Molnar  *
486470930SIngo Molnar  * Builtin record command: Record the profile of a workload
586470930SIngo Molnar  * (or a CPU, or a PID) into the perf.data output file - for
686470930SIngo Molnar  * later analysis via perf report.
786470930SIngo Molnar  */
886470930SIngo Molnar #include "builtin.h"
986470930SIngo Molnar 
1086470930SIngo Molnar #include "perf.h"
1186470930SIngo Molnar 
126122e4e4SArnaldo Carvalho de Melo #include "util/build-id.h"
1386470930SIngo Molnar #include "util/util.h"
1486470930SIngo Molnar #include "util/parse-options.h"
1586470930SIngo Molnar #include "util/parse-events.h"
1686470930SIngo Molnar 
178f651eaeSArnaldo Carvalho de Melo #include "util/callchain.h"
18f14d5707SArnaldo Carvalho de Melo #include "util/cgroup.h"
197c6a1c65SPeter Zijlstra #include "util/header.h"
2066e274f3SFrederic Weisbecker #include "util/event.h"
21361c99a6SArnaldo Carvalho de Melo #include "util/evlist.h"
2269aad6f1SArnaldo Carvalho de Melo #include "util/evsel.h"
238f28827aSFrederic Weisbecker #include "util/debug.h"
2494c744b6SArnaldo Carvalho de Melo #include "util/session.h"
2545694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
268d06367fSArnaldo Carvalho de Melo #include "util/symbol.h"
27a12b51c4SPaul Mackerras #include "util/cpumap.h"
28fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h"
29f5fc1412SJiri Olsa #include "util/data.h"
307c6a1c65SPeter Zijlstra 
3186470930SIngo Molnar #include <unistd.h>
3286470930SIngo Molnar #include <sched.h>
33a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3486470930SIngo Molnar 
3578da39faSBernhard Rosenkraenzer 
368c6f45a7SArnaldo Carvalho de Melo struct record {
3745694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
38b4006796SArnaldo Carvalho de Melo 	struct record_opts	opts;
39d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
40f5fc1412SJiri Olsa 	struct perf_data_file	file;
41d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
42d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
43d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
44d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
45d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
46d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
47d20deb64SArnaldo Carvalho de Melo 	long			samples;
480f82ebc4SArnaldo Carvalho de Melo };
4986470930SIngo Molnar 
508c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
51f5970550SPeter Zijlstra {
52cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
534f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
548d3eca20SDavid Ahern 		return -1;
558d3eca20SDavid Ahern 	}
56f5970550SPeter Zijlstra 
57cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
588d3eca20SDavid Ahern 	return 0;
59f5970550SPeter Zijlstra }
60f5970550SPeter Zijlstra 
6145694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
62d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
631d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
641d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
65234fbbf5SArnaldo Carvalho de Melo {
668c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
678c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
68234fbbf5SArnaldo Carvalho de Melo }
69234fbbf5SArnaldo Carvalho de Melo 
70e5685730SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, int idx)
7186470930SIngo Molnar {
72e5685730SArnaldo Carvalho de Melo 	struct perf_mmap *md = &rec->evlist->mmap[idx];
73744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
7486470930SIngo Molnar 	unsigned int old = md->prev;
75918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
7686470930SIngo Molnar 	unsigned long size;
7786470930SIngo Molnar 	void *buf;
788d3eca20SDavid Ahern 	int rc = 0;
7986470930SIngo Molnar 
80dc82009aSArnaldo Carvalho de Melo 	if (old == head)
818d3eca20SDavid Ahern 		return 0;
8286470930SIngo Molnar 
83d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
8486470930SIngo Molnar 
8586470930SIngo Molnar 	size = head - old;
8686470930SIngo Molnar 
8786470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
8886470930SIngo Molnar 		buf = &data[old & md->mask];
8986470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
9086470930SIngo Molnar 		old += size;
9186470930SIngo Molnar 
928c6f45a7SArnaldo Carvalho de Melo 		if (record__write(rec, buf, size) < 0) {
938d3eca20SDavid Ahern 			rc = -1;
948d3eca20SDavid Ahern 			goto out;
958d3eca20SDavid Ahern 		}
9686470930SIngo Molnar 	}
9786470930SIngo Molnar 
9886470930SIngo Molnar 	buf = &data[old & md->mask];
9986470930SIngo Molnar 	size = head - old;
10086470930SIngo Molnar 	old += size;
10186470930SIngo Molnar 
1028c6f45a7SArnaldo Carvalho de Melo 	if (record__write(rec, buf, size) < 0) {
1038d3eca20SDavid Ahern 		rc = -1;
1048d3eca20SDavid Ahern 		goto out;
1058d3eca20SDavid Ahern 	}
10686470930SIngo Molnar 
10786470930SIngo Molnar 	md->prev = old;
108e5685730SArnaldo Carvalho de Melo 	perf_evlist__mmap_consume(rec->evlist, idx);
1098d3eca20SDavid Ahern out:
1108d3eca20SDavid Ahern 	return rc;
11186470930SIngo Molnar }
11286470930SIngo Molnar 
11386470930SIngo Molnar static volatile int done = 0;
114f7b7c26eSPeter Zijlstra static volatile int signr = -1;
11533e49ea7SAndi Kleen static volatile int child_finished = 0;
11686470930SIngo Molnar 
11786470930SIngo Molnar static void sig_handler(int sig)
11886470930SIngo Molnar {
11933e49ea7SAndi Kleen 	if (sig == SIGCHLD)
12033e49ea7SAndi Kleen 		child_finished = 1;
12145604710SNamhyung Kim 	else
12245604710SNamhyung Kim 		signr = sig;
12333e49ea7SAndi Kleen 
12486470930SIngo Molnar 	done = 1;
125f7b7c26eSPeter Zijlstra }
126f7b7c26eSPeter Zijlstra 
12745604710SNamhyung Kim static void record__sig_exit(void)
128f7b7c26eSPeter Zijlstra {
12945604710SNamhyung Kim 	if (signr == -1)
130f7b7c26eSPeter Zijlstra 		return;
131f7b7c26eSPeter Zijlstra 
132f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
13345604710SNamhyung Kim 	raise(signr);
13486470930SIngo Molnar }
13586470930SIngo Molnar 
1368c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
137dd7927f4SArnaldo Carvalho de Melo {
13856e52e85SArnaldo Carvalho de Melo 	char msg[512];
1396a4bb04cSJiri Olsa 	struct perf_evsel *pos;
140d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
141d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
142b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
1438d3eca20SDavid Ahern 	int rc = 0;
144dd7927f4SArnaldo Carvalho de Melo 
145f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
146cac21425SJiri Olsa 
1470050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
1483da297a6SIngo Molnar try_again:
1496a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
15056e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
1513da297a6SIngo Molnar 				if (verbose)
152c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
1533da297a6SIngo Molnar 				goto try_again;
1543da297a6SIngo Molnar 			}
155ca6a4258SDavid Ahern 
15656e52e85SArnaldo Carvalho de Melo 			rc = -errno;
15756e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
15856e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
15956e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
1608d3eca20SDavid Ahern 			goto out;
1617c6a1c65SPeter Zijlstra 		}
1627c6a1c65SPeter Zijlstra 	}
1637c6a1c65SPeter Zijlstra 
1641491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
1650a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
16635550da3SMasami Hiramatsu 			strerror_r(errno, msg, sizeof(msg)));
1678d3eca20SDavid Ahern 		rc = -1;
1688d3eca20SDavid Ahern 		goto out;
1690a102479SFrederic Weisbecker 	}
1700a102479SFrederic Weisbecker 
17118e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
1728d3eca20SDavid Ahern 		if (errno == EPERM) {
1738d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
17418e60939SNelson Elhage 			       "Consider increasing "
17518e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
17618e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
17753653d70SAdrian Hunter 			       "(current value: %u)\n", opts->mmap_pages);
1788d3eca20SDavid Ahern 			rc = -errno;
1798d3eca20SDavid Ahern 		} else {
18035550da3SMasami Hiramatsu 			pr_err("failed to mmap with %d (%s)\n", errno,
18135550da3SMasami Hiramatsu 				strerror_r(errno, msg, sizeof(msg)));
1828d3eca20SDavid Ahern 			rc = -errno;
1838d3eca20SDavid Ahern 		}
1848d3eca20SDavid Ahern 		goto out;
18518e60939SNelson Elhage 	}
1860a27d7f9SArnaldo Carvalho de Melo 
187a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
1887b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
1898d3eca20SDavid Ahern out:
1908d3eca20SDavid Ahern 	return rc;
191a91e5431SArnaldo Carvalho de Melo }
192a91e5431SArnaldo Carvalho de Melo 
1938c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
1946122e4e4SArnaldo Carvalho de Melo {
195f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
196f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
1977ab75cffSDavid Ahern 	u64 start = session->header.data_offset;
1986122e4e4SArnaldo Carvalho de Melo 
199f5fc1412SJiri Olsa 	u64 size = lseek(file->fd, 0, SEEK_CUR);
2009f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2019f591fd7SArnaldo Carvalho de Melo 		return 0;
2029f591fd7SArnaldo Carvalho de Melo 
2037ab75cffSDavid Ahern 	return __perf_session__process_events(session, start,
2047ab75cffSDavid Ahern 					      size - start,
2056122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
2066122e4e4SArnaldo Carvalho de Melo }
2076122e4e4SArnaldo Carvalho de Melo 
2088115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
209a1645ce1SZhang, Yanmin {
210a1645ce1SZhang, Yanmin 	int err;
21145694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
212a1645ce1SZhang, Yanmin 	/*
213a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
214a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
215a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
216a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
217a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
218a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
219a1645ce1SZhang, Yanmin 	 */
22045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
221743eb868SArnaldo Carvalho de Melo 					     machine);
222a1645ce1SZhang, Yanmin 	if (err < 0)
223a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
22423346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
225a1645ce1SZhang, Yanmin 
226a1645ce1SZhang, Yanmin 	/*
227a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
228a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
229a1645ce1SZhang, Yanmin 	 */
23045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
2310ae617beSAdrian Hunter 						 machine);
232a1645ce1SZhang, Yanmin 	if (err < 0)
233a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
23423346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
235a1645ce1SZhang, Yanmin }
236a1645ce1SZhang, Yanmin 
23798402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
23898402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
23998402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
24098402807SFrederic Weisbecker };
24198402807SFrederic Weisbecker 
2428c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
24398402807SFrederic Weisbecker {
244dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
2450e2e63ddSPeter Zijlstra 	int i;
2468d3eca20SDavid Ahern 	int rc = 0;
24798402807SFrederic Weisbecker 
248d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
2498d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
250e5685730SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, i) != 0) {
2518d3eca20SDavid Ahern 				rc = -1;
2528d3eca20SDavid Ahern 				goto out;
2538d3eca20SDavid Ahern 			}
2548d3eca20SDavid Ahern 		}
25598402807SFrederic Weisbecker 	}
25698402807SFrederic Weisbecker 
257dcabb507SJiri Olsa 	/*
258dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
259dcabb507SJiri Olsa 	 * at least one event.
260dcabb507SJiri Olsa 	 */
261dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
2628c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
2638d3eca20SDavid Ahern 
2648d3eca20SDavid Ahern out:
2658d3eca20SDavid Ahern 	return rc;
26698402807SFrederic Weisbecker }
26798402807SFrederic Weisbecker 
2688c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
26957706abcSDavid Ahern {
27057706abcSDavid Ahern 	struct perf_session *session = rec->session;
27157706abcSDavid Ahern 	int feat;
27257706abcSDavid Ahern 
27357706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
27457706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
27557706abcSDavid Ahern 
27657706abcSDavid Ahern 	if (rec->no_buildid)
27757706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
27857706abcSDavid Ahern 
2793e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
28057706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
28157706abcSDavid Ahern 
28257706abcSDavid Ahern 	if (!rec->opts.branch_stack)
28357706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
28457706abcSDavid Ahern }
28557706abcSDavid Ahern 
286f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
287f33cbe72SArnaldo Carvalho de Melo 
288f33cbe72SArnaldo Carvalho de Melo /*
289f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
290f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
291f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
292f33cbe72SArnaldo Carvalho de Melo  */
29345604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
29445604710SNamhyung Kim 					siginfo_t *info,
295f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
296f33cbe72SArnaldo Carvalho de Melo {
297f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
298f33cbe72SArnaldo Carvalho de Melo 	done = 1;
299f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
300f33cbe72SArnaldo Carvalho de Melo }
301f33cbe72SArnaldo Carvalho de Melo 
3028c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
30386470930SIngo Molnar {
30457706abcSDavid Ahern 	int err;
30545604710SNamhyung Kim 	int status = 0;
3068b412664SPeter Zijlstra 	unsigned long waking = 0;
30746be604bSZhang, Yanmin 	const bool forks = argc > 0;
30823346f21SArnaldo Carvalho de Melo 	struct machine *machine;
30945694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
310b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
311f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
312d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3136dcf45efSArnaldo Carvalho de Melo 	bool disabled = false, draining = false;
31486470930SIngo Molnar 
315d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
31633e49ea7SAndi Kleen 
31745604710SNamhyung Kim 	atexit(record__sig_exit);
318f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
319f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
320804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
321f5970550SPeter Zijlstra 
322f5fc1412SJiri Olsa 	session = perf_session__new(file, false, NULL);
32394c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
324ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
325a9a70bbcSArnaldo Carvalho de Melo 		return -1;
326a9a70bbcSArnaldo Carvalho de Melo 	}
327a9a70bbcSArnaldo Carvalho de Melo 
328d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
329d20deb64SArnaldo Carvalho de Melo 
3308c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
331330aa675SStephane Eranian 
332d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
3333e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
334f5fc1412SJiri Olsa 						    argv, file->is_pipe,
335735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
33635b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
33735b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
33845604710SNamhyung Kim 			status = err;
33935b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
340856e9660SPeter Zijlstra 		}
341856e9660SPeter Zijlstra 	}
342856e9660SPeter Zijlstra 
3438c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
3448d3eca20SDavid Ahern 		err = -1;
34545604710SNamhyung Kim 		goto out_child;
3468d3eca20SDavid Ahern 	}
34786470930SIngo Molnar 
3483e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
349a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
350a8bb559bSNamhyung Kim 
351f5fc1412SJiri Olsa 	if (file->is_pipe) {
352f5fc1412SJiri Olsa 		err = perf_header__write_pipe(file->fd);
353529870e3STom Zanussi 		if (err < 0)
35445604710SNamhyung Kim 			goto out_child;
355563aecb2SJiri Olsa 	} else {
3563e2be2daSArnaldo Carvalho de Melo 		err = perf_session__write_header(session, rec->evlist,
357f5fc1412SJiri Olsa 						 file->fd, false);
358d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
35945604710SNamhyung Kim 			goto out_child;
360d5eed904SArnaldo Carvalho de Melo 	}
3617c6a1c65SPeter Zijlstra 
362d3665498SDavid Ahern 	if (!rec->no_buildid
363e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
364d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
365e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
3668d3eca20SDavid Ahern 		err = -1;
36745604710SNamhyung Kim 		goto out_child;
368e20960c0SRobert Richter 	}
369e20960c0SRobert Richter 
37034ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
371743eb868SArnaldo Carvalho de Melo 
372f5fc1412SJiri Olsa 	if (file->is_pipe) {
37345694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
374a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
3752c46dbb5STom Zanussi 		if (err < 0) {
3762c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
37745604710SNamhyung Kim 			goto out_child;
3782c46dbb5STom Zanussi 		}
379cd19a035STom Zanussi 
3803e2be2daSArnaldo Carvalho de Melo 		if (have_tracepoints(&rec->evlist->entries)) {
38163e0c771STom Zanussi 			/*
38263e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
38363e0c771STom Zanussi 			 * there were no tracepoints so its not really
38463e0c771STom Zanussi 			 * an error, just that we don't need to
38563e0c771STom Zanussi 			 * synthesize anything.  We really have to
38663e0c771STom Zanussi 			 * return this more properly and also
38763e0c771STom Zanussi 			 * propagate errors that now are calling die()
38863e0c771STom Zanussi 			 */
3893e2be2daSArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist,
390743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
39163e0c771STom Zanussi 			if (err <= 0) {
39263e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
39345604710SNamhyung Kim 				goto out_child;
39463e0c771STom Zanussi 			}
395f34b9001SDavid Ahern 			rec->bytes_written += err;
3962c46dbb5STom Zanussi 		}
39763e0c771STom Zanussi 	}
3982c46dbb5STom Zanussi 
39945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
4000ae617beSAdrian Hunter 						 machine);
401c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
402c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
403c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
404c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
40556b03f3cSArnaldo Carvalho de Melo 
40645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
407743eb868SArnaldo Carvalho de Melo 					     machine);
408c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
409c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
410c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
411c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
412c1a3a4b9SArnaldo Carvalho de Melo 
4137e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
414876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
4157e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
4167e383de4SArnaldo Carvalho de Melo 	}
417b7cece76SArnaldo Carvalho de Melo 
4183e2be2daSArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
41958d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
4208d3eca20SDavid Ahern 	if (err != 0)
42145604710SNamhyung Kim 		goto out_child;
4228d3eca20SDavid Ahern 
423d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
42486470930SIngo Molnar 		struct sched_param param;
42586470930SIngo Molnar 
426d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
42786470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
4286beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
4298d3eca20SDavid Ahern 			err = -1;
43045604710SNamhyung Kim 			goto out_child;
43186470930SIngo Molnar 		}
43286470930SIngo Molnar 	}
43386470930SIngo Molnar 
434774cb499SJiri Olsa 	/*
435774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
436774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
437774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
438774cb499SJiri Olsa 	 */
4396619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
4403e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
441764e16a3SDavid Ahern 
442856e9660SPeter Zijlstra 	/*
443856e9660SPeter Zijlstra 	 * Let the child rip
444856e9660SPeter Zijlstra 	 */
445735f7e0bSArnaldo Carvalho de Melo 	if (forks)
4463e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
447856e9660SPeter Zijlstra 
4486619a53eSAndi Kleen 	if (opts->initial_delay) {
4496619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
4506619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
4516619a53eSAndi Kleen 	}
4526619a53eSAndi Kleen 
453649c48a9SPeter Zijlstra 	for (;;) {
454d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
45586470930SIngo Molnar 
4568c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
4578d3eca20SDavid Ahern 			err = -1;
45845604710SNamhyung Kim 			goto out_child;
4598d3eca20SDavid Ahern 		}
46086470930SIngo Molnar 
461d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
4626dcf45efSArnaldo Carvalho de Melo 			if (done || draining)
463649c48a9SPeter Zijlstra 				break;
464f66a889dSArnaldo Carvalho de Melo 			err = perf_evlist__poll(rec->evlist, -1);
465a515114fSJiri Olsa 			/*
466a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
467a515114fSJiri Olsa 			 * number of returned events and interrupt error.
468a515114fSJiri Olsa 			 */
469a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
47045604710SNamhyung Kim 				err = 0;
4718b412664SPeter Zijlstra 			waking++;
4726dcf45efSArnaldo Carvalho de Melo 
4736dcf45efSArnaldo Carvalho de Melo 			if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
4746dcf45efSArnaldo Carvalho de Melo 				draining = true;
4758b412664SPeter Zijlstra 		}
4768b412664SPeter Zijlstra 
477774cb499SJiri Olsa 		/*
478774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
479774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
480774cb499SJiri Olsa 		 * disable events in this case.
481774cb499SJiri Olsa 		 */
482602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
4833e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
4842711926aSJiri Olsa 			disabled = true;
4852711926aSJiri Olsa 		}
4868b412664SPeter Zijlstra 	}
4878b412664SPeter Zijlstra 
488f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
48935550da3SMasami Hiramatsu 		char msg[STRERR_BUFSIZE];
490f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
491f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
492f33cbe72SArnaldo Carvalho de Melo 		err = -1;
49345604710SNamhyung Kim 		goto out_child;
494f33cbe72SArnaldo Carvalho de Melo 	}
495f33cbe72SArnaldo Carvalho de Melo 
49645604710SNamhyung Kim 	if (!quiet) {
4978b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
49886470930SIngo Molnar 
49986470930SIngo Molnar 		/*
50086470930SIngo Molnar 		 * Approximate RIP event size: 24 bytes.
50186470930SIngo Molnar 		 */
50286470930SIngo Molnar 		fprintf(stderr,
5039486aa38SArnaldo Carvalho de Melo 			"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
504d20deb64SArnaldo Carvalho de Melo 			(double)rec->bytes_written / 1024.0 / 1024.0,
5056a4d98d7SJiri Olsa 			file->path,
506d20deb64SArnaldo Carvalho de Melo 			rec->bytes_written / 24);
50745604710SNamhyung Kim 	}
50886470930SIngo Molnar 
50945604710SNamhyung Kim out_child:
51045604710SNamhyung Kim 	if (forks) {
51145604710SNamhyung Kim 		int exit_status;
51245604710SNamhyung Kim 
51345604710SNamhyung Kim 		if (!child_finished)
51445604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
51545604710SNamhyung Kim 
51645604710SNamhyung Kim 		wait(&exit_status);
51745604710SNamhyung Kim 
51845604710SNamhyung Kim 		if (err < 0)
51945604710SNamhyung Kim 			status = err;
52045604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
52145604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
52245604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
52345604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
52445604710SNamhyung Kim 	} else
52545604710SNamhyung Kim 		status = err;
52645604710SNamhyung Kim 
52745604710SNamhyung Kim 	if (!err && !file->is_pipe) {
52845604710SNamhyung Kim 		rec->session->header.data_size += rec->bytes_written;
52945604710SNamhyung Kim 
53045604710SNamhyung Kim 		if (!rec->no_buildid)
53145604710SNamhyung Kim 			process_buildids(rec);
53245604710SNamhyung Kim 		perf_session__write_header(rec->session, rec->evlist,
53345604710SNamhyung Kim 					   file->fd, true);
53445604710SNamhyung Kim 	}
53539d17dacSArnaldo Carvalho de Melo 
53639d17dacSArnaldo Carvalho de Melo out_delete_session:
53739d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
53845604710SNamhyung Kim 	return status;
53986470930SIngo Molnar }
54086470930SIngo Molnar 
541bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
542bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
543bdfebd84SRoberto Agostino Vitillo 
544bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
545bdfebd84SRoberto Agostino Vitillo 
546bdfebd84SRoberto Agostino Vitillo struct branch_mode {
547bdfebd84SRoberto Agostino Vitillo 	const char *name;
548bdfebd84SRoberto Agostino Vitillo 	int mode;
549bdfebd84SRoberto Agostino Vitillo };
550bdfebd84SRoberto Agostino Vitillo 
551bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
552bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
553bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
554bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
555bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
556bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
557bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
558bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
5590126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
5600126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
5610126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
5620fffa5dfSAnshuman Khandual 	BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
563bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
564bdfebd84SRoberto Agostino Vitillo };
565bdfebd84SRoberto Agostino Vitillo 
566bdfebd84SRoberto Agostino Vitillo static int
567a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
568bdfebd84SRoberto Agostino Vitillo {
569bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
570bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
571bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
572bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
573bdfebd84SRoberto Agostino Vitillo 
574bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
575bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
576a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
577bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
578bdfebd84SRoberto Agostino Vitillo 
579a5aabdacSStephane Eranian 	if (unset)
580a5aabdacSStephane Eranian 		return 0;
581bdfebd84SRoberto Agostino Vitillo 
582a5aabdacSStephane Eranian 	/*
583a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
584a5aabdacSStephane Eranian 	 */
585a5aabdacSStephane Eranian 	if (*mode)
586a5aabdacSStephane Eranian 		return -1;
587a5aabdacSStephane Eranian 
588a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
589a5aabdacSStephane Eranian 	if (str) {
590bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
591bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
592bdfebd84SRoberto Agostino Vitillo 		if (!s)
593bdfebd84SRoberto Agostino Vitillo 			return -1;
594bdfebd84SRoberto Agostino Vitillo 
595bdfebd84SRoberto Agostino Vitillo 		for (;;) {
596bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
597bdfebd84SRoberto Agostino Vitillo 			if (p)
598bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
599bdfebd84SRoberto Agostino Vitillo 
600bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
601bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
602bdfebd84SRoberto Agostino Vitillo 					break;
603bdfebd84SRoberto Agostino Vitillo 			}
604a5aabdacSStephane Eranian 			if (!br->name) {
605a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
606a5aabdacSStephane Eranian 					    " check man page\n", s);
607bdfebd84SRoberto Agostino Vitillo 				goto error;
608a5aabdacSStephane Eranian 			}
609bdfebd84SRoberto Agostino Vitillo 
610bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
611bdfebd84SRoberto Agostino Vitillo 
612bdfebd84SRoberto Agostino Vitillo 			if (!p)
613bdfebd84SRoberto Agostino Vitillo 				break;
614bdfebd84SRoberto Agostino Vitillo 
615bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
616bdfebd84SRoberto Agostino Vitillo 		}
617a5aabdacSStephane Eranian 	}
618bdfebd84SRoberto Agostino Vitillo 	ret = 0;
619bdfebd84SRoberto Agostino Vitillo 
620a5aabdacSStephane Eranian 	/* default to any branch */
621bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
622a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
623bdfebd84SRoberto Agostino Vitillo 	}
624bdfebd84SRoberto Agostino Vitillo error:
625bdfebd84SRoberto Agostino Vitillo 	free(os);
626bdfebd84SRoberto Agostino Vitillo 	return ret;
627bdfebd84SRoberto Agostino Vitillo }
628bdfebd84SRoberto Agostino Vitillo 
62972a128aaSNamhyung Kim static void callchain_debug(void)
63009b0fd45SJiri Olsa {
631a601fdffSJiri Olsa 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
632a601fdffSJiri Olsa 
63372a128aaSNamhyung Kim 	pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
63426d33022SJiri Olsa 
63572a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_DWARF)
63609b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
63772a128aaSNamhyung Kim 			 callchain_param.dump_size);
63809b0fd45SJiri Olsa }
63909b0fd45SJiri Olsa 
64072a128aaSNamhyung Kim int record_parse_callchain_opt(const struct option *opt __maybe_unused,
64109b0fd45SJiri Olsa 			       const char *arg,
64209b0fd45SJiri Olsa 			       int unset)
64309b0fd45SJiri Olsa {
64409b0fd45SJiri Olsa 	int ret;
64509b0fd45SJiri Olsa 
64672a128aaSNamhyung Kim 	callchain_param.enabled = !unset;
647eb853e80SJiri Olsa 
64809b0fd45SJiri Olsa 	/* --no-call-graph */
64909b0fd45SJiri Olsa 	if (unset) {
65072a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_NONE;
65109b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
65209b0fd45SJiri Olsa 		return 0;
65309b0fd45SJiri Olsa 	}
65409b0fd45SJiri Olsa 
655f7f084f4SNamhyung Kim 	ret = parse_callchain_record_opt(arg);
65609b0fd45SJiri Olsa 	if (!ret)
65772a128aaSNamhyung Kim 		callchain_debug();
65809b0fd45SJiri Olsa 
65926d33022SJiri Olsa 	return ret;
66026d33022SJiri Olsa }
66126d33022SJiri Olsa 
66272a128aaSNamhyung Kim int record_callchain_opt(const struct option *opt __maybe_unused,
66309b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
66409b0fd45SJiri Olsa 			 int unset __maybe_unused)
66509b0fd45SJiri Olsa {
66672a128aaSNamhyung Kim 	callchain_param.enabled = true;
66709b0fd45SJiri Olsa 
66872a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_NONE)
66972a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_FP;
670eb853e80SJiri Olsa 
67172a128aaSNamhyung Kim 	callchain_debug();
67209b0fd45SJiri Olsa 	return 0;
67309b0fd45SJiri Olsa }
67409b0fd45SJiri Olsa 
675eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
676eb853e80SJiri Olsa {
677eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
6785a2e5e85SNamhyung Kim 		var = "call-graph.record-mode"; /* fall-through */
679eb853e80SJiri Olsa 
680eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
681eb853e80SJiri Olsa }
682eb853e80SJiri Olsa 
683*e5b2c207SNamhyung Kim static const char * const __record_usage[] = {
68486470930SIngo Molnar 	"perf record [<options>] [<command>]",
68586470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
68686470930SIngo Molnar 	NULL
68786470930SIngo Molnar };
688*e5b2c207SNamhyung Kim const char * const *record_usage = __record_usage;
68986470930SIngo Molnar 
690d20deb64SArnaldo Carvalho de Melo /*
6918c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
6928c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
693d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
694d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
695d20deb64SArnaldo Carvalho de Melo  *
696d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
697d20deb64SArnaldo Carvalho de Melo  *
698d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
699d20deb64SArnaldo Carvalho de Melo  */
7008c6f45a7SArnaldo Carvalho de Melo static struct record record = {
701d20deb64SArnaldo Carvalho de Melo 	.opts = {
7028affc2b8SAndi Kleen 		.sample_time	     = true,
703d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
704d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
705d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
706447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
707d1cb9fceSNamhyung Kim 		.target		     = {
708d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
7093aa5939dSAdrian Hunter 			.default_per_cpu = true,
710d1cb9fceSNamhyung Kim 		},
711d20deb64SArnaldo Carvalho de Melo 	},
712d20deb64SArnaldo Carvalho de Melo };
7137865e817SFrederic Weisbecker 
71409b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
71561eaa3beSArnaldo Carvalho de Melo 
7169ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
71709b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
71861eaa3beSArnaldo Carvalho de Melo #else
71909b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp";
72061eaa3beSArnaldo Carvalho de Melo #endif
72161eaa3beSArnaldo Carvalho de Melo 
722d20deb64SArnaldo Carvalho de Melo /*
723d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
724d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
725b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
726d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
727d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
728d20deb64SArnaldo Carvalho de Melo  */
729*e5b2c207SNamhyung Kim struct option __record_options[] = {
730d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
73186470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
732f120f9d5SJiri Olsa 		     parse_events_option),
733d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
734c171b552SLi Zefan 		     "event filter", parse_filter),
735bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
736d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
737bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
738d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
739d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
74086470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
741509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
742acac03faSKirill Smelkov 		    "collect data without buffering"),
743d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
744daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
745bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
74686470930SIngo Molnar 			    "system-wide collection from all CPUs"),
747bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
748c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
749d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
750f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
75186470930SIngo Molnar 		    "output file name"),
75269e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
75369e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
7542e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
755d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
756994a1f78SJiri Olsa 	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
757994a1f78SJiri Olsa 		     "number of mmap data pages",
758994a1f78SJiri Olsa 		     perf_evlist__parse_mmap_pages),
759d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
76043bece79SLin Ming 		    "put the counters into a counter group"),
76109b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
76209b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
76309b0fd45SJiri Olsa 			   &record_callchain_opt),
76409b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
76575d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
76609b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
767c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
7683da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
769b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
770d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
771649c48a9SPeter Zijlstra 		    "per thread counts"),
772d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
7734bba828dSAnton Blanchard 		    "Sample addresses"),
774d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
7753e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
776d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
777649c48a9SPeter Zijlstra 		    "don't sample"),
778d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
779a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
780d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
781baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
782d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
783023695d9SStephane Eranian 		     "monitor event in cgroup name only",
784023695d9SStephane Eranian 		     parse_cgroups),
785a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
7866619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
787bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
788bea03405SNamhyung Kim 		   "user to profile"),
789a5aabdacSStephane Eranian 
790a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
791a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
792a5aabdacSStephane Eranian 		     parse_branch_stack),
793a5aabdacSStephane Eranian 
794a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
795a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
796bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
79705484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
79805484298SAndi Kleen 		    "sample by weight (on special events only)"),
799475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
800475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
8013aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
8023aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
80386470930SIngo Molnar 	OPT_END()
80486470930SIngo Molnar };
80586470930SIngo Molnar 
806*e5b2c207SNamhyung Kim struct option *record_options = __record_options;
807*e5b2c207SNamhyung Kim 
8081d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
80986470930SIngo Molnar {
81069aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
8118c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
81216ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
81386470930SIngo Molnar 
8143e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
8153e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
816361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
817361c99a6SArnaldo Carvalho de Melo 
818eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
819eb853e80SJiri Olsa 
820bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
821a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
822602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
823bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
82486470930SIngo Molnar 
825bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
8263780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
827023695d9SStephane Eranian 			  " system-wide mode\n");
828023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
829023695d9SStephane Eranian 	}
830023695d9SStephane Eranian 
8310a7e6d1bSNamhyung Kim 	symbol__init(NULL);
832baa2f6ceSArnaldo Carvalho de Melo 
833ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
834646aaea6SArnaldo Carvalho de Melo 		pr_warning(
835646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
836ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
837646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
838646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
839646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
840646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
841646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
842ec80fde7SArnaldo Carvalho de Melo 
843d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
844a1ac1d3cSStephane Eranian 		disable_buildid_cache();
845655000e7SArnaldo Carvalho de Melo 
8463e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
8473e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
84869aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
84969aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
850bbd36e5eSPeter Zijlstra 	}
85186470930SIngo Molnar 
85269e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
85369e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
85469e7e5b0SAdrian Hunter 
855602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
85616ad2ffbSNamhyung Kim 	if (err) {
857602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
85816ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
85916ad2ffbSNamhyung Kim 	}
8604bd0f2d2SNamhyung Kim 
861602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
86216ad2ffbSNamhyung Kim 	if (err) {
86316ad2ffbSNamhyung Kim 		int saved_errno = errno;
86416ad2ffbSNamhyung Kim 
865602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
8663780f488SNamhyung Kim 		ui__error("%s", errbuf);
86716ad2ffbSNamhyung Kim 
86816ad2ffbSNamhyung Kim 		err = -saved_errno;
8698fa60e1fSNamhyung Kim 		goto out_symbol_exit;
87016ad2ffbSNamhyung Kim 	}
8710d37aa34SArnaldo Carvalho de Melo 
87216ad2ffbSNamhyung Kim 	err = -ENOMEM;
8733e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
874dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
87569aad6f1SArnaldo Carvalho de Melo 
876b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
87739d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
87803ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
8797e4ff9e3SMike Galbraith 	}
8807e4ff9e3SMike Galbraith 
881d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
882d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
88345604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
884d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
88539d17dacSArnaldo Carvalho de Melo 	return err;
88686470930SIngo Molnar }
887