xref: /openbmc/linux/tools/perf/builtin-record.c (revision e68ae9cf7d734e669bc0a981b4154f70d29b5059)
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"
144b6ab94eSJosh 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"
3246bc29b9SAdrian Hunter #include "util/tsc.h"
33f00898f4SAndi Kleen #include "util/parse-branch-options.h"
34bcc84ec6SStephane Eranian #include "util/parse-regs-options.h"
3571dc2326SWang Nan #include "util/llvm-utils.h"
368690a2a7SWang Nan #include "util/bpf-loader.h"
37d8871ea7SWang Nan #include "asm/bug.h"
387c6a1c65SPeter Zijlstra 
3986470930SIngo Molnar #include <unistd.h>
4086470930SIngo Molnar #include <sched.h>
41a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
4286470930SIngo Molnar 
4378da39faSBernhard Rosenkraenzer 
448c6f45a7SArnaldo Carvalho de Melo struct record {
4545694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
46b4006796SArnaldo Carvalho de Melo 	struct record_opts	opts;
47d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
48f5fc1412SJiri Olsa 	struct perf_data_file	file;
49ef149c25SAdrian Hunter 	struct auxtrace_record	*itr;
50d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
51d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
52d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
53d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
54d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
55d2db9a98SWang Nan 	bool			no_buildid_set;
56d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
57d2db9a98SWang Nan 	bool			no_buildid_cache_set;
586156681bSNamhyung Kim 	bool			buildid_all;
599f065194SYang Shi 	unsigned long long	samples;
600f82ebc4SArnaldo Carvalho de Melo };
6186470930SIngo Molnar 
628c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
63f5970550SPeter Zijlstra {
64cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
654f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
668d3eca20SDavid Ahern 		return -1;
678d3eca20SDavid Ahern 	}
68f5970550SPeter Zijlstra 
69cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
708d3eca20SDavid Ahern 	return 0;
71f5970550SPeter Zijlstra }
72f5970550SPeter Zijlstra 
7345694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
74d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
751d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
761d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
77234fbbf5SArnaldo Carvalho de Melo {
788c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
798c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
80234fbbf5SArnaldo Carvalho de Melo }
81234fbbf5SArnaldo Carvalho de Melo 
82e5685730SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, int idx)
8386470930SIngo Molnar {
84e5685730SArnaldo Carvalho de Melo 	struct perf_mmap *md = &rec->evlist->mmap[idx];
857b8283b5SDavid Ahern 	u64 head = perf_mmap__read_head(md);
867b8283b5SDavid Ahern 	u64 old = md->prev;
87918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
8886470930SIngo Molnar 	unsigned long size;
8986470930SIngo Molnar 	void *buf;
908d3eca20SDavid Ahern 	int rc = 0;
9186470930SIngo Molnar 
92dc82009aSArnaldo Carvalho de Melo 	if (old == head)
938d3eca20SDavid Ahern 		return 0;
9486470930SIngo Molnar 
95d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
9686470930SIngo Molnar 
9786470930SIngo Molnar 	size = head - old;
9886470930SIngo Molnar 
9986470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
10086470930SIngo Molnar 		buf = &data[old & md->mask];
10186470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
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 
11086470930SIngo Molnar 	buf = &data[old & md->mask];
11186470930SIngo Molnar 	size = head - old;
11286470930SIngo Molnar 	old += size;
11386470930SIngo Molnar 
1148c6f45a7SArnaldo Carvalho de Melo 	if (record__write(rec, buf, size) < 0) {
1158d3eca20SDavid Ahern 		rc = -1;
1168d3eca20SDavid Ahern 		goto out;
1178d3eca20SDavid Ahern 	}
11886470930SIngo Molnar 
11986470930SIngo Molnar 	md->prev = old;
120e5685730SArnaldo Carvalho de Melo 	perf_evlist__mmap_consume(rec->evlist, idx);
1218d3eca20SDavid Ahern out:
1228d3eca20SDavid Ahern 	return rc;
12386470930SIngo Molnar }
12486470930SIngo Molnar 
1252dd6d8a1SAdrian Hunter static volatile int done;
1262dd6d8a1SAdrian Hunter static volatile int signr = -1;
1272dd6d8a1SAdrian Hunter static volatile int child_finished;
1282dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_enabled;
1292dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_err;
1302dd6d8a1SAdrian Hunter static volatile int auxtrace_record__snapshot_started;
1312dd6d8a1SAdrian Hunter 
1322dd6d8a1SAdrian Hunter static void sig_handler(int sig)
1332dd6d8a1SAdrian Hunter {
1342dd6d8a1SAdrian Hunter 	if (sig == SIGCHLD)
1352dd6d8a1SAdrian Hunter 		child_finished = 1;
1362dd6d8a1SAdrian Hunter 	else
1372dd6d8a1SAdrian Hunter 		signr = sig;
1382dd6d8a1SAdrian Hunter 
1392dd6d8a1SAdrian Hunter 	done = 1;
1402dd6d8a1SAdrian Hunter }
1412dd6d8a1SAdrian Hunter 
1422dd6d8a1SAdrian Hunter static void record__sig_exit(void)
1432dd6d8a1SAdrian Hunter {
1442dd6d8a1SAdrian Hunter 	if (signr == -1)
1452dd6d8a1SAdrian Hunter 		return;
1462dd6d8a1SAdrian Hunter 
1472dd6d8a1SAdrian Hunter 	signal(signr, SIG_DFL);
1482dd6d8a1SAdrian Hunter 	raise(signr);
1492dd6d8a1SAdrian Hunter }
1502dd6d8a1SAdrian Hunter 
151e31f0d01SAdrian Hunter #ifdef HAVE_AUXTRACE_SUPPORT
152e31f0d01SAdrian Hunter 
153ef149c25SAdrian Hunter static int record__process_auxtrace(struct perf_tool *tool,
154ef149c25SAdrian Hunter 				    union perf_event *event, void *data1,
155ef149c25SAdrian Hunter 				    size_t len1, void *data2, size_t len2)
156ef149c25SAdrian Hunter {
157ef149c25SAdrian Hunter 	struct record *rec = container_of(tool, struct record, tool);
15899fa2984SAdrian Hunter 	struct perf_data_file *file = &rec->file;
159ef149c25SAdrian Hunter 	size_t padding;
160ef149c25SAdrian Hunter 	u8 pad[8] = {0};
161ef149c25SAdrian Hunter 
16299fa2984SAdrian Hunter 	if (!perf_data_file__is_pipe(file)) {
16399fa2984SAdrian Hunter 		off_t file_offset;
16499fa2984SAdrian Hunter 		int fd = perf_data_file__fd(file);
16599fa2984SAdrian Hunter 		int err;
16699fa2984SAdrian Hunter 
16799fa2984SAdrian Hunter 		file_offset = lseek(fd, 0, SEEK_CUR);
16899fa2984SAdrian Hunter 		if (file_offset == -1)
16999fa2984SAdrian Hunter 			return -1;
17099fa2984SAdrian Hunter 		err = auxtrace_index__auxtrace_event(&rec->session->auxtrace_index,
17199fa2984SAdrian Hunter 						     event, file_offset);
17299fa2984SAdrian Hunter 		if (err)
17399fa2984SAdrian Hunter 			return err;
17499fa2984SAdrian Hunter 	}
17599fa2984SAdrian Hunter 
176ef149c25SAdrian Hunter 	/* event.auxtrace.size includes padding, see __auxtrace_mmap__read() */
177ef149c25SAdrian Hunter 	padding = (len1 + len2) & 7;
178ef149c25SAdrian Hunter 	if (padding)
179ef149c25SAdrian Hunter 		padding = 8 - padding;
180ef149c25SAdrian Hunter 
181ef149c25SAdrian Hunter 	record__write(rec, event, event->header.size);
182ef149c25SAdrian Hunter 	record__write(rec, data1, len1);
183ef149c25SAdrian Hunter 	if (len2)
184ef149c25SAdrian Hunter 		record__write(rec, data2, len2);
185ef149c25SAdrian Hunter 	record__write(rec, &pad, padding);
186ef149c25SAdrian Hunter 
187ef149c25SAdrian Hunter 	return 0;
188ef149c25SAdrian Hunter }
189ef149c25SAdrian Hunter 
190ef149c25SAdrian Hunter static int record__auxtrace_mmap_read(struct record *rec,
191ef149c25SAdrian Hunter 				      struct auxtrace_mmap *mm)
192ef149c25SAdrian Hunter {
193ef149c25SAdrian Hunter 	int ret;
194ef149c25SAdrian Hunter 
195ef149c25SAdrian Hunter 	ret = auxtrace_mmap__read(mm, rec->itr, &rec->tool,
196ef149c25SAdrian Hunter 				  record__process_auxtrace);
197ef149c25SAdrian Hunter 	if (ret < 0)
198ef149c25SAdrian Hunter 		return ret;
199ef149c25SAdrian Hunter 
200ef149c25SAdrian Hunter 	if (ret)
201ef149c25SAdrian Hunter 		rec->samples++;
202ef149c25SAdrian Hunter 
203ef149c25SAdrian Hunter 	return 0;
204ef149c25SAdrian Hunter }
205ef149c25SAdrian Hunter 
2062dd6d8a1SAdrian Hunter static int record__auxtrace_mmap_read_snapshot(struct record *rec,
2072dd6d8a1SAdrian Hunter 					       struct auxtrace_mmap *mm)
2082dd6d8a1SAdrian Hunter {
2092dd6d8a1SAdrian Hunter 	int ret;
2102dd6d8a1SAdrian Hunter 
2112dd6d8a1SAdrian Hunter 	ret = auxtrace_mmap__read_snapshot(mm, rec->itr, &rec->tool,
2122dd6d8a1SAdrian Hunter 					   record__process_auxtrace,
2132dd6d8a1SAdrian Hunter 					   rec->opts.auxtrace_snapshot_size);
2142dd6d8a1SAdrian Hunter 	if (ret < 0)
2152dd6d8a1SAdrian Hunter 		return ret;
2162dd6d8a1SAdrian Hunter 
2172dd6d8a1SAdrian Hunter 	if (ret)
2182dd6d8a1SAdrian Hunter 		rec->samples++;
2192dd6d8a1SAdrian Hunter 
2202dd6d8a1SAdrian Hunter 	return 0;
2212dd6d8a1SAdrian Hunter }
2222dd6d8a1SAdrian Hunter 
2232dd6d8a1SAdrian Hunter static int record__auxtrace_read_snapshot_all(struct record *rec)
2242dd6d8a1SAdrian Hunter {
2252dd6d8a1SAdrian Hunter 	int i;
2262dd6d8a1SAdrian Hunter 	int rc = 0;
2272dd6d8a1SAdrian Hunter 
2282dd6d8a1SAdrian Hunter 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
2292dd6d8a1SAdrian Hunter 		struct auxtrace_mmap *mm =
2302dd6d8a1SAdrian Hunter 				&rec->evlist->mmap[i].auxtrace_mmap;
2312dd6d8a1SAdrian Hunter 
2322dd6d8a1SAdrian Hunter 		if (!mm->base)
2332dd6d8a1SAdrian Hunter 			continue;
2342dd6d8a1SAdrian Hunter 
2352dd6d8a1SAdrian Hunter 		if (record__auxtrace_mmap_read_snapshot(rec, mm) != 0) {
2362dd6d8a1SAdrian Hunter 			rc = -1;
2372dd6d8a1SAdrian Hunter 			goto out;
2382dd6d8a1SAdrian Hunter 		}
2392dd6d8a1SAdrian Hunter 	}
2402dd6d8a1SAdrian Hunter out:
2412dd6d8a1SAdrian Hunter 	return rc;
2422dd6d8a1SAdrian Hunter }
2432dd6d8a1SAdrian Hunter 
2442dd6d8a1SAdrian Hunter static void record__read_auxtrace_snapshot(struct record *rec)
2452dd6d8a1SAdrian Hunter {
2462dd6d8a1SAdrian Hunter 	pr_debug("Recording AUX area tracing snapshot\n");
2472dd6d8a1SAdrian Hunter 	if (record__auxtrace_read_snapshot_all(rec) < 0) {
2482dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = -1;
2492dd6d8a1SAdrian Hunter 	} else {
2502dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr);
2512dd6d8a1SAdrian Hunter 		if (!auxtrace_snapshot_err)
2522dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 1;
2532dd6d8a1SAdrian Hunter 	}
2542dd6d8a1SAdrian Hunter }
2552dd6d8a1SAdrian Hunter 
256e31f0d01SAdrian Hunter #else
257e31f0d01SAdrian Hunter 
258e31f0d01SAdrian Hunter static inline
259e31f0d01SAdrian Hunter int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
260e31f0d01SAdrian Hunter 			       struct auxtrace_mmap *mm __maybe_unused)
261e31f0d01SAdrian Hunter {
262e31f0d01SAdrian Hunter 	return 0;
263e31f0d01SAdrian Hunter }
264e31f0d01SAdrian Hunter 
2652dd6d8a1SAdrian Hunter static inline
2662dd6d8a1SAdrian Hunter void record__read_auxtrace_snapshot(struct record *rec __maybe_unused)
2672dd6d8a1SAdrian Hunter {
2682dd6d8a1SAdrian Hunter }
2692dd6d8a1SAdrian Hunter 
2702dd6d8a1SAdrian Hunter static inline
2712dd6d8a1SAdrian Hunter int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused)
2722dd6d8a1SAdrian Hunter {
2732dd6d8a1SAdrian Hunter 	return 0;
2742dd6d8a1SAdrian Hunter }
2752dd6d8a1SAdrian Hunter 
276e31f0d01SAdrian Hunter #endif
277e31f0d01SAdrian Hunter 
2788c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
279dd7927f4SArnaldo Carvalho de Melo {
28056e52e85SArnaldo Carvalho de Melo 	char msg[512];
2816a4bb04cSJiri Olsa 	struct perf_evsel *pos;
282d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
283d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
284b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
2858d3eca20SDavid Ahern 	int rc = 0;
286dd7927f4SArnaldo Carvalho de Melo 
287*e68ae9cfSArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts, &callchain_param);
288cac21425SJiri Olsa 
2890050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
2903da297a6SIngo Molnar try_again:
291d988d5eeSKan Liang 		if (perf_evsel__open(pos, pos->cpus, pos->threads) < 0) {
29256e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2933da297a6SIngo Molnar 				if (verbose)
294c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2953da297a6SIngo Molnar 				goto try_again;
2963da297a6SIngo Molnar 			}
297ca6a4258SDavid Ahern 
29856e52e85SArnaldo Carvalho de Melo 			rc = -errno;
29956e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
30056e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
30156e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
3028d3eca20SDavid Ahern 			goto out;
3037c6a1c65SPeter Zijlstra 		}
3047c6a1c65SPeter Zijlstra 	}
3057c6a1c65SPeter Zijlstra 
30623d4aad4SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist, &pos)) {
30723d4aad4SArnaldo Carvalho de Melo 		error("failed to set filter \"%s\" on event %s with %d (%s)\n",
30823d4aad4SArnaldo Carvalho de Melo 			pos->filter, perf_evsel__name(pos), errno,
30935550da3SMasami Hiramatsu 			strerror_r(errno, msg, sizeof(msg)));
3108d3eca20SDavid Ahern 		rc = -1;
3118d3eca20SDavid Ahern 		goto out;
3120a102479SFrederic Weisbecker 	}
3130a102479SFrederic Weisbecker 
314ef149c25SAdrian Hunter 	if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
3152dd6d8a1SAdrian Hunter 				 opts->auxtrace_mmap_pages,
3162dd6d8a1SAdrian Hunter 				 opts->auxtrace_snapshot_mode) < 0) {
3178d3eca20SDavid Ahern 		if (errno == EPERM) {
3188d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
31918e60939SNelson Elhage 			       "Consider increasing "
32018e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
32118e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
322ef149c25SAdrian Hunter 			       "(current value: %u,%u)\n",
323ef149c25SAdrian Hunter 			       opts->mmap_pages, opts->auxtrace_mmap_pages);
3248d3eca20SDavid Ahern 			rc = -errno;
3258d3eca20SDavid Ahern 		} else {
32635550da3SMasami Hiramatsu 			pr_err("failed to mmap with %d (%s)\n", errno,
32735550da3SMasami Hiramatsu 				strerror_r(errno, msg, sizeof(msg)));
32895c36561SWang Nan 			if (errno)
3298d3eca20SDavid Ahern 				rc = -errno;
33095c36561SWang Nan 			else
33195c36561SWang Nan 				rc = -EINVAL;
3328d3eca20SDavid Ahern 		}
3338d3eca20SDavid Ahern 		goto out;
33418e60939SNelson Elhage 	}
3350a27d7f9SArnaldo Carvalho de Melo 
336a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
3377b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
3388d3eca20SDavid Ahern out:
3398d3eca20SDavid Ahern 	return rc;
340a91e5431SArnaldo Carvalho de Melo }
341a91e5431SArnaldo Carvalho de Melo 
342e3d59112SNamhyung Kim static int process_sample_event(struct perf_tool *tool,
343e3d59112SNamhyung Kim 				union perf_event *event,
344e3d59112SNamhyung Kim 				struct perf_sample *sample,
345e3d59112SNamhyung Kim 				struct perf_evsel *evsel,
346e3d59112SNamhyung Kim 				struct machine *machine)
347e3d59112SNamhyung Kim {
348e3d59112SNamhyung Kim 	struct record *rec = container_of(tool, struct record, tool);
349e3d59112SNamhyung Kim 
350e3d59112SNamhyung Kim 	rec->samples++;
351e3d59112SNamhyung Kim 
352e3d59112SNamhyung Kim 	return build_id__mark_dso_hit(tool, event, sample, evsel, machine);
353e3d59112SNamhyung Kim }
354e3d59112SNamhyung Kim 
3558c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
3566122e4e4SArnaldo Carvalho de Melo {
357f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
358f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
3596122e4e4SArnaldo Carvalho de Melo 
360457ae94aSHe Kuang 	if (file->size == 0)
3619f591fd7SArnaldo Carvalho de Melo 		return 0;
3629f591fd7SArnaldo Carvalho de Melo 
36300dc8657SNamhyung Kim 	/*
36400dc8657SNamhyung Kim 	 * During this process, it'll load kernel map and replace the
36500dc8657SNamhyung Kim 	 * dso->long_name to a real pathname it found.  In this case
36600dc8657SNamhyung Kim 	 * we prefer the vmlinux path like
36700dc8657SNamhyung Kim 	 *   /lib/modules/3.16.4/build/vmlinux
36800dc8657SNamhyung Kim 	 *
36900dc8657SNamhyung Kim 	 * rather than build-id path (in debug directory).
37000dc8657SNamhyung Kim 	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
37100dc8657SNamhyung Kim 	 */
37200dc8657SNamhyung Kim 	symbol_conf.ignore_vmlinux_buildid = true;
37300dc8657SNamhyung Kim 
3746156681bSNamhyung Kim 	/*
3756156681bSNamhyung Kim 	 * If --buildid-all is given, it marks all DSO regardless of hits,
3766156681bSNamhyung Kim 	 * so no need to process samples.
3776156681bSNamhyung Kim 	 */
3786156681bSNamhyung Kim 	if (rec->buildid_all)
3796156681bSNamhyung Kim 		rec->tool.sample = NULL;
3806156681bSNamhyung Kim 
381b7b61cbeSArnaldo Carvalho de Melo 	return perf_session__process_events(session);
3826122e4e4SArnaldo Carvalho de Melo }
3836122e4e4SArnaldo Carvalho de Melo 
3848115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
385a1645ce1SZhang, Yanmin {
386a1645ce1SZhang, Yanmin 	int err;
38745694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
388a1645ce1SZhang, Yanmin 	/*
389a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
390a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
391a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
392a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
393a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
394a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
395a1645ce1SZhang, Yanmin 	 */
39645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
397743eb868SArnaldo Carvalho de Melo 					     machine);
398a1645ce1SZhang, Yanmin 	if (err < 0)
399a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
40023346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
401a1645ce1SZhang, Yanmin 
402a1645ce1SZhang, Yanmin 	/*
403a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
404a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
405a1645ce1SZhang, Yanmin 	 */
40645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
4070ae617beSAdrian Hunter 						 machine);
408a1645ce1SZhang, Yanmin 	if (err < 0)
409a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
41023346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
411a1645ce1SZhang, Yanmin }
412a1645ce1SZhang, Yanmin 
41398402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
41498402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
41598402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
41698402807SFrederic Weisbecker };
41798402807SFrederic Weisbecker 
4188c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
41998402807SFrederic Weisbecker {
420dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
4210e2e63ddSPeter Zijlstra 	int i;
4228d3eca20SDavid Ahern 	int rc = 0;
42398402807SFrederic Weisbecker 
424d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
425ef149c25SAdrian Hunter 		struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap;
426ef149c25SAdrian Hunter 
4278d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
428e5685730SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, i) != 0) {
4298d3eca20SDavid Ahern 				rc = -1;
4308d3eca20SDavid Ahern 				goto out;
4318d3eca20SDavid Ahern 			}
4328d3eca20SDavid Ahern 		}
433ef149c25SAdrian Hunter 
4342dd6d8a1SAdrian Hunter 		if (mm->base && !rec->opts.auxtrace_snapshot_mode &&
435ef149c25SAdrian Hunter 		    record__auxtrace_mmap_read(rec, mm) != 0) {
436ef149c25SAdrian Hunter 			rc = -1;
437ef149c25SAdrian Hunter 			goto out;
438ef149c25SAdrian Hunter 		}
43998402807SFrederic Weisbecker 	}
44098402807SFrederic Weisbecker 
441dcabb507SJiri Olsa 	/*
442dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
443dcabb507SJiri Olsa 	 * at least one event.
444dcabb507SJiri Olsa 	 */
445dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
4468c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
4478d3eca20SDavid Ahern 
4488d3eca20SDavid Ahern out:
4498d3eca20SDavid Ahern 	return rc;
45098402807SFrederic Weisbecker }
45198402807SFrederic Weisbecker 
4528c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
45357706abcSDavid Ahern {
45457706abcSDavid Ahern 	struct perf_session *session = rec->session;
45557706abcSDavid Ahern 	int feat;
45657706abcSDavid Ahern 
45757706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
45857706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
45957706abcSDavid Ahern 
46057706abcSDavid Ahern 	if (rec->no_buildid)
46157706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
46257706abcSDavid Ahern 
4633e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
46457706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
46557706abcSDavid Ahern 
46657706abcSDavid Ahern 	if (!rec->opts.branch_stack)
46757706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
468ef149c25SAdrian Hunter 
469ef149c25SAdrian Hunter 	if (!rec->opts.full_auxtrace)
470ef149c25SAdrian Hunter 		perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
471ffa517adSJiri Olsa 
472ffa517adSJiri Olsa 	perf_header__clear_feat(&session->header, HEADER_STAT);
47357706abcSDavid Ahern }
47457706abcSDavid Ahern 
475e1ab48baSWang Nan static void
476e1ab48baSWang Nan record__finish_output(struct record *rec)
477e1ab48baSWang Nan {
478e1ab48baSWang Nan 	struct perf_data_file *file = &rec->file;
479e1ab48baSWang Nan 	int fd = perf_data_file__fd(file);
480e1ab48baSWang Nan 
481e1ab48baSWang Nan 	if (file->is_pipe)
482e1ab48baSWang Nan 		return;
483e1ab48baSWang Nan 
484e1ab48baSWang Nan 	rec->session->header.data_size += rec->bytes_written;
485e1ab48baSWang Nan 	file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
486e1ab48baSWang Nan 
487e1ab48baSWang Nan 	if (!rec->no_buildid) {
488e1ab48baSWang Nan 		process_buildids(rec);
489e1ab48baSWang Nan 
490e1ab48baSWang Nan 		if (rec->buildid_all)
491e1ab48baSWang Nan 			dsos__hit_all(rec->session);
492e1ab48baSWang Nan 	}
493e1ab48baSWang Nan 	perf_session__write_header(rec->session, rec->evlist, fd, true);
494e1ab48baSWang Nan 
495e1ab48baSWang Nan 	return;
496e1ab48baSWang Nan }
497e1ab48baSWang Nan 
498f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
499f33cbe72SArnaldo Carvalho de Melo 
500f33cbe72SArnaldo Carvalho de Melo /*
501f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
502f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
503f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
504f33cbe72SArnaldo Carvalho de Melo  */
50545604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
50645604710SNamhyung Kim 					siginfo_t *info,
507f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
508f33cbe72SArnaldo Carvalho de Melo {
509f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
510f33cbe72SArnaldo Carvalho de Melo 	done = 1;
511f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
512f33cbe72SArnaldo Carvalho de Melo }
513f33cbe72SArnaldo Carvalho de Melo 
5142dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig);
5152dd6d8a1SAdrian Hunter 
51646bc29b9SAdrian Hunter int __weak
51746bc29b9SAdrian Hunter perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused,
51846bc29b9SAdrian Hunter 			    struct perf_tool *tool __maybe_unused,
51946bc29b9SAdrian Hunter 			    perf_event__handler_t process __maybe_unused,
52046bc29b9SAdrian Hunter 			    struct machine *machine __maybe_unused)
52146bc29b9SAdrian Hunter {
52246bc29b9SAdrian Hunter 	return 0;
52346bc29b9SAdrian Hunter }
52446bc29b9SAdrian Hunter 
525c45c86ebSWang Nan static int record__synthesize(struct record *rec)
526c45c86ebSWang Nan {
527c45c86ebSWang Nan 	struct perf_session *session = rec->session;
528c45c86ebSWang Nan 	struct machine *machine = &session->machines.host;
529c45c86ebSWang Nan 	struct perf_data_file *file = &rec->file;
530c45c86ebSWang Nan 	struct record_opts *opts = &rec->opts;
531c45c86ebSWang Nan 	struct perf_tool *tool = &rec->tool;
532c45c86ebSWang Nan 	int fd = perf_data_file__fd(file);
533c45c86ebSWang Nan 	int err = 0;
534c45c86ebSWang Nan 
535c45c86ebSWang Nan 	if (file->is_pipe) {
536c45c86ebSWang Nan 		err = perf_event__synthesize_attrs(tool, session,
537c45c86ebSWang Nan 						   process_synthesized_event);
538c45c86ebSWang Nan 		if (err < 0) {
539c45c86ebSWang Nan 			pr_err("Couldn't synthesize attrs.\n");
540c45c86ebSWang Nan 			goto out;
541c45c86ebSWang Nan 		}
542c45c86ebSWang Nan 
543c45c86ebSWang Nan 		if (have_tracepoints(&rec->evlist->entries)) {
544c45c86ebSWang Nan 			/*
545c45c86ebSWang Nan 			 * FIXME err <= 0 here actually means that
546c45c86ebSWang Nan 			 * there were no tracepoints so its not really
547c45c86ebSWang Nan 			 * an error, just that we don't need to
548c45c86ebSWang Nan 			 * synthesize anything.  We really have to
549c45c86ebSWang Nan 			 * return this more properly and also
550c45c86ebSWang Nan 			 * propagate errors that now are calling die()
551c45c86ebSWang Nan 			 */
552c45c86ebSWang Nan 			err = perf_event__synthesize_tracing_data(tool,	fd, rec->evlist,
553c45c86ebSWang Nan 								  process_synthesized_event);
554c45c86ebSWang Nan 			if (err <= 0) {
555c45c86ebSWang Nan 				pr_err("Couldn't record tracing data.\n");
556c45c86ebSWang Nan 				goto out;
557c45c86ebSWang Nan 			}
558c45c86ebSWang Nan 			rec->bytes_written += err;
559c45c86ebSWang Nan 		}
560c45c86ebSWang Nan 	}
561c45c86ebSWang Nan 
56246bc29b9SAdrian Hunter 	err = perf_event__synth_time_conv(rec->evlist->mmap[0].base, tool,
56346bc29b9SAdrian Hunter 					  process_synthesized_event, machine);
56446bc29b9SAdrian Hunter 	if (err)
56546bc29b9SAdrian Hunter 		goto out;
56646bc29b9SAdrian Hunter 
567c45c86ebSWang Nan 	if (rec->opts.full_auxtrace) {
568c45c86ebSWang Nan 		err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
569c45c86ebSWang Nan 					session, process_synthesized_event);
570c45c86ebSWang Nan 		if (err)
571c45c86ebSWang Nan 			goto out;
572c45c86ebSWang Nan 	}
573c45c86ebSWang Nan 
574c45c86ebSWang Nan 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
575c45c86ebSWang Nan 						 machine);
576c45c86ebSWang Nan 	WARN_ONCE(err < 0, "Couldn't record kernel reference relocation symbol\n"
577c45c86ebSWang Nan 			   "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
578c45c86ebSWang Nan 			   "Check /proc/kallsyms permission or run as root.\n");
579c45c86ebSWang Nan 
580c45c86ebSWang Nan 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
581c45c86ebSWang Nan 					     machine);
582c45c86ebSWang Nan 	WARN_ONCE(err < 0, "Couldn't record kernel module information.\n"
583c45c86ebSWang Nan 			   "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
584c45c86ebSWang Nan 			   "Check /proc/modules permission or run as root.\n");
585c45c86ebSWang Nan 
586c45c86ebSWang Nan 	if (perf_guest) {
587c45c86ebSWang Nan 		machines__process_guests(&session->machines,
588c45c86ebSWang Nan 					 perf_event__synthesize_guest_os, tool);
589c45c86ebSWang Nan 	}
590c45c86ebSWang Nan 
591c45c86ebSWang Nan 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
592c45c86ebSWang Nan 					    process_synthesized_event, opts->sample_address,
593c45c86ebSWang Nan 					    opts->proc_map_timeout);
594c45c86ebSWang Nan out:
595c45c86ebSWang Nan 	return err;
596c45c86ebSWang Nan }
597c45c86ebSWang Nan 
5988c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
59986470930SIngo Molnar {
60057706abcSDavid Ahern 	int err;
60145604710SNamhyung Kim 	int status = 0;
6028b412664SPeter Zijlstra 	unsigned long waking = 0;
60346be604bSZhang, Yanmin 	const bool forks = argc > 0;
60423346f21SArnaldo Carvalho de Melo 	struct machine *machine;
60545694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
606b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
607f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
608d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
6096dcf45efSArnaldo Carvalho de Melo 	bool disabled = false, draining = false;
61042aa276fSNamhyung Kim 	int fd;
61186470930SIngo Molnar 
612d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
61333e49ea7SAndi Kleen 
61445604710SNamhyung Kim 	atexit(record__sig_exit);
615f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
616f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
617804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
6182dd6d8a1SAdrian Hunter 	if (rec->opts.auxtrace_snapshot_mode)
6192dd6d8a1SAdrian Hunter 		signal(SIGUSR2, snapshot_sig_handler);
6202dd6d8a1SAdrian Hunter 	else
6212dd6d8a1SAdrian Hunter 		signal(SIGUSR2, SIG_IGN);
622f5970550SPeter Zijlstra 
623b7b61cbeSArnaldo Carvalho de Melo 	session = perf_session__new(file, false, tool);
62494c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
625ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
626a9a70bbcSArnaldo Carvalho de Melo 		return -1;
627a9a70bbcSArnaldo Carvalho de Melo 	}
628a9a70bbcSArnaldo Carvalho de Melo 
62942aa276fSNamhyung Kim 	fd = perf_data_file__fd(file);
630d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
631d20deb64SArnaldo Carvalho de Melo 
6328c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
633330aa675SStephane Eranian 
634d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
6353e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
636f5fc1412SJiri Olsa 						    argv, file->is_pipe,
637735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
63835b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
63935b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
64045604710SNamhyung Kim 			status = err;
64135b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
642856e9660SPeter Zijlstra 		}
643856e9660SPeter Zijlstra 	}
644856e9660SPeter Zijlstra 
6458c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
6468d3eca20SDavid Ahern 		err = -1;
64745604710SNamhyung Kim 		goto out_child;
6488d3eca20SDavid Ahern 	}
64986470930SIngo Molnar 
6508690a2a7SWang Nan 	err = bpf__apply_obj_config();
6518690a2a7SWang Nan 	if (err) {
6528690a2a7SWang Nan 		char errbuf[BUFSIZ];
6538690a2a7SWang Nan 
6548690a2a7SWang Nan 		bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
6558690a2a7SWang Nan 		pr_err("ERROR: Apply config to BPF failed: %s\n",
6568690a2a7SWang Nan 			 errbuf);
6578690a2a7SWang Nan 		goto out_child;
6588690a2a7SWang Nan 	}
6598690a2a7SWang Nan 
660cca8482cSAdrian Hunter 	/*
661cca8482cSAdrian Hunter 	 * Normally perf_session__new would do this, but it doesn't have the
662cca8482cSAdrian Hunter 	 * evlist.
663cca8482cSAdrian Hunter 	 */
664cca8482cSAdrian Hunter 	if (rec->tool.ordered_events && !perf_evlist__sample_id_all(rec->evlist)) {
665cca8482cSAdrian Hunter 		pr_warning("WARNING: No sample_id_all support, falling back to unordered processing\n");
666cca8482cSAdrian Hunter 		rec->tool.ordered_events = false;
667cca8482cSAdrian Hunter 	}
668cca8482cSAdrian Hunter 
6693e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
670a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
671a8bb559bSNamhyung Kim 
672f5fc1412SJiri Olsa 	if (file->is_pipe) {
67342aa276fSNamhyung Kim 		err = perf_header__write_pipe(fd);
674529870e3STom Zanussi 		if (err < 0)
67545604710SNamhyung Kim 			goto out_child;
676563aecb2SJiri Olsa 	} else {
67742aa276fSNamhyung Kim 		err = perf_session__write_header(session, rec->evlist, fd, false);
678d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
67945604710SNamhyung Kim 			goto out_child;
680d5eed904SArnaldo Carvalho de Melo 	}
6817c6a1c65SPeter Zijlstra 
682d3665498SDavid Ahern 	if (!rec->no_buildid
683e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
684d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
685e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
6868d3eca20SDavid Ahern 		err = -1;
68745604710SNamhyung Kim 		goto out_child;
688e20960c0SRobert Richter 	}
689e20960c0SRobert Richter 
69034ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
691743eb868SArnaldo Carvalho de Melo 
692c45c86ebSWang Nan 	err = record__synthesize(rec);
693c45c86ebSWang Nan 	if (err < 0)
69445604710SNamhyung Kim 		goto out_child;
6958d3eca20SDavid Ahern 
696d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
69786470930SIngo Molnar 		struct sched_param param;
69886470930SIngo Molnar 
699d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
70086470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
7016beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
7028d3eca20SDavid Ahern 			err = -1;
70345604710SNamhyung Kim 			goto out_child;
70486470930SIngo Molnar 		}
70586470930SIngo Molnar 	}
70686470930SIngo Molnar 
707774cb499SJiri Olsa 	/*
708774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
709774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
710774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
711774cb499SJiri Olsa 	 */
7126619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
7133e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
714764e16a3SDavid Ahern 
715856e9660SPeter Zijlstra 	/*
716856e9660SPeter Zijlstra 	 * Let the child rip
717856e9660SPeter Zijlstra 	 */
718e803cf97SNamhyung Kim 	if (forks) {
719e5bed564SNamhyung Kim 		union perf_event *event;
720e5bed564SNamhyung Kim 
721e5bed564SNamhyung Kim 		event = malloc(sizeof(event->comm) + machine->id_hdr_size);
722e5bed564SNamhyung Kim 		if (event == NULL) {
723e5bed564SNamhyung Kim 			err = -ENOMEM;
724e5bed564SNamhyung Kim 			goto out_child;
725e5bed564SNamhyung Kim 		}
726e5bed564SNamhyung Kim 
727e803cf97SNamhyung Kim 		/*
728e803cf97SNamhyung Kim 		 * Some H/W events are generated before COMM event
729e803cf97SNamhyung Kim 		 * which is emitted during exec(), so perf script
730e803cf97SNamhyung Kim 		 * cannot see a correct process name for those events.
731e803cf97SNamhyung Kim 		 * Synthesize COMM event to prevent it.
732e803cf97SNamhyung Kim 		 */
733e5bed564SNamhyung Kim 		perf_event__synthesize_comm(tool, event,
734e803cf97SNamhyung Kim 					    rec->evlist->workload.pid,
735e803cf97SNamhyung Kim 					    process_synthesized_event,
736e803cf97SNamhyung Kim 					    machine);
737e5bed564SNamhyung Kim 		free(event);
738e803cf97SNamhyung Kim 
7393e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
740e803cf97SNamhyung Kim 	}
741856e9660SPeter Zijlstra 
7426619a53eSAndi Kleen 	if (opts->initial_delay) {
7436619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
7446619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
7456619a53eSAndi Kleen 	}
7466619a53eSAndi Kleen 
7472dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 1;
748649c48a9SPeter Zijlstra 	for (;;) {
7499f065194SYang Shi 		unsigned long long hits = rec->samples;
75086470930SIngo Molnar 
7518c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
7522dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
7538d3eca20SDavid Ahern 			err = -1;
75445604710SNamhyung Kim 			goto out_child;
7558d3eca20SDavid Ahern 		}
75686470930SIngo Molnar 
7572dd6d8a1SAdrian Hunter 		if (auxtrace_record__snapshot_started) {
7582dd6d8a1SAdrian Hunter 			auxtrace_record__snapshot_started = 0;
7592dd6d8a1SAdrian Hunter 			if (!auxtrace_snapshot_err)
7602dd6d8a1SAdrian Hunter 				record__read_auxtrace_snapshot(rec);
7612dd6d8a1SAdrian Hunter 			if (auxtrace_snapshot_err) {
7622dd6d8a1SAdrian Hunter 				pr_err("AUX area tracing snapshot failed\n");
7632dd6d8a1SAdrian Hunter 				err = -1;
7642dd6d8a1SAdrian Hunter 				goto out_child;
7652dd6d8a1SAdrian Hunter 			}
7662dd6d8a1SAdrian Hunter 		}
7672dd6d8a1SAdrian Hunter 
768d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
7696dcf45efSArnaldo Carvalho de Melo 			if (done || draining)
770649c48a9SPeter Zijlstra 				break;
771f66a889dSArnaldo Carvalho de Melo 			err = perf_evlist__poll(rec->evlist, -1);
772a515114fSJiri Olsa 			/*
773a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
774a515114fSJiri Olsa 			 * number of returned events and interrupt error.
775a515114fSJiri Olsa 			 */
776a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
77745604710SNamhyung Kim 				err = 0;
7788b412664SPeter Zijlstra 			waking++;
7796dcf45efSArnaldo Carvalho de Melo 
7806dcf45efSArnaldo Carvalho de Melo 			if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
7816dcf45efSArnaldo Carvalho de Melo 				draining = true;
7828b412664SPeter Zijlstra 		}
7838b412664SPeter Zijlstra 
784774cb499SJiri Olsa 		/*
785774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
786774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
787774cb499SJiri Olsa 		 * disable events in this case.
788774cb499SJiri Olsa 		 */
789602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
7902dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
7913e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
7922711926aSJiri Olsa 			disabled = true;
7932711926aSJiri Olsa 		}
7948b412664SPeter Zijlstra 	}
7952dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
7968b412664SPeter Zijlstra 
797f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
79835550da3SMasami Hiramatsu 		char msg[STRERR_BUFSIZE];
799f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
800f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
801f33cbe72SArnaldo Carvalho de Melo 		err = -1;
80245604710SNamhyung Kim 		goto out_child;
803f33cbe72SArnaldo Carvalho de Melo 	}
804f33cbe72SArnaldo Carvalho de Melo 
805e3d59112SNamhyung Kim 	if (!quiet)
8068b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
80786470930SIngo Molnar 
80845604710SNamhyung Kim out_child:
80945604710SNamhyung Kim 	if (forks) {
81045604710SNamhyung Kim 		int exit_status;
81145604710SNamhyung Kim 
81245604710SNamhyung Kim 		if (!child_finished)
81345604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
81445604710SNamhyung Kim 
81545604710SNamhyung Kim 		wait(&exit_status);
81645604710SNamhyung Kim 
81745604710SNamhyung Kim 		if (err < 0)
81845604710SNamhyung Kim 			status = err;
81945604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
82045604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
82145604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
82245604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
82345604710SNamhyung Kim 	} else
82445604710SNamhyung Kim 		status = err;
82545604710SNamhyung Kim 
826e3d59112SNamhyung Kim 	/* this will be recalculated during process_buildids() */
827e3d59112SNamhyung Kim 	rec->samples = 0;
828e3d59112SNamhyung Kim 
829e1ab48baSWang Nan 	if (!err)
830e1ab48baSWang Nan 		record__finish_output(rec);
83139d17dacSArnaldo Carvalho de Melo 
832e3d59112SNamhyung Kim 	if (!err && !quiet) {
833e3d59112SNamhyung Kim 		char samples[128];
834e3d59112SNamhyung Kim 
835ef149c25SAdrian Hunter 		if (rec->samples && !rec->opts.full_auxtrace)
836e3d59112SNamhyung Kim 			scnprintf(samples, sizeof(samples),
837e3d59112SNamhyung Kim 				  " (%" PRIu64 " samples)", rec->samples);
838e3d59112SNamhyung Kim 		else
839e3d59112SNamhyung Kim 			samples[0] = '\0';
840e3d59112SNamhyung Kim 
841e3d59112SNamhyung Kim 		fprintf(stderr,	"[ perf record: Captured and wrote %.3f MB %s%s ]\n",
842e3d59112SNamhyung Kim 			perf_data_file__size(file) / 1024.0 / 1024.0,
843e3d59112SNamhyung Kim 			file->path, samples);
844e3d59112SNamhyung Kim 	}
845e3d59112SNamhyung Kim 
84639d17dacSArnaldo Carvalho de Melo out_delete_session:
84739d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
84845604710SNamhyung Kim 	return status;
84986470930SIngo Molnar }
85086470930SIngo Molnar 
85172a128aaSNamhyung Kim static void callchain_debug(void)
85209b0fd45SJiri Olsa {
853aad2b21cSKan Liang 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" };
854a601fdffSJiri Olsa 
85572a128aaSNamhyung Kim 	pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
85626d33022SJiri Olsa 
85772a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_DWARF)
85809b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
85972a128aaSNamhyung Kim 			 callchain_param.dump_size);
86009b0fd45SJiri Olsa }
86109b0fd45SJiri Olsa 
862c421e80bSKan Liang int record_parse_callchain_opt(const struct option *opt,
86309b0fd45SJiri Olsa 			       const char *arg,
86409b0fd45SJiri Olsa 			       int unset)
86509b0fd45SJiri Olsa {
86609b0fd45SJiri Olsa 	int ret;
867c421e80bSKan Liang 	struct record_opts *record = (struct record_opts *)opt->value;
86809b0fd45SJiri Olsa 
869c421e80bSKan Liang 	record->callgraph_set = true;
87072a128aaSNamhyung Kim 	callchain_param.enabled = !unset;
871eb853e80SJiri Olsa 
87209b0fd45SJiri Olsa 	/* --no-call-graph */
87309b0fd45SJiri Olsa 	if (unset) {
87472a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_NONE;
87509b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
87609b0fd45SJiri Olsa 		return 0;
87709b0fd45SJiri Olsa 	}
87809b0fd45SJiri Olsa 
879c3a6a8c4SKan Liang 	ret = parse_callchain_record_opt(arg, &callchain_param);
8805c0cf224SJiri Olsa 	if (!ret) {
8815c0cf224SJiri Olsa 		/* Enable data address sampling for DWARF unwind. */
8825c0cf224SJiri Olsa 		if (callchain_param.record_mode == CALLCHAIN_DWARF)
8835c0cf224SJiri Olsa 			record->sample_address = true;
88472a128aaSNamhyung Kim 		callchain_debug();
8855c0cf224SJiri Olsa 	}
88609b0fd45SJiri Olsa 
88726d33022SJiri Olsa 	return ret;
88826d33022SJiri Olsa }
88926d33022SJiri Olsa 
890c421e80bSKan Liang int record_callchain_opt(const struct option *opt,
89109b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
89209b0fd45SJiri Olsa 			 int unset __maybe_unused)
89309b0fd45SJiri Olsa {
894c421e80bSKan Liang 	struct record_opts *record = (struct record_opts *)opt->value;
895c421e80bSKan Liang 
896c421e80bSKan Liang 	record->callgraph_set = true;
89772a128aaSNamhyung Kim 	callchain_param.enabled = true;
89809b0fd45SJiri Olsa 
89972a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_NONE)
90072a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_FP;
901eb853e80SJiri Olsa 
90272a128aaSNamhyung Kim 	callchain_debug();
90309b0fd45SJiri Olsa 	return 0;
90409b0fd45SJiri Olsa }
90509b0fd45SJiri Olsa 
906eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
907eb853e80SJiri Olsa {
9087a29c087SNamhyung Kim 	struct record *rec = cb;
9097a29c087SNamhyung Kim 
9107a29c087SNamhyung Kim 	if (!strcmp(var, "record.build-id")) {
9117a29c087SNamhyung Kim 		if (!strcmp(value, "cache"))
9127a29c087SNamhyung Kim 			rec->no_buildid_cache = false;
9137a29c087SNamhyung Kim 		else if (!strcmp(value, "no-cache"))
9147a29c087SNamhyung Kim 			rec->no_buildid_cache = true;
9157a29c087SNamhyung Kim 		else if (!strcmp(value, "skip"))
9167a29c087SNamhyung Kim 			rec->no_buildid = true;
9177a29c087SNamhyung Kim 		else
9187a29c087SNamhyung Kim 			return -1;
9197a29c087SNamhyung Kim 		return 0;
9207a29c087SNamhyung Kim 	}
921eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
9225a2e5e85SNamhyung Kim 		var = "call-graph.record-mode"; /* fall-through */
923eb853e80SJiri Olsa 
924eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
925eb853e80SJiri Olsa }
926eb853e80SJiri Olsa 
927814c8c38SPeter Zijlstra struct clockid_map {
928814c8c38SPeter Zijlstra 	const char *name;
929814c8c38SPeter Zijlstra 	int clockid;
930814c8c38SPeter Zijlstra };
931814c8c38SPeter Zijlstra 
932814c8c38SPeter Zijlstra #define CLOCKID_MAP(n, c)	\
933814c8c38SPeter Zijlstra 	{ .name = n, .clockid = (c), }
934814c8c38SPeter Zijlstra 
935814c8c38SPeter Zijlstra #define CLOCKID_END	{ .name = NULL, }
936814c8c38SPeter Zijlstra 
937814c8c38SPeter Zijlstra 
938814c8c38SPeter Zijlstra /*
939814c8c38SPeter Zijlstra  * Add the missing ones, we need to build on many distros...
940814c8c38SPeter Zijlstra  */
941814c8c38SPeter Zijlstra #ifndef CLOCK_MONOTONIC_RAW
942814c8c38SPeter Zijlstra #define CLOCK_MONOTONIC_RAW 4
943814c8c38SPeter Zijlstra #endif
944814c8c38SPeter Zijlstra #ifndef CLOCK_BOOTTIME
945814c8c38SPeter Zijlstra #define CLOCK_BOOTTIME 7
946814c8c38SPeter Zijlstra #endif
947814c8c38SPeter Zijlstra #ifndef CLOCK_TAI
948814c8c38SPeter Zijlstra #define CLOCK_TAI 11
949814c8c38SPeter Zijlstra #endif
950814c8c38SPeter Zijlstra 
951814c8c38SPeter Zijlstra static const struct clockid_map clockids[] = {
952814c8c38SPeter Zijlstra 	/* available for all events, NMI safe */
953814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic", CLOCK_MONOTONIC),
954814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW),
955814c8c38SPeter Zijlstra 
956814c8c38SPeter Zijlstra 	/* available for some events */
957814c8c38SPeter Zijlstra 	CLOCKID_MAP("realtime", CLOCK_REALTIME),
958814c8c38SPeter Zijlstra 	CLOCKID_MAP("boottime", CLOCK_BOOTTIME),
959814c8c38SPeter Zijlstra 	CLOCKID_MAP("tai", CLOCK_TAI),
960814c8c38SPeter Zijlstra 
961814c8c38SPeter Zijlstra 	/* available for the lazy */
962814c8c38SPeter Zijlstra 	CLOCKID_MAP("mono", CLOCK_MONOTONIC),
963814c8c38SPeter Zijlstra 	CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW),
964814c8c38SPeter Zijlstra 	CLOCKID_MAP("real", CLOCK_REALTIME),
965814c8c38SPeter Zijlstra 	CLOCKID_MAP("boot", CLOCK_BOOTTIME),
966814c8c38SPeter Zijlstra 
967814c8c38SPeter Zijlstra 	CLOCKID_END,
968814c8c38SPeter Zijlstra };
969814c8c38SPeter Zijlstra 
970814c8c38SPeter Zijlstra static int parse_clockid(const struct option *opt, const char *str, int unset)
971814c8c38SPeter Zijlstra {
972814c8c38SPeter Zijlstra 	struct record_opts *opts = (struct record_opts *)opt->value;
973814c8c38SPeter Zijlstra 	const struct clockid_map *cm;
974814c8c38SPeter Zijlstra 	const char *ostr = str;
975814c8c38SPeter Zijlstra 
976814c8c38SPeter Zijlstra 	if (unset) {
977814c8c38SPeter Zijlstra 		opts->use_clockid = 0;
978814c8c38SPeter Zijlstra 		return 0;
979814c8c38SPeter Zijlstra 	}
980814c8c38SPeter Zijlstra 
981814c8c38SPeter Zijlstra 	/* no arg passed */
982814c8c38SPeter Zijlstra 	if (!str)
983814c8c38SPeter Zijlstra 		return 0;
984814c8c38SPeter Zijlstra 
985814c8c38SPeter Zijlstra 	/* no setting it twice */
986814c8c38SPeter Zijlstra 	if (opts->use_clockid)
987814c8c38SPeter Zijlstra 		return -1;
988814c8c38SPeter Zijlstra 
989814c8c38SPeter Zijlstra 	opts->use_clockid = true;
990814c8c38SPeter Zijlstra 
991814c8c38SPeter Zijlstra 	/* if its a number, we're done */
992814c8c38SPeter Zijlstra 	if (sscanf(str, "%d", &opts->clockid) == 1)
993814c8c38SPeter Zijlstra 		return 0;
994814c8c38SPeter Zijlstra 
995814c8c38SPeter Zijlstra 	/* allow a "CLOCK_" prefix to the name */
996814c8c38SPeter Zijlstra 	if (!strncasecmp(str, "CLOCK_", 6))
997814c8c38SPeter Zijlstra 		str += 6;
998814c8c38SPeter Zijlstra 
999814c8c38SPeter Zijlstra 	for (cm = clockids; cm->name; cm++) {
1000814c8c38SPeter Zijlstra 		if (!strcasecmp(str, cm->name)) {
1001814c8c38SPeter Zijlstra 			opts->clockid = cm->clockid;
1002814c8c38SPeter Zijlstra 			return 0;
1003814c8c38SPeter Zijlstra 		}
1004814c8c38SPeter Zijlstra 	}
1005814c8c38SPeter Zijlstra 
1006814c8c38SPeter Zijlstra 	opts->use_clockid = false;
1007814c8c38SPeter Zijlstra 	ui__warning("unknown clockid %s, check man page\n", ostr);
1008814c8c38SPeter Zijlstra 	return -1;
1009814c8c38SPeter Zijlstra }
1010814c8c38SPeter Zijlstra 
1011e9db1310SAdrian Hunter static int record__parse_mmap_pages(const struct option *opt,
1012e9db1310SAdrian Hunter 				    const char *str,
1013e9db1310SAdrian Hunter 				    int unset __maybe_unused)
1014e9db1310SAdrian Hunter {
1015e9db1310SAdrian Hunter 	struct record_opts *opts = opt->value;
1016e9db1310SAdrian Hunter 	char *s, *p;
1017e9db1310SAdrian Hunter 	unsigned int mmap_pages;
1018e9db1310SAdrian Hunter 	int ret;
1019e9db1310SAdrian Hunter 
1020e9db1310SAdrian Hunter 	if (!str)
1021e9db1310SAdrian Hunter 		return -EINVAL;
1022e9db1310SAdrian Hunter 
1023e9db1310SAdrian Hunter 	s = strdup(str);
1024e9db1310SAdrian Hunter 	if (!s)
1025e9db1310SAdrian Hunter 		return -ENOMEM;
1026e9db1310SAdrian Hunter 
1027e9db1310SAdrian Hunter 	p = strchr(s, ',');
1028e9db1310SAdrian Hunter 	if (p)
1029e9db1310SAdrian Hunter 		*p = '\0';
1030e9db1310SAdrian Hunter 
1031e9db1310SAdrian Hunter 	if (*s) {
1032e9db1310SAdrian Hunter 		ret = __perf_evlist__parse_mmap_pages(&mmap_pages, s);
1033e9db1310SAdrian Hunter 		if (ret)
1034e9db1310SAdrian Hunter 			goto out_free;
1035e9db1310SAdrian Hunter 		opts->mmap_pages = mmap_pages;
1036e9db1310SAdrian Hunter 	}
1037e9db1310SAdrian Hunter 
1038e9db1310SAdrian Hunter 	if (!p) {
1039e9db1310SAdrian Hunter 		ret = 0;
1040e9db1310SAdrian Hunter 		goto out_free;
1041e9db1310SAdrian Hunter 	}
1042e9db1310SAdrian Hunter 
1043e9db1310SAdrian Hunter 	ret = __perf_evlist__parse_mmap_pages(&mmap_pages, p + 1);
1044e9db1310SAdrian Hunter 	if (ret)
1045e9db1310SAdrian Hunter 		goto out_free;
1046e9db1310SAdrian Hunter 
1047e9db1310SAdrian Hunter 	opts->auxtrace_mmap_pages = mmap_pages;
1048e9db1310SAdrian Hunter 
1049e9db1310SAdrian Hunter out_free:
1050e9db1310SAdrian Hunter 	free(s);
1051e9db1310SAdrian Hunter 	return ret;
1052e9db1310SAdrian Hunter }
1053e9db1310SAdrian Hunter 
1054e5b2c207SNamhyung Kim static const char * const __record_usage[] = {
105586470930SIngo Molnar 	"perf record [<options>] [<command>]",
105686470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
105786470930SIngo Molnar 	NULL
105886470930SIngo Molnar };
1059e5b2c207SNamhyung Kim const char * const *record_usage = __record_usage;
106086470930SIngo Molnar 
1061d20deb64SArnaldo Carvalho de Melo /*
10628c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
10638c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
1064d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
1065d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
1066d20deb64SArnaldo Carvalho de Melo  *
1067d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
1068d20deb64SArnaldo Carvalho de Melo  *
1069d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
1070d20deb64SArnaldo Carvalho de Melo  */
10718c6f45a7SArnaldo Carvalho de Melo static struct record record = {
1072d20deb64SArnaldo Carvalho de Melo 	.opts = {
10738affc2b8SAndi Kleen 		.sample_time	     = true,
1074d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
1075d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
1076d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
1077447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
1078d1cb9fceSNamhyung Kim 		.target		     = {
1079d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
10803aa5939dSAdrian Hunter 			.default_per_cpu = true,
1081d1cb9fceSNamhyung Kim 		},
10829d9cad76SKan Liang 		.proc_map_timeout     = 500,
1083d20deb64SArnaldo Carvalho de Melo 	},
1084e3d59112SNamhyung Kim 	.tool = {
1085e3d59112SNamhyung Kim 		.sample		= process_sample_event,
1086e3d59112SNamhyung Kim 		.fork		= perf_event__process_fork,
1087cca8482cSAdrian Hunter 		.exit		= perf_event__process_exit,
1088e3d59112SNamhyung Kim 		.comm		= perf_event__process_comm,
1089e3d59112SNamhyung Kim 		.mmap		= perf_event__process_mmap,
1090e3d59112SNamhyung Kim 		.mmap2		= perf_event__process_mmap2,
1091cca8482cSAdrian Hunter 		.ordered_events	= true,
1092e3d59112SNamhyung Kim 	},
1093d20deb64SArnaldo Carvalho de Melo };
10947865e817SFrederic Weisbecker 
109576a26549SNamhyung Kim const char record_callchain_help[] = CALLCHAIN_RECORD_HELP
109676a26549SNamhyung Kim 	"\n\t\t\t\tDefault: fp";
109761eaa3beSArnaldo Carvalho de Melo 
1098d20deb64SArnaldo Carvalho de Melo /*
1099d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
1100d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
1101b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
1102d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
1103d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
1104d20deb64SArnaldo Carvalho de Melo  */
1105e5b2c207SNamhyung Kim struct option __record_options[] = {
1106d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
110786470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
1108f120f9d5SJiri Olsa 		     parse_events_option),
1109d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
1110c171b552SLi Zefan 		     "event filter", parse_filter),
11114ba1faa1SWang Nan 	OPT_CALLBACK_NOOPT(0, "exclude-perf", &record.evlist,
11124ba1faa1SWang Nan 			   NULL, "don't record events from perf itself",
11134ba1faa1SWang Nan 			   exclude_perf),
1114bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
1115d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
1116bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
1117d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
1118d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
111986470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
1120509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
1121acac03faSKirill Smelkov 		    "collect data without buffering"),
1122d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
1123daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
1124bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
112586470930SIngo Molnar 			    "system-wide collection from all CPUs"),
1126bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
1127c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
1128d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
1129f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
113086470930SIngo Molnar 		    "output file name"),
113169e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
113269e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
11332e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
1134d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
1135e9db1310SAdrian Hunter 	OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]",
1136e9db1310SAdrian Hunter 		     "number of mmap data pages and AUX area tracing mmap pages",
1137e9db1310SAdrian Hunter 		     record__parse_mmap_pages),
1138d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
113943bece79SLin Ming 		    "put the counters into a counter group"),
114009b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
114109b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
114209b0fd45SJiri Olsa 			   &record_callchain_opt),
114309b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
114476a26549SNamhyung Kim 		     "record_mode[,record_size]", record_callchain_help,
114509b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
1146c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
11473da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
1148b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
1149d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
1150649c48a9SPeter Zijlstra 		    "per thread counts"),
115156100321SPeter Zijlstra 	OPT_BOOLEAN('d', "data", &record.opts.sample_address, "Record the sample addresses"),
11523abebc55SAdrian Hunter 	OPT_BOOLEAN_SET('T', "timestamp", &record.opts.sample_time,
11533abebc55SAdrian Hunter 			&record.opts.sample_time_set,
11543abebc55SAdrian Hunter 			"Record the sample timestamps"),
115556100321SPeter Zijlstra 	OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"),
1156d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
1157649c48a9SPeter Zijlstra 		    "don't sample"),
1158d2db9a98SWang Nan 	OPT_BOOLEAN_SET('N', "no-buildid-cache", &record.no_buildid_cache,
1159d2db9a98SWang Nan 			&record.no_buildid_cache_set,
1160a1ac1d3cSStephane Eranian 			"do not update the buildid cache"),
1161d2db9a98SWang Nan 	OPT_BOOLEAN_SET('B', "no-buildid", &record.no_buildid,
1162d2db9a98SWang Nan 			&record.no_buildid_set,
1163baa2f6ceSArnaldo Carvalho de Melo 			"do not collect buildids in perf.data"),
1164d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
1165023695d9SStephane Eranian 		     "monitor event in cgroup name only",
1166023695d9SStephane Eranian 		     parse_cgroups),
1167a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
11686619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
1169bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
1170bea03405SNamhyung Kim 		   "user to profile"),
1171a5aabdacSStephane Eranian 
1172a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
1173a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
1174a5aabdacSStephane Eranian 		     parse_branch_stack),
1175a5aabdacSStephane Eranian 
1176a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
1177a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
1178bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
117905484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
118005484298SAndi Kleen 		    "sample by weight (on special events only)"),
1181475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
1182475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
11833aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
11843aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
1185bcc84ec6SStephane Eranian 	OPT_CALLBACK_OPTARG('I', "intr-regs", &record.opts.sample_intr_regs, NULL, "any register",
1186bcc84ec6SStephane Eranian 		    "sample selected machine registers on interrupt,"
1187bcc84ec6SStephane Eranian 		    " use -I ? to list register names", parse_regs),
118885c273d2SAndi Kleen 	OPT_BOOLEAN(0, "running-time", &record.opts.running_time,
118985c273d2SAndi Kleen 		    "Record running/enabled time of read (:S) events"),
1190814c8c38SPeter Zijlstra 	OPT_CALLBACK('k', "clockid", &record.opts,
1191814c8c38SPeter Zijlstra 	"clockid", "clockid to use for events, see clock_gettime()",
1192814c8c38SPeter Zijlstra 	parse_clockid),
11932dd6d8a1SAdrian Hunter 	OPT_STRING_OPTARG('S', "snapshot", &record.opts.auxtrace_snapshot_opts,
11942dd6d8a1SAdrian Hunter 			  "opts", "AUX area tracing Snapshot Mode", ""),
11959d9cad76SKan Liang 	OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout,
11969d9cad76SKan Liang 			"per thread proc mmap processing timeout in ms"),
1197b757bb09SAdrian Hunter 	OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
1198b757bb09SAdrian Hunter 		    "Record context switch events"),
119985723885SJiri Olsa 	OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel,
120085723885SJiri Olsa 			 "Configure all used events to run in kernel space.",
120185723885SJiri Olsa 			 PARSE_OPT_EXCLUSIVE),
120285723885SJiri Olsa 	OPT_BOOLEAN_FLAG(0, "all-user", &record.opts.all_user,
120385723885SJiri Olsa 			 "Configure all used events to run in user space.",
120485723885SJiri Olsa 			 PARSE_OPT_EXCLUSIVE),
120571dc2326SWang Nan 	OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
120671dc2326SWang Nan 		   "clang binary to use for compiling BPF scriptlets"),
120771dc2326SWang Nan 	OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
120871dc2326SWang Nan 		   "options passed to clang when compiling BPF scriptlets"),
12097efe0e03SHe Kuang 	OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
12107efe0e03SHe Kuang 		   "file", "vmlinux pathname"),
12116156681bSNamhyung Kim 	OPT_BOOLEAN(0, "buildid-all", &record.buildid_all,
12126156681bSNamhyung Kim 		    "Record build-id of all DSOs regardless of hits"),
121386470930SIngo Molnar 	OPT_END()
121486470930SIngo Molnar };
121586470930SIngo Molnar 
1216e5b2c207SNamhyung Kim struct option *record_options = __record_options;
1217e5b2c207SNamhyung Kim 
12181d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
121986470930SIngo Molnar {
1220ef149c25SAdrian Hunter 	int err;
12218c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
122216ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
122386470930SIngo Molnar 
122448e1cab1SWang Nan #ifndef HAVE_LIBBPF_SUPPORT
122548e1cab1SWang Nan # define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c)
122648e1cab1SWang Nan 	set_nobuild('\0', "clang-path", true);
122748e1cab1SWang Nan 	set_nobuild('\0', "clang-opt", true);
122848e1cab1SWang Nan # undef set_nobuild
122948e1cab1SWang Nan #endif
123048e1cab1SWang Nan 
12317efe0e03SHe Kuang #ifndef HAVE_BPF_PROLOGUE
12327efe0e03SHe Kuang # if !defined (HAVE_DWARF_SUPPORT)
12337efe0e03SHe Kuang #  define REASON  "NO_DWARF=1"
12347efe0e03SHe Kuang # elif !defined (HAVE_LIBBPF_SUPPORT)
12357efe0e03SHe Kuang #  define REASON  "NO_LIBBPF=1"
12367efe0e03SHe Kuang # else
12377efe0e03SHe Kuang #  define REASON  "this architecture doesn't support BPF prologue"
12387efe0e03SHe Kuang # endif
12397efe0e03SHe Kuang # define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, REASON, c)
12407efe0e03SHe Kuang 	set_nobuild('\0', "vmlinux", true);
12417efe0e03SHe Kuang # undef set_nobuild
12427efe0e03SHe Kuang # undef REASON
12437efe0e03SHe Kuang #endif
12447efe0e03SHe Kuang 
12453e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
12463e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
1247361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
1248361c99a6SArnaldo Carvalho de Melo 
1249eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
1250eb853e80SJiri Olsa 
1251bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
1252a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
1253602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
1254bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
125586470930SIngo Molnar 
1256bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
1257c7118369SNamhyung Kim 		usage_with_options_msg(record_usage, record_options,
1258c7118369SNamhyung Kim 			"cgroup monitoring only available in system-wide mode");
1259c7118369SNamhyung Kim 
1260023695d9SStephane Eranian 	}
1261b757bb09SAdrian Hunter 	if (rec->opts.record_switch_events &&
1262b757bb09SAdrian Hunter 	    !perf_can_record_switch_events()) {
1263c7118369SNamhyung Kim 		ui__error("kernel does not support recording context switch events\n");
1264c7118369SNamhyung Kim 		parse_options_usage(record_usage, record_options, "switch-events", 0);
1265c7118369SNamhyung Kim 		return -EINVAL;
1266b757bb09SAdrian Hunter 	}
1267023695d9SStephane Eranian 
1268ef149c25SAdrian Hunter 	if (!rec->itr) {
1269ef149c25SAdrian Hunter 		rec->itr = auxtrace_record__init(rec->evlist, &err);
1270ef149c25SAdrian Hunter 		if (err)
1271ef149c25SAdrian Hunter 			return err;
1272ef149c25SAdrian Hunter 	}
1273ef149c25SAdrian Hunter 
12742dd6d8a1SAdrian Hunter 	err = auxtrace_parse_snapshot_options(rec->itr, &rec->opts,
12752dd6d8a1SAdrian Hunter 					      rec->opts.auxtrace_snapshot_opts);
12762dd6d8a1SAdrian Hunter 	if (err)
12772dd6d8a1SAdrian Hunter 		return err;
12782dd6d8a1SAdrian Hunter 
1279d7888573SWang Nan 	err = bpf__setup_stdout(rec->evlist);
1280d7888573SWang Nan 	if (err) {
1281d7888573SWang Nan 		bpf__strerror_setup_stdout(rec->evlist, err, errbuf, sizeof(errbuf));
1282d7888573SWang Nan 		pr_err("ERROR: Setup BPF stdout failed: %s\n",
1283d7888573SWang Nan 			 errbuf);
1284d7888573SWang Nan 		return err;
1285d7888573SWang Nan 	}
1286d7888573SWang Nan 
1287ef149c25SAdrian Hunter 	err = -ENOMEM;
1288ef149c25SAdrian Hunter 
12890a7e6d1bSNamhyung Kim 	symbol__init(NULL);
1290baa2f6ceSArnaldo Carvalho de Melo 
1291ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
1292646aaea6SArnaldo Carvalho de Melo 		pr_warning(
1293646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
1294ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
1295646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
1296646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
1297646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
1298646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
1299646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
1300ec80fde7SArnaldo Carvalho de Melo 
1301d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
1302a1ac1d3cSStephane Eranian 		disable_buildid_cache();
1303655000e7SArnaldo Carvalho de Melo 
13043e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
13053e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
130669aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
130769aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
1308bbd36e5eSPeter Zijlstra 	}
130986470930SIngo Molnar 
131069e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
131169e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
131269e7e5b0SAdrian Hunter 
1313602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
131416ad2ffbSNamhyung Kim 	if (err) {
1315602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
131616ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
131716ad2ffbSNamhyung Kim 	}
13184bd0f2d2SNamhyung Kim 
1319602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
132016ad2ffbSNamhyung Kim 	if (err) {
132116ad2ffbSNamhyung Kim 		int saved_errno = errno;
132216ad2ffbSNamhyung Kim 
1323602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
13243780f488SNamhyung Kim 		ui__error("%s", errbuf);
132516ad2ffbSNamhyung Kim 
132616ad2ffbSNamhyung Kim 		err = -saved_errno;
13278fa60e1fSNamhyung Kim 		goto out_symbol_exit;
132816ad2ffbSNamhyung Kim 	}
13290d37aa34SArnaldo Carvalho de Melo 
133016ad2ffbSNamhyung Kim 	err = -ENOMEM;
13313e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
1332dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
133369aad6f1SArnaldo Carvalho de Melo 
1334ef149c25SAdrian Hunter 	err = auxtrace_record__options(rec->itr, rec->evlist, &rec->opts);
1335ef149c25SAdrian Hunter 	if (err)
1336ef149c25SAdrian Hunter 		goto out_symbol_exit;
1337ef149c25SAdrian Hunter 
13386156681bSNamhyung Kim 	/*
13396156681bSNamhyung Kim 	 * We take all buildids when the file contains
13406156681bSNamhyung Kim 	 * AUX area tracing data because we do not decode the
13416156681bSNamhyung Kim 	 * trace because it would take too long.
13426156681bSNamhyung Kim 	 */
13436156681bSNamhyung Kim 	if (rec->opts.full_auxtrace)
13446156681bSNamhyung Kim 		rec->buildid_all = true;
13456156681bSNamhyung Kim 
1346b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
134739d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
134803ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
13497e4ff9e3SMike Galbraith 	}
13507e4ff9e3SMike Galbraith 
1351d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
1352d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
135345604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
1354d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
1355ef149c25SAdrian Hunter 	auxtrace_record__free(rec->itr);
135639d17dacSArnaldo Carvalho de Melo 	return err;
135786470930SIngo Molnar }
13582dd6d8a1SAdrian Hunter 
13592dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig __maybe_unused)
13602dd6d8a1SAdrian Hunter {
13612dd6d8a1SAdrian Hunter 	if (!auxtrace_snapshot_enabled)
13622dd6d8a1SAdrian Hunter 		return;
13632dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
13642dd6d8a1SAdrian Hunter 	auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
13652dd6d8a1SAdrian Hunter 	auxtrace_record__snapshot_started = 1;
13662dd6d8a1SAdrian Hunter }
1367