xref: /openbmc/linux/tools/perf/builtin-record.c (revision 2dd6d8a10a942c5fd8950d1046e172237d009c8e)
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*2dd6d8a1SAdrian Hunter static volatile int done;
116*2dd6d8a1SAdrian Hunter static volatile int signr = -1;
117*2dd6d8a1SAdrian Hunter static volatile int child_finished;
118*2dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_enabled;
119*2dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_err;
120*2dd6d8a1SAdrian Hunter static volatile int auxtrace_record__snapshot_started;
121*2dd6d8a1SAdrian Hunter 
122*2dd6d8a1SAdrian Hunter static void sig_handler(int sig)
123*2dd6d8a1SAdrian Hunter {
124*2dd6d8a1SAdrian Hunter 	if (sig == SIGCHLD)
125*2dd6d8a1SAdrian Hunter 		child_finished = 1;
126*2dd6d8a1SAdrian Hunter 	else
127*2dd6d8a1SAdrian Hunter 		signr = sig;
128*2dd6d8a1SAdrian Hunter 
129*2dd6d8a1SAdrian Hunter 	done = 1;
130*2dd6d8a1SAdrian Hunter }
131*2dd6d8a1SAdrian Hunter 
132*2dd6d8a1SAdrian Hunter static void record__sig_exit(void)
133*2dd6d8a1SAdrian Hunter {
134*2dd6d8a1SAdrian Hunter 	if (signr == -1)
135*2dd6d8a1SAdrian Hunter 		return;
136*2dd6d8a1SAdrian Hunter 
137*2dd6d8a1SAdrian Hunter 	signal(signr, SIG_DFL);
138*2dd6d8a1SAdrian Hunter 	raise(signr);
139*2dd6d8a1SAdrian Hunter }
140*2dd6d8a1SAdrian Hunter 
141e31f0d01SAdrian Hunter #ifdef HAVE_AUXTRACE_SUPPORT
142e31f0d01SAdrian Hunter 
143ef149c25SAdrian Hunter static int record__process_auxtrace(struct perf_tool *tool,
144ef149c25SAdrian Hunter 				    union perf_event *event, void *data1,
145ef149c25SAdrian Hunter 				    size_t len1, void *data2, size_t len2)
146ef149c25SAdrian Hunter {
147ef149c25SAdrian Hunter 	struct record *rec = container_of(tool, struct record, tool);
14899fa2984SAdrian Hunter 	struct perf_data_file *file = &rec->file;
149ef149c25SAdrian Hunter 	size_t padding;
150ef149c25SAdrian Hunter 	u8 pad[8] = {0};
151ef149c25SAdrian Hunter 
15299fa2984SAdrian Hunter 	if (!perf_data_file__is_pipe(file)) {
15399fa2984SAdrian Hunter 		off_t file_offset;
15499fa2984SAdrian Hunter 		int fd = perf_data_file__fd(file);
15599fa2984SAdrian Hunter 		int err;
15699fa2984SAdrian Hunter 
15799fa2984SAdrian Hunter 		file_offset = lseek(fd, 0, SEEK_CUR);
15899fa2984SAdrian Hunter 		if (file_offset == -1)
15999fa2984SAdrian Hunter 			return -1;
16099fa2984SAdrian Hunter 		err = auxtrace_index__auxtrace_event(&rec->session->auxtrace_index,
16199fa2984SAdrian Hunter 						     event, file_offset);
16299fa2984SAdrian Hunter 		if (err)
16399fa2984SAdrian Hunter 			return err;
16499fa2984SAdrian Hunter 	}
16599fa2984SAdrian Hunter 
166ef149c25SAdrian Hunter 	/* event.auxtrace.size includes padding, see __auxtrace_mmap__read() */
167ef149c25SAdrian Hunter 	padding = (len1 + len2) & 7;
168ef149c25SAdrian Hunter 	if (padding)
169ef149c25SAdrian Hunter 		padding = 8 - padding;
170ef149c25SAdrian Hunter 
171ef149c25SAdrian Hunter 	record__write(rec, event, event->header.size);
172ef149c25SAdrian Hunter 	record__write(rec, data1, len1);
173ef149c25SAdrian Hunter 	if (len2)
174ef149c25SAdrian Hunter 		record__write(rec, data2, len2);
175ef149c25SAdrian Hunter 	record__write(rec, &pad, padding);
176ef149c25SAdrian Hunter 
177ef149c25SAdrian Hunter 	return 0;
178ef149c25SAdrian Hunter }
179ef149c25SAdrian Hunter 
180ef149c25SAdrian Hunter static int record__auxtrace_mmap_read(struct record *rec,
181ef149c25SAdrian Hunter 				      struct auxtrace_mmap *mm)
182ef149c25SAdrian Hunter {
183ef149c25SAdrian Hunter 	int ret;
184ef149c25SAdrian Hunter 
185ef149c25SAdrian Hunter 	ret = auxtrace_mmap__read(mm, rec->itr, &rec->tool,
186ef149c25SAdrian Hunter 				  record__process_auxtrace);
187ef149c25SAdrian Hunter 	if (ret < 0)
188ef149c25SAdrian Hunter 		return ret;
189ef149c25SAdrian Hunter 
190ef149c25SAdrian Hunter 	if (ret)
191ef149c25SAdrian Hunter 		rec->samples++;
192ef149c25SAdrian Hunter 
193ef149c25SAdrian Hunter 	return 0;
194ef149c25SAdrian Hunter }
195ef149c25SAdrian Hunter 
196*2dd6d8a1SAdrian Hunter static int record__auxtrace_mmap_read_snapshot(struct record *rec,
197*2dd6d8a1SAdrian Hunter 					       struct auxtrace_mmap *mm)
198*2dd6d8a1SAdrian Hunter {
199*2dd6d8a1SAdrian Hunter 	int ret;
200*2dd6d8a1SAdrian Hunter 
201*2dd6d8a1SAdrian Hunter 	ret = auxtrace_mmap__read_snapshot(mm, rec->itr, &rec->tool,
202*2dd6d8a1SAdrian Hunter 					   record__process_auxtrace,
203*2dd6d8a1SAdrian Hunter 					   rec->opts.auxtrace_snapshot_size);
204*2dd6d8a1SAdrian Hunter 	if (ret < 0)
205*2dd6d8a1SAdrian Hunter 		return ret;
206*2dd6d8a1SAdrian Hunter 
207*2dd6d8a1SAdrian Hunter 	if (ret)
208*2dd6d8a1SAdrian Hunter 		rec->samples++;
209*2dd6d8a1SAdrian Hunter 
210*2dd6d8a1SAdrian Hunter 	return 0;
211*2dd6d8a1SAdrian Hunter }
212*2dd6d8a1SAdrian Hunter 
213*2dd6d8a1SAdrian Hunter static int record__auxtrace_read_snapshot_all(struct record *rec)
214*2dd6d8a1SAdrian Hunter {
215*2dd6d8a1SAdrian Hunter 	int i;
216*2dd6d8a1SAdrian Hunter 	int rc = 0;
217*2dd6d8a1SAdrian Hunter 
218*2dd6d8a1SAdrian Hunter 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
219*2dd6d8a1SAdrian Hunter 		struct auxtrace_mmap *mm =
220*2dd6d8a1SAdrian Hunter 				&rec->evlist->mmap[i].auxtrace_mmap;
221*2dd6d8a1SAdrian Hunter 
222*2dd6d8a1SAdrian Hunter 		if (!mm->base)
223*2dd6d8a1SAdrian Hunter 			continue;
224*2dd6d8a1SAdrian Hunter 
225*2dd6d8a1SAdrian Hunter 		if (record__auxtrace_mmap_read_snapshot(rec, mm) != 0) {
226*2dd6d8a1SAdrian Hunter 			rc = -1;
227*2dd6d8a1SAdrian Hunter 			goto out;
228*2dd6d8a1SAdrian Hunter 		}
229*2dd6d8a1SAdrian Hunter 	}
230*2dd6d8a1SAdrian Hunter out:
231*2dd6d8a1SAdrian Hunter 	return rc;
232*2dd6d8a1SAdrian Hunter }
233*2dd6d8a1SAdrian Hunter 
234*2dd6d8a1SAdrian Hunter static void record__read_auxtrace_snapshot(struct record *rec)
235*2dd6d8a1SAdrian Hunter {
236*2dd6d8a1SAdrian Hunter 	pr_debug("Recording AUX area tracing snapshot\n");
237*2dd6d8a1SAdrian Hunter 	if (record__auxtrace_read_snapshot_all(rec) < 0) {
238*2dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = -1;
239*2dd6d8a1SAdrian Hunter 	} else {
240*2dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr);
241*2dd6d8a1SAdrian Hunter 		if (!auxtrace_snapshot_err)
242*2dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 1;
243*2dd6d8a1SAdrian Hunter 	}
244*2dd6d8a1SAdrian Hunter }
245*2dd6d8a1SAdrian Hunter 
246e31f0d01SAdrian Hunter #else
247e31f0d01SAdrian Hunter 
248e31f0d01SAdrian Hunter static inline
249e31f0d01SAdrian Hunter int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
250e31f0d01SAdrian Hunter 			       struct auxtrace_mmap *mm __maybe_unused)
251e31f0d01SAdrian Hunter {
252e31f0d01SAdrian Hunter 	return 0;
253e31f0d01SAdrian Hunter }
254e31f0d01SAdrian Hunter 
255*2dd6d8a1SAdrian Hunter static inline
256*2dd6d8a1SAdrian Hunter void record__read_auxtrace_snapshot(struct record *rec __maybe_unused)
257*2dd6d8a1SAdrian Hunter {
258*2dd6d8a1SAdrian Hunter }
259*2dd6d8a1SAdrian Hunter 
260*2dd6d8a1SAdrian Hunter static inline
261*2dd6d8a1SAdrian Hunter int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused)
262*2dd6d8a1SAdrian Hunter {
263*2dd6d8a1SAdrian Hunter 	return 0;
264*2dd6d8a1SAdrian Hunter }
265*2dd6d8a1SAdrian Hunter 
266e31f0d01SAdrian Hunter #endif
267e31f0d01SAdrian Hunter 
2688c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
269dd7927f4SArnaldo Carvalho de Melo {
27056e52e85SArnaldo Carvalho de Melo 	char msg[512];
2716a4bb04cSJiri Olsa 	struct perf_evsel *pos;
272d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
273d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
274b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
2758d3eca20SDavid Ahern 	int rc = 0;
276dd7927f4SArnaldo Carvalho de Melo 
277f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
278cac21425SJiri Olsa 
2790050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
2803da297a6SIngo Molnar try_again:
2816a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
28256e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2833da297a6SIngo Molnar 				if (verbose)
284c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2853da297a6SIngo Molnar 				goto try_again;
2863da297a6SIngo Molnar 			}
287ca6a4258SDavid Ahern 
28856e52e85SArnaldo Carvalho de Melo 			rc = -errno;
28956e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
29056e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
29156e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
2928d3eca20SDavid Ahern 			goto out;
2937c6a1c65SPeter Zijlstra 		}
2947c6a1c65SPeter Zijlstra 	}
2957c6a1c65SPeter Zijlstra 
29623d4aad4SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist, &pos)) {
29723d4aad4SArnaldo Carvalho de Melo 		error("failed to set filter \"%s\" on event %s with %d (%s)\n",
29823d4aad4SArnaldo Carvalho de Melo 			pos->filter, perf_evsel__name(pos), errno,
29935550da3SMasami Hiramatsu 			strerror_r(errno, msg, sizeof(msg)));
3008d3eca20SDavid Ahern 		rc = -1;
3018d3eca20SDavid Ahern 		goto out;
3020a102479SFrederic Weisbecker 	}
3030a102479SFrederic Weisbecker 
304ef149c25SAdrian Hunter 	if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
305*2dd6d8a1SAdrian Hunter 				 opts->auxtrace_mmap_pages,
306*2dd6d8a1SAdrian Hunter 				 opts->auxtrace_snapshot_mode) < 0) {
3078d3eca20SDavid Ahern 		if (errno == EPERM) {
3088d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
30918e60939SNelson Elhage 			       "Consider increasing "
31018e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
31118e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
312ef149c25SAdrian Hunter 			       "(current value: %u,%u)\n",
313ef149c25SAdrian Hunter 			       opts->mmap_pages, opts->auxtrace_mmap_pages);
3148d3eca20SDavid Ahern 			rc = -errno;
3158d3eca20SDavid Ahern 		} else {
31635550da3SMasami Hiramatsu 			pr_err("failed to mmap with %d (%s)\n", errno,
31735550da3SMasami Hiramatsu 				strerror_r(errno, msg, sizeof(msg)));
3188d3eca20SDavid Ahern 			rc = -errno;
3198d3eca20SDavid Ahern 		}
3208d3eca20SDavid Ahern 		goto out;
32118e60939SNelson Elhage 	}
3220a27d7f9SArnaldo Carvalho de Melo 
323a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
3247b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
3258d3eca20SDavid Ahern out:
3268d3eca20SDavid Ahern 	return rc;
327a91e5431SArnaldo Carvalho de Melo }
328a91e5431SArnaldo Carvalho de Melo 
329e3d59112SNamhyung Kim static int process_sample_event(struct perf_tool *tool,
330e3d59112SNamhyung Kim 				union perf_event *event,
331e3d59112SNamhyung Kim 				struct perf_sample *sample,
332e3d59112SNamhyung Kim 				struct perf_evsel *evsel,
333e3d59112SNamhyung Kim 				struct machine *machine)
334e3d59112SNamhyung Kim {
335e3d59112SNamhyung Kim 	struct record *rec = container_of(tool, struct record, tool);
336e3d59112SNamhyung Kim 
337e3d59112SNamhyung Kim 	rec->samples++;
338e3d59112SNamhyung Kim 
339e3d59112SNamhyung Kim 	return build_id__mark_dso_hit(tool, event, sample, evsel, machine);
340e3d59112SNamhyung Kim }
341e3d59112SNamhyung Kim 
3428c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
3436122e4e4SArnaldo Carvalho de Melo {
344f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
345f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
3466122e4e4SArnaldo Carvalho de Melo 
34742aa276fSNamhyung Kim 	u64 size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
3489f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
3499f591fd7SArnaldo Carvalho de Melo 		return 0;
3509f591fd7SArnaldo Carvalho de Melo 
3514ac30cf7SNamhyung Kim 	file->size = size;
3524ac30cf7SNamhyung Kim 
35300dc8657SNamhyung Kim 	/*
35400dc8657SNamhyung Kim 	 * During this process, it'll load kernel map and replace the
35500dc8657SNamhyung Kim 	 * dso->long_name to a real pathname it found.  In this case
35600dc8657SNamhyung Kim 	 * we prefer the vmlinux path like
35700dc8657SNamhyung Kim 	 *   /lib/modules/3.16.4/build/vmlinux
35800dc8657SNamhyung Kim 	 *
35900dc8657SNamhyung Kim 	 * rather than build-id path (in debug directory).
36000dc8657SNamhyung Kim 	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
36100dc8657SNamhyung Kim 	 */
36200dc8657SNamhyung Kim 	symbol_conf.ignore_vmlinux_buildid = true;
36300dc8657SNamhyung Kim 
364b7b61cbeSArnaldo Carvalho de Melo 	return perf_session__process_events(session);
3656122e4e4SArnaldo Carvalho de Melo }
3666122e4e4SArnaldo Carvalho de Melo 
3678115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
368a1645ce1SZhang, Yanmin {
369a1645ce1SZhang, Yanmin 	int err;
37045694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
371a1645ce1SZhang, Yanmin 	/*
372a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
373a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
374a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
375a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
376a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
377a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
378a1645ce1SZhang, Yanmin 	 */
37945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
380743eb868SArnaldo Carvalho de Melo 					     machine);
381a1645ce1SZhang, Yanmin 	if (err < 0)
382a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
38323346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
384a1645ce1SZhang, Yanmin 
385a1645ce1SZhang, Yanmin 	/*
386a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
387a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
388a1645ce1SZhang, Yanmin 	 */
38945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
3900ae617beSAdrian Hunter 						 machine);
391a1645ce1SZhang, Yanmin 	if (err < 0)
392a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
39323346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
394a1645ce1SZhang, Yanmin }
395a1645ce1SZhang, Yanmin 
39698402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
39798402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
39898402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
39998402807SFrederic Weisbecker };
40098402807SFrederic Weisbecker 
4018c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
40298402807SFrederic Weisbecker {
403dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
4040e2e63ddSPeter Zijlstra 	int i;
4058d3eca20SDavid Ahern 	int rc = 0;
40698402807SFrederic Weisbecker 
407d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
408ef149c25SAdrian Hunter 		struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap;
409ef149c25SAdrian Hunter 
4108d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
411e5685730SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, i) != 0) {
4128d3eca20SDavid Ahern 				rc = -1;
4138d3eca20SDavid Ahern 				goto out;
4148d3eca20SDavid Ahern 			}
4158d3eca20SDavid Ahern 		}
416ef149c25SAdrian Hunter 
417*2dd6d8a1SAdrian Hunter 		if (mm->base && !rec->opts.auxtrace_snapshot_mode &&
418ef149c25SAdrian Hunter 		    record__auxtrace_mmap_read(rec, mm) != 0) {
419ef149c25SAdrian Hunter 			rc = -1;
420ef149c25SAdrian Hunter 			goto out;
421ef149c25SAdrian Hunter 		}
42298402807SFrederic Weisbecker 	}
42398402807SFrederic Weisbecker 
424dcabb507SJiri Olsa 	/*
425dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
426dcabb507SJiri Olsa 	 * at least one event.
427dcabb507SJiri Olsa 	 */
428dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
4298c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
4308d3eca20SDavid Ahern 
4318d3eca20SDavid Ahern out:
4328d3eca20SDavid Ahern 	return rc;
43398402807SFrederic Weisbecker }
43498402807SFrederic Weisbecker 
4358c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
43657706abcSDavid Ahern {
43757706abcSDavid Ahern 	struct perf_session *session = rec->session;
43857706abcSDavid Ahern 	int feat;
43957706abcSDavid Ahern 
44057706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
44157706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
44257706abcSDavid Ahern 
44357706abcSDavid Ahern 	if (rec->no_buildid)
44457706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
44557706abcSDavid Ahern 
4463e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
44757706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
44857706abcSDavid Ahern 
44957706abcSDavid Ahern 	if (!rec->opts.branch_stack)
45057706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
451ef149c25SAdrian Hunter 
452ef149c25SAdrian Hunter 	if (!rec->opts.full_auxtrace)
453ef149c25SAdrian Hunter 		perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
45457706abcSDavid Ahern }
45557706abcSDavid Ahern 
456f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
457f33cbe72SArnaldo Carvalho de Melo 
458f33cbe72SArnaldo Carvalho de Melo /*
459f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
460f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
461f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
462f33cbe72SArnaldo Carvalho de Melo  */
46345604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
46445604710SNamhyung Kim 					siginfo_t *info,
465f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
466f33cbe72SArnaldo Carvalho de Melo {
467f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
468f33cbe72SArnaldo Carvalho de Melo 	done = 1;
469f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
470f33cbe72SArnaldo Carvalho de Melo }
471f33cbe72SArnaldo Carvalho de Melo 
472*2dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig);
473*2dd6d8a1SAdrian Hunter 
4748c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
47586470930SIngo Molnar {
47657706abcSDavid Ahern 	int err;
47745604710SNamhyung Kim 	int status = 0;
4788b412664SPeter Zijlstra 	unsigned long waking = 0;
47946be604bSZhang, Yanmin 	const bool forks = argc > 0;
48023346f21SArnaldo Carvalho de Melo 	struct machine *machine;
48145694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
482b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
483f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
484d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
4856dcf45efSArnaldo Carvalho de Melo 	bool disabled = false, draining = false;
48642aa276fSNamhyung Kim 	int fd;
48786470930SIngo Molnar 
488d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
48933e49ea7SAndi Kleen 
49045604710SNamhyung Kim 	atexit(record__sig_exit);
491f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
492f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
493804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
494*2dd6d8a1SAdrian Hunter 	if (rec->opts.auxtrace_snapshot_mode)
495*2dd6d8a1SAdrian Hunter 		signal(SIGUSR2, snapshot_sig_handler);
496*2dd6d8a1SAdrian Hunter 	else
497*2dd6d8a1SAdrian Hunter 		signal(SIGUSR2, SIG_IGN);
498f5970550SPeter Zijlstra 
499b7b61cbeSArnaldo Carvalho de Melo 	session = perf_session__new(file, false, tool);
50094c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
501ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
502a9a70bbcSArnaldo Carvalho de Melo 		return -1;
503a9a70bbcSArnaldo Carvalho de Melo 	}
504a9a70bbcSArnaldo Carvalho de Melo 
50542aa276fSNamhyung Kim 	fd = perf_data_file__fd(file);
506d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
507d20deb64SArnaldo Carvalho de Melo 
5088c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
509330aa675SStephane Eranian 
510d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
5113e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
512f5fc1412SJiri Olsa 						    argv, file->is_pipe,
513735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
51435b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
51535b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
51645604710SNamhyung Kim 			status = err;
51735b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
518856e9660SPeter Zijlstra 		}
519856e9660SPeter Zijlstra 	}
520856e9660SPeter Zijlstra 
5218c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
5228d3eca20SDavid Ahern 		err = -1;
52345604710SNamhyung Kim 		goto out_child;
5248d3eca20SDavid Ahern 	}
52586470930SIngo Molnar 
5263e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
527a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
528a8bb559bSNamhyung Kim 
529f5fc1412SJiri Olsa 	if (file->is_pipe) {
53042aa276fSNamhyung Kim 		err = perf_header__write_pipe(fd);
531529870e3STom Zanussi 		if (err < 0)
53245604710SNamhyung Kim 			goto out_child;
533563aecb2SJiri Olsa 	} else {
53442aa276fSNamhyung Kim 		err = perf_session__write_header(session, rec->evlist, fd, false);
535d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
53645604710SNamhyung Kim 			goto out_child;
537d5eed904SArnaldo Carvalho de Melo 	}
5387c6a1c65SPeter Zijlstra 
539d3665498SDavid Ahern 	if (!rec->no_buildid
540e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
541d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
542e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
5438d3eca20SDavid Ahern 		err = -1;
54445604710SNamhyung Kim 		goto out_child;
545e20960c0SRobert Richter 	}
546e20960c0SRobert Richter 
54734ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
548743eb868SArnaldo Carvalho de Melo 
549f5fc1412SJiri Olsa 	if (file->is_pipe) {
55045694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
551a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
5522c46dbb5STom Zanussi 		if (err < 0) {
5532c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
55445604710SNamhyung Kim 			goto out_child;
5552c46dbb5STom Zanussi 		}
556cd19a035STom Zanussi 
5573e2be2daSArnaldo Carvalho de Melo 		if (have_tracepoints(&rec->evlist->entries)) {
55863e0c771STom Zanussi 			/*
55963e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
56063e0c771STom Zanussi 			 * there were no tracepoints so its not really
56163e0c771STom Zanussi 			 * an error, just that we don't need to
56263e0c771STom Zanussi 			 * synthesize anything.  We really have to
56363e0c771STom Zanussi 			 * return this more properly and also
56463e0c771STom Zanussi 			 * propagate errors that now are calling die()
56563e0c771STom Zanussi 			 */
56642aa276fSNamhyung Kim 			err = perf_event__synthesize_tracing_data(tool,	fd, rec->evlist,
567743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
56863e0c771STom Zanussi 			if (err <= 0) {
56963e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
57045604710SNamhyung Kim 				goto out_child;
57163e0c771STom Zanussi 			}
572f34b9001SDavid Ahern 			rec->bytes_written += err;
5732c46dbb5STom Zanussi 		}
57463e0c771STom Zanussi 	}
5752c46dbb5STom Zanussi 
576ef149c25SAdrian Hunter 	if (rec->opts.full_auxtrace) {
577ef149c25SAdrian Hunter 		err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
578ef149c25SAdrian Hunter 					session, process_synthesized_event);
579ef149c25SAdrian Hunter 		if (err)
580ef149c25SAdrian Hunter 			goto out_delete_session;
581ef149c25SAdrian Hunter 	}
582ef149c25SAdrian Hunter 
58345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
5840ae617beSAdrian Hunter 						 machine);
585c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
586c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
587c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
588c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
58956b03f3cSArnaldo Carvalho de Melo 
59045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
591743eb868SArnaldo Carvalho de Melo 					     machine);
592c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
593c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
594c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
595c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
596c1a3a4b9SArnaldo Carvalho de Melo 
5977e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
598876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
5997e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
6007e383de4SArnaldo Carvalho de Melo 	}
601b7cece76SArnaldo Carvalho de Melo 
6023e2be2daSArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
60358d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
6048d3eca20SDavid Ahern 	if (err != 0)
60545604710SNamhyung Kim 		goto out_child;
6068d3eca20SDavid Ahern 
607d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
60886470930SIngo Molnar 		struct sched_param param;
60986470930SIngo Molnar 
610d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
61186470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
6126beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
6138d3eca20SDavid Ahern 			err = -1;
61445604710SNamhyung Kim 			goto out_child;
61586470930SIngo Molnar 		}
61686470930SIngo Molnar 	}
61786470930SIngo Molnar 
618774cb499SJiri Olsa 	/*
619774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
620774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
621774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
622774cb499SJiri Olsa 	 */
6236619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
6243e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
625764e16a3SDavid Ahern 
626856e9660SPeter Zijlstra 	/*
627856e9660SPeter Zijlstra 	 * Let the child rip
628856e9660SPeter Zijlstra 	 */
629735f7e0bSArnaldo Carvalho de Melo 	if (forks)
6303e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
631856e9660SPeter Zijlstra 
6326619a53eSAndi Kleen 	if (opts->initial_delay) {
6336619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
6346619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
6356619a53eSAndi Kleen 	}
6366619a53eSAndi Kleen 
637*2dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 1;
638649c48a9SPeter Zijlstra 	for (;;) {
639d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
64086470930SIngo Molnar 
6418c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
642*2dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
6438d3eca20SDavid Ahern 			err = -1;
64445604710SNamhyung Kim 			goto out_child;
6458d3eca20SDavid Ahern 		}
64686470930SIngo Molnar 
647*2dd6d8a1SAdrian Hunter 		if (auxtrace_record__snapshot_started) {
648*2dd6d8a1SAdrian Hunter 			auxtrace_record__snapshot_started = 0;
649*2dd6d8a1SAdrian Hunter 			if (!auxtrace_snapshot_err)
650*2dd6d8a1SAdrian Hunter 				record__read_auxtrace_snapshot(rec);
651*2dd6d8a1SAdrian Hunter 			if (auxtrace_snapshot_err) {
652*2dd6d8a1SAdrian Hunter 				pr_err("AUX area tracing snapshot failed\n");
653*2dd6d8a1SAdrian Hunter 				err = -1;
654*2dd6d8a1SAdrian Hunter 				goto out_child;
655*2dd6d8a1SAdrian Hunter 			}
656*2dd6d8a1SAdrian Hunter 		}
657*2dd6d8a1SAdrian Hunter 
658d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
6596dcf45efSArnaldo Carvalho de Melo 			if (done || draining)
660649c48a9SPeter Zijlstra 				break;
661f66a889dSArnaldo Carvalho de Melo 			err = perf_evlist__poll(rec->evlist, -1);
662a515114fSJiri Olsa 			/*
663a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
664a515114fSJiri Olsa 			 * number of returned events and interrupt error.
665a515114fSJiri Olsa 			 */
666a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
66745604710SNamhyung Kim 				err = 0;
6688b412664SPeter Zijlstra 			waking++;
6696dcf45efSArnaldo Carvalho de Melo 
6706dcf45efSArnaldo Carvalho de Melo 			if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
6716dcf45efSArnaldo Carvalho de Melo 				draining = true;
6728b412664SPeter Zijlstra 		}
6738b412664SPeter Zijlstra 
674774cb499SJiri Olsa 		/*
675774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
676774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
677774cb499SJiri Olsa 		 * disable events in this case.
678774cb499SJiri Olsa 		 */
679602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
680*2dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
6813e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
6822711926aSJiri Olsa 			disabled = true;
6832711926aSJiri Olsa 		}
6848b412664SPeter Zijlstra 	}
685*2dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
6868b412664SPeter Zijlstra 
687f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
68835550da3SMasami Hiramatsu 		char msg[STRERR_BUFSIZE];
689f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
690f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
691f33cbe72SArnaldo Carvalho de Melo 		err = -1;
69245604710SNamhyung Kim 		goto out_child;
693f33cbe72SArnaldo Carvalho de Melo 	}
694f33cbe72SArnaldo Carvalho de Melo 
695e3d59112SNamhyung Kim 	if (!quiet)
6968b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
69786470930SIngo Molnar 
69845604710SNamhyung Kim out_child:
69945604710SNamhyung Kim 	if (forks) {
70045604710SNamhyung Kim 		int exit_status;
70145604710SNamhyung Kim 
70245604710SNamhyung Kim 		if (!child_finished)
70345604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
70445604710SNamhyung Kim 
70545604710SNamhyung Kim 		wait(&exit_status);
70645604710SNamhyung Kim 
70745604710SNamhyung Kim 		if (err < 0)
70845604710SNamhyung Kim 			status = err;
70945604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
71045604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
71145604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
71245604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
71345604710SNamhyung Kim 	} else
71445604710SNamhyung Kim 		status = err;
71545604710SNamhyung Kim 
716e3d59112SNamhyung Kim 	/* this will be recalculated during process_buildids() */
717e3d59112SNamhyung Kim 	rec->samples = 0;
718e3d59112SNamhyung Kim 
71945604710SNamhyung Kim 	if (!err && !file->is_pipe) {
72045604710SNamhyung Kim 		rec->session->header.data_size += rec->bytes_written;
72145604710SNamhyung Kim 
722cd10b289SAdrian Hunter 		if (!rec->no_buildid) {
72345604710SNamhyung Kim 			process_buildids(rec);
724cd10b289SAdrian Hunter 			/*
725cd10b289SAdrian Hunter 			 * We take all buildids when the file contains
726cd10b289SAdrian Hunter 			 * AUX area tracing data because we do not decode the
727cd10b289SAdrian Hunter 			 * trace because it would take too long.
728cd10b289SAdrian Hunter 			 */
729cd10b289SAdrian Hunter 			if (rec->opts.full_auxtrace)
730cd10b289SAdrian Hunter 				dsos__hit_all(rec->session);
731cd10b289SAdrian Hunter 		}
73242aa276fSNamhyung Kim 		perf_session__write_header(rec->session, rec->evlist, fd, true);
73345604710SNamhyung Kim 	}
73439d17dacSArnaldo Carvalho de Melo 
735e3d59112SNamhyung Kim 	if (!err && !quiet) {
736e3d59112SNamhyung Kim 		char samples[128];
737e3d59112SNamhyung Kim 
738ef149c25SAdrian Hunter 		if (rec->samples && !rec->opts.full_auxtrace)
739e3d59112SNamhyung Kim 			scnprintf(samples, sizeof(samples),
740e3d59112SNamhyung Kim 				  " (%" PRIu64 " samples)", rec->samples);
741e3d59112SNamhyung Kim 		else
742e3d59112SNamhyung Kim 			samples[0] = '\0';
743e3d59112SNamhyung Kim 
744e3d59112SNamhyung Kim 		fprintf(stderr,	"[ perf record: Captured and wrote %.3f MB %s%s ]\n",
745e3d59112SNamhyung Kim 			perf_data_file__size(file) / 1024.0 / 1024.0,
746e3d59112SNamhyung Kim 			file->path, samples);
747e3d59112SNamhyung Kim 	}
748e3d59112SNamhyung Kim 
74939d17dacSArnaldo Carvalho de Melo out_delete_session:
75039d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
75145604710SNamhyung Kim 	return status;
75286470930SIngo Molnar }
75386470930SIngo Molnar 
754bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
755bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
756bdfebd84SRoberto Agostino Vitillo 
757bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
758bdfebd84SRoberto Agostino Vitillo 
759bdfebd84SRoberto Agostino Vitillo struct branch_mode {
760bdfebd84SRoberto Agostino Vitillo 	const char *name;
761bdfebd84SRoberto Agostino Vitillo 	int mode;
762bdfebd84SRoberto Agostino Vitillo };
763bdfebd84SRoberto Agostino Vitillo 
764bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
765bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
766bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
767bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
768bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
769bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
770bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
771bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
7720126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
7730126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
7740126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
7750fffa5dfSAnshuman Khandual 	BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
776bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
777bdfebd84SRoberto Agostino Vitillo };
778bdfebd84SRoberto Agostino Vitillo 
779bdfebd84SRoberto Agostino Vitillo static int
780a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
781bdfebd84SRoberto Agostino Vitillo {
782bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
783bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
784bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
785bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
786bdfebd84SRoberto Agostino Vitillo 
787bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
788bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
789a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
790bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
791bdfebd84SRoberto Agostino Vitillo 
792a5aabdacSStephane Eranian 	if (unset)
793a5aabdacSStephane Eranian 		return 0;
794bdfebd84SRoberto Agostino Vitillo 
795a5aabdacSStephane Eranian 	/*
796a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
797a5aabdacSStephane Eranian 	 */
798a5aabdacSStephane Eranian 	if (*mode)
799a5aabdacSStephane Eranian 		return -1;
800a5aabdacSStephane Eranian 
801a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
802a5aabdacSStephane Eranian 	if (str) {
803bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
804bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
805bdfebd84SRoberto Agostino Vitillo 		if (!s)
806bdfebd84SRoberto Agostino Vitillo 			return -1;
807bdfebd84SRoberto Agostino Vitillo 
808bdfebd84SRoberto Agostino Vitillo 		for (;;) {
809bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
810bdfebd84SRoberto Agostino Vitillo 			if (p)
811bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
812bdfebd84SRoberto Agostino Vitillo 
813bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
814bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
815bdfebd84SRoberto Agostino Vitillo 					break;
816bdfebd84SRoberto Agostino Vitillo 			}
817a5aabdacSStephane Eranian 			if (!br->name) {
818a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
819a5aabdacSStephane Eranian 					    " check man page\n", s);
820bdfebd84SRoberto Agostino Vitillo 				goto error;
821a5aabdacSStephane Eranian 			}
822bdfebd84SRoberto Agostino Vitillo 
823bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
824bdfebd84SRoberto Agostino Vitillo 
825bdfebd84SRoberto Agostino Vitillo 			if (!p)
826bdfebd84SRoberto Agostino Vitillo 				break;
827bdfebd84SRoberto Agostino Vitillo 
828bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
829bdfebd84SRoberto Agostino Vitillo 		}
830a5aabdacSStephane Eranian 	}
831bdfebd84SRoberto Agostino Vitillo 	ret = 0;
832bdfebd84SRoberto Agostino Vitillo 
833a5aabdacSStephane Eranian 	/* default to any branch */
834bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
835a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
836bdfebd84SRoberto Agostino Vitillo 	}
837bdfebd84SRoberto Agostino Vitillo error:
838bdfebd84SRoberto Agostino Vitillo 	free(os);
839bdfebd84SRoberto Agostino Vitillo 	return ret;
840bdfebd84SRoberto Agostino Vitillo }
841bdfebd84SRoberto Agostino Vitillo 
84272a128aaSNamhyung Kim static void callchain_debug(void)
84309b0fd45SJiri Olsa {
844aad2b21cSKan Liang 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" };
845a601fdffSJiri Olsa 
84672a128aaSNamhyung Kim 	pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
84726d33022SJiri Olsa 
84872a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_DWARF)
84909b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
85072a128aaSNamhyung Kim 			 callchain_param.dump_size);
85109b0fd45SJiri Olsa }
85209b0fd45SJiri Olsa 
85372a128aaSNamhyung Kim int record_parse_callchain_opt(const struct option *opt __maybe_unused,
85409b0fd45SJiri Olsa 			       const char *arg,
85509b0fd45SJiri Olsa 			       int unset)
85609b0fd45SJiri Olsa {
85709b0fd45SJiri Olsa 	int ret;
85809b0fd45SJiri Olsa 
85972a128aaSNamhyung Kim 	callchain_param.enabled = !unset;
860eb853e80SJiri Olsa 
86109b0fd45SJiri Olsa 	/* --no-call-graph */
86209b0fd45SJiri Olsa 	if (unset) {
86372a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_NONE;
86409b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
86509b0fd45SJiri Olsa 		return 0;
86609b0fd45SJiri Olsa 	}
86709b0fd45SJiri Olsa 
868f7f084f4SNamhyung Kim 	ret = parse_callchain_record_opt(arg);
86909b0fd45SJiri Olsa 	if (!ret)
87072a128aaSNamhyung Kim 		callchain_debug();
87109b0fd45SJiri Olsa 
87226d33022SJiri Olsa 	return ret;
87326d33022SJiri Olsa }
87426d33022SJiri Olsa 
87572a128aaSNamhyung Kim int record_callchain_opt(const struct option *opt __maybe_unused,
87609b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
87709b0fd45SJiri Olsa 			 int unset __maybe_unused)
87809b0fd45SJiri Olsa {
87972a128aaSNamhyung Kim 	callchain_param.enabled = true;
88009b0fd45SJiri Olsa 
88172a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_NONE)
88272a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_FP;
883eb853e80SJiri Olsa 
88472a128aaSNamhyung Kim 	callchain_debug();
88509b0fd45SJiri Olsa 	return 0;
88609b0fd45SJiri Olsa }
88709b0fd45SJiri Olsa 
888eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
889eb853e80SJiri Olsa {
890eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
8915a2e5e85SNamhyung Kim 		var = "call-graph.record-mode"; /* fall-through */
892eb853e80SJiri Olsa 
893eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
894eb853e80SJiri Olsa }
895eb853e80SJiri Olsa 
896814c8c38SPeter Zijlstra struct clockid_map {
897814c8c38SPeter Zijlstra 	const char *name;
898814c8c38SPeter Zijlstra 	int clockid;
899814c8c38SPeter Zijlstra };
900814c8c38SPeter Zijlstra 
901814c8c38SPeter Zijlstra #define CLOCKID_MAP(n, c)	\
902814c8c38SPeter Zijlstra 	{ .name = n, .clockid = (c), }
903814c8c38SPeter Zijlstra 
904814c8c38SPeter Zijlstra #define CLOCKID_END	{ .name = NULL, }
905814c8c38SPeter Zijlstra 
906814c8c38SPeter Zijlstra 
907814c8c38SPeter Zijlstra /*
908814c8c38SPeter Zijlstra  * Add the missing ones, we need to build on many distros...
909814c8c38SPeter Zijlstra  */
910814c8c38SPeter Zijlstra #ifndef CLOCK_MONOTONIC_RAW
911814c8c38SPeter Zijlstra #define CLOCK_MONOTONIC_RAW 4
912814c8c38SPeter Zijlstra #endif
913814c8c38SPeter Zijlstra #ifndef CLOCK_BOOTTIME
914814c8c38SPeter Zijlstra #define CLOCK_BOOTTIME 7
915814c8c38SPeter Zijlstra #endif
916814c8c38SPeter Zijlstra #ifndef CLOCK_TAI
917814c8c38SPeter Zijlstra #define CLOCK_TAI 11
918814c8c38SPeter Zijlstra #endif
919814c8c38SPeter Zijlstra 
920814c8c38SPeter Zijlstra static const struct clockid_map clockids[] = {
921814c8c38SPeter Zijlstra 	/* available for all events, NMI safe */
922814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic", CLOCK_MONOTONIC),
923814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW),
924814c8c38SPeter Zijlstra 
925814c8c38SPeter Zijlstra 	/* available for some events */
926814c8c38SPeter Zijlstra 	CLOCKID_MAP("realtime", CLOCK_REALTIME),
927814c8c38SPeter Zijlstra 	CLOCKID_MAP("boottime", CLOCK_BOOTTIME),
928814c8c38SPeter Zijlstra 	CLOCKID_MAP("tai", CLOCK_TAI),
929814c8c38SPeter Zijlstra 
930814c8c38SPeter Zijlstra 	/* available for the lazy */
931814c8c38SPeter Zijlstra 	CLOCKID_MAP("mono", CLOCK_MONOTONIC),
932814c8c38SPeter Zijlstra 	CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW),
933814c8c38SPeter Zijlstra 	CLOCKID_MAP("real", CLOCK_REALTIME),
934814c8c38SPeter Zijlstra 	CLOCKID_MAP("boot", CLOCK_BOOTTIME),
935814c8c38SPeter Zijlstra 
936814c8c38SPeter Zijlstra 	CLOCKID_END,
937814c8c38SPeter Zijlstra };
938814c8c38SPeter Zijlstra 
939814c8c38SPeter Zijlstra static int parse_clockid(const struct option *opt, const char *str, int unset)
940814c8c38SPeter Zijlstra {
941814c8c38SPeter Zijlstra 	struct record_opts *opts = (struct record_opts *)opt->value;
942814c8c38SPeter Zijlstra 	const struct clockid_map *cm;
943814c8c38SPeter Zijlstra 	const char *ostr = str;
944814c8c38SPeter Zijlstra 
945814c8c38SPeter Zijlstra 	if (unset) {
946814c8c38SPeter Zijlstra 		opts->use_clockid = 0;
947814c8c38SPeter Zijlstra 		return 0;
948814c8c38SPeter Zijlstra 	}
949814c8c38SPeter Zijlstra 
950814c8c38SPeter Zijlstra 	/* no arg passed */
951814c8c38SPeter Zijlstra 	if (!str)
952814c8c38SPeter Zijlstra 		return 0;
953814c8c38SPeter Zijlstra 
954814c8c38SPeter Zijlstra 	/* no setting it twice */
955814c8c38SPeter Zijlstra 	if (opts->use_clockid)
956814c8c38SPeter Zijlstra 		return -1;
957814c8c38SPeter Zijlstra 
958814c8c38SPeter Zijlstra 	opts->use_clockid = true;
959814c8c38SPeter Zijlstra 
960814c8c38SPeter Zijlstra 	/* if its a number, we're done */
961814c8c38SPeter Zijlstra 	if (sscanf(str, "%d", &opts->clockid) == 1)
962814c8c38SPeter Zijlstra 		return 0;
963814c8c38SPeter Zijlstra 
964814c8c38SPeter Zijlstra 	/* allow a "CLOCK_" prefix to the name */
965814c8c38SPeter Zijlstra 	if (!strncasecmp(str, "CLOCK_", 6))
966814c8c38SPeter Zijlstra 		str += 6;
967814c8c38SPeter Zijlstra 
968814c8c38SPeter Zijlstra 	for (cm = clockids; cm->name; cm++) {
969814c8c38SPeter Zijlstra 		if (!strcasecmp(str, cm->name)) {
970814c8c38SPeter Zijlstra 			opts->clockid = cm->clockid;
971814c8c38SPeter Zijlstra 			return 0;
972814c8c38SPeter Zijlstra 		}
973814c8c38SPeter Zijlstra 	}
974814c8c38SPeter Zijlstra 
975814c8c38SPeter Zijlstra 	opts->use_clockid = false;
976814c8c38SPeter Zijlstra 	ui__warning("unknown clockid %s, check man page\n", ostr);
977814c8c38SPeter Zijlstra 	return -1;
978814c8c38SPeter Zijlstra }
979814c8c38SPeter Zijlstra 
980e9db1310SAdrian Hunter static int record__parse_mmap_pages(const struct option *opt,
981e9db1310SAdrian Hunter 				    const char *str,
982e9db1310SAdrian Hunter 				    int unset __maybe_unused)
983e9db1310SAdrian Hunter {
984e9db1310SAdrian Hunter 	struct record_opts *opts = opt->value;
985e9db1310SAdrian Hunter 	char *s, *p;
986e9db1310SAdrian Hunter 	unsigned int mmap_pages;
987e9db1310SAdrian Hunter 	int ret;
988e9db1310SAdrian Hunter 
989e9db1310SAdrian Hunter 	if (!str)
990e9db1310SAdrian Hunter 		return -EINVAL;
991e9db1310SAdrian Hunter 
992e9db1310SAdrian Hunter 	s = strdup(str);
993e9db1310SAdrian Hunter 	if (!s)
994e9db1310SAdrian Hunter 		return -ENOMEM;
995e9db1310SAdrian Hunter 
996e9db1310SAdrian Hunter 	p = strchr(s, ',');
997e9db1310SAdrian Hunter 	if (p)
998e9db1310SAdrian Hunter 		*p = '\0';
999e9db1310SAdrian Hunter 
1000e9db1310SAdrian Hunter 	if (*s) {
1001e9db1310SAdrian Hunter 		ret = __perf_evlist__parse_mmap_pages(&mmap_pages, s);
1002e9db1310SAdrian Hunter 		if (ret)
1003e9db1310SAdrian Hunter 			goto out_free;
1004e9db1310SAdrian Hunter 		opts->mmap_pages = mmap_pages;
1005e9db1310SAdrian Hunter 	}
1006e9db1310SAdrian Hunter 
1007e9db1310SAdrian Hunter 	if (!p) {
1008e9db1310SAdrian Hunter 		ret = 0;
1009e9db1310SAdrian Hunter 		goto out_free;
1010e9db1310SAdrian Hunter 	}
1011e9db1310SAdrian Hunter 
1012e9db1310SAdrian Hunter 	ret = __perf_evlist__parse_mmap_pages(&mmap_pages, p + 1);
1013e9db1310SAdrian Hunter 	if (ret)
1014e9db1310SAdrian Hunter 		goto out_free;
1015e9db1310SAdrian Hunter 
1016e9db1310SAdrian Hunter 	opts->auxtrace_mmap_pages = mmap_pages;
1017e9db1310SAdrian Hunter 
1018e9db1310SAdrian Hunter out_free:
1019e9db1310SAdrian Hunter 	free(s);
1020e9db1310SAdrian Hunter 	return ret;
1021e9db1310SAdrian Hunter }
1022e9db1310SAdrian Hunter 
1023e5b2c207SNamhyung Kim static const char * const __record_usage[] = {
102486470930SIngo Molnar 	"perf record [<options>] [<command>]",
102586470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
102686470930SIngo Molnar 	NULL
102786470930SIngo Molnar };
1028e5b2c207SNamhyung Kim const char * const *record_usage = __record_usage;
102986470930SIngo Molnar 
1030d20deb64SArnaldo Carvalho de Melo /*
10318c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
10328c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
1033d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
1034d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
1035d20deb64SArnaldo Carvalho de Melo  *
1036d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
1037d20deb64SArnaldo Carvalho de Melo  *
1038d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
1039d20deb64SArnaldo Carvalho de Melo  */
10408c6f45a7SArnaldo Carvalho de Melo static struct record record = {
1041d20deb64SArnaldo Carvalho de Melo 	.opts = {
10428affc2b8SAndi Kleen 		.sample_time	     = true,
1043d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
1044d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
1045d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
1046447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
1047d1cb9fceSNamhyung Kim 		.target		     = {
1048d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
10493aa5939dSAdrian Hunter 			.default_per_cpu = true,
1050d1cb9fceSNamhyung Kim 		},
1051d20deb64SArnaldo Carvalho de Melo 	},
1052e3d59112SNamhyung Kim 	.tool = {
1053e3d59112SNamhyung Kim 		.sample		= process_sample_event,
1054e3d59112SNamhyung Kim 		.fork		= perf_event__process_fork,
1055e3d59112SNamhyung Kim 		.comm		= perf_event__process_comm,
1056e3d59112SNamhyung Kim 		.mmap		= perf_event__process_mmap,
1057e3d59112SNamhyung Kim 		.mmap2		= perf_event__process_mmap2,
1058e3d59112SNamhyung Kim 	},
1059d20deb64SArnaldo Carvalho de Melo };
10607865e817SFrederic Weisbecker 
106109b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
106261eaa3beSArnaldo Carvalho de Melo 
10639ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
1064aad2b21cSKan Liang const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf lbr";
106561eaa3beSArnaldo Carvalho de Melo #else
1066aad2b21cSKan Liang const char record_callchain_help[] = CALLCHAIN_HELP "fp lbr";
106761eaa3beSArnaldo Carvalho de Melo #endif
106861eaa3beSArnaldo Carvalho de Melo 
1069d20deb64SArnaldo Carvalho de Melo /*
1070d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
1071d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
1072b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
1073d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
1074d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
1075d20deb64SArnaldo Carvalho de Melo  */
1076e5b2c207SNamhyung Kim struct option __record_options[] = {
1077d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
107886470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
1079f120f9d5SJiri Olsa 		     parse_events_option),
1080d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
1081c171b552SLi Zefan 		     "event filter", parse_filter),
1082bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
1083d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
1084bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
1085d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
1086d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
108786470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
1088509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
1089acac03faSKirill Smelkov 		    "collect data without buffering"),
1090d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
1091daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
1092bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
109386470930SIngo Molnar 			    "system-wide collection from all CPUs"),
1094bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
1095c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
1096d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
1097f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
109886470930SIngo Molnar 		    "output file name"),
109969e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
110069e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
11012e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
1102d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
1103e9db1310SAdrian Hunter 	OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]",
1104e9db1310SAdrian Hunter 		     "number of mmap data pages and AUX area tracing mmap pages",
1105e9db1310SAdrian Hunter 		     record__parse_mmap_pages),
1106d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
110743bece79SLin Ming 		    "put the counters into a counter group"),
110809b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
110909b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
111009b0fd45SJiri Olsa 			   &record_callchain_opt),
111109b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
111275d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
111309b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
1114c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
11153da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
1116b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
1117d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
1118649c48a9SPeter Zijlstra 		    "per thread counts"),
1119d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
11204bba828dSAnton Blanchard 		    "Sample addresses"),
1121d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
11223e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
1123d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
1124649c48a9SPeter Zijlstra 		    "don't sample"),
1125d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
1126a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
1127d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
1128baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
1129d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
1130023695d9SStephane Eranian 		     "monitor event in cgroup name only",
1131023695d9SStephane Eranian 		     parse_cgroups),
1132a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
11336619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
1134bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
1135bea03405SNamhyung Kim 		   "user to profile"),
1136a5aabdacSStephane Eranian 
1137a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
1138a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
1139a5aabdacSStephane Eranian 		     parse_branch_stack),
1140a5aabdacSStephane Eranian 
1141a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
1142a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
1143bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
114405484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
114505484298SAndi Kleen 		    "sample by weight (on special events only)"),
1146475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
1147475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
11483aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
11493aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
11504b6c5177SStephane Eranian 	OPT_BOOLEAN('I', "intr-regs", &record.opts.sample_intr_regs,
11514b6c5177SStephane Eranian 		    "Sample machine registers on interrupt"),
115285c273d2SAndi Kleen 	OPT_BOOLEAN(0, "running-time", &record.opts.running_time,
115385c273d2SAndi Kleen 		    "Record running/enabled time of read (:S) events"),
1154814c8c38SPeter Zijlstra 	OPT_CALLBACK('k', "clockid", &record.opts,
1155814c8c38SPeter Zijlstra 	"clockid", "clockid to use for events, see clock_gettime()",
1156814c8c38SPeter Zijlstra 	parse_clockid),
1157*2dd6d8a1SAdrian Hunter 	OPT_STRING_OPTARG('S', "snapshot", &record.opts.auxtrace_snapshot_opts,
1158*2dd6d8a1SAdrian Hunter 			  "opts", "AUX area tracing Snapshot Mode", ""),
115986470930SIngo Molnar 	OPT_END()
116086470930SIngo Molnar };
116186470930SIngo Molnar 
1162e5b2c207SNamhyung Kim struct option *record_options = __record_options;
1163e5b2c207SNamhyung Kim 
11641d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
116586470930SIngo Molnar {
1166ef149c25SAdrian Hunter 	int err;
11678c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
116816ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
116986470930SIngo Molnar 
11703e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
11713e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
1172361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
1173361c99a6SArnaldo Carvalho de Melo 
1174eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
1175eb853e80SJiri Olsa 
1176bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
1177a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
1178602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
1179bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
118086470930SIngo Molnar 
1181bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
11823780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
1183023695d9SStephane Eranian 			  " system-wide mode\n");
1184023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
1185023695d9SStephane Eranian 	}
1186023695d9SStephane Eranian 
1187ef149c25SAdrian Hunter 	if (!rec->itr) {
1188ef149c25SAdrian Hunter 		rec->itr = auxtrace_record__init(rec->evlist, &err);
1189ef149c25SAdrian Hunter 		if (err)
1190ef149c25SAdrian Hunter 			return err;
1191ef149c25SAdrian Hunter 	}
1192ef149c25SAdrian Hunter 
1193*2dd6d8a1SAdrian Hunter 	err = auxtrace_parse_snapshot_options(rec->itr, &rec->opts,
1194*2dd6d8a1SAdrian Hunter 					      rec->opts.auxtrace_snapshot_opts);
1195*2dd6d8a1SAdrian Hunter 	if (err)
1196*2dd6d8a1SAdrian Hunter 		return err;
1197*2dd6d8a1SAdrian Hunter 
1198ef149c25SAdrian Hunter 	err = -ENOMEM;
1199ef149c25SAdrian Hunter 
12000a7e6d1bSNamhyung Kim 	symbol__init(NULL);
1201baa2f6ceSArnaldo Carvalho de Melo 
1202ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
1203646aaea6SArnaldo Carvalho de Melo 		pr_warning(
1204646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
1205ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
1206646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
1207646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
1208646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
1209646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
1210646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
1211ec80fde7SArnaldo Carvalho de Melo 
1212d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
1213a1ac1d3cSStephane Eranian 		disable_buildid_cache();
1214655000e7SArnaldo Carvalho de Melo 
12153e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
12163e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
121769aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
121869aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
1219bbd36e5eSPeter Zijlstra 	}
122086470930SIngo Molnar 
122169e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
122269e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
122369e7e5b0SAdrian Hunter 
1224602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
122516ad2ffbSNamhyung Kim 	if (err) {
1226602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
122716ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
122816ad2ffbSNamhyung Kim 	}
12294bd0f2d2SNamhyung Kim 
1230602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
123116ad2ffbSNamhyung Kim 	if (err) {
123216ad2ffbSNamhyung Kim 		int saved_errno = errno;
123316ad2ffbSNamhyung Kim 
1234602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
12353780f488SNamhyung Kim 		ui__error("%s", errbuf);
123616ad2ffbSNamhyung Kim 
123716ad2ffbSNamhyung Kim 		err = -saved_errno;
12388fa60e1fSNamhyung Kim 		goto out_symbol_exit;
123916ad2ffbSNamhyung Kim 	}
12400d37aa34SArnaldo Carvalho de Melo 
124116ad2ffbSNamhyung Kim 	err = -ENOMEM;
12423e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
1243dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
124469aad6f1SArnaldo Carvalho de Melo 
1245ef149c25SAdrian Hunter 	err = auxtrace_record__options(rec->itr, rec->evlist, &rec->opts);
1246ef149c25SAdrian Hunter 	if (err)
1247ef149c25SAdrian Hunter 		goto out_symbol_exit;
1248ef149c25SAdrian Hunter 
1249b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
125039d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
125103ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
12527e4ff9e3SMike Galbraith 	}
12537e4ff9e3SMike Galbraith 
1254d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
1255d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
125645604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
1257d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
1258ef149c25SAdrian Hunter 	auxtrace_record__free(rec->itr);
125939d17dacSArnaldo Carvalho de Melo 	return err;
126086470930SIngo Molnar }
1261*2dd6d8a1SAdrian Hunter 
1262*2dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig __maybe_unused)
1263*2dd6d8a1SAdrian Hunter {
1264*2dd6d8a1SAdrian Hunter 	if (!auxtrace_snapshot_enabled)
1265*2dd6d8a1SAdrian Hunter 		return;
1266*2dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
1267*2dd6d8a1SAdrian Hunter 	auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
1268*2dd6d8a1SAdrian Hunter 	auxtrace_record__snapshot_started = 1;
1269*2dd6d8a1SAdrian Hunter }
1270