xref: /openbmc/linux/tools/perf/builtin-record.c (revision 7b8283b56d9fb36106ff1c459dfd399a20bd374d)
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"
307c6a1c65SPeter Zijlstra 
3186470930SIngo Molnar #include <unistd.h>
3286470930SIngo Molnar #include <sched.h>
33a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3486470930SIngo Molnar 
3578da39faSBernhard Rosenkraenzer 
368c6f45a7SArnaldo Carvalho de Melo struct record {
3745694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
38b4006796SArnaldo Carvalho de Melo 	struct record_opts	opts;
39d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
40f5fc1412SJiri Olsa 	struct perf_data_file	file;
41d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
42d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
43d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
44d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
45d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
46d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
47d20deb64SArnaldo Carvalho de Melo 	long			samples;
480f82ebc4SArnaldo Carvalho de Melo };
4986470930SIngo Molnar 
508c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
51f5970550SPeter Zijlstra {
52cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
534f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
548d3eca20SDavid Ahern 		return -1;
558d3eca20SDavid Ahern 	}
56f5970550SPeter Zijlstra 
57cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
588d3eca20SDavid Ahern 	return 0;
59f5970550SPeter Zijlstra }
60f5970550SPeter Zijlstra 
6145694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
62d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
631d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
641d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
65234fbbf5SArnaldo Carvalho de Melo {
668c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
678c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
68234fbbf5SArnaldo Carvalho de Melo }
69234fbbf5SArnaldo Carvalho de Melo 
70e5685730SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, int idx)
7186470930SIngo Molnar {
72e5685730SArnaldo Carvalho de Melo 	struct perf_mmap *md = &rec->evlist->mmap[idx];
73*7b8283b5SDavid Ahern 	u64 head = perf_mmap__read_head(md);
74*7b8283b5SDavid Ahern 	u64 old = md->prev;
75918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
7686470930SIngo Molnar 	unsigned long size;
7786470930SIngo Molnar 	void *buf;
788d3eca20SDavid Ahern 	int rc = 0;
7986470930SIngo Molnar 
80dc82009aSArnaldo Carvalho de Melo 	if (old == head)
818d3eca20SDavid Ahern 		return 0;
8286470930SIngo Molnar 
83d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
8486470930SIngo Molnar 
8586470930SIngo Molnar 	size = head - old;
8686470930SIngo Molnar 
8786470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
8886470930SIngo Molnar 		buf = &data[old & md->mask];
8986470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
9086470930SIngo Molnar 		old += size;
9186470930SIngo Molnar 
928c6f45a7SArnaldo Carvalho de Melo 		if (record__write(rec, buf, size) < 0) {
938d3eca20SDavid Ahern 			rc = -1;
948d3eca20SDavid Ahern 			goto out;
958d3eca20SDavid Ahern 		}
9686470930SIngo Molnar 	}
9786470930SIngo Molnar 
9886470930SIngo Molnar 	buf = &data[old & md->mask];
9986470930SIngo Molnar 	size = head - old;
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 	md->prev = old;
108e5685730SArnaldo Carvalho de Melo 	perf_evlist__mmap_consume(rec->evlist, idx);
1098d3eca20SDavid Ahern out:
1108d3eca20SDavid Ahern 	return rc;
11186470930SIngo Molnar }
11286470930SIngo Molnar 
11386470930SIngo Molnar static volatile int done = 0;
114f7b7c26eSPeter Zijlstra static volatile int signr = -1;
11533e49ea7SAndi Kleen static volatile int child_finished = 0;
11686470930SIngo Molnar 
11786470930SIngo Molnar static void sig_handler(int sig)
11886470930SIngo Molnar {
11933e49ea7SAndi Kleen 	if (sig == SIGCHLD)
12033e49ea7SAndi Kleen 		child_finished = 1;
12145604710SNamhyung Kim 	else
12245604710SNamhyung Kim 		signr = sig;
12333e49ea7SAndi Kleen 
12486470930SIngo Molnar 	done = 1;
125f7b7c26eSPeter Zijlstra }
126f7b7c26eSPeter Zijlstra 
12745604710SNamhyung Kim static void record__sig_exit(void)
128f7b7c26eSPeter Zijlstra {
12945604710SNamhyung Kim 	if (signr == -1)
130f7b7c26eSPeter Zijlstra 		return;
131f7b7c26eSPeter Zijlstra 
132f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
13345604710SNamhyung Kim 	raise(signr);
13486470930SIngo Molnar }
13586470930SIngo Molnar 
1368c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
137dd7927f4SArnaldo Carvalho de Melo {
13856e52e85SArnaldo Carvalho de Melo 	char msg[512];
1396a4bb04cSJiri Olsa 	struct perf_evsel *pos;
140d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
141d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
142b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
1438d3eca20SDavid Ahern 	int rc = 0;
144dd7927f4SArnaldo Carvalho de Melo 
145f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
146cac21425SJiri Olsa 
1470050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
1483da297a6SIngo Molnar try_again:
1496a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
15056e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
1513da297a6SIngo Molnar 				if (verbose)
152c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
1533da297a6SIngo Molnar 				goto try_again;
1543da297a6SIngo Molnar 			}
155ca6a4258SDavid Ahern 
15656e52e85SArnaldo Carvalho de Melo 			rc = -errno;
15756e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
15856e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
15956e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
1608d3eca20SDavid Ahern 			goto out;
1617c6a1c65SPeter Zijlstra 		}
1627c6a1c65SPeter Zijlstra 	}
1637c6a1c65SPeter Zijlstra 
16423d4aad4SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist, &pos)) {
16523d4aad4SArnaldo Carvalho de Melo 		error("failed to set filter \"%s\" on event %s with %d (%s)\n",
16623d4aad4SArnaldo Carvalho de Melo 			pos->filter, perf_evsel__name(pos), errno,
16735550da3SMasami Hiramatsu 			strerror_r(errno, msg, sizeof(msg)));
1688d3eca20SDavid Ahern 		rc = -1;
1698d3eca20SDavid Ahern 		goto out;
1700a102479SFrederic Weisbecker 	}
1710a102479SFrederic Weisbecker 
17218e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
1738d3eca20SDavid Ahern 		if (errno == EPERM) {
1748d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
17518e60939SNelson Elhage 			       "Consider increasing "
17618e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
17718e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
17853653d70SAdrian Hunter 			       "(current value: %u)\n", opts->mmap_pages);
1798d3eca20SDavid Ahern 			rc = -errno;
1808d3eca20SDavid Ahern 		} else {
18135550da3SMasami Hiramatsu 			pr_err("failed to mmap with %d (%s)\n", errno,
18235550da3SMasami Hiramatsu 				strerror_r(errno, msg, sizeof(msg)));
1838d3eca20SDavid Ahern 			rc = -errno;
1848d3eca20SDavid Ahern 		}
1858d3eca20SDavid Ahern 		goto out;
18618e60939SNelson Elhage 	}
1870a27d7f9SArnaldo Carvalho de Melo 
188a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
1897b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
1908d3eca20SDavid Ahern out:
1918d3eca20SDavid Ahern 	return rc;
192a91e5431SArnaldo Carvalho de Melo }
193a91e5431SArnaldo Carvalho de Melo 
194e3d59112SNamhyung Kim static int process_sample_event(struct perf_tool *tool,
195e3d59112SNamhyung Kim 				union perf_event *event,
196e3d59112SNamhyung Kim 				struct perf_sample *sample,
197e3d59112SNamhyung Kim 				struct perf_evsel *evsel,
198e3d59112SNamhyung Kim 				struct machine *machine)
199e3d59112SNamhyung Kim {
200e3d59112SNamhyung Kim 	struct record *rec = container_of(tool, struct record, tool);
201e3d59112SNamhyung Kim 
202e3d59112SNamhyung Kim 	rec->samples++;
203e3d59112SNamhyung Kim 
204e3d59112SNamhyung Kim 	return build_id__mark_dso_hit(tool, event, sample, evsel, machine);
205e3d59112SNamhyung Kim }
206e3d59112SNamhyung Kim 
2078c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
2086122e4e4SArnaldo Carvalho de Melo {
209f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
210f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
2116122e4e4SArnaldo Carvalho de Melo 
21242aa276fSNamhyung Kim 	u64 size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
2139f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2149f591fd7SArnaldo Carvalho de Melo 		return 0;
2159f591fd7SArnaldo Carvalho de Melo 
2164ac30cf7SNamhyung Kim 	file->size = size;
2174ac30cf7SNamhyung Kim 
21800dc8657SNamhyung Kim 	/*
21900dc8657SNamhyung Kim 	 * During this process, it'll load kernel map and replace the
22000dc8657SNamhyung Kim 	 * dso->long_name to a real pathname it found.  In this case
22100dc8657SNamhyung Kim 	 * we prefer the vmlinux path like
22200dc8657SNamhyung Kim 	 *   /lib/modules/3.16.4/build/vmlinux
22300dc8657SNamhyung Kim 	 *
22400dc8657SNamhyung Kim 	 * rather than build-id path (in debug directory).
22500dc8657SNamhyung Kim 	 *   $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
22600dc8657SNamhyung Kim 	 */
22700dc8657SNamhyung Kim 	symbol_conf.ignore_vmlinux_buildid = true;
22800dc8657SNamhyung Kim 
229b7b61cbeSArnaldo Carvalho de Melo 	return perf_session__process_events(session);
2306122e4e4SArnaldo Carvalho de Melo }
2316122e4e4SArnaldo Carvalho de Melo 
2328115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
233a1645ce1SZhang, Yanmin {
234a1645ce1SZhang, Yanmin 	int err;
23545694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
236a1645ce1SZhang, Yanmin 	/*
237a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
238a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
239a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
240a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
241a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
242a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
243a1645ce1SZhang, Yanmin 	 */
24445694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
245743eb868SArnaldo Carvalho de Melo 					     machine);
246a1645ce1SZhang, Yanmin 	if (err < 0)
247a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
24823346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
249a1645ce1SZhang, Yanmin 
250a1645ce1SZhang, Yanmin 	/*
251a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
252a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
253a1645ce1SZhang, Yanmin 	 */
25445694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
2550ae617beSAdrian Hunter 						 machine);
256a1645ce1SZhang, Yanmin 	if (err < 0)
257a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
25823346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
259a1645ce1SZhang, Yanmin }
260a1645ce1SZhang, Yanmin 
26198402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
26298402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
26398402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
26498402807SFrederic Weisbecker };
26598402807SFrederic Weisbecker 
2668c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
26798402807SFrederic Weisbecker {
268dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
2690e2e63ddSPeter Zijlstra 	int i;
2708d3eca20SDavid Ahern 	int rc = 0;
27198402807SFrederic Weisbecker 
272d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
2738d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
274e5685730SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, i) != 0) {
2758d3eca20SDavid Ahern 				rc = -1;
2768d3eca20SDavid Ahern 				goto out;
2778d3eca20SDavid Ahern 			}
2788d3eca20SDavid Ahern 		}
27998402807SFrederic Weisbecker 	}
28098402807SFrederic Weisbecker 
281dcabb507SJiri Olsa 	/*
282dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
283dcabb507SJiri Olsa 	 * at least one event.
284dcabb507SJiri Olsa 	 */
285dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
2868c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
2878d3eca20SDavid Ahern 
2888d3eca20SDavid Ahern out:
2898d3eca20SDavid Ahern 	return rc;
29098402807SFrederic Weisbecker }
29198402807SFrederic Weisbecker 
2928c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
29357706abcSDavid Ahern {
29457706abcSDavid Ahern 	struct perf_session *session = rec->session;
29557706abcSDavid Ahern 	int feat;
29657706abcSDavid Ahern 
29757706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
29857706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
29957706abcSDavid Ahern 
30057706abcSDavid Ahern 	if (rec->no_buildid)
30157706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
30257706abcSDavid Ahern 
3033e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
30457706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
30557706abcSDavid Ahern 
30657706abcSDavid Ahern 	if (!rec->opts.branch_stack)
30757706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
30857706abcSDavid Ahern }
30957706abcSDavid Ahern 
310f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
311f33cbe72SArnaldo Carvalho de Melo 
312f33cbe72SArnaldo Carvalho de Melo /*
313f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
314f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
315f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
316f33cbe72SArnaldo Carvalho de Melo  */
31745604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
31845604710SNamhyung Kim 					siginfo_t *info,
319f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
320f33cbe72SArnaldo Carvalho de Melo {
321f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
322f33cbe72SArnaldo Carvalho de Melo 	done = 1;
323f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
324f33cbe72SArnaldo Carvalho de Melo }
325f33cbe72SArnaldo Carvalho de Melo 
3268c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
32786470930SIngo Molnar {
32857706abcSDavid Ahern 	int err;
32945604710SNamhyung Kim 	int status = 0;
3308b412664SPeter Zijlstra 	unsigned long waking = 0;
33146be604bSZhang, Yanmin 	const bool forks = argc > 0;
33223346f21SArnaldo Carvalho de Melo 	struct machine *machine;
33345694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
334b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
335f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
336d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3376dcf45efSArnaldo Carvalho de Melo 	bool disabled = false, draining = false;
33842aa276fSNamhyung Kim 	int fd;
33986470930SIngo Molnar 
340d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
34133e49ea7SAndi Kleen 
34245604710SNamhyung Kim 	atexit(record__sig_exit);
343f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
344f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
345804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
346f5970550SPeter Zijlstra 
347b7b61cbeSArnaldo Carvalho de Melo 	session = perf_session__new(file, false, tool);
34894c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
349ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
350a9a70bbcSArnaldo Carvalho de Melo 		return -1;
351a9a70bbcSArnaldo Carvalho de Melo 	}
352a9a70bbcSArnaldo Carvalho de Melo 
35342aa276fSNamhyung Kim 	fd = perf_data_file__fd(file);
354d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
355d20deb64SArnaldo Carvalho de Melo 
3568c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
357330aa675SStephane Eranian 
358d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
3593e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
360f5fc1412SJiri Olsa 						    argv, file->is_pipe,
361735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
36235b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
36335b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
36445604710SNamhyung Kim 			status = err;
36535b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
366856e9660SPeter Zijlstra 		}
367856e9660SPeter Zijlstra 	}
368856e9660SPeter Zijlstra 
3698c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
3708d3eca20SDavid Ahern 		err = -1;
37145604710SNamhyung Kim 		goto out_child;
3728d3eca20SDavid Ahern 	}
37386470930SIngo Molnar 
3743e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
375a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
376a8bb559bSNamhyung Kim 
377f5fc1412SJiri Olsa 	if (file->is_pipe) {
37842aa276fSNamhyung Kim 		err = perf_header__write_pipe(fd);
379529870e3STom Zanussi 		if (err < 0)
38045604710SNamhyung Kim 			goto out_child;
381563aecb2SJiri Olsa 	} else {
38242aa276fSNamhyung Kim 		err = perf_session__write_header(session, rec->evlist, fd, false);
383d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
38445604710SNamhyung Kim 			goto out_child;
385d5eed904SArnaldo Carvalho de Melo 	}
3867c6a1c65SPeter Zijlstra 
387d3665498SDavid Ahern 	if (!rec->no_buildid
388e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
389d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
390e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
3918d3eca20SDavid Ahern 		err = -1;
39245604710SNamhyung Kim 		goto out_child;
393e20960c0SRobert Richter 	}
394e20960c0SRobert Richter 
39534ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
396743eb868SArnaldo Carvalho de Melo 
397f5fc1412SJiri Olsa 	if (file->is_pipe) {
39845694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
399a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
4002c46dbb5STom Zanussi 		if (err < 0) {
4012c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
40245604710SNamhyung Kim 			goto out_child;
4032c46dbb5STom Zanussi 		}
404cd19a035STom Zanussi 
4053e2be2daSArnaldo Carvalho de Melo 		if (have_tracepoints(&rec->evlist->entries)) {
40663e0c771STom Zanussi 			/*
40763e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
40863e0c771STom Zanussi 			 * there were no tracepoints so its not really
40963e0c771STom Zanussi 			 * an error, just that we don't need to
41063e0c771STom Zanussi 			 * synthesize anything.  We really have to
41163e0c771STom Zanussi 			 * return this more properly and also
41263e0c771STom Zanussi 			 * propagate errors that now are calling die()
41363e0c771STom Zanussi 			 */
41442aa276fSNamhyung Kim 			err = perf_event__synthesize_tracing_data(tool,	fd, rec->evlist,
415743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
41663e0c771STom Zanussi 			if (err <= 0) {
41763e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
41845604710SNamhyung Kim 				goto out_child;
41963e0c771STom Zanussi 			}
420f34b9001SDavid Ahern 			rec->bytes_written += err;
4212c46dbb5STom Zanussi 		}
42263e0c771STom Zanussi 	}
4232c46dbb5STom Zanussi 
42445694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
4250ae617beSAdrian Hunter 						 machine);
426c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
427c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
428c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
429c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
43056b03f3cSArnaldo Carvalho de Melo 
43145694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
432743eb868SArnaldo Carvalho de Melo 					     machine);
433c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
434c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
435c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
436c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
437c1a3a4b9SArnaldo Carvalho de Melo 
4387e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
439876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
4407e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
4417e383de4SArnaldo Carvalho de Melo 	}
442b7cece76SArnaldo Carvalho de Melo 
4433e2be2daSArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
44458d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
4458d3eca20SDavid Ahern 	if (err != 0)
44645604710SNamhyung Kim 		goto out_child;
4478d3eca20SDavid Ahern 
448d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
44986470930SIngo Molnar 		struct sched_param param;
45086470930SIngo Molnar 
451d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
45286470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
4536beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
4548d3eca20SDavid Ahern 			err = -1;
45545604710SNamhyung Kim 			goto out_child;
45686470930SIngo Molnar 		}
45786470930SIngo Molnar 	}
45886470930SIngo Molnar 
459774cb499SJiri Olsa 	/*
460774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
461774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
462774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
463774cb499SJiri Olsa 	 */
4646619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
4653e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
466764e16a3SDavid Ahern 
467856e9660SPeter Zijlstra 	/*
468856e9660SPeter Zijlstra 	 * Let the child rip
469856e9660SPeter Zijlstra 	 */
470735f7e0bSArnaldo Carvalho de Melo 	if (forks)
4713e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
472856e9660SPeter Zijlstra 
4736619a53eSAndi Kleen 	if (opts->initial_delay) {
4746619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
4756619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
4766619a53eSAndi Kleen 	}
4776619a53eSAndi Kleen 
478649c48a9SPeter Zijlstra 	for (;;) {
479d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
48086470930SIngo Molnar 
4818c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
4828d3eca20SDavid Ahern 			err = -1;
48345604710SNamhyung Kim 			goto out_child;
4848d3eca20SDavid Ahern 		}
48586470930SIngo Molnar 
486d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
4876dcf45efSArnaldo Carvalho de Melo 			if (done || draining)
488649c48a9SPeter Zijlstra 				break;
489f66a889dSArnaldo Carvalho de Melo 			err = perf_evlist__poll(rec->evlist, -1);
490a515114fSJiri Olsa 			/*
491a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
492a515114fSJiri Olsa 			 * number of returned events and interrupt error.
493a515114fSJiri Olsa 			 */
494a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
49545604710SNamhyung Kim 				err = 0;
4968b412664SPeter Zijlstra 			waking++;
4976dcf45efSArnaldo Carvalho de Melo 
4986dcf45efSArnaldo Carvalho de Melo 			if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
4996dcf45efSArnaldo Carvalho de Melo 				draining = true;
5008b412664SPeter Zijlstra 		}
5018b412664SPeter Zijlstra 
502774cb499SJiri Olsa 		/*
503774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
504774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
505774cb499SJiri Olsa 		 * disable events in this case.
506774cb499SJiri Olsa 		 */
507602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
5083e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
5092711926aSJiri Olsa 			disabled = true;
5102711926aSJiri Olsa 		}
5118b412664SPeter Zijlstra 	}
5128b412664SPeter Zijlstra 
513f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
51435550da3SMasami Hiramatsu 		char msg[STRERR_BUFSIZE];
515f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
516f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
517f33cbe72SArnaldo Carvalho de Melo 		err = -1;
51845604710SNamhyung Kim 		goto out_child;
519f33cbe72SArnaldo Carvalho de Melo 	}
520f33cbe72SArnaldo Carvalho de Melo 
521e3d59112SNamhyung Kim 	if (!quiet)
5228b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
52386470930SIngo Molnar 
52445604710SNamhyung Kim out_child:
52545604710SNamhyung Kim 	if (forks) {
52645604710SNamhyung Kim 		int exit_status;
52745604710SNamhyung Kim 
52845604710SNamhyung Kim 		if (!child_finished)
52945604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
53045604710SNamhyung Kim 
53145604710SNamhyung Kim 		wait(&exit_status);
53245604710SNamhyung Kim 
53345604710SNamhyung Kim 		if (err < 0)
53445604710SNamhyung Kim 			status = err;
53545604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
53645604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
53745604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
53845604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
53945604710SNamhyung Kim 	} else
54045604710SNamhyung Kim 		status = err;
54145604710SNamhyung Kim 
542e3d59112SNamhyung Kim 	/* this will be recalculated during process_buildids() */
543e3d59112SNamhyung Kim 	rec->samples = 0;
544e3d59112SNamhyung Kim 
54545604710SNamhyung Kim 	if (!err && !file->is_pipe) {
54645604710SNamhyung Kim 		rec->session->header.data_size += rec->bytes_written;
54745604710SNamhyung Kim 
54845604710SNamhyung Kim 		if (!rec->no_buildid)
54945604710SNamhyung Kim 			process_buildids(rec);
55042aa276fSNamhyung Kim 		perf_session__write_header(rec->session, rec->evlist, fd, true);
55145604710SNamhyung Kim 	}
55239d17dacSArnaldo Carvalho de Melo 
553e3d59112SNamhyung Kim 	if (!err && !quiet) {
554e3d59112SNamhyung Kim 		char samples[128];
555e3d59112SNamhyung Kim 
556e3d59112SNamhyung Kim 		if (rec->samples)
557e3d59112SNamhyung Kim 			scnprintf(samples, sizeof(samples),
558e3d59112SNamhyung Kim 				  " (%" PRIu64 " samples)", rec->samples);
559e3d59112SNamhyung Kim 		else
560e3d59112SNamhyung Kim 			samples[0] = '\0';
561e3d59112SNamhyung Kim 
562e3d59112SNamhyung Kim 		fprintf(stderr,	"[ perf record: Captured and wrote %.3f MB %s%s ]\n",
563e3d59112SNamhyung Kim 			perf_data_file__size(file) / 1024.0 / 1024.0,
564e3d59112SNamhyung Kim 			file->path, samples);
565e3d59112SNamhyung Kim 	}
566e3d59112SNamhyung Kim 
56739d17dacSArnaldo Carvalho de Melo out_delete_session:
56839d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
56945604710SNamhyung Kim 	return status;
57086470930SIngo Molnar }
57186470930SIngo Molnar 
572bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
573bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
574bdfebd84SRoberto Agostino Vitillo 
575bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
576bdfebd84SRoberto Agostino Vitillo 
577bdfebd84SRoberto Agostino Vitillo struct branch_mode {
578bdfebd84SRoberto Agostino Vitillo 	const char *name;
579bdfebd84SRoberto Agostino Vitillo 	int mode;
580bdfebd84SRoberto Agostino Vitillo };
581bdfebd84SRoberto Agostino Vitillo 
582bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
583bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
584bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
585bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
586bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
587bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
588bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
589bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
5900126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
5910126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
5920126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
5930fffa5dfSAnshuman Khandual 	BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
594bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
595bdfebd84SRoberto Agostino Vitillo };
596bdfebd84SRoberto Agostino Vitillo 
597bdfebd84SRoberto Agostino Vitillo static int
598a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
599bdfebd84SRoberto Agostino Vitillo {
600bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
601bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
602bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
603bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
604bdfebd84SRoberto Agostino Vitillo 
605bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
606bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
607a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
608bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
609bdfebd84SRoberto Agostino Vitillo 
610a5aabdacSStephane Eranian 	if (unset)
611a5aabdacSStephane Eranian 		return 0;
612bdfebd84SRoberto Agostino Vitillo 
613a5aabdacSStephane Eranian 	/*
614a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
615a5aabdacSStephane Eranian 	 */
616a5aabdacSStephane Eranian 	if (*mode)
617a5aabdacSStephane Eranian 		return -1;
618a5aabdacSStephane Eranian 
619a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
620a5aabdacSStephane Eranian 	if (str) {
621bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
622bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
623bdfebd84SRoberto Agostino Vitillo 		if (!s)
624bdfebd84SRoberto Agostino Vitillo 			return -1;
625bdfebd84SRoberto Agostino Vitillo 
626bdfebd84SRoberto Agostino Vitillo 		for (;;) {
627bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
628bdfebd84SRoberto Agostino Vitillo 			if (p)
629bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
630bdfebd84SRoberto Agostino Vitillo 
631bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
632bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
633bdfebd84SRoberto Agostino Vitillo 					break;
634bdfebd84SRoberto Agostino Vitillo 			}
635a5aabdacSStephane Eranian 			if (!br->name) {
636a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
637a5aabdacSStephane Eranian 					    " check man page\n", s);
638bdfebd84SRoberto Agostino Vitillo 				goto error;
639a5aabdacSStephane Eranian 			}
640bdfebd84SRoberto Agostino Vitillo 
641bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
642bdfebd84SRoberto Agostino Vitillo 
643bdfebd84SRoberto Agostino Vitillo 			if (!p)
644bdfebd84SRoberto Agostino Vitillo 				break;
645bdfebd84SRoberto Agostino Vitillo 
646bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
647bdfebd84SRoberto Agostino Vitillo 		}
648a5aabdacSStephane Eranian 	}
649bdfebd84SRoberto Agostino Vitillo 	ret = 0;
650bdfebd84SRoberto Agostino Vitillo 
651a5aabdacSStephane Eranian 	/* default to any branch */
652bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
653a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
654bdfebd84SRoberto Agostino Vitillo 	}
655bdfebd84SRoberto Agostino Vitillo error:
656bdfebd84SRoberto Agostino Vitillo 	free(os);
657bdfebd84SRoberto Agostino Vitillo 	return ret;
658bdfebd84SRoberto Agostino Vitillo }
659bdfebd84SRoberto Agostino Vitillo 
66072a128aaSNamhyung Kim static void callchain_debug(void)
66109b0fd45SJiri Olsa {
662aad2b21cSKan Liang 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" };
663a601fdffSJiri Olsa 
66472a128aaSNamhyung Kim 	pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
66526d33022SJiri Olsa 
66672a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_DWARF)
66709b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
66872a128aaSNamhyung Kim 			 callchain_param.dump_size);
66909b0fd45SJiri Olsa }
67009b0fd45SJiri Olsa 
67172a128aaSNamhyung Kim int record_parse_callchain_opt(const struct option *opt __maybe_unused,
67209b0fd45SJiri Olsa 			       const char *arg,
67309b0fd45SJiri Olsa 			       int unset)
67409b0fd45SJiri Olsa {
67509b0fd45SJiri Olsa 	int ret;
67609b0fd45SJiri Olsa 
67772a128aaSNamhyung Kim 	callchain_param.enabled = !unset;
678eb853e80SJiri Olsa 
67909b0fd45SJiri Olsa 	/* --no-call-graph */
68009b0fd45SJiri Olsa 	if (unset) {
68172a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_NONE;
68209b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
68309b0fd45SJiri Olsa 		return 0;
68409b0fd45SJiri Olsa 	}
68509b0fd45SJiri Olsa 
686f7f084f4SNamhyung Kim 	ret = parse_callchain_record_opt(arg);
68709b0fd45SJiri Olsa 	if (!ret)
68872a128aaSNamhyung Kim 		callchain_debug();
68909b0fd45SJiri Olsa 
69026d33022SJiri Olsa 	return ret;
69126d33022SJiri Olsa }
69226d33022SJiri Olsa 
69372a128aaSNamhyung Kim int record_callchain_opt(const struct option *opt __maybe_unused,
69409b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
69509b0fd45SJiri Olsa 			 int unset __maybe_unused)
69609b0fd45SJiri Olsa {
69772a128aaSNamhyung Kim 	callchain_param.enabled = true;
69809b0fd45SJiri Olsa 
69972a128aaSNamhyung Kim 	if (callchain_param.record_mode == CALLCHAIN_NONE)
70072a128aaSNamhyung Kim 		callchain_param.record_mode = CALLCHAIN_FP;
701eb853e80SJiri Olsa 
70272a128aaSNamhyung Kim 	callchain_debug();
70309b0fd45SJiri Olsa 	return 0;
70409b0fd45SJiri Olsa }
70509b0fd45SJiri Olsa 
706eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
707eb853e80SJiri Olsa {
708eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
7095a2e5e85SNamhyung Kim 		var = "call-graph.record-mode"; /* fall-through */
710eb853e80SJiri Olsa 
711eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
712eb853e80SJiri Olsa }
713eb853e80SJiri Olsa 
714814c8c38SPeter Zijlstra struct clockid_map {
715814c8c38SPeter Zijlstra 	const char *name;
716814c8c38SPeter Zijlstra 	int clockid;
717814c8c38SPeter Zijlstra };
718814c8c38SPeter Zijlstra 
719814c8c38SPeter Zijlstra #define CLOCKID_MAP(n, c)	\
720814c8c38SPeter Zijlstra 	{ .name = n, .clockid = (c), }
721814c8c38SPeter Zijlstra 
722814c8c38SPeter Zijlstra #define CLOCKID_END	{ .name = NULL, }
723814c8c38SPeter Zijlstra 
724814c8c38SPeter Zijlstra 
725814c8c38SPeter Zijlstra /*
726814c8c38SPeter Zijlstra  * Add the missing ones, we need to build on many distros...
727814c8c38SPeter Zijlstra  */
728814c8c38SPeter Zijlstra #ifndef CLOCK_MONOTONIC_RAW
729814c8c38SPeter Zijlstra #define CLOCK_MONOTONIC_RAW 4
730814c8c38SPeter Zijlstra #endif
731814c8c38SPeter Zijlstra #ifndef CLOCK_BOOTTIME
732814c8c38SPeter Zijlstra #define CLOCK_BOOTTIME 7
733814c8c38SPeter Zijlstra #endif
734814c8c38SPeter Zijlstra #ifndef CLOCK_TAI
735814c8c38SPeter Zijlstra #define CLOCK_TAI 11
736814c8c38SPeter Zijlstra #endif
737814c8c38SPeter Zijlstra 
738814c8c38SPeter Zijlstra static const struct clockid_map clockids[] = {
739814c8c38SPeter Zijlstra 	/* available for all events, NMI safe */
740814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic", CLOCK_MONOTONIC),
741814c8c38SPeter Zijlstra 	CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW),
742814c8c38SPeter Zijlstra 
743814c8c38SPeter Zijlstra 	/* available for some events */
744814c8c38SPeter Zijlstra 	CLOCKID_MAP("realtime", CLOCK_REALTIME),
745814c8c38SPeter Zijlstra 	CLOCKID_MAP("boottime", CLOCK_BOOTTIME),
746814c8c38SPeter Zijlstra 	CLOCKID_MAP("tai", CLOCK_TAI),
747814c8c38SPeter Zijlstra 
748814c8c38SPeter Zijlstra 	/* available for the lazy */
749814c8c38SPeter Zijlstra 	CLOCKID_MAP("mono", CLOCK_MONOTONIC),
750814c8c38SPeter Zijlstra 	CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW),
751814c8c38SPeter Zijlstra 	CLOCKID_MAP("real", CLOCK_REALTIME),
752814c8c38SPeter Zijlstra 	CLOCKID_MAP("boot", CLOCK_BOOTTIME),
753814c8c38SPeter Zijlstra 
754814c8c38SPeter Zijlstra 	CLOCKID_END,
755814c8c38SPeter Zijlstra };
756814c8c38SPeter Zijlstra 
757814c8c38SPeter Zijlstra static int parse_clockid(const struct option *opt, const char *str, int unset)
758814c8c38SPeter Zijlstra {
759814c8c38SPeter Zijlstra 	struct record_opts *opts = (struct record_opts *)opt->value;
760814c8c38SPeter Zijlstra 	const struct clockid_map *cm;
761814c8c38SPeter Zijlstra 	const char *ostr = str;
762814c8c38SPeter Zijlstra 
763814c8c38SPeter Zijlstra 	if (unset) {
764814c8c38SPeter Zijlstra 		opts->use_clockid = 0;
765814c8c38SPeter Zijlstra 		return 0;
766814c8c38SPeter Zijlstra 	}
767814c8c38SPeter Zijlstra 
768814c8c38SPeter Zijlstra 	/* no arg passed */
769814c8c38SPeter Zijlstra 	if (!str)
770814c8c38SPeter Zijlstra 		return 0;
771814c8c38SPeter Zijlstra 
772814c8c38SPeter Zijlstra 	/* no setting it twice */
773814c8c38SPeter Zijlstra 	if (opts->use_clockid)
774814c8c38SPeter Zijlstra 		return -1;
775814c8c38SPeter Zijlstra 
776814c8c38SPeter Zijlstra 	opts->use_clockid = true;
777814c8c38SPeter Zijlstra 
778814c8c38SPeter Zijlstra 	/* if its a number, we're done */
779814c8c38SPeter Zijlstra 	if (sscanf(str, "%d", &opts->clockid) == 1)
780814c8c38SPeter Zijlstra 		return 0;
781814c8c38SPeter Zijlstra 
782814c8c38SPeter Zijlstra 	/* allow a "CLOCK_" prefix to the name */
783814c8c38SPeter Zijlstra 	if (!strncasecmp(str, "CLOCK_", 6))
784814c8c38SPeter Zijlstra 		str += 6;
785814c8c38SPeter Zijlstra 
786814c8c38SPeter Zijlstra 	for (cm = clockids; cm->name; cm++) {
787814c8c38SPeter Zijlstra 		if (!strcasecmp(str, cm->name)) {
788814c8c38SPeter Zijlstra 			opts->clockid = cm->clockid;
789814c8c38SPeter Zijlstra 			return 0;
790814c8c38SPeter Zijlstra 		}
791814c8c38SPeter Zijlstra 	}
792814c8c38SPeter Zijlstra 
793814c8c38SPeter Zijlstra 	opts->use_clockid = false;
794814c8c38SPeter Zijlstra 	ui__warning("unknown clockid %s, check man page\n", ostr);
795814c8c38SPeter Zijlstra 	return -1;
796814c8c38SPeter Zijlstra }
797814c8c38SPeter Zijlstra 
798e5b2c207SNamhyung Kim static const char * const __record_usage[] = {
79986470930SIngo Molnar 	"perf record [<options>] [<command>]",
80086470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
80186470930SIngo Molnar 	NULL
80286470930SIngo Molnar };
803e5b2c207SNamhyung Kim const char * const *record_usage = __record_usage;
80486470930SIngo Molnar 
805d20deb64SArnaldo Carvalho de Melo /*
8068c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
8078c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
808d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
809d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
810d20deb64SArnaldo Carvalho de Melo  *
811d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
812d20deb64SArnaldo Carvalho de Melo  *
813d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
814d20deb64SArnaldo Carvalho de Melo  */
8158c6f45a7SArnaldo Carvalho de Melo static struct record record = {
816d20deb64SArnaldo Carvalho de Melo 	.opts = {
8178affc2b8SAndi Kleen 		.sample_time	     = true,
818d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
819d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
820d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
821447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
822d1cb9fceSNamhyung Kim 		.target		     = {
823d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
8243aa5939dSAdrian Hunter 			.default_per_cpu = true,
825d1cb9fceSNamhyung Kim 		},
826d20deb64SArnaldo Carvalho de Melo 	},
827e3d59112SNamhyung Kim 	.tool = {
828e3d59112SNamhyung Kim 		.sample		= process_sample_event,
829e3d59112SNamhyung Kim 		.fork		= perf_event__process_fork,
830e3d59112SNamhyung Kim 		.comm		= perf_event__process_comm,
831e3d59112SNamhyung Kim 		.mmap		= perf_event__process_mmap,
832e3d59112SNamhyung Kim 		.mmap2		= perf_event__process_mmap2,
833e3d59112SNamhyung Kim 	},
834d20deb64SArnaldo Carvalho de Melo };
8357865e817SFrederic Weisbecker 
83609b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
83761eaa3beSArnaldo Carvalho de Melo 
8389ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
839aad2b21cSKan Liang const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf lbr";
84061eaa3beSArnaldo Carvalho de Melo #else
841aad2b21cSKan Liang const char record_callchain_help[] = CALLCHAIN_HELP "fp lbr";
84261eaa3beSArnaldo Carvalho de Melo #endif
84361eaa3beSArnaldo Carvalho de Melo 
844d20deb64SArnaldo Carvalho de Melo /*
845d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
846d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
847b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
848d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
849d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
850d20deb64SArnaldo Carvalho de Melo  */
851e5b2c207SNamhyung Kim struct option __record_options[] = {
852d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
85386470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
854f120f9d5SJiri Olsa 		     parse_events_option),
855d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
856c171b552SLi Zefan 		     "event filter", parse_filter),
857bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
858d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
859bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
860d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
861d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
86286470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
863509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
864acac03faSKirill Smelkov 		    "collect data without buffering"),
865d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
866daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
867bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
86886470930SIngo Molnar 			    "system-wide collection from all CPUs"),
869bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
870c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
871d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
872f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
87386470930SIngo Molnar 		    "output file name"),
87469e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
87569e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
8762e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
877d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
878994a1f78SJiri Olsa 	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
879994a1f78SJiri Olsa 		     "number of mmap data pages",
880994a1f78SJiri Olsa 		     perf_evlist__parse_mmap_pages),
881d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
88243bece79SLin Ming 		    "put the counters into a counter group"),
88309b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
88409b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
88509b0fd45SJiri Olsa 			   &record_callchain_opt),
88609b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
88775d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
88809b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
889c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8903da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
891b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
892d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
893649c48a9SPeter Zijlstra 		    "per thread counts"),
894d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8954bba828dSAnton Blanchard 		    "Sample addresses"),
896d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8973e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
898d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
899649c48a9SPeter Zijlstra 		    "don't sample"),
900d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
901a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
902d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
903baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
904d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
905023695d9SStephane Eranian 		     "monitor event in cgroup name only",
906023695d9SStephane Eranian 		     parse_cgroups),
907a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
9086619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
909bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
910bea03405SNamhyung Kim 		   "user to profile"),
911a5aabdacSStephane Eranian 
912a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
913a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
914a5aabdacSStephane Eranian 		     parse_branch_stack),
915a5aabdacSStephane Eranian 
916a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
917a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
918bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
91905484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
92005484298SAndi Kleen 		    "sample by weight (on special events only)"),
921475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
922475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
9233aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
9243aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
9254b6c5177SStephane Eranian 	OPT_BOOLEAN('I', "intr-regs", &record.opts.sample_intr_regs,
9264b6c5177SStephane Eranian 		    "Sample machine registers on interrupt"),
92785c273d2SAndi Kleen 	OPT_BOOLEAN(0, "running-time", &record.opts.running_time,
92885c273d2SAndi Kleen 		    "Record running/enabled time of read (:S) events"),
929814c8c38SPeter Zijlstra 	OPT_CALLBACK('k', "clockid", &record.opts,
930814c8c38SPeter Zijlstra 	"clockid", "clockid to use for events, see clock_gettime()",
931814c8c38SPeter Zijlstra 	parse_clockid),
93286470930SIngo Molnar 	OPT_END()
93386470930SIngo Molnar };
93486470930SIngo Molnar 
935e5b2c207SNamhyung Kim struct option *record_options = __record_options;
936e5b2c207SNamhyung Kim 
9371d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
93886470930SIngo Molnar {
93969aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
9408c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
94116ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
94286470930SIngo Molnar 
9433e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
9443e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
945361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
946361c99a6SArnaldo Carvalho de Melo 
947eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
948eb853e80SJiri Olsa 
949bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
950a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
951602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
952bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
95386470930SIngo Molnar 
954bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
9553780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
956023695d9SStephane Eranian 			  " system-wide mode\n");
957023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
958023695d9SStephane Eranian 	}
959023695d9SStephane Eranian 
9600a7e6d1bSNamhyung Kim 	symbol__init(NULL);
961baa2f6ceSArnaldo Carvalho de Melo 
962ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
963646aaea6SArnaldo Carvalho de Melo 		pr_warning(
964646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
965ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
966646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
967646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
968646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
969646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
970646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
971ec80fde7SArnaldo Carvalho de Melo 
972d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
973a1ac1d3cSStephane Eranian 		disable_buildid_cache();
974655000e7SArnaldo Carvalho de Melo 
9753e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
9763e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
97769aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
97869aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
979bbd36e5eSPeter Zijlstra 	}
98086470930SIngo Molnar 
98169e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
98269e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
98369e7e5b0SAdrian Hunter 
984602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
98516ad2ffbSNamhyung Kim 	if (err) {
986602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
98716ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
98816ad2ffbSNamhyung Kim 	}
9894bd0f2d2SNamhyung Kim 
990602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
99116ad2ffbSNamhyung Kim 	if (err) {
99216ad2ffbSNamhyung Kim 		int saved_errno = errno;
99316ad2ffbSNamhyung Kim 
994602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9953780f488SNamhyung Kim 		ui__error("%s", errbuf);
99616ad2ffbSNamhyung Kim 
99716ad2ffbSNamhyung Kim 		err = -saved_errno;
9988fa60e1fSNamhyung Kim 		goto out_symbol_exit;
99916ad2ffbSNamhyung Kim 	}
10000d37aa34SArnaldo Carvalho de Melo 
100116ad2ffbSNamhyung Kim 	err = -ENOMEM;
10023e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
1003dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
100469aad6f1SArnaldo Carvalho de Melo 
1005b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
100639d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
100703ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
10087e4ff9e3SMike Galbraith 	}
10097e4ff9e3SMike Galbraith 
1010d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
1011d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
101245604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
1013d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
101439d17dacSArnaldo Carvalho de Melo 	return err;
101586470930SIngo Molnar }
1016