xref: /openbmc/linux/tools/perf/builtin-record.c (revision 8690a2a773703e4ad2a07a7f3912ea6b131307cc)
186470930SIngo Molnar /*
286470930SIngo Molnar  * builtin-record.c
386470930SIngo Molnar  *
486470930SIngo Molnar  * Builtin record command: Record the profile of a workload
586470930SIngo Molnar  * (or a CPU, or a PID) into the perf.data output file - for
686470930SIngo Molnar  * later analysis via perf report.
786470930SIngo Molnar  */
886470930SIngo Molnar #include "builtin.h"
986470930SIngo Molnar 
1086470930SIngo Molnar #include "perf.h"
1186470930SIngo Molnar 
126122e4e4SArnaldo Carvalho de Melo #include "util/build-id.h"
1386470930SIngo Molnar #include "util/util.h"
144b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h>
1586470930SIngo Molnar #include "util/parse-events.h"
1686470930SIngo Molnar 
178f651eaeSArnaldo Carvalho de Melo #include "util/callchain.h"
18f14d5707SArnaldo Carvalho de Melo #include "util/cgroup.h"
197c6a1c65SPeter Zijlstra #include "util/header.h"
2066e274f3SFrederic Weisbecker #include "util/event.h"
21361c99a6SArnaldo Carvalho de Melo #include "util/evlist.h"
2269aad6f1SArnaldo Carvalho de Melo #include "util/evsel.h"
238f28827aSFrederic Weisbecker #include "util/debug.h"
2494c744b6SArnaldo Carvalho de Melo #include "util/session.h"
2545694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
268d06367fSArnaldo Carvalho de Melo #include "util/symbol.h"
27a12b51c4SPaul Mackerras #include "util/cpumap.h"
28fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h"
29f5fc1412SJiri Olsa #include "util/data.h"
30bcc84ec6SStephane Eranian #include "util/perf_regs.h"
31ef149c25SAdrian Hunter #include "util/auxtrace.h"
32f00898f4SAndi Kleen #include "util/parse-branch-options.h"
33bcc84ec6SStephane Eranian #include "util/parse-regs-options.h"
3471dc2326SWang Nan #include "util/llvm-utils.h"
35*8690a2a7SWang Nan #include "util/bpf-loader.h"
367c6a1c65SPeter Zijlstra 
3786470930SIngo Molnar #include <unistd.h>
3886470930SIngo Molnar #include <sched.h>
39a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
4086470930SIngo Molnar 
4178da39faSBernhard Rosenkraenzer 
428c6f45a7SArnaldo Carvalho de Melo struct record {
4345694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
44b4006796SArnaldo Carvalho de Melo 	struct record_opts	opts;
45d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
46f5fc1412SJiri Olsa 	struct perf_data_file	file;
47ef149c25SAdrian Hunter 	struct auxtrace_record	*itr;
48d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
49d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
50d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
51d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
52d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
53d2db9a98SWang Nan 	bool			no_buildid_set;
54d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
55d2db9a98SWang Nan 	bool			no_buildid_cache_set;
566156681bSNamhyung Kim 	bool			buildid_all;
579f065194SYang Shi 	unsigned long long	samples;
580f82ebc4SArnaldo Carvalho de Melo };
5986470930SIngo Molnar 
608c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
61f5970550SPeter Zijlstra {
62cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
634f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
648d3eca20SDavid Ahern 		return -1;
658d3eca20SDavid Ahern 	}
66f5970550SPeter Zijlstra 
67cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
688d3eca20SDavid Ahern 	return 0;
69f5970550SPeter Zijlstra }
70f5970550SPeter Zijlstra 
7145694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
72d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
731d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
741d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
75234fbbf5SArnaldo Carvalho de Melo {
768c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
778c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
78234fbbf5SArnaldo Carvalho de Melo }
79234fbbf5SArnaldo Carvalho de Melo 
80e5685730SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, int idx)
8186470930SIngo Molnar {
82e5685730SArnaldo Carvalho de Melo 	struct perf_mmap *md = &rec->evlist->mmap[idx];
837b8283b5SDavid Ahern 	u64 head = perf_mmap__read_head(md);
847b8283b5SDavid Ahern 	u64 old = md->prev;
85918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
8686470930SIngo Molnar 	unsigned long size;
8786470930SIngo Molnar 	void *buf;
888d3eca20SDavid Ahern 	int rc = 0;
8986470930SIngo Molnar 
90dc82009aSArnaldo Carvalho de Melo 	if (old == head)
918d3eca20SDavid Ahern 		return 0;
9286470930SIngo Molnar 
93d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
9486470930SIngo Molnar 
9586470930SIngo Molnar 	size = head - old;
9686470930SIngo Molnar 
9786470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
9886470930SIngo Molnar 		buf = &data[old & md->mask];
9986470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
10086470930SIngo Molnar 		old += size;
10186470930SIngo Molnar 
1028c6f45a7SArnaldo Carvalho de Melo 		if (record__write(rec, buf, size) < 0) {
1038d3eca20SDavid Ahern 			rc = -1;
1048d3eca20SDavid Ahern 			goto out;
1058d3eca20SDavid Ahern 		}
10686470930SIngo Molnar 	}
10786470930SIngo Molnar 
10886470930SIngo Molnar 	buf = &data[old & md->mask];
10986470930SIngo Molnar 	size = head - old;
11086470930SIngo Molnar 	old += size;
11186470930SIngo Molnar 
1128c6f45a7SArnaldo Carvalho de Melo 	if (record__write(rec, buf, size) < 0) {
1138d3eca20SDavid Ahern 		rc = -1;
1148d3eca20SDavid Ahern 		goto out;
1158d3eca20SDavid Ahern 	}
11686470930SIngo Molnar 
11786470930SIngo Molnar 	md->prev = old;
118e5685730SArnaldo Carvalho de Melo 	perf_evlist__mmap_consume(rec->evlist, idx);
1198d3eca20SDavid Ahern out:
1208d3eca20SDavid Ahern 	return rc;
12186470930SIngo Molnar }
12286470930SIngo Molnar 
1232dd6d8a1SAdrian Hunter static volatile int done;
1242dd6d8a1SAdrian Hunter static volatile int signr = -1;
1252dd6d8a1SAdrian Hunter static volatile int child_finished;
1262dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_enabled;
1272dd6d8a1SAdrian Hunter static volatile int auxtrace_snapshot_err;
1282dd6d8a1SAdrian Hunter static volatile int auxtrace_record__snapshot_started;
1292dd6d8a1SAdrian Hunter 
1302dd6d8a1SAdrian Hunter static void sig_handler(int sig)
1312dd6d8a1SAdrian Hunter {
1322dd6d8a1SAdrian Hunter 	if (sig == SIGCHLD)
1332dd6d8a1SAdrian Hunter 		child_finished = 1;
1342dd6d8a1SAdrian Hunter 	else
1352dd6d8a1SAdrian Hunter 		signr = sig;
1362dd6d8a1SAdrian Hunter 
1372dd6d8a1SAdrian Hunter 	done = 1;
1382dd6d8a1SAdrian Hunter }
1392dd6d8a1SAdrian Hunter 
1402dd6d8a1SAdrian Hunter static void record__sig_exit(void)
1412dd6d8a1SAdrian Hunter {
1422dd6d8a1SAdrian Hunter 	if (signr == -1)
1432dd6d8a1SAdrian Hunter 		return;
1442dd6d8a1SAdrian Hunter 
1452dd6d8a1SAdrian Hunter 	signal(signr, SIG_DFL);
1462dd6d8a1SAdrian Hunter 	raise(signr);
1472dd6d8a1SAdrian Hunter }
1482dd6d8a1SAdrian Hunter 
149e31f0d01SAdrian Hunter #ifdef HAVE_AUXTRACE_SUPPORT
150e31f0d01SAdrian Hunter 
151ef149c25SAdrian Hunter static int record__process_auxtrace(struct perf_tool *tool,
152ef149c25SAdrian Hunter 				    union perf_event *event, void *data1,
153ef149c25SAdrian Hunter 				    size_t len1, void *data2, size_t len2)
154ef149c25SAdrian Hunter {
155ef149c25SAdrian Hunter 	struct record *rec = container_of(tool, struct record, tool);
15699fa2984SAdrian Hunter 	struct perf_data_file *file = &rec->file;
157ef149c25SAdrian Hunter 	size_t padding;
158ef149c25SAdrian Hunter 	u8 pad[8] = {0};
159ef149c25SAdrian Hunter 
16099fa2984SAdrian Hunter 	if (!perf_data_file__is_pipe(file)) {
16199fa2984SAdrian Hunter 		off_t file_offset;
16299fa2984SAdrian Hunter 		int fd = perf_data_file__fd(file);
16399fa2984SAdrian Hunter 		int err;
16499fa2984SAdrian Hunter 
16599fa2984SAdrian Hunter 		file_offset = lseek(fd, 0, SEEK_CUR);
16699fa2984SAdrian Hunter 		if (file_offset == -1)
16799fa2984SAdrian Hunter 			return -1;
16899fa2984SAdrian Hunter 		err = auxtrace_index__auxtrace_event(&rec->session->auxtrace_index,
16999fa2984SAdrian Hunter 						     event, file_offset);
17099fa2984SAdrian Hunter 		if (err)
17199fa2984SAdrian Hunter 			return err;
17299fa2984SAdrian Hunter 	}
17399fa2984SAdrian Hunter 
174ef149c25SAdrian Hunter 	/* event.auxtrace.size includes padding, see __auxtrace_mmap__read() */
175ef149c25SAdrian Hunter 	padding = (len1 + len2) & 7;
176ef149c25SAdrian Hunter 	if (padding)
177ef149c25SAdrian Hunter 		padding = 8 - padding;
178ef149c25SAdrian Hunter 
179ef149c25SAdrian Hunter 	record__write(rec, event, event->header.size);
180ef149c25SAdrian Hunter 	record__write(rec, data1, len1);
181ef149c25SAdrian Hunter 	if (len2)
182ef149c25SAdrian Hunter 		record__write(rec, data2, len2);
183ef149c25SAdrian Hunter 	record__write(rec, &pad, padding);
184ef149c25SAdrian Hunter 
185ef149c25SAdrian Hunter 	return 0;
186ef149c25SAdrian Hunter }
187ef149c25SAdrian Hunter 
188ef149c25SAdrian Hunter static int record__auxtrace_mmap_read(struct record *rec,
189ef149c25SAdrian Hunter 				      struct auxtrace_mmap *mm)
190ef149c25SAdrian Hunter {
191ef149c25SAdrian Hunter 	int ret;
192ef149c25SAdrian Hunter 
193ef149c25SAdrian Hunter 	ret = auxtrace_mmap__read(mm, rec->itr, &rec->tool,
194ef149c25SAdrian Hunter 				  record__process_auxtrace);
195ef149c25SAdrian Hunter 	if (ret < 0)
196ef149c25SAdrian Hunter 		return ret;
197ef149c25SAdrian Hunter 
198ef149c25SAdrian Hunter 	if (ret)
199ef149c25SAdrian Hunter 		rec->samples++;
200ef149c25SAdrian Hunter 
201ef149c25SAdrian Hunter 	return 0;
202ef149c25SAdrian Hunter }
203ef149c25SAdrian Hunter 
2042dd6d8a1SAdrian Hunter static int record__auxtrace_mmap_read_snapshot(struct record *rec,
2052dd6d8a1SAdrian Hunter 					       struct auxtrace_mmap *mm)
2062dd6d8a1SAdrian Hunter {
2072dd6d8a1SAdrian Hunter 	int ret;
2082dd6d8a1SAdrian Hunter 
2092dd6d8a1SAdrian Hunter 	ret = auxtrace_mmap__read_snapshot(mm, rec->itr, &rec->tool,
2102dd6d8a1SAdrian Hunter 					   record__process_auxtrace,
2112dd6d8a1SAdrian Hunter 					   rec->opts.auxtrace_snapshot_size);
2122dd6d8a1SAdrian Hunter 	if (ret < 0)
2132dd6d8a1SAdrian Hunter 		return ret;
2142dd6d8a1SAdrian Hunter 
2152dd6d8a1SAdrian Hunter 	if (ret)
2162dd6d8a1SAdrian Hunter 		rec->samples++;
2172dd6d8a1SAdrian Hunter 
2182dd6d8a1SAdrian Hunter 	return 0;
2192dd6d8a1SAdrian Hunter }
2202dd6d8a1SAdrian Hunter 
2212dd6d8a1SAdrian Hunter static int record__auxtrace_read_snapshot_all(struct record *rec)
2222dd6d8a1SAdrian Hunter {
2232dd6d8a1SAdrian Hunter 	int i;
2242dd6d8a1SAdrian Hunter 	int rc = 0;
2252dd6d8a1SAdrian Hunter 
2262dd6d8a1SAdrian Hunter 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
2272dd6d8a1SAdrian Hunter 		struct auxtrace_mmap *mm =
2282dd6d8a1SAdrian Hunter 				&rec->evlist->mmap[i].auxtrace_mmap;
2292dd6d8a1SAdrian Hunter 
2302dd6d8a1SAdrian Hunter 		if (!mm->base)
2312dd6d8a1SAdrian Hunter 			continue;
2322dd6d8a1SAdrian Hunter 
2332dd6d8a1SAdrian Hunter 		if (record__auxtrace_mmap_read_snapshot(rec, mm) != 0) {
2342dd6d8a1SAdrian Hunter 			rc = -1;
2352dd6d8a1SAdrian Hunter 			goto out;
2362dd6d8a1SAdrian Hunter 		}
2372dd6d8a1SAdrian Hunter 	}
2382dd6d8a1SAdrian Hunter out:
2392dd6d8a1SAdrian Hunter 	return rc;
2402dd6d8a1SAdrian Hunter }
2412dd6d8a1SAdrian Hunter 
2422dd6d8a1SAdrian Hunter static void record__read_auxtrace_snapshot(struct record *rec)
2432dd6d8a1SAdrian Hunter {
2442dd6d8a1SAdrian Hunter 	pr_debug("Recording AUX area tracing snapshot\n");
2452dd6d8a1SAdrian Hunter 	if (record__auxtrace_read_snapshot_all(rec) < 0) {
2462dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = -1;
2472dd6d8a1SAdrian Hunter 	} else {
2482dd6d8a1SAdrian Hunter 		auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr);
2492dd6d8a1SAdrian Hunter 		if (!auxtrace_snapshot_err)
2502dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 1;
2512dd6d8a1SAdrian Hunter 	}
2522dd6d8a1SAdrian Hunter }
2532dd6d8a1SAdrian Hunter 
254e31f0d01SAdrian Hunter #else
255e31f0d01SAdrian Hunter 
256e31f0d01SAdrian Hunter static inline
257e31f0d01SAdrian Hunter int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
258e31f0d01SAdrian Hunter 			       struct auxtrace_mmap *mm __maybe_unused)
259e31f0d01SAdrian Hunter {
260e31f0d01SAdrian Hunter 	return 0;
261e31f0d01SAdrian Hunter }
262e31f0d01SAdrian Hunter 
2632dd6d8a1SAdrian Hunter static inline
2642dd6d8a1SAdrian Hunter void record__read_auxtrace_snapshot(struct record *rec __maybe_unused)
2652dd6d8a1SAdrian Hunter {
2662dd6d8a1SAdrian Hunter }
2672dd6d8a1SAdrian Hunter 
2682dd6d8a1SAdrian Hunter static inline
2692dd6d8a1SAdrian Hunter int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused)
2702dd6d8a1SAdrian Hunter {
2712dd6d8a1SAdrian Hunter 	return 0;
2722dd6d8a1SAdrian Hunter }
2732dd6d8a1SAdrian Hunter 
274e31f0d01SAdrian Hunter #endif
275e31f0d01SAdrian Hunter 
2768c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
277dd7927f4SArnaldo Carvalho de Melo {
27856e52e85SArnaldo Carvalho de Melo 	char msg[512];
2796a4bb04cSJiri Olsa 	struct perf_evsel *pos;
280d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
281d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
282b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
2838d3eca20SDavid Ahern 	int rc = 0;
284dd7927f4SArnaldo Carvalho de Melo 
285f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
286cac21425SJiri Olsa 
2870050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
2883da297a6SIngo Molnar try_again:
289d988d5eeSKan Liang 		if (perf_evsel__open(pos, pos->cpus, pos->threads) < 0) {
29056e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2913da297a6SIngo Molnar 				if (verbose)
292c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2933da297a6SIngo Molnar 				goto try_again;
2943da297a6SIngo Molnar 			}
295ca6a4258SDavid Ahern 
29656e52e85SArnaldo Carvalho de Melo 			rc = -errno;
29756e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
29856e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
29956e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
3008d3eca20SDavid Ahern 			goto out;
3017c6a1c65SPeter Zijlstra 		}
3027c6a1c65SPeter Zijlstra 	}
3037c6a1c65SPeter Zijlstra 
30423d4aad4SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist, &pos)) {
30523d4aad4SArnaldo Carvalho de Melo 		error("failed to set filter \"%s\" on event %s with %d (%s)\n",
30623d4aad4SArnaldo Carvalho de Melo 			pos->filter, perf_evsel__name(pos), errno,
30735550da3SMasami Hiramatsu 			strerror_r(errno, msg, sizeof(msg)));
3088d3eca20SDavid Ahern 		rc = -1;
3098d3eca20SDavid Ahern 		goto out;
3100a102479SFrederic Weisbecker 	}
3110a102479SFrederic Weisbecker 
312ef149c25SAdrian Hunter 	if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
3132dd6d8a1SAdrian Hunter 				 opts->auxtrace_mmap_pages,
3142dd6d8a1SAdrian Hunter 				 opts->auxtrace_snapshot_mode) < 0) {
3158d3eca20SDavid Ahern 		if (errno == EPERM) {
3168d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
31718e60939SNelson Elhage 			       "Consider increasing "
31818e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
31918e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
320ef149c25SAdrian Hunter 			       "(current value: %u,%u)\n",
321ef149c25SAdrian Hunter 			       opts->mmap_pages, opts->auxtrace_mmap_pages);
3228d3eca20SDavid Ahern 			rc = -errno;
3238d3eca20SDavid Ahern 		} else {
32435550da3SMasami Hiramatsu 			pr_err("failed to mmap with %d (%s)\n", errno,
32535550da3SMasami Hiramatsu 				strerror_r(errno, msg, sizeof(msg)));
3268d3eca20SDavid Ahern 			rc = -errno;
3278d3eca20SDavid Ahern 		}
3288d3eca20SDavid Ahern 		goto out;
32918e60939SNelson Elhage 	}
3300a27d7f9SArnaldo Carvalho de Melo 
331a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
3327b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
3338d3eca20SDavid Ahern out:
3348d3eca20SDavid Ahern 	return rc;
335a91e5431SArnaldo Carvalho de Melo }
336a91e5431SArnaldo Carvalho de Melo 
337e3d59112SNamhyung Kim static int process_sample_event(struct perf_tool *tool,
338e3d59112SNamhyung Kim 				union perf_event *event,
339e3d59112SNamhyung Kim 				struct perf_sample *sample,
340e3d59112SNamhyung Kim 				struct perf_evsel *evsel,
341e3d59112SNamhyung Kim 				struct machine *machine)
342e3d59112SNamhyung Kim {
343e3d59112SNamhyung Kim 	struct record *rec = container_of(tool, struct record, tool);
344e3d59112SNamhyung Kim 
345e3d59112SNamhyung Kim 	rec->samples++;
346e3d59112SNamhyung Kim 
347e3d59112SNamhyung Kim 	return build_id__mark_dso_hit(tool, event, sample, evsel, machine);
348e3d59112SNamhyung Kim }
349e3d59112SNamhyung Kim 
3508c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
3516122e4e4SArnaldo Carvalho de Melo {
352f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
353f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
3546122e4e4SArnaldo Carvalho de Melo 
355457ae94aSHe Kuang 	if (file->size == 0)
3569f591fd7SArnaldo Carvalho de Melo 		return 0;
3579f591fd7SArnaldo Carvalho de Melo 
35800dc8657SNamhyung Kim 	/*
35900dc8657SNamhyung Kim 	 * During this process, it'll load kernel map and replace the
36000dc8657SNamhyung Kim 	 * dso->long_name to a real pathname it found.  In this case
36100dc8657SNamhyung Kim 	 * we prefer the vmlinux path like
36200dc8657SNamhyung Kim 	 *   /lib/modules/3.16.4/build/vmlinux
36300dc8657SNamhyung Kim 	 *
36400dc8657SNamhyung Kim 	 * rather than build-id path (in debug directory).
36500dc8657SNamhyung Kim 	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
36600dc8657SNamhyung Kim 	 */
36700dc8657SNamhyung Kim 	symbol_conf.ignore_vmlinux_buildid = true;
36800dc8657SNamhyung Kim 
3696156681bSNamhyung Kim 	/*
3706156681bSNamhyung Kim 	 * If --buildid-all is given, it marks all DSO regardless of hits,
3716156681bSNamhyung Kim 	 * so no need to process samples.
3726156681bSNamhyung Kim 	 */
3736156681bSNamhyung Kim 	if (rec->buildid_all)
3746156681bSNamhyung Kim 		rec->tool.sample = NULL;
3756156681bSNamhyung Kim 
376b7b61cbeSArnaldo Carvalho de Melo 	return perf_session__process_events(session);
3776122e4e4SArnaldo Carvalho de Melo }
3786122e4e4SArnaldo Carvalho de Melo 
3798115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
380a1645ce1SZhang, Yanmin {
381a1645ce1SZhang, Yanmin 	int err;
38245694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
383a1645ce1SZhang, Yanmin 	/*
384a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
385a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
386a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
387a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
388a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
389a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
390a1645ce1SZhang, Yanmin 	 */
39145694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
392743eb868SArnaldo Carvalho de Melo 					     machine);
393a1645ce1SZhang, Yanmin 	if (err < 0)
394a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
39523346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
396a1645ce1SZhang, Yanmin 
397a1645ce1SZhang, Yanmin 	/*
398a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
399a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
400a1645ce1SZhang, Yanmin 	 */
40145694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
4020ae617beSAdrian Hunter 						 machine);
403a1645ce1SZhang, Yanmin 	if (err < 0)
404a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
40523346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
406a1645ce1SZhang, Yanmin }
407a1645ce1SZhang, Yanmin 
40898402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
40998402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
41098402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
41198402807SFrederic Weisbecker };
41298402807SFrederic Weisbecker 
4138c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
41498402807SFrederic Weisbecker {
415dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
4160e2e63ddSPeter Zijlstra 	int i;
4178d3eca20SDavid Ahern 	int rc = 0;
41898402807SFrederic Weisbecker 
419d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
420ef149c25SAdrian Hunter 		struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap;
421ef149c25SAdrian Hunter 
4228d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
423e5685730SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, i) != 0) {
4248d3eca20SDavid Ahern 				rc = -1;
4258d3eca20SDavid Ahern 				goto out;
4268d3eca20SDavid Ahern 			}
4278d3eca20SDavid Ahern 		}
428ef149c25SAdrian Hunter 
4292dd6d8a1SAdrian Hunter 		if (mm->base && !rec->opts.auxtrace_snapshot_mode &&
430ef149c25SAdrian Hunter 		    record__auxtrace_mmap_read(rec, mm) != 0) {
431ef149c25SAdrian Hunter 			rc = -1;
432ef149c25SAdrian Hunter 			goto out;
433ef149c25SAdrian Hunter 		}
43498402807SFrederic Weisbecker 	}
43598402807SFrederic Weisbecker 
436dcabb507SJiri Olsa 	/*
437dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
438dcabb507SJiri Olsa 	 * at least one event.
439dcabb507SJiri Olsa 	 */
440dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
4418c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
4428d3eca20SDavid Ahern 
4438d3eca20SDavid Ahern out:
4448d3eca20SDavid Ahern 	return rc;
44598402807SFrederic Weisbecker }
44698402807SFrederic Weisbecker 
4478c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
44857706abcSDavid Ahern {
44957706abcSDavid Ahern 	struct perf_session *session = rec->session;
45057706abcSDavid Ahern 	int feat;
45157706abcSDavid Ahern 
45257706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
45357706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
45457706abcSDavid Ahern 
45557706abcSDavid Ahern 	if (rec->no_buildid)
45657706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
45757706abcSDavid Ahern 
4583e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
45957706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
46057706abcSDavid Ahern 
46157706abcSDavid Ahern 	if (!rec->opts.branch_stack)
46257706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
463ef149c25SAdrian Hunter 
464ef149c25SAdrian Hunter 	if (!rec->opts.full_auxtrace)
465ef149c25SAdrian Hunter 		perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
466ffa517adSJiri Olsa 
467ffa517adSJiri Olsa 	perf_header__clear_feat(&session->header, HEADER_STAT);
46857706abcSDavid Ahern }
46957706abcSDavid Ahern 
470f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
471f33cbe72SArnaldo Carvalho de Melo 
472f33cbe72SArnaldo Carvalho de Melo /*
473f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
474f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
475f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
476f33cbe72SArnaldo Carvalho de Melo  */
47745604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
47845604710SNamhyung Kim 					siginfo_t *info,
479f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
480f33cbe72SArnaldo Carvalho de Melo {
481f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
482f33cbe72SArnaldo Carvalho de Melo 	done = 1;
483f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
484f33cbe72SArnaldo Carvalho de Melo }
485f33cbe72SArnaldo Carvalho de Melo 
4862dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig);
4872dd6d8a1SAdrian Hunter 
4888c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
48986470930SIngo Molnar {
49057706abcSDavid Ahern 	int err;
49145604710SNamhyung Kim 	int status = 0;
4928b412664SPeter Zijlstra 	unsigned long waking = 0;
49346be604bSZhang, Yanmin 	const bool forks = argc > 0;
49423346f21SArnaldo Carvalho de Melo 	struct machine *machine;
49545694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
496b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
497f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
498d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
4996dcf45efSArnaldo Carvalho de Melo 	bool disabled = false, draining = false;
50042aa276fSNamhyung Kim 	int fd;
50186470930SIngo Molnar 
502d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
50333e49ea7SAndi Kleen 
50445604710SNamhyung Kim 	atexit(record__sig_exit);
505f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
506f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
507804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
5082dd6d8a1SAdrian Hunter 	if (rec->opts.auxtrace_snapshot_mode)
5092dd6d8a1SAdrian Hunter 		signal(SIGUSR2, snapshot_sig_handler);
5102dd6d8a1SAdrian Hunter 	else
5112dd6d8a1SAdrian Hunter 		signal(SIGUSR2, SIG_IGN);
512f5970550SPeter Zijlstra 
513b7b61cbeSArnaldo Carvalho de Melo 	session = perf_session__new(file, false, tool);
51494c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
515ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
516a9a70bbcSArnaldo Carvalho de Melo 		return -1;
517a9a70bbcSArnaldo Carvalho de Melo 	}
518a9a70bbcSArnaldo Carvalho de Melo 
51942aa276fSNamhyung Kim 	fd = perf_data_file__fd(file);
520d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
521d20deb64SArnaldo Carvalho de Melo 
5228c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
523330aa675SStephane Eranian 
524d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
5253e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
526f5fc1412SJiri Olsa 						    argv, file->is_pipe,
527735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
52835b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
52935b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
53045604710SNamhyung Kim 			status = err;
53135b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
532856e9660SPeter Zijlstra 		}
533856e9660SPeter Zijlstra 	}
534856e9660SPeter Zijlstra 
5358c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
5368d3eca20SDavid Ahern 		err = -1;
53745604710SNamhyung Kim 		goto out_child;
5388d3eca20SDavid Ahern 	}
53986470930SIngo Molnar 
540*8690a2a7SWang Nan 	err = bpf__apply_obj_config();
541*8690a2a7SWang Nan 	if (err) {
542*8690a2a7SWang Nan 		char errbuf[BUFSIZ];
543*8690a2a7SWang Nan 
544*8690a2a7SWang Nan 		bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
545*8690a2a7SWang Nan 		pr_err("ERROR: Apply config to BPF failed: %s\n",
546*8690a2a7SWang Nan 			 errbuf);
547*8690a2a7SWang Nan 		goto out_child;
548*8690a2a7SWang Nan 	}
549*8690a2a7SWang Nan 
550cca8482cSAdrian Hunter 	/*
551cca8482cSAdrian Hunter 	 * Normally perf_session__new would do this, but it doesn't have the
552cca8482cSAdrian Hunter 	 * evlist.
553cca8482cSAdrian Hunter 	 */
554cca8482cSAdrian Hunter 	if (rec->tool.ordered_events && !perf_evlist__sample_id_all(rec->evlist)) {
555cca8482cSAdrian Hunter 		pr_warning("WARNING: No sample_id_all support, falling back to unordered processing\n");
556cca8482cSAdrian Hunter 		rec->tool.ordered_events = false;
557cca8482cSAdrian Hunter 	}
558cca8482cSAdrian Hunter 
5593e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
560a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
561a8bb559bSNamhyung Kim 
562f5fc1412SJiri Olsa 	if (file->is_pipe) {
56342aa276fSNamhyung Kim 		err = perf_header__write_pipe(fd);
564529870e3STom Zanussi 		if (err < 0)
56545604710SNamhyung Kim 			goto out_child;
566563aecb2SJiri Olsa 	} else {
56742aa276fSNamhyung Kim 		err = perf_session__write_header(session, rec->evlist, fd, false);
568d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
56945604710SNamhyung Kim 			goto out_child;
570d5eed904SArnaldo Carvalho de Melo 	}
5717c6a1c65SPeter Zijlstra 
572d3665498SDavid Ahern 	if (!rec->no_buildid
573e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
574d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
575e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
5768d3eca20SDavid Ahern 		err = -1;
57745604710SNamhyung Kim 		goto out_child;
578e20960c0SRobert Richter 	}
579e20960c0SRobert Richter 
58034ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
581743eb868SArnaldo Carvalho de Melo 
582f5fc1412SJiri Olsa 	if (file->is_pipe) {
58345694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
584a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
5852c46dbb5STom Zanussi 		if (err < 0) {
5862c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
58745604710SNamhyung Kim 			goto out_child;
5882c46dbb5STom Zanussi 		}
589cd19a035STom Zanussi 
5903e2be2daSArnaldo Carvalho de Melo 		if (have_tracepoints(&rec->evlist->entries)) {
59163e0c771STom Zanussi 			/*
59263e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
59363e0c771STom Zanussi 			 * there were no tracepoints so its not really
59463e0c771STom Zanussi 			 * an error, just that we don't need to
59563e0c771STom Zanussi 			 * synthesize anything.  We really have to
59663e0c771STom Zanussi 			 * return this more properly and also
59763e0c771STom Zanussi 			 * propagate errors that now are calling die()
59863e0c771STom Zanussi 			 */
59942aa276fSNamhyung Kim 			err = perf_event__synthesize_tracing_data(tool,	fd, rec->evlist,
600743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
60163e0c771STom Zanussi 			if (err <= 0) {
60263e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
60345604710SNamhyung Kim 				goto out_child;
60463e0c771STom Zanussi 			}
605f34b9001SDavid Ahern 			rec->bytes_written += err;
6062c46dbb5STom Zanussi 		}
60763e0c771STom Zanussi 	}
6082c46dbb5STom Zanussi 
609ef149c25SAdrian Hunter 	if (rec->opts.full_auxtrace) {
610ef149c25SAdrian Hunter 		err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
611ef149c25SAdrian Hunter 					session, process_synthesized_event);
612ef149c25SAdrian Hunter 		if (err)
613ef149c25SAdrian Hunter 			goto out_delete_session;
614ef149c25SAdrian Hunter 	}
615ef149c25SAdrian Hunter 
61645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
6170ae617beSAdrian Hunter 						 machine);
618c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
619c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
620c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
621c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
62256b03f3cSArnaldo Carvalho de Melo 
62345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
624743eb868SArnaldo Carvalho de Melo 					     machine);
625c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
626c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
627c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
628c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
629c1a3a4b9SArnaldo Carvalho de Melo 
6307e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
631876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
6327e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
6337e383de4SArnaldo Carvalho de Melo 	}
634b7cece76SArnaldo Carvalho de Melo 
6353e2be2daSArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
6369d9cad76SKan Liang 					    process_synthesized_event, opts->sample_address,
6379d9cad76SKan Liang 					    opts->proc_map_timeout);
6388d3eca20SDavid Ahern 	if (err != 0)
63945604710SNamhyung Kim 		goto out_child;
6408d3eca20SDavid Ahern 
641d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
64286470930SIngo Molnar 		struct sched_param param;
64386470930SIngo Molnar 
644d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
64586470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
6466beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
6478d3eca20SDavid Ahern 			err = -1;
64845604710SNamhyung Kim 			goto out_child;
64986470930SIngo Molnar 		}
65086470930SIngo Molnar 	}
65186470930SIngo Molnar 
652774cb499SJiri Olsa 	/*
653774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
654774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
655774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
656774cb499SJiri Olsa 	 */
6576619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
6583e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
659764e16a3SDavid Ahern 
660856e9660SPeter Zijlstra 	/*
661856e9660SPeter Zijlstra 	 * Let the child rip
662856e9660SPeter Zijlstra 	 */
663e803cf97SNamhyung Kim 	if (forks) {
664e5bed564SNamhyung Kim 		union perf_event *event;
665e5bed564SNamhyung Kim 
666e5bed564SNamhyung Kim 		event = malloc(sizeof(event->comm) + machine->id_hdr_size);
667e5bed564SNamhyung Kim 		if (event == NULL) {
668e5bed564SNamhyung Kim 			err = -ENOMEM;
669e5bed564SNamhyung Kim 			goto out_child;
670e5bed564SNamhyung Kim 		}
671e5bed564SNamhyung Kim 
672e803cf97SNamhyung Kim 		/*
673e803cf97SNamhyung Kim 		 * Some H/W events are generated before COMM event
674e803cf97SNamhyung Kim 		 * which is emitted during exec(), so perf script
675e803cf97SNamhyung Kim 		 * cannot see a correct process name for those events.
676e803cf97SNamhyung Kim 		 * Synthesize COMM event to prevent it.
677e803cf97SNamhyung Kim 		 */
678e5bed564SNamhyung Kim 		perf_event__synthesize_comm(tool, event,
679e803cf97SNamhyung Kim 					    rec->evlist->workload.pid,
680e803cf97SNamhyung Kim 					    process_synthesized_event,
681e803cf97SNamhyung Kim 					    machine);
682e5bed564SNamhyung Kim 		free(event);
683e803cf97SNamhyung Kim 
6843e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
685e803cf97SNamhyung Kim 	}
686856e9660SPeter Zijlstra 
6876619a53eSAndi Kleen 	if (opts->initial_delay) {
6886619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
6896619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
6906619a53eSAndi Kleen 	}
6916619a53eSAndi Kleen 
6922dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 1;
693649c48a9SPeter Zijlstra 	for (;;) {
6949f065194SYang Shi 		unsigned long long hits = rec->samples;
69586470930SIngo Molnar 
6968c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
6972dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
6988d3eca20SDavid Ahern 			err = -1;
69945604710SNamhyung Kim 			goto out_child;
7008d3eca20SDavid Ahern 		}
70186470930SIngo Molnar 
7022dd6d8a1SAdrian Hunter 		if (auxtrace_record__snapshot_started) {
7032dd6d8a1SAdrian Hunter 			auxtrace_record__snapshot_started = 0;
7042dd6d8a1SAdrian Hunter 			if (!auxtrace_snapshot_err)
7052dd6d8a1SAdrian Hunter 				record__read_auxtrace_snapshot(rec);
7062dd6d8a1SAdrian Hunter 			if (auxtrace_snapshot_err) {
7072dd6d8a1SAdrian Hunter 				pr_err("AUX area tracing snapshot failed\n");
7082dd6d8a1SAdrian Hunter 				err = -1;
7092dd6d8a1SAdrian Hunter 				goto out_child;
7102dd6d8a1SAdrian Hunter 			}
7112dd6d8a1SAdrian Hunter 		}
7122dd6d8a1SAdrian Hunter 
713d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
7146dcf45efSArnaldo Carvalho de Melo 			if (done || draining)
715649c48a9SPeter Zijlstra 				break;
716f66a889dSArnaldo Carvalho de Melo 			err = perf_evlist__poll(rec->evlist, -1);
717a515114fSJiri Olsa 			/*
718a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
719a515114fSJiri Olsa 			 * number of returned events and interrupt error.
720a515114fSJiri Olsa 			 */
721a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
72245604710SNamhyung Kim 				err = 0;
7238b412664SPeter Zijlstra 			waking++;
7246dcf45efSArnaldo Carvalho de Melo 
7256dcf45efSArnaldo Carvalho de Melo 			if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
7266dcf45efSArnaldo Carvalho de Melo 				draining = true;
7278b412664SPeter Zijlstra 		}
7288b412664SPeter Zijlstra 
729774cb499SJiri Olsa 		/*
730774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
731774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
732774cb499SJiri Olsa 		 * disable events in this case.
733774cb499SJiri Olsa 		 */
734602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
7352dd6d8a1SAdrian Hunter 			auxtrace_snapshot_enabled = 0;
7363e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
7372711926aSJiri Olsa 			disabled = true;
7382711926aSJiri Olsa 		}
7398b412664SPeter Zijlstra 	}
7402dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
7418b412664SPeter Zijlstra 
742f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
74335550da3SMasami Hiramatsu 		char msg[STRERR_BUFSIZE];
744f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
745f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
746f33cbe72SArnaldo Carvalho de Melo 		err = -1;
74745604710SNamhyung Kim 		goto out_child;
748f33cbe72SArnaldo Carvalho de Melo 	}
749f33cbe72SArnaldo Carvalho de Melo 
750e3d59112SNamhyung Kim 	if (!quiet)
7518b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
75286470930SIngo Molnar 
75345604710SNamhyung Kim out_child:
75445604710SNamhyung Kim 	if (forks) {
75545604710SNamhyung Kim 		int exit_status;
75645604710SNamhyung Kim 
75745604710SNamhyung Kim 		if (!child_finished)
75845604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
75945604710SNamhyung Kim 
76045604710SNamhyung Kim 		wait(&exit_status);
76145604710SNamhyung Kim 
76245604710SNamhyung Kim 		if (err < 0)
76345604710SNamhyung Kim 			status = err;
76445604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
76545604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
76645604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
76745604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
76845604710SNamhyung Kim 	} else
76945604710SNamhyung Kim 		status = err;
77045604710SNamhyung Kim 
771e3d59112SNamhyung Kim 	/* this will be recalculated during process_buildids() */
772e3d59112SNamhyung Kim 	rec->samples = 0;
773e3d59112SNamhyung Kim 
77445604710SNamhyung Kim 	if (!err && !file->is_pipe) {
77545604710SNamhyung Kim 		rec->session->header.data_size += rec->bytes_written;
776457ae94aSHe Kuang 		file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
77745604710SNamhyung Kim 
778cd10b289SAdrian Hunter 		if (!rec->no_buildid) {
77945604710SNamhyung Kim 			process_buildids(rec);
7806156681bSNamhyung Kim 
7816156681bSNamhyung Kim 			if (rec->buildid_all)
782cd10b289SAdrian Hunter 				dsos__hit_all(rec->session);
783cd10b289SAdrian Hunter 		}
78442aa276fSNamhyung Kim 		perf_session__write_header(rec->session, rec->evlist, fd, true);
78545604710SNamhyung Kim 	}
78639d17dacSArnaldo Carvalho de Melo 
787e3d59112SNamhyung Kim 	if (!err && !quiet) {
788e3d59112SNamhyung Kim 		char samples[128];
789e3d59112SNamhyung Kim 
790ef149c25SAdrian Hunter 		if (rec->samples && !rec->opts.full_auxtrace)
791e3d59112SNamhyung Kim 			scnprintf(samples, sizeof(samples),
792e3d59112SNamhyung Kim 				  " (%" PRIu64 " samples)", rec->samples);
793e3d59112SNamhyung Kim 		else
794e3d59112SNamhyung Kim 			samples[0] = '\0';
795e3d59112SNamhyung Kim 
796e3d59112SNamhyung Kim 		fprintf(stderr,	"[ perf record: Captured and wrote %.3f MB %s%s ]\n",
797e3d59112SNamhyung Kim 			perf_data_file__size(file) / 1024.0 / 1024.0,
798e3d59112SNamhyung Kim 			file->path, samples);
799e3d59112SNamhyung Kim 	}
800e3d59112SNamhyung Kim 
80139d17dacSArnaldo Carvalho de Melo out_delete_session:
80239d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
80345604710SNamhyung Kim 	return status;
80486470930SIngo Molnar }
80586470930SIngo Molnar 
80672a128aaSNamhyung Kim static void callchain_debug(void)
80709b0fd45SJiri Olsa {
808aad2b21cSKan Liang 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" };
809a601fdffSJiri Olsa 
81072a128aaSNamhyung Kim 	pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
81126d33022SJiri Olsa 
81272a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_DWARF)
81309b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
81472a128aaSNamhyung Kim 			 callchain_param.dump_size);
81509b0fd45SJiri Olsa }
81609b0fd45SJiri Olsa 
817c421e80bSKan Liang int record_parse_callchain_opt(const struct option *opt,
81809b0fd45SJiri Olsa 			       const char *arg,
81909b0fd45SJiri Olsa 			       int unset)
82009b0fd45SJiri Olsa {
82109b0fd45SJiri Olsa 	int ret;
822c421e80bSKan Liang 	struct record_opts *record = (struct record_opts *)opt->value;
82309b0fd45SJiri Olsa 
824c421e80bSKan Liang 	record->callgraph_set = true;
82572a128aaSNamhyung Kim 	callchain_param.enabled = !unset;
826eb853e80SJiri Olsa 
82709b0fd45SJiri Olsa 	/* --no-call-graph */
82809b0fd45SJiri Olsa 	if (unset) {
82972a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_NONE;
83009b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
83109b0fd45SJiri Olsa 		return 0;
83209b0fd45SJiri Olsa 	}
83309b0fd45SJiri Olsa 
834c3a6a8c4SKan Liang 	ret = parse_callchain_record_opt(arg, &callchain_param);
8355c0cf224SJiri Olsa 	if (!ret) {
8365c0cf224SJiri Olsa 		/* Enable data address sampling for DWARF unwind. */
8375c0cf224SJiri Olsa 		if (callchain_param.record_mode == CALLCHAIN_DWARF)
8385c0cf224SJiri Olsa 			record->sample_address = true;
83972a128aaSNamhyung Kim 		callchain_debug();
8405c0cf224SJiri Olsa 	}
84109b0fd45SJiri Olsa 
84226d33022SJiri Olsa 	return ret;
84326d33022SJiri Olsa }
84426d33022SJiri Olsa 
845c421e80bSKan Liang int record_callchain_opt(const struct option *opt,
84609b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
84709b0fd45SJiri Olsa 			 int unset __maybe_unused)
84809b0fd45SJiri Olsa {
849c421e80bSKan Liang 	struct record_opts *record = (struct record_opts *)opt->value;
850c421e80bSKan Liang 
851c421e80bSKan Liang 	record->callgraph_set = true;
85272a128aaSNamhyung Kim 	callchain_param.enabled = true;
85309b0fd45SJiri Olsa 
85472a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_NONE)
85572a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_FP;
856eb853e80SJiri Olsa 
85772a128aaSNamhyung Kim 	callchain_debug();
85809b0fd45SJiri Olsa 	return 0;
85909b0fd45SJiri Olsa }
86009b0fd45SJiri Olsa 
861eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
862eb853e80SJiri Olsa {
8637a29c087SNamhyung Kim 	struct record *rec = cb;
8647a29c087SNamhyung Kim 
8657a29c087SNamhyung Kim 	if (!strcmp(var, "record.build-id")) {
8667a29c087SNamhyung Kim 		if (!strcmp(value, "cache"))
8677a29c087SNamhyung Kim 			rec->no_buildid_cache = false;
8687a29c087SNamhyung Kim 		else if (!strcmp(value, "no-cache"))
8697a29c087SNamhyung Kim 			rec->no_buildid_cache = true;
8707a29c087SNamhyung Kim 		else if (!strcmp(value, "skip"))
8717a29c087SNamhyung Kim 			rec->no_buildid = true;
8727a29c087SNamhyung Kim 		else
8737a29c087SNamhyung Kim 			return -1;
8747a29c087SNamhyung Kim 		return 0;
8757a29c087SNamhyung Kim 	}
876eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
8775a2e5e85SNamhyung Kim 		var = "call-graph.record-mode"; /* fall-through */
878eb853e80SJiri Olsa 
879eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
880eb853e80SJiri Olsa }
881eb853e80SJiri Olsa 
882814c8c38SPeter Zijlstra struct clockid_map {
883814c8c38SPeter Zijlstra 	const char *name;
884814c8c38SPeter Zijlstra 	int clockid;
885814c8c38SPeter Zijlstra };
886814c8c38SPeter Zijlstra 
887814c8c38SPeter Zijlstra #define CLOCKID_MAP(n, c)	\
888814c8c38SPeter Zijlstra 	{ .name = n, .clockid = (c), }
889814c8c38SPeter Zijlstra 
890814c8c38SPeter Zijlstra #define CLOCKID_END	{ .name = NULL, }
891814c8c38SPeter Zijlstra 
892814c8c38SPeter Zijlstra 
893814c8c38SPeter Zijlstra /*
894814c8c38SPeter Zijlstra  * Add the missing ones, we need to build on many distros...
895814c8c38SPeter Zijlstra  */
896814c8c38SPeter Zijlstra #ifndef CLOCK_MONOTONIC_RAW
897814c8c38SPeter Zijlstra #define CLOCK_MONOTONIC_RAW 4
898814c8c38SPeter Zijlstra #endif
899814c8c38SPeter Zijlstra #ifndef CLOCK_BOOTTIME
900814c8c38SPeter Zijlstra #define CLOCK_BOOTTIME 7
901814c8c38SPeter Zijlstra #endif
902814c8c38SPeter Zijlstra #ifndef CLOCK_TAI
903814c8c38SPeter Zijlstra #define CLOCK_TAI 11
904814c8c38SPeter Zijlstra #endif
905814c8c38SPeter Zijlstra 
906814c8c38SPeter Zijlstra static const struct clockid_map clockids[] = {
907814c8c38SPeter Zijlstra 	/* available for all events, NMI safe */
908814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic", CLOCK_MONOTONIC),
909814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW),
910814c8c38SPeter Zijlstra 
911814c8c38SPeter Zijlstra 	/* available for some events */
912814c8c38SPeter Zijlstra 	CLOCKID_MAP("realtime", CLOCK_REALTIME),
913814c8c38SPeter Zijlstra 	CLOCKID_MAP("boottime", CLOCK_BOOTTIME),
914814c8c38SPeter Zijlstra 	CLOCKID_MAP("tai", CLOCK_TAI),
915814c8c38SPeter Zijlstra 
916814c8c38SPeter Zijlstra 	/* available for the lazy */
917814c8c38SPeter Zijlstra 	CLOCKID_MAP("mono", CLOCK_MONOTONIC),
918814c8c38SPeter Zijlstra 	CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW),
919814c8c38SPeter Zijlstra 	CLOCKID_MAP("real", CLOCK_REALTIME),
920814c8c38SPeter Zijlstra 	CLOCKID_MAP("boot", CLOCK_BOOTTIME),
921814c8c38SPeter Zijlstra 
922814c8c38SPeter Zijlstra 	CLOCKID_END,
923814c8c38SPeter Zijlstra };
924814c8c38SPeter Zijlstra 
925814c8c38SPeter Zijlstra static int parse_clockid(const struct option *opt, const char *str, int unset)
926814c8c38SPeter Zijlstra {
927814c8c38SPeter Zijlstra 	struct record_opts *opts = (struct record_opts *)opt->value;
928814c8c38SPeter Zijlstra 	const struct clockid_map *cm;
929814c8c38SPeter Zijlstra 	const char *ostr = str;
930814c8c38SPeter Zijlstra 
931814c8c38SPeter Zijlstra 	if (unset) {
932814c8c38SPeter Zijlstra 		opts->use_clockid = 0;
933814c8c38SPeter Zijlstra 		return 0;
934814c8c38SPeter Zijlstra 	}
935814c8c38SPeter Zijlstra 
936814c8c38SPeter Zijlstra 	/* no arg passed */
937814c8c38SPeter Zijlstra 	if (!str)
938814c8c38SPeter Zijlstra 		return 0;
939814c8c38SPeter Zijlstra 
940814c8c38SPeter Zijlstra 	/* no setting it twice */
941814c8c38SPeter Zijlstra 	if (opts->use_clockid)
942814c8c38SPeter Zijlstra 		return -1;
943814c8c38SPeter Zijlstra 
944814c8c38SPeter Zijlstra 	opts->use_clockid = true;
945814c8c38SPeter Zijlstra 
946814c8c38SPeter Zijlstra 	/* if its a number, we're done */
947814c8c38SPeter Zijlstra 	if (sscanf(str, "%d", &opts->clockid) == 1)
948814c8c38SPeter Zijlstra 		return 0;
949814c8c38SPeter Zijlstra 
950814c8c38SPeter Zijlstra 	/* allow a "CLOCK_" prefix to the name */
951814c8c38SPeter Zijlstra 	if (!strncasecmp(str, "CLOCK_", 6))
952814c8c38SPeter Zijlstra 		str += 6;
953814c8c38SPeter Zijlstra 
954814c8c38SPeter Zijlstra 	for (cm = clockids; cm->name; cm++) {
955814c8c38SPeter Zijlstra 		if (!strcasecmp(str, cm->name)) {
956814c8c38SPeter Zijlstra 			opts->clockid = cm->clockid;
957814c8c38SPeter Zijlstra 			return 0;
958814c8c38SPeter Zijlstra 		}
959814c8c38SPeter Zijlstra 	}
960814c8c38SPeter Zijlstra 
961814c8c38SPeter Zijlstra 	opts->use_clockid = false;
962814c8c38SPeter Zijlstra 	ui__warning("unknown clockid %s, check man page\n", ostr);
963814c8c38SPeter Zijlstra 	return -1;
964814c8c38SPeter Zijlstra }
965814c8c38SPeter Zijlstra 
966e9db1310SAdrian Hunter static int record__parse_mmap_pages(const struct option *opt,
967e9db1310SAdrian Hunter 				    const char *str,
968e9db1310SAdrian Hunter 				    int unset __maybe_unused)
969e9db1310SAdrian Hunter {
970e9db1310SAdrian Hunter 	struct record_opts *opts = opt->value;
971e9db1310SAdrian Hunter 	char *s, *p;
972e9db1310SAdrian Hunter 	unsigned int mmap_pages;
973e9db1310SAdrian Hunter 	int ret;
974e9db1310SAdrian Hunter 
975e9db1310SAdrian Hunter 	if (!str)
976e9db1310SAdrian Hunter 		return -EINVAL;
977e9db1310SAdrian Hunter 
978e9db1310SAdrian Hunter 	s = strdup(str);
979e9db1310SAdrian Hunter 	if (!s)
980e9db1310SAdrian Hunter 		return -ENOMEM;
981e9db1310SAdrian Hunter 
982e9db1310SAdrian Hunter 	p = strchr(s, ',');
983e9db1310SAdrian Hunter 	if (p)
984e9db1310SAdrian Hunter 		*p = '\0';
985e9db1310SAdrian Hunter 
986e9db1310SAdrian Hunter 	if (*s) {
987e9db1310SAdrian Hunter 		ret = __perf_evlist__parse_mmap_pages(&mmap_pages, s);
988e9db1310SAdrian Hunter 		if (ret)
989e9db1310SAdrian Hunter 			goto out_free;
990e9db1310SAdrian Hunter 		opts->mmap_pages = mmap_pages;
991e9db1310SAdrian Hunter 	}
992e9db1310SAdrian Hunter 
993e9db1310SAdrian Hunter 	if (!p) {
994e9db1310SAdrian Hunter 		ret = 0;
995e9db1310SAdrian Hunter 		goto out_free;
996e9db1310SAdrian Hunter 	}
997e9db1310SAdrian Hunter 
998e9db1310SAdrian Hunter 	ret = __perf_evlist__parse_mmap_pages(&mmap_pages, p + 1);
999e9db1310SAdrian Hunter 	if (ret)
1000e9db1310SAdrian Hunter 		goto out_free;
1001e9db1310SAdrian Hunter 
1002e9db1310SAdrian Hunter 	opts->auxtrace_mmap_pages = mmap_pages;
1003e9db1310SAdrian Hunter 
1004e9db1310SAdrian Hunter out_free:
1005e9db1310SAdrian Hunter 	free(s);
1006e9db1310SAdrian Hunter 	return ret;
1007e9db1310SAdrian Hunter }
1008e9db1310SAdrian Hunter 
1009e5b2c207SNamhyung Kim static const char * const __record_usage[] = {
101086470930SIngo Molnar 	"perf record [<options>] [<command>]",
101186470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
101286470930SIngo Molnar 	NULL
101386470930SIngo Molnar };
1014e5b2c207SNamhyung Kim const char * const *record_usage = __record_usage;
101586470930SIngo Molnar 
1016d20deb64SArnaldo Carvalho de Melo /*
10178c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
10188c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
1019d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
1020d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
1021d20deb64SArnaldo Carvalho de Melo  *
1022d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
1023d20deb64SArnaldo Carvalho de Melo  *
1024d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
1025d20deb64SArnaldo Carvalho de Melo  */
10268c6f45a7SArnaldo Carvalho de Melo static struct record record = {
1027d20deb64SArnaldo Carvalho de Melo 	.opts = {
10288affc2b8SAndi Kleen 		.sample_time	     = true,
1029d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
1030d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
1031d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
1032447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
1033d1cb9fceSNamhyung Kim 		.target		     = {
1034d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
10353aa5939dSAdrian Hunter 			.default_per_cpu = true,
1036d1cb9fceSNamhyung Kim 		},
10379d9cad76SKan Liang 		.proc_map_timeout     = 500,
1038d20deb64SArnaldo Carvalho de Melo 	},
1039e3d59112SNamhyung Kim 	.tool = {
1040e3d59112SNamhyung Kim 		.sample		= process_sample_event,
1041e3d59112SNamhyung Kim 		.fork		= perf_event__process_fork,
1042cca8482cSAdrian Hunter 		.exit		= perf_event__process_exit,
1043e3d59112SNamhyung Kim 		.comm		= perf_event__process_comm,
1044e3d59112SNamhyung Kim 		.mmap		= perf_event__process_mmap,
1045e3d59112SNamhyung Kim 		.mmap2		= perf_event__process_mmap2,
1046cca8482cSAdrian Hunter 		.ordered_events	= true,
1047e3d59112SNamhyung Kim 	},
1048d20deb64SArnaldo Carvalho de Melo };
10497865e817SFrederic Weisbecker 
105076a26549SNamhyung Kim const char record_callchain_help[] = CALLCHAIN_RECORD_HELP
105176a26549SNamhyung Kim 	"\n\t\t\t\tDefault: fp";
105261eaa3beSArnaldo Carvalho de Melo 
1053d20deb64SArnaldo Carvalho de Melo /*
1054d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
1055d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
1056b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
1057d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
1058d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
1059d20deb64SArnaldo Carvalho de Melo  */
1060e5b2c207SNamhyung Kim struct option __record_options[] = {
1061d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
106286470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
1063f120f9d5SJiri Olsa 		     parse_events_option),
1064d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
1065c171b552SLi Zefan 		     "event filter", parse_filter),
10664ba1faa1SWang Nan 	OPT_CALLBACK_NOOPT(0, "exclude-perf", &record.evlist,
10674ba1faa1SWang Nan 			   NULL, "don't record events from perf itself",
10684ba1faa1SWang Nan 			   exclude_perf),
1069bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
1070d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
1071bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
1072d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
1073d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
107486470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
1075509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
1076acac03faSKirill Smelkov 		    "collect data without buffering"),
1077d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
1078daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
1079bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
108086470930SIngo Molnar 			    "system-wide collection from all CPUs"),
1081bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
1082c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
1083d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
1084f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
108586470930SIngo Molnar 		    "output file name"),
108669e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
108769e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
10882e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
1089d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
1090e9db1310SAdrian Hunter 	OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]",
1091e9db1310SAdrian Hunter 		     "number of mmap data pages and AUX area tracing mmap pages",
1092e9db1310SAdrian Hunter 		     record__parse_mmap_pages),
1093d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
109443bece79SLin Ming 		    "put the counters into a counter group"),
109509b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
109609b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
109709b0fd45SJiri Olsa 			   &record_callchain_opt),
109809b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
109976a26549SNamhyung Kim 		     "record_mode[,record_size]", record_callchain_help,
110009b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
1101c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
11023da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
1103b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
1104d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
1105649c48a9SPeter Zijlstra 		    "per thread counts"),
110656100321SPeter Zijlstra 	OPT_BOOLEAN('d', "data", &record.opts.sample_address, "Record the sample addresses"),
11073abebc55SAdrian Hunter 	OPT_BOOLEAN_SET('T', "timestamp", &record.opts.sample_time,
11083abebc55SAdrian Hunter 			&record.opts.sample_time_set,
11093abebc55SAdrian Hunter 			"Record the sample timestamps"),
111056100321SPeter Zijlstra 	OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"),
1111d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
1112649c48a9SPeter Zijlstra 		    "don't sample"),
1113d2db9a98SWang Nan 	OPT_BOOLEAN_SET('N', "no-buildid-cache", &record.no_buildid_cache,
1114d2db9a98SWang Nan 			&record.no_buildid_cache_set,
1115a1ac1d3cSStephane Eranian 			"do not update the buildid cache"),
1116d2db9a98SWang Nan 	OPT_BOOLEAN_SET('B', "no-buildid", &record.no_buildid,
1117d2db9a98SWang Nan 			&record.no_buildid_set,
1118baa2f6ceSArnaldo Carvalho de Melo 			"do not collect buildids in perf.data"),
1119d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
1120023695d9SStephane Eranian 		     "monitor event in cgroup name only",
1121023695d9SStephane Eranian 		     parse_cgroups),
1122a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
11236619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
1124bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
1125bea03405SNamhyung Kim 		   "user to profile"),
1126a5aabdacSStephane Eranian 
1127a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
1128a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
1129a5aabdacSStephane Eranian 		     parse_branch_stack),
1130a5aabdacSStephane Eranian 
1131a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
1132a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
1133bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
113405484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
113505484298SAndi Kleen 		    "sample by weight (on special events only)"),
1136475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
1137475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
11383aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
11393aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
1140bcc84ec6SStephane Eranian 	OPT_CALLBACK_OPTARG('I', "intr-regs", &record.opts.sample_intr_regs, NULL, "any register",
1141bcc84ec6SStephane Eranian 		    "sample selected machine registers on interrupt,"
1142bcc84ec6SStephane Eranian 		    " use -I ? to list register names", parse_regs),
114385c273d2SAndi Kleen 	OPT_BOOLEAN(0, "running-time", &record.opts.running_time,
114485c273d2SAndi Kleen 		    "Record running/enabled time of read (:S) events"),
1145814c8c38SPeter Zijlstra 	OPT_CALLBACK('k', "clockid", &record.opts,
1146814c8c38SPeter Zijlstra 	"clockid", "clockid to use for events, see clock_gettime()",
1147814c8c38SPeter Zijlstra 	parse_clockid),
11482dd6d8a1SAdrian Hunter 	OPT_STRING_OPTARG('S', "snapshot", &record.opts.auxtrace_snapshot_opts,
11492dd6d8a1SAdrian Hunter 			  "opts", "AUX area tracing Snapshot Mode", ""),
11509d9cad76SKan Liang 	OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout,
11519d9cad76SKan Liang 			"per thread proc mmap processing timeout in ms"),
1152b757bb09SAdrian Hunter 	OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
1153b757bb09SAdrian Hunter 		    "Record context switch events"),
115485723885SJiri Olsa 	OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel,
115585723885SJiri Olsa 			 "Configure all used events to run in kernel space.",
115685723885SJiri Olsa 			 PARSE_OPT_EXCLUSIVE),
115785723885SJiri Olsa 	OPT_BOOLEAN_FLAG(0, "all-user", &record.opts.all_user,
115885723885SJiri Olsa 			 "Configure all used events to run in user space.",
115985723885SJiri Olsa 			 PARSE_OPT_EXCLUSIVE),
116071dc2326SWang Nan 	OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
116171dc2326SWang Nan 		   "clang binary to use for compiling BPF scriptlets"),
116271dc2326SWang Nan 	OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
116371dc2326SWang Nan 		   "options passed to clang when compiling BPF scriptlets"),
11647efe0e03SHe Kuang 	OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
11657efe0e03SHe Kuang 		   "file", "vmlinux pathname"),
11666156681bSNamhyung Kim 	OPT_BOOLEAN(0, "buildid-all", &record.buildid_all,
11676156681bSNamhyung Kim 		    "Record build-id of all DSOs regardless of hits"),
116886470930SIngo Molnar 	OPT_END()
116986470930SIngo Molnar };
117086470930SIngo Molnar 
1171e5b2c207SNamhyung Kim struct option *record_options = __record_options;
1172e5b2c207SNamhyung Kim 
11731d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
117486470930SIngo Molnar {
1175ef149c25SAdrian Hunter 	int err;
11768c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
117716ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
117886470930SIngo Molnar 
117948e1cab1SWang Nan #ifndef HAVE_LIBBPF_SUPPORT
118048e1cab1SWang Nan # define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c)
118148e1cab1SWang Nan 	set_nobuild('\0', "clang-path", true);
118248e1cab1SWang Nan 	set_nobuild('\0', "clang-opt", true);
118348e1cab1SWang Nan # undef set_nobuild
118448e1cab1SWang Nan #endif
118548e1cab1SWang Nan 
11867efe0e03SHe Kuang #ifndef HAVE_BPF_PROLOGUE
11877efe0e03SHe Kuang # if !defined (HAVE_DWARF_SUPPORT)
11887efe0e03SHe Kuang #  define REASON  "NO_DWARF=1"
11897efe0e03SHe Kuang # elif !defined (HAVE_LIBBPF_SUPPORT)
11907efe0e03SHe Kuang #  define REASON  "NO_LIBBPF=1"
11917efe0e03SHe Kuang # else
11927efe0e03SHe Kuang #  define REASON  "this architecture doesn't support BPF prologue"
11937efe0e03SHe Kuang # endif
11947efe0e03SHe Kuang # define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, REASON, c)
11957efe0e03SHe Kuang 	set_nobuild('\0', "vmlinux", true);
11967efe0e03SHe Kuang # undef set_nobuild
11977efe0e03SHe Kuang # undef REASON
11987efe0e03SHe Kuang #endif
11997efe0e03SHe Kuang 
12003e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
12013e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
1202361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
1203361c99a6SArnaldo Carvalho de Melo 
1204eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
1205eb853e80SJiri Olsa 
1206bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
1207a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
1208602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
1209bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
121086470930SIngo Molnar 
1211bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
1212c7118369SNamhyung Kim 		usage_with_options_msg(record_usage, record_options,
1213c7118369SNamhyung Kim 			"cgroup monitoring only available in system-wide mode");
1214c7118369SNamhyung Kim 
1215023695d9SStephane Eranian 	}
1216b757bb09SAdrian Hunter 	if (rec->opts.record_switch_events &&
1217b757bb09SAdrian Hunter 	    !perf_can_record_switch_events()) {
1218c7118369SNamhyung Kim 		ui__error("kernel does not support recording context switch events\n");
1219c7118369SNamhyung Kim 		parse_options_usage(record_usage, record_options, "switch-events", 0);
1220c7118369SNamhyung Kim 		return -EINVAL;
1221b757bb09SAdrian Hunter 	}
1222023695d9SStephane Eranian 
1223ef149c25SAdrian Hunter 	if (!rec->itr) {
1224ef149c25SAdrian Hunter 		rec->itr = auxtrace_record__init(rec->evlist, &err);
1225ef149c25SAdrian Hunter 		if (err)
1226ef149c25SAdrian Hunter 			return err;
1227ef149c25SAdrian Hunter 	}
1228ef149c25SAdrian Hunter 
12292dd6d8a1SAdrian Hunter 	err = auxtrace_parse_snapshot_options(rec->itr, &rec->opts,
12302dd6d8a1SAdrian Hunter 					      rec->opts.auxtrace_snapshot_opts);
12312dd6d8a1SAdrian Hunter 	if (err)
12322dd6d8a1SAdrian Hunter 		return err;
12332dd6d8a1SAdrian Hunter 
1234ef149c25SAdrian Hunter 	err = -ENOMEM;
1235ef149c25SAdrian Hunter 
12360a7e6d1bSNamhyung Kim 	symbol__init(NULL);
1237baa2f6ceSArnaldo Carvalho de Melo 
1238ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
1239646aaea6SArnaldo Carvalho de Melo 		pr_warning(
1240646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
1241ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
1242646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
1243646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
1244646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
1245646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
1246646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
1247ec80fde7SArnaldo Carvalho de Melo 
1248d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
1249a1ac1d3cSStephane Eranian 		disable_buildid_cache();
1250655000e7SArnaldo Carvalho de Melo 
12513e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
12523e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
125369aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
125469aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
1255bbd36e5eSPeter Zijlstra 	}
125686470930SIngo Molnar 
125769e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
125869e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
125969e7e5b0SAdrian Hunter 
1260602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
126116ad2ffbSNamhyung Kim 	if (err) {
1262602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
126316ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
126416ad2ffbSNamhyung Kim 	}
12654bd0f2d2SNamhyung Kim 
1266602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
126716ad2ffbSNamhyung Kim 	if (err) {
126816ad2ffbSNamhyung Kim 		int saved_errno = errno;
126916ad2ffbSNamhyung Kim 
1270602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
12713780f488SNamhyung Kim 		ui__error("%s", errbuf);
127216ad2ffbSNamhyung Kim 
127316ad2ffbSNamhyung Kim 		err = -saved_errno;
12748fa60e1fSNamhyung Kim 		goto out_symbol_exit;
127516ad2ffbSNamhyung Kim 	}
12760d37aa34SArnaldo Carvalho de Melo 
127716ad2ffbSNamhyung Kim 	err = -ENOMEM;
12783e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
1279dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
128069aad6f1SArnaldo Carvalho de Melo 
1281ef149c25SAdrian Hunter 	err = auxtrace_record__options(rec->itr, rec->evlist, &rec->opts);
1282ef149c25SAdrian Hunter 	if (err)
1283ef149c25SAdrian Hunter 		goto out_symbol_exit;
1284ef149c25SAdrian Hunter 
12856156681bSNamhyung Kim 	/*
12866156681bSNamhyung Kim 	 * We take all buildids when the file contains
12876156681bSNamhyung Kim 	 * AUX area tracing data because we do not decode the
12886156681bSNamhyung Kim 	 * trace because it would take too long.
12896156681bSNamhyung Kim 	 */
12906156681bSNamhyung Kim 	if (rec->opts.full_auxtrace)
12916156681bSNamhyung Kim 		rec->buildid_all = true;
12926156681bSNamhyung Kim 
1293b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
129439d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
129503ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
12967e4ff9e3SMike Galbraith 	}
12977e4ff9e3SMike Galbraith 
1298d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
1299d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
130045604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
1301d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
1302ef149c25SAdrian Hunter 	auxtrace_record__free(rec->itr);
130339d17dacSArnaldo Carvalho de Melo 	return err;
130486470930SIngo Molnar }
13052dd6d8a1SAdrian Hunter 
13062dd6d8a1SAdrian Hunter static void snapshot_sig_handler(int sig __maybe_unused)
13072dd6d8a1SAdrian Hunter {
13082dd6d8a1SAdrian Hunter 	if (!auxtrace_snapshot_enabled)
13092dd6d8a1SAdrian Hunter 		return;
13102dd6d8a1SAdrian Hunter 	auxtrace_snapshot_enabled = 0;
13112dd6d8a1SAdrian Hunter 	auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
13122dd6d8a1SAdrian Hunter 	auxtrace_record__snapshot_started = 1;
13132dd6d8a1SAdrian Hunter }
1314