xref: /openbmc/linux/tools/perf/builtin-record.c (revision 5a2e5e85989025a3bb23ea5571fdac0cc5787807)
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 
177c6a1c65SPeter Zijlstra #include "util/header.h"
1866e274f3SFrederic Weisbecker #include "util/event.h"
19361c99a6SArnaldo Carvalho de Melo #include "util/evlist.h"
2069aad6f1SArnaldo Carvalho de Melo #include "util/evsel.h"
218f28827aSFrederic Weisbecker #include "util/debug.h"
2294c744b6SArnaldo Carvalho de Melo #include "util/session.h"
2345694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
248d06367fSArnaldo Carvalho de Melo #include "util/symbol.h"
25a12b51c4SPaul Mackerras #include "util/cpumap.h"
26fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h"
27f5fc1412SJiri Olsa #include "util/data.h"
287c6a1c65SPeter Zijlstra 
2986470930SIngo Molnar #include <unistd.h>
3086470930SIngo Molnar #include <sched.h>
31a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3286470930SIngo Molnar 
3378da39faSBernhard Rosenkraenzer 
348c6f45a7SArnaldo Carvalho de Melo struct record {
3545694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
36b4006796SArnaldo Carvalho de Melo 	struct record_opts	opts;
37d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
38f5fc1412SJiri Olsa 	struct perf_data_file	file;
39d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
40d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
41d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
42d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
43d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
44d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
45d20deb64SArnaldo Carvalho de Melo 	long			samples;
460f82ebc4SArnaldo Carvalho de Melo };
4786470930SIngo Molnar 
488c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
49f5970550SPeter Zijlstra {
50cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
514f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
528d3eca20SDavid Ahern 		return -1;
538d3eca20SDavid Ahern 	}
54f5970550SPeter Zijlstra 
55cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
568d3eca20SDavid Ahern 	return 0;
57f5970550SPeter Zijlstra }
58f5970550SPeter Zijlstra 
5945694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
60d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
611d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
621d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
63234fbbf5SArnaldo Carvalho de Melo {
648c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
658c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
66234fbbf5SArnaldo Carvalho de Melo }
67234fbbf5SArnaldo Carvalho de Melo 
68e5685730SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, int idx)
6986470930SIngo Molnar {
70e5685730SArnaldo Carvalho de Melo 	struct perf_mmap *md = &rec->evlist->mmap[idx];
71744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
7286470930SIngo Molnar 	unsigned int old = md->prev;
73918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
7486470930SIngo Molnar 	unsigned long size;
7586470930SIngo Molnar 	void *buf;
768d3eca20SDavid Ahern 	int rc = 0;
7786470930SIngo Molnar 
78dc82009aSArnaldo Carvalho de Melo 	if (old == head)
798d3eca20SDavid Ahern 		return 0;
8086470930SIngo Molnar 
81d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
8286470930SIngo Molnar 
8386470930SIngo Molnar 	size = head - old;
8486470930SIngo Molnar 
8586470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
8686470930SIngo Molnar 		buf = &data[old & md->mask];
8786470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
8886470930SIngo Molnar 		old += size;
8986470930SIngo Molnar 
908c6f45a7SArnaldo Carvalho de Melo 		if (record__write(rec, buf, size) < 0) {
918d3eca20SDavid Ahern 			rc = -1;
928d3eca20SDavid Ahern 			goto out;
938d3eca20SDavid Ahern 		}
9486470930SIngo Molnar 	}
9586470930SIngo Molnar 
9686470930SIngo Molnar 	buf = &data[old & md->mask];
9786470930SIngo Molnar 	size = head - old;
9886470930SIngo Molnar 	old += size;
9986470930SIngo Molnar 
1008c6f45a7SArnaldo Carvalho de Melo 	if (record__write(rec, buf, size) < 0) {
1018d3eca20SDavid Ahern 		rc = -1;
1028d3eca20SDavid Ahern 		goto out;
1038d3eca20SDavid Ahern 	}
10486470930SIngo Molnar 
10586470930SIngo Molnar 	md->prev = old;
106e5685730SArnaldo Carvalho de Melo 	perf_evlist__mmap_consume(rec->evlist, idx);
1078d3eca20SDavid Ahern out:
1088d3eca20SDavid Ahern 	return rc;
10986470930SIngo Molnar }
11086470930SIngo Molnar 
11186470930SIngo Molnar static volatile int done = 0;
112f7b7c26eSPeter Zijlstra static volatile int signr = -1;
11333e49ea7SAndi Kleen static volatile int child_finished = 0;
11486470930SIngo Molnar 
11586470930SIngo Molnar static void sig_handler(int sig)
11686470930SIngo Molnar {
11733e49ea7SAndi Kleen 	if (sig == SIGCHLD)
11833e49ea7SAndi Kleen 		child_finished = 1;
11945604710SNamhyung Kim 	else
12045604710SNamhyung Kim 		signr = sig;
12133e49ea7SAndi Kleen 
12286470930SIngo Molnar 	done = 1;
123f7b7c26eSPeter Zijlstra }
124f7b7c26eSPeter Zijlstra 
12545604710SNamhyung Kim static void record__sig_exit(void)
126f7b7c26eSPeter Zijlstra {
12745604710SNamhyung Kim 	if (signr == -1)
128f7b7c26eSPeter Zijlstra 		return;
129f7b7c26eSPeter Zijlstra 
130f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
13145604710SNamhyung Kim 	raise(signr);
13286470930SIngo Molnar }
13386470930SIngo Molnar 
1348c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
135dd7927f4SArnaldo Carvalho de Melo {
13656e52e85SArnaldo Carvalho de Melo 	char msg[512];
1376a4bb04cSJiri Olsa 	struct perf_evsel *pos;
138d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
139d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
140b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
1418d3eca20SDavid Ahern 	int rc = 0;
142dd7927f4SArnaldo Carvalho de Melo 
143f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
144cac21425SJiri Olsa 
1450050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
1463da297a6SIngo Molnar try_again:
1476a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
14856e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
1493da297a6SIngo Molnar 				if (verbose)
150c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
1513da297a6SIngo Molnar 				goto try_again;
1523da297a6SIngo Molnar 			}
153ca6a4258SDavid Ahern 
15456e52e85SArnaldo Carvalho de Melo 			rc = -errno;
15556e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
15656e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
15756e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
1588d3eca20SDavid Ahern 			goto out;
1597c6a1c65SPeter Zijlstra 		}
1607c6a1c65SPeter Zijlstra 	}
1617c6a1c65SPeter Zijlstra 
1621491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
1630a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
16435550da3SMasami Hiramatsu 			strerror_r(errno, msg, sizeof(msg)));
1658d3eca20SDavid Ahern 		rc = -1;
1668d3eca20SDavid Ahern 		goto out;
1670a102479SFrederic Weisbecker 	}
1680a102479SFrederic Weisbecker 
16918e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
1708d3eca20SDavid Ahern 		if (errno == EPERM) {
1718d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
17218e60939SNelson Elhage 			       "Consider increasing "
17318e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
17418e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
17553653d70SAdrian Hunter 			       "(current value: %u)\n", opts->mmap_pages);
1768d3eca20SDavid Ahern 			rc = -errno;
1778d3eca20SDavid Ahern 		} else {
17835550da3SMasami Hiramatsu 			pr_err("failed to mmap with %d (%s)\n", errno,
17935550da3SMasami Hiramatsu 				strerror_r(errno, msg, sizeof(msg)));
1808d3eca20SDavid Ahern 			rc = -errno;
1818d3eca20SDavid Ahern 		}
1828d3eca20SDavid Ahern 		goto out;
18318e60939SNelson Elhage 	}
1840a27d7f9SArnaldo Carvalho de Melo 
185a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
1867b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
1878d3eca20SDavid Ahern out:
1888d3eca20SDavid Ahern 	return rc;
189a91e5431SArnaldo Carvalho de Melo }
190a91e5431SArnaldo Carvalho de Melo 
1918c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
1926122e4e4SArnaldo Carvalho de Melo {
193f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
194f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
1957ab75cffSDavid Ahern 	u64 start = session->header.data_offset;
1966122e4e4SArnaldo Carvalho de Melo 
197f5fc1412SJiri Olsa 	u64 size = lseek(file->fd, 0, SEEK_CUR);
1989f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
1999f591fd7SArnaldo Carvalho de Melo 		return 0;
2009f591fd7SArnaldo Carvalho de Melo 
2017ab75cffSDavid Ahern 	return __perf_session__process_events(session, start,
2027ab75cffSDavid Ahern 					      size - start,
2036122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
2046122e4e4SArnaldo Carvalho de Melo }
2056122e4e4SArnaldo Carvalho de Melo 
2068115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
207a1645ce1SZhang, Yanmin {
208a1645ce1SZhang, Yanmin 	int err;
20945694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
210a1645ce1SZhang, Yanmin 	/*
211a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
212a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
213a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
214a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
215a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
216a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
217a1645ce1SZhang, Yanmin 	 */
21845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
219743eb868SArnaldo Carvalho de Melo 					     machine);
220a1645ce1SZhang, Yanmin 	if (err < 0)
221a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
22223346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
223a1645ce1SZhang, Yanmin 
224a1645ce1SZhang, Yanmin 	/*
225a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
226a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
227a1645ce1SZhang, Yanmin 	 */
22845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
2290ae617beSAdrian Hunter 						 machine);
230a1645ce1SZhang, Yanmin 	if (err < 0)
231a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
23223346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
233a1645ce1SZhang, Yanmin }
234a1645ce1SZhang, Yanmin 
23598402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
23698402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
23798402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
23898402807SFrederic Weisbecker };
23998402807SFrederic Weisbecker 
2408c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
24198402807SFrederic Weisbecker {
242dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
2430e2e63ddSPeter Zijlstra 	int i;
2448d3eca20SDavid Ahern 	int rc = 0;
24598402807SFrederic Weisbecker 
246d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
2478d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
248e5685730SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, i) != 0) {
2498d3eca20SDavid Ahern 				rc = -1;
2508d3eca20SDavid Ahern 				goto out;
2518d3eca20SDavid Ahern 			}
2528d3eca20SDavid Ahern 		}
25398402807SFrederic Weisbecker 	}
25498402807SFrederic Weisbecker 
255dcabb507SJiri Olsa 	/*
256dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
257dcabb507SJiri Olsa 	 * at least one event.
258dcabb507SJiri Olsa 	 */
259dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
2608c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
2618d3eca20SDavid Ahern 
2628d3eca20SDavid Ahern out:
2638d3eca20SDavid Ahern 	return rc;
26498402807SFrederic Weisbecker }
26598402807SFrederic Weisbecker 
2668c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
26757706abcSDavid Ahern {
26857706abcSDavid Ahern 	struct perf_session *session = rec->session;
26957706abcSDavid Ahern 	int feat;
27057706abcSDavid Ahern 
27157706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
27257706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
27357706abcSDavid Ahern 
27457706abcSDavid Ahern 	if (rec->no_buildid)
27557706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
27657706abcSDavid Ahern 
2773e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
27857706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
27957706abcSDavid Ahern 
28057706abcSDavid Ahern 	if (!rec->opts.branch_stack)
28157706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
28257706abcSDavid Ahern }
28357706abcSDavid Ahern 
284f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
285f33cbe72SArnaldo Carvalho de Melo 
286f33cbe72SArnaldo Carvalho de Melo /*
287f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
288f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
289f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
290f33cbe72SArnaldo Carvalho de Melo  */
29145604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
29245604710SNamhyung Kim 					siginfo_t *info,
293f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
294f33cbe72SArnaldo Carvalho de Melo {
295f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
296f33cbe72SArnaldo Carvalho de Melo 	done = 1;
297f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
298f33cbe72SArnaldo Carvalho de Melo }
299f33cbe72SArnaldo Carvalho de Melo 
3008c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
30186470930SIngo Molnar {
30257706abcSDavid Ahern 	int err;
30345604710SNamhyung Kim 	int status = 0;
3048b412664SPeter Zijlstra 	unsigned long waking = 0;
30546be604bSZhang, Yanmin 	const bool forks = argc > 0;
30623346f21SArnaldo Carvalho de Melo 	struct machine *machine;
30745694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
308b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
309f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
310d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3116dcf45efSArnaldo Carvalho de Melo 	bool disabled = false, draining = false;
31286470930SIngo Molnar 
313d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
31433e49ea7SAndi Kleen 
31545604710SNamhyung Kim 	atexit(record__sig_exit);
316f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
317f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
318804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
319f5970550SPeter Zijlstra 
320f5fc1412SJiri Olsa 	session = perf_session__new(file, false, NULL);
32194c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
322ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
323a9a70bbcSArnaldo Carvalho de Melo 		return -1;
324a9a70bbcSArnaldo Carvalho de Melo 	}
325a9a70bbcSArnaldo Carvalho de Melo 
326d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
327d20deb64SArnaldo Carvalho de Melo 
3288c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
329330aa675SStephane Eranian 
330d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
3313e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
332f5fc1412SJiri Olsa 						    argv, file->is_pipe,
333735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
33435b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
33535b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
33645604710SNamhyung Kim 			status = err;
33735b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
338856e9660SPeter Zijlstra 		}
339856e9660SPeter Zijlstra 	}
340856e9660SPeter Zijlstra 
3418c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
3428d3eca20SDavid Ahern 		err = -1;
34345604710SNamhyung Kim 		goto out_child;
3448d3eca20SDavid Ahern 	}
34586470930SIngo Molnar 
3463e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
347a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
348a8bb559bSNamhyung Kim 
349f5fc1412SJiri Olsa 	if (file->is_pipe) {
350f5fc1412SJiri Olsa 		err = perf_header__write_pipe(file->fd);
351529870e3STom Zanussi 		if (err < 0)
35245604710SNamhyung Kim 			goto out_child;
353563aecb2SJiri Olsa 	} else {
3543e2be2daSArnaldo Carvalho de Melo 		err = perf_session__write_header(session, rec->evlist,
355f5fc1412SJiri Olsa 						 file->fd, false);
356d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
35745604710SNamhyung Kim 			goto out_child;
358d5eed904SArnaldo Carvalho de Melo 	}
3597c6a1c65SPeter Zijlstra 
360d3665498SDavid Ahern 	if (!rec->no_buildid
361e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
362d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
363e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
3648d3eca20SDavid Ahern 		err = -1;
36545604710SNamhyung Kim 		goto out_child;
366e20960c0SRobert Richter 	}
367e20960c0SRobert Richter 
36834ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
369743eb868SArnaldo Carvalho de Melo 
370f5fc1412SJiri Olsa 	if (file->is_pipe) {
37145694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
372a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
3732c46dbb5STom Zanussi 		if (err < 0) {
3742c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
37545604710SNamhyung Kim 			goto out_child;
3762c46dbb5STom Zanussi 		}
377cd19a035STom Zanussi 
3783e2be2daSArnaldo Carvalho de Melo 		if (have_tracepoints(&rec->evlist->entries)) {
37963e0c771STom Zanussi 			/*
38063e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
38163e0c771STom Zanussi 			 * there were no tracepoints so its not really
38263e0c771STom Zanussi 			 * an error, just that we don't need to
38363e0c771STom Zanussi 			 * synthesize anything.  We really have to
38463e0c771STom Zanussi 			 * return this more properly and also
38563e0c771STom Zanussi 			 * propagate errors that now are calling die()
38663e0c771STom Zanussi 			 */
3873e2be2daSArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist,
388743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
38963e0c771STom Zanussi 			if (err <= 0) {
39063e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
39145604710SNamhyung Kim 				goto out_child;
39263e0c771STom Zanussi 			}
393f34b9001SDavid Ahern 			rec->bytes_written += err;
3942c46dbb5STom Zanussi 		}
39563e0c771STom Zanussi 	}
3962c46dbb5STom Zanussi 
39745694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
3980ae617beSAdrian Hunter 						 machine);
399c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
400c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
401c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
402c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
40356b03f3cSArnaldo Carvalho de Melo 
40445694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
405743eb868SArnaldo Carvalho de Melo 					     machine);
406c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
407c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
408c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
409c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
410c1a3a4b9SArnaldo Carvalho de Melo 
4117e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
412876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
4137e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
4147e383de4SArnaldo Carvalho de Melo 	}
415b7cece76SArnaldo Carvalho de Melo 
4163e2be2daSArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
41758d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
4188d3eca20SDavid Ahern 	if (err != 0)
41945604710SNamhyung Kim 		goto out_child;
4208d3eca20SDavid Ahern 
421d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
42286470930SIngo Molnar 		struct sched_param param;
42386470930SIngo Molnar 
424d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
42586470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
4266beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
4278d3eca20SDavid Ahern 			err = -1;
42845604710SNamhyung Kim 			goto out_child;
42986470930SIngo Molnar 		}
43086470930SIngo Molnar 	}
43186470930SIngo Molnar 
432774cb499SJiri Olsa 	/*
433774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
434774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
435774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
436774cb499SJiri Olsa 	 */
4376619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
4383e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
439764e16a3SDavid Ahern 
440856e9660SPeter Zijlstra 	/*
441856e9660SPeter Zijlstra 	 * Let the child rip
442856e9660SPeter Zijlstra 	 */
443735f7e0bSArnaldo Carvalho de Melo 	if (forks)
4443e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
445856e9660SPeter Zijlstra 
4466619a53eSAndi Kleen 	if (opts->initial_delay) {
4476619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
4486619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
4496619a53eSAndi Kleen 	}
4506619a53eSAndi Kleen 
451649c48a9SPeter Zijlstra 	for (;;) {
452d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
45386470930SIngo Molnar 
4548c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
4558d3eca20SDavid Ahern 			err = -1;
45645604710SNamhyung Kim 			goto out_child;
4578d3eca20SDavid Ahern 		}
45886470930SIngo Molnar 
459d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
4606dcf45efSArnaldo Carvalho de Melo 			if (done || draining)
461649c48a9SPeter Zijlstra 				break;
462f66a889dSArnaldo Carvalho de Melo 			err = perf_evlist__poll(rec->evlist, -1);
463a515114fSJiri Olsa 			/*
464a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
465a515114fSJiri Olsa 			 * number of returned events and interrupt error.
466a515114fSJiri Olsa 			 */
467a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
46845604710SNamhyung Kim 				err = 0;
4698b412664SPeter Zijlstra 			waking++;
4706dcf45efSArnaldo Carvalho de Melo 
4716dcf45efSArnaldo Carvalho de Melo 			if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
4726dcf45efSArnaldo Carvalho de Melo 				draining = true;
4738b412664SPeter Zijlstra 		}
4748b412664SPeter Zijlstra 
475774cb499SJiri Olsa 		/*
476774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
477774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
478774cb499SJiri Olsa 		 * disable events in this case.
479774cb499SJiri Olsa 		 */
480602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
4813e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
4822711926aSJiri Olsa 			disabled = true;
4832711926aSJiri Olsa 		}
4848b412664SPeter Zijlstra 	}
4858b412664SPeter Zijlstra 
486f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
48735550da3SMasami Hiramatsu 		char msg[STRERR_BUFSIZE];
488f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
489f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
490f33cbe72SArnaldo Carvalho de Melo 		err = -1;
49145604710SNamhyung Kim 		goto out_child;
492f33cbe72SArnaldo Carvalho de Melo 	}
493f33cbe72SArnaldo Carvalho de Melo 
49445604710SNamhyung Kim 	if (!quiet) {
4958b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
49686470930SIngo Molnar 
49786470930SIngo Molnar 		/*
49886470930SIngo Molnar 		 * Approximate RIP event size: 24 bytes.
49986470930SIngo Molnar 		 */
50086470930SIngo Molnar 		fprintf(stderr,
5019486aa38SArnaldo Carvalho de Melo 			"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
502d20deb64SArnaldo Carvalho de Melo 			(double)rec->bytes_written / 1024.0 / 1024.0,
5036a4d98d7SJiri Olsa 			file->path,
504d20deb64SArnaldo Carvalho de Melo 			rec->bytes_written / 24);
50545604710SNamhyung Kim 	}
50686470930SIngo Molnar 
50745604710SNamhyung Kim out_child:
50845604710SNamhyung Kim 	if (forks) {
50945604710SNamhyung Kim 		int exit_status;
51045604710SNamhyung Kim 
51145604710SNamhyung Kim 		if (!child_finished)
51245604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
51345604710SNamhyung Kim 
51445604710SNamhyung Kim 		wait(&exit_status);
51545604710SNamhyung Kim 
51645604710SNamhyung Kim 		if (err < 0)
51745604710SNamhyung Kim 			status = err;
51845604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
51945604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
52045604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
52145604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
52245604710SNamhyung Kim 	} else
52345604710SNamhyung Kim 		status = err;
52445604710SNamhyung Kim 
52545604710SNamhyung Kim 	if (!err && !file->is_pipe) {
52645604710SNamhyung Kim 		rec->session->header.data_size += rec->bytes_written;
52745604710SNamhyung Kim 
52845604710SNamhyung Kim 		if (!rec->no_buildid)
52945604710SNamhyung Kim 			process_buildids(rec);
53045604710SNamhyung Kim 		perf_session__write_header(rec->session, rec->evlist,
53145604710SNamhyung Kim 					   file->fd, true);
53245604710SNamhyung Kim 	}
53339d17dacSArnaldo Carvalho de Melo 
53439d17dacSArnaldo Carvalho de Melo out_delete_session:
53539d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
53645604710SNamhyung Kim 	return status;
53786470930SIngo Molnar }
53886470930SIngo Molnar 
539bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
540bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
541bdfebd84SRoberto Agostino Vitillo 
542bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
543bdfebd84SRoberto Agostino Vitillo 
544bdfebd84SRoberto Agostino Vitillo struct branch_mode {
545bdfebd84SRoberto Agostino Vitillo 	const char *name;
546bdfebd84SRoberto Agostino Vitillo 	int mode;
547bdfebd84SRoberto Agostino Vitillo };
548bdfebd84SRoberto Agostino Vitillo 
549bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
550bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
551bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
552bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
553bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
554bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
555bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
556bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
5570126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
5580126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
5590126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
5600fffa5dfSAnshuman Khandual 	BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
561bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
562bdfebd84SRoberto Agostino Vitillo };
563bdfebd84SRoberto Agostino Vitillo 
564bdfebd84SRoberto Agostino Vitillo static int
565a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
566bdfebd84SRoberto Agostino Vitillo {
567bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
568bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
569bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
570bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
571bdfebd84SRoberto Agostino Vitillo 
572bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
573bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
574a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
575bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
576bdfebd84SRoberto Agostino Vitillo 
577a5aabdacSStephane Eranian 	if (unset)
578a5aabdacSStephane Eranian 		return 0;
579bdfebd84SRoberto Agostino Vitillo 
580a5aabdacSStephane Eranian 	/*
581a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
582a5aabdacSStephane Eranian 	 */
583a5aabdacSStephane Eranian 	if (*mode)
584a5aabdacSStephane Eranian 		return -1;
585a5aabdacSStephane Eranian 
586a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
587a5aabdacSStephane Eranian 	if (str) {
588bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
589bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
590bdfebd84SRoberto Agostino Vitillo 		if (!s)
591bdfebd84SRoberto Agostino Vitillo 			return -1;
592bdfebd84SRoberto Agostino Vitillo 
593bdfebd84SRoberto Agostino Vitillo 		for (;;) {
594bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
595bdfebd84SRoberto Agostino Vitillo 			if (p)
596bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
597bdfebd84SRoberto Agostino Vitillo 
598bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
599bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
600bdfebd84SRoberto Agostino Vitillo 					break;
601bdfebd84SRoberto Agostino Vitillo 			}
602a5aabdacSStephane Eranian 			if (!br->name) {
603a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
604a5aabdacSStephane Eranian 					    " check man page\n", s);
605bdfebd84SRoberto Agostino Vitillo 				goto error;
606a5aabdacSStephane Eranian 			}
607bdfebd84SRoberto Agostino Vitillo 
608bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
609bdfebd84SRoberto Agostino Vitillo 
610bdfebd84SRoberto Agostino Vitillo 			if (!p)
611bdfebd84SRoberto Agostino Vitillo 				break;
612bdfebd84SRoberto Agostino Vitillo 
613bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
614bdfebd84SRoberto Agostino Vitillo 		}
615a5aabdacSStephane Eranian 	}
616bdfebd84SRoberto Agostino Vitillo 	ret = 0;
617bdfebd84SRoberto Agostino Vitillo 
618a5aabdacSStephane Eranian 	/* default to any branch */
619bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
620a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
621bdfebd84SRoberto Agostino Vitillo 	}
622bdfebd84SRoberto Agostino Vitillo error:
623bdfebd84SRoberto Agostino Vitillo 	free(os);
624bdfebd84SRoberto Agostino Vitillo 	return ret;
625bdfebd84SRoberto Agostino Vitillo }
626bdfebd84SRoberto Agostino Vitillo 
62772a128aaSNamhyung Kim static void callchain_debug(void)
62809b0fd45SJiri Olsa {
629a601fdffSJiri Olsa 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
630a601fdffSJiri Olsa 
63172a128aaSNamhyung Kim 	pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
63226d33022SJiri Olsa 
63372a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_DWARF)
63409b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
63572a128aaSNamhyung Kim 			 callchain_param.dump_size);
63609b0fd45SJiri Olsa }
63709b0fd45SJiri Olsa 
63872a128aaSNamhyung Kim int record_parse_callchain_opt(const struct option *opt __maybe_unused,
63909b0fd45SJiri Olsa 			       const char *arg,
64009b0fd45SJiri Olsa 			       int unset)
64109b0fd45SJiri Olsa {
64209b0fd45SJiri Olsa 	int ret;
64309b0fd45SJiri Olsa 
64472a128aaSNamhyung Kim 	callchain_param.enabled = !unset;
645eb853e80SJiri Olsa 
64609b0fd45SJiri Olsa 	/* --no-call-graph */
64709b0fd45SJiri Olsa 	if (unset) {
64872a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_NONE;
64909b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
65009b0fd45SJiri Olsa 		return 0;
65109b0fd45SJiri Olsa 	}
65209b0fd45SJiri Olsa 
653f7f084f4SNamhyung Kim 	ret = parse_callchain_record_opt(arg);
65409b0fd45SJiri Olsa 	if (!ret)
65572a128aaSNamhyung Kim 		callchain_debug();
65609b0fd45SJiri Olsa 
65726d33022SJiri Olsa 	return ret;
65826d33022SJiri Olsa }
65926d33022SJiri Olsa 
66072a128aaSNamhyung Kim int record_callchain_opt(const struct option *opt __maybe_unused,
66109b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
66209b0fd45SJiri Olsa 			 int unset __maybe_unused)
66309b0fd45SJiri Olsa {
66472a128aaSNamhyung Kim 	callchain_param.enabled = true;
66509b0fd45SJiri Olsa 
66672a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_NONE)
66772a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_FP;
668eb853e80SJiri Olsa 
66972a128aaSNamhyung Kim 	callchain_debug();
67009b0fd45SJiri Olsa 	return 0;
67109b0fd45SJiri Olsa }
67209b0fd45SJiri Olsa 
673eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
674eb853e80SJiri Olsa {
675eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
676*5a2e5e85SNamhyung Kim 		var = "call-graph.record-mode"; /* fall-through */
677eb853e80SJiri Olsa 
678eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
679eb853e80SJiri Olsa }
680eb853e80SJiri Olsa 
68186470930SIngo Molnar static const char * const record_usage[] = {
68286470930SIngo Molnar 	"perf record [<options>] [<command>]",
68386470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
68486470930SIngo Molnar 	NULL
68586470930SIngo Molnar };
68686470930SIngo Molnar 
687d20deb64SArnaldo Carvalho de Melo /*
6888c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
6898c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
690d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
691d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
692d20deb64SArnaldo Carvalho de Melo  *
693d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
694d20deb64SArnaldo Carvalho de Melo  *
695d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
696d20deb64SArnaldo Carvalho de Melo  */
6978c6f45a7SArnaldo Carvalho de Melo static struct record record = {
698d20deb64SArnaldo Carvalho de Melo 	.opts = {
6998affc2b8SAndi Kleen 		.sample_time	     = true,
700d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
701d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
702d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
703447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
704d1cb9fceSNamhyung Kim 		.target		     = {
705d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
7063aa5939dSAdrian Hunter 			.default_per_cpu = true,
707d1cb9fceSNamhyung Kim 		},
708d20deb64SArnaldo Carvalho de Melo 	},
709d20deb64SArnaldo Carvalho de Melo };
7107865e817SFrederic Weisbecker 
71109b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
71261eaa3beSArnaldo Carvalho de Melo 
7139ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
71409b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
71561eaa3beSArnaldo Carvalho de Melo #else
71609b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp";
71761eaa3beSArnaldo Carvalho de Melo #endif
71861eaa3beSArnaldo Carvalho de Melo 
719d20deb64SArnaldo Carvalho de Melo /*
720d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
721d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
722b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
723d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
724d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
725d20deb64SArnaldo Carvalho de Melo  */
726bca647aaSTom Zanussi const struct option record_options[] = {
727d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
72886470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
729f120f9d5SJiri Olsa 		     parse_events_option),
730d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
731c171b552SLi Zefan 		     "event filter", parse_filter),
732bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
733d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
734bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
735d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
736d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
73786470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
738509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
739acac03faSKirill Smelkov 		    "collect data without buffering"),
740d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
741daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
742bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
74386470930SIngo Molnar 			    "system-wide collection from all CPUs"),
744bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
745c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
746d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
747f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
74886470930SIngo Molnar 		    "output file name"),
74969e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
75069e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
7512e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
752d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
753994a1f78SJiri Olsa 	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
754994a1f78SJiri Olsa 		     "number of mmap data pages",
755994a1f78SJiri Olsa 		     perf_evlist__parse_mmap_pages),
756d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
75743bece79SLin Ming 		    "put the counters into a counter group"),
75809b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
75909b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
76009b0fd45SJiri Olsa 			   &record_callchain_opt),
76109b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
76275d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
76309b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
764c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
7653da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
766b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
767d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
768649c48a9SPeter Zijlstra 		    "per thread counts"),
769d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
7704bba828dSAnton Blanchard 		    "Sample addresses"),
771d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
7723e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
773d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
774649c48a9SPeter Zijlstra 		    "don't sample"),
775d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
776a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
777d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
778baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
779d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
780023695d9SStephane Eranian 		     "monitor event in cgroup name only",
781023695d9SStephane Eranian 		     parse_cgroups),
782a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
7836619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
784bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
785bea03405SNamhyung Kim 		   "user to profile"),
786a5aabdacSStephane Eranian 
787a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
788a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
789a5aabdacSStephane Eranian 		     parse_branch_stack),
790a5aabdacSStephane Eranian 
791a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
792a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
793bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
79405484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
79505484298SAndi Kleen 		    "sample by weight (on special events only)"),
796475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
797475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
7983aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
7993aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
80086470930SIngo Molnar 	OPT_END()
80186470930SIngo Molnar };
80286470930SIngo Molnar 
8031d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
80486470930SIngo Molnar {
80569aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
8068c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
80716ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
80886470930SIngo Molnar 
8093e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
8103e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
811361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
812361c99a6SArnaldo Carvalho de Melo 
813eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
814eb853e80SJiri Olsa 
815bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
816a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
817602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
818bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
81986470930SIngo Molnar 
820bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
8213780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
822023695d9SStephane Eranian 			  " system-wide mode\n");
823023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
824023695d9SStephane Eranian 	}
825023695d9SStephane Eranian 
8260a7e6d1bSNamhyung Kim 	symbol__init(NULL);
827baa2f6ceSArnaldo Carvalho de Melo 
828ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
829646aaea6SArnaldo Carvalho de Melo 		pr_warning(
830646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
831ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
832646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
833646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
834646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
835646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
836646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
837ec80fde7SArnaldo Carvalho de Melo 
838d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
839a1ac1d3cSStephane Eranian 		disable_buildid_cache();
840655000e7SArnaldo Carvalho de Melo 
8413e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
8423e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
84369aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
84469aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
845bbd36e5eSPeter Zijlstra 	}
84686470930SIngo Molnar 
84769e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
84869e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
84969e7e5b0SAdrian Hunter 
850602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
85116ad2ffbSNamhyung Kim 	if (err) {
852602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
85316ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
85416ad2ffbSNamhyung Kim 	}
8554bd0f2d2SNamhyung Kim 
856602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
85716ad2ffbSNamhyung Kim 	if (err) {
85816ad2ffbSNamhyung Kim 		int saved_errno = errno;
85916ad2ffbSNamhyung Kim 
860602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
8613780f488SNamhyung Kim 		ui__error("%s", errbuf);
86216ad2ffbSNamhyung Kim 
86316ad2ffbSNamhyung Kim 		err = -saved_errno;
8648fa60e1fSNamhyung Kim 		goto out_symbol_exit;
86516ad2ffbSNamhyung Kim 	}
8660d37aa34SArnaldo Carvalho de Melo 
86716ad2ffbSNamhyung Kim 	err = -ENOMEM;
8683e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
869dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
87069aad6f1SArnaldo Carvalho de Melo 
871b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
87239d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
87303ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
8747e4ff9e3SMike Galbraith 	}
8757e4ff9e3SMike Galbraith 
876d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
877d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
87845604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
879d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
88039d17dacSArnaldo Carvalho de Melo 	return err;
88186470930SIngo Molnar }
882