xref: /openbmc/linux/tools/perf/builtin-record.c (revision 457ae94ae047330e75c13f28ead6de31eab245ed)
186470930SIngo Molnar /*
286470930SIngo Molnar  * builtin-record.c
386470930SIngo Molnar  *
486470930SIngo Molnar  * Builtin record command: Record the profile of a workload
586470930SIngo Molnar  * (or a CPU, or a PID) into the perf.data output file - for
686470930SIngo Molnar  * later analysis via perf report.
786470930SIngo Molnar  */
886470930SIngo Molnar #include "builtin.h"
986470930SIngo Molnar 
1086470930SIngo Molnar #include "perf.h"
1186470930SIngo Molnar 
126122e4e4SArnaldo Carvalho de Melo #include "util/build-id.h"
1386470930SIngo Molnar #include "util/util.h"
1486470930SIngo Molnar #include "util/parse-options.h"
1586470930SIngo Molnar #include "util/parse-events.h"
1686470930SIngo Molnar 
178f651eaeSArnaldo Carvalho de Melo #include "util/callchain.h"
18f14d5707SArnaldo Carvalho de Melo #include "util/cgroup.h"
197c6a1c65SPeter Zijlstra #include "util/header.h"
2066e274f3SFrederic Weisbecker #include "util/event.h"
21361c99a6SArnaldo Carvalho de Melo #include "util/evlist.h"
2269aad6f1SArnaldo Carvalho de Melo #include "util/evsel.h"
238f28827aSFrederic Weisbecker #include "util/debug.h"
2494c744b6SArnaldo Carvalho de Melo #include "util/session.h"
2545694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
268d06367fSArnaldo Carvalho de Melo #include "util/symbol.h"
27a12b51c4SPaul Mackerras #include "util/cpumap.h"
28fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h"
29f5fc1412SJiri Olsa #include "util/data.h"
30ef149c25SAdrian Hunter #include "util/auxtrace.h"
31f00898f4SAndi Kleen #include "util/parse-branch-options.h"
327c6a1c65SPeter Zijlstra 
3386470930SIngo Molnar #include <unistd.h>
3486470930SIngo Molnar #include <sched.h>
35a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3686470930SIngo Molnar 
3778da39faSBernhard Rosenkraenzer 
388c6f45a7SArnaldo Carvalho de Melo struct record {
3945694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
40b4006796SArnaldo Carvalho de Melo 	struct record_opts	opts;
41d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
42f5fc1412SJiri Olsa 	struct perf_data_file	file;
43ef149c25SAdrian Hunter 	struct auxtrace_record	*itr;
44d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
45d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
46d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
47d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
48d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
49d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
50d20deb64SArnaldo Carvalho de Melo 	long			samples;
510f82ebc4SArnaldo Carvalho de Melo };
5286470930SIngo Molnar 
538c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
54f5970550SPeter Zijlstra {
55cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
564f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
578d3eca20SDavid Ahern 		return -1;
588d3eca20SDavid Ahern 	}
59f5970550SPeter Zijlstra 
60cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
618d3eca20SDavid Ahern 	return 0;
62f5970550SPeter Zijlstra }
63f5970550SPeter Zijlstra 
6445694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
65d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
661d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
671d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
68234fbbf5SArnaldo Carvalho de Melo {
698c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
708c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
71234fbbf5SArnaldo Carvalho de Melo }
72234fbbf5SArnaldo Carvalho de Melo 
73e5685730SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, int idx)
7486470930SIngo Molnar {
75e5685730SArnaldo Carvalho de Melo 	struct perf_mmap *md = &rec->evlist->mmap[idx];
767b8283b5SDavid Ahern 	u64 head = perf_mmap__read_head(md);
777b8283b5SDavid Ahern 	u64 old = md->prev;
78918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
7986470930SIngo Molnar 	unsigned long size;
8086470930SIngo Molnar 	void *buf;
818d3eca20SDavid Ahern 	int rc = 0;
8286470930SIngo Molnar 
83dc82009aSArnaldo Carvalho de Melo 	if (old == head)
848d3eca20SDavid Ahern 		return 0;
8586470930SIngo Molnar 
86d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
8786470930SIngo Molnar 
8886470930SIngo Molnar 	size = head - old;
8986470930SIngo Molnar 
9086470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
9186470930SIngo Molnar 		buf = &data[old & md->mask];
9286470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
9386470930SIngo Molnar 		old += size;
9486470930SIngo Molnar 
958c6f45a7SArnaldo Carvalho de Melo 		if (record__write(rec, buf, size) < 0) {
968d3eca20SDavid Ahern 			rc = -1;
978d3eca20SDavid Ahern 			goto out;
988d3eca20SDavid Ahern 		}
9986470930SIngo Molnar 	}
10086470930SIngo Molnar 
10186470930SIngo Molnar 	buf = &data[old & md->mask];
10286470930SIngo Molnar 	size = head - old;
10386470930SIngo Molnar 	old += size;
10486470930SIngo Molnar 
1058c6f45a7SArnaldo Carvalho de Melo 	if (record__write(rec, buf, size) < 0) {
1068d3eca20SDavid Ahern 		rc = -1;
1078d3eca20SDavid Ahern 		goto out;
1088d3eca20SDavid Ahern 	}
10986470930SIngo Molnar 
11086470930SIngo Molnar 	md->prev = old;
111e5685730SArnaldo Carvalho de Melo 	perf_evlist__mmap_consume(rec->evlist, idx);
1128d3eca20SDavid Ahern out:
1138d3eca20SDavid Ahern 	return rc;
11486470930SIngo Molnar }
11586470930SIngo Molnar 
1162dd6d8a1SAdrian Hunter static volatile int done;
1172dd6d8a1SAdrian Hunter static volatile int signr = -1;
1182dd6d8a1SAdrian Hunter static volatile int child_finished;
1192dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_enabled;
1202dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_err;
1212dd6d8a1SAdrian Hunter static volatile int auxtrace_record__snapshot_started;
1222dd6d8a1SAdrian Hunter 
1232dd6d8a1SAdrian Hunter static void sig_handler(int sig)
1242dd6d8a1SAdrian Hunter {
1252dd6d8a1SAdrian Hunter 	if (sig == SIGCHLD)
1262dd6d8a1SAdrian Hunter 		child_finished = 1;
1272dd6d8a1SAdrian Hunter 	else
1282dd6d8a1SAdrian Hunter 		signr = sig;
1292dd6d8a1SAdrian Hunter 
1302dd6d8a1SAdrian Hunter 	done = 1;
1312dd6d8a1SAdrian Hunter }
1322dd6d8a1SAdrian Hunter 
1332dd6d8a1SAdrian Hunter static void record__sig_exit(void)
1342dd6d8a1SAdrian Hunter {
1352dd6d8a1SAdrian Hunter 	if (signr == -1)
1362dd6d8a1SAdrian Hunter 		return;
1372dd6d8a1SAdrian Hunter 
1382dd6d8a1SAdrian Hunter 	signal(signr, SIG_DFL);
1392dd6d8a1SAdrian Hunter 	raise(signr);
1402dd6d8a1SAdrian Hunter }
1412dd6d8a1SAdrian Hunter 
142e31f0d01SAdrian Hunter #ifdef HAVE_AUXTRACE_SUPPORT
143e31f0d01SAdrian Hunter 
144ef149c25SAdrian Hunter static int record__process_auxtrace(struct perf_tool *tool,
145ef149c25SAdrian Hunter 				    union perf_event *event, void *data1,
146ef149c25SAdrian Hunter 				    size_t len1, void *data2, size_t len2)
147ef149c25SAdrian Hunter {
148ef149c25SAdrian Hunter 	struct record *rec = container_of(tool, struct record, tool);
14999fa2984SAdrian Hunter 	struct perf_data_file *file = &rec->file;
150ef149c25SAdrian Hunter 	size_t padding;
151ef149c25SAdrian Hunter 	u8 pad[8] = {0};
152ef149c25SAdrian Hunter 
15399fa2984SAdrian Hunter 	if (!perf_data_file__is_pipe(file)) {
15499fa2984SAdrian Hunter 		off_t file_offset;
15599fa2984SAdrian Hunter 		int fd = perf_data_file__fd(file);
15699fa2984SAdrian Hunter 		int err;
15799fa2984SAdrian Hunter 
15899fa2984SAdrian Hunter 		file_offset = lseek(fd, 0, SEEK_CUR);
15999fa2984SAdrian Hunter 		if (file_offset == -1)
16099fa2984SAdrian Hunter 			return -1;
16199fa2984SAdrian Hunter 		err = auxtrace_index__auxtrace_event(&rec->session->auxtrace_index,
16299fa2984SAdrian Hunter 						     event, file_offset);
16399fa2984SAdrian Hunter 		if (err)
16499fa2984SAdrian Hunter 			return err;
16599fa2984SAdrian Hunter 	}
16699fa2984SAdrian Hunter 
167ef149c25SAdrian Hunter 	/* event.auxtrace.size includes padding, see __auxtrace_mmap__read() */
168ef149c25SAdrian Hunter 	padding = (len1 + len2) & 7;
169ef149c25SAdrian Hunter 	if (padding)
170ef149c25SAdrian Hunter 		padding = 8 - padding;
171ef149c25SAdrian Hunter 
172ef149c25SAdrian Hunter 	record__write(rec, event, event->header.size);
173ef149c25SAdrian Hunter 	record__write(rec, data1, len1);
174ef149c25SAdrian Hunter 	if (len2)
175ef149c25SAdrian Hunter 		record__write(rec, data2, len2);
176ef149c25SAdrian Hunter 	record__write(rec, &pad, padding);
177ef149c25SAdrian Hunter 
178ef149c25SAdrian Hunter 	return 0;
179ef149c25SAdrian Hunter }
180ef149c25SAdrian Hunter 
181ef149c25SAdrian Hunter static int record__auxtrace_mmap_read(struct record *rec,
182ef149c25SAdrian Hunter 				      struct auxtrace_mmap *mm)
183ef149c25SAdrian Hunter {
184ef149c25SAdrian Hunter 	int ret;
185ef149c25SAdrian Hunter 
186ef149c25SAdrian Hunter 	ret = auxtrace_mmap__read(mm, rec->itr, &rec->tool,
187ef149c25SAdrian Hunter 				  record__process_auxtrace);
188ef149c25SAdrian Hunter 	if (ret < 0)
189ef149c25SAdrian Hunter 		return ret;
190ef149c25SAdrian Hunter 
191ef149c25SAdrian Hunter 	if (ret)
192ef149c25SAdrian Hunter 		rec->samples++;
193ef149c25SAdrian Hunter 
194ef149c25SAdrian Hunter 	return 0;
195ef149c25SAdrian Hunter }
196ef149c25SAdrian Hunter 
1972dd6d8a1SAdrian Hunter static int record__auxtrace_mmap_read_snapshot(struct record *rec,
1982dd6d8a1SAdrian Hunter 					       struct auxtrace_mmap *mm)
1992dd6d8a1SAdrian Hunter {
2002dd6d8a1SAdrian Hunter 	int ret;
2012dd6d8a1SAdrian Hunter 
2022dd6d8a1SAdrian Hunter 	ret = auxtrace_mmap__read_snapshot(mm, rec->itr, &rec->tool,
2032dd6d8a1SAdrian Hunter 					   record__process_auxtrace,
2042dd6d8a1SAdrian Hunter 					   rec->opts.auxtrace_snapshot_size);
2052dd6d8a1SAdrian Hunter 	if (ret < 0)
2062dd6d8a1SAdrian Hunter 		return ret;
2072dd6d8a1SAdrian Hunter 
2082dd6d8a1SAdrian Hunter 	if (ret)
2092dd6d8a1SAdrian Hunter 		rec->samples++;
2102dd6d8a1SAdrian Hunter 
2112dd6d8a1SAdrian Hunter 	return 0;
2122dd6d8a1SAdrian Hunter }
2132dd6d8a1SAdrian Hunter 
2142dd6d8a1SAdrian Hunter static int record__auxtrace_read_snapshot_all(struct record *rec)
2152dd6d8a1SAdrian Hunter {
2162dd6d8a1SAdrian Hunter 	int i;
2172dd6d8a1SAdrian Hunter 	int rc = 0;
2182dd6d8a1SAdrian Hunter 
2192dd6d8a1SAdrian Hunter 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
2202dd6d8a1SAdrian Hunter 		struct auxtrace_mmap *mm =
2212dd6d8a1SAdrian Hunter 				&rec->evlist->mmap[i].auxtrace_mmap;
2222dd6d8a1SAdrian Hunter 
2232dd6d8a1SAdrian Hunter 		if (!mm->base)
2242dd6d8a1SAdrian Hunter 			continue;
2252dd6d8a1SAdrian Hunter 
2262dd6d8a1SAdrian Hunter 		if (record__auxtrace_mmap_read_snapshot(rec, mm) != 0) {
2272dd6d8a1SAdrian Hunter 			rc = -1;
2282dd6d8a1SAdrian Hunter 			goto out;
2292dd6d8a1SAdrian Hunter 		}
2302dd6d8a1SAdrian Hunter 	}
2312dd6d8a1SAdrian Hunter out:
2322dd6d8a1SAdrian Hunter 	return rc;
2332dd6d8a1SAdrian Hunter }
2342dd6d8a1SAdrian Hunter 
2352dd6d8a1SAdrian Hunter static void record__read_auxtrace_snapshot(struct record *rec)
2362dd6d8a1SAdrian Hunter {
2372dd6d8a1SAdrian Hunter 	pr_debug("Recording AUX area tracing snapshot\n");
2382dd6d8a1SAdrian Hunter 	if (record__auxtrace_read_snapshot_all(rec) < 0) {
2392dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = -1;
2402dd6d8a1SAdrian Hunter 	} else {
2412dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr);
2422dd6d8a1SAdrian Hunter 		if (!auxtrace_snapshot_err)
2432dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 1;
2442dd6d8a1SAdrian Hunter 	}
2452dd6d8a1SAdrian Hunter }
2462dd6d8a1SAdrian Hunter 
247e31f0d01SAdrian Hunter #else
248e31f0d01SAdrian Hunter 
249e31f0d01SAdrian Hunter static inline
250e31f0d01SAdrian Hunter int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
251e31f0d01SAdrian Hunter 			       struct auxtrace_mmap *mm __maybe_unused)
252e31f0d01SAdrian Hunter {
253e31f0d01SAdrian Hunter 	return 0;
254e31f0d01SAdrian Hunter }
255e31f0d01SAdrian Hunter 
2562dd6d8a1SAdrian Hunter static inline
2572dd6d8a1SAdrian Hunter void record__read_auxtrace_snapshot(struct record *rec __maybe_unused)
2582dd6d8a1SAdrian Hunter {
2592dd6d8a1SAdrian Hunter }
2602dd6d8a1SAdrian Hunter 
2612dd6d8a1SAdrian Hunter static inline
2622dd6d8a1SAdrian Hunter int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused)
2632dd6d8a1SAdrian Hunter {
2642dd6d8a1SAdrian Hunter 	return 0;
2652dd6d8a1SAdrian Hunter }
2662dd6d8a1SAdrian Hunter 
267e31f0d01SAdrian Hunter #endif
268e31f0d01SAdrian Hunter 
2698c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
270dd7927f4SArnaldo Carvalho de Melo {
27156e52e85SArnaldo Carvalho de Melo 	char msg[512];
2726a4bb04cSJiri Olsa 	struct perf_evsel *pos;
273d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
274d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
275b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
2768d3eca20SDavid Ahern 	int rc = 0;
277dd7927f4SArnaldo Carvalho de Melo 
278f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
279cac21425SJiri Olsa 
2800050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
2813da297a6SIngo Molnar try_again:
2826a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
28356e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2843da297a6SIngo Molnar 				if (verbose)
285c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2863da297a6SIngo Molnar 				goto try_again;
2873da297a6SIngo Molnar 			}
288ca6a4258SDavid Ahern 
28956e52e85SArnaldo Carvalho de Melo 			rc = -errno;
29056e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
29156e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
29256e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
2938d3eca20SDavid Ahern 			goto out;
2947c6a1c65SPeter Zijlstra 		}
2957c6a1c65SPeter Zijlstra 	}
2967c6a1c65SPeter Zijlstra 
29723d4aad4SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist, &pos)) {
29823d4aad4SArnaldo Carvalho de Melo 		error("failed to set filter \"%s\" on event %s with %d (%s)\n",
29923d4aad4SArnaldo Carvalho de Melo 			pos->filter, perf_evsel__name(pos), errno,
30035550da3SMasami Hiramatsu 			strerror_r(errno, msg, sizeof(msg)));
3018d3eca20SDavid Ahern 		rc = -1;
3028d3eca20SDavid Ahern 		goto out;
3030a102479SFrederic Weisbecker 	}
3040a102479SFrederic Weisbecker 
305ef149c25SAdrian Hunter 	if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
3062dd6d8a1SAdrian Hunter 				 opts->auxtrace_mmap_pages,
3072dd6d8a1SAdrian Hunter 				 opts->auxtrace_snapshot_mode) < 0) {
3088d3eca20SDavid Ahern 		if (errno == EPERM) {
3098d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
31018e60939SNelson Elhage 			       "Consider increasing "
31118e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
31218e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
313ef149c25SAdrian Hunter 			       "(current value: %u,%u)\n",
314ef149c25SAdrian Hunter 			       opts->mmap_pages, opts->auxtrace_mmap_pages);
3158d3eca20SDavid Ahern 			rc = -errno;
3168d3eca20SDavid Ahern 		} else {
31735550da3SMasami Hiramatsu 			pr_err("failed to mmap with %d (%s)\n", errno,
31835550da3SMasami Hiramatsu 				strerror_r(errno, msg, sizeof(msg)));
3198d3eca20SDavid Ahern 			rc = -errno;
3208d3eca20SDavid Ahern 		}
3218d3eca20SDavid Ahern 		goto out;
32218e60939SNelson Elhage 	}
3230a27d7f9SArnaldo Carvalho de Melo 
324a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
3257b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
3268d3eca20SDavid Ahern out:
3278d3eca20SDavid Ahern 	return rc;
328a91e5431SArnaldo Carvalho de Melo }
329a91e5431SArnaldo Carvalho de Melo 
330e3d59112SNamhyung Kim static int process_sample_event(struct perf_tool *tool,
331e3d59112SNamhyung Kim 				union perf_event *event,
332e3d59112SNamhyung Kim 				struct perf_sample *sample,
333e3d59112SNamhyung Kim 				struct perf_evsel *evsel,
334e3d59112SNamhyung Kim 				struct machine *machine)
335e3d59112SNamhyung Kim {
336e3d59112SNamhyung Kim 	struct record *rec = container_of(tool, struct record, tool);
337e3d59112SNamhyung Kim 
338e3d59112SNamhyung Kim 	rec->samples++;
339e3d59112SNamhyung Kim 
340e3d59112SNamhyung Kim 	return build_id__mark_dso_hit(tool, event, sample, evsel, machine);
341e3d59112SNamhyung Kim }
342e3d59112SNamhyung Kim 
3438c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
3446122e4e4SArnaldo Carvalho de Melo {
345f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
346f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
3476122e4e4SArnaldo Carvalho de Melo 
348*457ae94aSHe Kuang 	if (file->size == 0)
3499f591fd7SArnaldo Carvalho de Melo 		return 0;
3509f591fd7SArnaldo Carvalho de Melo 
35100dc8657SNamhyung Kim 	/*
35200dc8657SNamhyung Kim 	 * During this process, it'll load kernel map and replace the
35300dc8657SNamhyung Kim 	 * dso->long_name to a real pathname it found.  In this case
35400dc8657SNamhyung Kim 	 * we prefer the vmlinux path like
35500dc8657SNamhyung Kim 	 *   /lib/modules/3.16.4/build/vmlinux
35600dc8657SNamhyung Kim 	 *
35700dc8657SNamhyung Kim 	 * rather than build-id path (in debug directory).
35800dc8657SNamhyung Kim 	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
35900dc8657SNamhyung Kim 	 */
36000dc8657SNamhyung Kim 	symbol_conf.ignore_vmlinux_buildid = true;
36100dc8657SNamhyung Kim 
362b7b61cbeSArnaldo Carvalho de Melo 	return perf_session__process_events(session);
3636122e4e4SArnaldo Carvalho de Melo }
3646122e4e4SArnaldo Carvalho de Melo 
3658115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
366a1645ce1SZhang, Yanmin {
367a1645ce1SZhang, Yanmin 	int err;
36845694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
369a1645ce1SZhang, Yanmin 	/*
370a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
371a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
372a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
373a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
374a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
375a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
376a1645ce1SZhang, Yanmin 	 */
37745694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
378743eb868SArnaldo Carvalho de Melo 					     machine);
379a1645ce1SZhang, Yanmin 	if (err < 0)
380a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
38123346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
382a1645ce1SZhang, Yanmin 
383a1645ce1SZhang, Yanmin 	/*
384a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
385a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
386a1645ce1SZhang, Yanmin 	 */
38745694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
3880ae617beSAdrian Hunter 						 machine);
389a1645ce1SZhang, Yanmin 	if (err < 0)
390a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
39123346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
392a1645ce1SZhang, Yanmin }
393a1645ce1SZhang, Yanmin 
39498402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
39598402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
39698402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
39798402807SFrederic Weisbecker };
39898402807SFrederic Weisbecker 
3998c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
40098402807SFrederic Weisbecker {
401dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
4020e2e63ddSPeter Zijlstra 	int i;
4038d3eca20SDavid Ahern 	int rc = 0;
40498402807SFrederic Weisbecker 
405d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
406ef149c25SAdrian Hunter 		struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap;
407ef149c25SAdrian Hunter 
4088d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
409e5685730SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, i) != 0) {
4108d3eca20SDavid Ahern 				rc = -1;
4118d3eca20SDavid Ahern 				goto out;
4128d3eca20SDavid Ahern 			}
4138d3eca20SDavid Ahern 		}
414ef149c25SAdrian Hunter 
4152dd6d8a1SAdrian Hunter 		if (mm->base && !rec->opts.auxtrace_snapshot_mode &&
416ef149c25SAdrian Hunter 		    record__auxtrace_mmap_read(rec, mm) != 0) {
417ef149c25SAdrian Hunter 			rc = -1;
418ef149c25SAdrian Hunter 			goto out;
419ef149c25SAdrian Hunter 		}
42098402807SFrederic Weisbecker 	}
42198402807SFrederic Weisbecker 
422dcabb507SJiri Olsa 	/*
423dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
424dcabb507SJiri Olsa 	 * at least one event.
425dcabb507SJiri Olsa 	 */
426dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
4278c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
4288d3eca20SDavid Ahern 
4298d3eca20SDavid Ahern out:
4308d3eca20SDavid Ahern 	return rc;
43198402807SFrederic Weisbecker }
43298402807SFrederic Weisbecker 
4338c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
43457706abcSDavid Ahern {
43557706abcSDavid Ahern 	struct perf_session *session = rec->session;
43657706abcSDavid Ahern 	int feat;
43757706abcSDavid Ahern 
43857706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
43957706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
44057706abcSDavid Ahern 
44157706abcSDavid Ahern 	if (rec->no_buildid)
44257706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
44357706abcSDavid Ahern 
4443e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
44557706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
44657706abcSDavid Ahern 
44757706abcSDavid Ahern 	if (!rec->opts.branch_stack)
44857706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
449ef149c25SAdrian Hunter 
450ef149c25SAdrian Hunter 	if (!rec->opts.full_auxtrace)
451ef149c25SAdrian Hunter 		perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
45257706abcSDavid Ahern }
45357706abcSDavid Ahern 
454f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
455f33cbe72SArnaldo Carvalho de Melo 
456f33cbe72SArnaldo Carvalho de Melo /*
457f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
458f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
459f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
460f33cbe72SArnaldo Carvalho de Melo  */
46145604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
46245604710SNamhyung Kim 					siginfo_t *info,
463f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
464f33cbe72SArnaldo Carvalho de Melo {
465f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
466f33cbe72SArnaldo Carvalho de Melo 	done = 1;
467f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
468f33cbe72SArnaldo Carvalho de Melo }
469f33cbe72SArnaldo Carvalho de Melo 
4702dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig);
4712dd6d8a1SAdrian Hunter 
4728c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
47386470930SIngo Molnar {
47457706abcSDavid Ahern 	int err;
47545604710SNamhyung Kim 	int status = 0;
4768b412664SPeter Zijlstra 	unsigned long waking = 0;
47746be604bSZhang, Yanmin 	const bool forks = argc > 0;
47823346f21SArnaldo Carvalho de Melo 	struct machine *machine;
47945694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
480b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
481f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
482d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
4836dcf45efSArnaldo Carvalho de Melo 	bool disabled = false, draining = false;
48442aa276fSNamhyung Kim 	int fd;
48586470930SIngo Molnar 
486d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
48733e49ea7SAndi Kleen 
48845604710SNamhyung Kim 	atexit(record__sig_exit);
489f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
490f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
491804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
4922dd6d8a1SAdrian Hunter 	if (rec->opts.auxtrace_snapshot_mode)
4932dd6d8a1SAdrian Hunter 		signal(SIGUSR2, snapshot_sig_handler);
4942dd6d8a1SAdrian Hunter 	else
4952dd6d8a1SAdrian Hunter 		signal(SIGUSR2, SIG_IGN);
496f5970550SPeter Zijlstra 
497b7b61cbeSArnaldo Carvalho de Melo 	session = perf_session__new(file, false, tool);
49894c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
499ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
500a9a70bbcSArnaldo Carvalho de Melo 		return -1;
501a9a70bbcSArnaldo Carvalho de Melo 	}
502a9a70bbcSArnaldo Carvalho de Melo 
50342aa276fSNamhyung Kim 	fd = perf_data_file__fd(file);
504d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
505d20deb64SArnaldo Carvalho de Melo 
5068c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
507330aa675SStephane Eranian 
508d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
5093e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
510f5fc1412SJiri Olsa 						    argv, file->is_pipe,
511735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
51235b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
51335b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
51445604710SNamhyung Kim 			status = err;
51535b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
516856e9660SPeter Zijlstra 		}
517856e9660SPeter Zijlstra 	}
518856e9660SPeter Zijlstra 
5198c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
5208d3eca20SDavid Ahern 		err = -1;
52145604710SNamhyung Kim 		goto out_child;
5228d3eca20SDavid Ahern 	}
52386470930SIngo Molnar 
5243e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
525a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
526a8bb559bSNamhyung Kim 
527f5fc1412SJiri Olsa 	if (file->is_pipe) {
52842aa276fSNamhyung Kim 		err = perf_header__write_pipe(fd);
529529870e3STom Zanussi 		if (err < 0)
53045604710SNamhyung Kim 			goto out_child;
531563aecb2SJiri Olsa 	} else {
53242aa276fSNamhyung Kim 		err = perf_session__write_header(session, rec->evlist, fd, false);
533d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
53445604710SNamhyung Kim 			goto out_child;
535d5eed904SArnaldo Carvalho de Melo 	}
5367c6a1c65SPeter Zijlstra 
537d3665498SDavid Ahern 	if (!rec->no_buildid
538e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
539d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
540e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
5418d3eca20SDavid Ahern 		err = -1;
54245604710SNamhyung Kim 		goto out_child;
543e20960c0SRobert Richter 	}
544e20960c0SRobert Richter 
54534ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
546743eb868SArnaldo Carvalho de Melo 
547f5fc1412SJiri Olsa 	if (file->is_pipe) {
54845694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
549a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
5502c46dbb5STom Zanussi 		if (err < 0) {
5512c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
55245604710SNamhyung Kim 			goto out_child;
5532c46dbb5STom Zanussi 		}
554cd19a035STom Zanussi 
5553e2be2daSArnaldo Carvalho de Melo 		if (have_tracepoints(&rec->evlist->entries)) {
55663e0c771STom Zanussi 			/*
55763e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
55863e0c771STom Zanussi 			 * there were no tracepoints so its not really
55963e0c771STom Zanussi 			 * an error, just that we don't need to
56063e0c771STom Zanussi 			 * synthesize anything.  We really have to
56163e0c771STom Zanussi 			 * return this more properly and also
56263e0c771STom Zanussi 			 * propagate errors that now are calling die()
56363e0c771STom Zanussi 			 */
56442aa276fSNamhyung Kim 			err = perf_event__synthesize_tracing_data(tool,	fd, rec->evlist,
565743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
56663e0c771STom Zanussi 			if (err <= 0) {
56763e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
56845604710SNamhyung Kim 				goto out_child;
56963e0c771STom Zanussi 			}
570f34b9001SDavid Ahern 			rec->bytes_written += err;
5712c46dbb5STom Zanussi 		}
57263e0c771STom Zanussi 	}
5732c46dbb5STom Zanussi 
574ef149c25SAdrian Hunter 	if (rec->opts.full_auxtrace) {
575ef149c25SAdrian Hunter 		err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
576ef149c25SAdrian Hunter 					session, process_synthesized_event);
577ef149c25SAdrian Hunter 		if (err)
578ef149c25SAdrian Hunter 			goto out_delete_session;
579ef149c25SAdrian Hunter 	}
580ef149c25SAdrian Hunter 
58145694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
5820ae617beSAdrian Hunter 						 machine);
583c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
584c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
585c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
586c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
58756b03f3cSArnaldo Carvalho de Melo 
58845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
589743eb868SArnaldo Carvalho de Melo 					     machine);
590c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
591c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
592c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
593c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
594c1a3a4b9SArnaldo Carvalho de Melo 
5957e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
596876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
5977e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
5987e383de4SArnaldo Carvalho de Melo 	}
599b7cece76SArnaldo Carvalho de Melo 
6003e2be2daSArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
60158d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
6028d3eca20SDavid Ahern 	if (err != 0)
60345604710SNamhyung Kim 		goto out_child;
6048d3eca20SDavid Ahern 
605d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
60686470930SIngo Molnar 		struct sched_param param;
60786470930SIngo Molnar 
608d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
60986470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
6106beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
6118d3eca20SDavid Ahern 			err = -1;
61245604710SNamhyung Kim 			goto out_child;
61386470930SIngo Molnar 		}
61486470930SIngo Molnar 	}
61586470930SIngo Molnar 
616774cb499SJiri Olsa 	/*
617774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
618774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
619774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
620774cb499SJiri Olsa 	 */
6216619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
6223e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
623764e16a3SDavid Ahern 
624856e9660SPeter Zijlstra 	/*
625856e9660SPeter Zijlstra 	 * Let the child rip
626856e9660SPeter Zijlstra 	 */
627735f7e0bSArnaldo Carvalho de Melo 	if (forks)
6283e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
629856e9660SPeter Zijlstra 
6306619a53eSAndi Kleen 	if (opts->initial_delay) {
6316619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
6326619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
6336619a53eSAndi Kleen 	}
6346619a53eSAndi Kleen 
6352dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 1;
636649c48a9SPeter Zijlstra 	for (;;) {
637d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
63886470930SIngo Molnar 
6398c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
6402dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
6418d3eca20SDavid Ahern 			err = -1;
64245604710SNamhyung Kim 			goto out_child;
6438d3eca20SDavid Ahern 		}
64486470930SIngo Molnar 
6452dd6d8a1SAdrian Hunter 		if (auxtrace_record__snapshot_started) {
6462dd6d8a1SAdrian Hunter 			auxtrace_record__snapshot_started = 0;
6472dd6d8a1SAdrian Hunter 			if (!auxtrace_snapshot_err)
6482dd6d8a1SAdrian Hunter 				record__read_auxtrace_snapshot(rec);
6492dd6d8a1SAdrian Hunter 			if (auxtrace_snapshot_err) {
6502dd6d8a1SAdrian Hunter 				pr_err("AUX area tracing snapshot failed\n");
6512dd6d8a1SAdrian Hunter 				err = -1;
6522dd6d8a1SAdrian Hunter 				goto out_child;
6532dd6d8a1SAdrian Hunter 			}
6542dd6d8a1SAdrian Hunter 		}
6552dd6d8a1SAdrian Hunter 
656d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
6576dcf45efSArnaldo Carvalho de Melo 			if (done || draining)
658649c48a9SPeter Zijlstra 				break;
659f66a889dSArnaldo Carvalho de Melo 			err = perf_evlist__poll(rec->evlist, -1);
660a515114fSJiri Olsa 			/*
661a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
662a515114fSJiri Olsa 			 * number of returned events and interrupt error.
663a515114fSJiri Olsa 			 */
664a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
66545604710SNamhyung Kim 				err = 0;
6668b412664SPeter Zijlstra 			waking++;
6676dcf45efSArnaldo Carvalho de Melo 
6686dcf45efSArnaldo Carvalho de Melo 			if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
6696dcf45efSArnaldo Carvalho de Melo 				draining = true;
6708b412664SPeter Zijlstra 		}
6718b412664SPeter Zijlstra 
672774cb499SJiri Olsa 		/*
673774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
674774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
675774cb499SJiri Olsa 		 * disable events in this case.
676774cb499SJiri Olsa 		 */
677602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
6782dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
6793e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
6802711926aSJiri Olsa 			disabled = true;
6812711926aSJiri Olsa 		}
6828b412664SPeter Zijlstra 	}
6832dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
6848b412664SPeter Zijlstra 
685f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
68635550da3SMasami Hiramatsu 		char msg[STRERR_BUFSIZE];
687f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
688f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
689f33cbe72SArnaldo Carvalho de Melo 		err = -1;
69045604710SNamhyung Kim 		goto out_child;
691f33cbe72SArnaldo Carvalho de Melo 	}
692f33cbe72SArnaldo Carvalho de Melo 
693e3d59112SNamhyung Kim 	if (!quiet)
6948b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
69586470930SIngo Molnar 
69645604710SNamhyung Kim out_child:
69745604710SNamhyung Kim 	if (forks) {
69845604710SNamhyung Kim 		int exit_status;
69945604710SNamhyung Kim 
70045604710SNamhyung Kim 		if (!child_finished)
70145604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
70245604710SNamhyung Kim 
70345604710SNamhyung Kim 		wait(&exit_status);
70445604710SNamhyung Kim 
70545604710SNamhyung Kim 		if (err < 0)
70645604710SNamhyung Kim 			status = err;
70745604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
70845604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
70945604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
71045604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
71145604710SNamhyung Kim 	} else
71245604710SNamhyung Kim 		status = err;
71345604710SNamhyung Kim 
714e3d59112SNamhyung Kim 	/* this will be recalculated during process_buildids() */
715e3d59112SNamhyung Kim 	rec->samples = 0;
716e3d59112SNamhyung Kim 
71745604710SNamhyung Kim 	if (!err && !file->is_pipe) {
71845604710SNamhyung Kim 		rec->session->header.data_size += rec->bytes_written;
719*457ae94aSHe Kuang 		file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
72045604710SNamhyung Kim 
721cd10b289SAdrian Hunter 		if (!rec->no_buildid) {
72245604710SNamhyung Kim 			process_buildids(rec);
723cd10b289SAdrian Hunter 			/*
724cd10b289SAdrian Hunter 			 * We take all buildids when the file contains
725cd10b289SAdrian Hunter 			 * AUX area tracing data because we do not decode the
726cd10b289SAdrian Hunter 			 * trace because it would take too long.
727cd10b289SAdrian Hunter 			 */
728cd10b289SAdrian Hunter 			if (rec->opts.full_auxtrace)
729cd10b289SAdrian Hunter 				dsos__hit_all(rec->session);
730cd10b289SAdrian Hunter 		}
73142aa276fSNamhyung Kim 		perf_session__write_header(rec->session, rec->evlist, fd, true);
73245604710SNamhyung Kim 	}
73339d17dacSArnaldo Carvalho de Melo 
734e3d59112SNamhyung Kim 	if (!err && !quiet) {
735e3d59112SNamhyung Kim 		char samples[128];
736e3d59112SNamhyung Kim 
737ef149c25SAdrian Hunter 		if (rec->samples && !rec->opts.full_auxtrace)
738e3d59112SNamhyung Kim 			scnprintf(samples, sizeof(samples),
739e3d59112SNamhyung Kim 				  " (%" PRIu64 " samples)", rec->samples);
740e3d59112SNamhyung Kim 		else
741e3d59112SNamhyung Kim 			samples[0] = '\0';
742e3d59112SNamhyung Kim 
743e3d59112SNamhyung Kim 		fprintf(stderr,	"[ perf record: Captured and wrote %.3f MB %s%s ]\n",
744e3d59112SNamhyung Kim 			perf_data_file__size(file) / 1024.0 / 1024.0,
745e3d59112SNamhyung Kim 			file->path, samples);
746e3d59112SNamhyung Kim 	}
747e3d59112SNamhyung Kim 
74839d17dacSArnaldo Carvalho de Melo out_delete_session:
74939d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
75045604710SNamhyung Kim 	return status;
75186470930SIngo Molnar }
75286470930SIngo Molnar 
75372a128aaSNamhyung Kim static void callchain_debug(void)
75409b0fd45SJiri Olsa {
755aad2b21cSKan Liang 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" };
756a601fdffSJiri Olsa 
75772a128aaSNamhyung Kim 	pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
75826d33022SJiri Olsa 
75972a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_DWARF)
76009b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
76172a128aaSNamhyung Kim 			 callchain_param.dump_size);
76209b0fd45SJiri Olsa }
76309b0fd45SJiri Olsa 
76472a128aaSNamhyung Kim int record_parse_callchain_opt(const struct option *opt __maybe_unused,
76509b0fd45SJiri Olsa 			       const char *arg,
76609b0fd45SJiri Olsa 			       int unset)
76709b0fd45SJiri Olsa {
76809b0fd45SJiri Olsa 	int ret;
76909b0fd45SJiri Olsa 
77072a128aaSNamhyung Kim 	callchain_param.enabled = !unset;
771eb853e80SJiri Olsa 
77209b0fd45SJiri Olsa 	/* --no-call-graph */
77309b0fd45SJiri Olsa 	if (unset) {
77472a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_NONE;
77509b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
77609b0fd45SJiri Olsa 		return 0;
77709b0fd45SJiri Olsa 	}
77809b0fd45SJiri Olsa 
779f7f084f4SNamhyung Kim 	ret = parse_callchain_record_opt(arg);
78009b0fd45SJiri Olsa 	if (!ret)
78172a128aaSNamhyung Kim 		callchain_debug();
78209b0fd45SJiri Olsa 
78326d33022SJiri Olsa 	return ret;
78426d33022SJiri Olsa }
78526d33022SJiri Olsa 
78672a128aaSNamhyung Kim int record_callchain_opt(const struct option *opt __maybe_unused,
78709b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
78809b0fd45SJiri Olsa 			 int unset __maybe_unused)
78909b0fd45SJiri Olsa {
79072a128aaSNamhyung Kim 	callchain_param.enabled = true;
79109b0fd45SJiri Olsa 
79272a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_NONE)
79372a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_FP;
794eb853e80SJiri Olsa 
79572a128aaSNamhyung Kim 	callchain_debug();
79609b0fd45SJiri Olsa 	return 0;
79709b0fd45SJiri Olsa }
79809b0fd45SJiri Olsa 
799eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
800eb853e80SJiri Olsa {
801eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
8025a2e5e85SNamhyung Kim 		var = "call-graph.record-mode"; /* fall-through */
803eb853e80SJiri Olsa 
804eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
805eb853e80SJiri Olsa }
806eb853e80SJiri Olsa 
807814c8c38SPeter Zijlstra struct clockid_map {
808814c8c38SPeter Zijlstra 	const char *name;
809814c8c38SPeter Zijlstra 	int clockid;
810814c8c38SPeter Zijlstra };
811814c8c38SPeter Zijlstra 
812814c8c38SPeter Zijlstra #define CLOCKID_MAP(n, c)	\
813814c8c38SPeter Zijlstra 	{ .name = n, .clockid = (c), }
814814c8c38SPeter Zijlstra 
815814c8c38SPeter Zijlstra #define CLOCKID_END	{ .name = NULL, }
816814c8c38SPeter Zijlstra 
817814c8c38SPeter Zijlstra 
818814c8c38SPeter Zijlstra /*
819814c8c38SPeter Zijlstra  * Add the missing ones, we need to build on many distros...
820814c8c38SPeter Zijlstra  */
821814c8c38SPeter Zijlstra #ifndef CLOCK_MONOTONIC_RAW
822814c8c38SPeter Zijlstra #define CLOCK_MONOTONIC_RAW 4
823814c8c38SPeter Zijlstra #endif
824814c8c38SPeter Zijlstra #ifndef CLOCK_BOOTTIME
825814c8c38SPeter Zijlstra #define CLOCK_BOOTTIME 7
826814c8c38SPeter Zijlstra #endif
827814c8c38SPeter Zijlstra #ifndef CLOCK_TAI
828814c8c38SPeter Zijlstra #define CLOCK_TAI 11
829814c8c38SPeter Zijlstra #endif
830814c8c38SPeter Zijlstra 
831814c8c38SPeter Zijlstra static const struct clockid_map clockids[] = {
832814c8c38SPeter Zijlstra 	/* available for all events, NMI safe */
833814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic", CLOCK_MONOTONIC),
834814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW),
835814c8c38SPeter Zijlstra 
836814c8c38SPeter Zijlstra 	/* available for some events */
837814c8c38SPeter Zijlstra 	CLOCKID_MAP("realtime", CLOCK_REALTIME),
838814c8c38SPeter Zijlstra 	CLOCKID_MAP("boottime", CLOCK_BOOTTIME),
839814c8c38SPeter Zijlstra 	CLOCKID_MAP("tai", CLOCK_TAI),
840814c8c38SPeter Zijlstra 
841814c8c38SPeter Zijlstra 	/* available for the lazy */
842814c8c38SPeter Zijlstra 	CLOCKID_MAP("mono", CLOCK_MONOTONIC),
843814c8c38SPeter Zijlstra 	CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW),
844814c8c38SPeter Zijlstra 	CLOCKID_MAP("real", CLOCK_REALTIME),
845814c8c38SPeter Zijlstra 	CLOCKID_MAP("boot", CLOCK_BOOTTIME),
846814c8c38SPeter Zijlstra 
847814c8c38SPeter Zijlstra 	CLOCKID_END,
848814c8c38SPeter Zijlstra };
849814c8c38SPeter Zijlstra 
850814c8c38SPeter Zijlstra static int parse_clockid(const struct option *opt, const char *str, int unset)
851814c8c38SPeter Zijlstra {
852814c8c38SPeter Zijlstra 	struct record_opts *opts = (struct record_opts *)opt->value;
853814c8c38SPeter Zijlstra 	const struct clockid_map *cm;
854814c8c38SPeter Zijlstra 	const char *ostr = str;
855814c8c38SPeter Zijlstra 
856814c8c38SPeter Zijlstra 	if (unset) {
857814c8c38SPeter Zijlstra 		opts->use_clockid = 0;
858814c8c38SPeter Zijlstra 		return 0;
859814c8c38SPeter Zijlstra 	}
860814c8c38SPeter Zijlstra 
861814c8c38SPeter Zijlstra 	/* no arg passed */
862814c8c38SPeter Zijlstra 	if (!str)
863814c8c38SPeter Zijlstra 		return 0;
864814c8c38SPeter Zijlstra 
865814c8c38SPeter Zijlstra 	/* no setting it twice */
866814c8c38SPeter Zijlstra 	if (opts->use_clockid)
867814c8c38SPeter Zijlstra 		return -1;
868814c8c38SPeter Zijlstra 
869814c8c38SPeter Zijlstra 	opts->use_clockid = true;
870814c8c38SPeter Zijlstra 
871814c8c38SPeter Zijlstra 	/* if its a number, we're done */
872814c8c38SPeter Zijlstra 	if (sscanf(str, "%d", &opts->clockid) == 1)
873814c8c38SPeter Zijlstra 		return 0;
874814c8c38SPeter Zijlstra 
875814c8c38SPeter Zijlstra 	/* allow a "CLOCK_" prefix to the name */
876814c8c38SPeter Zijlstra 	if (!strncasecmp(str, "CLOCK_", 6))
877814c8c38SPeter Zijlstra 		str += 6;
878814c8c38SPeter Zijlstra 
879814c8c38SPeter Zijlstra 	for (cm = clockids; cm->name; cm++) {
880814c8c38SPeter Zijlstra 		if (!strcasecmp(str, cm->name)) {
881814c8c38SPeter Zijlstra 			opts->clockid = cm->clockid;
882814c8c38SPeter Zijlstra 			return 0;
883814c8c38SPeter Zijlstra 		}
884814c8c38SPeter Zijlstra 	}
885814c8c38SPeter Zijlstra 
886814c8c38SPeter Zijlstra 	opts->use_clockid = false;
887814c8c38SPeter Zijlstra 	ui__warning("unknown clockid %s, check man page\n", ostr);
888814c8c38SPeter Zijlstra 	return -1;
889814c8c38SPeter Zijlstra }
890814c8c38SPeter Zijlstra 
891e9db1310SAdrian Hunter static int record__parse_mmap_pages(const struct option *opt,
892e9db1310SAdrian Hunter 				    const char *str,
893e9db1310SAdrian Hunter 				    int unset __maybe_unused)
894e9db1310SAdrian Hunter {
895e9db1310SAdrian Hunter 	struct record_opts *opts = opt->value;
896e9db1310SAdrian Hunter 	char *s, *p;
897e9db1310SAdrian Hunter 	unsigned int mmap_pages;
898e9db1310SAdrian Hunter 	int ret;
899e9db1310SAdrian Hunter 
900e9db1310SAdrian Hunter 	if (!str)
901e9db1310SAdrian Hunter 		return -EINVAL;
902e9db1310SAdrian Hunter 
903e9db1310SAdrian Hunter 	s = strdup(str);
904e9db1310SAdrian Hunter 	if (!s)
905e9db1310SAdrian Hunter 		return -ENOMEM;
906e9db1310SAdrian Hunter 
907e9db1310SAdrian Hunter 	p = strchr(s, ',');
908e9db1310SAdrian Hunter 	if (p)
909e9db1310SAdrian Hunter 		*p = '\0';
910e9db1310SAdrian Hunter 
911e9db1310SAdrian Hunter 	if (*s) {
912e9db1310SAdrian Hunter 		ret = __perf_evlist__parse_mmap_pages(&mmap_pages, s);
913e9db1310SAdrian Hunter 		if (ret)
914e9db1310SAdrian Hunter 			goto out_free;
915e9db1310SAdrian Hunter 		opts->mmap_pages = mmap_pages;
916e9db1310SAdrian Hunter 	}
917e9db1310SAdrian Hunter 
918e9db1310SAdrian Hunter 	if (!p) {
919e9db1310SAdrian Hunter 		ret = 0;
920e9db1310SAdrian Hunter 		goto out_free;
921e9db1310SAdrian Hunter 	}
922e9db1310SAdrian Hunter 
923e9db1310SAdrian Hunter 	ret = __perf_evlist__parse_mmap_pages(&mmap_pages, p + 1);
924e9db1310SAdrian Hunter 	if (ret)
925e9db1310SAdrian Hunter 		goto out_free;
926e9db1310SAdrian Hunter 
927e9db1310SAdrian Hunter 	opts->auxtrace_mmap_pages = mmap_pages;
928e9db1310SAdrian Hunter 
929e9db1310SAdrian Hunter out_free:
930e9db1310SAdrian Hunter 	free(s);
931e9db1310SAdrian Hunter 	return ret;
932e9db1310SAdrian Hunter }
933e9db1310SAdrian Hunter 
934e5b2c207SNamhyung Kim static const char * const __record_usage[] = {
93586470930SIngo Molnar 	"perf record [<options>] [<command>]",
93686470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
93786470930SIngo Molnar 	NULL
93886470930SIngo Molnar };
939e5b2c207SNamhyung Kim const char * const *record_usage = __record_usage;
94086470930SIngo Molnar 
941d20deb64SArnaldo Carvalho de Melo /*
9428c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
9438c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
944d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
945d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
946d20deb64SArnaldo Carvalho de Melo  *
947d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
948d20deb64SArnaldo Carvalho de Melo  *
949d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
950d20deb64SArnaldo Carvalho de Melo  */
9518c6f45a7SArnaldo Carvalho de Melo static struct record record = {
952d20deb64SArnaldo Carvalho de Melo 	.opts = {
9538affc2b8SAndi Kleen 		.sample_time	     = true,
954d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
955d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
956d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
957447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
958d1cb9fceSNamhyung Kim 		.target		     = {
959d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
9603aa5939dSAdrian Hunter 			.default_per_cpu = true,
961d1cb9fceSNamhyung Kim 		},
962d20deb64SArnaldo Carvalho de Melo 	},
963e3d59112SNamhyung Kim 	.tool = {
964e3d59112SNamhyung Kim 		.sample		= process_sample_event,
965e3d59112SNamhyung Kim 		.fork		= perf_event__process_fork,
966e3d59112SNamhyung Kim 		.comm		= perf_event__process_comm,
967e3d59112SNamhyung Kim 		.mmap		= perf_event__process_mmap,
968e3d59112SNamhyung Kim 		.mmap2		= perf_event__process_mmap2,
969e3d59112SNamhyung Kim 	},
970d20deb64SArnaldo Carvalho de Melo };
9717865e817SFrederic Weisbecker 
97209b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
97361eaa3beSArnaldo Carvalho de Melo 
9749ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
975aad2b21cSKan Liang const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf lbr";
97661eaa3beSArnaldo Carvalho de Melo #else
977aad2b21cSKan Liang const char record_callchain_help[] = CALLCHAIN_HELP "fp lbr";
97861eaa3beSArnaldo Carvalho de Melo #endif
97961eaa3beSArnaldo Carvalho de Melo 
980d20deb64SArnaldo Carvalho de Melo /*
981d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
982d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
983b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
984d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
985d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
986d20deb64SArnaldo Carvalho de Melo  */
987e5b2c207SNamhyung Kim struct option __record_options[] = {
988d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
98986470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
990f120f9d5SJiri Olsa 		     parse_events_option),
991d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
992c171b552SLi Zefan 		     "event filter", parse_filter),
993bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
994d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
995bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
996d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
997d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
99886470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
999509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
1000acac03faSKirill Smelkov 		    "collect data without buffering"),
1001d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
1002daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
1003bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
100486470930SIngo Molnar 			    "system-wide collection from all CPUs"),
1005bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
1006c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
1007d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
1008f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
100986470930SIngo Molnar 		    "output file name"),
101069e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
101169e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
10122e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
1013d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
1014e9db1310SAdrian Hunter 	OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]",
1015e9db1310SAdrian Hunter 		     "number of mmap data pages and AUX area tracing mmap pages",
1016e9db1310SAdrian Hunter 		     record__parse_mmap_pages),
1017d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
101843bece79SLin Ming 		    "put the counters into a counter group"),
101909b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
102009b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
102109b0fd45SJiri Olsa 			   &record_callchain_opt),
102209b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
102375d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
102409b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
1025c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
10263da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
1027b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
1028d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
1029649c48a9SPeter Zijlstra 		    "per thread counts"),
1030d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
10314bba828dSAnton Blanchard 		    "Sample addresses"),
1032d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
10333e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
1034d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
1035649c48a9SPeter Zijlstra 		    "don't sample"),
1036d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
1037a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
1038d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
1039baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
1040d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
1041023695d9SStephane Eranian 		     "monitor event in cgroup name only",
1042023695d9SStephane Eranian 		     parse_cgroups),
1043a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
10446619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
1045bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
1046bea03405SNamhyung Kim 		   "user to profile"),
1047a5aabdacSStephane Eranian 
1048a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
1049a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
1050a5aabdacSStephane Eranian 		     parse_branch_stack),
1051a5aabdacSStephane Eranian 
1052a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
1053a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
1054bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
105505484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
105605484298SAndi Kleen 		    "sample by weight (on special events only)"),
1057475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
1058475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
10593aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
10603aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
10614b6c5177SStephane Eranian 	OPT_BOOLEAN('I', "intr-regs", &record.opts.sample_intr_regs,
10624b6c5177SStephane Eranian 		    "Sample machine registers on interrupt"),
106385c273d2SAndi Kleen 	OPT_BOOLEAN(0, "running-time", &record.opts.running_time,
106485c273d2SAndi Kleen 		    "Record running/enabled time of read (:S) events"),
1065814c8c38SPeter Zijlstra 	OPT_CALLBACK('k', "clockid", &record.opts,
1066814c8c38SPeter Zijlstra 	"clockid", "clockid to use for events, see clock_gettime()",
1067814c8c38SPeter Zijlstra 	parse_clockid),
10682dd6d8a1SAdrian Hunter 	OPT_STRING_OPTARG('S', "snapshot", &record.opts.auxtrace_snapshot_opts,
10692dd6d8a1SAdrian Hunter 			  "opts", "AUX area tracing Snapshot Mode", ""),
107086470930SIngo Molnar 	OPT_END()
107186470930SIngo Molnar };
107286470930SIngo Molnar 
1073e5b2c207SNamhyung Kim struct option *record_options = __record_options;
1074e5b2c207SNamhyung Kim 
10751d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
107686470930SIngo Molnar {
1077ef149c25SAdrian Hunter 	int err;
10788c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
107916ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
108086470930SIngo Molnar 
10813e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
10823e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
1083361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
1084361c99a6SArnaldo Carvalho de Melo 
1085eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
1086eb853e80SJiri Olsa 
1087bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
1088a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
1089602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
1090bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
109186470930SIngo Molnar 
1092bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
10933780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
1094023695d9SStephane Eranian 			  " system-wide mode\n");
1095023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
1096023695d9SStephane Eranian 	}
1097023695d9SStephane Eranian 
1098ef149c25SAdrian Hunter 	if (!rec->itr) {
1099ef149c25SAdrian Hunter 		rec->itr = auxtrace_record__init(rec->evlist, &err);
1100ef149c25SAdrian Hunter 		if (err)
1101ef149c25SAdrian Hunter 			return err;
1102ef149c25SAdrian Hunter 	}
1103ef149c25SAdrian Hunter 
11042dd6d8a1SAdrian Hunter 	err = auxtrace_parse_snapshot_options(rec->itr, &rec->opts,
11052dd6d8a1SAdrian Hunter 					      rec->opts.auxtrace_snapshot_opts);
11062dd6d8a1SAdrian Hunter 	if (err)
11072dd6d8a1SAdrian Hunter 		return err;
11082dd6d8a1SAdrian Hunter 
1109ef149c25SAdrian Hunter 	err = -ENOMEM;
1110ef149c25SAdrian Hunter 
11110a7e6d1bSNamhyung Kim 	symbol__init(NULL);
1112baa2f6ceSArnaldo Carvalho de Melo 
1113ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
1114646aaea6SArnaldo Carvalho de Melo 		pr_warning(
1115646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
1116ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
1117646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
1118646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
1119646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
1120646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
1121646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
1122ec80fde7SArnaldo Carvalho de Melo 
1123d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
1124a1ac1d3cSStephane Eranian 		disable_buildid_cache();
1125655000e7SArnaldo Carvalho de Melo 
11263e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
11273e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
112869aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
112969aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
1130bbd36e5eSPeter Zijlstra 	}
113186470930SIngo Molnar 
113269e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
113369e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
113469e7e5b0SAdrian Hunter 
1135602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
113616ad2ffbSNamhyung Kim 	if (err) {
1137602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
113816ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
113916ad2ffbSNamhyung Kim 	}
11404bd0f2d2SNamhyung Kim 
1141602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
114216ad2ffbSNamhyung Kim 	if (err) {
114316ad2ffbSNamhyung Kim 		int saved_errno = errno;
114416ad2ffbSNamhyung Kim 
1145602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
11463780f488SNamhyung Kim 		ui__error("%s", errbuf);
114716ad2ffbSNamhyung Kim 
114816ad2ffbSNamhyung Kim 		err = -saved_errno;
11498fa60e1fSNamhyung Kim 		goto out_symbol_exit;
115016ad2ffbSNamhyung Kim 	}
11510d37aa34SArnaldo Carvalho de Melo 
115216ad2ffbSNamhyung Kim 	err = -ENOMEM;
11533e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
1154dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
115569aad6f1SArnaldo Carvalho de Melo 
1156ef149c25SAdrian Hunter 	err = auxtrace_record__options(rec->itr, rec->evlist, &rec->opts);
1157ef149c25SAdrian Hunter 	if (err)
1158ef149c25SAdrian Hunter 		goto out_symbol_exit;
1159ef149c25SAdrian Hunter 
1160b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
116139d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
116203ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
11637e4ff9e3SMike Galbraith 	}
11647e4ff9e3SMike Galbraith 
1165d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
1166d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
116745604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
1168d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
1169ef149c25SAdrian Hunter 	auxtrace_record__free(rec->itr);
117039d17dacSArnaldo Carvalho de Melo 	return err;
117186470930SIngo Molnar }
11722dd6d8a1SAdrian Hunter 
11732dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig __maybe_unused)
11742dd6d8a1SAdrian Hunter {
11752dd6d8a1SAdrian Hunter 	if (!auxtrace_snapshot_enabled)
11762dd6d8a1SAdrian Hunter 		return;
11772dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
11782dd6d8a1SAdrian Hunter 	auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
11792dd6d8a1SAdrian Hunter 	auxtrace_record__snapshot_started = 1;
11802dd6d8a1SAdrian Hunter }
1181