xref: /openbmc/linux/tools/perf/builtin-record.c (revision 95c365617aa37878592f2f1c6c64e1abb19f0d4a)
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"
32f00898f4SAndi Kleen #include "util/parse-branch-options.h"
33bcc84ec6SStephane Eranian #include "util/parse-regs-options.h"
3471dc2326SWang Nan #include "util/llvm-utils.h"
358690a2a7SWang Nan #include "util/bpf-loader.h"
36d8871ea7SWang Nan #include "asm/bug.h"
377c6a1c65SPeter Zijlstra 
3886470930SIngo Molnar #include <unistd.h>
3986470930SIngo Molnar #include <sched.h>
40a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
4186470930SIngo Molnar 
4278da39faSBernhard Rosenkraenzer 
438c6f45a7SArnaldo Carvalho de Melo struct record {
4445694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
45b4006796SArnaldo Carvalho de Melo 	struct record_opts	opts;
46d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
47f5fc1412SJiri Olsa 	struct perf_data_file	file;
48ef149c25SAdrian Hunter 	struct auxtrace_record	*itr;
49d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
50d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
51d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
52d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
53d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
54d2db9a98SWang Nan 	bool			no_buildid_set;
55d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
56d2db9a98SWang Nan 	bool			no_buildid_cache_set;
576156681bSNamhyung Kim 	bool			buildid_all;
589f065194SYang Shi 	unsigned long long	samples;
590f82ebc4SArnaldo Carvalho de Melo };
6086470930SIngo Molnar 
618c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
62f5970550SPeter Zijlstra {
63cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
644f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
658d3eca20SDavid Ahern 		return -1;
668d3eca20SDavid Ahern 	}
67f5970550SPeter Zijlstra 
68cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
698d3eca20SDavid Ahern 	return 0;
70f5970550SPeter Zijlstra }
71f5970550SPeter Zijlstra 
7245694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
73d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
741d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
751d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
76234fbbf5SArnaldo Carvalho de Melo {
778c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
788c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
79234fbbf5SArnaldo Carvalho de Melo }
80234fbbf5SArnaldo Carvalho de Melo 
81e5685730SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, int idx)
8286470930SIngo Molnar {
83e5685730SArnaldo Carvalho de Melo 	struct perf_mmap *md = &rec->evlist->mmap[idx];
847b8283b5SDavid Ahern 	u64 head = perf_mmap__read_head(md);
857b8283b5SDavid Ahern 	u64 old = md->prev;
86918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
8786470930SIngo Molnar 	unsigned long size;
8886470930SIngo Molnar 	void *buf;
898d3eca20SDavid Ahern 	int rc = 0;
9086470930SIngo Molnar 
91dc82009aSArnaldo Carvalho de Melo 	if (old == head)
928d3eca20SDavid Ahern 		return 0;
9386470930SIngo Molnar 
94d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
9586470930SIngo Molnar 
9686470930SIngo Molnar 	size = head - old;
9786470930SIngo Molnar 
9886470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
9986470930SIngo Molnar 		buf = &data[old & md->mask];
10086470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
10186470930SIngo Molnar 		old += size;
10286470930SIngo Molnar 
1038c6f45a7SArnaldo Carvalho de Melo 		if (record__write(rec, buf, size) < 0) {
1048d3eca20SDavid Ahern 			rc = -1;
1058d3eca20SDavid Ahern 			goto out;
1068d3eca20SDavid Ahern 		}
10786470930SIngo Molnar 	}
10886470930SIngo Molnar 
10986470930SIngo Molnar 	buf = &data[old & md->mask];
11086470930SIngo Molnar 	size = head - old;
11186470930SIngo Molnar 	old += size;
11286470930SIngo Molnar 
1138c6f45a7SArnaldo Carvalho de Melo 	if (record__write(rec, buf, size) < 0) {
1148d3eca20SDavid Ahern 		rc = -1;
1158d3eca20SDavid Ahern 		goto out;
1168d3eca20SDavid Ahern 	}
11786470930SIngo Molnar 
11886470930SIngo Molnar 	md->prev = old;
119e5685730SArnaldo Carvalho de Melo 	perf_evlist__mmap_consume(rec->evlist, idx);
1208d3eca20SDavid Ahern out:
1218d3eca20SDavid Ahern 	return rc;
12286470930SIngo Molnar }
12386470930SIngo Molnar 
1242dd6d8a1SAdrian Hunter static volatile int done;
1252dd6d8a1SAdrian Hunter static volatile int signr = -1;
1262dd6d8a1SAdrian Hunter static volatile int child_finished;
1272dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_enabled;
1282dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_err;
1292dd6d8a1SAdrian Hunter static volatile int auxtrace_record__snapshot_started;
1302dd6d8a1SAdrian Hunter 
1312dd6d8a1SAdrian Hunter static void sig_handler(int sig)
1322dd6d8a1SAdrian Hunter {
1332dd6d8a1SAdrian Hunter 	if (sig == SIGCHLD)
1342dd6d8a1SAdrian Hunter 		child_finished = 1;
1352dd6d8a1SAdrian Hunter 	else
1362dd6d8a1SAdrian Hunter 		signr = sig;
1372dd6d8a1SAdrian Hunter 
1382dd6d8a1SAdrian Hunter 	done = 1;
1392dd6d8a1SAdrian Hunter }
1402dd6d8a1SAdrian Hunter 
1412dd6d8a1SAdrian Hunter static void record__sig_exit(void)
1422dd6d8a1SAdrian Hunter {
1432dd6d8a1SAdrian Hunter 	if (signr == -1)
1442dd6d8a1SAdrian Hunter 		return;
1452dd6d8a1SAdrian Hunter 
1462dd6d8a1SAdrian Hunter 	signal(signr, SIG_DFL);
1472dd6d8a1SAdrian Hunter 	raise(signr);
1482dd6d8a1SAdrian Hunter }
1492dd6d8a1SAdrian Hunter 
150e31f0d01SAdrian Hunter #ifdef HAVE_AUXTRACE_SUPPORT
151e31f0d01SAdrian Hunter 
152ef149c25SAdrian Hunter static int record__process_auxtrace(struct perf_tool *tool,
153ef149c25SAdrian Hunter 				    union perf_event *event, void *data1,
154ef149c25SAdrian Hunter 				    size_t len1, void *data2, size_t len2)
155ef149c25SAdrian Hunter {
156ef149c25SAdrian Hunter 	struct record *rec = container_of(tool, struct record, tool);
15799fa2984SAdrian Hunter 	struct perf_data_file *file = &rec->file;
158ef149c25SAdrian Hunter 	size_t padding;
159ef149c25SAdrian Hunter 	u8 pad[8] = {0};
160ef149c25SAdrian Hunter 
16199fa2984SAdrian Hunter 	if (!perf_data_file__is_pipe(file)) {
16299fa2984SAdrian Hunter 		off_t file_offset;
16399fa2984SAdrian Hunter 		int fd = perf_data_file__fd(file);
16499fa2984SAdrian Hunter 		int err;
16599fa2984SAdrian Hunter 
16699fa2984SAdrian Hunter 		file_offset = lseek(fd, 0, SEEK_CUR);
16799fa2984SAdrian Hunter 		if (file_offset == -1)
16899fa2984SAdrian Hunter 			return -1;
16999fa2984SAdrian Hunter 		err = auxtrace_index__auxtrace_event(&rec->session->auxtrace_index,
17099fa2984SAdrian Hunter 						     event, file_offset);
17199fa2984SAdrian Hunter 		if (err)
17299fa2984SAdrian Hunter 			return err;
17399fa2984SAdrian Hunter 	}
17499fa2984SAdrian Hunter 
175ef149c25SAdrian Hunter 	/* event.auxtrace.size includes padding, see __auxtrace_mmap__read() */
176ef149c25SAdrian Hunter 	padding = (len1 + len2) & 7;
177ef149c25SAdrian Hunter 	if (padding)
178ef149c25SAdrian Hunter 		padding = 8 - padding;
179ef149c25SAdrian Hunter 
180ef149c25SAdrian Hunter 	record__write(rec, event, event->header.size);
181ef149c25SAdrian Hunter 	record__write(rec, data1, len1);
182ef149c25SAdrian Hunter 	if (len2)
183ef149c25SAdrian Hunter 		record__write(rec, data2, len2);
184ef149c25SAdrian Hunter 	record__write(rec, &pad, padding);
185ef149c25SAdrian Hunter 
186ef149c25SAdrian Hunter 	return 0;
187ef149c25SAdrian Hunter }
188ef149c25SAdrian Hunter 
189ef149c25SAdrian Hunter static int record__auxtrace_mmap_read(struct record *rec,
190ef149c25SAdrian Hunter 				      struct auxtrace_mmap *mm)
191ef149c25SAdrian Hunter {
192ef149c25SAdrian Hunter 	int ret;
193ef149c25SAdrian Hunter 
194ef149c25SAdrian Hunter 	ret = auxtrace_mmap__read(mm, rec->itr, &rec->tool,
195ef149c25SAdrian Hunter 				  record__process_auxtrace);
196ef149c25SAdrian Hunter 	if (ret < 0)
197ef149c25SAdrian Hunter 		return ret;
198ef149c25SAdrian Hunter 
199ef149c25SAdrian Hunter 	if (ret)
200ef149c25SAdrian Hunter 		rec->samples++;
201ef149c25SAdrian Hunter 
202ef149c25SAdrian Hunter 	return 0;
203ef149c25SAdrian Hunter }
204ef149c25SAdrian Hunter 
2052dd6d8a1SAdrian Hunter static int record__auxtrace_mmap_read_snapshot(struct record *rec,
2062dd6d8a1SAdrian Hunter 					       struct auxtrace_mmap *mm)
2072dd6d8a1SAdrian Hunter {
2082dd6d8a1SAdrian Hunter 	int ret;
2092dd6d8a1SAdrian Hunter 
2102dd6d8a1SAdrian Hunter 	ret = auxtrace_mmap__read_snapshot(mm, rec->itr, &rec->tool,
2112dd6d8a1SAdrian Hunter 					   record__process_auxtrace,
2122dd6d8a1SAdrian Hunter 					   rec->opts.auxtrace_snapshot_size);
2132dd6d8a1SAdrian Hunter 	if (ret < 0)
2142dd6d8a1SAdrian Hunter 		return ret;
2152dd6d8a1SAdrian Hunter 
2162dd6d8a1SAdrian Hunter 	if (ret)
2172dd6d8a1SAdrian Hunter 		rec->samples++;
2182dd6d8a1SAdrian Hunter 
2192dd6d8a1SAdrian Hunter 	return 0;
2202dd6d8a1SAdrian Hunter }
2212dd6d8a1SAdrian Hunter 
2222dd6d8a1SAdrian Hunter static int record__auxtrace_read_snapshot_all(struct record *rec)
2232dd6d8a1SAdrian Hunter {
2242dd6d8a1SAdrian Hunter 	int i;
2252dd6d8a1SAdrian Hunter 	int rc = 0;
2262dd6d8a1SAdrian Hunter 
2272dd6d8a1SAdrian Hunter 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
2282dd6d8a1SAdrian Hunter 		struct auxtrace_mmap *mm =
2292dd6d8a1SAdrian Hunter 				&rec->evlist->mmap[i].auxtrace_mmap;
2302dd6d8a1SAdrian Hunter 
2312dd6d8a1SAdrian Hunter 		if (!mm->base)
2322dd6d8a1SAdrian Hunter 			continue;
2332dd6d8a1SAdrian Hunter 
2342dd6d8a1SAdrian Hunter 		if (record__auxtrace_mmap_read_snapshot(rec, mm) != 0) {
2352dd6d8a1SAdrian Hunter 			rc = -1;
2362dd6d8a1SAdrian Hunter 			goto out;
2372dd6d8a1SAdrian Hunter 		}
2382dd6d8a1SAdrian Hunter 	}
2392dd6d8a1SAdrian Hunter out:
2402dd6d8a1SAdrian Hunter 	return rc;
2412dd6d8a1SAdrian Hunter }
2422dd6d8a1SAdrian Hunter 
2432dd6d8a1SAdrian Hunter static void record__read_auxtrace_snapshot(struct record *rec)
2442dd6d8a1SAdrian Hunter {
2452dd6d8a1SAdrian Hunter 	pr_debug("Recording AUX area tracing snapshot\n");
2462dd6d8a1SAdrian Hunter 	if (record__auxtrace_read_snapshot_all(rec) < 0) {
2472dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = -1;
2482dd6d8a1SAdrian Hunter 	} else {
2492dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr);
2502dd6d8a1SAdrian Hunter 		if (!auxtrace_snapshot_err)
2512dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 1;
2522dd6d8a1SAdrian Hunter 	}
2532dd6d8a1SAdrian Hunter }
2542dd6d8a1SAdrian Hunter 
255e31f0d01SAdrian Hunter #else
256e31f0d01SAdrian Hunter 
257e31f0d01SAdrian Hunter static inline
258e31f0d01SAdrian Hunter int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
259e31f0d01SAdrian Hunter 			       struct auxtrace_mmap *mm __maybe_unused)
260e31f0d01SAdrian Hunter {
261e31f0d01SAdrian Hunter 	return 0;
262e31f0d01SAdrian Hunter }
263e31f0d01SAdrian Hunter 
2642dd6d8a1SAdrian Hunter static inline
2652dd6d8a1SAdrian Hunter void record__read_auxtrace_snapshot(struct record *rec __maybe_unused)
2662dd6d8a1SAdrian Hunter {
2672dd6d8a1SAdrian Hunter }
2682dd6d8a1SAdrian Hunter 
2692dd6d8a1SAdrian Hunter static inline
2702dd6d8a1SAdrian Hunter int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused)
2712dd6d8a1SAdrian Hunter {
2722dd6d8a1SAdrian Hunter 	return 0;
2732dd6d8a1SAdrian Hunter }
2742dd6d8a1SAdrian Hunter 
275e31f0d01SAdrian Hunter #endif
276e31f0d01SAdrian Hunter 
2778c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
278dd7927f4SArnaldo Carvalho de Melo {
27956e52e85SArnaldo Carvalho de Melo 	char msg[512];
2806a4bb04cSJiri Olsa 	struct perf_evsel *pos;
281d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
282d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
283b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
2848d3eca20SDavid Ahern 	int rc = 0;
285dd7927f4SArnaldo Carvalho de Melo 
286f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
287cac21425SJiri Olsa 
2880050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
2893da297a6SIngo Molnar try_again:
290d988d5eeSKan Liang 		if (perf_evsel__open(pos, pos->cpus, pos->threads) < 0) {
29156e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2923da297a6SIngo Molnar 				if (verbose)
293c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2943da297a6SIngo Molnar 				goto try_again;
2953da297a6SIngo Molnar 			}
296ca6a4258SDavid Ahern 
29756e52e85SArnaldo Carvalho de Melo 			rc = -errno;
29856e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
29956e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
30056e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
3018d3eca20SDavid Ahern 			goto out;
3027c6a1c65SPeter Zijlstra 		}
3037c6a1c65SPeter Zijlstra 	}
3047c6a1c65SPeter Zijlstra 
30523d4aad4SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist, &pos)) {
30623d4aad4SArnaldo Carvalho de Melo 		error("failed to set filter \"%s\" on event %s with %d (%s)\n",
30723d4aad4SArnaldo Carvalho de Melo 			pos->filter, perf_evsel__name(pos), errno,
30835550da3SMasami Hiramatsu 			strerror_r(errno, msg, sizeof(msg)));
3098d3eca20SDavid Ahern 		rc = -1;
3108d3eca20SDavid Ahern 		goto out;
3110a102479SFrederic Weisbecker 	}
3120a102479SFrederic Weisbecker 
313ef149c25SAdrian Hunter 	if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
3142dd6d8a1SAdrian Hunter 				 opts->auxtrace_mmap_pages,
3152dd6d8a1SAdrian Hunter 				 opts->auxtrace_snapshot_mode) < 0) {
3168d3eca20SDavid Ahern 		if (errno == EPERM) {
3178d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
31818e60939SNelson Elhage 			       "Consider increasing "
31918e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
32018e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
321ef149c25SAdrian Hunter 			       "(current value: %u,%u)\n",
322ef149c25SAdrian Hunter 			       opts->mmap_pages, opts->auxtrace_mmap_pages);
3238d3eca20SDavid Ahern 			rc = -errno;
3248d3eca20SDavid Ahern 		} else {
32535550da3SMasami Hiramatsu 			pr_err("failed to mmap with %d (%s)\n", errno,
32635550da3SMasami Hiramatsu 				strerror_r(errno, msg, sizeof(msg)));
327*95c36561SWang Nan 			if (errno)
3288d3eca20SDavid Ahern 				rc = -errno;
329*95c36561SWang Nan 			else
330*95c36561SWang Nan 				rc = -EINVAL;
3318d3eca20SDavid Ahern 		}
3328d3eca20SDavid Ahern 		goto out;
33318e60939SNelson Elhage 	}
3340a27d7f9SArnaldo Carvalho de Melo 
335a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
3367b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
3378d3eca20SDavid Ahern out:
3388d3eca20SDavid Ahern 	return rc;
339a91e5431SArnaldo Carvalho de Melo }
340a91e5431SArnaldo Carvalho de Melo 
341e3d59112SNamhyung Kim static int process_sample_event(struct perf_tool *tool,
342e3d59112SNamhyung Kim 				union perf_event *event,
343e3d59112SNamhyung Kim 				struct perf_sample *sample,
344e3d59112SNamhyung Kim 				struct perf_evsel *evsel,
345e3d59112SNamhyung Kim 				struct machine *machine)
346e3d59112SNamhyung Kim {
347e3d59112SNamhyung Kim 	struct record *rec = container_of(tool, struct record, tool);
348e3d59112SNamhyung Kim 
349e3d59112SNamhyung Kim 	rec->samples++;
350e3d59112SNamhyung Kim 
351e3d59112SNamhyung Kim 	return build_id__mark_dso_hit(tool, event, sample, evsel, machine);
352e3d59112SNamhyung Kim }
353e3d59112SNamhyung Kim 
3548c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
3556122e4e4SArnaldo Carvalho de Melo {
356f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
357f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
3586122e4e4SArnaldo Carvalho de Melo 
359457ae94aSHe Kuang 	if (file->size == 0)
3609f591fd7SArnaldo Carvalho de Melo 		return 0;
3619f591fd7SArnaldo Carvalho de Melo 
36200dc8657SNamhyung Kim 	/*
36300dc8657SNamhyung Kim 	 * During this process, it'll load kernel map and replace the
36400dc8657SNamhyung Kim 	 * dso->long_name to a real pathname it found.  In this case
36500dc8657SNamhyung Kim 	 * we prefer the vmlinux path like
36600dc8657SNamhyung Kim 	 *   /lib/modules/3.16.4/build/vmlinux
36700dc8657SNamhyung Kim 	 *
36800dc8657SNamhyung Kim 	 * rather than build-id path (in debug directory).
36900dc8657SNamhyung Kim 	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
37000dc8657SNamhyung Kim 	 */
37100dc8657SNamhyung Kim 	symbol_conf.ignore_vmlinux_buildid = true;
37200dc8657SNamhyung Kim 
3736156681bSNamhyung Kim 	/*
3746156681bSNamhyung Kim 	 * If --buildid-all is given, it marks all DSO regardless of hits,
3756156681bSNamhyung Kim 	 * so no need to process samples.
3766156681bSNamhyung Kim 	 */
3776156681bSNamhyung Kim 	if (rec->buildid_all)
3786156681bSNamhyung Kim 		rec->tool.sample = NULL;
3796156681bSNamhyung Kim 
380b7b61cbeSArnaldo Carvalho de Melo 	return perf_session__process_events(session);
3816122e4e4SArnaldo Carvalho de Melo }
3826122e4e4SArnaldo Carvalho de Melo 
3838115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
384a1645ce1SZhang, Yanmin {
385a1645ce1SZhang, Yanmin 	int err;
38645694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
387a1645ce1SZhang, Yanmin 	/*
388a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
389a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
390a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
391a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
392a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
393a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
394a1645ce1SZhang, Yanmin 	 */
39545694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
396743eb868SArnaldo Carvalho de Melo 					     machine);
397a1645ce1SZhang, Yanmin 	if (err < 0)
398a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
39923346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
400a1645ce1SZhang, Yanmin 
401a1645ce1SZhang, Yanmin 	/*
402a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
403a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
404a1645ce1SZhang, Yanmin 	 */
40545694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
4060ae617beSAdrian Hunter 						 machine);
407a1645ce1SZhang, Yanmin 	if (err < 0)
408a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
40923346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
410a1645ce1SZhang, Yanmin }
411a1645ce1SZhang, Yanmin 
41298402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
41398402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
41498402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
41598402807SFrederic Weisbecker };
41698402807SFrederic Weisbecker 
4178c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
41898402807SFrederic Weisbecker {
419dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
4200e2e63ddSPeter Zijlstra 	int i;
4218d3eca20SDavid Ahern 	int rc = 0;
42298402807SFrederic Weisbecker 
423d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
424ef149c25SAdrian Hunter 		struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap;
425ef149c25SAdrian Hunter 
4268d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
427e5685730SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, i) != 0) {
4288d3eca20SDavid Ahern 				rc = -1;
4298d3eca20SDavid Ahern 				goto out;
4308d3eca20SDavid Ahern 			}
4318d3eca20SDavid Ahern 		}
432ef149c25SAdrian Hunter 
4332dd6d8a1SAdrian Hunter 		if (mm->base && !rec->opts.auxtrace_snapshot_mode &&
434ef149c25SAdrian Hunter 		    record__auxtrace_mmap_read(rec, mm) != 0) {
435ef149c25SAdrian Hunter 			rc = -1;
436ef149c25SAdrian Hunter 			goto out;
437ef149c25SAdrian Hunter 		}
43898402807SFrederic Weisbecker 	}
43998402807SFrederic Weisbecker 
440dcabb507SJiri Olsa 	/*
441dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
442dcabb507SJiri Olsa 	 * at least one event.
443dcabb507SJiri Olsa 	 */
444dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
4458c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
4468d3eca20SDavid Ahern 
4478d3eca20SDavid Ahern out:
4488d3eca20SDavid Ahern 	return rc;
44998402807SFrederic Weisbecker }
45098402807SFrederic Weisbecker 
4518c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
45257706abcSDavid Ahern {
45357706abcSDavid Ahern 	struct perf_session *session = rec->session;
45457706abcSDavid Ahern 	int feat;
45557706abcSDavid Ahern 
45657706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
45757706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
45857706abcSDavid Ahern 
45957706abcSDavid Ahern 	if (rec->no_buildid)
46057706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
46157706abcSDavid Ahern 
4623e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
46357706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
46457706abcSDavid Ahern 
46557706abcSDavid Ahern 	if (!rec->opts.branch_stack)
46657706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
467ef149c25SAdrian Hunter 
468ef149c25SAdrian Hunter 	if (!rec->opts.full_auxtrace)
469ef149c25SAdrian Hunter 		perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
470ffa517adSJiri Olsa 
471ffa517adSJiri Olsa 	perf_header__clear_feat(&session->header, HEADER_STAT);
47257706abcSDavid Ahern }
47357706abcSDavid Ahern 
474e1ab48baSWang Nan static void
475e1ab48baSWang Nan record__finish_output(struct record *rec)
476e1ab48baSWang Nan {
477e1ab48baSWang Nan 	struct perf_data_file *file = &rec->file;
478e1ab48baSWang Nan 	int fd = perf_data_file__fd(file);
479e1ab48baSWang Nan 
480e1ab48baSWang Nan 	if (file->is_pipe)
481e1ab48baSWang Nan 		return;
482e1ab48baSWang Nan 
483e1ab48baSWang Nan 	rec->session->header.data_size += rec->bytes_written;
484e1ab48baSWang Nan 	file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
485e1ab48baSWang Nan 
486e1ab48baSWang Nan 	if (!rec->no_buildid) {
487e1ab48baSWang Nan 		process_buildids(rec);
488e1ab48baSWang Nan 
489e1ab48baSWang Nan 		if (rec->buildid_all)
490e1ab48baSWang Nan 			dsos__hit_all(rec->session);
491e1ab48baSWang Nan 	}
492e1ab48baSWang Nan 	perf_session__write_header(rec->session, rec->evlist, fd, true);
493e1ab48baSWang Nan 
494e1ab48baSWang Nan 	return;
495e1ab48baSWang Nan }
496e1ab48baSWang Nan 
497f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
498f33cbe72SArnaldo Carvalho de Melo 
499f33cbe72SArnaldo Carvalho de Melo /*
500f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
501f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
502f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
503f33cbe72SArnaldo Carvalho de Melo  */
50445604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
50545604710SNamhyung Kim 					siginfo_t *info,
506f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
507f33cbe72SArnaldo Carvalho de Melo {
508f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
509f33cbe72SArnaldo Carvalho de Melo 	done = 1;
510f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
511f33cbe72SArnaldo Carvalho de Melo }
512f33cbe72SArnaldo Carvalho de Melo 
5132dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig);
5142dd6d8a1SAdrian Hunter 
515c45c86ebSWang Nan static int record__synthesize(struct record *rec)
516c45c86ebSWang Nan {
517c45c86ebSWang Nan 	struct perf_session *session = rec->session;
518c45c86ebSWang Nan 	struct machine *machine = &session->machines.host;
519c45c86ebSWang Nan 	struct perf_data_file *file = &rec->file;
520c45c86ebSWang Nan 	struct record_opts *opts = &rec->opts;
521c45c86ebSWang Nan 	struct perf_tool *tool = &rec->tool;
522c45c86ebSWang Nan 	int fd = perf_data_file__fd(file);
523c45c86ebSWang Nan 	int err = 0;
524c45c86ebSWang Nan 
525c45c86ebSWang Nan 	if (file->is_pipe) {
526c45c86ebSWang Nan 		err = perf_event__synthesize_attrs(tool, session,
527c45c86ebSWang Nan 						   process_synthesized_event);
528c45c86ebSWang Nan 		if (err < 0) {
529c45c86ebSWang Nan 			pr_err("Couldn't synthesize attrs.\n");
530c45c86ebSWang Nan 			goto out;
531c45c86ebSWang Nan 		}
532c45c86ebSWang Nan 
533c45c86ebSWang Nan 		if (have_tracepoints(&rec->evlist->entries)) {
534c45c86ebSWang Nan 			/*
535c45c86ebSWang Nan 			 * FIXME err <= 0 here actually means that
536c45c86ebSWang Nan 			 * there were no tracepoints so its not really
537c45c86ebSWang Nan 			 * an error, just that we don't need to
538c45c86ebSWang Nan 			 * synthesize anything.  We really have to
539c45c86ebSWang Nan 			 * return this more properly and also
540c45c86ebSWang Nan 			 * propagate errors that now are calling die()
541c45c86ebSWang Nan 			 */
542c45c86ebSWang Nan 			err = perf_event__synthesize_tracing_data(tool,	fd, rec->evlist,
543c45c86ebSWang Nan 								  process_synthesized_event);
544c45c86ebSWang Nan 			if (err <= 0) {
545c45c86ebSWang Nan 				pr_err("Couldn't record tracing data.\n");
546c45c86ebSWang Nan 				goto out;
547c45c86ebSWang Nan 			}
548c45c86ebSWang Nan 			rec->bytes_written += err;
549c45c86ebSWang Nan 		}
550c45c86ebSWang Nan 	}
551c45c86ebSWang Nan 
552c45c86ebSWang Nan 	if (rec->opts.full_auxtrace) {
553c45c86ebSWang Nan 		err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
554c45c86ebSWang Nan 					session, process_synthesized_event);
555c45c86ebSWang Nan 		if (err)
556c45c86ebSWang Nan 			goto out;
557c45c86ebSWang Nan 	}
558c45c86ebSWang Nan 
559c45c86ebSWang Nan 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
560c45c86ebSWang Nan 						 machine);
561c45c86ebSWang Nan 	WARN_ONCE(err < 0, "Couldn't record kernel reference relocation symbol\n"
562c45c86ebSWang Nan 			   "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
563c45c86ebSWang Nan 			   "Check /proc/kallsyms permission or run as root.\n");
564c45c86ebSWang Nan 
565c45c86ebSWang Nan 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
566c45c86ebSWang Nan 					     machine);
567c45c86ebSWang Nan 	WARN_ONCE(err < 0, "Couldn't record kernel module information.\n"
568c45c86ebSWang Nan 			   "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
569c45c86ebSWang Nan 			   "Check /proc/modules permission or run as root.\n");
570c45c86ebSWang Nan 
571c45c86ebSWang Nan 	if (perf_guest) {
572c45c86ebSWang Nan 		machines__process_guests(&session->machines,
573c45c86ebSWang Nan 					 perf_event__synthesize_guest_os, tool);
574c45c86ebSWang Nan 	}
575c45c86ebSWang Nan 
576c45c86ebSWang Nan 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
577c45c86ebSWang Nan 					    process_synthesized_event, opts->sample_address,
578c45c86ebSWang Nan 					    opts->proc_map_timeout);
579c45c86ebSWang Nan out:
580c45c86ebSWang Nan 	return err;
581c45c86ebSWang Nan }
582c45c86ebSWang Nan 
5838c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
58486470930SIngo Molnar {
58557706abcSDavid Ahern 	int err;
58645604710SNamhyung Kim 	int status = 0;
5878b412664SPeter Zijlstra 	unsigned long waking = 0;
58846be604bSZhang, Yanmin 	const bool forks = argc > 0;
58923346f21SArnaldo Carvalho de Melo 	struct machine *machine;
59045694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
591b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
592f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
593d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
5946dcf45efSArnaldo Carvalho de Melo 	bool disabled = false, draining = false;
59542aa276fSNamhyung Kim 	int fd;
59686470930SIngo Molnar 
597d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
59833e49ea7SAndi Kleen 
59945604710SNamhyung Kim 	atexit(record__sig_exit);
600f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
601f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
602804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
6032dd6d8a1SAdrian Hunter 	if (rec->opts.auxtrace_snapshot_mode)
6042dd6d8a1SAdrian Hunter 		signal(SIGUSR2, snapshot_sig_handler);
6052dd6d8a1SAdrian Hunter 	else
6062dd6d8a1SAdrian Hunter 		signal(SIGUSR2, SIG_IGN);
607f5970550SPeter Zijlstra 
608b7b61cbeSArnaldo Carvalho de Melo 	session = perf_session__new(file, false, tool);
60994c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
610ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
611a9a70bbcSArnaldo Carvalho de Melo 		return -1;
612a9a70bbcSArnaldo Carvalho de Melo 	}
613a9a70bbcSArnaldo Carvalho de Melo 
61442aa276fSNamhyung Kim 	fd = perf_data_file__fd(file);
615d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
616d20deb64SArnaldo Carvalho de Melo 
6178c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
618330aa675SStephane Eranian 
619d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
6203e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
621f5fc1412SJiri Olsa 						    argv, file->is_pipe,
622735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
62335b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
62435b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
62545604710SNamhyung Kim 			status = err;
62635b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
627856e9660SPeter Zijlstra 		}
628856e9660SPeter Zijlstra 	}
629856e9660SPeter Zijlstra 
6308c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
6318d3eca20SDavid Ahern 		err = -1;
63245604710SNamhyung Kim 		goto out_child;
6338d3eca20SDavid Ahern 	}
63486470930SIngo Molnar 
6358690a2a7SWang Nan 	err = bpf__apply_obj_config();
6368690a2a7SWang Nan 	if (err) {
6378690a2a7SWang Nan 		char errbuf[BUFSIZ];
6388690a2a7SWang Nan 
6398690a2a7SWang Nan 		bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
6408690a2a7SWang Nan 		pr_err("ERROR: Apply config to BPF failed: %s\n",
6418690a2a7SWang Nan 			 errbuf);
6428690a2a7SWang Nan 		goto out_child;
6438690a2a7SWang Nan 	}
6448690a2a7SWang Nan 
645cca8482cSAdrian Hunter 	/*
646cca8482cSAdrian Hunter 	 * Normally perf_session__new would do this, but it doesn't have the
647cca8482cSAdrian Hunter 	 * evlist.
648cca8482cSAdrian Hunter 	 */
649cca8482cSAdrian Hunter 	if (rec->tool.ordered_events && !perf_evlist__sample_id_all(rec->evlist)) {
650cca8482cSAdrian Hunter 		pr_warning("WARNING: No sample_id_all support, falling back to unordered processing\n");
651cca8482cSAdrian Hunter 		rec->tool.ordered_events = false;
652cca8482cSAdrian Hunter 	}
653cca8482cSAdrian Hunter 
6543e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
655a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
656a8bb559bSNamhyung Kim 
657f5fc1412SJiri Olsa 	if (file->is_pipe) {
65842aa276fSNamhyung Kim 		err = perf_header__write_pipe(fd);
659529870e3STom Zanussi 		if (err < 0)
66045604710SNamhyung Kim 			goto out_child;
661563aecb2SJiri Olsa 	} else {
66242aa276fSNamhyung Kim 		err = perf_session__write_header(session, rec->evlist, fd, false);
663d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
66445604710SNamhyung Kim 			goto out_child;
665d5eed904SArnaldo Carvalho de Melo 	}
6667c6a1c65SPeter Zijlstra 
667d3665498SDavid Ahern 	if (!rec->no_buildid
668e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
669d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
670e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
6718d3eca20SDavid Ahern 		err = -1;
67245604710SNamhyung Kim 		goto out_child;
673e20960c0SRobert Richter 	}
674e20960c0SRobert Richter 
67534ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
676743eb868SArnaldo Carvalho de Melo 
677c45c86ebSWang Nan 	err = record__synthesize(rec);
678c45c86ebSWang Nan 	if (err < 0)
67945604710SNamhyung Kim 		goto out_child;
6808d3eca20SDavid Ahern 
681d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
68286470930SIngo Molnar 		struct sched_param param;
68386470930SIngo Molnar 
684d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
68586470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
6866beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
6878d3eca20SDavid Ahern 			err = -1;
68845604710SNamhyung Kim 			goto out_child;
68986470930SIngo Molnar 		}
69086470930SIngo Molnar 	}
69186470930SIngo Molnar 
692774cb499SJiri Olsa 	/*
693774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
694774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
695774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
696774cb499SJiri Olsa 	 */
6976619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
6983e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
699764e16a3SDavid Ahern 
700856e9660SPeter Zijlstra 	/*
701856e9660SPeter Zijlstra 	 * Let the child rip
702856e9660SPeter Zijlstra 	 */
703e803cf97SNamhyung Kim 	if (forks) {
704e5bed564SNamhyung Kim 		union perf_event *event;
705e5bed564SNamhyung Kim 
706e5bed564SNamhyung Kim 		event = malloc(sizeof(event->comm) + machine->id_hdr_size);
707e5bed564SNamhyung Kim 		if (event == NULL) {
708e5bed564SNamhyung Kim 			err = -ENOMEM;
709e5bed564SNamhyung Kim 			goto out_child;
710e5bed564SNamhyung Kim 		}
711e5bed564SNamhyung Kim 
712e803cf97SNamhyung Kim 		/*
713e803cf97SNamhyung Kim 		 * Some H/W events are generated before COMM event
714e803cf97SNamhyung Kim 		 * which is emitted during exec(), so perf script
715e803cf97SNamhyung Kim 		 * cannot see a correct process name for those events.
716e803cf97SNamhyung Kim 		 * Synthesize COMM event to prevent it.
717e803cf97SNamhyung Kim 		 */
718e5bed564SNamhyung Kim 		perf_event__synthesize_comm(tool, event,
719e803cf97SNamhyung Kim 					    rec->evlist->workload.pid,
720e803cf97SNamhyung Kim 					    process_synthesized_event,
721e803cf97SNamhyung Kim 					    machine);
722e5bed564SNamhyung Kim 		free(event);
723e803cf97SNamhyung Kim 
7243e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
725e803cf97SNamhyung Kim 	}
726856e9660SPeter Zijlstra 
7276619a53eSAndi Kleen 	if (opts->initial_delay) {
7286619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
7296619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
7306619a53eSAndi Kleen 	}
7316619a53eSAndi Kleen 
7322dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 1;
733649c48a9SPeter Zijlstra 	for (;;) {
7349f065194SYang Shi 		unsigned long long hits = rec->samples;
73586470930SIngo Molnar 
7368c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
7372dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
7388d3eca20SDavid Ahern 			err = -1;
73945604710SNamhyung Kim 			goto out_child;
7408d3eca20SDavid Ahern 		}
74186470930SIngo Molnar 
7422dd6d8a1SAdrian Hunter 		if (auxtrace_record__snapshot_started) {
7432dd6d8a1SAdrian Hunter 			auxtrace_record__snapshot_started = 0;
7442dd6d8a1SAdrian Hunter 			if (!auxtrace_snapshot_err)
7452dd6d8a1SAdrian Hunter 				record__read_auxtrace_snapshot(rec);
7462dd6d8a1SAdrian Hunter 			if (auxtrace_snapshot_err) {
7472dd6d8a1SAdrian Hunter 				pr_err("AUX area tracing snapshot failed\n");
7482dd6d8a1SAdrian Hunter 				err = -1;
7492dd6d8a1SAdrian Hunter 				goto out_child;
7502dd6d8a1SAdrian Hunter 			}
7512dd6d8a1SAdrian Hunter 		}
7522dd6d8a1SAdrian Hunter 
753d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
7546dcf45efSArnaldo Carvalho de Melo 			if (done || draining)
755649c48a9SPeter Zijlstra 				break;
756f66a889dSArnaldo Carvalho de Melo 			err = perf_evlist__poll(rec->evlist, -1);
757a515114fSJiri Olsa 			/*
758a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
759a515114fSJiri Olsa 			 * number of returned events and interrupt error.
760a515114fSJiri Olsa 			 */
761a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
76245604710SNamhyung Kim 				err = 0;
7638b412664SPeter Zijlstra 			waking++;
7646dcf45efSArnaldo Carvalho de Melo 
7656dcf45efSArnaldo Carvalho de Melo 			if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
7666dcf45efSArnaldo Carvalho de Melo 				draining = true;
7678b412664SPeter Zijlstra 		}
7688b412664SPeter Zijlstra 
769774cb499SJiri Olsa 		/*
770774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
771774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
772774cb499SJiri Olsa 		 * disable events in this case.
773774cb499SJiri Olsa 		 */
774602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
7752dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
7763e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
7772711926aSJiri Olsa 			disabled = true;
7782711926aSJiri Olsa 		}
7798b412664SPeter Zijlstra 	}
7802dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
7818b412664SPeter Zijlstra 
782f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
78335550da3SMasami Hiramatsu 		char msg[STRERR_BUFSIZE];
784f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
785f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
786f33cbe72SArnaldo Carvalho de Melo 		err = -1;
78745604710SNamhyung Kim 		goto out_child;
788f33cbe72SArnaldo Carvalho de Melo 	}
789f33cbe72SArnaldo Carvalho de Melo 
790e3d59112SNamhyung Kim 	if (!quiet)
7918b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
79286470930SIngo Molnar 
79345604710SNamhyung Kim out_child:
79445604710SNamhyung Kim 	if (forks) {
79545604710SNamhyung Kim 		int exit_status;
79645604710SNamhyung Kim 
79745604710SNamhyung Kim 		if (!child_finished)
79845604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
79945604710SNamhyung Kim 
80045604710SNamhyung Kim 		wait(&exit_status);
80145604710SNamhyung Kim 
80245604710SNamhyung Kim 		if (err < 0)
80345604710SNamhyung Kim 			status = err;
80445604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
80545604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
80645604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
80745604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
80845604710SNamhyung Kim 	} else
80945604710SNamhyung Kim 		status = err;
81045604710SNamhyung Kim 
811e3d59112SNamhyung Kim 	/* this will be recalculated during process_buildids() */
812e3d59112SNamhyung Kim 	rec->samples = 0;
813e3d59112SNamhyung Kim 
814e1ab48baSWang Nan 	if (!err)
815e1ab48baSWang Nan 		record__finish_output(rec);
81639d17dacSArnaldo Carvalho de Melo 
817e3d59112SNamhyung Kim 	if (!err && !quiet) {
818e3d59112SNamhyung Kim 		char samples[128];
819e3d59112SNamhyung Kim 
820ef149c25SAdrian Hunter 		if (rec->samples && !rec->opts.full_auxtrace)
821e3d59112SNamhyung Kim 			scnprintf(samples, sizeof(samples),
822e3d59112SNamhyung Kim 				  " (%" PRIu64 " samples)", rec->samples);
823e3d59112SNamhyung Kim 		else
824e3d59112SNamhyung Kim 			samples[0] = '\0';
825e3d59112SNamhyung Kim 
826e3d59112SNamhyung Kim 		fprintf(stderr,	"[ perf record: Captured and wrote %.3f MB %s%s ]\n",
827e3d59112SNamhyung Kim 			perf_data_file__size(file) / 1024.0 / 1024.0,
828e3d59112SNamhyung Kim 			file->path, samples);
829e3d59112SNamhyung Kim 	}
830e3d59112SNamhyung Kim 
83139d17dacSArnaldo Carvalho de Melo out_delete_session:
83239d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
83345604710SNamhyung Kim 	return status;
83486470930SIngo Molnar }
83586470930SIngo Molnar 
83672a128aaSNamhyung Kim static void callchain_debug(void)
83709b0fd45SJiri Olsa {
838aad2b21cSKan Liang 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" };
839a601fdffSJiri Olsa 
84072a128aaSNamhyung Kim 	pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
84126d33022SJiri Olsa 
84272a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_DWARF)
84309b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
84472a128aaSNamhyung Kim 			 callchain_param.dump_size);
84509b0fd45SJiri Olsa }
84609b0fd45SJiri Olsa 
847c421e80bSKan Liang int record_parse_callchain_opt(const struct option *opt,
84809b0fd45SJiri Olsa 			       const char *arg,
84909b0fd45SJiri Olsa 			       int unset)
85009b0fd45SJiri Olsa {
85109b0fd45SJiri Olsa 	int ret;
852c421e80bSKan Liang 	struct record_opts *record = (struct record_opts *)opt->value;
85309b0fd45SJiri Olsa 
854c421e80bSKan Liang 	record->callgraph_set = true;
85572a128aaSNamhyung Kim 	callchain_param.enabled = !unset;
856eb853e80SJiri Olsa 
85709b0fd45SJiri Olsa 	/* --no-call-graph */
85809b0fd45SJiri Olsa 	if (unset) {
85972a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_NONE;
86009b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
86109b0fd45SJiri Olsa 		return 0;
86209b0fd45SJiri Olsa 	}
86309b0fd45SJiri Olsa 
864c3a6a8c4SKan Liang 	ret = parse_callchain_record_opt(arg, &callchain_param);
8655c0cf224SJiri Olsa 	if (!ret) {
8665c0cf224SJiri Olsa 		/* Enable data address sampling for DWARF unwind. */
8675c0cf224SJiri Olsa 		if (callchain_param.record_mode == CALLCHAIN_DWARF)
8685c0cf224SJiri Olsa 			record->sample_address = true;
86972a128aaSNamhyung Kim 		callchain_debug();
8705c0cf224SJiri Olsa 	}
87109b0fd45SJiri Olsa 
87226d33022SJiri Olsa 	return ret;
87326d33022SJiri Olsa }
87426d33022SJiri Olsa 
875c421e80bSKan Liang int record_callchain_opt(const struct option *opt,
87609b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
87709b0fd45SJiri Olsa 			 int unset __maybe_unused)
87809b0fd45SJiri Olsa {
879c421e80bSKan Liang 	struct record_opts *record = (struct record_opts *)opt->value;
880c421e80bSKan Liang 
881c421e80bSKan Liang 	record->callgraph_set = true;
88272a128aaSNamhyung Kim 	callchain_param.enabled = true;
88309b0fd45SJiri Olsa 
88472a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_NONE)
88572a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_FP;
886eb853e80SJiri Olsa 
88772a128aaSNamhyung Kim 	callchain_debug();
88809b0fd45SJiri Olsa 	return 0;
88909b0fd45SJiri Olsa }
89009b0fd45SJiri Olsa 
891eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
892eb853e80SJiri Olsa {
8937a29c087SNamhyung Kim 	struct record *rec = cb;
8947a29c087SNamhyung Kim 
8957a29c087SNamhyung Kim 	if (!strcmp(var, "record.build-id")) {
8967a29c087SNamhyung Kim 		if (!strcmp(value, "cache"))
8977a29c087SNamhyung Kim 			rec->no_buildid_cache = false;
8987a29c087SNamhyung Kim 		else if (!strcmp(value, "no-cache"))
8997a29c087SNamhyung Kim 			rec->no_buildid_cache = true;
9007a29c087SNamhyung Kim 		else if (!strcmp(value, "skip"))
9017a29c087SNamhyung Kim 			rec->no_buildid = true;
9027a29c087SNamhyung Kim 		else
9037a29c087SNamhyung Kim 			return -1;
9047a29c087SNamhyung Kim 		return 0;
9057a29c087SNamhyung Kim 	}
906eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
9075a2e5e85SNamhyung Kim 		var = "call-graph.record-mode"; /* fall-through */
908eb853e80SJiri Olsa 
909eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
910eb853e80SJiri Olsa }
911eb853e80SJiri Olsa 
912814c8c38SPeter Zijlstra struct clockid_map {
913814c8c38SPeter Zijlstra 	const char *name;
914814c8c38SPeter Zijlstra 	int clockid;
915814c8c38SPeter Zijlstra };
916814c8c38SPeter Zijlstra 
917814c8c38SPeter Zijlstra #define CLOCKID_MAP(n, c)	\
918814c8c38SPeter Zijlstra 	{ .name = n, .clockid = (c), }
919814c8c38SPeter Zijlstra 
920814c8c38SPeter Zijlstra #define CLOCKID_END	{ .name = NULL, }
921814c8c38SPeter Zijlstra 
922814c8c38SPeter Zijlstra 
923814c8c38SPeter Zijlstra /*
924814c8c38SPeter Zijlstra  * Add the missing ones, we need to build on many distros...
925814c8c38SPeter Zijlstra  */
926814c8c38SPeter Zijlstra #ifndef CLOCK_MONOTONIC_RAW
927814c8c38SPeter Zijlstra #define CLOCK_MONOTONIC_RAW 4
928814c8c38SPeter Zijlstra #endif
929814c8c38SPeter Zijlstra #ifndef CLOCK_BOOTTIME
930814c8c38SPeter Zijlstra #define CLOCK_BOOTTIME 7
931814c8c38SPeter Zijlstra #endif
932814c8c38SPeter Zijlstra #ifndef CLOCK_TAI
933814c8c38SPeter Zijlstra #define CLOCK_TAI 11
934814c8c38SPeter Zijlstra #endif
935814c8c38SPeter Zijlstra 
936814c8c38SPeter Zijlstra static const struct clockid_map clockids[] = {
937814c8c38SPeter Zijlstra 	/* available for all events, NMI safe */
938814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic", CLOCK_MONOTONIC),
939814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW),
940814c8c38SPeter Zijlstra 
941814c8c38SPeter Zijlstra 	/* available for some events */
942814c8c38SPeter Zijlstra 	CLOCKID_MAP("realtime", CLOCK_REALTIME),
943814c8c38SPeter Zijlstra 	CLOCKID_MAP("boottime", CLOCK_BOOTTIME),
944814c8c38SPeter Zijlstra 	CLOCKID_MAP("tai", CLOCK_TAI),
945814c8c38SPeter Zijlstra 
946814c8c38SPeter Zijlstra 	/* available for the lazy */
947814c8c38SPeter Zijlstra 	CLOCKID_MAP("mono", CLOCK_MONOTONIC),
948814c8c38SPeter Zijlstra 	CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW),
949814c8c38SPeter Zijlstra 	CLOCKID_MAP("real", CLOCK_REALTIME),
950814c8c38SPeter Zijlstra 	CLOCKID_MAP("boot", CLOCK_BOOTTIME),
951814c8c38SPeter Zijlstra 
952814c8c38SPeter Zijlstra 	CLOCKID_END,
953814c8c38SPeter Zijlstra };
954814c8c38SPeter Zijlstra 
955814c8c38SPeter Zijlstra static int parse_clockid(const struct option *opt, const char *str, int unset)
956814c8c38SPeter Zijlstra {
957814c8c38SPeter Zijlstra 	struct record_opts *opts = (struct record_opts *)opt->value;
958814c8c38SPeter Zijlstra 	const struct clockid_map *cm;
959814c8c38SPeter Zijlstra 	const char *ostr = str;
960814c8c38SPeter Zijlstra 
961814c8c38SPeter Zijlstra 	if (unset) {
962814c8c38SPeter Zijlstra 		opts->use_clockid = 0;
963814c8c38SPeter Zijlstra 		return 0;
964814c8c38SPeter Zijlstra 	}
965814c8c38SPeter Zijlstra 
966814c8c38SPeter Zijlstra 	/* no arg passed */
967814c8c38SPeter Zijlstra 	if (!str)
968814c8c38SPeter Zijlstra 		return 0;
969814c8c38SPeter Zijlstra 
970814c8c38SPeter Zijlstra 	/* no setting it twice */
971814c8c38SPeter Zijlstra 	if (opts->use_clockid)
972814c8c38SPeter Zijlstra 		return -1;
973814c8c38SPeter Zijlstra 
974814c8c38SPeter Zijlstra 	opts->use_clockid = true;
975814c8c38SPeter Zijlstra 
976814c8c38SPeter Zijlstra 	/* if its a number, we're done */
977814c8c38SPeter Zijlstra 	if (sscanf(str, "%d", &opts->clockid) == 1)
978814c8c38SPeter Zijlstra 		return 0;
979814c8c38SPeter Zijlstra 
980814c8c38SPeter Zijlstra 	/* allow a "CLOCK_" prefix to the name */
981814c8c38SPeter Zijlstra 	if (!strncasecmp(str, "CLOCK_", 6))
982814c8c38SPeter Zijlstra 		str += 6;
983814c8c38SPeter Zijlstra 
984814c8c38SPeter Zijlstra 	for (cm = clockids; cm->name; cm++) {
985814c8c38SPeter Zijlstra 		if (!strcasecmp(str, cm->name)) {
986814c8c38SPeter Zijlstra 			opts->clockid = cm->clockid;
987814c8c38SPeter Zijlstra 			return 0;
988814c8c38SPeter Zijlstra 		}
989814c8c38SPeter Zijlstra 	}
990814c8c38SPeter Zijlstra 
991814c8c38SPeter Zijlstra 	opts->use_clockid = false;
992814c8c38SPeter Zijlstra 	ui__warning("unknown clockid %s, check man page\n", ostr);
993814c8c38SPeter Zijlstra 	return -1;
994814c8c38SPeter Zijlstra }
995814c8c38SPeter Zijlstra 
996e9db1310SAdrian Hunter static int record__parse_mmap_pages(const struct option *opt,
997e9db1310SAdrian Hunter 				    const char *str,
998e9db1310SAdrian Hunter 				    int unset __maybe_unused)
999e9db1310SAdrian Hunter {
1000e9db1310SAdrian Hunter 	struct record_opts *opts = opt->value;
1001e9db1310SAdrian Hunter 	char *s, *p;
1002e9db1310SAdrian Hunter 	unsigned int mmap_pages;
1003e9db1310SAdrian Hunter 	int ret;
1004e9db1310SAdrian Hunter 
1005e9db1310SAdrian Hunter 	if (!str)
1006e9db1310SAdrian Hunter 		return -EINVAL;
1007e9db1310SAdrian Hunter 
1008e9db1310SAdrian Hunter 	s = strdup(str);
1009e9db1310SAdrian Hunter 	if (!s)
1010e9db1310SAdrian Hunter 		return -ENOMEM;
1011e9db1310SAdrian Hunter 
1012e9db1310SAdrian Hunter 	p = strchr(s, ',');
1013e9db1310SAdrian Hunter 	if (p)
1014e9db1310SAdrian Hunter 		*p = '\0';
1015e9db1310SAdrian Hunter 
1016e9db1310SAdrian Hunter 	if (*s) {
1017e9db1310SAdrian Hunter 		ret = __perf_evlist__parse_mmap_pages(&mmap_pages, s);
1018e9db1310SAdrian Hunter 		if (ret)
1019e9db1310SAdrian Hunter 			goto out_free;
1020e9db1310SAdrian Hunter 		opts->mmap_pages = mmap_pages;
1021e9db1310SAdrian Hunter 	}
1022e9db1310SAdrian Hunter 
1023e9db1310SAdrian Hunter 	if (!p) {
1024e9db1310SAdrian Hunter 		ret = 0;
1025e9db1310SAdrian Hunter 		goto out_free;
1026e9db1310SAdrian Hunter 	}
1027e9db1310SAdrian Hunter 
1028e9db1310SAdrian Hunter 	ret = __perf_evlist__parse_mmap_pages(&mmap_pages, p + 1);
1029e9db1310SAdrian Hunter 	if (ret)
1030e9db1310SAdrian Hunter 		goto out_free;
1031e9db1310SAdrian Hunter 
1032e9db1310SAdrian Hunter 	opts->auxtrace_mmap_pages = mmap_pages;
1033e9db1310SAdrian Hunter 
1034e9db1310SAdrian Hunter out_free:
1035e9db1310SAdrian Hunter 	free(s);
1036e9db1310SAdrian Hunter 	return ret;
1037e9db1310SAdrian Hunter }
1038e9db1310SAdrian Hunter 
1039e5b2c207SNamhyung Kim static const char * const __record_usage[] = {
104086470930SIngo Molnar 	"perf record [<options>] [<command>]",
104186470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
104286470930SIngo Molnar 	NULL
104386470930SIngo Molnar };
1044e5b2c207SNamhyung Kim const char * const *record_usage = __record_usage;
104586470930SIngo Molnar 
1046d20deb64SArnaldo Carvalho de Melo /*
10478c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
10488c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
1049d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
1050d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
1051d20deb64SArnaldo Carvalho de Melo  *
1052d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
1053d20deb64SArnaldo Carvalho de Melo  *
1054d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
1055d20deb64SArnaldo Carvalho de Melo  */
10568c6f45a7SArnaldo Carvalho de Melo static struct record record = {
1057d20deb64SArnaldo Carvalho de Melo 	.opts = {
10588affc2b8SAndi Kleen 		.sample_time	     = true,
1059d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
1060d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
1061d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
1062447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
1063d1cb9fceSNamhyung Kim 		.target		     = {
1064d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
10653aa5939dSAdrian Hunter 			.default_per_cpu = true,
1066d1cb9fceSNamhyung Kim 		},
10679d9cad76SKan Liang 		.proc_map_timeout     = 500,
1068d20deb64SArnaldo Carvalho de Melo 	},
1069e3d59112SNamhyung Kim 	.tool = {
1070e3d59112SNamhyung Kim 		.sample		= process_sample_event,
1071e3d59112SNamhyung Kim 		.fork		= perf_event__process_fork,
1072cca8482cSAdrian Hunter 		.exit		= perf_event__process_exit,
1073e3d59112SNamhyung Kim 		.comm		= perf_event__process_comm,
1074e3d59112SNamhyung Kim 		.mmap		= perf_event__process_mmap,
1075e3d59112SNamhyung Kim 		.mmap2		= perf_event__process_mmap2,
1076cca8482cSAdrian Hunter 		.ordered_events	= true,
1077e3d59112SNamhyung Kim 	},
1078d20deb64SArnaldo Carvalho de Melo };
10797865e817SFrederic Weisbecker 
108076a26549SNamhyung Kim const char record_callchain_help[] = CALLCHAIN_RECORD_HELP
108176a26549SNamhyung Kim 	"\n\t\t\t\tDefault: fp";
108261eaa3beSArnaldo Carvalho de Melo 
1083d20deb64SArnaldo Carvalho de Melo /*
1084d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
1085d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
1086b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
1087d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
1088d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
1089d20deb64SArnaldo Carvalho de Melo  */
1090e5b2c207SNamhyung Kim struct option __record_options[] = {
1091d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
109286470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
1093f120f9d5SJiri Olsa 		     parse_events_option),
1094d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
1095c171b552SLi Zefan 		     "event filter", parse_filter),
10964ba1faa1SWang Nan 	OPT_CALLBACK_NOOPT(0, "exclude-perf", &record.evlist,
10974ba1faa1SWang Nan 			   NULL, "don't record events from perf itself",
10984ba1faa1SWang Nan 			   exclude_perf),
1099bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
1100d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
1101bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
1102d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
1103d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
110486470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
1105509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
1106acac03faSKirill Smelkov 		    "collect data without buffering"),
1107d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
1108daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
1109bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
111086470930SIngo Molnar 			    "system-wide collection from all CPUs"),
1111bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
1112c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
1113d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
1114f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
111586470930SIngo Molnar 		    "output file name"),
111669e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
111769e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
11182e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
1119d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
1120e9db1310SAdrian Hunter 	OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]",
1121e9db1310SAdrian Hunter 		     "number of mmap data pages and AUX area tracing mmap pages",
1122e9db1310SAdrian Hunter 		     record__parse_mmap_pages),
1123d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
112443bece79SLin Ming 		    "put the counters into a counter group"),
112509b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
112609b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
112709b0fd45SJiri Olsa 			   &record_callchain_opt),
112809b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
112976a26549SNamhyung Kim 		     "record_mode[,record_size]", record_callchain_help,
113009b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
1131c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
11323da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
1133b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
1134d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
1135649c48a9SPeter Zijlstra 		    "per thread counts"),
113656100321SPeter Zijlstra 	OPT_BOOLEAN('d', "data", &record.opts.sample_address, "Record the sample addresses"),
11373abebc55SAdrian Hunter 	OPT_BOOLEAN_SET('T', "timestamp", &record.opts.sample_time,
11383abebc55SAdrian Hunter 			&record.opts.sample_time_set,
11393abebc55SAdrian Hunter 			"Record the sample timestamps"),
114056100321SPeter Zijlstra 	OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"),
1141d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
1142649c48a9SPeter Zijlstra 		    "don't sample"),
1143d2db9a98SWang Nan 	OPT_BOOLEAN_SET('N', "no-buildid-cache", &record.no_buildid_cache,
1144d2db9a98SWang Nan 			&record.no_buildid_cache_set,
1145a1ac1d3cSStephane Eranian 			"do not update the buildid cache"),
1146d2db9a98SWang Nan 	OPT_BOOLEAN_SET('B', "no-buildid", &record.no_buildid,
1147d2db9a98SWang Nan 			&record.no_buildid_set,
1148baa2f6ceSArnaldo Carvalho de Melo 			"do not collect buildids in perf.data"),
1149d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
1150023695d9SStephane Eranian 		     "monitor event in cgroup name only",
1151023695d9SStephane Eranian 		     parse_cgroups),
1152a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
11536619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
1154bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
1155bea03405SNamhyung Kim 		   "user to profile"),
1156a5aabdacSStephane Eranian 
1157a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
1158a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
1159a5aabdacSStephane Eranian 		     parse_branch_stack),
1160a5aabdacSStephane Eranian 
1161a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
1162a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
1163bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
116405484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
116505484298SAndi Kleen 		    "sample by weight (on special events only)"),
1166475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
1167475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
11683aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
11693aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
1170bcc84ec6SStephane Eranian 	OPT_CALLBACK_OPTARG('I', "intr-regs", &record.opts.sample_intr_regs, NULL, "any register",
1171bcc84ec6SStephane Eranian 		    "sample selected machine registers on interrupt,"
1172bcc84ec6SStephane Eranian 		    " use -I ? to list register names", parse_regs),
117385c273d2SAndi Kleen 	OPT_BOOLEAN(0, "running-time", &record.opts.running_time,
117485c273d2SAndi Kleen 		    "Record running/enabled time of read (:S) events"),
1175814c8c38SPeter Zijlstra 	OPT_CALLBACK('k', "clockid", &record.opts,
1176814c8c38SPeter Zijlstra 	"clockid", "clockid to use for events, see clock_gettime()",
1177814c8c38SPeter Zijlstra 	parse_clockid),
11782dd6d8a1SAdrian Hunter 	OPT_STRING_OPTARG('S', "snapshot", &record.opts.auxtrace_snapshot_opts,
11792dd6d8a1SAdrian Hunter 			  "opts", "AUX area tracing Snapshot Mode", ""),
11809d9cad76SKan Liang 	OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout,
11819d9cad76SKan Liang 			"per thread proc mmap processing timeout in ms"),
1182b757bb09SAdrian Hunter 	OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
1183b757bb09SAdrian Hunter 		    "Record context switch events"),
118485723885SJiri Olsa 	OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel,
118585723885SJiri Olsa 			 "Configure all used events to run in kernel space.",
118685723885SJiri Olsa 			 PARSE_OPT_EXCLUSIVE),
118785723885SJiri Olsa 	OPT_BOOLEAN_FLAG(0, "all-user", &record.opts.all_user,
118885723885SJiri Olsa 			 "Configure all used events to run in user space.",
118985723885SJiri Olsa 			 PARSE_OPT_EXCLUSIVE),
119071dc2326SWang Nan 	OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
119171dc2326SWang Nan 		   "clang binary to use for compiling BPF scriptlets"),
119271dc2326SWang Nan 	OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
119371dc2326SWang Nan 		   "options passed to clang when compiling BPF scriptlets"),
11947efe0e03SHe Kuang 	OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
11957efe0e03SHe Kuang 		   "file", "vmlinux pathname"),
11966156681bSNamhyung Kim 	OPT_BOOLEAN(0, "buildid-all", &record.buildid_all,
11976156681bSNamhyung Kim 		    "Record build-id of all DSOs regardless of hits"),
119886470930SIngo Molnar 	OPT_END()
119986470930SIngo Molnar };
120086470930SIngo Molnar 
1201e5b2c207SNamhyung Kim struct option *record_options = __record_options;
1202e5b2c207SNamhyung Kim 
12031d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
120486470930SIngo Molnar {
1205ef149c25SAdrian Hunter 	int err;
12068c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
120716ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
120886470930SIngo Molnar 
120948e1cab1SWang Nan #ifndef HAVE_LIBBPF_SUPPORT
121048e1cab1SWang Nan # define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c)
121148e1cab1SWang Nan 	set_nobuild('\0', "clang-path", true);
121248e1cab1SWang Nan 	set_nobuild('\0', "clang-opt", true);
121348e1cab1SWang Nan # undef set_nobuild
121448e1cab1SWang Nan #endif
121548e1cab1SWang Nan 
12167efe0e03SHe Kuang #ifndef HAVE_BPF_PROLOGUE
12177efe0e03SHe Kuang # if !defined (HAVE_DWARF_SUPPORT)
12187efe0e03SHe Kuang #  define REASON  "NO_DWARF=1"
12197efe0e03SHe Kuang # elif !defined (HAVE_LIBBPF_SUPPORT)
12207efe0e03SHe Kuang #  define REASON  "NO_LIBBPF=1"
12217efe0e03SHe Kuang # else
12227efe0e03SHe Kuang #  define REASON  "this architecture doesn't support BPF prologue"
12237efe0e03SHe Kuang # endif
12247efe0e03SHe Kuang # define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, REASON, c)
12257efe0e03SHe Kuang 	set_nobuild('\0', "vmlinux", true);
12267efe0e03SHe Kuang # undef set_nobuild
12277efe0e03SHe Kuang # undef REASON
12287efe0e03SHe Kuang #endif
12297efe0e03SHe Kuang 
12303e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
12313e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
1232361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
1233361c99a6SArnaldo Carvalho de Melo 
1234eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
1235eb853e80SJiri Olsa 
1236bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
1237a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
1238602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
1239bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
124086470930SIngo Molnar 
1241bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
1242c7118369SNamhyung Kim 		usage_with_options_msg(record_usage, record_options,
1243c7118369SNamhyung Kim 			"cgroup monitoring only available in system-wide mode");
1244c7118369SNamhyung Kim 
1245023695d9SStephane Eranian 	}
1246b757bb09SAdrian Hunter 	if (rec->opts.record_switch_events &&
1247b757bb09SAdrian Hunter 	    !perf_can_record_switch_events()) {
1248c7118369SNamhyung Kim 		ui__error("kernel does not support recording context switch events\n");
1249c7118369SNamhyung Kim 		parse_options_usage(record_usage, record_options, "switch-events", 0);
1250c7118369SNamhyung Kim 		return -EINVAL;
1251b757bb09SAdrian Hunter 	}
1252023695d9SStephane Eranian 
1253ef149c25SAdrian Hunter 	if (!rec->itr) {
1254ef149c25SAdrian Hunter 		rec->itr = auxtrace_record__init(rec->evlist, &err);
1255ef149c25SAdrian Hunter 		if (err)
1256ef149c25SAdrian Hunter 			return err;
1257ef149c25SAdrian Hunter 	}
1258ef149c25SAdrian Hunter 
12592dd6d8a1SAdrian Hunter 	err = auxtrace_parse_snapshot_options(rec->itr, &rec->opts,
12602dd6d8a1SAdrian Hunter 					      rec->opts.auxtrace_snapshot_opts);
12612dd6d8a1SAdrian Hunter 	if (err)
12622dd6d8a1SAdrian Hunter 		return err;
12632dd6d8a1SAdrian Hunter 
1264ef149c25SAdrian Hunter 	err = -ENOMEM;
1265ef149c25SAdrian Hunter 
12660a7e6d1bSNamhyung Kim 	symbol__init(NULL);
1267baa2f6ceSArnaldo Carvalho de Melo 
1268ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
1269646aaea6SArnaldo Carvalho de Melo 		pr_warning(
1270646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
1271ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
1272646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
1273646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
1274646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
1275646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
1276646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
1277ec80fde7SArnaldo Carvalho de Melo 
1278d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
1279a1ac1d3cSStephane Eranian 		disable_buildid_cache();
1280655000e7SArnaldo Carvalho de Melo 
12813e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
12823e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
128369aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
128469aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
1285bbd36e5eSPeter Zijlstra 	}
128686470930SIngo Molnar 
128769e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
128869e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
128969e7e5b0SAdrian Hunter 
1290602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
129116ad2ffbSNamhyung Kim 	if (err) {
1292602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
129316ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
129416ad2ffbSNamhyung Kim 	}
12954bd0f2d2SNamhyung Kim 
1296602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
129716ad2ffbSNamhyung Kim 	if (err) {
129816ad2ffbSNamhyung Kim 		int saved_errno = errno;
129916ad2ffbSNamhyung Kim 
1300602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
13013780f488SNamhyung Kim 		ui__error("%s", errbuf);
130216ad2ffbSNamhyung Kim 
130316ad2ffbSNamhyung Kim 		err = -saved_errno;
13048fa60e1fSNamhyung Kim 		goto out_symbol_exit;
130516ad2ffbSNamhyung Kim 	}
13060d37aa34SArnaldo Carvalho de Melo 
130716ad2ffbSNamhyung Kim 	err = -ENOMEM;
13083e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
1309dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
131069aad6f1SArnaldo Carvalho de Melo 
1311ef149c25SAdrian Hunter 	err = auxtrace_record__options(rec->itr, rec->evlist, &rec->opts);
1312ef149c25SAdrian Hunter 	if (err)
1313ef149c25SAdrian Hunter 		goto out_symbol_exit;
1314ef149c25SAdrian Hunter 
13156156681bSNamhyung Kim 	/*
13166156681bSNamhyung Kim 	 * We take all buildids when the file contains
13176156681bSNamhyung Kim 	 * AUX area tracing data because we do not decode the
13186156681bSNamhyung Kim 	 * trace because it would take too long.
13196156681bSNamhyung Kim 	 */
13206156681bSNamhyung Kim 	if (rec->opts.full_auxtrace)
13216156681bSNamhyung Kim 		rec->buildid_all = true;
13226156681bSNamhyung Kim 
1323b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
132439d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
132503ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
13267e4ff9e3SMike Galbraith 	}
13277e4ff9e3SMike Galbraith 
1328d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
1329d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
133045604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
1331d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
1332ef149c25SAdrian Hunter 	auxtrace_record__free(rec->itr);
133339d17dacSArnaldo Carvalho de Melo 	return err;
133486470930SIngo Molnar }
13352dd6d8a1SAdrian Hunter 
13362dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig __maybe_unused)
13372dd6d8a1SAdrian Hunter {
13382dd6d8a1SAdrian Hunter 	if (!auxtrace_snapshot_enabled)
13392dd6d8a1SAdrian Hunter 		return;
13402dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
13412dd6d8a1SAdrian Hunter 	auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
13422dd6d8a1SAdrian Hunter 	auxtrace_record__snapshot_started = 1;
13432dd6d8a1SAdrian Hunter }
1344