xref: /openbmc/linux/tools/perf/builtin-record.c (revision 0a7e6d1b6844bec2d6817615a693c7fce447b80d)
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 
177c6a1c65SPeter Zijlstra #include "util/header.h"
1866e274f3SFrederic Weisbecker #include "util/event.h"
19361c99a6SArnaldo Carvalho de Melo #include "util/evlist.h"
2069aad6f1SArnaldo Carvalho de Melo #include "util/evsel.h"
218f28827aSFrederic Weisbecker #include "util/debug.h"
2294c744b6SArnaldo Carvalho de Melo #include "util/session.h"
2345694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
248d06367fSArnaldo Carvalho de Melo #include "util/symbol.h"
25a12b51c4SPaul Mackerras #include "util/cpumap.h"
26fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h"
27f5fc1412SJiri Olsa #include "util/data.h"
287c6a1c65SPeter Zijlstra 
2986470930SIngo Molnar #include <unistd.h>
3086470930SIngo Molnar #include <sched.h>
31a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3286470930SIngo Molnar 
3378da39faSBernhard Rosenkraenzer 
348c6f45a7SArnaldo Carvalho de Melo struct record {
3545694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
36b4006796SArnaldo Carvalho de Melo 	struct record_opts	opts;
37d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
38f5fc1412SJiri Olsa 	struct perf_data_file	file;
39d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
40d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
41d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
42d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
43d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
44d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
45d20deb64SArnaldo Carvalho de Melo 	long			samples;
460f82ebc4SArnaldo Carvalho de Melo };
4786470930SIngo Molnar 
488c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
49f5970550SPeter Zijlstra {
50cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
514f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
528d3eca20SDavid Ahern 		return -1;
538d3eca20SDavid Ahern 	}
54f5970550SPeter Zijlstra 
55cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
568d3eca20SDavid Ahern 	return 0;
57f5970550SPeter Zijlstra }
58f5970550SPeter Zijlstra 
5945694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
60d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
611d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
621d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
63234fbbf5SArnaldo Carvalho de Melo {
648c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
658c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
66234fbbf5SArnaldo Carvalho de Melo }
67234fbbf5SArnaldo Carvalho de Melo 
688c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, struct perf_mmap *md)
6986470930SIngo Molnar {
70744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
7186470930SIngo Molnar 	unsigned int old = md->prev;
72918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
7386470930SIngo Molnar 	unsigned long size;
7486470930SIngo Molnar 	void *buf;
758d3eca20SDavid Ahern 	int rc = 0;
7686470930SIngo Molnar 
77dc82009aSArnaldo Carvalho de Melo 	if (old == head)
788d3eca20SDavid Ahern 		return 0;
7986470930SIngo Molnar 
80d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
8186470930SIngo Molnar 
8286470930SIngo Molnar 	size = head - old;
8386470930SIngo Molnar 
8486470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
8586470930SIngo Molnar 		buf = &data[old & md->mask];
8686470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
8786470930SIngo Molnar 		old += size;
8886470930SIngo Molnar 
898c6f45a7SArnaldo Carvalho de Melo 		if (record__write(rec, buf, size) < 0) {
908d3eca20SDavid Ahern 			rc = -1;
918d3eca20SDavid Ahern 			goto out;
928d3eca20SDavid Ahern 		}
9386470930SIngo Molnar 	}
9486470930SIngo Molnar 
9586470930SIngo Molnar 	buf = &data[old & md->mask];
9686470930SIngo Molnar 	size = head - old;
9786470930SIngo Molnar 	old += size;
9886470930SIngo Molnar 
998c6f45a7SArnaldo Carvalho de Melo 	if (record__write(rec, buf, size) < 0) {
1008d3eca20SDavid Ahern 		rc = -1;
1018d3eca20SDavid Ahern 		goto out;
1028d3eca20SDavid Ahern 	}
10386470930SIngo Molnar 
10486470930SIngo Molnar 	md->prev = old;
105115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
1068d3eca20SDavid Ahern 
1078d3eca20SDavid Ahern out:
1088d3eca20SDavid Ahern 	return rc;
10986470930SIngo Molnar }
11086470930SIngo Molnar 
11186470930SIngo Molnar static volatile int done = 0;
112f7b7c26eSPeter Zijlstra static volatile int signr = -1;
11333e49ea7SAndi Kleen static volatile int child_finished = 0;
11486470930SIngo Molnar 
11586470930SIngo Molnar static void sig_handler(int sig)
11686470930SIngo Molnar {
11733e49ea7SAndi Kleen 	if (sig == SIGCHLD)
11833e49ea7SAndi Kleen 		child_finished = 1;
11945604710SNamhyung Kim 	else
12045604710SNamhyung Kim 		signr = sig;
12133e49ea7SAndi Kleen 
12286470930SIngo Molnar 	done = 1;
123f7b7c26eSPeter Zijlstra }
124f7b7c26eSPeter Zijlstra 
12545604710SNamhyung Kim static void record__sig_exit(void)
126f7b7c26eSPeter Zijlstra {
12745604710SNamhyung Kim 	if (signr == -1)
128f7b7c26eSPeter Zijlstra 		return;
129f7b7c26eSPeter Zijlstra 
130f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
13145604710SNamhyung Kim 	raise(signr);
13286470930SIngo Molnar }
13386470930SIngo Molnar 
1348c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
135dd7927f4SArnaldo Carvalho de Melo {
13656e52e85SArnaldo Carvalho de Melo 	char msg[512];
1376a4bb04cSJiri Olsa 	struct perf_evsel *pos;
138d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
139d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
140b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
1418d3eca20SDavid Ahern 	int rc = 0;
142dd7927f4SArnaldo Carvalho de Melo 
143f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
144cac21425SJiri Olsa 
1450050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
1463da297a6SIngo Molnar try_again:
1476a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
14856e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
1493da297a6SIngo Molnar 				if (verbose)
150c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
1513da297a6SIngo Molnar 				goto try_again;
1523da297a6SIngo Molnar 			}
153ca6a4258SDavid Ahern 
15456e52e85SArnaldo Carvalho de Melo 			rc = -errno;
15556e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
15656e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
15756e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
1588d3eca20SDavid Ahern 			goto out;
1597c6a1c65SPeter Zijlstra 		}
1607c6a1c65SPeter Zijlstra 	}
1617c6a1c65SPeter Zijlstra 
1621491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
1630a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
1640a102479SFrederic Weisbecker 			strerror(errno));
1658d3eca20SDavid Ahern 		rc = -1;
1668d3eca20SDavid Ahern 		goto out;
1670a102479SFrederic Weisbecker 	}
1680a102479SFrederic Weisbecker 
16918e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
1708d3eca20SDavid Ahern 		if (errno == EPERM) {
1718d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
17218e60939SNelson Elhage 			       "Consider increasing "
17318e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
17418e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
17553653d70SAdrian Hunter 			       "(current value: %u)\n", opts->mmap_pages);
1768d3eca20SDavid Ahern 			rc = -errno;
1778d3eca20SDavid Ahern 		} else {
1788d3eca20SDavid Ahern 			pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
1798d3eca20SDavid Ahern 			rc = -errno;
1808d3eca20SDavid Ahern 		}
1818d3eca20SDavid Ahern 		goto out;
18218e60939SNelson Elhage 	}
1830a27d7f9SArnaldo Carvalho de Melo 
184a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
1857b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
1868d3eca20SDavid Ahern out:
1878d3eca20SDavid Ahern 	return rc;
188a91e5431SArnaldo Carvalho de Melo }
189a91e5431SArnaldo Carvalho de Melo 
1908c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
1916122e4e4SArnaldo Carvalho de Melo {
192f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
193f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
1947ab75cffSDavid Ahern 	u64 start = session->header.data_offset;
1956122e4e4SArnaldo Carvalho de Melo 
196f5fc1412SJiri Olsa 	u64 size = lseek(file->fd, 0, SEEK_CUR);
1979f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
1989f591fd7SArnaldo Carvalho de Melo 		return 0;
1999f591fd7SArnaldo Carvalho de Melo 
2007ab75cffSDavid Ahern 	return __perf_session__process_events(session, start,
2017ab75cffSDavid Ahern 					      size - start,
2026122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
2036122e4e4SArnaldo Carvalho de Melo }
2046122e4e4SArnaldo Carvalho de Melo 
2058115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
206a1645ce1SZhang, Yanmin {
207a1645ce1SZhang, Yanmin 	int err;
20845694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
209a1645ce1SZhang, Yanmin 	/*
210a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
211a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
212a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
213a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
214a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
215a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
216a1645ce1SZhang, Yanmin 	 */
21745694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
218743eb868SArnaldo Carvalho de Melo 					     machine);
219a1645ce1SZhang, Yanmin 	if (err < 0)
220a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
22123346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
222a1645ce1SZhang, Yanmin 
223a1645ce1SZhang, Yanmin 	/*
224a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
225a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
226a1645ce1SZhang, Yanmin 	 */
22745694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
2280ae617beSAdrian Hunter 						 machine);
229a1645ce1SZhang, Yanmin 	if (err < 0)
230a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
23123346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
232a1645ce1SZhang, Yanmin }
233a1645ce1SZhang, Yanmin 
23498402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
23598402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
23698402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
23798402807SFrederic Weisbecker };
23898402807SFrederic Weisbecker 
2398c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
24098402807SFrederic Weisbecker {
241dcabb507SJiri Olsa 	u64 bytes_written = rec->bytes_written;
2420e2e63ddSPeter Zijlstra 	int i;
2438d3eca20SDavid Ahern 	int rc = 0;
24498402807SFrederic Weisbecker 
245d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
2468d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
2478c6f45a7SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
2488d3eca20SDavid Ahern 				rc = -1;
2498d3eca20SDavid Ahern 				goto out;
2508d3eca20SDavid Ahern 			}
2518d3eca20SDavid Ahern 		}
25298402807SFrederic Weisbecker 	}
25398402807SFrederic Weisbecker 
254dcabb507SJiri Olsa 	/*
255dcabb507SJiri Olsa 	 * Mark the round finished in case we wrote
256dcabb507SJiri Olsa 	 * at least one event.
257dcabb507SJiri Olsa 	 */
258dcabb507SJiri Olsa 	if (bytes_written != rec->bytes_written)
2598c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
2608d3eca20SDavid Ahern 
2618d3eca20SDavid Ahern out:
2628d3eca20SDavid Ahern 	return rc;
26398402807SFrederic Weisbecker }
26498402807SFrederic Weisbecker 
2658c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
26657706abcSDavid Ahern {
26757706abcSDavid Ahern 	struct perf_session *session = rec->session;
26857706abcSDavid Ahern 	int feat;
26957706abcSDavid Ahern 
27057706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
27157706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
27257706abcSDavid Ahern 
27357706abcSDavid Ahern 	if (rec->no_buildid)
27457706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
27557706abcSDavid Ahern 
2763e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
27757706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
27857706abcSDavid Ahern 
27957706abcSDavid Ahern 	if (!rec->opts.branch_stack)
28057706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
28157706abcSDavid Ahern }
28257706abcSDavid Ahern 
283f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
284f33cbe72SArnaldo Carvalho de Melo 
285f33cbe72SArnaldo Carvalho de Melo /*
286f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
287f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
288f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
289f33cbe72SArnaldo Carvalho de Melo  */
29045604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused,
29145604710SNamhyung Kim 					siginfo_t *info,
292f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
293f33cbe72SArnaldo Carvalho de Melo {
294f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
295f33cbe72SArnaldo Carvalho de Melo 	done = 1;
296f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
297f33cbe72SArnaldo Carvalho de Melo }
298f33cbe72SArnaldo Carvalho de Melo 
2998c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
30086470930SIngo Molnar {
30157706abcSDavid Ahern 	int err;
30245604710SNamhyung Kim 	int status = 0;
3038b412664SPeter Zijlstra 	unsigned long waking = 0;
30446be604bSZhang, Yanmin 	const bool forks = argc > 0;
30523346f21SArnaldo Carvalho de Melo 	struct machine *machine;
30645694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
307b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
308f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
309d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3102711926aSJiri Olsa 	bool disabled = false;
31186470930SIngo Molnar 
312d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
31333e49ea7SAndi Kleen 
31445604710SNamhyung Kim 	atexit(record__sig_exit);
315f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
316f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
317804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
318f5970550SPeter Zijlstra 
319f5fc1412SJiri Olsa 	session = perf_session__new(file, false, NULL);
32094c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
321ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
322a9a70bbcSArnaldo Carvalho de Melo 		return -1;
323a9a70bbcSArnaldo Carvalho de Melo 	}
324a9a70bbcSArnaldo Carvalho de Melo 
325d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
326d20deb64SArnaldo Carvalho de Melo 
3278c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
328330aa675SStephane Eranian 
329d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
3303e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
331f5fc1412SJiri Olsa 						    argv, file->is_pipe,
332735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
33335b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
33435b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
33545604710SNamhyung Kim 			status = err;
33635b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
337856e9660SPeter Zijlstra 		}
338856e9660SPeter Zijlstra 	}
339856e9660SPeter Zijlstra 
3408c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
3418d3eca20SDavid Ahern 		err = -1;
34245604710SNamhyung Kim 		goto out_child;
3438d3eca20SDavid Ahern 	}
34486470930SIngo Molnar 
3453e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
346a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
347a8bb559bSNamhyung Kim 
348f5fc1412SJiri Olsa 	if (file->is_pipe) {
349f5fc1412SJiri Olsa 		err = perf_header__write_pipe(file->fd);
350529870e3STom Zanussi 		if (err < 0)
35145604710SNamhyung Kim 			goto out_child;
352563aecb2SJiri Olsa 	} else {
3533e2be2daSArnaldo Carvalho de Melo 		err = perf_session__write_header(session, rec->evlist,
354f5fc1412SJiri Olsa 						 file->fd, false);
355d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
35645604710SNamhyung Kim 			goto out_child;
357d5eed904SArnaldo Carvalho de Melo 	}
3587c6a1c65SPeter Zijlstra 
359d3665498SDavid Ahern 	if (!rec->no_buildid
360e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
361d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
362e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
3638d3eca20SDavid Ahern 		err = -1;
36445604710SNamhyung Kim 		goto out_child;
365e20960c0SRobert Richter 	}
366e20960c0SRobert Richter 
36734ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
368743eb868SArnaldo Carvalho de Melo 
369f5fc1412SJiri Olsa 	if (file->is_pipe) {
37045694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
371a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
3722c46dbb5STom Zanussi 		if (err < 0) {
3732c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
37445604710SNamhyung Kim 			goto out_child;
3752c46dbb5STom Zanussi 		}
376cd19a035STom Zanussi 
3773e2be2daSArnaldo Carvalho de Melo 		if (have_tracepoints(&rec->evlist->entries)) {
37863e0c771STom Zanussi 			/*
37963e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
38063e0c771STom Zanussi 			 * there were no tracepoints so its not really
38163e0c771STom Zanussi 			 * an error, just that we don't need to
38263e0c771STom Zanussi 			 * synthesize anything.  We really have to
38363e0c771STom Zanussi 			 * return this more properly and also
38463e0c771STom Zanussi 			 * propagate errors that now are calling die()
38563e0c771STom Zanussi 			 */
3863e2be2daSArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist,
387743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
38863e0c771STom Zanussi 			if (err <= 0) {
38963e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
39045604710SNamhyung Kim 				goto out_child;
39163e0c771STom Zanussi 			}
392f34b9001SDavid Ahern 			rec->bytes_written += err;
3932c46dbb5STom Zanussi 		}
39463e0c771STom Zanussi 	}
3952c46dbb5STom Zanussi 
39645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
3970ae617beSAdrian Hunter 						 machine);
398c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
399c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
400c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
401c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
40256b03f3cSArnaldo Carvalho de Melo 
40345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
404743eb868SArnaldo Carvalho de Melo 					     machine);
405c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
406c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
407c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
408c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
409c1a3a4b9SArnaldo Carvalho de Melo 
4107e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
411876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
4127e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
4137e383de4SArnaldo Carvalho de Melo 	}
414b7cece76SArnaldo Carvalho de Melo 
4153e2be2daSArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
41658d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
4178d3eca20SDavid Ahern 	if (err != 0)
41845604710SNamhyung Kim 		goto out_child;
4198d3eca20SDavid Ahern 
420d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
42186470930SIngo Molnar 		struct sched_param param;
42286470930SIngo Molnar 
423d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
42486470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
4256beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
4268d3eca20SDavid Ahern 			err = -1;
42745604710SNamhyung Kim 			goto out_child;
42886470930SIngo Molnar 		}
42986470930SIngo Molnar 	}
43086470930SIngo Molnar 
431774cb499SJiri Olsa 	/*
432774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
433774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
434774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
435774cb499SJiri Olsa 	 */
4366619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
4373e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
438764e16a3SDavid Ahern 
439856e9660SPeter Zijlstra 	/*
440856e9660SPeter Zijlstra 	 * Let the child rip
441856e9660SPeter Zijlstra 	 */
442735f7e0bSArnaldo Carvalho de Melo 	if (forks)
4433e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
444856e9660SPeter Zijlstra 
4456619a53eSAndi Kleen 	if (opts->initial_delay) {
4466619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
4476619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
4486619a53eSAndi Kleen 	}
4496619a53eSAndi Kleen 
450649c48a9SPeter Zijlstra 	for (;;) {
451d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
45286470930SIngo Molnar 
4538c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
4548d3eca20SDavid Ahern 			err = -1;
45545604710SNamhyung Kim 			goto out_child;
4568d3eca20SDavid Ahern 		}
45786470930SIngo Molnar 
458d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
459649c48a9SPeter Zijlstra 			if (done)
460649c48a9SPeter Zijlstra 				break;
4613e2be2daSArnaldo Carvalho de Melo 			err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1);
462a515114fSJiri Olsa 			/*
463a515114fSJiri Olsa 			 * Propagate error, only if there's any. Ignore positive
464a515114fSJiri Olsa 			 * number of returned events and interrupt error.
465a515114fSJiri Olsa 			 */
466a515114fSJiri Olsa 			if (err > 0 || (err < 0 && errno == EINTR))
46745604710SNamhyung Kim 				err = 0;
4688b412664SPeter Zijlstra 			waking++;
4698b412664SPeter Zijlstra 		}
4708b412664SPeter Zijlstra 
471774cb499SJiri Olsa 		/*
472774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
473774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
474774cb499SJiri Olsa 		 * disable events in this case.
475774cb499SJiri Olsa 		 */
476602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
4773e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
4782711926aSJiri Olsa 			disabled = true;
4792711926aSJiri Olsa 		}
4808b412664SPeter Zijlstra 	}
4818b412664SPeter Zijlstra 
482f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
483f33cbe72SArnaldo Carvalho de Melo 		char msg[512];
484f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
485f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
486f33cbe72SArnaldo Carvalho de Melo 		err = -1;
48745604710SNamhyung Kim 		goto out_child;
488f33cbe72SArnaldo Carvalho de Melo 	}
489f33cbe72SArnaldo Carvalho de Melo 
49045604710SNamhyung Kim 	if (!quiet) {
4918b412664SPeter Zijlstra 		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
49286470930SIngo Molnar 
49386470930SIngo Molnar 		/*
49486470930SIngo Molnar 		 * Approximate RIP event size: 24 bytes.
49586470930SIngo Molnar 		 */
49686470930SIngo Molnar 		fprintf(stderr,
4979486aa38SArnaldo Carvalho de Melo 			"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
498d20deb64SArnaldo Carvalho de Melo 			(double)rec->bytes_written / 1024.0 / 1024.0,
4996a4d98d7SJiri Olsa 			file->path,
500d20deb64SArnaldo Carvalho de Melo 			rec->bytes_written / 24);
50145604710SNamhyung Kim 	}
50286470930SIngo Molnar 
50345604710SNamhyung Kim out_child:
50445604710SNamhyung Kim 	if (forks) {
50545604710SNamhyung Kim 		int exit_status;
50645604710SNamhyung Kim 
50745604710SNamhyung Kim 		if (!child_finished)
50845604710SNamhyung Kim 			kill(rec->evlist->workload.pid, SIGTERM);
50945604710SNamhyung Kim 
51045604710SNamhyung Kim 		wait(&exit_status);
51145604710SNamhyung Kim 
51245604710SNamhyung Kim 		if (err < 0)
51345604710SNamhyung Kim 			status = err;
51445604710SNamhyung Kim 		else if (WIFEXITED(exit_status))
51545604710SNamhyung Kim 			status = WEXITSTATUS(exit_status);
51645604710SNamhyung Kim 		else if (WIFSIGNALED(exit_status))
51745604710SNamhyung Kim 			signr = WTERMSIG(exit_status);
51845604710SNamhyung Kim 	} else
51945604710SNamhyung Kim 		status = err;
52045604710SNamhyung Kim 
52145604710SNamhyung Kim 	if (!err && !file->is_pipe) {
52245604710SNamhyung Kim 		rec->session->header.data_size += rec->bytes_written;
52345604710SNamhyung Kim 
52445604710SNamhyung Kim 		if (!rec->no_buildid)
52545604710SNamhyung Kim 			process_buildids(rec);
52645604710SNamhyung Kim 		perf_session__write_header(rec->session, rec->evlist,
52745604710SNamhyung Kim 					   file->fd, true);
52845604710SNamhyung Kim 	}
52939d17dacSArnaldo Carvalho de Melo 
53039d17dacSArnaldo Carvalho de Melo out_delete_session:
53139d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
53245604710SNamhyung Kim 	return status;
53386470930SIngo Molnar }
53486470930SIngo Molnar 
535bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
536bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
537bdfebd84SRoberto Agostino Vitillo 
538bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
539bdfebd84SRoberto Agostino Vitillo 
540bdfebd84SRoberto Agostino Vitillo struct branch_mode {
541bdfebd84SRoberto Agostino Vitillo 	const char *name;
542bdfebd84SRoberto Agostino Vitillo 	int mode;
543bdfebd84SRoberto Agostino Vitillo };
544bdfebd84SRoberto Agostino Vitillo 
545bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
546bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
547bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
548bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
549bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
550bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
551bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
552bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
5530126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
5540126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
5550126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
5560fffa5dfSAnshuman Khandual 	BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
557bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
558bdfebd84SRoberto Agostino Vitillo };
559bdfebd84SRoberto Agostino Vitillo 
560bdfebd84SRoberto Agostino Vitillo static int
561a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
562bdfebd84SRoberto Agostino Vitillo {
563bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
564bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
565bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
566bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
567bdfebd84SRoberto Agostino Vitillo 
568bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
569bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
570a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
571bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
572bdfebd84SRoberto Agostino Vitillo 
573a5aabdacSStephane Eranian 	if (unset)
574a5aabdacSStephane Eranian 		return 0;
575bdfebd84SRoberto Agostino Vitillo 
576a5aabdacSStephane Eranian 	/*
577a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
578a5aabdacSStephane Eranian 	 */
579a5aabdacSStephane Eranian 	if (*mode)
580a5aabdacSStephane Eranian 		return -1;
581a5aabdacSStephane Eranian 
582a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
583a5aabdacSStephane Eranian 	if (str) {
584bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
585bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
586bdfebd84SRoberto Agostino Vitillo 		if (!s)
587bdfebd84SRoberto Agostino Vitillo 			return -1;
588bdfebd84SRoberto Agostino Vitillo 
589bdfebd84SRoberto Agostino Vitillo 		for (;;) {
590bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
591bdfebd84SRoberto Agostino Vitillo 			if (p)
592bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
593bdfebd84SRoberto Agostino Vitillo 
594bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
595bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
596bdfebd84SRoberto Agostino Vitillo 					break;
597bdfebd84SRoberto Agostino Vitillo 			}
598a5aabdacSStephane Eranian 			if (!br->name) {
599a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
600a5aabdacSStephane Eranian 					    " check man page\n", s);
601bdfebd84SRoberto Agostino Vitillo 				goto error;
602a5aabdacSStephane Eranian 			}
603bdfebd84SRoberto Agostino Vitillo 
604bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
605bdfebd84SRoberto Agostino Vitillo 
606bdfebd84SRoberto Agostino Vitillo 			if (!p)
607bdfebd84SRoberto Agostino Vitillo 				break;
608bdfebd84SRoberto Agostino Vitillo 
609bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
610bdfebd84SRoberto Agostino Vitillo 		}
611a5aabdacSStephane Eranian 	}
612bdfebd84SRoberto Agostino Vitillo 	ret = 0;
613bdfebd84SRoberto Agostino Vitillo 
614a5aabdacSStephane Eranian 	/* default to any branch */
615bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
616a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
617bdfebd84SRoberto Agostino Vitillo 	}
618bdfebd84SRoberto Agostino Vitillo error:
619bdfebd84SRoberto Agostino Vitillo 	free(os);
620bdfebd84SRoberto Agostino Vitillo 	return ret;
621bdfebd84SRoberto Agostino Vitillo }
622bdfebd84SRoberto Agostino Vitillo 
6239ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
62426d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size)
62526d33022SJiri Olsa {
62626d33022SJiri Olsa 	char *endptr;
62726d33022SJiri Olsa 	unsigned long size;
62826d33022SJiri Olsa 	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
62926d33022SJiri Olsa 
63026d33022SJiri Olsa 	size = strtoul(str, &endptr, 0);
63126d33022SJiri Olsa 
63226d33022SJiri Olsa 	do {
63326d33022SJiri Olsa 		if (*endptr)
63426d33022SJiri Olsa 			break;
63526d33022SJiri Olsa 
63626d33022SJiri Olsa 		size = round_up(size, sizeof(u64));
63726d33022SJiri Olsa 		if (!size || size > max_size)
63826d33022SJiri Olsa 			break;
63926d33022SJiri Olsa 
64026d33022SJiri Olsa 		*_size = size;
64126d33022SJiri Olsa 		return 0;
64226d33022SJiri Olsa 
64326d33022SJiri Olsa 	} while (0);
64426d33022SJiri Olsa 
64526d33022SJiri Olsa 	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
64626d33022SJiri Olsa 	       max_size, str);
64726d33022SJiri Olsa 	return -1;
64826d33022SJiri Olsa }
6499ff125d1SJiri Olsa #endif /* HAVE_DWARF_UNWIND_SUPPORT */
65026d33022SJiri Olsa 
651b4006796SArnaldo Carvalho de Melo int record_parse_callchain(const char *arg, struct record_opts *opts)
65226d33022SJiri Olsa {
65326d33022SJiri Olsa 	char *tok, *name, *saveptr = NULL;
65426d33022SJiri Olsa 	char *buf;
65526d33022SJiri Olsa 	int ret = -1;
65626d33022SJiri Olsa 
65726d33022SJiri Olsa 	/* We need buffer that we know we can write to. */
65826d33022SJiri Olsa 	buf = malloc(strlen(arg) + 1);
65926d33022SJiri Olsa 	if (!buf)
66026d33022SJiri Olsa 		return -ENOMEM;
66126d33022SJiri Olsa 
66226d33022SJiri Olsa 	strcpy(buf, arg);
66326d33022SJiri Olsa 
66426d33022SJiri Olsa 	tok = strtok_r((char *)buf, ",", &saveptr);
66526d33022SJiri Olsa 	name = tok ? : (char *)buf;
66626d33022SJiri Olsa 
66726d33022SJiri Olsa 	do {
66826d33022SJiri Olsa 		/* Framepointer style */
66926d33022SJiri Olsa 		if (!strncmp(name, "fp", sizeof("fp"))) {
67026d33022SJiri Olsa 			if (!strtok_r(NULL, ",", &saveptr)) {
671c5ff78c3SArnaldo Carvalho de Melo 				opts->call_graph = CALLCHAIN_FP;
67226d33022SJiri Olsa 				ret = 0;
67326d33022SJiri Olsa 			} else
67426d33022SJiri Olsa 				pr_err("callchain: No more arguments "
67526d33022SJiri Olsa 				       "needed for -g fp\n");
67626d33022SJiri Olsa 			break;
67726d33022SJiri Olsa 
6789ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
67926d33022SJiri Olsa 		/* Dwarf style */
68026d33022SJiri Olsa 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
68161eaa3beSArnaldo Carvalho de Melo 			const unsigned long default_stack_dump_size = 8192;
68261eaa3beSArnaldo Carvalho de Melo 
68326d33022SJiri Olsa 			ret = 0;
684c5ff78c3SArnaldo Carvalho de Melo 			opts->call_graph = CALLCHAIN_DWARF;
685c5ff78c3SArnaldo Carvalho de Melo 			opts->stack_dump_size = default_stack_dump_size;
68626d33022SJiri Olsa 
68726d33022SJiri Olsa 			tok = strtok_r(NULL, ",", &saveptr);
68826d33022SJiri Olsa 			if (tok) {
68926d33022SJiri Olsa 				unsigned long size = 0;
69026d33022SJiri Olsa 
69126d33022SJiri Olsa 				ret = get_stack_size(tok, &size);
692c5ff78c3SArnaldo Carvalho de Melo 				opts->stack_dump_size = size;
69326d33022SJiri Olsa 			}
6949ff125d1SJiri Olsa #endif /* HAVE_DWARF_UNWIND_SUPPORT */
69526d33022SJiri Olsa 		} else {
69609b0fd45SJiri Olsa 			pr_err("callchain: Unknown --call-graph option "
69726d33022SJiri Olsa 			       "value: %s\n", arg);
69826d33022SJiri Olsa 			break;
69926d33022SJiri Olsa 		}
70026d33022SJiri Olsa 
70126d33022SJiri Olsa 	} while (0);
70226d33022SJiri Olsa 
70326d33022SJiri Olsa 	free(buf);
70409b0fd45SJiri Olsa 	return ret;
70509b0fd45SJiri Olsa }
70626d33022SJiri Olsa 
707b4006796SArnaldo Carvalho de Melo static void callchain_debug(struct record_opts *opts)
70809b0fd45SJiri Olsa {
709a601fdffSJiri Olsa 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
710a601fdffSJiri Olsa 
711a601fdffSJiri Olsa 	pr_debug("callchain: type %s\n", str[opts->call_graph]);
71226d33022SJiri Olsa 
71309b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_DWARF)
71409b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
71509b0fd45SJiri Olsa 			 opts->stack_dump_size);
71609b0fd45SJiri Olsa }
71709b0fd45SJiri Olsa 
71809b0fd45SJiri Olsa int record_parse_callchain_opt(const struct option *opt,
71909b0fd45SJiri Olsa 			       const char *arg,
72009b0fd45SJiri Olsa 			       int unset)
72109b0fd45SJiri Olsa {
722b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = opt->value;
72309b0fd45SJiri Olsa 	int ret;
72409b0fd45SJiri Olsa 
725eb853e80SJiri Olsa 	opts->call_graph_enabled = !unset;
726eb853e80SJiri Olsa 
72709b0fd45SJiri Olsa 	/* --no-call-graph */
72809b0fd45SJiri Olsa 	if (unset) {
72909b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_NONE;
73009b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
73109b0fd45SJiri Olsa 		return 0;
73209b0fd45SJiri Olsa 	}
73309b0fd45SJiri Olsa 
73409b0fd45SJiri Olsa 	ret = record_parse_callchain(arg, opts);
73509b0fd45SJiri Olsa 	if (!ret)
73609b0fd45SJiri Olsa 		callchain_debug(opts);
73709b0fd45SJiri Olsa 
73826d33022SJiri Olsa 	return ret;
73926d33022SJiri Olsa }
74026d33022SJiri Olsa 
74109b0fd45SJiri Olsa int record_callchain_opt(const struct option *opt,
74209b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
74309b0fd45SJiri Olsa 			 int unset __maybe_unused)
74409b0fd45SJiri Olsa {
745b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = opt->value;
74609b0fd45SJiri Olsa 
747eb853e80SJiri Olsa 	opts->call_graph_enabled = !unset;
748eb853e80SJiri Olsa 
74909b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_NONE)
75009b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_FP;
75109b0fd45SJiri Olsa 
75209b0fd45SJiri Olsa 	callchain_debug(opts);
75309b0fd45SJiri Olsa 	return 0;
75409b0fd45SJiri Olsa }
75509b0fd45SJiri Olsa 
756eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
757eb853e80SJiri Olsa {
758eb853e80SJiri Olsa 	struct record *rec = cb;
759eb853e80SJiri Olsa 
760eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
761eb853e80SJiri Olsa 		return record_parse_callchain(value, &rec->opts);
762eb853e80SJiri Olsa 
763eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
764eb853e80SJiri Olsa }
765eb853e80SJiri Olsa 
76686470930SIngo Molnar static const char * const record_usage[] = {
76786470930SIngo Molnar 	"perf record [<options>] [<command>]",
76886470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
76986470930SIngo Molnar 	NULL
77086470930SIngo Molnar };
77186470930SIngo Molnar 
772d20deb64SArnaldo Carvalho de Melo /*
7738c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
7748c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
775d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
776d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
777d20deb64SArnaldo Carvalho de Melo  *
778d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
779d20deb64SArnaldo Carvalho de Melo  *
780d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
781d20deb64SArnaldo Carvalho de Melo  */
7828c6f45a7SArnaldo Carvalho de Melo static struct record record = {
783d20deb64SArnaldo Carvalho de Melo 	.opts = {
7848affc2b8SAndi Kleen 		.sample_time	     = true,
785d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
786d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
787d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
788447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
789d1cb9fceSNamhyung Kim 		.target		     = {
790d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
7913aa5939dSAdrian Hunter 			.default_per_cpu = true,
792d1cb9fceSNamhyung Kim 		},
793d20deb64SArnaldo Carvalho de Melo 	},
794d20deb64SArnaldo Carvalho de Melo };
7957865e817SFrederic Weisbecker 
79609b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
79761eaa3beSArnaldo Carvalho de Melo 
7989ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
79909b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
80061eaa3beSArnaldo Carvalho de Melo #else
80109b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp";
80261eaa3beSArnaldo Carvalho de Melo #endif
80361eaa3beSArnaldo Carvalho de Melo 
804d20deb64SArnaldo Carvalho de Melo /*
805d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
806d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
807b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
808d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
809d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
810d20deb64SArnaldo Carvalho de Melo  */
811bca647aaSTom Zanussi const struct option record_options[] = {
812d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
81386470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
814f120f9d5SJiri Olsa 		     parse_events_option),
815d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
816c171b552SLi Zefan 		     "event filter", parse_filter),
817bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
818d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
819bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
820d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
821d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
82286470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
823509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
824acac03faSKirill Smelkov 		    "collect data without buffering"),
825d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
826daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
827bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
82886470930SIngo Molnar 			    "system-wide collection from all CPUs"),
829bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
830c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
831d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
832f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
83386470930SIngo Molnar 		    "output file name"),
83469e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
83569e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
8362e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
837d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
838994a1f78SJiri Olsa 	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
839994a1f78SJiri Olsa 		     "number of mmap data pages",
840994a1f78SJiri Olsa 		     perf_evlist__parse_mmap_pages),
841d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
84243bece79SLin Ming 		    "put the counters into a counter group"),
84309b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
84409b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
84509b0fd45SJiri Olsa 			   &record_callchain_opt),
84609b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
84775d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
84809b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
849c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8503da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
851b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
852d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
853649c48a9SPeter Zijlstra 		    "per thread counts"),
854d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8554bba828dSAnton Blanchard 		    "Sample addresses"),
856d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8573e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
858d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
859649c48a9SPeter Zijlstra 		    "don't sample"),
860d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
861a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
862d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
863baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
864d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
865023695d9SStephane Eranian 		     "monitor event in cgroup name only",
866023695d9SStephane Eranian 		     parse_cgroups),
867a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
8686619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
869bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
870bea03405SNamhyung Kim 		   "user to profile"),
871a5aabdacSStephane Eranian 
872a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
873a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
874a5aabdacSStephane Eranian 		     parse_branch_stack),
875a5aabdacSStephane Eranian 
876a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
877a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
878bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
87905484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
88005484298SAndi Kleen 		    "sample by weight (on special events only)"),
881475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
882475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
8833aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
8843aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
88586470930SIngo Molnar 	OPT_END()
88686470930SIngo Molnar };
88786470930SIngo Molnar 
8881d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
88986470930SIngo Molnar {
89069aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
8918c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
89216ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
89386470930SIngo Molnar 
8943e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
8953e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
896361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
897361c99a6SArnaldo Carvalho de Melo 
898eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
899eb853e80SJiri Olsa 
900bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
901a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
902602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
903bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
90486470930SIngo Molnar 
905bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
9063780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
907023695d9SStephane Eranian 			  " system-wide mode\n");
908023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
909023695d9SStephane Eranian 	}
910023695d9SStephane Eranian 
911*0a7e6d1bSNamhyung Kim 	symbol__init(NULL);
912baa2f6ceSArnaldo Carvalho de Melo 
913ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
914646aaea6SArnaldo Carvalho de Melo 		pr_warning(
915646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
916ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
917646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
918646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
919646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
920646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
921646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
922ec80fde7SArnaldo Carvalho de Melo 
923d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
924a1ac1d3cSStephane Eranian 		disable_buildid_cache();
925655000e7SArnaldo Carvalho de Melo 
9263e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
9273e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
92869aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
92969aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
930bbd36e5eSPeter Zijlstra 	}
93186470930SIngo Molnar 
93269e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
93369e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
93469e7e5b0SAdrian Hunter 
935602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
93616ad2ffbSNamhyung Kim 	if (err) {
937602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
93816ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
93916ad2ffbSNamhyung Kim 	}
9404bd0f2d2SNamhyung Kim 
941602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
94216ad2ffbSNamhyung Kim 	if (err) {
94316ad2ffbSNamhyung Kim 		int saved_errno = errno;
94416ad2ffbSNamhyung Kim 
945602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9463780f488SNamhyung Kim 		ui__error("%s", errbuf);
94716ad2ffbSNamhyung Kim 
94816ad2ffbSNamhyung Kim 		err = -saved_errno;
9498fa60e1fSNamhyung Kim 		goto out_symbol_exit;
95016ad2ffbSNamhyung Kim 	}
9510d37aa34SArnaldo Carvalho de Melo 
95216ad2ffbSNamhyung Kim 	err = -ENOMEM;
9533e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
954dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
95569aad6f1SArnaldo Carvalho de Melo 
956b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
95739d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
95803ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
9597e4ff9e3SMike Galbraith 	}
9607e4ff9e3SMike Galbraith 
961d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
962d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
96345604710SNamhyung Kim 	perf_evlist__delete(rec->evlist);
964d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
96539d17dacSArnaldo Carvalho de Melo 	return err;
96686470930SIngo Molnar }
967