xref: /openbmc/linux/tools/perf/builtin-record.c (revision b7b61cbebd789a3dbca522e3fdb727fe5c95593f)
186470930SIngo Molnar /*
286470930SIngo Molnar  * builtin-record.c
386470930SIngo Molnar  *
486470930SIngo Molnar  * Builtin record command: Record the profile of a workload
586470930SIngo Molnar  * (or a CPU, or a PID) into the perf.data output file - for
686470930SIngo Molnar  * later analysis via perf report.
786470930SIngo Molnar  */
886470930SIngo Molnar #include "builtin.h"
986470930SIngo Molnar 
1086470930SIngo Molnar #include "perf.h"
1186470930SIngo Molnar 
126122e4e4SArnaldo Carvalho de Melo #include "util/build-id.h"
1386470930SIngo Molnar #include "util/util.h"
1486470930SIngo Molnar #include "util/parse-options.h"
1586470930SIngo Molnar #include "util/parse-events.h"
1686470930SIngo Molnar 
178f651eaeSArnaldo Carvalho de Melo #include "util/callchain.h"
18f14d5707SArnaldo Carvalho de Melo #include "util/cgroup.h"
197c6a1c65SPeter Zijlstra #include "util/header.h"
2066e274f3SFrederic Weisbecker #include "util/event.h"
21361c99a6SArnaldo Carvalho de Melo #include "util/evlist.h"
2269aad6f1SArnaldo Carvalho de Melo #include "util/evsel.h"
238f28827aSFrederic Weisbecker #include "util/debug.h"
2494c744b6SArnaldo Carvalho de Melo #include "util/session.h"
2545694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
268d06367fSArnaldo Carvalho de Melo #include "util/symbol.h"
27a12b51c4SPaul Mackerras #include "util/cpumap.h"
28fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h"
29f5fc1412SJiri Olsa #include "util/data.h"
307c6a1c65SPeter Zijlstra 
3186470930SIngo Molnar #include <unistd.h>
3286470930SIngo Molnar #include <sched.h>
33a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3486470930SIngo Molnar 
3578da39faSBernhard Rosenkraenzer 
368c6f45a7SArnaldo Carvalho de Melo struct record {
3745694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
38b4006796SArnaldo Carvalho de Melo 	struct record_opts	opts;
39d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
40f5fc1412SJiri Olsa 	struct perf_data_file	file;
41d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
42d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
43d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
44d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
45d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
46d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
47d20deb64SArnaldo Carvalho de Melo 	long			samples;
480f82ebc4SArnaldo Carvalho de Melo };
4986470930SIngo Molnar 
508c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
51f5970550SPeter Zijlstra {
52cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
534f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
548d3eca20SDavid Ahern 		return -1;
558d3eca20SDavid Ahern 	}
56f5970550SPeter Zijlstra 
57cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
588d3eca20SDavid Ahern 	return 0;
59f5970550SPeter Zijlstra }
60f5970550SPeter Zijlstra 
6145694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
62d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
631d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
641d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
65234fbbf5SArnaldo Carvalho de Melo {
668c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
678c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
68234fbbf5SArnaldo Carvalho de Melo }
69234fbbf5SArnaldo Carvalho de Melo 
70e5685730SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, int idx)
7186470930SIngo Molnar {
72e5685730SArnaldo Carvalho de Melo 	struct perf_mmap *md = &rec->evlist->mmap[idx];
73744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
7486470930SIngo Molnar 	unsigned int old = md->prev;
75918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
7686470930SIngo Molnar 	unsigned long size;
7786470930SIngo Molnar 	void *buf;
788d3eca20SDavid Ahern 	int rc = 0;
7986470930SIngo Molnar 
80dc82009aSArnaldo Carvalho de Melo 	if (old == head)
818d3eca20SDavid Ahern 		return 0;
8286470930SIngo Molnar 
83d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
8486470930SIngo Molnar 
8586470930SIngo Molnar 	size = head - old;
8686470930SIngo Molnar 
8786470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
8886470930SIngo Molnar 		buf = &data[old & md->mask];
8986470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
9086470930SIngo Molnar 		old += size;
9186470930SIngo Molnar 
928c6f45a7SArnaldo Carvalho de Melo 		if (record__write(rec, buf, size) < 0) {
938d3eca20SDavid Ahern 			rc = -1;
948d3eca20SDavid Ahern 			goto out;
958d3eca20SDavid Ahern 		}
9686470930SIngo Molnar 	}
9786470930SIngo Molnar 
9886470930SIngo Molnar 	buf = &data[old & md->mask];
9986470930SIngo Molnar 	size = head - old;
10086470930SIngo Molnar 	old += size;
10186470930SIngo Molnar 
1028c6f45a7SArnaldo Carvalho de Melo 	if (record__write(rec, buf, size) < 0) {
1038d3eca20SDavid Ahern 		rc = -1;
1048d3eca20SDavid Ahern 		goto out;
1058d3eca20SDavid Ahern 	}
10686470930SIngo Molnar 
10786470930SIngo Molnar 	md->prev = old;
108e5685730SArnaldo Carvalho de Melo 	perf_evlist__mmap_consume(rec->evlist, idx);
1098d3eca20SDavid Ahern out:
1108d3eca20SDavid Ahern 	return rc;
11186470930SIngo Molnar }
11286470930SIngo Molnar 
11386470930SIngo Molnar static volatile int done = 0;
114f7b7c26eSPeter Zijlstra static volatile int signr = -1;
11533e49ea7SAndi Kleen static volatile int child_finished = 0;
11686470930SIngo Molnar 
11786470930SIngo Molnar static void sig_handler(int sig)
11886470930SIngo Molnar {
11933e49ea7SAndi Kleen 	if (sig == SIGCHLD)
12033e49ea7SAndi Kleen 		child_finished = 1;
12145604710SNamhyung Kim 	else
12245604710SNamhyung Kim 		signr = sig;
12333e49ea7SAndi Kleen 
12486470930SIngo Molnar 	done = 1;
125f7b7c26eSPeter Zijlstra }
126f7b7c26eSPeter Zijlstra 
12745604710SNamhyung Kim static void record__sig_exit(void)
128f7b7c26eSPeter Zijlstra {
12945604710SNamhyung Kim 	if (signr == -1)
130f7b7c26eSPeter Zijlstra 		return;
131f7b7c26eSPeter Zijlstra 
132f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
13345604710SNamhyung Kim 	raise(signr);
13486470930SIngo Molnar }
13586470930SIngo Molnar 
1368c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
137dd7927f4SArnaldo Carvalho de Melo {
13856e52e85SArnaldo Carvalho de Melo 	char msg[512];
1396a4bb04cSJiri Olsa 	struct perf_evsel *pos;
140d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
141d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
142b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
1438d3eca20SDavid Ahern 	int rc = 0;
144dd7927f4SArnaldo Carvalho de Melo 
145f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
146cac21425SJiri Olsa 
1470050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
1483da297a6SIngo Molnar try_again:
1496a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
15056e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
1513da297a6SIngo Molnar 				if (verbose)
152c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
1533da297a6SIngo Molnar 				goto try_again;
1543da297a6SIngo Molnar 			}
155ca6a4258SDavid Ahern 
15656e52e85SArnaldo Carvalho de Melo 			rc = -errno;
15756e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
15856e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
15956e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
1608d3eca20SDavid Ahern 			goto out;
1617c6a1c65SPeter Zijlstra 		}
1627c6a1c65SPeter Zijlstra 	}
1637c6a1c65SPeter Zijlstra 
1641491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
1650a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
16635550da3SMasami Hiramatsu 			strerror_r(errno, msg, sizeof(msg)));
1678d3eca20SDavid Ahern 		rc = -1;
1688d3eca20SDavid Ahern 		goto out;
1690a102479SFrederic Weisbecker 	}
1700a102479SFrederic Weisbecker 
17118e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
1728d3eca20SDavid Ahern 		if (errno == EPERM) {
1738d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
17418e60939SNelson Elhage 			       "Consider increasing "
17518e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
17618e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
17753653d70SAdrian Hunter 			       "(current value: %u)\n", opts->mmap_pages);
1788d3eca20SDavid Ahern 			rc = -errno;
1798d3eca20SDavid Ahern 		} else {
18035550da3SMasami Hiramatsu 			pr_err("failed to mmap with %d (%s)\n", errno,
18135550da3SMasami Hiramatsu 				strerror_r(errno, msg, sizeof(msg)));
1828d3eca20SDavid Ahern 			rc = -errno;
1838d3eca20SDavid Ahern 		}
1848d3eca20SDavid Ahern 		goto out;
18518e60939SNelson Elhage 	}
1860a27d7f9SArnaldo Carvalho de Melo 
187a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
1887b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
1898d3eca20SDavid Ahern out:
1908d3eca20SDavid Ahern 	return rc;
191a91e5431SArnaldo Carvalho de Melo }
192a91e5431SArnaldo Carvalho de Melo 
193e3d59112SNamhyung Kim static int process_sample_event(struct perf_tool *tool,
194e3d59112SNamhyung Kim 				union perf_event *event,
195e3d59112SNamhyung Kim 				struct perf_sample *sample,
196e3d59112SNamhyung Kim 				struct perf_evsel *evsel,
197e3d59112SNamhyung Kim 				struct machine *machine)
198e3d59112SNamhyung Kim {
199e3d59112SNamhyung Kim 	struct record *rec = container_of(tool, struct record, tool);
200e3d59112SNamhyung Kim 
201e3d59112SNamhyung Kim 	rec->samples++;
202e3d59112SNamhyung Kim 
203e3d59112SNamhyung Kim 	return build_id__mark_dso_hit(tool, event, sample, evsel, machine);
204e3d59112SNamhyung Kim }
205e3d59112SNamhyung Kim 
2068c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
2076122e4e4SArnaldo Carvalho de Melo {
208f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
209f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
2106122e4e4SArnaldo Carvalho de Melo 
21142aa276fSNamhyung Kim 	u64 size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
2129f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2139f591fd7SArnaldo Carvalho de Melo 		return 0;
2149f591fd7SArnaldo Carvalho de Melo 
2154ac30cf7SNamhyung Kim 	file->size = size;
2164ac30cf7SNamhyung Kim 
21700dc8657SNamhyung Kim 	/*
21800dc8657SNamhyung Kim 	 * During this process, it'll load kernel map and replace the
21900dc8657SNamhyung Kim 	 * dso->long_name to a real pathname it found.  In this case
22000dc8657SNamhyung Kim 	 * we prefer the vmlinux path like
22100dc8657SNamhyung Kim 	 *   /lib/modules/3.16.4/build/vmlinux
22200dc8657SNamhyung Kim 	 *
22300dc8657SNamhyung Kim 	 * rather than build-id path (in debug directory).
22400dc8657SNamhyung Kim 	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
22500dc8657SNamhyung Kim 	 */
22600dc8657SNamhyung Kim 	symbol_conf.ignore_vmlinux_buildid = true;
22700dc8657SNamhyung Kim 
228*b7b61cbeSArnaldo Carvalho de Melo 	return perf_session__process_events(session);
2296122e4e4SArnaldo Carvalho de Melo }
2306122e4e4SArnaldo Carvalho de Melo 
2318115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
232a1645ce1SZhang, Yanmin {
233a1645ce1SZhang, Yanmin 	int err;
23445694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
235a1645ce1SZhang, Yanmin 	/*
236a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
237a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
238a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
239a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
240a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
241a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
242a1645ce1SZhang, Yanmin 	 */
24345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
244743eb868SArnaldo Carvalho de Melo 					     machine);
245a1645ce1SZhang, Yanmin 	if (err < 0)
246a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
24723346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
248a1645ce1SZhang, Yanmin 
249a1645ce1SZhang, Yanmin 	/*
250a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
251a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
252a1645ce1SZhang, Yanmin 	 */
25345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
2540ae617beSAdrian Hunter 						 machine);
255a1645ce1SZhang, Yanmin 	if (err < 0)
256a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
25723346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
258a1645ce1SZhang, Yanmin }
259a1645ce1SZhang, Yanmin 
26098402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
26198402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
26298402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
26398402807SFrederic Weisbecker };
26498402807SFrederic Weisbecker 
2658c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
26698402807SFrederic Weisbecker {
267dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
2680e2e63ddSPeter Zijlstra 	int i;
2698d3eca20SDavid Ahern 	int rc = 0;
27098402807SFrederic Weisbecker 
271d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
2728d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
273e5685730SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, i) != 0) {
2748d3eca20SDavid Ahern 				rc = -1;
2758d3eca20SDavid Ahern 				goto out;
2768d3eca20SDavid Ahern 			}
2778d3eca20SDavid Ahern 		}
27898402807SFrederic Weisbecker 	}
27998402807SFrederic Weisbecker 
280dcabb507SJiri Olsa 	/*
281dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
282dcabb507SJiri Olsa 	 * at least one event.
283dcabb507SJiri Olsa 	 */
284dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
2858c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
2868d3eca20SDavid Ahern 
2878d3eca20SDavid Ahern out:
2888d3eca20SDavid Ahern 	return rc;
28998402807SFrederic Weisbecker }
29098402807SFrederic Weisbecker 
2918c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
29257706abcSDavid Ahern {
29357706abcSDavid Ahern 	struct perf_session *session = rec->session;
29457706abcSDavid Ahern 	int feat;
29557706abcSDavid Ahern 
29657706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
29757706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
29857706abcSDavid Ahern 
29957706abcSDavid Ahern 	if (rec->no_buildid)
30057706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
30157706abcSDavid Ahern 
3023e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
30357706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
30457706abcSDavid Ahern 
30557706abcSDavid Ahern 	if (!rec->opts.branch_stack)
30657706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
30757706abcSDavid Ahern }
30857706abcSDavid Ahern 
309f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
310f33cbe72SArnaldo Carvalho de Melo 
311f33cbe72SArnaldo Carvalho de Melo /*
312f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
313f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
314f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
315f33cbe72SArnaldo Carvalho de Melo  */
31645604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
31745604710SNamhyung Kim 					siginfo_t *info,
318f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
319f33cbe72SArnaldo Carvalho de Melo {
320f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
321f33cbe72SArnaldo Carvalho de Melo 	done = 1;
322f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
323f33cbe72SArnaldo Carvalho de Melo }
324f33cbe72SArnaldo Carvalho de Melo 
3258c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
32686470930SIngo Molnar {
32757706abcSDavid Ahern 	int err;
32845604710SNamhyung Kim 	int status = 0;
3298b412664SPeter Zijlstra 	unsigned long waking = 0;
33046be604bSZhang, Yanmin 	const bool forks = argc > 0;
33123346f21SArnaldo Carvalho de Melo 	struct machine *machine;
33245694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
333b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
334f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
335d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3366dcf45efSArnaldo Carvalho de Melo 	bool disabled = false, draining = false;
33742aa276fSNamhyung Kim 	int fd;
33886470930SIngo Molnar 
339d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
34033e49ea7SAndi Kleen 
34145604710SNamhyung Kim 	atexit(record__sig_exit);
342f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
343f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
344804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
345f5970550SPeter Zijlstra 
346*b7b61cbeSArnaldo Carvalho de Melo 	session = perf_session__new(file, false, tool);
34794c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
348ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
349a9a70bbcSArnaldo Carvalho de Melo 		return -1;
350a9a70bbcSArnaldo Carvalho de Melo 	}
351a9a70bbcSArnaldo Carvalho de Melo 
35242aa276fSNamhyung Kim 	fd = perf_data_file__fd(file);
353d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
354d20deb64SArnaldo Carvalho de Melo 
3558c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
356330aa675SStephane Eranian 
357d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
3583e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
359f5fc1412SJiri Olsa 						    argv, file->is_pipe,
360735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
36135b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
36235b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
36345604710SNamhyung Kim 			status = err;
36435b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
365856e9660SPeter Zijlstra 		}
366856e9660SPeter Zijlstra 	}
367856e9660SPeter Zijlstra 
3688c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
3698d3eca20SDavid Ahern 		err = -1;
37045604710SNamhyung Kim 		goto out_child;
3718d3eca20SDavid Ahern 	}
37286470930SIngo Molnar 
3733e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
374a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
375a8bb559bSNamhyung Kim 
376f5fc1412SJiri Olsa 	if (file->is_pipe) {
37742aa276fSNamhyung Kim 		err = perf_header__write_pipe(fd);
378529870e3STom Zanussi 		if (err < 0)
37945604710SNamhyung Kim 			goto out_child;
380563aecb2SJiri Olsa 	} else {
38142aa276fSNamhyung Kim 		err = perf_session__write_header(session, rec->evlist, fd, false);
382d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
38345604710SNamhyung Kim 			goto out_child;
384d5eed904SArnaldo Carvalho de Melo 	}
3857c6a1c65SPeter Zijlstra 
386d3665498SDavid Ahern 	if (!rec->no_buildid
387e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
388d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
389e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
3908d3eca20SDavid Ahern 		err = -1;
39145604710SNamhyung Kim 		goto out_child;
392e20960c0SRobert Richter 	}
393e20960c0SRobert Richter 
39434ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
395743eb868SArnaldo Carvalho de Melo 
396f5fc1412SJiri Olsa 	if (file->is_pipe) {
39745694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
398a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
3992c46dbb5STom Zanussi 		if (err < 0) {
4002c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
40145604710SNamhyung Kim 			goto out_child;
4022c46dbb5STom Zanussi 		}
403cd19a035STom Zanussi 
4043e2be2daSArnaldo Carvalho de Melo 		if (have_tracepoints(&rec->evlist->entries)) {
40563e0c771STom Zanussi 			/*
40663e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
40763e0c771STom Zanussi 			 * there were no tracepoints so its not really
40863e0c771STom Zanussi 			 * an error, just that we don't need to
40963e0c771STom Zanussi 			 * synthesize anything.  We really have to
41063e0c771STom Zanussi 			 * return this more properly and also
41163e0c771STom Zanussi 			 * propagate errors that now are calling die()
41263e0c771STom Zanussi 			 */
41342aa276fSNamhyung Kim 			err = perf_event__synthesize_tracing_data(tool,	fd, rec->evlist,
414743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
41563e0c771STom Zanussi 			if (err <= 0) {
41663e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
41745604710SNamhyung Kim 				goto out_child;
41863e0c771STom Zanussi 			}
419f34b9001SDavid Ahern 			rec->bytes_written += err;
4202c46dbb5STom Zanussi 		}
42163e0c771STom Zanussi 	}
4222c46dbb5STom Zanussi 
42345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
4240ae617beSAdrian Hunter 						 machine);
425c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
426c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
427c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
428c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
42956b03f3cSArnaldo Carvalho de Melo 
43045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
431743eb868SArnaldo Carvalho de Melo 					     machine);
432c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
433c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
434c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
435c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
436c1a3a4b9SArnaldo Carvalho de Melo 
4377e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
438876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
4397e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
4407e383de4SArnaldo Carvalho de Melo 	}
441b7cece76SArnaldo Carvalho de Melo 
4423e2be2daSArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
44358d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
4448d3eca20SDavid Ahern 	if (err != 0)
44545604710SNamhyung Kim 		goto out_child;
4468d3eca20SDavid Ahern 
447d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
44886470930SIngo Molnar 		struct sched_param param;
44986470930SIngo Molnar 
450d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
45186470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
4526beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
4538d3eca20SDavid Ahern 			err = -1;
45445604710SNamhyung Kim 			goto out_child;
45586470930SIngo Molnar 		}
45686470930SIngo Molnar 	}
45786470930SIngo Molnar 
458774cb499SJiri Olsa 	/*
459774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
460774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
461774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
462774cb499SJiri Olsa 	 */
4636619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
4643e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
465764e16a3SDavid Ahern 
466856e9660SPeter Zijlstra 	/*
467856e9660SPeter Zijlstra 	 * Let the child rip
468856e9660SPeter Zijlstra 	 */
469735f7e0bSArnaldo Carvalho de Melo 	if (forks)
4703e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
471856e9660SPeter Zijlstra 
4726619a53eSAndi Kleen 	if (opts->initial_delay) {
4736619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
4746619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
4756619a53eSAndi Kleen 	}
4766619a53eSAndi Kleen 
477649c48a9SPeter Zijlstra 	for (;;) {
478d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
47986470930SIngo Molnar 
4808c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
4818d3eca20SDavid Ahern 			err = -1;
48245604710SNamhyung Kim 			goto out_child;
4838d3eca20SDavid Ahern 		}
48486470930SIngo Molnar 
485d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
4866dcf45efSArnaldo Carvalho de Melo 			if (done || draining)
487649c48a9SPeter Zijlstra 				break;
488f66a889dSArnaldo Carvalho de Melo 			err = perf_evlist__poll(rec->evlist, -1);
489a515114fSJiri Olsa 			/*
490a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
491a515114fSJiri Olsa 			 * number of returned events and interrupt error.
492a515114fSJiri Olsa 			 */
493a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
49445604710SNamhyung Kim 				err = 0;
4958b412664SPeter Zijlstra 			waking++;
4966dcf45efSArnaldo Carvalho de Melo 
4976dcf45efSArnaldo Carvalho de Melo 			if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
4986dcf45efSArnaldo Carvalho de Melo 				draining = true;
4998b412664SPeter Zijlstra 		}
5008b412664SPeter Zijlstra 
501774cb499SJiri Olsa 		/*
502774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
503774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
504774cb499SJiri Olsa 		 * disable events in this case.
505774cb499SJiri Olsa 		 */
506602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
5073e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
5082711926aSJiri Olsa 			disabled = true;
5092711926aSJiri Olsa 		}
5108b412664SPeter Zijlstra 	}
5118b412664SPeter Zijlstra 
512f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
51335550da3SMasami Hiramatsu 		char msg[STRERR_BUFSIZE];
514f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
515f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
516f33cbe72SArnaldo Carvalho de Melo 		err = -1;
51745604710SNamhyung Kim 		goto out_child;
518f33cbe72SArnaldo Carvalho de Melo 	}
519f33cbe72SArnaldo Carvalho de Melo 
520e3d59112SNamhyung Kim 	if (!quiet)
5218b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
52286470930SIngo Molnar 
52345604710SNamhyung Kim out_child:
52445604710SNamhyung Kim 	if (forks) {
52545604710SNamhyung Kim 		int exit_status;
52645604710SNamhyung Kim 
52745604710SNamhyung Kim 		if (!child_finished)
52845604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
52945604710SNamhyung Kim 
53045604710SNamhyung Kim 		wait(&exit_status);
53145604710SNamhyung Kim 
53245604710SNamhyung Kim 		if (err < 0)
53345604710SNamhyung Kim 			status = err;
53445604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
53545604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
53645604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
53745604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
53845604710SNamhyung Kim 	} else
53945604710SNamhyung Kim 		status = err;
54045604710SNamhyung Kim 
541e3d59112SNamhyung Kim 	/* this will be recalculated during process_buildids() */
542e3d59112SNamhyung Kim 	rec->samples = 0;
543e3d59112SNamhyung Kim 
54445604710SNamhyung Kim 	if (!err && !file->is_pipe) {
54545604710SNamhyung Kim 		rec->session->header.data_size += rec->bytes_written;
54645604710SNamhyung Kim 
54745604710SNamhyung Kim 		if (!rec->no_buildid)
54845604710SNamhyung Kim 			process_buildids(rec);
54942aa276fSNamhyung Kim 		perf_session__write_header(rec->session, rec->evlist, fd, true);
55045604710SNamhyung Kim 	}
55139d17dacSArnaldo Carvalho de Melo 
552e3d59112SNamhyung Kim 	if (!err && !quiet) {
553e3d59112SNamhyung Kim 		char samples[128];
554e3d59112SNamhyung Kim 
555e3d59112SNamhyung Kim 		if (rec->samples)
556e3d59112SNamhyung Kim 			scnprintf(samples, sizeof(samples),
557e3d59112SNamhyung Kim 				  " (%" PRIu64 " samples)", rec->samples);
558e3d59112SNamhyung Kim 		else
559e3d59112SNamhyung Kim 			samples[0] = '\0';
560e3d59112SNamhyung Kim 
561e3d59112SNamhyung Kim 		fprintf(stderr,	"[ perf record: Captured and wrote %.3f MB %s%s ]\n",
562e3d59112SNamhyung Kim 			perf_data_file__size(file) / 1024.0 / 1024.0,
563e3d59112SNamhyung Kim 			file->path, samples);
564e3d59112SNamhyung Kim 	}
565e3d59112SNamhyung Kim 
56639d17dacSArnaldo Carvalho de Melo out_delete_session:
56739d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
56845604710SNamhyung Kim 	return status;
56986470930SIngo Molnar }
57086470930SIngo Molnar 
571bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
572bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
573bdfebd84SRoberto Agostino Vitillo 
574bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
575bdfebd84SRoberto Agostino Vitillo 
576bdfebd84SRoberto Agostino Vitillo struct branch_mode {
577bdfebd84SRoberto Agostino Vitillo 	const char *name;
578bdfebd84SRoberto Agostino Vitillo 	int mode;
579bdfebd84SRoberto Agostino Vitillo };
580bdfebd84SRoberto Agostino Vitillo 
581bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
582bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
583bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
584bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
585bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
586bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
587bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
588bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
5890126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
5900126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
5910126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
5920fffa5dfSAnshuman Khandual 	BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
593bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
594bdfebd84SRoberto Agostino Vitillo };
595bdfebd84SRoberto Agostino Vitillo 
596bdfebd84SRoberto Agostino Vitillo static int
597a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
598bdfebd84SRoberto Agostino Vitillo {
599bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
600bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
601bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
602bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
603bdfebd84SRoberto Agostino Vitillo 
604bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
605bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
606a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
607bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
608bdfebd84SRoberto Agostino Vitillo 
609a5aabdacSStephane Eranian 	if (unset)
610a5aabdacSStephane Eranian 		return 0;
611bdfebd84SRoberto Agostino Vitillo 
612a5aabdacSStephane Eranian 	/*
613a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
614a5aabdacSStephane Eranian 	 */
615a5aabdacSStephane Eranian 	if (*mode)
616a5aabdacSStephane Eranian 		return -1;
617a5aabdacSStephane Eranian 
618a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
619a5aabdacSStephane Eranian 	if (str) {
620bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
621bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
622bdfebd84SRoberto Agostino Vitillo 		if (!s)
623bdfebd84SRoberto Agostino Vitillo 			return -1;
624bdfebd84SRoberto Agostino Vitillo 
625bdfebd84SRoberto Agostino Vitillo 		for (;;) {
626bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
627bdfebd84SRoberto Agostino Vitillo 			if (p)
628bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
629bdfebd84SRoberto Agostino Vitillo 
630bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
631bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
632bdfebd84SRoberto Agostino Vitillo 					break;
633bdfebd84SRoberto Agostino Vitillo 			}
634a5aabdacSStephane Eranian 			if (!br->name) {
635a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
636a5aabdacSStephane Eranian 					    " check man page\n", s);
637bdfebd84SRoberto Agostino Vitillo 				goto error;
638a5aabdacSStephane Eranian 			}
639bdfebd84SRoberto Agostino Vitillo 
640bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
641bdfebd84SRoberto Agostino Vitillo 
642bdfebd84SRoberto Agostino Vitillo 			if (!p)
643bdfebd84SRoberto Agostino Vitillo 				break;
644bdfebd84SRoberto Agostino Vitillo 
645bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
646bdfebd84SRoberto Agostino Vitillo 		}
647a5aabdacSStephane Eranian 	}
648bdfebd84SRoberto Agostino Vitillo 	ret = 0;
649bdfebd84SRoberto Agostino Vitillo 
650a5aabdacSStephane Eranian 	/* default to any branch */
651bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
652a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
653bdfebd84SRoberto Agostino Vitillo 	}
654bdfebd84SRoberto Agostino Vitillo error:
655bdfebd84SRoberto Agostino Vitillo 	free(os);
656bdfebd84SRoberto Agostino Vitillo 	return ret;
657bdfebd84SRoberto Agostino Vitillo }
658bdfebd84SRoberto Agostino Vitillo 
65972a128aaSNamhyung Kim static void callchain_debug(void)
66009b0fd45SJiri Olsa {
661aad2b21cSKan Liang 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" };
662a601fdffSJiri Olsa 
66372a128aaSNamhyung Kim 	pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
66426d33022SJiri Olsa 
66572a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_DWARF)
66609b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
66772a128aaSNamhyung Kim 			 callchain_param.dump_size);
66809b0fd45SJiri Olsa }
66909b0fd45SJiri Olsa 
67072a128aaSNamhyung Kim int record_parse_callchain_opt(const struct option *opt __maybe_unused,
67109b0fd45SJiri Olsa 			       const char *arg,
67209b0fd45SJiri Olsa 			       int unset)
67309b0fd45SJiri Olsa {
67409b0fd45SJiri Olsa 	int ret;
67509b0fd45SJiri Olsa 
67672a128aaSNamhyung Kim 	callchain_param.enabled = !unset;
677eb853e80SJiri Olsa 
67809b0fd45SJiri Olsa 	/* --no-call-graph */
67909b0fd45SJiri Olsa 	if (unset) {
68072a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_NONE;
68109b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
68209b0fd45SJiri Olsa 		return 0;
68309b0fd45SJiri Olsa 	}
68409b0fd45SJiri Olsa 
685f7f084f4SNamhyung Kim 	ret = parse_callchain_record_opt(arg);
68609b0fd45SJiri Olsa 	if (!ret)
68772a128aaSNamhyung Kim 		callchain_debug();
68809b0fd45SJiri Olsa 
68926d33022SJiri Olsa 	return ret;
69026d33022SJiri Olsa }
69126d33022SJiri Olsa 
69272a128aaSNamhyung Kim int record_callchain_opt(const struct option *opt __maybe_unused,
69309b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
69409b0fd45SJiri Olsa 			 int unset __maybe_unused)
69509b0fd45SJiri Olsa {
69672a128aaSNamhyung Kim 	callchain_param.enabled = true;
69709b0fd45SJiri Olsa 
69872a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_NONE)
69972a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_FP;
700eb853e80SJiri Olsa 
70172a128aaSNamhyung Kim 	callchain_debug();
70209b0fd45SJiri Olsa 	return 0;
70309b0fd45SJiri Olsa }
70409b0fd45SJiri Olsa 
705eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
706eb853e80SJiri Olsa {
707eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
7085a2e5e85SNamhyung Kim 		var = "call-graph.record-mode"; /* fall-through */
709eb853e80SJiri Olsa 
710eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
711eb853e80SJiri Olsa }
712eb853e80SJiri Olsa 
713e5b2c207SNamhyung Kim static const char * const __record_usage[] = {
71486470930SIngo Molnar 	"perf record [<options>] [<command>]",
71586470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
71686470930SIngo Molnar 	NULL
71786470930SIngo Molnar };
718e5b2c207SNamhyung Kim const char * const *record_usage = __record_usage;
71986470930SIngo Molnar 
720d20deb64SArnaldo Carvalho de Melo /*
7218c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
7228c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
723d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
724d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
725d20deb64SArnaldo Carvalho de Melo  *
726d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
727d20deb64SArnaldo Carvalho de Melo  *
728d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
729d20deb64SArnaldo Carvalho de Melo  */
7308c6f45a7SArnaldo Carvalho de Melo static struct record record = {
731d20deb64SArnaldo Carvalho de Melo 	.opts = {
7328affc2b8SAndi Kleen 		.sample_time	     = true,
733d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
734d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
735d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
736447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
737d1cb9fceSNamhyung Kim 		.target		     = {
738d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
7393aa5939dSAdrian Hunter 			.default_per_cpu = true,
740d1cb9fceSNamhyung Kim 		},
741d20deb64SArnaldo Carvalho de Melo 	},
742e3d59112SNamhyung Kim 	.tool = {
743e3d59112SNamhyung Kim 		.sample		= process_sample_event,
744e3d59112SNamhyung Kim 		.fork		= perf_event__process_fork,
745e3d59112SNamhyung Kim 		.comm		= perf_event__process_comm,
746e3d59112SNamhyung Kim 		.mmap		= perf_event__process_mmap,
747e3d59112SNamhyung Kim 		.mmap2		= perf_event__process_mmap2,
748e3d59112SNamhyung Kim 	},
749d20deb64SArnaldo Carvalho de Melo };
7507865e817SFrederic Weisbecker 
75109b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
75261eaa3beSArnaldo Carvalho de Melo 
7539ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
754aad2b21cSKan Liang const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf lbr";
75561eaa3beSArnaldo Carvalho de Melo #else
756aad2b21cSKan Liang const char record_callchain_help[] = CALLCHAIN_HELP "fp lbr";
75761eaa3beSArnaldo Carvalho de Melo #endif
75861eaa3beSArnaldo Carvalho de Melo 
759d20deb64SArnaldo Carvalho de Melo /*
760d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
761d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
762b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
763d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
764d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
765d20deb64SArnaldo Carvalho de Melo  */
766e5b2c207SNamhyung Kim struct option __record_options[] = {
767d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
76886470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
769f120f9d5SJiri Olsa 		     parse_events_option),
770d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
771c171b552SLi Zefan 		     "event filter", parse_filter),
772bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
773d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
774bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
775d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
776d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
77786470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
778509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
779acac03faSKirill Smelkov 		    "collect data without buffering"),
780d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
781daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
782bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
78386470930SIngo Molnar 			    "system-wide collection from all CPUs"),
784bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
785c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
786d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
787f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
78886470930SIngo Molnar 		    "output file name"),
78969e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
79069e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
7912e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
792d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
793994a1f78SJiri Olsa 	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
794994a1f78SJiri Olsa 		     "number of mmap data pages",
795994a1f78SJiri Olsa 		     perf_evlist__parse_mmap_pages),
796d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
79743bece79SLin Ming 		    "put the counters into a counter group"),
79809b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
79909b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
80009b0fd45SJiri Olsa 			   &record_callchain_opt),
80109b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
80275d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
80309b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
804c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8053da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
806b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
807d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
808649c48a9SPeter Zijlstra 		    "per thread counts"),
809d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8104bba828dSAnton Blanchard 		    "Sample addresses"),
811d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8123e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
813d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
814649c48a9SPeter Zijlstra 		    "don't sample"),
815d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
816a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
817d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
818baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
819d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
820023695d9SStephane Eranian 		     "monitor event in cgroup name only",
821023695d9SStephane Eranian 		     parse_cgroups),
822a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
8236619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
824bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
825bea03405SNamhyung Kim 		   "user to profile"),
826a5aabdacSStephane Eranian 
827a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
828a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
829a5aabdacSStephane Eranian 		     parse_branch_stack),
830a5aabdacSStephane Eranian 
831a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
832a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
833bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
83405484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
83505484298SAndi Kleen 		    "sample by weight (on special events only)"),
836475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
837475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
8383aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
8393aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
8404b6c5177SStephane Eranian 	OPT_BOOLEAN('I', "intr-regs", &record.opts.sample_intr_regs,
8414b6c5177SStephane Eranian 		    "Sample machine registers on interrupt"),
84285c273d2SAndi Kleen 	OPT_BOOLEAN(0, "running-time", &record.opts.running_time,
84385c273d2SAndi Kleen 		    "Record running/enabled time of read (:S) events"),
84486470930SIngo Molnar 	OPT_END()
84586470930SIngo Molnar };
84686470930SIngo Molnar 
847e5b2c207SNamhyung Kim struct option *record_options = __record_options;
848e5b2c207SNamhyung Kim 
8491d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
85086470930SIngo Molnar {
85169aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
8528c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
85316ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
85486470930SIngo Molnar 
8553e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
8563e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
857361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
858361c99a6SArnaldo Carvalho de Melo 
859eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
860eb853e80SJiri Olsa 
861bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
862a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
863602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
864bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
86586470930SIngo Molnar 
866bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
8673780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
868023695d9SStephane Eranian 			  " system-wide mode\n");
869023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
870023695d9SStephane Eranian 	}
871023695d9SStephane Eranian 
8720a7e6d1bSNamhyung Kim 	symbol__init(NULL);
873baa2f6ceSArnaldo Carvalho de Melo 
874ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
875646aaea6SArnaldo Carvalho de Melo 		pr_warning(
876646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
877ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
878646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
879646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
880646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
881646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
882646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
883ec80fde7SArnaldo Carvalho de Melo 
884d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
885a1ac1d3cSStephane Eranian 		disable_buildid_cache();
886655000e7SArnaldo Carvalho de Melo 
8873e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
8883e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
88969aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
89069aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
891bbd36e5eSPeter Zijlstra 	}
89286470930SIngo Molnar 
89369e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
89469e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
89569e7e5b0SAdrian Hunter 
896602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
89716ad2ffbSNamhyung Kim 	if (err) {
898602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
89916ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
90016ad2ffbSNamhyung Kim 	}
9014bd0f2d2SNamhyung Kim 
902602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
90316ad2ffbSNamhyung Kim 	if (err) {
90416ad2ffbSNamhyung Kim 		int saved_errno = errno;
90516ad2ffbSNamhyung Kim 
906602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9073780f488SNamhyung Kim 		ui__error("%s", errbuf);
90816ad2ffbSNamhyung Kim 
90916ad2ffbSNamhyung Kim 		err = -saved_errno;
9108fa60e1fSNamhyung Kim 		goto out_symbol_exit;
91116ad2ffbSNamhyung Kim 	}
9120d37aa34SArnaldo Carvalho de Melo 
91316ad2ffbSNamhyung Kim 	err = -ENOMEM;
9143e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
915dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
91669aad6f1SArnaldo Carvalho de Melo 
917b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
91839d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
91903ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
9207e4ff9e3SMike Galbraith 	}
9217e4ff9e3SMike Galbraith 
922d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
923d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
92445604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
925d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
92639d17dacSArnaldo Carvalho de Melo 	return err;
92786470930SIngo Molnar }
928