xref: /openbmc/linux/tools/perf/builtin-record.c (revision 8f651eae186f4dfb1740988623c83ba03dcf3a76)
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 
17*8f651eaeSArnaldo Carvalho de Melo #include "util/callchain.h"
187c6a1c65SPeter Zijlstra #include "util/header.h"
1966e274f3SFrederic Weisbecker #include "util/event.h"
20361c99a6SArnaldo Carvalho de Melo #include "util/evlist.h"
2169aad6f1SArnaldo Carvalho de Melo #include "util/evsel.h"
228f28827aSFrederic Weisbecker #include "util/debug.h"
2394c744b6SArnaldo Carvalho de Melo #include "util/session.h"
2445694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
258d06367fSArnaldo Carvalho de Melo #include "util/symbol.h"
26a12b51c4SPaul Mackerras #include "util/cpumap.h"
27fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h"
28f5fc1412SJiri Olsa #include "util/data.h"
297c6a1c65SPeter Zijlstra 
3086470930SIngo Molnar #include <unistd.h>
3186470930SIngo Molnar #include <sched.h>
32a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3386470930SIngo Molnar 
3478da39faSBernhard Rosenkraenzer 
358c6f45a7SArnaldo Carvalho de Melo struct record {
3645694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
37b4006796SArnaldo Carvalho de Melo 	struct record_opts	opts;
38d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
39f5fc1412SJiri Olsa 	struct perf_data_file	file;
40d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
41d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
42d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
43d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
44d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
45d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
46d20deb64SArnaldo Carvalho de Melo 	long			samples;
470f82ebc4SArnaldo Carvalho de Melo };
4886470930SIngo Molnar 
498c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
50f5970550SPeter Zijlstra {
51cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
524f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
538d3eca20SDavid Ahern 		return -1;
548d3eca20SDavid Ahern 	}
55f5970550SPeter Zijlstra 
56cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
578d3eca20SDavid Ahern 	return 0;
58f5970550SPeter Zijlstra }
59f5970550SPeter Zijlstra 
6045694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
61d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
621d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
631d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
64234fbbf5SArnaldo Carvalho de Melo {
658c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
668c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
67234fbbf5SArnaldo Carvalho de Melo }
68234fbbf5SArnaldo Carvalho de Melo 
69e5685730SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, int idx)
7086470930SIngo Molnar {
71e5685730SArnaldo Carvalho de Melo 	struct perf_mmap *md = &rec->evlist->mmap[idx];
72744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
7386470930SIngo Molnar 	unsigned int old = md->prev;
74918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
7586470930SIngo Molnar 	unsigned long size;
7686470930SIngo Molnar 	void *buf;
778d3eca20SDavid Ahern 	int rc = 0;
7886470930SIngo Molnar 
79dc82009aSArnaldo Carvalho de Melo 	if (old == head)
808d3eca20SDavid Ahern 		return 0;
8186470930SIngo Molnar 
82d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
8386470930SIngo Molnar 
8486470930SIngo Molnar 	size = head - old;
8586470930SIngo Molnar 
8686470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
8786470930SIngo Molnar 		buf = &data[old & md->mask];
8886470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
8986470930SIngo Molnar 		old += size;
9086470930SIngo Molnar 
918c6f45a7SArnaldo Carvalho de Melo 		if (record__write(rec, buf, size) < 0) {
928d3eca20SDavid Ahern 			rc = -1;
938d3eca20SDavid Ahern 			goto out;
948d3eca20SDavid Ahern 		}
9586470930SIngo Molnar 	}
9686470930SIngo Molnar 
9786470930SIngo Molnar 	buf = &data[old & md->mask];
9886470930SIngo Molnar 	size = head - old;
9986470930SIngo Molnar 	old += size;
10086470930SIngo Molnar 
1018c6f45a7SArnaldo Carvalho de Melo 	if (record__write(rec, buf, size) < 0) {
1028d3eca20SDavid Ahern 		rc = -1;
1038d3eca20SDavid Ahern 		goto out;
1048d3eca20SDavid Ahern 	}
10586470930SIngo Molnar 
10686470930SIngo Molnar 	md->prev = old;
107e5685730SArnaldo Carvalho de Melo 	perf_evlist__mmap_consume(rec->evlist, idx);
1088d3eca20SDavid Ahern out:
1098d3eca20SDavid Ahern 	return rc;
11086470930SIngo Molnar }
11186470930SIngo Molnar 
11286470930SIngo Molnar static volatile int done = 0;
113f7b7c26eSPeter Zijlstra static volatile int signr = -1;
11433e49ea7SAndi Kleen static volatile int child_finished = 0;
11586470930SIngo Molnar 
11686470930SIngo Molnar static void sig_handler(int sig)
11786470930SIngo Molnar {
11833e49ea7SAndi Kleen 	if (sig == SIGCHLD)
11933e49ea7SAndi Kleen 		child_finished = 1;
12045604710SNamhyung Kim 	else
12145604710SNamhyung Kim 		signr = sig;
12233e49ea7SAndi Kleen 
12386470930SIngo Molnar 	done = 1;
124f7b7c26eSPeter Zijlstra }
125f7b7c26eSPeter Zijlstra 
12645604710SNamhyung Kim static void record__sig_exit(void)
127f7b7c26eSPeter Zijlstra {
12845604710SNamhyung Kim 	if (signr == -1)
129f7b7c26eSPeter Zijlstra 		return;
130f7b7c26eSPeter Zijlstra 
131f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
13245604710SNamhyung Kim 	raise(signr);
13386470930SIngo Molnar }
13486470930SIngo Molnar 
1358c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
136dd7927f4SArnaldo Carvalho de Melo {
13756e52e85SArnaldo Carvalho de Melo 	char msg[512];
1386a4bb04cSJiri Olsa 	struct perf_evsel *pos;
139d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
140d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
141b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
1428d3eca20SDavid Ahern 	int rc = 0;
143dd7927f4SArnaldo Carvalho de Melo 
144f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
145cac21425SJiri Olsa 
1460050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
1473da297a6SIngo Molnar try_again:
1486a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
14956e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
1503da297a6SIngo Molnar 				if (verbose)
151c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
1523da297a6SIngo Molnar 				goto try_again;
1533da297a6SIngo Molnar 			}
154ca6a4258SDavid Ahern 
15556e52e85SArnaldo Carvalho de Melo 			rc = -errno;
15656e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
15756e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
15856e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
1598d3eca20SDavid Ahern 			goto out;
1607c6a1c65SPeter Zijlstra 		}
1617c6a1c65SPeter Zijlstra 	}
1627c6a1c65SPeter Zijlstra 
1631491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
1640a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
16535550da3SMasami Hiramatsu 			strerror_r(errno, msg, sizeof(msg)));
1668d3eca20SDavid Ahern 		rc = -1;
1678d3eca20SDavid Ahern 		goto out;
1680a102479SFrederic Weisbecker 	}
1690a102479SFrederic Weisbecker 
17018e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
1718d3eca20SDavid Ahern 		if (errno == EPERM) {
1728d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
17318e60939SNelson Elhage 			       "Consider increasing "
17418e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
17518e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
17653653d70SAdrian Hunter 			       "(current value: %u)\n", opts->mmap_pages);
1778d3eca20SDavid Ahern 			rc = -errno;
1788d3eca20SDavid Ahern 		} else {
17935550da3SMasami Hiramatsu 			pr_err("failed to mmap with %d (%s)\n", errno,
18035550da3SMasami Hiramatsu 				strerror_r(errno, msg, sizeof(msg)));
1818d3eca20SDavid Ahern 			rc = -errno;
1828d3eca20SDavid Ahern 		}
1838d3eca20SDavid Ahern 		goto out;
18418e60939SNelson Elhage 	}
1850a27d7f9SArnaldo Carvalho de Melo 
186a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
1877b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
1888d3eca20SDavid Ahern out:
1898d3eca20SDavid Ahern 	return rc;
190a91e5431SArnaldo Carvalho de Melo }
191a91e5431SArnaldo Carvalho de Melo 
1928c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
1936122e4e4SArnaldo Carvalho de Melo {
194f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
195f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
1967ab75cffSDavid Ahern 	u64 start = session->header.data_offset;
1976122e4e4SArnaldo Carvalho de Melo 
198f5fc1412SJiri Olsa 	u64 size = lseek(file->fd, 0, SEEK_CUR);
1999f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2009f591fd7SArnaldo Carvalho de Melo 		return 0;
2019f591fd7SArnaldo Carvalho de Melo 
2027ab75cffSDavid Ahern 	return __perf_session__process_events(session, start,
2037ab75cffSDavid Ahern 					      size - start,
2046122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
2056122e4e4SArnaldo Carvalho de Melo }
2066122e4e4SArnaldo Carvalho de Melo 
2078115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
208a1645ce1SZhang, Yanmin {
209a1645ce1SZhang, Yanmin 	int err;
21045694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
211a1645ce1SZhang, Yanmin 	/*
212a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
213a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
214a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
215a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
216a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
217a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
218a1645ce1SZhang, Yanmin 	 */
21945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
220743eb868SArnaldo Carvalho de Melo 					     machine);
221a1645ce1SZhang, Yanmin 	if (err < 0)
222a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
22323346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
224a1645ce1SZhang, Yanmin 
225a1645ce1SZhang, Yanmin 	/*
226a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
227a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
228a1645ce1SZhang, Yanmin 	 */
22945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
2300ae617beSAdrian Hunter 						 machine);
231a1645ce1SZhang, Yanmin 	if (err < 0)
232a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
23323346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
234a1645ce1SZhang, Yanmin }
235a1645ce1SZhang, Yanmin 
23698402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
23798402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
23898402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
23998402807SFrederic Weisbecker };
24098402807SFrederic Weisbecker 
2418c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
24298402807SFrederic Weisbecker {
243dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
2440e2e63ddSPeter Zijlstra 	int i;
2458d3eca20SDavid Ahern 	int rc = 0;
24698402807SFrederic Weisbecker 
247d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
2488d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
249e5685730SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, i) != 0) {
2508d3eca20SDavid Ahern 				rc = -1;
2518d3eca20SDavid Ahern 				goto out;
2528d3eca20SDavid Ahern 			}
2538d3eca20SDavid Ahern 		}
25498402807SFrederic Weisbecker 	}
25598402807SFrederic Weisbecker 
256dcabb507SJiri Olsa 	/*
257dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
258dcabb507SJiri Olsa 	 * at least one event.
259dcabb507SJiri Olsa 	 */
260dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
2618c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
2628d3eca20SDavid Ahern 
2638d3eca20SDavid Ahern out:
2648d3eca20SDavid Ahern 	return rc;
26598402807SFrederic Weisbecker }
26698402807SFrederic Weisbecker 
2678c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
26857706abcSDavid Ahern {
26957706abcSDavid Ahern 	struct perf_session *session = rec->session;
27057706abcSDavid Ahern 	int feat;
27157706abcSDavid Ahern 
27257706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
27357706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
27457706abcSDavid Ahern 
27557706abcSDavid Ahern 	if (rec->no_buildid)
27657706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
27757706abcSDavid Ahern 
2783e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
27957706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
28057706abcSDavid Ahern 
28157706abcSDavid Ahern 	if (!rec->opts.branch_stack)
28257706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
28357706abcSDavid Ahern }
28457706abcSDavid Ahern 
285f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
286f33cbe72SArnaldo Carvalho de Melo 
287f33cbe72SArnaldo Carvalho de Melo /*
288f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
289f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
290f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
291f33cbe72SArnaldo Carvalho de Melo  */
29245604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
29345604710SNamhyung Kim 					siginfo_t *info,
294f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
295f33cbe72SArnaldo Carvalho de Melo {
296f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
297f33cbe72SArnaldo Carvalho de Melo 	done = 1;
298f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
299f33cbe72SArnaldo Carvalho de Melo }
300f33cbe72SArnaldo Carvalho de Melo 
3018c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
30286470930SIngo Molnar {
30357706abcSDavid Ahern 	int err;
30445604710SNamhyung Kim 	int status = 0;
3058b412664SPeter Zijlstra 	unsigned long waking = 0;
30646be604bSZhang, Yanmin 	const bool forks = argc > 0;
30723346f21SArnaldo Carvalho de Melo 	struct machine *machine;
30845694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
309b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
310f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
311d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3126dcf45efSArnaldo Carvalho de Melo 	bool disabled = false, draining = false;
31386470930SIngo Molnar 
314d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
31533e49ea7SAndi Kleen 
31645604710SNamhyung Kim 	atexit(record__sig_exit);
317f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
318f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
319804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
320f5970550SPeter Zijlstra 
321f5fc1412SJiri Olsa 	session = perf_session__new(file, false, NULL);
32294c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
323ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
324a9a70bbcSArnaldo Carvalho de Melo 		return -1;
325a9a70bbcSArnaldo Carvalho de Melo 	}
326a9a70bbcSArnaldo Carvalho de Melo 
327d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
328d20deb64SArnaldo Carvalho de Melo 
3298c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
330330aa675SStephane Eranian 
331d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
3323e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
333f5fc1412SJiri Olsa 						    argv, file->is_pipe,
334735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
33535b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
33635b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
33745604710SNamhyung Kim 			status = err;
33835b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
339856e9660SPeter Zijlstra 		}
340856e9660SPeter Zijlstra 	}
341856e9660SPeter Zijlstra 
3428c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
3438d3eca20SDavid Ahern 		err = -1;
34445604710SNamhyung Kim 		goto out_child;
3458d3eca20SDavid Ahern 	}
34686470930SIngo Molnar 
3473e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
348a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
349a8bb559bSNamhyung Kim 
350f5fc1412SJiri Olsa 	if (file->is_pipe) {
351f5fc1412SJiri Olsa 		err = perf_header__write_pipe(file->fd);
352529870e3STom Zanussi 		if (err < 0)
35345604710SNamhyung Kim 			goto out_child;
354563aecb2SJiri Olsa 	} else {
3553e2be2daSArnaldo Carvalho de Melo 		err = perf_session__write_header(session, rec->evlist,
356f5fc1412SJiri Olsa 						 file->fd, false);
357d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
35845604710SNamhyung Kim 			goto out_child;
359d5eed904SArnaldo Carvalho de Melo 	}
3607c6a1c65SPeter Zijlstra 
361d3665498SDavid Ahern 	if (!rec->no_buildid
362e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
363d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
364e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
3658d3eca20SDavid Ahern 		err = -1;
36645604710SNamhyung Kim 		goto out_child;
367e20960c0SRobert Richter 	}
368e20960c0SRobert Richter 
36934ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
370743eb868SArnaldo Carvalho de Melo 
371f5fc1412SJiri Olsa 	if (file->is_pipe) {
37245694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
373a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
3742c46dbb5STom Zanussi 		if (err < 0) {
3752c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
37645604710SNamhyung Kim 			goto out_child;
3772c46dbb5STom Zanussi 		}
378cd19a035STom Zanussi 
3793e2be2daSArnaldo Carvalho de Melo 		if (have_tracepoints(&rec->evlist->entries)) {
38063e0c771STom Zanussi 			/*
38163e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
38263e0c771STom Zanussi 			 * there were no tracepoints so its not really
38363e0c771STom Zanussi 			 * an error, just that we don't need to
38463e0c771STom Zanussi 			 * synthesize anything.  We really have to
38563e0c771STom Zanussi 			 * return this more properly and also
38663e0c771STom Zanussi 			 * propagate errors that now are calling die()
38763e0c771STom Zanussi 			 */
3883e2be2daSArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist,
389743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
39063e0c771STom Zanussi 			if (err <= 0) {
39163e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
39245604710SNamhyung Kim 				goto out_child;
39363e0c771STom Zanussi 			}
394f34b9001SDavid Ahern 			rec->bytes_written += err;
3952c46dbb5STom Zanussi 		}
39663e0c771STom Zanussi 	}
3972c46dbb5STom Zanussi 
39845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
3990ae617beSAdrian Hunter 						 machine);
400c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
401c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
402c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
403c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
40456b03f3cSArnaldo Carvalho de Melo 
40545694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
406743eb868SArnaldo Carvalho de Melo 					     machine);
407c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
408c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
409c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
410c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
411c1a3a4b9SArnaldo Carvalho de Melo 
4127e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
413876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
4147e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
4157e383de4SArnaldo Carvalho de Melo 	}
416b7cece76SArnaldo Carvalho de Melo 
4173e2be2daSArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
41858d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
4198d3eca20SDavid Ahern 	if (err != 0)
42045604710SNamhyung Kim 		goto out_child;
4218d3eca20SDavid Ahern 
422d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
42386470930SIngo Molnar 		struct sched_param param;
42486470930SIngo Molnar 
425d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
42686470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
4276beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
4288d3eca20SDavid Ahern 			err = -1;
42945604710SNamhyung Kim 			goto out_child;
43086470930SIngo Molnar 		}
43186470930SIngo Molnar 	}
43286470930SIngo Molnar 
433774cb499SJiri Olsa 	/*
434774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
435774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
436774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
437774cb499SJiri Olsa 	 */
4386619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
4393e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
440764e16a3SDavid Ahern 
441856e9660SPeter Zijlstra 	/*
442856e9660SPeter Zijlstra 	 * Let the child rip
443856e9660SPeter Zijlstra 	 */
444735f7e0bSArnaldo Carvalho de Melo 	if (forks)
4453e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
446856e9660SPeter Zijlstra 
4476619a53eSAndi Kleen 	if (opts->initial_delay) {
4486619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
4496619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
4506619a53eSAndi Kleen 	}
4516619a53eSAndi Kleen 
452649c48a9SPeter Zijlstra 	for (;;) {
453d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
45486470930SIngo Molnar 
4558c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
4568d3eca20SDavid Ahern 			err = -1;
45745604710SNamhyung Kim 			goto out_child;
4588d3eca20SDavid Ahern 		}
45986470930SIngo Molnar 
460d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
4616dcf45efSArnaldo Carvalho de Melo 			if (done || draining)
462649c48a9SPeter Zijlstra 				break;
463f66a889dSArnaldo Carvalho de Melo 			err = perf_evlist__poll(rec->evlist, -1);
464a515114fSJiri Olsa 			/*
465a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
466a515114fSJiri Olsa 			 * number of returned events and interrupt error.
467a515114fSJiri Olsa 			 */
468a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
46945604710SNamhyung Kim 				err = 0;
4708b412664SPeter Zijlstra 			waking++;
4716dcf45efSArnaldo Carvalho de Melo 
4726dcf45efSArnaldo Carvalho de Melo 			if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
4736dcf45efSArnaldo Carvalho de Melo 				draining = true;
4748b412664SPeter Zijlstra 		}
4758b412664SPeter Zijlstra 
476774cb499SJiri Olsa 		/*
477774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
478774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
479774cb499SJiri Olsa 		 * disable events in this case.
480774cb499SJiri Olsa 		 */
481602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
4823e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
4832711926aSJiri Olsa 			disabled = true;
4842711926aSJiri Olsa 		}
4858b412664SPeter Zijlstra 	}
4868b412664SPeter Zijlstra 
487f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
48835550da3SMasami Hiramatsu 		char msg[STRERR_BUFSIZE];
489f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
490f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
491f33cbe72SArnaldo Carvalho de Melo 		err = -1;
49245604710SNamhyung Kim 		goto out_child;
493f33cbe72SArnaldo Carvalho de Melo 	}
494f33cbe72SArnaldo Carvalho de Melo 
49545604710SNamhyung Kim 	if (!quiet) {
4968b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
49786470930SIngo Molnar 
49886470930SIngo Molnar 		/*
49986470930SIngo Molnar 		 * Approximate RIP event size: 24 bytes.
50086470930SIngo Molnar 		 */
50186470930SIngo Molnar 		fprintf(stderr,
5029486aa38SArnaldo Carvalho de Melo 			"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
503d20deb64SArnaldo Carvalho de Melo 			(double)rec->bytes_written / 1024.0 / 1024.0,
5046a4d98d7SJiri Olsa 			file->path,
505d20deb64SArnaldo Carvalho de Melo 			rec->bytes_written / 24);
50645604710SNamhyung Kim 	}
50786470930SIngo Molnar 
50845604710SNamhyung Kim out_child:
50945604710SNamhyung Kim 	if (forks) {
51045604710SNamhyung Kim 		int exit_status;
51145604710SNamhyung Kim 
51245604710SNamhyung Kim 		if (!child_finished)
51345604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
51445604710SNamhyung Kim 
51545604710SNamhyung Kim 		wait(&exit_status);
51645604710SNamhyung Kim 
51745604710SNamhyung Kim 		if (err < 0)
51845604710SNamhyung Kim 			status = err;
51945604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
52045604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
52145604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
52245604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
52345604710SNamhyung Kim 	} else
52445604710SNamhyung Kim 		status = err;
52545604710SNamhyung Kim 
52645604710SNamhyung Kim 	if (!err && !file->is_pipe) {
52745604710SNamhyung Kim 		rec->session->header.data_size += rec->bytes_written;
52845604710SNamhyung Kim 
52945604710SNamhyung Kim 		if (!rec->no_buildid)
53045604710SNamhyung Kim 			process_buildids(rec);
53145604710SNamhyung Kim 		perf_session__write_header(rec->session, rec->evlist,
53245604710SNamhyung Kim 					   file->fd, true);
53345604710SNamhyung Kim 	}
53439d17dacSArnaldo Carvalho de Melo 
53539d17dacSArnaldo Carvalho de Melo out_delete_session:
53639d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
53745604710SNamhyung Kim 	return status;
53886470930SIngo Molnar }
53986470930SIngo Molnar 
540bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
541bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
542bdfebd84SRoberto Agostino Vitillo 
543bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
544bdfebd84SRoberto Agostino Vitillo 
545bdfebd84SRoberto Agostino Vitillo struct branch_mode {
546bdfebd84SRoberto Agostino Vitillo 	const char *name;
547bdfebd84SRoberto Agostino Vitillo 	int mode;
548bdfebd84SRoberto Agostino Vitillo };
549bdfebd84SRoberto Agostino Vitillo 
550bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
551bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
552bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
553bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
554bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
555bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
556bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
557bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
5580126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
5590126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
5600126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
5610fffa5dfSAnshuman Khandual 	BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
562bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
563bdfebd84SRoberto Agostino Vitillo };
564bdfebd84SRoberto Agostino Vitillo 
565bdfebd84SRoberto Agostino Vitillo static int
566a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
567bdfebd84SRoberto Agostino Vitillo {
568bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
569bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
570bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
571bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
572bdfebd84SRoberto Agostino Vitillo 
573bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
574bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
575a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
576bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
577bdfebd84SRoberto Agostino Vitillo 
578a5aabdacSStephane Eranian 	if (unset)
579a5aabdacSStephane Eranian 		return 0;
580bdfebd84SRoberto Agostino Vitillo 
581a5aabdacSStephane Eranian 	/*
582a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
583a5aabdacSStephane Eranian 	 */
584a5aabdacSStephane Eranian 	if (*mode)
585a5aabdacSStephane Eranian 		return -1;
586a5aabdacSStephane Eranian 
587a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
588a5aabdacSStephane Eranian 	if (str) {
589bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
590bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
591bdfebd84SRoberto Agostino Vitillo 		if (!s)
592bdfebd84SRoberto Agostino Vitillo 			return -1;
593bdfebd84SRoberto Agostino Vitillo 
594bdfebd84SRoberto Agostino Vitillo 		for (;;) {
595bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
596bdfebd84SRoberto Agostino Vitillo 			if (p)
597bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
598bdfebd84SRoberto Agostino Vitillo 
599bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
600bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
601bdfebd84SRoberto Agostino Vitillo 					break;
602bdfebd84SRoberto Agostino Vitillo 			}
603a5aabdacSStephane Eranian 			if (!br->name) {
604a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
605a5aabdacSStephane Eranian 					    " check man page\n", s);
606bdfebd84SRoberto Agostino Vitillo 				goto error;
607a5aabdacSStephane Eranian 			}
608bdfebd84SRoberto Agostino Vitillo 
609bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
610bdfebd84SRoberto Agostino Vitillo 
611bdfebd84SRoberto Agostino Vitillo 			if (!p)
612bdfebd84SRoberto Agostino Vitillo 				break;
613bdfebd84SRoberto Agostino Vitillo 
614bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
615bdfebd84SRoberto Agostino Vitillo 		}
616a5aabdacSStephane Eranian 	}
617bdfebd84SRoberto Agostino Vitillo 	ret = 0;
618bdfebd84SRoberto Agostino Vitillo 
619a5aabdacSStephane Eranian 	/* default to any branch */
620bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
621a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
622bdfebd84SRoberto Agostino Vitillo 	}
623bdfebd84SRoberto Agostino Vitillo error:
624bdfebd84SRoberto Agostino Vitillo 	free(os);
625bdfebd84SRoberto Agostino Vitillo 	return ret;
626bdfebd84SRoberto Agostino Vitillo }
627bdfebd84SRoberto Agostino Vitillo 
62872a128aaSNamhyung Kim static void callchain_debug(void)
62909b0fd45SJiri Olsa {
630a601fdffSJiri Olsa 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
631a601fdffSJiri Olsa 
63272a128aaSNamhyung Kim 	pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
63326d33022SJiri Olsa 
63472a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_DWARF)
63509b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
63672a128aaSNamhyung Kim 			 callchain_param.dump_size);
63709b0fd45SJiri Olsa }
63809b0fd45SJiri Olsa 
63972a128aaSNamhyung Kim int record_parse_callchain_opt(const struct option *opt __maybe_unused,
64009b0fd45SJiri Olsa 			       const char *arg,
64109b0fd45SJiri Olsa 			       int unset)
64209b0fd45SJiri Olsa {
64309b0fd45SJiri Olsa 	int ret;
64409b0fd45SJiri Olsa 
64572a128aaSNamhyung Kim 	callchain_param.enabled = !unset;
646eb853e80SJiri Olsa 
64709b0fd45SJiri Olsa 	/* --no-call-graph */
64809b0fd45SJiri Olsa 	if (unset) {
64972a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_NONE;
65009b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
65109b0fd45SJiri Olsa 		return 0;
65209b0fd45SJiri Olsa 	}
65309b0fd45SJiri Olsa 
654f7f084f4SNamhyung Kim 	ret = parse_callchain_record_opt(arg);
65509b0fd45SJiri Olsa 	if (!ret)
65672a128aaSNamhyung Kim 		callchain_debug();
65709b0fd45SJiri Olsa 
65826d33022SJiri Olsa 	return ret;
65926d33022SJiri Olsa }
66026d33022SJiri Olsa 
66172a128aaSNamhyung Kim int record_callchain_opt(const struct option *opt __maybe_unused,
66209b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
66309b0fd45SJiri Olsa 			 int unset __maybe_unused)
66409b0fd45SJiri Olsa {
66572a128aaSNamhyung Kim 	callchain_param.enabled = true;
66609b0fd45SJiri Olsa 
66772a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_NONE)
66872a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_FP;
669eb853e80SJiri Olsa 
67072a128aaSNamhyung Kim 	callchain_debug();
67109b0fd45SJiri Olsa 	return 0;
67209b0fd45SJiri Olsa }
67309b0fd45SJiri Olsa 
674eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
675eb853e80SJiri Olsa {
676eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
6775a2e5e85SNamhyung Kim 		var = "call-graph.record-mode"; /* fall-through */
678eb853e80SJiri Olsa 
679eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
680eb853e80SJiri Olsa }
681eb853e80SJiri Olsa 
68286470930SIngo Molnar static const char * const record_usage[] = {
68386470930SIngo Molnar 	"perf record [<options>] [<command>]",
68486470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
68586470930SIngo Molnar 	NULL
68686470930SIngo Molnar };
68786470930SIngo Molnar 
688d20deb64SArnaldo Carvalho de Melo /*
6898c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
6908c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
691d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
692d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
693d20deb64SArnaldo Carvalho de Melo  *
694d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
695d20deb64SArnaldo Carvalho de Melo  *
696d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
697d20deb64SArnaldo Carvalho de Melo  */
6988c6f45a7SArnaldo Carvalho de Melo static struct record record = {
699d20deb64SArnaldo Carvalho de Melo 	.opts = {
7008affc2b8SAndi Kleen 		.sample_time	     = true,
701d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
702d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
703d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
704447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
705d1cb9fceSNamhyung Kim 		.target		     = {
706d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
7073aa5939dSAdrian Hunter 			.default_per_cpu = true,
708d1cb9fceSNamhyung Kim 		},
709d20deb64SArnaldo Carvalho de Melo 	},
710d20deb64SArnaldo Carvalho de Melo };
7117865e817SFrederic Weisbecker 
71209b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
71361eaa3beSArnaldo Carvalho de Melo 
7149ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
71509b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
71661eaa3beSArnaldo Carvalho de Melo #else
71709b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp";
71861eaa3beSArnaldo Carvalho de Melo #endif
71961eaa3beSArnaldo Carvalho de Melo 
720d20deb64SArnaldo Carvalho de Melo /*
721d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
722d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
723b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
724d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
725d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
726d20deb64SArnaldo Carvalho de Melo  */
727bca647aaSTom Zanussi const struct option record_options[] = {
728d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
72986470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
730f120f9d5SJiri Olsa 		     parse_events_option),
731d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
732c171b552SLi Zefan 		     "event filter", parse_filter),
733bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
734d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
735bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
736d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
737d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
73886470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
739509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
740acac03faSKirill Smelkov 		    "collect data without buffering"),
741d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
742daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
743bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
74486470930SIngo Molnar 			    "system-wide collection from all CPUs"),
745bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
746c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
747d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
748f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
74986470930SIngo Molnar 		    "output file name"),
75069e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
75169e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
7522e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
753d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
754994a1f78SJiri Olsa 	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
755994a1f78SJiri Olsa 		     "number of mmap data pages",
756994a1f78SJiri Olsa 		     perf_evlist__parse_mmap_pages),
757d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
75843bece79SLin Ming 		    "put the counters into a counter group"),
75909b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
76009b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
76109b0fd45SJiri Olsa 			   &record_callchain_opt),
76209b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
76375d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
76409b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
765c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
7663da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
767b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
768d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
769649c48a9SPeter Zijlstra 		    "per thread counts"),
770d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
7714bba828dSAnton Blanchard 		    "Sample addresses"),
772d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
7733e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
774d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
775649c48a9SPeter Zijlstra 		    "don't sample"),
776d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
777a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
778d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
779baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
780d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
781023695d9SStephane Eranian 		     "monitor event in cgroup name only",
782023695d9SStephane Eranian 		     parse_cgroups),
783a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
7846619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
785bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
786bea03405SNamhyung Kim 		   "user to profile"),
787a5aabdacSStephane Eranian 
788a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
789a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
790a5aabdacSStephane Eranian 		     parse_branch_stack),
791a5aabdacSStephane Eranian 
792a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
793a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
794bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
79505484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
79605484298SAndi Kleen 		    "sample by weight (on special events only)"),
797475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
798475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
7993aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
8003aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
80186470930SIngo Molnar 	OPT_END()
80286470930SIngo Molnar };
80386470930SIngo Molnar 
8041d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
80586470930SIngo Molnar {
80669aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
8078c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
80816ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
80986470930SIngo Molnar 
8103e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
8113e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
812361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
813361c99a6SArnaldo Carvalho de Melo 
814eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
815eb853e80SJiri Olsa 
816bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
817a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
818602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
819bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
82086470930SIngo Molnar 
821bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
8223780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
823023695d9SStephane Eranian 			  " system-wide mode\n");
824023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
825023695d9SStephane Eranian 	}
826023695d9SStephane Eranian 
8270a7e6d1bSNamhyung Kim 	symbol__init(NULL);
828baa2f6ceSArnaldo Carvalho de Melo 
829ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
830646aaea6SArnaldo Carvalho de Melo 		pr_warning(
831646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
832ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
833646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
834646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
835646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
836646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
837646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
838ec80fde7SArnaldo Carvalho de Melo 
839d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
840a1ac1d3cSStephane Eranian 		disable_buildid_cache();
841655000e7SArnaldo Carvalho de Melo 
8423e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
8433e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
84469aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
84569aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
846bbd36e5eSPeter Zijlstra 	}
84786470930SIngo Molnar 
84869e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
84969e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
85069e7e5b0SAdrian Hunter 
851602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
85216ad2ffbSNamhyung Kim 	if (err) {
853602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
85416ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
85516ad2ffbSNamhyung Kim 	}
8564bd0f2d2SNamhyung Kim 
857602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
85816ad2ffbSNamhyung Kim 	if (err) {
85916ad2ffbSNamhyung Kim 		int saved_errno = errno;
86016ad2ffbSNamhyung Kim 
861602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
8623780f488SNamhyung Kim 		ui__error("%s", errbuf);
86316ad2ffbSNamhyung Kim 
86416ad2ffbSNamhyung Kim 		err = -saved_errno;
8658fa60e1fSNamhyung Kim 		goto out_symbol_exit;
86616ad2ffbSNamhyung Kim 	}
8670d37aa34SArnaldo Carvalho de Melo 
86816ad2ffbSNamhyung Kim 	err = -ENOMEM;
8693e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
870dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
87169aad6f1SArnaldo Carvalho de Melo 
872b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
87339d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
87403ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
8757e4ff9e3SMike Galbraith 	}
8767e4ff9e3SMike Galbraith 
877d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
878d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
87945604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
880d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
88139d17dacSArnaldo Carvalho de Melo 	return err;
88286470930SIngo Molnar }
883