xref: /openbmc/linux/tools/perf/builtin-record.c (revision 4b6ab94eabe4f55371cff4569750bb3996c55db6)
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"
14*4b6ab94eSJosh Poimboeuf #include <subcmd/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"
30bcc84ec6SStephane Eranian #include "util/perf_regs.h"
31ef149c25SAdrian Hunter #include "util/auxtrace.h"
32f00898f4SAndi Kleen #include "util/parse-branch-options.h"
33bcc84ec6SStephane Eranian #include "util/parse-regs-options.h"
3471dc2326SWang Nan #include "util/llvm-utils.h"
357c6a1c65SPeter Zijlstra 
3686470930SIngo Molnar #include <unistd.h>
3786470930SIngo Molnar #include <sched.h>
38a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3986470930SIngo Molnar 
4078da39faSBernhard Rosenkraenzer 
418c6f45a7SArnaldo Carvalho de Melo struct record {
4245694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
43b4006796SArnaldo Carvalho de Melo 	struct record_opts	opts;
44d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
45f5fc1412SJiri Olsa 	struct perf_data_file	file;
46ef149c25SAdrian Hunter 	struct auxtrace_record	*itr;
47d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
48d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
49d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
50d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
51d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
52d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
539f065194SYang Shi 	unsigned long long	samples;
540f82ebc4SArnaldo Carvalho de Melo };
5586470930SIngo Molnar 
568c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
57f5970550SPeter Zijlstra {
58cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
594f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
608d3eca20SDavid Ahern 		return -1;
618d3eca20SDavid Ahern 	}
62f5970550SPeter Zijlstra 
63cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
648d3eca20SDavid Ahern 	return 0;
65f5970550SPeter Zijlstra }
66f5970550SPeter Zijlstra 
6745694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
68d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
691d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
701d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
71234fbbf5SArnaldo Carvalho de Melo {
728c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
738c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
74234fbbf5SArnaldo Carvalho de Melo }
75234fbbf5SArnaldo Carvalho de Melo 
76e5685730SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, int idx)
7786470930SIngo Molnar {
78e5685730SArnaldo Carvalho de Melo 	struct perf_mmap *md = &rec->evlist->mmap[idx];
797b8283b5SDavid Ahern 	u64 head = perf_mmap__read_head(md);
807b8283b5SDavid Ahern 	u64 old = md->prev;
81918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
8286470930SIngo Molnar 	unsigned long size;
8386470930SIngo Molnar 	void *buf;
848d3eca20SDavid Ahern 	int rc = 0;
8586470930SIngo Molnar 
86dc82009aSArnaldo Carvalho de Melo 	if (old == head)
878d3eca20SDavid Ahern 		return 0;
8886470930SIngo Molnar 
89d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
9086470930SIngo Molnar 
9186470930SIngo Molnar 	size = head - old;
9286470930SIngo Molnar 
9386470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
9486470930SIngo Molnar 		buf = &data[old & md->mask];
9586470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
9686470930SIngo Molnar 		old += size;
9786470930SIngo Molnar 
988c6f45a7SArnaldo Carvalho de Melo 		if (record__write(rec, buf, size) < 0) {
998d3eca20SDavid Ahern 			rc = -1;
1008d3eca20SDavid Ahern 			goto out;
1018d3eca20SDavid Ahern 		}
10286470930SIngo Molnar 	}
10386470930SIngo Molnar 
10486470930SIngo Molnar 	buf = &data[old & md->mask];
10586470930SIngo Molnar 	size = head - old;
10686470930SIngo Molnar 	old += size;
10786470930SIngo Molnar 
1088c6f45a7SArnaldo Carvalho de Melo 	if (record__write(rec, buf, size) < 0) {
1098d3eca20SDavid Ahern 		rc = -1;
1108d3eca20SDavid Ahern 		goto out;
1118d3eca20SDavid Ahern 	}
11286470930SIngo Molnar 
11386470930SIngo Molnar 	md->prev = old;
114e5685730SArnaldo Carvalho de Melo 	perf_evlist__mmap_consume(rec->evlist, idx);
1158d3eca20SDavid Ahern out:
1168d3eca20SDavid Ahern 	return rc;
11786470930SIngo Molnar }
11886470930SIngo Molnar 
1192dd6d8a1SAdrian Hunter static volatile int done;
1202dd6d8a1SAdrian Hunter static volatile int signr = -1;
1212dd6d8a1SAdrian Hunter static volatile int child_finished;
1222dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_enabled;
1232dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_err;
1242dd6d8a1SAdrian Hunter static volatile int auxtrace_record__snapshot_started;
1252dd6d8a1SAdrian Hunter 
1262dd6d8a1SAdrian Hunter static void sig_handler(int sig)
1272dd6d8a1SAdrian Hunter {
1282dd6d8a1SAdrian Hunter 	if (sig == SIGCHLD)
1292dd6d8a1SAdrian Hunter 		child_finished = 1;
1302dd6d8a1SAdrian Hunter 	else
1312dd6d8a1SAdrian Hunter 		signr = sig;
1322dd6d8a1SAdrian Hunter 
1332dd6d8a1SAdrian Hunter 	done = 1;
1342dd6d8a1SAdrian Hunter }
1352dd6d8a1SAdrian Hunter 
1362dd6d8a1SAdrian Hunter static void record__sig_exit(void)
1372dd6d8a1SAdrian Hunter {
1382dd6d8a1SAdrian Hunter 	if (signr == -1)
1392dd6d8a1SAdrian Hunter 		return;
1402dd6d8a1SAdrian Hunter 
1412dd6d8a1SAdrian Hunter 	signal(signr, SIG_DFL);
1422dd6d8a1SAdrian Hunter 	raise(signr);
1432dd6d8a1SAdrian Hunter }
1442dd6d8a1SAdrian Hunter 
145e31f0d01SAdrian Hunter #ifdef HAVE_AUXTRACE_SUPPORT
146e31f0d01SAdrian Hunter 
147ef149c25SAdrian Hunter static int record__process_auxtrace(struct perf_tool *tool,
148ef149c25SAdrian Hunter 				    union perf_event *event, void *data1,
149ef149c25SAdrian Hunter 				    size_t len1, void *data2, size_t len2)
150ef149c25SAdrian Hunter {
151ef149c25SAdrian Hunter 	struct record *rec = container_of(tool, struct record, tool);
15299fa2984SAdrian Hunter 	struct perf_data_file *file = &rec->file;
153ef149c25SAdrian Hunter 	size_t padding;
154ef149c25SAdrian Hunter 	u8 pad[8] = {0};
155ef149c25SAdrian Hunter 
15699fa2984SAdrian Hunter 	if (!perf_data_file__is_pipe(file)) {
15799fa2984SAdrian Hunter 		off_t file_offset;
15899fa2984SAdrian Hunter 		int fd = perf_data_file__fd(file);
15999fa2984SAdrian Hunter 		int err;
16099fa2984SAdrian Hunter 
16199fa2984SAdrian Hunter 		file_offset = lseek(fd, 0, SEEK_CUR);
16299fa2984SAdrian Hunter 		if (file_offset == -1)
16399fa2984SAdrian Hunter 			return -1;
16499fa2984SAdrian Hunter 		err = auxtrace_index__auxtrace_event(&rec->session->auxtrace_index,
16599fa2984SAdrian Hunter 						     event, file_offset);
16699fa2984SAdrian Hunter 		if (err)
16799fa2984SAdrian Hunter 			return err;
16899fa2984SAdrian Hunter 	}
16999fa2984SAdrian Hunter 
170ef149c25SAdrian Hunter 	/* event.auxtrace.size includes padding, see __auxtrace_mmap__read() */
171ef149c25SAdrian Hunter 	padding = (len1 + len2) & 7;
172ef149c25SAdrian Hunter 	if (padding)
173ef149c25SAdrian Hunter 		padding = 8 - padding;
174ef149c25SAdrian Hunter 
175ef149c25SAdrian Hunter 	record__write(rec, event, event->header.size);
176ef149c25SAdrian Hunter 	record__write(rec, data1, len1);
177ef149c25SAdrian Hunter 	if (len2)
178ef149c25SAdrian Hunter 		record__write(rec, data2, len2);
179ef149c25SAdrian Hunter 	record__write(rec, &pad, padding);
180ef149c25SAdrian Hunter 
181ef149c25SAdrian Hunter 	return 0;
182ef149c25SAdrian Hunter }
183ef149c25SAdrian Hunter 
184ef149c25SAdrian Hunter static int record__auxtrace_mmap_read(struct record *rec,
185ef149c25SAdrian Hunter 				      struct auxtrace_mmap *mm)
186ef149c25SAdrian Hunter {
187ef149c25SAdrian Hunter 	int ret;
188ef149c25SAdrian Hunter 
189ef149c25SAdrian Hunter 	ret = auxtrace_mmap__read(mm, rec->itr, &rec->tool,
190ef149c25SAdrian Hunter 				  record__process_auxtrace);
191ef149c25SAdrian Hunter 	if (ret < 0)
192ef149c25SAdrian Hunter 		return ret;
193ef149c25SAdrian Hunter 
194ef149c25SAdrian Hunter 	if (ret)
195ef149c25SAdrian Hunter 		rec->samples++;
196ef149c25SAdrian Hunter 
197ef149c25SAdrian Hunter 	return 0;
198ef149c25SAdrian Hunter }
199ef149c25SAdrian Hunter 
2002dd6d8a1SAdrian Hunter static int record__auxtrace_mmap_read_snapshot(struct record *rec,
2012dd6d8a1SAdrian Hunter 					       struct auxtrace_mmap *mm)
2022dd6d8a1SAdrian Hunter {
2032dd6d8a1SAdrian Hunter 	int ret;
2042dd6d8a1SAdrian Hunter 
2052dd6d8a1SAdrian Hunter 	ret = auxtrace_mmap__read_snapshot(mm, rec->itr, &rec->tool,
2062dd6d8a1SAdrian Hunter 					   record__process_auxtrace,
2072dd6d8a1SAdrian Hunter 					   rec->opts.auxtrace_snapshot_size);
2082dd6d8a1SAdrian Hunter 	if (ret < 0)
2092dd6d8a1SAdrian Hunter 		return ret;
2102dd6d8a1SAdrian Hunter 
2112dd6d8a1SAdrian Hunter 	if (ret)
2122dd6d8a1SAdrian Hunter 		rec->samples++;
2132dd6d8a1SAdrian Hunter 
2142dd6d8a1SAdrian Hunter 	return 0;
2152dd6d8a1SAdrian Hunter }
2162dd6d8a1SAdrian Hunter 
2172dd6d8a1SAdrian Hunter static int record__auxtrace_read_snapshot_all(struct record *rec)
2182dd6d8a1SAdrian Hunter {
2192dd6d8a1SAdrian Hunter 	int i;
2202dd6d8a1SAdrian Hunter 	int rc = 0;
2212dd6d8a1SAdrian Hunter 
2222dd6d8a1SAdrian Hunter 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
2232dd6d8a1SAdrian Hunter 		struct auxtrace_mmap *mm =
2242dd6d8a1SAdrian Hunter 				&rec->evlist->mmap[i].auxtrace_mmap;
2252dd6d8a1SAdrian Hunter 
2262dd6d8a1SAdrian Hunter 		if (!mm->base)
2272dd6d8a1SAdrian Hunter 			continue;
2282dd6d8a1SAdrian Hunter 
2292dd6d8a1SAdrian Hunter 		if (record__auxtrace_mmap_read_snapshot(rec, mm) != 0) {
2302dd6d8a1SAdrian Hunter 			rc = -1;
2312dd6d8a1SAdrian Hunter 			goto out;
2322dd6d8a1SAdrian Hunter 		}
2332dd6d8a1SAdrian Hunter 	}
2342dd6d8a1SAdrian Hunter out:
2352dd6d8a1SAdrian Hunter 	return rc;
2362dd6d8a1SAdrian Hunter }
2372dd6d8a1SAdrian Hunter 
2382dd6d8a1SAdrian Hunter static void record__read_auxtrace_snapshot(struct record *rec)
2392dd6d8a1SAdrian Hunter {
2402dd6d8a1SAdrian Hunter 	pr_debug("Recording AUX area tracing snapshot\n");
2412dd6d8a1SAdrian Hunter 	if (record__auxtrace_read_snapshot_all(rec) < 0) {
2422dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = -1;
2432dd6d8a1SAdrian Hunter 	} else {
2442dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr);
2452dd6d8a1SAdrian Hunter 		if (!auxtrace_snapshot_err)
2462dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 1;
2472dd6d8a1SAdrian Hunter 	}
2482dd6d8a1SAdrian Hunter }
2492dd6d8a1SAdrian Hunter 
250e31f0d01SAdrian Hunter #else
251e31f0d01SAdrian Hunter 
252e31f0d01SAdrian Hunter static inline
253e31f0d01SAdrian Hunter int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
254e31f0d01SAdrian Hunter 			       struct auxtrace_mmap *mm __maybe_unused)
255e31f0d01SAdrian Hunter {
256e31f0d01SAdrian Hunter 	return 0;
257e31f0d01SAdrian Hunter }
258e31f0d01SAdrian Hunter 
2592dd6d8a1SAdrian Hunter static inline
2602dd6d8a1SAdrian Hunter void record__read_auxtrace_snapshot(struct record *rec __maybe_unused)
2612dd6d8a1SAdrian Hunter {
2622dd6d8a1SAdrian Hunter }
2632dd6d8a1SAdrian Hunter 
2642dd6d8a1SAdrian Hunter static inline
2652dd6d8a1SAdrian Hunter int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused)
2662dd6d8a1SAdrian Hunter {
2672dd6d8a1SAdrian Hunter 	return 0;
2682dd6d8a1SAdrian Hunter }
2692dd6d8a1SAdrian Hunter 
270e31f0d01SAdrian Hunter #endif
271e31f0d01SAdrian Hunter 
2728c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
273dd7927f4SArnaldo Carvalho de Melo {
27456e52e85SArnaldo Carvalho de Melo 	char msg[512];
2756a4bb04cSJiri Olsa 	struct perf_evsel *pos;
276d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
277d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
278b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
2798d3eca20SDavid Ahern 	int rc = 0;
280dd7927f4SArnaldo Carvalho de Melo 
281f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
282cac21425SJiri Olsa 
2830050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
2843da297a6SIngo Molnar try_again:
285d988d5eeSKan Liang 		if (perf_evsel__open(pos, pos->cpus, pos->threads) < 0) {
28656e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2873da297a6SIngo Molnar 				if (verbose)
288c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2893da297a6SIngo Molnar 				goto try_again;
2903da297a6SIngo Molnar 			}
291ca6a4258SDavid Ahern 
29256e52e85SArnaldo Carvalho de Melo 			rc = -errno;
29356e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
29456e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
29556e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
2968d3eca20SDavid Ahern 			goto out;
2977c6a1c65SPeter Zijlstra 		}
2987c6a1c65SPeter Zijlstra 	}
2997c6a1c65SPeter Zijlstra 
30023d4aad4SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist, &pos)) {
30123d4aad4SArnaldo Carvalho de Melo 		error("failed to set filter \"%s\" on event %s with %d (%s)\n",
30223d4aad4SArnaldo Carvalho de Melo 			pos->filter, perf_evsel__name(pos), errno,
30335550da3SMasami Hiramatsu 			strerror_r(errno, msg, sizeof(msg)));
3048d3eca20SDavid Ahern 		rc = -1;
3058d3eca20SDavid Ahern 		goto out;
3060a102479SFrederic Weisbecker 	}
3070a102479SFrederic Weisbecker 
308ef149c25SAdrian Hunter 	if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
3092dd6d8a1SAdrian Hunter 				 opts->auxtrace_mmap_pages,
3102dd6d8a1SAdrian Hunter 				 opts->auxtrace_snapshot_mode) < 0) {
3118d3eca20SDavid Ahern 		if (errno == EPERM) {
3128d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
31318e60939SNelson Elhage 			       "Consider increasing "
31418e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
31518e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
316ef149c25SAdrian Hunter 			       "(current value: %u,%u)\n",
317ef149c25SAdrian Hunter 			       opts->mmap_pages, opts->auxtrace_mmap_pages);
3188d3eca20SDavid Ahern 			rc = -errno;
3198d3eca20SDavid Ahern 		} else {
32035550da3SMasami Hiramatsu 			pr_err("failed to mmap with %d (%s)\n", errno,
32135550da3SMasami Hiramatsu 				strerror_r(errno, msg, sizeof(msg)));
3228d3eca20SDavid Ahern 			rc = -errno;
3238d3eca20SDavid Ahern 		}
3248d3eca20SDavid Ahern 		goto out;
32518e60939SNelson Elhage 	}
3260a27d7f9SArnaldo Carvalho de Melo 
327a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
3287b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
3298d3eca20SDavid Ahern out:
3308d3eca20SDavid Ahern 	return rc;
331a91e5431SArnaldo Carvalho de Melo }
332a91e5431SArnaldo Carvalho de Melo 
333e3d59112SNamhyung Kim static int process_sample_event(struct perf_tool *tool,
334e3d59112SNamhyung Kim 				union perf_event *event,
335e3d59112SNamhyung Kim 				struct perf_sample *sample,
336e3d59112SNamhyung Kim 				struct perf_evsel *evsel,
337e3d59112SNamhyung Kim 				struct machine *machine)
338e3d59112SNamhyung Kim {
339e3d59112SNamhyung Kim 	struct record *rec = container_of(tool, struct record, tool);
340e3d59112SNamhyung Kim 
341e3d59112SNamhyung Kim 	rec->samples++;
342e3d59112SNamhyung Kim 
343e3d59112SNamhyung Kim 	return build_id__mark_dso_hit(tool, event, sample, evsel, machine);
344e3d59112SNamhyung Kim }
345e3d59112SNamhyung Kim 
3468c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
3476122e4e4SArnaldo Carvalho de Melo {
348f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
349f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
3506122e4e4SArnaldo Carvalho de Melo 
351457ae94aSHe Kuang 	if (file->size == 0)
3529f591fd7SArnaldo Carvalho de Melo 		return 0;
3539f591fd7SArnaldo Carvalho de Melo 
35400dc8657SNamhyung Kim 	/*
35500dc8657SNamhyung Kim 	 * During this process, it'll load kernel map and replace the
35600dc8657SNamhyung Kim 	 * dso->long_name to a real pathname it found.  In this case
35700dc8657SNamhyung Kim 	 * we prefer the vmlinux path like
35800dc8657SNamhyung Kim 	 *   /lib/modules/3.16.4/build/vmlinux
35900dc8657SNamhyung Kim 	 *
36000dc8657SNamhyung Kim 	 * rather than build-id path (in debug directory).
36100dc8657SNamhyung Kim 	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
36200dc8657SNamhyung Kim 	 */
36300dc8657SNamhyung Kim 	symbol_conf.ignore_vmlinux_buildid = true;
36400dc8657SNamhyung Kim 
365b7b61cbeSArnaldo Carvalho de Melo 	return perf_session__process_events(session);
3666122e4e4SArnaldo Carvalho de Melo }
3676122e4e4SArnaldo Carvalho de Melo 
3688115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
369a1645ce1SZhang, Yanmin {
370a1645ce1SZhang, Yanmin 	int err;
37145694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
372a1645ce1SZhang, Yanmin 	/*
373a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
374a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
375a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
376a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
377a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
378a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
379a1645ce1SZhang, Yanmin 	 */
38045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
381743eb868SArnaldo Carvalho de Melo 					     machine);
382a1645ce1SZhang, Yanmin 	if (err < 0)
383a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
38423346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
385a1645ce1SZhang, Yanmin 
386a1645ce1SZhang, Yanmin 	/*
387a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
388a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
389a1645ce1SZhang, Yanmin 	 */
39045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
3910ae617beSAdrian Hunter 						 machine);
392a1645ce1SZhang, Yanmin 	if (err < 0)
393a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
39423346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
395a1645ce1SZhang, Yanmin }
396a1645ce1SZhang, Yanmin 
39798402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
39898402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
39998402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
40098402807SFrederic Weisbecker };
40198402807SFrederic Weisbecker 
4028c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
40398402807SFrederic Weisbecker {
404dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
4050e2e63ddSPeter Zijlstra 	int i;
4068d3eca20SDavid Ahern 	int rc = 0;
40798402807SFrederic Weisbecker 
408d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
409ef149c25SAdrian Hunter 		struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap;
410ef149c25SAdrian Hunter 
4118d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
412e5685730SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, i) != 0) {
4138d3eca20SDavid Ahern 				rc = -1;
4148d3eca20SDavid Ahern 				goto out;
4158d3eca20SDavid Ahern 			}
4168d3eca20SDavid Ahern 		}
417ef149c25SAdrian Hunter 
4182dd6d8a1SAdrian Hunter 		if (mm->base && !rec->opts.auxtrace_snapshot_mode &&
419ef149c25SAdrian Hunter 		    record__auxtrace_mmap_read(rec, mm) != 0) {
420ef149c25SAdrian Hunter 			rc = -1;
421ef149c25SAdrian Hunter 			goto out;
422ef149c25SAdrian Hunter 		}
42398402807SFrederic Weisbecker 	}
42498402807SFrederic Weisbecker 
425dcabb507SJiri Olsa 	/*
426dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
427dcabb507SJiri Olsa 	 * at least one event.
428dcabb507SJiri Olsa 	 */
429dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
4308c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
4318d3eca20SDavid Ahern 
4328d3eca20SDavid Ahern out:
4338d3eca20SDavid Ahern 	return rc;
43498402807SFrederic Weisbecker }
43598402807SFrederic Weisbecker 
4368c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
43757706abcSDavid Ahern {
43857706abcSDavid Ahern 	struct perf_session *session = rec->session;
43957706abcSDavid Ahern 	int feat;
44057706abcSDavid Ahern 
44157706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
44257706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
44357706abcSDavid Ahern 
44457706abcSDavid Ahern 	if (rec->no_buildid)
44557706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
44657706abcSDavid Ahern 
4473e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
44857706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
44957706abcSDavid Ahern 
45057706abcSDavid Ahern 	if (!rec->opts.branch_stack)
45157706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
452ef149c25SAdrian Hunter 
453ef149c25SAdrian Hunter 	if (!rec->opts.full_auxtrace)
454ef149c25SAdrian Hunter 		perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
45557706abcSDavid Ahern }
45657706abcSDavid Ahern 
457f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
458f33cbe72SArnaldo Carvalho de Melo 
459f33cbe72SArnaldo Carvalho de Melo /*
460f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
461f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
462f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
463f33cbe72SArnaldo Carvalho de Melo  */
46445604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
46545604710SNamhyung Kim 					siginfo_t *info,
466f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
467f33cbe72SArnaldo Carvalho de Melo {
468f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
469f33cbe72SArnaldo Carvalho de Melo 	done = 1;
470f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
471f33cbe72SArnaldo Carvalho de Melo }
472f33cbe72SArnaldo Carvalho de Melo 
4732dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig);
4742dd6d8a1SAdrian Hunter 
4758c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
47686470930SIngo Molnar {
47757706abcSDavid Ahern 	int err;
47845604710SNamhyung Kim 	int status = 0;
4798b412664SPeter Zijlstra 	unsigned long waking = 0;
48046be604bSZhang, Yanmin 	const bool forks = argc > 0;
48123346f21SArnaldo Carvalho de Melo 	struct machine *machine;
48245694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
483b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
484f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
485d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
4866dcf45efSArnaldo Carvalho de Melo 	bool disabled = false, draining = false;
48742aa276fSNamhyung Kim 	int fd;
48886470930SIngo Molnar 
489d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
49033e49ea7SAndi Kleen 
49145604710SNamhyung Kim 	atexit(record__sig_exit);
492f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
493f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
494804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
4952dd6d8a1SAdrian Hunter 	if (rec->opts.auxtrace_snapshot_mode)
4962dd6d8a1SAdrian Hunter 		signal(SIGUSR2, snapshot_sig_handler);
4972dd6d8a1SAdrian Hunter 	else
4982dd6d8a1SAdrian Hunter 		signal(SIGUSR2, SIG_IGN);
499f5970550SPeter Zijlstra 
500b7b61cbeSArnaldo Carvalho de Melo 	session = perf_session__new(file, false, tool);
50194c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
502ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
503a9a70bbcSArnaldo Carvalho de Melo 		return -1;
504a9a70bbcSArnaldo Carvalho de Melo 	}
505a9a70bbcSArnaldo Carvalho de Melo 
50642aa276fSNamhyung Kim 	fd = perf_data_file__fd(file);
507d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
508d20deb64SArnaldo Carvalho de Melo 
5098c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
510330aa675SStephane Eranian 
511d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
5123e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
513f5fc1412SJiri Olsa 						    argv, file->is_pipe,
514735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
51535b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
51635b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
51745604710SNamhyung Kim 			status = err;
51835b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
519856e9660SPeter Zijlstra 		}
520856e9660SPeter Zijlstra 	}
521856e9660SPeter Zijlstra 
5228c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
5238d3eca20SDavid Ahern 		err = -1;
52445604710SNamhyung Kim 		goto out_child;
5258d3eca20SDavid Ahern 	}
52686470930SIngo Molnar 
527cca8482cSAdrian Hunter 	/*
528cca8482cSAdrian Hunter 	 * Normally perf_session__new would do this, but it doesn't have the
529cca8482cSAdrian Hunter 	 * evlist.
530cca8482cSAdrian Hunter 	 */
531cca8482cSAdrian Hunter 	if (rec->tool.ordered_events && !perf_evlist__sample_id_all(rec->evlist)) {
532cca8482cSAdrian Hunter 		pr_warning("WARNING: No sample_id_all support, falling back to unordered processing\n");
533cca8482cSAdrian Hunter 		rec->tool.ordered_events = false;
534cca8482cSAdrian Hunter 	}
535cca8482cSAdrian Hunter 
5363e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
537a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
538a8bb559bSNamhyung Kim 
539f5fc1412SJiri Olsa 	if (file->is_pipe) {
54042aa276fSNamhyung Kim 		err = perf_header__write_pipe(fd);
541529870e3STom Zanussi 		if (err < 0)
54245604710SNamhyung Kim 			goto out_child;
543563aecb2SJiri Olsa 	} else {
54442aa276fSNamhyung Kim 		err = perf_session__write_header(session, rec->evlist, fd, false);
545d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
54645604710SNamhyung Kim 			goto out_child;
547d5eed904SArnaldo Carvalho de Melo 	}
5487c6a1c65SPeter Zijlstra 
549d3665498SDavid Ahern 	if (!rec->no_buildid
550e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
551d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
552e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
5538d3eca20SDavid Ahern 		err = -1;
55445604710SNamhyung Kim 		goto out_child;
555e20960c0SRobert Richter 	}
556e20960c0SRobert Richter 
55734ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
558743eb868SArnaldo Carvalho de Melo 
559f5fc1412SJiri Olsa 	if (file->is_pipe) {
56045694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
561a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
5622c46dbb5STom Zanussi 		if (err < 0) {
5632c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
56445604710SNamhyung Kim 			goto out_child;
5652c46dbb5STom Zanussi 		}
566cd19a035STom Zanussi 
5673e2be2daSArnaldo Carvalho de Melo 		if (have_tracepoints(&rec->evlist->entries)) {
56863e0c771STom Zanussi 			/*
56963e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
57063e0c771STom Zanussi 			 * there were no tracepoints so its not really
57163e0c771STom Zanussi 			 * an error, just that we don't need to
57263e0c771STom Zanussi 			 * synthesize anything.  We really have to
57363e0c771STom Zanussi 			 * return this more properly and also
57463e0c771STom Zanussi 			 * propagate errors that now are calling die()
57563e0c771STom Zanussi 			 */
57642aa276fSNamhyung Kim 			err = perf_event__synthesize_tracing_data(tool,	fd, rec->evlist,
577743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
57863e0c771STom Zanussi 			if (err <= 0) {
57963e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
58045604710SNamhyung Kim 				goto out_child;
58163e0c771STom Zanussi 			}
582f34b9001SDavid Ahern 			rec->bytes_written += err;
5832c46dbb5STom Zanussi 		}
58463e0c771STom Zanussi 	}
5852c46dbb5STom Zanussi 
586ef149c25SAdrian Hunter 	if (rec->opts.full_auxtrace) {
587ef149c25SAdrian Hunter 		err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
588ef149c25SAdrian Hunter 					session, process_synthesized_event);
589ef149c25SAdrian Hunter 		if (err)
590ef149c25SAdrian Hunter 			goto out_delete_session;
591ef149c25SAdrian Hunter 	}
592ef149c25SAdrian Hunter 
59345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
5940ae617beSAdrian Hunter 						 machine);
595c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
596c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
597c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
598c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
59956b03f3cSArnaldo Carvalho de Melo 
60045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
601743eb868SArnaldo Carvalho de Melo 					     machine);
602c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
603c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
604c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
605c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
606c1a3a4b9SArnaldo Carvalho de Melo 
6077e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
608876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
6097e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
6107e383de4SArnaldo Carvalho de Melo 	}
611b7cece76SArnaldo Carvalho de Melo 
6123e2be2daSArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
6139d9cad76SKan Liang 					    process_synthesized_event, opts->sample_address,
6149d9cad76SKan Liang 					    opts->proc_map_timeout);
6158d3eca20SDavid Ahern 	if (err != 0)
61645604710SNamhyung Kim 		goto out_child;
6178d3eca20SDavid Ahern 
618d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
61986470930SIngo Molnar 		struct sched_param param;
62086470930SIngo Molnar 
621d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
62286470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
6236beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
6248d3eca20SDavid Ahern 			err = -1;
62545604710SNamhyung Kim 			goto out_child;
62686470930SIngo Molnar 		}
62786470930SIngo Molnar 	}
62886470930SIngo Molnar 
629774cb499SJiri Olsa 	/*
630774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
631774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
632774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
633774cb499SJiri Olsa 	 */
6346619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
6353e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
636764e16a3SDavid Ahern 
637856e9660SPeter Zijlstra 	/*
638856e9660SPeter Zijlstra 	 * Let the child rip
639856e9660SPeter Zijlstra 	 */
640e803cf97SNamhyung Kim 	if (forks) {
641e5bed564SNamhyung Kim 		union perf_event *event;
642e5bed564SNamhyung Kim 
643e5bed564SNamhyung Kim 		event = malloc(sizeof(event->comm) + machine->id_hdr_size);
644e5bed564SNamhyung Kim 		if (event == NULL) {
645e5bed564SNamhyung Kim 			err = -ENOMEM;
646e5bed564SNamhyung Kim 			goto out_child;
647e5bed564SNamhyung Kim 		}
648e5bed564SNamhyung Kim 
649e803cf97SNamhyung Kim 		/*
650e803cf97SNamhyung Kim 		 * Some H/W events are generated before COMM event
651e803cf97SNamhyung Kim 		 * which is emitted during exec(), so perf script
652e803cf97SNamhyung Kim 		 * cannot see a correct process name for those events.
653e803cf97SNamhyung Kim 		 * Synthesize COMM event to prevent it.
654e803cf97SNamhyung Kim 		 */
655e5bed564SNamhyung Kim 		perf_event__synthesize_comm(tool, event,
656e803cf97SNamhyung Kim 					    rec->evlist->workload.pid,
657e803cf97SNamhyung Kim 					    process_synthesized_event,
658e803cf97SNamhyung Kim 					    machine);
659e5bed564SNamhyung Kim 		free(event);
660e803cf97SNamhyung Kim 
6613e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
662e803cf97SNamhyung Kim 	}
663856e9660SPeter Zijlstra 
6646619a53eSAndi Kleen 	if (opts->initial_delay) {
6656619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
6666619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
6676619a53eSAndi Kleen 	}
6686619a53eSAndi Kleen 
6692dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 1;
670649c48a9SPeter Zijlstra 	for (;;) {
6719f065194SYang Shi 		unsigned long long hits = rec->samples;
67286470930SIngo Molnar 
6738c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
6742dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
6758d3eca20SDavid Ahern 			err = -1;
67645604710SNamhyung Kim 			goto out_child;
6778d3eca20SDavid Ahern 		}
67886470930SIngo Molnar 
6792dd6d8a1SAdrian Hunter 		if (auxtrace_record__snapshot_started) {
6802dd6d8a1SAdrian Hunter 			auxtrace_record__snapshot_started = 0;
6812dd6d8a1SAdrian Hunter 			if (!auxtrace_snapshot_err)
6822dd6d8a1SAdrian Hunter 				record__read_auxtrace_snapshot(rec);
6832dd6d8a1SAdrian Hunter 			if (auxtrace_snapshot_err) {
6842dd6d8a1SAdrian Hunter 				pr_err("AUX area tracing snapshot failed\n");
6852dd6d8a1SAdrian Hunter 				err = -1;
6862dd6d8a1SAdrian Hunter 				goto out_child;
6872dd6d8a1SAdrian Hunter 			}
6882dd6d8a1SAdrian Hunter 		}
6892dd6d8a1SAdrian Hunter 
690d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
6916dcf45efSArnaldo Carvalho de Melo 			if (done || draining)
692649c48a9SPeter Zijlstra 				break;
693f66a889dSArnaldo Carvalho de Melo 			err = perf_evlist__poll(rec->evlist, -1);
694a515114fSJiri Olsa 			/*
695a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
696a515114fSJiri Olsa 			 * number of returned events and interrupt error.
697a515114fSJiri Olsa 			 */
698a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
69945604710SNamhyung Kim 				err = 0;
7008b412664SPeter Zijlstra 			waking++;
7016dcf45efSArnaldo Carvalho de Melo 
7026dcf45efSArnaldo Carvalho de Melo 			if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
7036dcf45efSArnaldo Carvalho de Melo 				draining = true;
7048b412664SPeter Zijlstra 		}
7058b412664SPeter Zijlstra 
706774cb499SJiri Olsa 		/*
707774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
708774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
709774cb499SJiri Olsa 		 * disable events in this case.
710774cb499SJiri Olsa 		 */
711602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
7122dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
7133e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
7142711926aSJiri Olsa 			disabled = true;
7152711926aSJiri Olsa 		}
7168b412664SPeter Zijlstra 	}
7172dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
7188b412664SPeter Zijlstra 
719f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
72035550da3SMasami Hiramatsu 		char msg[STRERR_BUFSIZE];
721f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
722f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
723f33cbe72SArnaldo Carvalho de Melo 		err = -1;
72445604710SNamhyung Kim 		goto out_child;
725f33cbe72SArnaldo Carvalho de Melo 	}
726f33cbe72SArnaldo Carvalho de Melo 
727e3d59112SNamhyung Kim 	if (!quiet)
7288b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
72986470930SIngo Molnar 
73045604710SNamhyung Kim out_child:
73145604710SNamhyung Kim 	if (forks) {
73245604710SNamhyung Kim 		int exit_status;
73345604710SNamhyung Kim 
73445604710SNamhyung Kim 		if (!child_finished)
73545604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
73645604710SNamhyung Kim 
73745604710SNamhyung Kim 		wait(&exit_status);
73845604710SNamhyung Kim 
73945604710SNamhyung Kim 		if (err < 0)
74045604710SNamhyung Kim 			status = err;
74145604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
74245604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
74345604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
74445604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
74545604710SNamhyung Kim 	} else
74645604710SNamhyung Kim 		status = err;
74745604710SNamhyung Kim 
748e3d59112SNamhyung Kim 	/* this will be recalculated during process_buildids() */
749e3d59112SNamhyung Kim 	rec->samples = 0;
750e3d59112SNamhyung Kim 
75145604710SNamhyung Kim 	if (!err && !file->is_pipe) {
75245604710SNamhyung Kim 		rec->session->header.data_size += rec->bytes_written;
753457ae94aSHe Kuang 		file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
75445604710SNamhyung Kim 
755cd10b289SAdrian Hunter 		if (!rec->no_buildid) {
75645604710SNamhyung Kim 			process_buildids(rec);
757cd10b289SAdrian Hunter 			/*
758cd10b289SAdrian Hunter 			 * We take all buildids when the file contains
759cd10b289SAdrian Hunter 			 * AUX area tracing data because we do not decode the
760cd10b289SAdrian Hunter 			 * trace because it would take too long.
761cd10b289SAdrian Hunter 			 */
762cd10b289SAdrian Hunter 			if (rec->opts.full_auxtrace)
763cd10b289SAdrian Hunter 				dsos__hit_all(rec->session);
764cd10b289SAdrian Hunter 		}
76542aa276fSNamhyung Kim 		perf_session__write_header(rec->session, rec->evlist, fd, true);
76645604710SNamhyung Kim 	}
76739d17dacSArnaldo Carvalho de Melo 
768e3d59112SNamhyung Kim 	if (!err && !quiet) {
769e3d59112SNamhyung Kim 		char samples[128];
770e3d59112SNamhyung Kim 
771ef149c25SAdrian Hunter 		if (rec->samples && !rec->opts.full_auxtrace)
772e3d59112SNamhyung Kim 			scnprintf(samples, sizeof(samples),
773e3d59112SNamhyung Kim 				  " (%" PRIu64 " samples)", rec->samples);
774e3d59112SNamhyung Kim 		else
775e3d59112SNamhyung Kim 			samples[0] = '\0';
776e3d59112SNamhyung Kim 
777e3d59112SNamhyung Kim 		fprintf(stderr,	"[ perf record: Captured and wrote %.3f MB %s%s ]\n",
778e3d59112SNamhyung Kim 			perf_data_file__size(file) / 1024.0 / 1024.0,
779e3d59112SNamhyung Kim 			file->path, samples);
780e3d59112SNamhyung Kim 	}
781e3d59112SNamhyung Kim 
78239d17dacSArnaldo Carvalho de Melo out_delete_session:
78339d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
78445604710SNamhyung Kim 	return status;
78586470930SIngo Molnar }
78686470930SIngo Molnar 
78772a128aaSNamhyung Kim static void callchain_debug(void)
78809b0fd45SJiri Olsa {
789aad2b21cSKan Liang 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" };
790a601fdffSJiri Olsa 
79172a128aaSNamhyung Kim 	pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
79226d33022SJiri Olsa 
79372a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_DWARF)
79409b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
79572a128aaSNamhyung Kim 			 callchain_param.dump_size);
79609b0fd45SJiri Olsa }
79709b0fd45SJiri Olsa 
798c421e80bSKan Liang int record_parse_callchain_opt(const struct option *opt,
79909b0fd45SJiri Olsa 			       const char *arg,
80009b0fd45SJiri Olsa 			       int unset)
80109b0fd45SJiri Olsa {
80209b0fd45SJiri Olsa 	int ret;
803c421e80bSKan Liang 	struct record_opts *record = (struct record_opts *)opt->value;
80409b0fd45SJiri Olsa 
805c421e80bSKan Liang 	record->callgraph_set = true;
80672a128aaSNamhyung Kim 	callchain_param.enabled = !unset;
807eb853e80SJiri Olsa 
80809b0fd45SJiri Olsa 	/* --no-call-graph */
80909b0fd45SJiri Olsa 	if (unset) {
81072a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_NONE;
81109b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
81209b0fd45SJiri Olsa 		return 0;
81309b0fd45SJiri Olsa 	}
81409b0fd45SJiri Olsa 
815c3a6a8c4SKan Liang 	ret = parse_callchain_record_opt(arg, &callchain_param);
81609b0fd45SJiri Olsa 	if (!ret)
81772a128aaSNamhyung Kim 		callchain_debug();
81809b0fd45SJiri Olsa 
81926d33022SJiri Olsa 	return ret;
82026d33022SJiri Olsa }
82126d33022SJiri Olsa 
822c421e80bSKan Liang int record_callchain_opt(const struct option *opt,
82309b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
82409b0fd45SJiri Olsa 			 int unset __maybe_unused)
82509b0fd45SJiri Olsa {
826c421e80bSKan Liang 	struct record_opts *record = (struct record_opts *)opt->value;
827c421e80bSKan Liang 
828c421e80bSKan Liang 	record->callgraph_set = true;
82972a128aaSNamhyung Kim 	callchain_param.enabled = true;
83009b0fd45SJiri Olsa 
83172a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_NONE)
83272a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_FP;
833eb853e80SJiri Olsa 
83472a128aaSNamhyung Kim 	callchain_debug();
83509b0fd45SJiri Olsa 	return 0;
83609b0fd45SJiri Olsa }
83709b0fd45SJiri Olsa 
838eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
839eb853e80SJiri Olsa {
8407a29c087SNamhyung Kim 	struct record *rec = cb;
8417a29c087SNamhyung Kim 
8427a29c087SNamhyung Kim 	if (!strcmp(var, "record.build-id")) {
8437a29c087SNamhyung Kim 		if (!strcmp(value, "cache"))
8447a29c087SNamhyung Kim 			rec->no_buildid_cache = false;
8457a29c087SNamhyung Kim 		else if (!strcmp(value, "no-cache"))
8467a29c087SNamhyung Kim 			rec->no_buildid_cache = true;
8477a29c087SNamhyung Kim 		else if (!strcmp(value, "skip"))
8487a29c087SNamhyung Kim 			rec->no_buildid = true;
8497a29c087SNamhyung Kim 		else
8507a29c087SNamhyung Kim 			return -1;
8517a29c087SNamhyung Kim 		return 0;
8527a29c087SNamhyung Kim 	}
853eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
8545a2e5e85SNamhyung Kim 		var = "call-graph.record-mode"; /* fall-through */
855eb853e80SJiri Olsa 
856eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
857eb853e80SJiri Olsa }
858eb853e80SJiri Olsa 
859814c8c38SPeter Zijlstra struct clockid_map {
860814c8c38SPeter Zijlstra 	const char *name;
861814c8c38SPeter Zijlstra 	int clockid;
862814c8c38SPeter Zijlstra };
863814c8c38SPeter Zijlstra 
864814c8c38SPeter Zijlstra #define CLOCKID_MAP(n, c)	\
865814c8c38SPeter Zijlstra 	{ .name = n, .clockid = (c), }
866814c8c38SPeter Zijlstra 
867814c8c38SPeter Zijlstra #define CLOCKID_END	{ .name = NULL, }
868814c8c38SPeter Zijlstra 
869814c8c38SPeter Zijlstra 
870814c8c38SPeter Zijlstra /*
871814c8c38SPeter Zijlstra  * Add the missing ones, we need to build on many distros...
872814c8c38SPeter Zijlstra  */
873814c8c38SPeter Zijlstra #ifndef CLOCK_MONOTONIC_RAW
874814c8c38SPeter Zijlstra #define CLOCK_MONOTONIC_RAW 4
875814c8c38SPeter Zijlstra #endif
876814c8c38SPeter Zijlstra #ifndef CLOCK_BOOTTIME
877814c8c38SPeter Zijlstra #define CLOCK_BOOTTIME 7
878814c8c38SPeter Zijlstra #endif
879814c8c38SPeter Zijlstra #ifndef CLOCK_TAI
880814c8c38SPeter Zijlstra #define CLOCK_TAI 11
881814c8c38SPeter Zijlstra #endif
882814c8c38SPeter Zijlstra 
883814c8c38SPeter Zijlstra static const struct clockid_map clockids[] = {
884814c8c38SPeter Zijlstra 	/* available for all events, NMI safe */
885814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic", CLOCK_MONOTONIC),
886814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW),
887814c8c38SPeter Zijlstra 
888814c8c38SPeter Zijlstra 	/* available for some events */
889814c8c38SPeter Zijlstra 	CLOCKID_MAP("realtime", CLOCK_REALTIME),
890814c8c38SPeter Zijlstra 	CLOCKID_MAP("boottime", CLOCK_BOOTTIME),
891814c8c38SPeter Zijlstra 	CLOCKID_MAP("tai", CLOCK_TAI),
892814c8c38SPeter Zijlstra 
893814c8c38SPeter Zijlstra 	/* available for the lazy */
894814c8c38SPeter Zijlstra 	CLOCKID_MAP("mono", CLOCK_MONOTONIC),
895814c8c38SPeter Zijlstra 	CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW),
896814c8c38SPeter Zijlstra 	CLOCKID_MAP("real", CLOCK_REALTIME),
897814c8c38SPeter Zijlstra 	CLOCKID_MAP("boot", CLOCK_BOOTTIME),
898814c8c38SPeter Zijlstra 
899814c8c38SPeter Zijlstra 	CLOCKID_END,
900814c8c38SPeter Zijlstra };
901814c8c38SPeter Zijlstra 
902814c8c38SPeter Zijlstra static int parse_clockid(const struct option *opt, const char *str, int unset)
903814c8c38SPeter Zijlstra {
904814c8c38SPeter Zijlstra 	struct record_opts *opts = (struct record_opts *)opt->value;
905814c8c38SPeter Zijlstra 	const struct clockid_map *cm;
906814c8c38SPeter Zijlstra 	const char *ostr = str;
907814c8c38SPeter Zijlstra 
908814c8c38SPeter Zijlstra 	if (unset) {
909814c8c38SPeter Zijlstra 		opts->use_clockid = 0;
910814c8c38SPeter Zijlstra 		return 0;
911814c8c38SPeter Zijlstra 	}
912814c8c38SPeter Zijlstra 
913814c8c38SPeter Zijlstra 	/* no arg passed */
914814c8c38SPeter Zijlstra 	if (!str)
915814c8c38SPeter Zijlstra 		return 0;
916814c8c38SPeter Zijlstra 
917814c8c38SPeter Zijlstra 	/* no setting it twice */
918814c8c38SPeter Zijlstra 	if (opts->use_clockid)
919814c8c38SPeter Zijlstra 		return -1;
920814c8c38SPeter Zijlstra 
921814c8c38SPeter Zijlstra 	opts->use_clockid = true;
922814c8c38SPeter Zijlstra 
923814c8c38SPeter Zijlstra 	/* if its a number, we're done */
924814c8c38SPeter Zijlstra 	if (sscanf(str, "%d", &opts->clockid) == 1)
925814c8c38SPeter Zijlstra 		return 0;
926814c8c38SPeter Zijlstra 
927814c8c38SPeter Zijlstra 	/* allow a "CLOCK_" prefix to the name */
928814c8c38SPeter Zijlstra 	if (!strncasecmp(str, "CLOCK_", 6))
929814c8c38SPeter Zijlstra 		str += 6;
930814c8c38SPeter Zijlstra 
931814c8c38SPeter Zijlstra 	for (cm = clockids; cm->name; cm++) {
932814c8c38SPeter Zijlstra 		if (!strcasecmp(str, cm->name)) {
933814c8c38SPeter Zijlstra 			opts->clockid = cm->clockid;
934814c8c38SPeter Zijlstra 			return 0;
935814c8c38SPeter Zijlstra 		}
936814c8c38SPeter Zijlstra 	}
937814c8c38SPeter Zijlstra 
938814c8c38SPeter Zijlstra 	opts->use_clockid = false;
939814c8c38SPeter Zijlstra 	ui__warning("unknown clockid %s, check man page\n", ostr);
940814c8c38SPeter Zijlstra 	return -1;
941814c8c38SPeter Zijlstra }
942814c8c38SPeter Zijlstra 
943e9db1310SAdrian Hunter static int record__parse_mmap_pages(const struct option *opt,
944e9db1310SAdrian Hunter 				    const char *str,
945e9db1310SAdrian Hunter 				    int unset __maybe_unused)
946e9db1310SAdrian Hunter {
947e9db1310SAdrian Hunter 	struct record_opts *opts = opt->value;
948e9db1310SAdrian Hunter 	char *s, *p;
949e9db1310SAdrian Hunter 	unsigned int mmap_pages;
950e9db1310SAdrian Hunter 	int ret;
951e9db1310SAdrian Hunter 
952e9db1310SAdrian Hunter 	if (!str)
953e9db1310SAdrian Hunter 		return -EINVAL;
954e9db1310SAdrian Hunter 
955e9db1310SAdrian Hunter 	s = strdup(str);
956e9db1310SAdrian Hunter 	if (!s)
957e9db1310SAdrian Hunter 		return -ENOMEM;
958e9db1310SAdrian Hunter 
959e9db1310SAdrian Hunter 	p = strchr(s, ',');
960e9db1310SAdrian Hunter 	if (p)
961e9db1310SAdrian Hunter 		*p = '\0';
962e9db1310SAdrian Hunter 
963e9db1310SAdrian Hunter 	if (*s) {
964e9db1310SAdrian Hunter 		ret = __perf_evlist__parse_mmap_pages(&mmap_pages, s);
965e9db1310SAdrian Hunter 		if (ret)
966e9db1310SAdrian Hunter 			goto out_free;
967e9db1310SAdrian Hunter 		opts->mmap_pages = mmap_pages;
968e9db1310SAdrian Hunter 	}
969e9db1310SAdrian Hunter 
970e9db1310SAdrian Hunter 	if (!p) {
971e9db1310SAdrian Hunter 		ret = 0;
972e9db1310SAdrian Hunter 		goto out_free;
973e9db1310SAdrian Hunter 	}
974e9db1310SAdrian Hunter 
975e9db1310SAdrian Hunter 	ret = __perf_evlist__parse_mmap_pages(&mmap_pages, p + 1);
976e9db1310SAdrian Hunter 	if (ret)
977e9db1310SAdrian Hunter 		goto out_free;
978e9db1310SAdrian Hunter 
979e9db1310SAdrian Hunter 	opts->auxtrace_mmap_pages = mmap_pages;
980e9db1310SAdrian Hunter 
981e9db1310SAdrian Hunter out_free:
982e9db1310SAdrian Hunter 	free(s);
983e9db1310SAdrian Hunter 	return ret;
984e9db1310SAdrian Hunter }
985e9db1310SAdrian Hunter 
986e5b2c207SNamhyung Kim static const char * const __record_usage[] = {
98786470930SIngo Molnar 	"perf record [<options>] [<command>]",
98886470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
98986470930SIngo Molnar 	NULL
99086470930SIngo Molnar };
991e5b2c207SNamhyung Kim const char * const *record_usage = __record_usage;
99286470930SIngo Molnar 
993d20deb64SArnaldo Carvalho de Melo /*
9948c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
9958c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
996d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
997d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
998d20deb64SArnaldo Carvalho de Melo  *
999d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
1000d20deb64SArnaldo Carvalho de Melo  *
1001d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
1002d20deb64SArnaldo Carvalho de Melo  */
10038c6f45a7SArnaldo Carvalho de Melo static struct record record = {
1004d20deb64SArnaldo Carvalho de Melo 	.opts = {
10058affc2b8SAndi Kleen 		.sample_time	     = true,
1006d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
1007d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
1008d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
1009447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
1010d1cb9fceSNamhyung Kim 		.target		     = {
1011d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
10123aa5939dSAdrian Hunter 			.default_per_cpu = true,
1013d1cb9fceSNamhyung Kim 		},
10149d9cad76SKan Liang 		.proc_map_timeout     = 500,
1015d20deb64SArnaldo Carvalho de Melo 	},
1016e3d59112SNamhyung Kim 	.tool = {
1017e3d59112SNamhyung Kim 		.sample		= process_sample_event,
1018e3d59112SNamhyung Kim 		.fork		= perf_event__process_fork,
1019cca8482cSAdrian Hunter 		.exit		= perf_event__process_exit,
1020e3d59112SNamhyung Kim 		.comm		= perf_event__process_comm,
1021e3d59112SNamhyung Kim 		.mmap		= perf_event__process_mmap,
1022e3d59112SNamhyung Kim 		.mmap2		= perf_event__process_mmap2,
1023cca8482cSAdrian Hunter 		.ordered_events	= true,
1024e3d59112SNamhyung Kim 	},
1025d20deb64SArnaldo Carvalho de Melo };
10267865e817SFrederic Weisbecker 
102776a26549SNamhyung Kim const char record_callchain_help[] = CALLCHAIN_RECORD_HELP
102876a26549SNamhyung Kim 	"\n\t\t\t\tDefault: fp";
102961eaa3beSArnaldo Carvalho de Melo 
1030d20deb64SArnaldo Carvalho de Melo /*
1031d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
1032d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
1033b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
1034d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
1035d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
1036d20deb64SArnaldo Carvalho de Melo  */
1037e5b2c207SNamhyung Kim struct option __record_options[] = {
1038d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
103986470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
1040f120f9d5SJiri Olsa 		     parse_events_option),
1041d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
1042c171b552SLi Zefan 		     "event filter", parse_filter),
10434ba1faa1SWang Nan 	OPT_CALLBACK_NOOPT(0, "exclude-perf", &record.evlist,
10444ba1faa1SWang Nan 			   NULL, "don't record events from perf itself",
10454ba1faa1SWang Nan 			   exclude_perf),
1046bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
1047d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
1048bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
1049d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
1050d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
105186470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
1052509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
1053acac03faSKirill Smelkov 		    "collect data without buffering"),
1054d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
1055daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
1056bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
105786470930SIngo Molnar 			    "system-wide collection from all CPUs"),
1058bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
1059c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
1060d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
1061f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
106286470930SIngo Molnar 		    "output file name"),
106369e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
106469e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
10652e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
1066d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
1067e9db1310SAdrian Hunter 	OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]",
1068e9db1310SAdrian Hunter 		     "number of mmap data pages and AUX area tracing mmap pages",
1069e9db1310SAdrian Hunter 		     record__parse_mmap_pages),
1070d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
107143bece79SLin Ming 		    "put the counters into a counter group"),
107209b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
107309b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
107409b0fd45SJiri Olsa 			   &record_callchain_opt),
107509b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
107676a26549SNamhyung Kim 		     "record_mode[,record_size]", record_callchain_help,
107709b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
1078c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
10793da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
1080b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
1081d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
1082649c48a9SPeter Zijlstra 		    "per thread counts"),
108356100321SPeter Zijlstra 	OPT_BOOLEAN('d', "data", &record.opts.sample_address, "Record the sample addresses"),
10843abebc55SAdrian Hunter 	OPT_BOOLEAN_SET('T', "timestamp", &record.opts.sample_time,
10853abebc55SAdrian Hunter 			&record.opts.sample_time_set,
10863abebc55SAdrian Hunter 			"Record the sample timestamps"),
108756100321SPeter Zijlstra 	OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"),
1088d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
1089649c48a9SPeter Zijlstra 		    "don't sample"),
1090d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
1091a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
1092d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
1093baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
1094d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
1095023695d9SStephane Eranian 		     "monitor event in cgroup name only",
1096023695d9SStephane Eranian 		     parse_cgroups),
1097a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
10986619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
1099bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
1100bea03405SNamhyung Kim 		   "user to profile"),
1101a5aabdacSStephane Eranian 
1102a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
1103a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
1104a5aabdacSStephane Eranian 		     parse_branch_stack),
1105a5aabdacSStephane Eranian 
1106a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
1107a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
1108bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
110905484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
111005484298SAndi Kleen 		    "sample by weight (on special events only)"),
1111475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
1112475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
11133aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
11143aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
1115bcc84ec6SStephane Eranian 	OPT_CALLBACK_OPTARG('I', "intr-regs", &record.opts.sample_intr_regs, NULL, "any register",
1116bcc84ec6SStephane Eranian 		    "sample selected machine registers on interrupt,"
1117bcc84ec6SStephane Eranian 		    " use -I ? to list register names", parse_regs),
111885c273d2SAndi Kleen 	OPT_BOOLEAN(0, "running-time", &record.opts.running_time,
111985c273d2SAndi Kleen 		    "Record running/enabled time of read (:S) events"),
1120814c8c38SPeter Zijlstra 	OPT_CALLBACK('k', "clockid", &record.opts,
1121814c8c38SPeter Zijlstra 	"clockid", "clockid to use for events, see clock_gettime()",
1122814c8c38SPeter Zijlstra 	parse_clockid),
11232dd6d8a1SAdrian Hunter 	OPT_STRING_OPTARG('S', "snapshot", &record.opts.auxtrace_snapshot_opts,
11242dd6d8a1SAdrian Hunter 			  "opts", "AUX area tracing Snapshot Mode", ""),
11259d9cad76SKan Liang 	OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout,
11269d9cad76SKan Liang 			"per thread proc mmap processing timeout in ms"),
1127b757bb09SAdrian Hunter 	OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
1128b757bb09SAdrian Hunter 		    "Record context switch events"),
112971dc2326SWang Nan 	OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
113071dc2326SWang Nan 		   "clang binary to use for compiling BPF scriptlets"),
113171dc2326SWang Nan 	OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
113271dc2326SWang Nan 		   "options passed to clang when compiling BPF scriptlets"),
11337efe0e03SHe Kuang 	OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
11347efe0e03SHe Kuang 		   "file", "vmlinux pathname"),
113586470930SIngo Molnar 	OPT_END()
113686470930SIngo Molnar };
113786470930SIngo Molnar 
1138e5b2c207SNamhyung Kim struct option *record_options = __record_options;
1139e5b2c207SNamhyung Kim 
11401d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
114186470930SIngo Molnar {
1142ef149c25SAdrian Hunter 	int err;
11438c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
114416ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
114586470930SIngo Molnar 
114648e1cab1SWang Nan #ifndef HAVE_LIBBPF_SUPPORT
114748e1cab1SWang Nan # define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c)
114848e1cab1SWang Nan 	set_nobuild('\0', "clang-path", true);
114948e1cab1SWang Nan 	set_nobuild('\0', "clang-opt", true);
115048e1cab1SWang Nan # undef set_nobuild
115148e1cab1SWang Nan #endif
115248e1cab1SWang Nan 
11537efe0e03SHe Kuang #ifndef HAVE_BPF_PROLOGUE
11547efe0e03SHe Kuang # if !defined (HAVE_DWARF_SUPPORT)
11557efe0e03SHe Kuang #  define REASON  "NO_DWARF=1"
11567efe0e03SHe Kuang # elif !defined (HAVE_LIBBPF_SUPPORT)
11577efe0e03SHe Kuang #  define REASON  "NO_LIBBPF=1"
11587efe0e03SHe Kuang # else
11597efe0e03SHe Kuang #  define REASON  "this architecture doesn't support BPF prologue"
11607efe0e03SHe Kuang # endif
11617efe0e03SHe Kuang # define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, REASON, c)
11627efe0e03SHe Kuang 	set_nobuild('\0', "vmlinux", true);
11637efe0e03SHe Kuang # undef set_nobuild
11647efe0e03SHe Kuang # undef REASON
11657efe0e03SHe Kuang #endif
11667efe0e03SHe Kuang 
11673e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
11683e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
1169361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
1170361c99a6SArnaldo Carvalho de Melo 
1171eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
1172eb853e80SJiri Olsa 
1173bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
1174a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
1175602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
1176bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
117786470930SIngo Molnar 
1178bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
1179c7118369SNamhyung Kim 		usage_with_options_msg(record_usage, record_options,
1180c7118369SNamhyung Kim 			"cgroup monitoring only available in system-wide mode");
1181c7118369SNamhyung Kim 
1182023695d9SStephane Eranian 	}
1183b757bb09SAdrian Hunter 	if (rec->opts.record_switch_events &&
1184b757bb09SAdrian Hunter 	    !perf_can_record_switch_events()) {
1185c7118369SNamhyung Kim 		ui__error("kernel does not support recording context switch events\n");
1186c7118369SNamhyung Kim 		parse_options_usage(record_usage, record_options, "switch-events", 0);
1187c7118369SNamhyung Kim 		return -EINVAL;
1188b757bb09SAdrian Hunter 	}
1189023695d9SStephane Eranian 
1190ef149c25SAdrian Hunter 	if (!rec->itr) {
1191ef149c25SAdrian Hunter 		rec->itr = auxtrace_record__init(rec->evlist, &err);
1192ef149c25SAdrian Hunter 		if (err)
1193ef149c25SAdrian Hunter 			return err;
1194ef149c25SAdrian Hunter 	}
1195ef149c25SAdrian Hunter 
11962dd6d8a1SAdrian Hunter 	err = auxtrace_parse_snapshot_options(rec->itr, &rec->opts,
11972dd6d8a1SAdrian Hunter 					      rec->opts.auxtrace_snapshot_opts);
11982dd6d8a1SAdrian Hunter 	if (err)
11992dd6d8a1SAdrian Hunter 		return err;
12002dd6d8a1SAdrian Hunter 
1201ef149c25SAdrian Hunter 	err = -ENOMEM;
1202ef149c25SAdrian Hunter 
12030a7e6d1bSNamhyung Kim 	symbol__init(NULL);
1204baa2f6ceSArnaldo Carvalho de Melo 
1205ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
1206646aaea6SArnaldo Carvalho de Melo 		pr_warning(
1207646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
1208ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
1209646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
1210646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
1211646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
1212646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
1213646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
1214ec80fde7SArnaldo Carvalho de Melo 
1215d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
1216a1ac1d3cSStephane Eranian 		disable_buildid_cache();
1217655000e7SArnaldo Carvalho de Melo 
12183e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
12193e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
122069aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
122169aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
1222bbd36e5eSPeter Zijlstra 	}
122386470930SIngo Molnar 
122469e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
122569e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
122669e7e5b0SAdrian Hunter 
1227602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
122816ad2ffbSNamhyung Kim 	if (err) {
1229602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
123016ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
123116ad2ffbSNamhyung Kim 	}
12324bd0f2d2SNamhyung Kim 
1233602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
123416ad2ffbSNamhyung Kim 	if (err) {
123516ad2ffbSNamhyung Kim 		int saved_errno = errno;
123616ad2ffbSNamhyung Kim 
1237602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
12383780f488SNamhyung Kim 		ui__error("%s", errbuf);
123916ad2ffbSNamhyung Kim 
124016ad2ffbSNamhyung Kim 		err = -saved_errno;
12418fa60e1fSNamhyung Kim 		goto out_symbol_exit;
124216ad2ffbSNamhyung Kim 	}
12430d37aa34SArnaldo Carvalho de Melo 
124416ad2ffbSNamhyung Kim 	err = -ENOMEM;
12453e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
1246dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
124769aad6f1SArnaldo Carvalho de Melo 
1248ef149c25SAdrian Hunter 	err = auxtrace_record__options(rec->itr, rec->evlist, &rec->opts);
1249ef149c25SAdrian Hunter 	if (err)
1250ef149c25SAdrian Hunter 		goto out_symbol_exit;
1251ef149c25SAdrian Hunter 
1252b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
125339d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
125403ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
12557e4ff9e3SMike Galbraith 	}
12567e4ff9e3SMike Galbraith 
1257d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
1258d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
125945604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
1260d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
1261ef149c25SAdrian Hunter 	auxtrace_record__free(rec->itr);
126239d17dacSArnaldo Carvalho de Melo 	return err;
126386470930SIngo Molnar }
12642dd6d8a1SAdrian Hunter 
12652dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig __maybe_unused)
12662dd6d8a1SAdrian Hunter {
12672dd6d8a1SAdrian Hunter 	if (!auxtrace_snapshot_enabled)
12682dd6d8a1SAdrian Hunter 		return;
12692dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
12702dd6d8a1SAdrian Hunter 	auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
12712dd6d8a1SAdrian Hunter 	auxtrace_record__snapshot_started = 1;
12722dd6d8a1SAdrian Hunter }
1273