xref: /openbmc/linux/tools/perf/builtin-record.c (revision e803cf97a4f90d31bcc2c9a1ea20fe9cdc12b2f9)
186470930SIngo Molnar /*
286470930SIngo Molnar  * builtin-record.c
386470930SIngo Molnar  *
486470930SIngo Molnar  * Builtin record command: Record the profile of a workload
586470930SIngo Molnar  * (or a CPU, or a PID) into the perf.data output file - for
686470930SIngo Molnar  * later analysis via perf report.
786470930SIngo Molnar  */
886470930SIngo Molnar #include "builtin.h"
986470930SIngo Molnar 
1086470930SIngo Molnar #include "perf.h"
1186470930SIngo Molnar 
126122e4e4SArnaldo Carvalho de Melo #include "util/build-id.h"
1386470930SIngo Molnar #include "util/util.h"
1486470930SIngo Molnar #include "util/parse-options.h"
1586470930SIngo Molnar #include "util/parse-events.h"
1686470930SIngo Molnar 
178f651eaeSArnaldo Carvalho de Melo #include "util/callchain.h"
18f14d5707SArnaldo Carvalho de Melo #include "util/cgroup.h"
197c6a1c65SPeter Zijlstra #include "util/header.h"
2066e274f3SFrederic Weisbecker #include "util/event.h"
21361c99a6SArnaldo Carvalho de Melo #include "util/evlist.h"
2269aad6f1SArnaldo Carvalho de Melo #include "util/evsel.h"
238f28827aSFrederic Weisbecker #include "util/debug.h"
2494c744b6SArnaldo Carvalho de Melo #include "util/session.h"
2545694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
268d06367fSArnaldo Carvalho de Melo #include "util/symbol.h"
27a12b51c4SPaul Mackerras #include "util/cpumap.h"
28fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h"
29f5fc1412SJiri Olsa #include "util/data.h"
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"
347c6a1c65SPeter Zijlstra 
3586470930SIngo Molnar #include <unistd.h>
3686470930SIngo Molnar #include <sched.h>
37a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3886470930SIngo Molnar 
3978da39faSBernhard Rosenkraenzer 
408c6f45a7SArnaldo Carvalho de Melo struct record {
4145694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
42b4006796SArnaldo Carvalho de Melo 	struct record_opts	opts;
43d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
44f5fc1412SJiri Olsa 	struct perf_data_file	file;
45ef149c25SAdrian Hunter 	struct auxtrace_record	*itr;
46d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
47d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
48d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
49d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
50d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
51d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
52d20deb64SArnaldo Carvalho de Melo 	long			samples;
530f82ebc4SArnaldo Carvalho de Melo };
5486470930SIngo Molnar 
558c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
56f5970550SPeter Zijlstra {
57cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
584f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
598d3eca20SDavid Ahern 		return -1;
608d3eca20SDavid Ahern 	}
61f5970550SPeter Zijlstra 
62cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
638d3eca20SDavid Ahern 	return 0;
64f5970550SPeter Zijlstra }
65f5970550SPeter Zijlstra 
6645694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
67d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
681d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
691d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
70234fbbf5SArnaldo Carvalho de Melo {
718c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
728c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
73234fbbf5SArnaldo Carvalho de Melo }
74234fbbf5SArnaldo Carvalho de Melo 
75e5685730SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, int idx)
7686470930SIngo Molnar {
77e5685730SArnaldo Carvalho de Melo 	struct perf_mmap *md = &rec->evlist->mmap[idx];
787b8283b5SDavid Ahern 	u64 head = perf_mmap__read_head(md);
797b8283b5SDavid Ahern 	u64 old = md->prev;
80918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
8186470930SIngo Molnar 	unsigned long size;
8286470930SIngo Molnar 	void *buf;
838d3eca20SDavid Ahern 	int rc = 0;
8486470930SIngo Molnar 
85dc82009aSArnaldo Carvalho de Melo 	if (old == head)
868d3eca20SDavid Ahern 		return 0;
8786470930SIngo Molnar 
88d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
8986470930SIngo Molnar 
9086470930SIngo Molnar 	size = head - old;
9186470930SIngo Molnar 
9286470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
9386470930SIngo Molnar 		buf = &data[old & md->mask];
9486470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
9586470930SIngo Molnar 		old += size;
9686470930SIngo Molnar 
978c6f45a7SArnaldo Carvalho de Melo 		if (record__write(rec, buf, size) < 0) {
988d3eca20SDavid Ahern 			rc = -1;
998d3eca20SDavid Ahern 			goto out;
1008d3eca20SDavid Ahern 		}
10186470930SIngo Molnar 	}
10286470930SIngo Molnar 
10386470930SIngo Molnar 	buf = &data[old & md->mask];
10486470930SIngo Molnar 	size = head - old;
10586470930SIngo Molnar 	old += size;
10686470930SIngo Molnar 
1078c6f45a7SArnaldo Carvalho de Melo 	if (record__write(rec, buf, size) < 0) {
1088d3eca20SDavid Ahern 		rc = -1;
1098d3eca20SDavid Ahern 		goto out;
1108d3eca20SDavid Ahern 	}
11186470930SIngo Molnar 
11286470930SIngo Molnar 	md->prev = old;
113e5685730SArnaldo Carvalho de Melo 	perf_evlist__mmap_consume(rec->evlist, idx);
1148d3eca20SDavid Ahern out:
1158d3eca20SDavid Ahern 	return rc;
11686470930SIngo Molnar }
11786470930SIngo Molnar 
1182dd6d8a1SAdrian Hunter static volatile int done;
1192dd6d8a1SAdrian Hunter static volatile int signr = -1;
1202dd6d8a1SAdrian Hunter static volatile int child_finished;
1212dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_enabled;
1222dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_err;
1232dd6d8a1SAdrian Hunter static volatile int auxtrace_record__snapshot_started;
1242dd6d8a1SAdrian Hunter 
1252dd6d8a1SAdrian Hunter static void sig_handler(int sig)
1262dd6d8a1SAdrian Hunter {
1272dd6d8a1SAdrian Hunter 	if (sig == SIGCHLD)
1282dd6d8a1SAdrian Hunter 		child_finished = 1;
1292dd6d8a1SAdrian Hunter 	else
1302dd6d8a1SAdrian Hunter 		signr = sig;
1312dd6d8a1SAdrian Hunter 
1322dd6d8a1SAdrian Hunter 	done = 1;
1332dd6d8a1SAdrian Hunter }
1342dd6d8a1SAdrian Hunter 
1352dd6d8a1SAdrian Hunter static void record__sig_exit(void)
1362dd6d8a1SAdrian Hunter {
1372dd6d8a1SAdrian Hunter 	if (signr == -1)
1382dd6d8a1SAdrian Hunter 		return;
1392dd6d8a1SAdrian Hunter 
1402dd6d8a1SAdrian Hunter 	signal(signr, SIG_DFL);
1412dd6d8a1SAdrian Hunter 	raise(signr);
1422dd6d8a1SAdrian Hunter }
1432dd6d8a1SAdrian Hunter 
144e31f0d01SAdrian Hunter #ifdef HAVE_AUXTRACE_SUPPORT
145e31f0d01SAdrian Hunter 
146ef149c25SAdrian Hunter static int record__process_auxtrace(struct perf_tool *tool,
147ef149c25SAdrian Hunter 				    union perf_event *event, void *data1,
148ef149c25SAdrian Hunter 				    size_t len1, void *data2, size_t len2)
149ef149c25SAdrian Hunter {
150ef149c25SAdrian Hunter 	struct record *rec = container_of(tool, struct record, tool);
15199fa2984SAdrian Hunter 	struct perf_data_file *file = &rec->file;
152ef149c25SAdrian Hunter 	size_t padding;
153ef149c25SAdrian Hunter 	u8 pad[8] = {0};
154ef149c25SAdrian Hunter 
15599fa2984SAdrian Hunter 	if (!perf_data_file__is_pipe(file)) {
15699fa2984SAdrian Hunter 		off_t file_offset;
15799fa2984SAdrian Hunter 		int fd = perf_data_file__fd(file);
15899fa2984SAdrian Hunter 		int err;
15999fa2984SAdrian Hunter 
16099fa2984SAdrian Hunter 		file_offset = lseek(fd, 0, SEEK_CUR);
16199fa2984SAdrian Hunter 		if (file_offset == -1)
16299fa2984SAdrian Hunter 			return -1;
16399fa2984SAdrian Hunter 		err = auxtrace_index__auxtrace_event(&rec->session->auxtrace_index,
16499fa2984SAdrian Hunter 						     event, file_offset);
16599fa2984SAdrian Hunter 		if (err)
16699fa2984SAdrian Hunter 			return err;
16799fa2984SAdrian Hunter 	}
16899fa2984SAdrian Hunter 
169ef149c25SAdrian Hunter 	/* event.auxtrace.size includes padding, see __auxtrace_mmap__read() */
170ef149c25SAdrian Hunter 	padding = (len1 + len2) & 7;
171ef149c25SAdrian Hunter 	if (padding)
172ef149c25SAdrian Hunter 		padding = 8 - padding;
173ef149c25SAdrian Hunter 
174ef149c25SAdrian Hunter 	record__write(rec, event, event->header.size);
175ef149c25SAdrian Hunter 	record__write(rec, data1, len1);
176ef149c25SAdrian Hunter 	if (len2)
177ef149c25SAdrian Hunter 		record__write(rec, data2, len2);
178ef149c25SAdrian Hunter 	record__write(rec, &pad, padding);
179ef149c25SAdrian Hunter 
180ef149c25SAdrian Hunter 	return 0;
181ef149c25SAdrian Hunter }
182ef149c25SAdrian Hunter 
183ef149c25SAdrian Hunter static int record__auxtrace_mmap_read(struct record *rec,
184ef149c25SAdrian Hunter 				      struct auxtrace_mmap *mm)
185ef149c25SAdrian Hunter {
186ef149c25SAdrian Hunter 	int ret;
187ef149c25SAdrian Hunter 
188ef149c25SAdrian Hunter 	ret = auxtrace_mmap__read(mm, rec->itr, &rec->tool,
189ef149c25SAdrian Hunter 				  record__process_auxtrace);
190ef149c25SAdrian Hunter 	if (ret < 0)
191ef149c25SAdrian Hunter 		return ret;
192ef149c25SAdrian Hunter 
193ef149c25SAdrian Hunter 	if (ret)
194ef149c25SAdrian Hunter 		rec->samples++;
195ef149c25SAdrian Hunter 
196ef149c25SAdrian Hunter 	return 0;
197ef149c25SAdrian Hunter }
198ef149c25SAdrian Hunter 
1992dd6d8a1SAdrian Hunter static int record__auxtrace_mmap_read_snapshot(struct record *rec,
2002dd6d8a1SAdrian Hunter 					       struct auxtrace_mmap *mm)
2012dd6d8a1SAdrian Hunter {
2022dd6d8a1SAdrian Hunter 	int ret;
2032dd6d8a1SAdrian Hunter 
2042dd6d8a1SAdrian Hunter 	ret = auxtrace_mmap__read_snapshot(mm, rec->itr, &rec->tool,
2052dd6d8a1SAdrian Hunter 					   record__process_auxtrace,
2062dd6d8a1SAdrian Hunter 					   rec->opts.auxtrace_snapshot_size);
2072dd6d8a1SAdrian Hunter 	if (ret < 0)
2082dd6d8a1SAdrian Hunter 		return ret;
2092dd6d8a1SAdrian Hunter 
2102dd6d8a1SAdrian Hunter 	if (ret)
2112dd6d8a1SAdrian Hunter 		rec->samples++;
2122dd6d8a1SAdrian Hunter 
2132dd6d8a1SAdrian Hunter 	return 0;
2142dd6d8a1SAdrian Hunter }
2152dd6d8a1SAdrian Hunter 
2162dd6d8a1SAdrian Hunter static int record__auxtrace_read_snapshot_all(struct record *rec)
2172dd6d8a1SAdrian Hunter {
2182dd6d8a1SAdrian Hunter 	int i;
2192dd6d8a1SAdrian Hunter 	int rc = 0;
2202dd6d8a1SAdrian Hunter 
2212dd6d8a1SAdrian Hunter 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
2222dd6d8a1SAdrian Hunter 		struct auxtrace_mmap *mm =
2232dd6d8a1SAdrian Hunter 				&rec->evlist->mmap[i].auxtrace_mmap;
2242dd6d8a1SAdrian Hunter 
2252dd6d8a1SAdrian Hunter 		if (!mm->base)
2262dd6d8a1SAdrian Hunter 			continue;
2272dd6d8a1SAdrian Hunter 
2282dd6d8a1SAdrian Hunter 		if (record__auxtrace_mmap_read_snapshot(rec, mm) != 0) {
2292dd6d8a1SAdrian Hunter 			rc = -1;
2302dd6d8a1SAdrian Hunter 			goto out;
2312dd6d8a1SAdrian Hunter 		}
2322dd6d8a1SAdrian Hunter 	}
2332dd6d8a1SAdrian Hunter out:
2342dd6d8a1SAdrian Hunter 	return rc;
2352dd6d8a1SAdrian Hunter }
2362dd6d8a1SAdrian Hunter 
2372dd6d8a1SAdrian Hunter static void record__read_auxtrace_snapshot(struct record *rec)
2382dd6d8a1SAdrian Hunter {
2392dd6d8a1SAdrian Hunter 	pr_debug("Recording AUX area tracing snapshot\n");
2402dd6d8a1SAdrian Hunter 	if (record__auxtrace_read_snapshot_all(rec) < 0) {
2412dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = -1;
2422dd6d8a1SAdrian Hunter 	} else {
2432dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr);
2442dd6d8a1SAdrian Hunter 		if (!auxtrace_snapshot_err)
2452dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 1;
2462dd6d8a1SAdrian Hunter 	}
2472dd6d8a1SAdrian Hunter }
2482dd6d8a1SAdrian Hunter 
249e31f0d01SAdrian Hunter #else
250e31f0d01SAdrian Hunter 
251e31f0d01SAdrian Hunter static inline
252e31f0d01SAdrian Hunter int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
253e31f0d01SAdrian Hunter 			       struct auxtrace_mmap *mm __maybe_unused)
254e31f0d01SAdrian Hunter {
255e31f0d01SAdrian Hunter 	return 0;
256e31f0d01SAdrian Hunter }
257e31f0d01SAdrian Hunter 
2582dd6d8a1SAdrian Hunter static inline
2592dd6d8a1SAdrian Hunter void record__read_auxtrace_snapshot(struct record *rec __maybe_unused)
2602dd6d8a1SAdrian Hunter {
2612dd6d8a1SAdrian Hunter }
2622dd6d8a1SAdrian Hunter 
2632dd6d8a1SAdrian Hunter static inline
2642dd6d8a1SAdrian Hunter int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused)
2652dd6d8a1SAdrian Hunter {
2662dd6d8a1SAdrian Hunter 	return 0;
2672dd6d8a1SAdrian Hunter }
2682dd6d8a1SAdrian Hunter 
269e31f0d01SAdrian Hunter #endif
270e31f0d01SAdrian Hunter 
2718c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
272dd7927f4SArnaldo Carvalho de Melo {
27356e52e85SArnaldo Carvalho de Melo 	char msg[512];
2746a4bb04cSJiri Olsa 	struct perf_evsel *pos;
275d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
276d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
277b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
2788d3eca20SDavid Ahern 	int rc = 0;
279dd7927f4SArnaldo Carvalho de Melo 
280f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
281cac21425SJiri Olsa 
2820050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
2833da297a6SIngo Molnar try_again:
284d988d5eeSKan Liang 		if (perf_evsel__open(pos, pos->cpus, pos->threads) < 0) {
28556e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2863da297a6SIngo Molnar 				if (verbose)
287c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2883da297a6SIngo Molnar 				goto try_again;
2893da297a6SIngo Molnar 			}
290ca6a4258SDavid Ahern 
29156e52e85SArnaldo Carvalho de Melo 			rc = -errno;
29256e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
29356e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
29456e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
2958d3eca20SDavid Ahern 			goto out;
2967c6a1c65SPeter Zijlstra 		}
2977c6a1c65SPeter Zijlstra 	}
2987c6a1c65SPeter Zijlstra 
29923d4aad4SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist, &pos)) {
30023d4aad4SArnaldo Carvalho de Melo 		error("failed to set filter \"%s\" on event %s with %d (%s)\n",
30123d4aad4SArnaldo Carvalho de Melo 			pos->filter, perf_evsel__name(pos), errno,
30235550da3SMasami Hiramatsu 			strerror_r(errno, msg, sizeof(msg)));
3038d3eca20SDavid Ahern 		rc = -1;
3048d3eca20SDavid Ahern 		goto out;
3050a102479SFrederic Weisbecker 	}
3060a102479SFrederic Weisbecker 
307ef149c25SAdrian Hunter 	if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
3082dd6d8a1SAdrian Hunter 				 opts->auxtrace_mmap_pages,
3092dd6d8a1SAdrian Hunter 				 opts->auxtrace_snapshot_mode) < 0) {
3108d3eca20SDavid Ahern 		if (errno == EPERM) {
3118d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
31218e60939SNelson Elhage 			       "Consider increasing "
31318e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
31418e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
315ef149c25SAdrian Hunter 			       "(current value: %u,%u)\n",
316ef149c25SAdrian Hunter 			       opts->mmap_pages, opts->auxtrace_mmap_pages);
3178d3eca20SDavid Ahern 			rc = -errno;
3188d3eca20SDavid Ahern 		} else {
31935550da3SMasami Hiramatsu 			pr_err("failed to mmap with %d (%s)\n", errno,
32035550da3SMasami Hiramatsu 				strerror_r(errno, msg, sizeof(msg)));
3218d3eca20SDavid Ahern 			rc = -errno;
3228d3eca20SDavid Ahern 		}
3238d3eca20SDavid Ahern 		goto out;
32418e60939SNelson Elhage 	}
3250a27d7f9SArnaldo Carvalho de Melo 
326a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
3277b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
3288d3eca20SDavid Ahern out:
3298d3eca20SDavid Ahern 	return rc;
330a91e5431SArnaldo Carvalho de Melo }
331a91e5431SArnaldo Carvalho de Melo 
332e3d59112SNamhyung Kim static int process_sample_event(struct perf_tool *tool,
333e3d59112SNamhyung Kim 				union perf_event *event,
334e3d59112SNamhyung Kim 				struct perf_sample *sample,
335e3d59112SNamhyung Kim 				struct perf_evsel *evsel,
336e3d59112SNamhyung Kim 				struct machine *machine)
337e3d59112SNamhyung Kim {
338e3d59112SNamhyung Kim 	struct record *rec = container_of(tool, struct record, tool);
339e3d59112SNamhyung Kim 
340e3d59112SNamhyung Kim 	rec->samples++;
341e3d59112SNamhyung Kim 
342e3d59112SNamhyung Kim 	return build_id__mark_dso_hit(tool, event, sample, evsel, machine);
343e3d59112SNamhyung Kim }
344e3d59112SNamhyung Kim 
3458c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
3466122e4e4SArnaldo Carvalho de Melo {
347f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
348f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
3496122e4e4SArnaldo Carvalho de Melo 
350457ae94aSHe Kuang 	if (file->size == 0)
3519f591fd7SArnaldo Carvalho de Melo 		return 0;
3529f591fd7SArnaldo Carvalho de Melo 
35300dc8657SNamhyung Kim 	/*
35400dc8657SNamhyung Kim 	 * During this process, it'll load kernel map and replace the
35500dc8657SNamhyung Kim 	 * dso->long_name to a real pathname it found.  In this case
35600dc8657SNamhyung Kim 	 * we prefer the vmlinux path like
35700dc8657SNamhyung Kim 	 *   /lib/modules/3.16.4/build/vmlinux
35800dc8657SNamhyung Kim 	 *
35900dc8657SNamhyung Kim 	 * rather than build-id path (in debug directory).
36000dc8657SNamhyung Kim 	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
36100dc8657SNamhyung Kim 	 */
36200dc8657SNamhyung Kim 	symbol_conf.ignore_vmlinux_buildid = true;
36300dc8657SNamhyung Kim 
364b7b61cbeSArnaldo Carvalho de Melo 	return perf_session__process_events(session);
3656122e4e4SArnaldo Carvalho de Melo }
3666122e4e4SArnaldo Carvalho de Melo 
3678115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
368a1645ce1SZhang, Yanmin {
369a1645ce1SZhang, Yanmin 	int err;
37045694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
371a1645ce1SZhang, Yanmin 	/*
372a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
373a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
374a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
375a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
376a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
377a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
378a1645ce1SZhang, Yanmin 	 */
37945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
380743eb868SArnaldo Carvalho de Melo 					     machine);
381a1645ce1SZhang, Yanmin 	if (err < 0)
382a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
38323346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
384a1645ce1SZhang, Yanmin 
385a1645ce1SZhang, Yanmin 	/*
386a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
387a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
388a1645ce1SZhang, Yanmin 	 */
38945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
3900ae617beSAdrian Hunter 						 machine);
391a1645ce1SZhang, Yanmin 	if (err < 0)
392a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
39323346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
394a1645ce1SZhang, Yanmin }
395a1645ce1SZhang, Yanmin 
39698402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
39798402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
39898402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
39998402807SFrederic Weisbecker };
40098402807SFrederic Weisbecker 
4018c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
40298402807SFrederic Weisbecker {
403dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
4040e2e63ddSPeter Zijlstra 	int i;
4058d3eca20SDavid Ahern 	int rc = 0;
40698402807SFrederic Weisbecker 
407d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
408ef149c25SAdrian Hunter 		struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap;
409ef149c25SAdrian Hunter 
4108d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
411e5685730SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, i) != 0) {
4128d3eca20SDavid Ahern 				rc = -1;
4138d3eca20SDavid Ahern 				goto out;
4148d3eca20SDavid Ahern 			}
4158d3eca20SDavid Ahern 		}
416ef149c25SAdrian Hunter 
4172dd6d8a1SAdrian Hunter 		if (mm->base && !rec->opts.auxtrace_snapshot_mode &&
418ef149c25SAdrian Hunter 		    record__auxtrace_mmap_read(rec, mm) != 0) {
419ef149c25SAdrian Hunter 			rc = -1;
420ef149c25SAdrian Hunter 			goto out;
421ef149c25SAdrian Hunter 		}
42298402807SFrederic Weisbecker 	}
42398402807SFrederic Weisbecker 
424dcabb507SJiri Olsa 	/*
425dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
426dcabb507SJiri Olsa 	 * at least one event.
427dcabb507SJiri Olsa 	 */
428dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
4298c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
4308d3eca20SDavid Ahern 
4318d3eca20SDavid Ahern out:
4328d3eca20SDavid Ahern 	return rc;
43398402807SFrederic Weisbecker }
43498402807SFrederic Weisbecker 
4358c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
43657706abcSDavid Ahern {
43757706abcSDavid Ahern 	struct perf_session *session = rec->session;
43857706abcSDavid Ahern 	int feat;
43957706abcSDavid Ahern 
44057706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
44157706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
44257706abcSDavid Ahern 
44357706abcSDavid Ahern 	if (rec->no_buildid)
44457706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
44557706abcSDavid Ahern 
4463e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
44757706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
44857706abcSDavid Ahern 
44957706abcSDavid Ahern 	if (!rec->opts.branch_stack)
45057706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
451ef149c25SAdrian Hunter 
452ef149c25SAdrian Hunter 	if (!rec->opts.full_auxtrace)
453ef149c25SAdrian Hunter 		perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
45457706abcSDavid Ahern }
45557706abcSDavid Ahern 
456f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
457f33cbe72SArnaldo Carvalho de Melo 
458f33cbe72SArnaldo Carvalho de Melo /*
459f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
460f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
461f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
462f33cbe72SArnaldo Carvalho de Melo  */
46345604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
46445604710SNamhyung Kim 					siginfo_t *info,
465f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
466f33cbe72SArnaldo Carvalho de Melo {
467f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
468f33cbe72SArnaldo Carvalho de Melo 	done = 1;
469f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
470f33cbe72SArnaldo Carvalho de Melo }
471f33cbe72SArnaldo Carvalho de Melo 
4722dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig);
4732dd6d8a1SAdrian Hunter 
4748c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
47586470930SIngo Molnar {
47657706abcSDavid Ahern 	int err;
47745604710SNamhyung Kim 	int status = 0;
4788b412664SPeter Zijlstra 	unsigned long waking = 0;
47946be604bSZhang, Yanmin 	const bool forks = argc > 0;
48023346f21SArnaldo Carvalho de Melo 	struct machine *machine;
48145694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
482b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
483f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
484d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
4856dcf45efSArnaldo Carvalho de Melo 	bool disabled = false, draining = false;
48642aa276fSNamhyung Kim 	int fd;
48786470930SIngo Molnar 
488d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
48933e49ea7SAndi Kleen 
49045604710SNamhyung Kim 	atexit(record__sig_exit);
491f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
492f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
493804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
4942dd6d8a1SAdrian Hunter 	if (rec->opts.auxtrace_snapshot_mode)
4952dd6d8a1SAdrian Hunter 		signal(SIGUSR2, snapshot_sig_handler);
4962dd6d8a1SAdrian Hunter 	else
4972dd6d8a1SAdrian Hunter 		signal(SIGUSR2, SIG_IGN);
498f5970550SPeter Zijlstra 
499b7b61cbeSArnaldo Carvalho de Melo 	session = perf_session__new(file, false, tool);
50094c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
501ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
502a9a70bbcSArnaldo Carvalho de Melo 		return -1;
503a9a70bbcSArnaldo Carvalho de Melo 	}
504a9a70bbcSArnaldo Carvalho de Melo 
50542aa276fSNamhyung Kim 	fd = perf_data_file__fd(file);
506d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
507d20deb64SArnaldo Carvalho de Melo 
5088c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
509330aa675SStephane Eranian 
510d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
5113e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
512f5fc1412SJiri Olsa 						    argv, file->is_pipe,
513735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
51435b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
51535b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
51645604710SNamhyung Kim 			status = err;
51735b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
518856e9660SPeter Zijlstra 		}
519856e9660SPeter Zijlstra 	}
520856e9660SPeter Zijlstra 
5218c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
5228d3eca20SDavid Ahern 		err = -1;
52345604710SNamhyung Kim 		goto out_child;
5248d3eca20SDavid Ahern 	}
52586470930SIngo Molnar 
526cca8482cSAdrian Hunter 	/*
527cca8482cSAdrian Hunter 	 * Normally perf_session__new would do this, but it doesn't have the
528cca8482cSAdrian Hunter 	 * evlist.
529cca8482cSAdrian Hunter 	 */
530cca8482cSAdrian Hunter 	if (rec->tool.ordered_events && !perf_evlist__sample_id_all(rec->evlist)) {
531cca8482cSAdrian Hunter 		pr_warning("WARNING: No sample_id_all support, falling back to unordered processing\n");
532cca8482cSAdrian Hunter 		rec->tool.ordered_events = false;
533cca8482cSAdrian Hunter 	}
534cca8482cSAdrian Hunter 
5353e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
536a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
537a8bb559bSNamhyung Kim 
538f5fc1412SJiri Olsa 	if (file->is_pipe) {
53942aa276fSNamhyung Kim 		err = perf_header__write_pipe(fd);
540529870e3STom Zanussi 		if (err < 0)
54145604710SNamhyung Kim 			goto out_child;
542563aecb2SJiri Olsa 	} else {
54342aa276fSNamhyung Kim 		err = perf_session__write_header(session, rec->evlist, fd, false);
544d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
54545604710SNamhyung Kim 			goto out_child;
546d5eed904SArnaldo Carvalho de Melo 	}
5477c6a1c65SPeter Zijlstra 
548d3665498SDavid Ahern 	if (!rec->no_buildid
549e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
550d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
551e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
5528d3eca20SDavid Ahern 		err = -1;
55345604710SNamhyung Kim 		goto out_child;
554e20960c0SRobert Richter 	}
555e20960c0SRobert Richter 
55634ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
557743eb868SArnaldo Carvalho de Melo 
558f5fc1412SJiri Olsa 	if (file->is_pipe) {
55945694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
560a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
5612c46dbb5STom Zanussi 		if (err < 0) {
5622c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
56345604710SNamhyung Kim 			goto out_child;
5642c46dbb5STom Zanussi 		}
565cd19a035STom Zanussi 
5663e2be2daSArnaldo Carvalho de Melo 		if (have_tracepoints(&rec->evlist->entries)) {
56763e0c771STom Zanussi 			/*
56863e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
56963e0c771STom Zanussi 			 * there were no tracepoints so its not really
57063e0c771STom Zanussi 			 * an error, just that we don't need to
57163e0c771STom Zanussi 			 * synthesize anything.  We really have to
57263e0c771STom Zanussi 			 * return this more properly and also
57363e0c771STom Zanussi 			 * propagate errors that now are calling die()
57463e0c771STom Zanussi 			 */
57542aa276fSNamhyung Kim 			err = perf_event__synthesize_tracing_data(tool,	fd, rec->evlist,
576743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
57763e0c771STom Zanussi 			if (err <= 0) {
57863e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
57945604710SNamhyung Kim 				goto out_child;
58063e0c771STom Zanussi 			}
581f34b9001SDavid Ahern 			rec->bytes_written += err;
5822c46dbb5STom Zanussi 		}
58363e0c771STom Zanussi 	}
5842c46dbb5STom Zanussi 
585ef149c25SAdrian Hunter 	if (rec->opts.full_auxtrace) {
586ef149c25SAdrian Hunter 		err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
587ef149c25SAdrian Hunter 					session, process_synthesized_event);
588ef149c25SAdrian Hunter 		if (err)
589ef149c25SAdrian Hunter 			goto out_delete_session;
590ef149c25SAdrian Hunter 	}
591ef149c25SAdrian Hunter 
59245694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
5930ae617beSAdrian Hunter 						 machine);
594c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
595c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
596c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
597c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
59856b03f3cSArnaldo Carvalho de Melo 
59945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
600743eb868SArnaldo Carvalho de Melo 					     machine);
601c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
602c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
603c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
604c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
605c1a3a4b9SArnaldo Carvalho de Melo 
6067e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
607876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
6087e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
6097e383de4SArnaldo Carvalho de Melo 	}
610b7cece76SArnaldo Carvalho de Melo 
6113e2be2daSArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
6129d9cad76SKan Liang 					    process_synthesized_event, opts->sample_address,
6139d9cad76SKan Liang 					    opts->proc_map_timeout);
6148d3eca20SDavid Ahern 	if (err != 0)
61545604710SNamhyung Kim 		goto out_child;
6168d3eca20SDavid Ahern 
617d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
61886470930SIngo Molnar 		struct sched_param param;
61986470930SIngo Molnar 
620d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
62186470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
6226beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
6238d3eca20SDavid Ahern 			err = -1;
62445604710SNamhyung Kim 			goto out_child;
62586470930SIngo Molnar 		}
62686470930SIngo Molnar 	}
62786470930SIngo Molnar 
628774cb499SJiri Olsa 	/*
629774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
630774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
631774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
632774cb499SJiri Olsa 	 */
6336619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
6343e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
635764e16a3SDavid Ahern 
636856e9660SPeter Zijlstra 	/*
637856e9660SPeter Zijlstra 	 * Let the child rip
638856e9660SPeter Zijlstra 	 */
639*e803cf97SNamhyung Kim 	if (forks) {
640*e803cf97SNamhyung Kim 		union perf_event event;
641*e803cf97SNamhyung Kim 		/*
642*e803cf97SNamhyung Kim 		 * Some H/W events are generated before COMM event
643*e803cf97SNamhyung Kim 		 * which is emitted during exec(), so perf script
644*e803cf97SNamhyung Kim 		 * cannot see a correct process name for those events.
645*e803cf97SNamhyung Kim 		 * Synthesize COMM event to prevent it.
646*e803cf97SNamhyung Kim 		 */
647*e803cf97SNamhyung Kim 		perf_event__synthesize_comm(tool, &event,
648*e803cf97SNamhyung Kim 					    rec->evlist->workload.pid,
649*e803cf97SNamhyung Kim 					    process_synthesized_event,
650*e803cf97SNamhyung Kim 					    machine);
651*e803cf97SNamhyung Kim 
6523e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
653*e803cf97SNamhyung Kim 	}
654856e9660SPeter Zijlstra 
6556619a53eSAndi Kleen 	if (opts->initial_delay) {
6566619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
6576619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
6586619a53eSAndi Kleen 	}
6596619a53eSAndi Kleen 
6602dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 1;
661649c48a9SPeter Zijlstra 	for (;;) {
662d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
66386470930SIngo Molnar 
6648c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
6652dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
6668d3eca20SDavid Ahern 			err = -1;
66745604710SNamhyung Kim 			goto out_child;
6688d3eca20SDavid Ahern 		}
66986470930SIngo Molnar 
6702dd6d8a1SAdrian Hunter 		if (auxtrace_record__snapshot_started) {
6712dd6d8a1SAdrian Hunter 			auxtrace_record__snapshot_started = 0;
6722dd6d8a1SAdrian Hunter 			if (!auxtrace_snapshot_err)
6732dd6d8a1SAdrian Hunter 				record__read_auxtrace_snapshot(rec);
6742dd6d8a1SAdrian Hunter 			if (auxtrace_snapshot_err) {
6752dd6d8a1SAdrian Hunter 				pr_err("AUX area tracing snapshot failed\n");
6762dd6d8a1SAdrian Hunter 				err = -1;
6772dd6d8a1SAdrian Hunter 				goto out_child;
6782dd6d8a1SAdrian Hunter 			}
6792dd6d8a1SAdrian Hunter 		}
6802dd6d8a1SAdrian Hunter 
681d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
6826dcf45efSArnaldo Carvalho de Melo 			if (done || draining)
683649c48a9SPeter Zijlstra 				break;
684f66a889dSArnaldo Carvalho de Melo 			err = perf_evlist__poll(rec->evlist, -1);
685a515114fSJiri Olsa 			/*
686a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
687a515114fSJiri Olsa 			 * number of returned events and interrupt error.
688a515114fSJiri Olsa 			 */
689a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
69045604710SNamhyung Kim 				err = 0;
6918b412664SPeter Zijlstra 			waking++;
6926dcf45efSArnaldo Carvalho de Melo 
6936dcf45efSArnaldo Carvalho de Melo 			if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
6946dcf45efSArnaldo Carvalho de Melo 				draining = true;
6958b412664SPeter Zijlstra 		}
6968b412664SPeter Zijlstra 
697774cb499SJiri Olsa 		/*
698774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
699774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
700774cb499SJiri Olsa 		 * disable events in this case.
701774cb499SJiri Olsa 		 */
702602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
7032dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
7043e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
7052711926aSJiri Olsa 			disabled = true;
7062711926aSJiri Olsa 		}
7078b412664SPeter Zijlstra 	}
7082dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
7098b412664SPeter Zijlstra 
710f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
71135550da3SMasami Hiramatsu 		char msg[STRERR_BUFSIZE];
712f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
713f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
714f33cbe72SArnaldo Carvalho de Melo 		err = -1;
71545604710SNamhyung Kim 		goto out_child;
716f33cbe72SArnaldo Carvalho de Melo 	}
717f33cbe72SArnaldo Carvalho de Melo 
718e3d59112SNamhyung Kim 	if (!quiet)
7198b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
72086470930SIngo Molnar 
72145604710SNamhyung Kim out_child:
72245604710SNamhyung Kim 	if (forks) {
72345604710SNamhyung Kim 		int exit_status;
72445604710SNamhyung Kim 
72545604710SNamhyung Kim 		if (!child_finished)
72645604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
72745604710SNamhyung Kim 
72845604710SNamhyung Kim 		wait(&exit_status);
72945604710SNamhyung Kim 
73045604710SNamhyung Kim 		if (err < 0)
73145604710SNamhyung Kim 			status = err;
73245604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
73345604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
73445604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
73545604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
73645604710SNamhyung Kim 	} else
73745604710SNamhyung Kim 		status = err;
73845604710SNamhyung Kim 
739e3d59112SNamhyung Kim 	/* this will be recalculated during process_buildids() */
740e3d59112SNamhyung Kim 	rec->samples = 0;
741e3d59112SNamhyung Kim 
74245604710SNamhyung Kim 	if (!err && !file->is_pipe) {
74345604710SNamhyung Kim 		rec->session->header.data_size += rec->bytes_written;
744457ae94aSHe Kuang 		file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
74545604710SNamhyung Kim 
746cd10b289SAdrian Hunter 		if (!rec->no_buildid) {
74745604710SNamhyung Kim 			process_buildids(rec);
748cd10b289SAdrian Hunter 			/*
749cd10b289SAdrian Hunter 			 * We take all buildids when the file contains
750cd10b289SAdrian Hunter 			 * AUX area tracing data because we do not decode the
751cd10b289SAdrian Hunter 			 * trace because it would take too long.
752cd10b289SAdrian Hunter 			 */
753cd10b289SAdrian Hunter 			if (rec->opts.full_auxtrace)
754cd10b289SAdrian Hunter 				dsos__hit_all(rec->session);
755cd10b289SAdrian Hunter 		}
75642aa276fSNamhyung Kim 		perf_session__write_header(rec->session, rec->evlist, fd, true);
75745604710SNamhyung Kim 	}
75839d17dacSArnaldo Carvalho de Melo 
759e3d59112SNamhyung Kim 	if (!err && !quiet) {
760e3d59112SNamhyung Kim 		char samples[128];
761e3d59112SNamhyung Kim 
762ef149c25SAdrian Hunter 		if (rec->samples && !rec->opts.full_auxtrace)
763e3d59112SNamhyung Kim 			scnprintf(samples, sizeof(samples),
764e3d59112SNamhyung Kim 				  " (%" PRIu64 " samples)", rec->samples);
765e3d59112SNamhyung Kim 		else
766e3d59112SNamhyung Kim 			samples[0] = '\0';
767e3d59112SNamhyung Kim 
768e3d59112SNamhyung Kim 		fprintf(stderr,	"[ perf record: Captured and wrote %.3f MB %s%s ]\n",
769e3d59112SNamhyung Kim 			perf_data_file__size(file) / 1024.0 / 1024.0,
770e3d59112SNamhyung Kim 			file->path, samples);
771e3d59112SNamhyung Kim 	}
772e3d59112SNamhyung Kim 
77339d17dacSArnaldo Carvalho de Melo out_delete_session:
77439d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
77545604710SNamhyung Kim 	return status;
77686470930SIngo Molnar }
77786470930SIngo Molnar 
77872a128aaSNamhyung Kim static void callchain_debug(void)
77909b0fd45SJiri Olsa {
780aad2b21cSKan Liang 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" };
781a601fdffSJiri Olsa 
78272a128aaSNamhyung Kim 	pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
78326d33022SJiri Olsa 
78472a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_DWARF)
78509b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
78672a128aaSNamhyung Kim 			 callchain_param.dump_size);
78709b0fd45SJiri Olsa }
78809b0fd45SJiri Olsa 
789c421e80bSKan Liang int record_parse_callchain_opt(const struct option *opt,
79009b0fd45SJiri Olsa 			       const char *arg,
79109b0fd45SJiri Olsa 			       int unset)
79209b0fd45SJiri Olsa {
79309b0fd45SJiri Olsa 	int ret;
794c421e80bSKan Liang 	struct record_opts *record = (struct record_opts *)opt->value;
79509b0fd45SJiri Olsa 
796c421e80bSKan Liang 	record->callgraph_set = true;
79772a128aaSNamhyung Kim 	callchain_param.enabled = !unset;
798eb853e80SJiri Olsa 
79909b0fd45SJiri Olsa 	/* --no-call-graph */
80009b0fd45SJiri Olsa 	if (unset) {
80172a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_NONE;
80209b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
80309b0fd45SJiri Olsa 		return 0;
80409b0fd45SJiri Olsa 	}
80509b0fd45SJiri Olsa 
806c3a6a8c4SKan Liang 	ret = parse_callchain_record_opt(arg, &callchain_param);
80709b0fd45SJiri Olsa 	if (!ret)
80872a128aaSNamhyung Kim 		callchain_debug();
80909b0fd45SJiri Olsa 
81026d33022SJiri Olsa 	return ret;
81126d33022SJiri Olsa }
81226d33022SJiri Olsa 
813c421e80bSKan Liang int record_callchain_opt(const struct option *opt,
81409b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
81509b0fd45SJiri Olsa 			 int unset __maybe_unused)
81609b0fd45SJiri Olsa {
817c421e80bSKan Liang 	struct record_opts *record = (struct record_opts *)opt->value;
818c421e80bSKan Liang 
819c421e80bSKan Liang 	record->callgraph_set = true;
82072a128aaSNamhyung Kim 	callchain_param.enabled = true;
82109b0fd45SJiri Olsa 
82272a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_NONE)
82372a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_FP;
824eb853e80SJiri Olsa 
82572a128aaSNamhyung Kim 	callchain_debug();
82609b0fd45SJiri Olsa 	return 0;
82709b0fd45SJiri Olsa }
82809b0fd45SJiri Olsa 
829eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
830eb853e80SJiri Olsa {
831eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
8325a2e5e85SNamhyung Kim 		var = "call-graph.record-mode"; /* fall-through */
833eb853e80SJiri Olsa 
834eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
835eb853e80SJiri Olsa }
836eb853e80SJiri Olsa 
837814c8c38SPeter Zijlstra struct clockid_map {
838814c8c38SPeter Zijlstra 	const char *name;
839814c8c38SPeter Zijlstra 	int clockid;
840814c8c38SPeter Zijlstra };
841814c8c38SPeter Zijlstra 
842814c8c38SPeter Zijlstra #define CLOCKID_MAP(n, c)	\
843814c8c38SPeter Zijlstra 	{ .name = n, .clockid = (c), }
844814c8c38SPeter Zijlstra 
845814c8c38SPeter Zijlstra #define CLOCKID_END	{ .name = NULL, }
846814c8c38SPeter Zijlstra 
847814c8c38SPeter Zijlstra 
848814c8c38SPeter Zijlstra /*
849814c8c38SPeter Zijlstra  * Add the missing ones, we need to build on many distros...
850814c8c38SPeter Zijlstra  */
851814c8c38SPeter Zijlstra #ifndef CLOCK_MONOTONIC_RAW
852814c8c38SPeter Zijlstra #define CLOCK_MONOTONIC_RAW 4
853814c8c38SPeter Zijlstra #endif
854814c8c38SPeter Zijlstra #ifndef CLOCK_BOOTTIME
855814c8c38SPeter Zijlstra #define CLOCK_BOOTTIME 7
856814c8c38SPeter Zijlstra #endif
857814c8c38SPeter Zijlstra #ifndef CLOCK_TAI
858814c8c38SPeter Zijlstra #define CLOCK_TAI 11
859814c8c38SPeter Zijlstra #endif
860814c8c38SPeter Zijlstra 
861814c8c38SPeter Zijlstra static const struct clockid_map clockids[] = {
862814c8c38SPeter Zijlstra 	/* available for all events, NMI safe */
863814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic", CLOCK_MONOTONIC),
864814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW),
865814c8c38SPeter Zijlstra 
866814c8c38SPeter Zijlstra 	/* available for some events */
867814c8c38SPeter Zijlstra 	CLOCKID_MAP("realtime", CLOCK_REALTIME),
868814c8c38SPeter Zijlstra 	CLOCKID_MAP("boottime", CLOCK_BOOTTIME),
869814c8c38SPeter Zijlstra 	CLOCKID_MAP("tai", CLOCK_TAI),
870814c8c38SPeter Zijlstra 
871814c8c38SPeter Zijlstra 	/* available for the lazy */
872814c8c38SPeter Zijlstra 	CLOCKID_MAP("mono", CLOCK_MONOTONIC),
873814c8c38SPeter Zijlstra 	CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW),
874814c8c38SPeter Zijlstra 	CLOCKID_MAP("real", CLOCK_REALTIME),
875814c8c38SPeter Zijlstra 	CLOCKID_MAP("boot", CLOCK_BOOTTIME),
876814c8c38SPeter Zijlstra 
877814c8c38SPeter Zijlstra 	CLOCKID_END,
878814c8c38SPeter Zijlstra };
879814c8c38SPeter Zijlstra 
880814c8c38SPeter Zijlstra static int parse_clockid(const struct option *opt, const char *str, int unset)
881814c8c38SPeter Zijlstra {
882814c8c38SPeter Zijlstra 	struct record_opts *opts = (struct record_opts *)opt->value;
883814c8c38SPeter Zijlstra 	const struct clockid_map *cm;
884814c8c38SPeter Zijlstra 	const char *ostr = str;
885814c8c38SPeter Zijlstra 
886814c8c38SPeter Zijlstra 	if (unset) {
887814c8c38SPeter Zijlstra 		opts->use_clockid = 0;
888814c8c38SPeter Zijlstra 		return 0;
889814c8c38SPeter Zijlstra 	}
890814c8c38SPeter Zijlstra 
891814c8c38SPeter Zijlstra 	/* no arg passed */
892814c8c38SPeter Zijlstra 	if (!str)
893814c8c38SPeter Zijlstra 		return 0;
894814c8c38SPeter Zijlstra 
895814c8c38SPeter Zijlstra 	/* no setting it twice */
896814c8c38SPeter Zijlstra 	if (opts->use_clockid)
897814c8c38SPeter Zijlstra 		return -1;
898814c8c38SPeter Zijlstra 
899814c8c38SPeter Zijlstra 	opts->use_clockid = true;
900814c8c38SPeter Zijlstra 
901814c8c38SPeter Zijlstra 	/* if its a number, we're done */
902814c8c38SPeter Zijlstra 	if (sscanf(str, "%d", &opts->clockid) == 1)
903814c8c38SPeter Zijlstra 		return 0;
904814c8c38SPeter Zijlstra 
905814c8c38SPeter Zijlstra 	/* allow a "CLOCK_" prefix to the name */
906814c8c38SPeter Zijlstra 	if (!strncasecmp(str, "CLOCK_", 6))
907814c8c38SPeter Zijlstra 		str += 6;
908814c8c38SPeter Zijlstra 
909814c8c38SPeter Zijlstra 	for (cm = clockids; cm->name; cm++) {
910814c8c38SPeter Zijlstra 		if (!strcasecmp(str, cm->name)) {
911814c8c38SPeter Zijlstra 			opts->clockid = cm->clockid;
912814c8c38SPeter Zijlstra 			return 0;
913814c8c38SPeter Zijlstra 		}
914814c8c38SPeter Zijlstra 	}
915814c8c38SPeter Zijlstra 
916814c8c38SPeter Zijlstra 	opts->use_clockid = false;
917814c8c38SPeter Zijlstra 	ui__warning("unknown clockid %s, check man page\n", ostr);
918814c8c38SPeter Zijlstra 	return -1;
919814c8c38SPeter Zijlstra }
920814c8c38SPeter Zijlstra 
921e9db1310SAdrian Hunter static int record__parse_mmap_pages(const struct option *opt,
922e9db1310SAdrian Hunter 				    const char *str,
923e9db1310SAdrian Hunter 				    int unset __maybe_unused)
924e9db1310SAdrian Hunter {
925e9db1310SAdrian Hunter 	struct record_opts *opts = opt->value;
926e9db1310SAdrian Hunter 	char *s, *p;
927e9db1310SAdrian Hunter 	unsigned int mmap_pages;
928e9db1310SAdrian Hunter 	int ret;
929e9db1310SAdrian Hunter 
930e9db1310SAdrian Hunter 	if (!str)
931e9db1310SAdrian Hunter 		return -EINVAL;
932e9db1310SAdrian Hunter 
933e9db1310SAdrian Hunter 	s = strdup(str);
934e9db1310SAdrian Hunter 	if (!s)
935e9db1310SAdrian Hunter 		return -ENOMEM;
936e9db1310SAdrian Hunter 
937e9db1310SAdrian Hunter 	p = strchr(s, ',');
938e9db1310SAdrian Hunter 	if (p)
939e9db1310SAdrian Hunter 		*p = '\0';
940e9db1310SAdrian Hunter 
941e9db1310SAdrian Hunter 	if (*s) {
942e9db1310SAdrian Hunter 		ret = __perf_evlist__parse_mmap_pages(&mmap_pages, s);
943e9db1310SAdrian Hunter 		if (ret)
944e9db1310SAdrian Hunter 			goto out_free;
945e9db1310SAdrian Hunter 		opts->mmap_pages = mmap_pages;
946e9db1310SAdrian Hunter 	}
947e9db1310SAdrian Hunter 
948e9db1310SAdrian Hunter 	if (!p) {
949e9db1310SAdrian Hunter 		ret = 0;
950e9db1310SAdrian Hunter 		goto out_free;
951e9db1310SAdrian Hunter 	}
952e9db1310SAdrian Hunter 
953e9db1310SAdrian Hunter 	ret = __perf_evlist__parse_mmap_pages(&mmap_pages, p + 1);
954e9db1310SAdrian Hunter 	if (ret)
955e9db1310SAdrian Hunter 		goto out_free;
956e9db1310SAdrian Hunter 
957e9db1310SAdrian Hunter 	opts->auxtrace_mmap_pages = mmap_pages;
958e9db1310SAdrian Hunter 
959e9db1310SAdrian Hunter out_free:
960e9db1310SAdrian Hunter 	free(s);
961e9db1310SAdrian Hunter 	return ret;
962e9db1310SAdrian Hunter }
963e9db1310SAdrian Hunter 
964e5b2c207SNamhyung Kim static const char * const __record_usage[] = {
96586470930SIngo Molnar 	"perf record [<options>] [<command>]",
96686470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
96786470930SIngo Molnar 	NULL
96886470930SIngo Molnar };
969e5b2c207SNamhyung Kim const char * const *record_usage = __record_usage;
97086470930SIngo Molnar 
971d20deb64SArnaldo Carvalho de Melo /*
9728c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
9738c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
974d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
975d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
976d20deb64SArnaldo Carvalho de Melo  *
977d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
978d20deb64SArnaldo Carvalho de Melo  *
979d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
980d20deb64SArnaldo Carvalho de Melo  */
9818c6f45a7SArnaldo Carvalho de Melo static struct record record = {
982d20deb64SArnaldo Carvalho de Melo 	.opts = {
9838affc2b8SAndi Kleen 		.sample_time	     = true,
984d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
985d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
986d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
987447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
988d1cb9fceSNamhyung Kim 		.target		     = {
989d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
9903aa5939dSAdrian Hunter 			.default_per_cpu = true,
991d1cb9fceSNamhyung Kim 		},
9929d9cad76SKan Liang 		.proc_map_timeout     = 500,
993d20deb64SArnaldo Carvalho de Melo 	},
994e3d59112SNamhyung Kim 	.tool = {
995e3d59112SNamhyung Kim 		.sample		= process_sample_event,
996e3d59112SNamhyung Kim 		.fork		= perf_event__process_fork,
997cca8482cSAdrian Hunter 		.exit		= perf_event__process_exit,
998e3d59112SNamhyung Kim 		.comm		= perf_event__process_comm,
999e3d59112SNamhyung Kim 		.mmap		= perf_event__process_mmap,
1000e3d59112SNamhyung Kim 		.mmap2		= perf_event__process_mmap2,
1001cca8482cSAdrian Hunter 		.ordered_events	= true,
1002e3d59112SNamhyung Kim 	},
1003d20deb64SArnaldo Carvalho de Melo };
10047865e817SFrederic Weisbecker 
100509b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
100661eaa3beSArnaldo Carvalho de Melo 
10079ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
1008aad2b21cSKan Liang const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf lbr";
100961eaa3beSArnaldo Carvalho de Melo #else
1010aad2b21cSKan Liang const char record_callchain_help[] = CALLCHAIN_HELP "fp lbr";
101161eaa3beSArnaldo Carvalho de Melo #endif
101261eaa3beSArnaldo Carvalho de Melo 
1013d20deb64SArnaldo Carvalho de Melo /*
1014d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
1015d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
1016b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
1017d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
1018d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
1019d20deb64SArnaldo Carvalho de Melo  */
1020e5b2c207SNamhyung Kim struct option __record_options[] = {
1021d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
102286470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
1023f120f9d5SJiri Olsa 		     parse_events_option),
1024d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
1025c171b552SLi Zefan 		     "event filter", parse_filter),
10264ba1faa1SWang Nan 	OPT_CALLBACK_NOOPT(0, "exclude-perf", &record.evlist,
10274ba1faa1SWang Nan 			   NULL, "don't record events from perf itself",
10284ba1faa1SWang Nan 			   exclude_perf),
1029bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
1030d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
1031bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
1032d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
1033d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
103486470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
1035509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
1036acac03faSKirill Smelkov 		    "collect data without buffering"),
1037d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
1038daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
1039bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
104086470930SIngo Molnar 			    "system-wide collection from all CPUs"),
1041bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
1042c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
1043d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
1044f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
104586470930SIngo Molnar 		    "output file name"),
104669e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
104769e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
10482e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
1049d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
1050e9db1310SAdrian Hunter 	OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]",
1051e9db1310SAdrian Hunter 		     "number of mmap data pages and AUX area tracing mmap pages",
1052e9db1310SAdrian Hunter 		     record__parse_mmap_pages),
1053d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
105443bece79SLin Ming 		    "put the counters into a counter group"),
105509b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
105609b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
105709b0fd45SJiri Olsa 			   &record_callchain_opt),
105809b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
105975d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
106009b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
1061c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
10623da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
1063b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
1064d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
1065649c48a9SPeter Zijlstra 		    "per thread counts"),
106656100321SPeter Zijlstra 	OPT_BOOLEAN('d', "data", &record.opts.sample_address, "Record the sample addresses"),
10673abebc55SAdrian Hunter 	OPT_BOOLEAN_SET('T', "timestamp", &record.opts.sample_time,
10683abebc55SAdrian Hunter 			&record.opts.sample_time_set,
10693abebc55SAdrian Hunter 			"Record the sample timestamps"),
107056100321SPeter Zijlstra 	OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"),
1071d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
1072649c48a9SPeter Zijlstra 		    "don't sample"),
1073d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
1074a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
1075d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
1076baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
1077d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
1078023695d9SStephane Eranian 		     "monitor event in cgroup name only",
1079023695d9SStephane Eranian 		     parse_cgroups),
1080a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
10816619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
1082bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
1083bea03405SNamhyung Kim 		   "user to profile"),
1084a5aabdacSStephane Eranian 
1085a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
1086a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
1087a5aabdacSStephane Eranian 		     parse_branch_stack),
1088a5aabdacSStephane Eranian 
1089a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
1090a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
1091bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
109205484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
109305484298SAndi Kleen 		    "sample by weight (on special events only)"),
1094475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
1095475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
10963aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
10973aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
1098bcc84ec6SStephane Eranian 	OPT_CALLBACK_OPTARG('I', "intr-regs", &record.opts.sample_intr_regs, NULL, "any register",
1099bcc84ec6SStephane Eranian 		    "sample selected machine registers on interrupt,"
1100bcc84ec6SStephane Eranian 		    " use -I ? to list register names", parse_regs),
110185c273d2SAndi Kleen 	OPT_BOOLEAN(0, "running-time", &record.opts.running_time,
110285c273d2SAndi Kleen 		    "Record running/enabled time of read (:S) events"),
1103814c8c38SPeter Zijlstra 	OPT_CALLBACK('k', "clockid", &record.opts,
1104814c8c38SPeter Zijlstra 	"clockid", "clockid to use for events, see clock_gettime()",
1105814c8c38SPeter Zijlstra 	parse_clockid),
11062dd6d8a1SAdrian Hunter 	OPT_STRING_OPTARG('S', "snapshot", &record.opts.auxtrace_snapshot_opts,
11072dd6d8a1SAdrian Hunter 			  "opts", "AUX area tracing Snapshot Mode", ""),
11089d9cad76SKan Liang 	OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout,
11099d9cad76SKan Liang 			"per thread proc mmap processing timeout in ms"),
1110b757bb09SAdrian Hunter 	OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
1111b757bb09SAdrian Hunter 		    "Record context switch events"),
111286470930SIngo Molnar 	OPT_END()
111386470930SIngo Molnar };
111486470930SIngo Molnar 
1115e5b2c207SNamhyung Kim struct option *record_options = __record_options;
1116e5b2c207SNamhyung Kim 
11171d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
111886470930SIngo Molnar {
1119ef149c25SAdrian Hunter 	int err;
11208c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
112116ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
112286470930SIngo Molnar 
11233e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
11243e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
1125361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
1126361c99a6SArnaldo Carvalho de Melo 
1127eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
1128eb853e80SJiri Olsa 
1129bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
1130a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
1131602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
1132bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
113386470930SIngo Molnar 
1134bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
11353780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
1136023695d9SStephane Eranian 			  " system-wide mode\n");
1137023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
1138023695d9SStephane Eranian 	}
1139b757bb09SAdrian Hunter 	if (rec->opts.record_switch_events &&
1140b757bb09SAdrian Hunter 	    !perf_can_record_switch_events()) {
1141b757bb09SAdrian Hunter 		ui__error("kernel does not support recording context switch events (--switch-events option)\n");
1142b757bb09SAdrian Hunter 		usage_with_options(record_usage, record_options);
1143b757bb09SAdrian Hunter 	}
1144023695d9SStephane Eranian 
1145ef149c25SAdrian Hunter 	if (!rec->itr) {
1146ef149c25SAdrian Hunter 		rec->itr = auxtrace_record__init(rec->evlist, &err);
1147ef149c25SAdrian Hunter 		if (err)
1148ef149c25SAdrian Hunter 			return err;
1149ef149c25SAdrian Hunter 	}
1150ef149c25SAdrian Hunter 
11512dd6d8a1SAdrian Hunter 	err = auxtrace_parse_snapshot_options(rec->itr, &rec->opts,
11522dd6d8a1SAdrian Hunter 					      rec->opts.auxtrace_snapshot_opts);
11532dd6d8a1SAdrian Hunter 	if (err)
11542dd6d8a1SAdrian Hunter 		return err;
11552dd6d8a1SAdrian Hunter 
1156ef149c25SAdrian Hunter 	err = -ENOMEM;
1157ef149c25SAdrian Hunter 
11580a7e6d1bSNamhyung Kim 	symbol__init(NULL);
1159baa2f6ceSArnaldo Carvalho de Melo 
1160ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
1161646aaea6SArnaldo Carvalho de Melo 		pr_warning(
1162646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
1163ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
1164646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
1165646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
1166646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
1167646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
1168646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
1169ec80fde7SArnaldo Carvalho de Melo 
1170d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
1171a1ac1d3cSStephane Eranian 		disable_buildid_cache();
1172655000e7SArnaldo Carvalho de Melo 
11733e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
11743e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
117569aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
117669aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
1177bbd36e5eSPeter Zijlstra 	}
117886470930SIngo Molnar 
117969e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
118069e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
118169e7e5b0SAdrian Hunter 
1182602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
118316ad2ffbSNamhyung Kim 	if (err) {
1184602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
118516ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
118616ad2ffbSNamhyung Kim 	}
11874bd0f2d2SNamhyung Kim 
1188602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
118916ad2ffbSNamhyung Kim 	if (err) {
119016ad2ffbSNamhyung Kim 		int saved_errno = errno;
119116ad2ffbSNamhyung Kim 
1192602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
11933780f488SNamhyung Kim 		ui__error("%s", errbuf);
119416ad2ffbSNamhyung Kim 
119516ad2ffbSNamhyung Kim 		err = -saved_errno;
11968fa60e1fSNamhyung Kim 		goto out_symbol_exit;
119716ad2ffbSNamhyung Kim 	}
11980d37aa34SArnaldo Carvalho de Melo 
119916ad2ffbSNamhyung Kim 	err = -ENOMEM;
12003e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
1201dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
120269aad6f1SArnaldo Carvalho de Melo 
1203ef149c25SAdrian Hunter 	err = auxtrace_record__options(rec->itr, rec->evlist, &rec->opts);
1204ef149c25SAdrian Hunter 	if (err)
1205ef149c25SAdrian Hunter 		goto out_symbol_exit;
1206ef149c25SAdrian Hunter 
1207b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
120839d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
120903ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
12107e4ff9e3SMike Galbraith 	}
12117e4ff9e3SMike Galbraith 
1212d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
1213d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
121445604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
1215d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
1216ef149c25SAdrian Hunter 	auxtrace_record__free(rec->itr);
121739d17dacSArnaldo Carvalho de Melo 	return err;
121886470930SIngo Molnar }
12192dd6d8a1SAdrian Hunter 
12202dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig __maybe_unused)
12212dd6d8a1SAdrian Hunter {
12222dd6d8a1SAdrian Hunter 	if (!auxtrace_snapshot_enabled)
12232dd6d8a1SAdrian Hunter 		return;
12242dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
12252dd6d8a1SAdrian Hunter 	auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
12262dd6d8a1SAdrian Hunter 	auxtrace_record__snapshot_started = 1;
12272dd6d8a1SAdrian Hunter }
1228