xref: /openbmc/linux/tools/perf/builtin-record.c (revision e31f0d017ea19fce9f12f084e1c750a0e3b43680)
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"
30ef149c25SAdrian Hunter #include "util/auxtrace.h"
317c6a1c65SPeter Zijlstra 
3286470930SIngo Molnar #include <unistd.h>
3386470930SIngo Molnar #include <sched.h>
34a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3586470930SIngo Molnar 
3678da39faSBernhard Rosenkraenzer 
378c6f45a7SArnaldo Carvalho de Melo struct record {
3845694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
39b4006796SArnaldo Carvalho de Melo 	struct record_opts	opts;
40d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
41f5fc1412SJiri Olsa 	struct perf_data_file	file;
42ef149c25SAdrian Hunter 	struct auxtrace_record	*itr;
43d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
44d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
45d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
46d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
47d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
48d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
49d20deb64SArnaldo Carvalho de Melo 	long			samples;
500f82ebc4SArnaldo Carvalho de Melo };
5186470930SIngo Molnar 
528c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
53f5970550SPeter Zijlstra {
54cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
554f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
568d3eca20SDavid Ahern 		return -1;
578d3eca20SDavid Ahern 	}
58f5970550SPeter Zijlstra 
59cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
608d3eca20SDavid Ahern 	return 0;
61f5970550SPeter Zijlstra }
62f5970550SPeter Zijlstra 
6345694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
64d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
651d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
661d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
67234fbbf5SArnaldo Carvalho de Melo {
688c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
698c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
70234fbbf5SArnaldo Carvalho de Melo }
71234fbbf5SArnaldo Carvalho de Melo 
72e5685730SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, int idx)
7386470930SIngo Molnar {
74e5685730SArnaldo Carvalho de Melo 	struct perf_mmap *md = &rec->evlist->mmap[idx];
757b8283b5SDavid Ahern 	u64 head = perf_mmap__read_head(md);
767b8283b5SDavid Ahern 	u64 old = md->prev;
77918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
7886470930SIngo Molnar 	unsigned long size;
7986470930SIngo Molnar 	void *buf;
808d3eca20SDavid Ahern 	int rc = 0;
8186470930SIngo Molnar 
82dc82009aSArnaldo Carvalho de Melo 	if (old == head)
838d3eca20SDavid Ahern 		return 0;
8486470930SIngo Molnar 
85d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
8686470930SIngo Molnar 
8786470930SIngo Molnar 	size = head - old;
8886470930SIngo Molnar 
8986470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
9086470930SIngo Molnar 		buf = &data[old & md->mask];
9186470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
9286470930SIngo Molnar 		old += size;
9386470930SIngo Molnar 
948c6f45a7SArnaldo Carvalho de Melo 		if (record__write(rec, buf, size) < 0) {
958d3eca20SDavid Ahern 			rc = -1;
968d3eca20SDavid Ahern 			goto out;
978d3eca20SDavid Ahern 		}
9886470930SIngo Molnar 	}
9986470930SIngo Molnar 
10086470930SIngo Molnar 	buf = &data[old & md->mask];
10186470930SIngo Molnar 	size = head - old;
10286470930SIngo Molnar 	old += size;
10386470930SIngo Molnar 
1048c6f45a7SArnaldo Carvalho de Melo 	if (record__write(rec, buf, size) < 0) {
1058d3eca20SDavid Ahern 		rc = -1;
1068d3eca20SDavid Ahern 		goto out;
1078d3eca20SDavid Ahern 	}
10886470930SIngo Molnar 
10986470930SIngo Molnar 	md->prev = old;
110e5685730SArnaldo Carvalho de Melo 	perf_evlist__mmap_consume(rec->evlist, idx);
1118d3eca20SDavid Ahern out:
1128d3eca20SDavid Ahern 	return rc;
11386470930SIngo Molnar }
11486470930SIngo Molnar 
115*e31f0d01SAdrian Hunter #ifdef HAVE_AUXTRACE_SUPPORT
116*e31f0d01SAdrian Hunter 
117ef149c25SAdrian Hunter static int record__process_auxtrace(struct perf_tool *tool,
118ef149c25SAdrian Hunter 				    union perf_event *event, void *data1,
119ef149c25SAdrian Hunter 				    size_t len1, void *data2, size_t len2)
120ef149c25SAdrian Hunter {
121ef149c25SAdrian Hunter 	struct record *rec = container_of(tool, struct record, tool);
12299fa2984SAdrian Hunter 	struct perf_data_file *file = &rec->file;
123ef149c25SAdrian Hunter 	size_t padding;
124ef149c25SAdrian Hunter 	u8 pad[8] = {0};
125ef149c25SAdrian Hunter 
12699fa2984SAdrian Hunter 	if (!perf_data_file__is_pipe(file)) {
12799fa2984SAdrian Hunter 		off_t file_offset;
12899fa2984SAdrian Hunter 		int fd = perf_data_file__fd(file);
12999fa2984SAdrian Hunter 		int err;
13099fa2984SAdrian Hunter 
13199fa2984SAdrian Hunter 		file_offset = lseek(fd, 0, SEEK_CUR);
13299fa2984SAdrian Hunter 		if (file_offset == -1)
13399fa2984SAdrian Hunter 			return -1;
13499fa2984SAdrian Hunter 		err = auxtrace_index__auxtrace_event(&rec->session->auxtrace_index,
13599fa2984SAdrian Hunter 						     event, file_offset);
13699fa2984SAdrian Hunter 		if (err)
13799fa2984SAdrian Hunter 			return err;
13899fa2984SAdrian Hunter 	}
13999fa2984SAdrian Hunter 
140ef149c25SAdrian Hunter 	/* event.auxtrace.size includes padding, see __auxtrace_mmap__read() */
141ef149c25SAdrian Hunter 	padding = (len1 + len2) & 7;
142ef149c25SAdrian Hunter 	if (padding)
143ef149c25SAdrian Hunter 		padding = 8 - padding;
144ef149c25SAdrian Hunter 
145ef149c25SAdrian Hunter 	record__write(rec, event, event->header.size);
146ef149c25SAdrian Hunter 	record__write(rec, data1, len1);
147ef149c25SAdrian Hunter 	if (len2)
148ef149c25SAdrian Hunter 		record__write(rec, data2, len2);
149ef149c25SAdrian Hunter 	record__write(rec, &pad, padding);
150ef149c25SAdrian Hunter 
151ef149c25SAdrian Hunter 	return 0;
152ef149c25SAdrian Hunter }
153ef149c25SAdrian Hunter 
154ef149c25SAdrian Hunter static int record__auxtrace_mmap_read(struct record *rec,
155ef149c25SAdrian Hunter 				      struct auxtrace_mmap *mm)
156ef149c25SAdrian Hunter {
157ef149c25SAdrian Hunter 	int ret;
158ef149c25SAdrian Hunter 
159ef149c25SAdrian Hunter 	ret = auxtrace_mmap__read(mm, rec->itr, &rec->tool,
160ef149c25SAdrian Hunter 				  record__process_auxtrace);
161ef149c25SAdrian Hunter 	if (ret < 0)
162ef149c25SAdrian Hunter 		return ret;
163ef149c25SAdrian Hunter 
164ef149c25SAdrian Hunter 	if (ret)
165ef149c25SAdrian Hunter 		rec->samples++;
166ef149c25SAdrian Hunter 
167ef149c25SAdrian Hunter 	return 0;
168ef149c25SAdrian Hunter }
169ef149c25SAdrian Hunter 
170*e31f0d01SAdrian Hunter #else
171*e31f0d01SAdrian Hunter 
172*e31f0d01SAdrian Hunter static inline
173*e31f0d01SAdrian Hunter int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
174*e31f0d01SAdrian Hunter 			       struct auxtrace_mmap *mm __maybe_unused)
175*e31f0d01SAdrian Hunter {
176*e31f0d01SAdrian Hunter 	return 0;
177*e31f0d01SAdrian Hunter }
178*e31f0d01SAdrian Hunter 
179*e31f0d01SAdrian Hunter #endif
180*e31f0d01SAdrian Hunter 
18186470930SIngo Molnar static volatile int done = 0;
182f7b7c26eSPeter Zijlstra static volatile int signr = -1;
18333e49ea7SAndi Kleen static volatile int child_finished = 0;
18486470930SIngo Molnar 
18586470930SIngo Molnar static void sig_handler(int sig)
18686470930SIngo Molnar {
18733e49ea7SAndi Kleen 	if (sig == SIGCHLD)
18833e49ea7SAndi Kleen 		child_finished = 1;
18945604710SNamhyung Kim 	else
19045604710SNamhyung Kim 		signr = sig;
19133e49ea7SAndi Kleen 
19286470930SIngo Molnar 	done = 1;
193f7b7c26eSPeter Zijlstra }
194f7b7c26eSPeter Zijlstra 
19545604710SNamhyung Kim static void record__sig_exit(void)
196f7b7c26eSPeter Zijlstra {
19745604710SNamhyung Kim 	if (signr == -1)
198f7b7c26eSPeter Zijlstra 		return;
199f7b7c26eSPeter Zijlstra 
200f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
20145604710SNamhyung Kim 	raise(signr);
20286470930SIngo Molnar }
20386470930SIngo Molnar 
2048c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
205dd7927f4SArnaldo Carvalho de Melo {
20656e52e85SArnaldo Carvalho de Melo 	char msg[512];
2076a4bb04cSJiri Olsa 	struct perf_evsel *pos;
208d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
209d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
210b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
2118d3eca20SDavid Ahern 	int rc = 0;
212dd7927f4SArnaldo Carvalho de Melo 
213f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
214cac21425SJiri Olsa 
2150050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
2163da297a6SIngo Molnar try_again:
2176a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
21856e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2193da297a6SIngo Molnar 				if (verbose)
220c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2213da297a6SIngo Molnar 				goto try_again;
2223da297a6SIngo Molnar 			}
223ca6a4258SDavid Ahern 
22456e52e85SArnaldo Carvalho de Melo 			rc = -errno;
22556e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
22656e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
22756e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
2288d3eca20SDavid Ahern 			goto out;
2297c6a1c65SPeter Zijlstra 		}
2307c6a1c65SPeter Zijlstra 	}
2317c6a1c65SPeter Zijlstra 
23223d4aad4SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist, &pos)) {
23323d4aad4SArnaldo Carvalho de Melo 		error("failed to set filter \"%s\" on event %s with %d (%s)\n",
23423d4aad4SArnaldo Carvalho de Melo 			pos->filter, perf_evsel__name(pos), errno,
23535550da3SMasami Hiramatsu 			strerror_r(errno, msg, sizeof(msg)));
2368d3eca20SDavid Ahern 		rc = -1;
2378d3eca20SDavid Ahern 		goto out;
2380a102479SFrederic Weisbecker 	}
2390a102479SFrederic Weisbecker 
240ef149c25SAdrian Hunter 	if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
241ef149c25SAdrian Hunter 				 opts->auxtrace_mmap_pages, false) < 0) {
2428d3eca20SDavid Ahern 		if (errno == EPERM) {
2438d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
24418e60939SNelson Elhage 			       "Consider increasing "
24518e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
24618e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
247ef149c25SAdrian Hunter 			       "(current value: %u,%u)\n",
248ef149c25SAdrian Hunter 			       opts->mmap_pages, opts->auxtrace_mmap_pages);
2498d3eca20SDavid Ahern 			rc = -errno;
2508d3eca20SDavid Ahern 		} else {
25135550da3SMasami Hiramatsu 			pr_err("failed to mmap with %d (%s)\n", errno,
25235550da3SMasami Hiramatsu 				strerror_r(errno, msg, sizeof(msg)));
2538d3eca20SDavid Ahern 			rc = -errno;
2548d3eca20SDavid Ahern 		}
2558d3eca20SDavid Ahern 		goto out;
25618e60939SNelson Elhage 	}
2570a27d7f9SArnaldo Carvalho de Melo 
258a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
2597b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
2608d3eca20SDavid Ahern out:
2618d3eca20SDavid Ahern 	return rc;
262a91e5431SArnaldo Carvalho de Melo }
263a91e5431SArnaldo Carvalho de Melo 
264e3d59112SNamhyung Kim static int process_sample_event(struct perf_tool *tool,
265e3d59112SNamhyung Kim 				union perf_event *event,
266e3d59112SNamhyung Kim 				struct perf_sample *sample,
267e3d59112SNamhyung Kim 				struct perf_evsel *evsel,
268e3d59112SNamhyung Kim 				struct machine *machine)
269e3d59112SNamhyung Kim {
270e3d59112SNamhyung Kim 	struct record *rec = container_of(tool, struct record, tool);
271e3d59112SNamhyung Kim 
272e3d59112SNamhyung Kim 	rec->samples++;
273e3d59112SNamhyung Kim 
274e3d59112SNamhyung Kim 	return build_id__mark_dso_hit(tool, event, sample, evsel, machine);
275e3d59112SNamhyung Kim }
276e3d59112SNamhyung Kim 
2778c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
2786122e4e4SArnaldo Carvalho de Melo {
279f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
280f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
2816122e4e4SArnaldo Carvalho de Melo 
28242aa276fSNamhyung Kim 	u64 size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
2839f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2849f591fd7SArnaldo Carvalho de Melo 		return 0;
2859f591fd7SArnaldo Carvalho de Melo 
2864ac30cf7SNamhyung Kim 	file->size = size;
2874ac30cf7SNamhyung Kim 
28800dc8657SNamhyung Kim 	/*
28900dc8657SNamhyung Kim 	 * During this process, it'll load kernel map and replace the
29000dc8657SNamhyung Kim 	 * dso->long_name to a real pathname it found.  In this case
29100dc8657SNamhyung Kim 	 * we prefer the vmlinux path like
29200dc8657SNamhyung Kim 	 *   /lib/modules/3.16.4/build/vmlinux
29300dc8657SNamhyung Kim 	 *
29400dc8657SNamhyung Kim 	 * rather than build-id path (in debug directory).
29500dc8657SNamhyung Kim 	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
29600dc8657SNamhyung Kim 	 */
29700dc8657SNamhyung Kim 	symbol_conf.ignore_vmlinux_buildid = true;
29800dc8657SNamhyung Kim 
299b7b61cbeSArnaldo Carvalho de Melo 	return perf_session__process_events(session);
3006122e4e4SArnaldo Carvalho de Melo }
3016122e4e4SArnaldo Carvalho de Melo 
3028115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
303a1645ce1SZhang, Yanmin {
304a1645ce1SZhang, Yanmin 	int err;
30545694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
306a1645ce1SZhang, Yanmin 	/*
307a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
308a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
309a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
310a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
311a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
312a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
313a1645ce1SZhang, Yanmin 	 */
31445694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
315743eb868SArnaldo Carvalho de Melo 					     machine);
316a1645ce1SZhang, Yanmin 	if (err < 0)
317a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
31823346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
319a1645ce1SZhang, Yanmin 
320a1645ce1SZhang, Yanmin 	/*
321a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
322a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
323a1645ce1SZhang, Yanmin 	 */
32445694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
3250ae617beSAdrian Hunter 						 machine);
326a1645ce1SZhang, Yanmin 	if (err < 0)
327a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
32823346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
329a1645ce1SZhang, Yanmin }
330a1645ce1SZhang, Yanmin 
33198402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
33298402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
33398402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
33498402807SFrederic Weisbecker };
33598402807SFrederic Weisbecker 
3368c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
33798402807SFrederic Weisbecker {
338dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
3390e2e63ddSPeter Zijlstra 	int i;
3408d3eca20SDavid Ahern 	int rc = 0;
34198402807SFrederic Weisbecker 
342d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
343ef149c25SAdrian Hunter 		struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap;
344ef149c25SAdrian Hunter 
3458d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
346e5685730SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, i) != 0) {
3478d3eca20SDavid Ahern 				rc = -1;
3488d3eca20SDavid Ahern 				goto out;
3498d3eca20SDavid Ahern 			}
3508d3eca20SDavid Ahern 		}
351ef149c25SAdrian Hunter 
352ef149c25SAdrian Hunter 		if (mm->base &&
353ef149c25SAdrian Hunter 		    record__auxtrace_mmap_read(rec, mm) != 0) {
354ef149c25SAdrian Hunter 			rc = -1;
355ef149c25SAdrian Hunter 			goto out;
356ef149c25SAdrian Hunter 		}
35798402807SFrederic Weisbecker 	}
35898402807SFrederic Weisbecker 
359dcabb507SJiri Olsa 	/*
360dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
361dcabb507SJiri Olsa 	 * at least one event.
362dcabb507SJiri Olsa 	 */
363dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
3648c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
3658d3eca20SDavid Ahern 
3668d3eca20SDavid Ahern out:
3678d3eca20SDavid Ahern 	return rc;
36898402807SFrederic Weisbecker }
36998402807SFrederic Weisbecker 
3708c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
37157706abcSDavid Ahern {
37257706abcSDavid Ahern 	struct perf_session *session = rec->session;
37357706abcSDavid Ahern 	int feat;
37457706abcSDavid Ahern 
37557706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
37657706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
37757706abcSDavid Ahern 
37857706abcSDavid Ahern 	if (rec->no_buildid)
37957706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
38057706abcSDavid Ahern 
3813e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
38257706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
38357706abcSDavid Ahern 
38457706abcSDavid Ahern 	if (!rec->opts.branch_stack)
38557706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
386ef149c25SAdrian Hunter 
387ef149c25SAdrian Hunter 	if (!rec->opts.full_auxtrace)
388ef149c25SAdrian Hunter 		perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
38957706abcSDavid Ahern }
39057706abcSDavid Ahern 
391f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
392f33cbe72SArnaldo Carvalho de Melo 
393f33cbe72SArnaldo Carvalho de Melo /*
394f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
395f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
396f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
397f33cbe72SArnaldo Carvalho de Melo  */
39845604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
39945604710SNamhyung Kim 					siginfo_t *info,
400f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
401f33cbe72SArnaldo Carvalho de Melo {
402f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
403f33cbe72SArnaldo Carvalho de Melo 	done = 1;
404f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
405f33cbe72SArnaldo Carvalho de Melo }
406f33cbe72SArnaldo Carvalho de Melo 
4078c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
40886470930SIngo Molnar {
40957706abcSDavid Ahern 	int err;
41045604710SNamhyung Kim 	int status = 0;
4118b412664SPeter Zijlstra 	unsigned long waking = 0;
41246be604bSZhang, Yanmin 	const bool forks = argc > 0;
41323346f21SArnaldo Carvalho de Melo 	struct machine *machine;
41445694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
415b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
416f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
417d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
4186dcf45efSArnaldo Carvalho de Melo 	bool disabled = false, draining = false;
41942aa276fSNamhyung Kim 	int fd;
42086470930SIngo Molnar 
421d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
42233e49ea7SAndi Kleen 
42345604710SNamhyung Kim 	atexit(record__sig_exit);
424f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
425f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
426804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
427f5970550SPeter Zijlstra 
428b7b61cbeSArnaldo Carvalho de Melo 	session = perf_session__new(file, false, tool);
42994c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
430ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
431a9a70bbcSArnaldo Carvalho de Melo 		return -1;
432a9a70bbcSArnaldo Carvalho de Melo 	}
433a9a70bbcSArnaldo Carvalho de Melo 
43442aa276fSNamhyung Kim 	fd = perf_data_file__fd(file);
435d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
436d20deb64SArnaldo Carvalho de Melo 
4378c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
438330aa675SStephane Eranian 
439d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
4403e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
441f5fc1412SJiri Olsa 						    argv, file->is_pipe,
442735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
44335b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
44435b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
44545604710SNamhyung Kim 			status = err;
44635b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
447856e9660SPeter Zijlstra 		}
448856e9660SPeter Zijlstra 	}
449856e9660SPeter Zijlstra 
4508c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
4518d3eca20SDavid Ahern 		err = -1;
45245604710SNamhyung Kim 		goto out_child;
4538d3eca20SDavid Ahern 	}
45486470930SIngo Molnar 
4553e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
456a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
457a8bb559bSNamhyung Kim 
458f5fc1412SJiri Olsa 	if (file->is_pipe) {
45942aa276fSNamhyung Kim 		err = perf_header__write_pipe(fd);
460529870e3STom Zanussi 		if (err < 0)
46145604710SNamhyung Kim 			goto out_child;
462563aecb2SJiri Olsa 	} else {
46342aa276fSNamhyung Kim 		err = perf_session__write_header(session, rec->evlist, fd, false);
464d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
46545604710SNamhyung Kim 			goto out_child;
466d5eed904SArnaldo Carvalho de Melo 	}
4677c6a1c65SPeter Zijlstra 
468d3665498SDavid Ahern 	if (!rec->no_buildid
469e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
470d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
471e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
4728d3eca20SDavid Ahern 		err = -1;
47345604710SNamhyung Kim 		goto out_child;
474e20960c0SRobert Richter 	}
475e20960c0SRobert Richter 
47634ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
477743eb868SArnaldo Carvalho de Melo 
478f5fc1412SJiri Olsa 	if (file->is_pipe) {
47945694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
480a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
4812c46dbb5STom Zanussi 		if (err < 0) {
4822c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
48345604710SNamhyung Kim 			goto out_child;
4842c46dbb5STom Zanussi 		}
485cd19a035STom Zanussi 
4863e2be2daSArnaldo Carvalho de Melo 		if (have_tracepoints(&rec->evlist->entries)) {
48763e0c771STom Zanussi 			/*
48863e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
48963e0c771STom Zanussi 			 * there were no tracepoints so its not really
49063e0c771STom Zanussi 			 * an error, just that we don't need to
49163e0c771STom Zanussi 			 * synthesize anything.  We really have to
49263e0c771STom Zanussi 			 * return this more properly and also
49363e0c771STom Zanussi 			 * propagate errors that now are calling die()
49463e0c771STom Zanussi 			 */
49542aa276fSNamhyung Kim 			err = perf_event__synthesize_tracing_data(tool,	fd, rec->evlist,
496743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
49763e0c771STom Zanussi 			if (err <= 0) {
49863e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
49945604710SNamhyung Kim 				goto out_child;
50063e0c771STom Zanussi 			}
501f34b9001SDavid Ahern 			rec->bytes_written += err;
5022c46dbb5STom Zanussi 		}
50363e0c771STom Zanussi 	}
5042c46dbb5STom Zanussi 
505ef149c25SAdrian Hunter 	if (rec->opts.full_auxtrace) {
506ef149c25SAdrian Hunter 		err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
507ef149c25SAdrian Hunter 					session, process_synthesized_event);
508ef149c25SAdrian Hunter 		if (err)
509ef149c25SAdrian Hunter 			goto out_delete_session;
510ef149c25SAdrian Hunter 	}
511ef149c25SAdrian Hunter 
51245694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
5130ae617beSAdrian Hunter 						 machine);
514c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
515c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
516c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
517c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
51856b03f3cSArnaldo Carvalho de Melo 
51945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
520743eb868SArnaldo Carvalho de Melo 					     machine);
521c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
522c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
523c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
524c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
525c1a3a4b9SArnaldo Carvalho de Melo 
5267e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
527876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
5287e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
5297e383de4SArnaldo Carvalho de Melo 	}
530b7cece76SArnaldo Carvalho de Melo 
5313e2be2daSArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
53258d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
5338d3eca20SDavid Ahern 	if (err != 0)
53445604710SNamhyung Kim 		goto out_child;
5358d3eca20SDavid Ahern 
536d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
53786470930SIngo Molnar 		struct sched_param param;
53886470930SIngo Molnar 
539d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
54086470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5416beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
5428d3eca20SDavid Ahern 			err = -1;
54345604710SNamhyung Kim 			goto out_child;
54486470930SIngo Molnar 		}
54586470930SIngo Molnar 	}
54686470930SIngo Molnar 
547774cb499SJiri Olsa 	/*
548774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
549774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
550774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
551774cb499SJiri Olsa 	 */
5526619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
5533e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
554764e16a3SDavid Ahern 
555856e9660SPeter Zijlstra 	/*
556856e9660SPeter Zijlstra 	 * Let the child rip
557856e9660SPeter Zijlstra 	 */
558735f7e0bSArnaldo Carvalho de Melo 	if (forks)
5593e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
560856e9660SPeter Zijlstra 
5616619a53eSAndi Kleen 	if (opts->initial_delay) {
5626619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
5636619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
5646619a53eSAndi Kleen 	}
5656619a53eSAndi Kleen 
566649c48a9SPeter Zijlstra 	for (;;) {
567d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
56886470930SIngo Molnar 
5698c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
5708d3eca20SDavid Ahern 			err = -1;
57145604710SNamhyung Kim 			goto out_child;
5728d3eca20SDavid Ahern 		}
57386470930SIngo Molnar 
574d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
5756dcf45efSArnaldo Carvalho de Melo 			if (done || draining)
576649c48a9SPeter Zijlstra 				break;
577f66a889dSArnaldo Carvalho de Melo 			err = perf_evlist__poll(rec->evlist, -1);
578a515114fSJiri Olsa 			/*
579a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
580a515114fSJiri Olsa 			 * number of returned events and interrupt error.
581a515114fSJiri Olsa 			 */
582a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
58345604710SNamhyung Kim 				err = 0;
5848b412664SPeter Zijlstra 			waking++;
5856dcf45efSArnaldo Carvalho de Melo 
5866dcf45efSArnaldo Carvalho de Melo 			if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
5876dcf45efSArnaldo Carvalho de Melo 				draining = true;
5888b412664SPeter Zijlstra 		}
5898b412664SPeter Zijlstra 
590774cb499SJiri Olsa 		/*
591774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
592774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
593774cb499SJiri Olsa 		 * disable events in this case.
594774cb499SJiri Olsa 		 */
595602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
5963e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
5972711926aSJiri Olsa 			disabled = true;
5982711926aSJiri Olsa 		}
5998b412664SPeter Zijlstra 	}
6008b412664SPeter Zijlstra 
601f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
60235550da3SMasami Hiramatsu 		char msg[STRERR_BUFSIZE];
603f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
604f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
605f33cbe72SArnaldo Carvalho de Melo 		err = -1;
60645604710SNamhyung Kim 		goto out_child;
607f33cbe72SArnaldo Carvalho de Melo 	}
608f33cbe72SArnaldo Carvalho de Melo 
609e3d59112SNamhyung Kim 	if (!quiet)
6108b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
61186470930SIngo Molnar 
61245604710SNamhyung Kim out_child:
61345604710SNamhyung Kim 	if (forks) {
61445604710SNamhyung Kim 		int exit_status;
61545604710SNamhyung Kim 
61645604710SNamhyung Kim 		if (!child_finished)
61745604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
61845604710SNamhyung Kim 
61945604710SNamhyung Kim 		wait(&exit_status);
62045604710SNamhyung Kim 
62145604710SNamhyung Kim 		if (err < 0)
62245604710SNamhyung Kim 			status = err;
62345604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
62445604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
62545604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
62645604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
62745604710SNamhyung Kim 	} else
62845604710SNamhyung Kim 		status = err;
62945604710SNamhyung Kim 
630e3d59112SNamhyung Kim 	/* this will be recalculated during process_buildids() */
631e3d59112SNamhyung Kim 	rec->samples = 0;
632e3d59112SNamhyung Kim 
63345604710SNamhyung Kim 	if (!err && !file->is_pipe) {
63445604710SNamhyung Kim 		rec->session->header.data_size += rec->bytes_written;
63545604710SNamhyung Kim 
636cd10b289SAdrian Hunter 		if (!rec->no_buildid) {
63745604710SNamhyung Kim 			process_buildids(rec);
638cd10b289SAdrian Hunter 			/*
639cd10b289SAdrian Hunter 			 * We take all buildids when the file contains
640cd10b289SAdrian Hunter 			 * AUX area tracing data because we do not decode the
641cd10b289SAdrian Hunter 			 * trace because it would take too long.
642cd10b289SAdrian Hunter 			 */
643cd10b289SAdrian Hunter 			if (rec->opts.full_auxtrace)
644cd10b289SAdrian Hunter 				dsos__hit_all(rec->session);
645cd10b289SAdrian Hunter 		}
64642aa276fSNamhyung Kim 		perf_session__write_header(rec->session, rec->evlist, fd, true);
64745604710SNamhyung Kim 	}
64839d17dacSArnaldo Carvalho de Melo 
649e3d59112SNamhyung Kim 	if (!err && !quiet) {
650e3d59112SNamhyung Kim 		char samples[128];
651e3d59112SNamhyung Kim 
652ef149c25SAdrian Hunter 		if (rec->samples && !rec->opts.full_auxtrace)
653e3d59112SNamhyung Kim 			scnprintf(samples, sizeof(samples),
654e3d59112SNamhyung Kim 				  " (%" PRIu64 " samples)", rec->samples);
655e3d59112SNamhyung Kim 		else
656e3d59112SNamhyung Kim 			samples[0] = '\0';
657e3d59112SNamhyung Kim 
658e3d59112SNamhyung Kim 		fprintf(stderr,	"[ perf record: Captured and wrote %.3f MB %s%s ]\n",
659e3d59112SNamhyung Kim 			perf_data_file__size(file) / 1024.0 / 1024.0,
660e3d59112SNamhyung Kim 			file->path, samples);
661e3d59112SNamhyung Kim 	}
662e3d59112SNamhyung Kim 
66339d17dacSArnaldo Carvalho de Melo out_delete_session:
66439d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
66545604710SNamhyung Kim 	return status;
66686470930SIngo Molnar }
66786470930SIngo Molnar 
668bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
669bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
670bdfebd84SRoberto Agostino Vitillo 
671bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
672bdfebd84SRoberto Agostino Vitillo 
673bdfebd84SRoberto Agostino Vitillo struct branch_mode {
674bdfebd84SRoberto Agostino Vitillo 	const char *name;
675bdfebd84SRoberto Agostino Vitillo 	int mode;
676bdfebd84SRoberto Agostino Vitillo };
677bdfebd84SRoberto Agostino Vitillo 
678bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
679bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
680bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
681bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
682bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
683bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
684bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
685bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
6860126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
6870126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
6880126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
6890fffa5dfSAnshuman Khandual 	BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
690bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
691bdfebd84SRoberto Agostino Vitillo };
692bdfebd84SRoberto Agostino Vitillo 
693bdfebd84SRoberto Agostino Vitillo static int
694a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
695bdfebd84SRoberto Agostino Vitillo {
696bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
697bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
698bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
699bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
700bdfebd84SRoberto Agostino Vitillo 
701bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
702bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
703a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
704bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
705bdfebd84SRoberto Agostino Vitillo 
706a5aabdacSStephane Eranian 	if (unset)
707a5aabdacSStephane Eranian 		return 0;
708bdfebd84SRoberto Agostino Vitillo 
709a5aabdacSStephane Eranian 	/*
710a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
711a5aabdacSStephane Eranian 	 */
712a5aabdacSStephane Eranian 	if (*mode)
713a5aabdacSStephane Eranian 		return -1;
714a5aabdacSStephane Eranian 
715a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
716a5aabdacSStephane Eranian 	if (str) {
717bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
718bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
719bdfebd84SRoberto Agostino Vitillo 		if (!s)
720bdfebd84SRoberto Agostino Vitillo 			return -1;
721bdfebd84SRoberto Agostino Vitillo 
722bdfebd84SRoberto Agostino Vitillo 		for (;;) {
723bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
724bdfebd84SRoberto Agostino Vitillo 			if (p)
725bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
726bdfebd84SRoberto Agostino Vitillo 
727bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
728bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
729bdfebd84SRoberto Agostino Vitillo 					break;
730bdfebd84SRoberto Agostino Vitillo 			}
731a5aabdacSStephane Eranian 			if (!br->name) {
732a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
733a5aabdacSStephane Eranian 					    " check man page\n", s);
734bdfebd84SRoberto Agostino Vitillo 				goto error;
735a5aabdacSStephane Eranian 			}
736bdfebd84SRoberto Agostino Vitillo 
737bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
738bdfebd84SRoberto Agostino Vitillo 
739bdfebd84SRoberto Agostino Vitillo 			if (!p)
740bdfebd84SRoberto Agostino Vitillo 				break;
741bdfebd84SRoberto Agostino Vitillo 
742bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
743bdfebd84SRoberto Agostino Vitillo 		}
744a5aabdacSStephane Eranian 	}
745bdfebd84SRoberto Agostino Vitillo 	ret = 0;
746bdfebd84SRoberto Agostino Vitillo 
747a5aabdacSStephane Eranian 	/* default to any branch */
748bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
749a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
750bdfebd84SRoberto Agostino Vitillo 	}
751bdfebd84SRoberto Agostino Vitillo error:
752bdfebd84SRoberto Agostino Vitillo 	free(os);
753bdfebd84SRoberto Agostino Vitillo 	return ret;
754bdfebd84SRoberto Agostino Vitillo }
755bdfebd84SRoberto Agostino Vitillo 
75672a128aaSNamhyung Kim static void callchain_debug(void)
75709b0fd45SJiri Olsa {
758aad2b21cSKan Liang 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" };
759a601fdffSJiri Olsa 
76072a128aaSNamhyung Kim 	pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
76126d33022SJiri Olsa 
76272a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_DWARF)
76309b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
76472a128aaSNamhyung Kim 			 callchain_param.dump_size);
76509b0fd45SJiri Olsa }
76609b0fd45SJiri Olsa 
76772a128aaSNamhyung Kim int record_parse_callchain_opt(const struct option *opt __maybe_unused,
76809b0fd45SJiri Olsa 			       const char *arg,
76909b0fd45SJiri Olsa 			       int unset)
77009b0fd45SJiri Olsa {
77109b0fd45SJiri Olsa 	int ret;
77209b0fd45SJiri Olsa 
77372a128aaSNamhyung Kim 	callchain_param.enabled = !unset;
774eb853e80SJiri Olsa 
77509b0fd45SJiri Olsa 	/* --no-call-graph */
77609b0fd45SJiri Olsa 	if (unset) {
77772a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_NONE;
77809b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
77909b0fd45SJiri Olsa 		return 0;
78009b0fd45SJiri Olsa 	}
78109b0fd45SJiri Olsa 
782f7f084f4SNamhyung Kim 	ret = parse_callchain_record_opt(arg);
78309b0fd45SJiri Olsa 	if (!ret)
78472a128aaSNamhyung Kim 		callchain_debug();
78509b0fd45SJiri Olsa 
78626d33022SJiri Olsa 	return ret;
78726d33022SJiri Olsa }
78826d33022SJiri Olsa 
78972a128aaSNamhyung Kim int record_callchain_opt(const struct option *opt __maybe_unused,
79009b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
79109b0fd45SJiri Olsa 			 int unset __maybe_unused)
79209b0fd45SJiri Olsa {
79372a128aaSNamhyung Kim 	callchain_param.enabled = true;
79409b0fd45SJiri Olsa 
79572a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_NONE)
79672a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_FP;
797eb853e80SJiri Olsa 
79872a128aaSNamhyung Kim 	callchain_debug();
79909b0fd45SJiri Olsa 	return 0;
80009b0fd45SJiri Olsa }
80109b0fd45SJiri Olsa 
802eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
803eb853e80SJiri Olsa {
804eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
8055a2e5e85SNamhyung Kim 		var = "call-graph.record-mode"; /* fall-through */
806eb853e80SJiri Olsa 
807eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
808eb853e80SJiri Olsa }
809eb853e80SJiri Olsa 
810814c8c38SPeter Zijlstra struct clockid_map {
811814c8c38SPeter Zijlstra 	const char *name;
812814c8c38SPeter Zijlstra 	int clockid;
813814c8c38SPeter Zijlstra };
814814c8c38SPeter Zijlstra 
815814c8c38SPeter Zijlstra #define CLOCKID_MAP(n, c)	\
816814c8c38SPeter Zijlstra 	{ .name = n, .clockid = (c), }
817814c8c38SPeter Zijlstra 
818814c8c38SPeter Zijlstra #define CLOCKID_END	{ .name = NULL, }
819814c8c38SPeter Zijlstra 
820814c8c38SPeter Zijlstra 
821814c8c38SPeter Zijlstra /*
822814c8c38SPeter Zijlstra  * Add the missing ones, we need to build on many distros...
823814c8c38SPeter Zijlstra  */
824814c8c38SPeter Zijlstra #ifndef CLOCK_MONOTONIC_RAW
825814c8c38SPeter Zijlstra #define CLOCK_MONOTONIC_RAW 4
826814c8c38SPeter Zijlstra #endif
827814c8c38SPeter Zijlstra #ifndef CLOCK_BOOTTIME
828814c8c38SPeter Zijlstra #define CLOCK_BOOTTIME 7
829814c8c38SPeter Zijlstra #endif
830814c8c38SPeter Zijlstra #ifndef CLOCK_TAI
831814c8c38SPeter Zijlstra #define CLOCK_TAI 11
832814c8c38SPeter Zijlstra #endif
833814c8c38SPeter Zijlstra 
834814c8c38SPeter Zijlstra static const struct clockid_map clockids[] = {
835814c8c38SPeter Zijlstra 	/* available for all events, NMI safe */
836814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic", CLOCK_MONOTONIC),
837814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW),
838814c8c38SPeter Zijlstra 
839814c8c38SPeter Zijlstra 	/* available for some events */
840814c8c38SPeter Zijlstra 	CLOCKID_MAP("realtime", CLOCK_REALTIME),
841814c8c38SPeter Zijlstra 	CLOCKID_MAP("boottime", CLOCK_BOOTTIME),
842814c8c38SPeter Zijlstra 	CLOCKID_MAP("tai", CLOCK_TAI),
843814c8c38SPeter Zijlstra 
844814c8c38SPeter Zijlstra 	/* available for the lazy */
845814c8c38SPeter Zijlstra 	CLOCKID_MAP("mono", CLOCK_MONOTONIC),
846814c8c38SPeter Zijlstra 	CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW),
847814c8c38SPeter Zijlstra 	CLOCKID_MAP("real", CLOCK_REALTIME),
848814c8c38SPeter Zijlstra 	CLOCKID_MAP("boot", CLOCK_BOOTTIME),
849814c8c38SPeter Zijlstra 
850814c8c38SPeter Zijlstra 	CLOCKID_END,
851814c8c38SPeter Zijlstra };
852814c8c38SPeter Zijlstra 
853814c8c38SPeter Zijlstra static int parse_clockid(const struct option *opt, const char *str, int unset)
854814c8c38SPeter Zijlstra {
855814c8c38SPeter Zijlstra 	struct record_opts *opts = (struct record_opts *)opt->value;
856814c8c38SPeter Zijlstra 	const struct clockid_map *cm;
857814c8c38SPeter Zijlstra 	const char *ostr = str;
858814c8c38SPeter Zijlstra 
859814c8c38SPeter Zijlstra 	if (unset) {
860814c8c38SPeter Zijlstra 		opts->use_clockid = 0;
861814c8c38SPeter Zijlstra 		return 0;
862814c8c38SPeter Zijlstra 	}
863814c8c38SPeter Zijlstra 
864814c8c38SPeter Zijlstra 	/* no arg passed */
865814c8c38SPeter Zijlstra 	if (!str)
866814c8c38SPeter Zijlstra 		return 0;
867814c8c38SPeter Zijlstra 
868814c8c38SPeter Zijlstra 	/* no setting it twice */
869814c8c38SPeter Zijlstra 	if (opts->use_clockid)
870814c8c38SPeter Zijlstra 		return -1;
871814c8c38SPeter Zijlstra 
872814c8c38SPeter Zijlstra 	opts->use_clockid = true;
873814c8c38SPeter Zijlstra 
874814c8c38SPeter Zijlstra 	/* if its a number, we're done */
875814c8c38SPeter Zijlstra 	if (sscanf(str, "%d", &opts->clockid) == 1)
876814c8c38SPeter Zijlstra 		return 0;
877814c8c38SPeter Zijlstra 
878814c8c38SPeter Zijlstra 	/* allow a "CLOCK_" prefix to the name */
879814c8c38SPeter Zijlstra 	if (!strncasecmp(str, "CLOCK_", 6))
880814c8c38SPeter Zijlstra 		str += 6;
881814c8c38SPeter Zijlstra 
882814c8c38SPeter Zijlstra 	for (cm = clockids; cm->name; cm++) {
883814c8c38SPeter Zijlstra 		if (!strcasecmp(str, cm->name)) {
884814c8c38SPeter Zijlstra 			opts->clockid = cm->clockid;
885814c8c38SPeter Zijlstra 			return 0;
886814c8c38SPeter Zijlstra 		}
887814c8c38SPeter Zijlstra 	}
888814c8c38SPeter Zijlstra 
889814c8c38SPeter Zijlstra 	opts->use_clockid = false;
890814c8c38SPeter Zijlstra 	ui__warning("unknown clockid %s, check man page\n", ostr);
891814c8c38SPeter Zijlstra 	return -1;
892814c8c38SPeter Zijlstra }
893814c8c38SPeter Zijlstra 
894e9db1310SAdrian Hunter static int record__parse_mmap_pages(const struct option *opt,
895e9db1310SAdrian Hunter 				    const char *str,
896e9db1310SAdrian Hunter 				    int unset __maybe_unused)
897e9db1310SAdrian Hunter {
898e9db1310SAdrian Hunter 	struct record_opts *opts = opt->value;
899e9db1310SAdrian Hunter 	char *s, *p;
900e9db1310SAdrian Hunter 	unsigned int mmap_pages;
901e9db1310SAdrian Hunter 	int ret;
902e9db1310SAdrian Hunter 
903e9db1310SAdrian Hunter 	if (!str)
904e9db1310SAdrian Hunter 		return -EINVAL;
905e9db1310SAdrian Hunter 
906e9db1310SAdrian Hunter 	s = strdup(str);
907e9db1310SAdrian Hunter 	if (!s)
908e9db1310SAdrian Hunter 		return -ENOMEM;
909e9db1310SAdrian Hunter 
910e9db1310SAdrian Hunter 	p = strchr(s, ',');
911e9db1310SAdrian Hunter 	if (p)
912e9db1310SAdrian Hunter 		*p = '\0';
913e9db1310SAdrian Hunter 
914e9db1310SAdrian Hunter 	if (*s) {
915e9db1310SAdrian Hunter 		ret = __perf_evlist__parse_mmap_pages(&mmap_pages, s);
916e9db1310SAdrian Hunter 		if (ret)
917e9db1310SAdrian Hunter 			goto out_free;
918e9db1310SAdrian Hunter 		opts->mmap_pages = mmap_pages;
919e9db1310SAdrian Hunter 	}
920e9db1310SAdrian Hunter 
921e9db1310SAdrian Hunter 	if (!p) {
922e9db1310SAdrian Hunter 		ret = 0;
923e9db1310SAdrian Hunter 		goto out_free;
924e9db1310SAdrian Hunter 	}
925e9db1310SAdrian Hunter 
926e9db1310SAdrian Hunter 	ret = __perf_evlist__parse_mmap_pages(&mmap_pages, p + 1);
927e9db1310SAdrian Hunter 	if (ret)
928e9db1310SAdrian Hunter 		goto out_free;
929e9db1310SAdrian Hunter 
930e9db1310SAdrian Hunter 	opts->auxtrace_mmap_pages = mmap_pages;
931e9db1310SAdrian Hunter 
932e9db1310SAdrian Hunter out_free:
933e9db1310SAdrian Hunter 	free(s);
934e9db1310SAdrian Hunter 	return ret;
935e9db1310SAdrian Hunter }
936e9db1310SAdrian Hunter 
937e5b2c207SNamhyung Kim static const char * const __record_usage[] = {
93886470930SIngo Molnar 	"perf record [<options>] [<command>]",
93986470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
94086470930SIngo Molnar 	NULL
94186470930SIngo Molnar };
942e5b2c207SNamhyung Kim const char * const *record_usage = __record_usage;
94386470930SIngo Molnar 
944d20deb64SArnaldo Carvalho de Melo /*
9458c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
9468c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
947d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
948d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
949d20deb64SArnaldo Carvalho de Melo  *
950d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
951d20deb64SArnaldo Carvalho de Melo  *
952d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
953d20deb64SArnaldo Carvalho de Melo  */
9548c6f45a7SArnaldo Carvalho de Melo static struct record record = {
955d20deb64SArnaldo Carvalho de Melo 	.opts = {
9568affc2b8SAndi Kleen 		.sample_time	     = true,
957d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
958d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
959d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
960447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
961d1cb9fceSNamhyung Kim 		.target		     = {
962d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
9633aa5939dSAdrian Hunter 			.default_per_cpu = true,
964d1cb9fceSNamhyung Kim 		},
965d20deb64SArnaldo Carvalho de Melo 	},
966e3d59112SNamhyung Kim 	.tool = {
967e3d59112SNamhyung Kim 		.sample		= process_sample_event,
968e3d59112SNamhyung Kim 		.fork		= perf_event__process_fork,
969e3d59112SNamhyung Kim 		.comm		= perf_event__process_comm,
970e3d59112SNamhyung Kim 		.mmap		= perf_event__process_mmap,
971e3d59112SNamhyung Kim 		.mmap2		= perf_event__process_mmap2,
972e3d59112SNamhyung Kim 	},
973d20deb64SArnaldo Carvalho de Melo };
9747865e817SFrederic Weisbecker 
97509b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
97661eaa3beSArnaldo Carvalho de Melo 
9779ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
978aad2b21cSKan Liang const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf lbr";
97961eaa3beSArnaldo Carvalho de Melo #else
980aad2b21cSKan Liang const char record_callchain_help[] = CALLCHAIN_HELP "fp lbr";
98161eaa3beSArnaldo Carvalho de Melo #endif
98261eaa3beSArnaldo Carvalho de Melo 
983d20deb64SArnaldo Carvalho de Melo /*
984d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
985d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
986b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
987d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
988d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
989d20deb64SArnaldo Carvalho de Melo  */
990e5b2c207SNamhyung Kim struct option __record_options[] = {
991d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
99286470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
993f120f9d5SJiri Olsa 		     parse_events_option),
994d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
995c171b552SLi Zefan 		     "event filter", parse_filter),
996bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
997d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
998bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
999d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
1000d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
100186470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
1002509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
1003acac03faSKirill Smelkov 		    "collect data without buffering"),
1004d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
1005daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
1006bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
100786470930SIngo Molnar 			    "system-wide collection from all CPUs"),
1008bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
1009c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
1010d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
1011f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
101286470930SIngo Molnar 		    "output file name"),
101369e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
101469e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
10152e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
1016d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
1017e9db1310SAdrian Hunter 	OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]",
1018e9db1310SAdrian Hunter 		     "number of mmap data pages and AUX area tracing mmap pages",
1019e9db1310SAdrian Hunter 		     record__parse_mmap_pages),
1020d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
102143bece79SLin Ming 		    "put the counters into a counter group"),
102209b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
102309b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
102409b0fd45SJiri Olsa 			   &record_callchain_opt),
102509b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
102675d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
102709b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
1028c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
10293da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
1030b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
1031d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
1032649c48a9SPeter Zijlstra 		    "per thread counts"),
1033d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
10344bba828dSAnton Blanchard 		    "Sample addresses"),
1035d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
10363e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
1037d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
1038649c48a9SPeter Zijlstra 		    "don't sample"),
1039d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
1040a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
1041d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
1042baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
1043d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
1044023695d9SStephane Eranian 		     "monitor event in cgroup name only",
1045023695d9SStephane Eranian 		     parse_cgroups),
1046a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
10476619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
1048bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
1049bea03405SNamhyung Kim 		   "user to profile"),
1050a5aabdacSStephane Eranian 
1051a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
1052a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
1053a5aabdacSStephane Eranian 		     parse_branch_stack),
1054a5aabdacSStephane Eranian 
1055a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
1056a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
1057bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
105805484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
105905484298SAndi Kleen 		    "sample by weight (on special events only)"),
1060475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
1061475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
10623aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
10633aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
10644b6c5177SStephane Eranian 	OPT_BOOLEAN('I', "intr-regs", &record.opts.sample_intr_regs,
10654b6c5177SStephane Eranian 		    "Sample machine registers on interrupt"),
106685c273d2SAndi Kleen 	OPT_BOOLEAN(0, "running-time", &record.opts.running_time,
106785c273d2SAndi Kleen 		    "Record running/enabled time of read (:S) events"),
1068814c8c38SPeter Zijlstra 	OPT_CALLBACK('k', "clockid", &record.opts,
1069814c8c38SPeter Zijlstra 	"clockid", "clockid to use for events, see clock_gettime()",
1070814c8c38SPeter Zijlstra 	parse_clockid),
107186470930SIngo Molnar 	OPT_END()
107286470930SIngo Molnar };
107386470930SIngo Molnar 
1074e5b2c207SNamhyung Kim struct option *record_options = __record_options;
1075e5b2c207SNamhyung Kim 
10761d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
107786470930SIngo Molnar {
1078ef149c25SAdrian Hunter 	int err;
10798c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
108016ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
108186470930SIngo Molnar 
10823e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
10833e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
1084361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
1085361c99a6SArnaldo Carvalho de Melo 
1086eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
1087eb853e80SJiri Olsa 
1088bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
1089a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
1090602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
1091bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
109286470930SIngo Molnar 
1093bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
10943780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
1095023695d9SStephane Eranian 			  " system-wide mode\n");
1096023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
1097023695d9SStephane Eranian 	}
1098023695d9SStephane Eranian 
1099ef149c25SAdrian Hunter 	if (!rec->itr) {
1100ef149c25SAdrian Hunter 		rec->itr = auxtrace_record__init(rec->evlist, &err);
1101ef149c25SAdrian Hunter 		if (err)
1102ef149c25SAdrian Hunter 			return err;
1103ef149c25SAdrian Hunter 	}
1104ef149c25SAdrian Hunter 
1105ef149c25SAdrian Hunter 	err = -ENOMEM;
1106ef149c25SAdrian Hunter 
11070a7e6d1bSNamhyung Kim 	symbol__init(NULL);
1108baa2f6ceSArnaldo Carvalho de Melo 
1109ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
1110646aaea6SArnaldo Carvalho de Melo 		pr_warning(
1111646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
1112ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
1113646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
1114646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
1115646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
1116646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
1117646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
1118ec80fde7SArnaldo Carvalho de Melo 
1119d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
1120a1ac1d3cSStephane Eranian 		disable_buildid_cache();
1121655000e7SArnaldo Carvalho de Melo 
11223e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
11233e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
112469aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
112569aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
1126bbd36e5eSPeter Zijlstra 	}
112786470930SIngo Molnar 
112869e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
112969e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
113069e7e5b0SAdrian Hunter 
1131602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
113216ad2ffbSNamhyung Kim 	if (err) {
1133602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
113416ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
113516ad2ffbSNamhyung Kim 	}
11364bd0f2d2SNamhyung Kim 
1137602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
113816ad2ffbSNamhyung Kim 	if (err) {
113916ad2ffbSNamhyung Kim 		int saved_errno = errno;
114016ad2ffbSNamhyung Kim 
1141602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
11423780f488SNamhyung Kim 		ui__error("%s", errbuf);
114316ad2ffbSNamhyung Kim 
114416ad2ffbSNamhyung Kim 		err = -saved_errno;
11458fa60e1fSNamhyung Kim 		goto out_symbol_exit;
114616ad2ffbSNamhyung Kim 	}
11470d37aa34SArnaldo Carvalho de Melo 
114816ad2ffbSNamhyung Kim 	err = -ENOMEM;
11493e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
1150dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
115169aad6f1SArnaldo Carvalho de Melo 
1152ef149c25SAdrian Hunter 	err = auxtrace_record__options(rec->itr, rec->evlist, &rec->opts);
1153ef149c25SAdrian Hunter 	if (err)
1154ef149c25SAdrian Hunter 		goto out_symbol_exit;
1155ef149c25SAdrian Hunter 
1156b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
115739d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
115803ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
11597e4ff9e3SMike Galbraith 	}
11607e4ff9e3SMike Galbraith 
1161d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
1162d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
116345604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
1164d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
1165ef149c25SAdrian Hunter 	auxtrace_record__free(rec->itr);
116639d17dacSArnaldo Carvalho de Melo 	return err;
116786470930SIngo Molnar }
1168