xref: /openbmc/linux/tools/perf/builtin-record.c (revision 8c6f45a7c263840c27dfe846d40577b49e43b85b)
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 
3389fe808aSIngo Molnar #ifndef HAVE_ON_EXIT_SUPPORT
3478da39faSBernhard Rosenkraenzer #ifndef ATEXIT_MAX
3578da39faSBernhard Rosenkraenzer #define ATEXIT_MAX 32
3678da39faSBernhard Rosenkraenzer #endif
3778da39faSBernhard Rosenkraenzer static int __on_exit_count = 0;
3878da39faSBernhard Rosenkraenzer typedef void (*on_exit_func_t) (int, void *);
3978da39faSBernhard Rosenkraenzer static on_exit_func_t __on_exit_funcs[ATEXIT_MAX];
4078da39faSBernhard Rosenkraenzer static void *__on_exit_args[ATEXIT_MAX];
4178da39faSBernhard Rosenkraenzer static int __exitcode = 0;
4278da39faSBernhard Rosenkraenzer static void __handle_on_exit_funcs(void);
4378da39faSBernhard Rosenkraenzer static int on_exit(on_exit_func_t function, void *arg);
4478da39faSBernhard Rosenkraenzer #define exit(x) (exit)(__exitcode = (x))
4578da39faSBernhard Rosenkraenzer 
4678da39faSBernhard Rosenkraenzer static int on_exit(on_exit_func_t function, void *arg)
4778da39faSBernhard Rosenkraenzer {
4878da39faSBernhard Rosenkraenzer 	if (__on_exit_count == ATEXIT_MAX)
4978da39faSBernhard Rosenkraenzer 		return -ENOMEM;
5078da39faSBernhard Rosenkraenzer 	else if (__on_exit_count == 0)
5178da39faSBernhard Rosenkraenzer 		atexit(__handle_on_exit_funcs);
5278da39faSBernhard Rosenkraenzer 	__on_exit_funcs[__on_exit_count] = function;
5378da39faSBernhard Rosenkraenzer 	__on_exit_args[__on_exit_count++] = arg;
5478da39faSBernhard Rosenkraenzer 	return 0;
5578da39faSBernhard Rosenkraenzer }
5678da39faSBernhard Rosenkraenzer 
5778da39faSBernhard Rosenkraenzer static void __handle_on_exit_funcs(void)
5878da39faSBernhard Rosenkraenzer {
5978da39faSBernhard Rosenkraenzer 	int i;
6078da39faSBernhard Rosenkraenzer 	for (i = 0; i < __on_exit_count; i++)
6178da39faSBernhard Rosenkraenzer 		__on_exit_funcs[i] (__exitcode, __on_exit_args[i]);
6278da39faSBernhard Rosenkraenzer }
6378da39faSBernhard Rosenkraenzer #endif
6478da39faSBernhard Rosenkraenzer 
65*8c6f45a7SArnaldo Carvalho de Melo struct record {
6645694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
67d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts	opts;
68d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
69f5fc1412SJiri Olsa 	struct perf_data_file	file;
70d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
71d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
72d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
73d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
74d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
75d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
76d20deb64SArnaldo Carvalho de Melo 	long			samples;
770f82ebc4SArnaldo Carvalho de Melo };
7886470930SIngo Molnar 
79*8c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size)
80f5970550SPeter Zijlstra {
81cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
824f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
838d3eca20SDavid Ahern 		return -1;
848d3eca20SDavid Ahern 	}
85f5970550SPeter Zijlstra 
86cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
878d3eca20SDavid Ahern 	return 0;
88f5970550SPeter Zijlstra }
89f5970550SPeter Zijlstra 
9045694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
91d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
921d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
931d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
94234fbbf5SArnaldo Carvalho de Melo {
95*8c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
96*8c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
97234fbbf5SArnaldo Carvalho de Melo }
98234fbbf5SArnaldo Carvalho de Melo 
99*8c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, struct perf_mmap *md)
10086470930SIngo Molnar {
101744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
10286470930SIngo Molnar 	unsigned int old = md->prev;
103918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
10486470930SIngo Molnar 	unsigned long size;
10586470930SIngo Molnar 	void *buf;
1068d3eca20SDavid Ahern 	int rc = 0;
10786470930SIngo Molnar 
108dc82009aSArnaldo Carvalho de Melo 	if (old == head)
1098d3eca20SDavid Ahern 		return 0;
11086470930SIngo Molnar 
111d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
11286470930SIngo Molnar 
11386470930SIngo Molnar 	size = head - old;
11486470930SIngo Molnar 
11586470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
11686470930SIngo Molnar 		buf = &data[old & md->mask];
11786470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
11886470930SIngo Molnar 		old += size;
11986470930SIngo Molnar 
120*8c6f45a7SArnaldo Carvalho de Melo 		if (record__write(rec, buf, size) < 0) {
1218d3eca20SDavid Ahern 			rc = -1;
1228d3eca20SDavid Ahern 			goto out;
1238d3eca20SDavid Ahern 		}
12486470930SIngo Molnar 	}
12586470930SIngo Molnar 
12686470930SIngo Molnar 	buf = &data[old & md->mask];
12786470930SIngo Molnar 	size = head - old;
12886470930SIngo Molnar 	old += size;
12986470930SIngo Molnar 
130*8c6f45a7SArnaldo Carvalho de Melo 	if (record__write(rec, buf, size) < 0) {
1318d3eca20SDavid Ahern 		rc = -1;
1328d3eca20SDavid Ahern 		goto out;
1338d3eca20SDavid Ahern 	}
13486470930SIngo Molnar 
13586470930SIngo Molnar 	md->prev = old;
136115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
1378d3eca20SDavid Ahern 
1388d3eca20SDavid Ahern out:
1398d3eca20SDavid Ahern 	return rc;
14086470930SIngo Molnar }
14186470930SIngo Molnar 
14286470930SIngo Molnar static volatile int done = 0;
143f7b7c26eSPeter Zijlstra static volatile int signr = -1;
14433e49ea7SAndi Kleen static volatile int child_finished = 0;
14586470930SIngo Molnar 
14686470930SIngo Molnar static void sig_handler(int sig)
14786470930SIngo Molnar {
14833e49ea7SAndi Kleen 	if (sig == SIGCHLD)
14933e49ea7SAndi Kleen 		child_finished = 1;
15033e49ea7SAndi Kleen 
15186470930SIngo Molnar 	done = 1;
152f7b7c26eSPeter Zijlstra 	signr = sig;
153f7b7c26eSPeter Zijlstra }
154f7b7c26eSPeter Zijlstra 
155*8c6f45a7SArnaldo Carvalho de Melo static void record__sig_exit(int exit_status __maybe_unused, void *arg)
156f7b7c26eSPeter Zijlstra {
157*8c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = arg;
15833e49ea7SAndi Kleen 	int status;
15933e49ea7SAndi Kleen 
160d20deb64SArnaldo Carvalho de Melo 	if (rec->evlist->workload.pid > 0) {
16133e49ea7SAndi Kleen 		if (!child_finished)
162d20deb64SArnaldo Carvalho de Melo 			kill(rec->evlist->workload.pid, SIGTERM);
163933da83aSChris Wilson 
16433e49ea7SAndi Kleen 		wait(&status);
16533e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
166d20deb64SArnaldo Carvalho de Melo 			psignal(WTERMSIG(status), rec->progname);
16733e49ea7SAndi Kleen 	}
16833e49ea7SAndi Kleen 
16918483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
170f7b7c26eSPeter Zijlstra 		return;
171f7b7c26eSPeter Zijlstra 
172f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
17386470930SIngo Molnar }
17486470930SIngo Molnar 
175*8c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec)
176dd7927f4SArnaldo Carvalho de Melo {
17756e52e85SArnaldo Carvalho de Melo 	char msg[512];
1786a4bb04cSJiri Olsa 	struct perf_evsel *pos;
179d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
180d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
181d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
1828d3eca20SDavid Ahern 	int rc = 0;
183dd7927f4SArnaldo Carvalho de Melo 
184f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
185cac21425SJiri Olsa 
186dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
1873da297a6SIngo Molnar try_again:
1886a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
18956e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
1903da297a6SIngo Molnar 				if (verbose)
191c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
1923da297a6SIngo Molnar 				goto try_again;
1933da297a6SIngo Molnar 			}
194ca6a4258SDavid Ahern 
19556e52e85SArnaldo Carvalho de Melo 			rc = -errno;
19656e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
19756e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
19856e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
1998d3eca20SDavid Ahern 			goto out;
2007c6a1c65SPeter Zijlstra 		}
2017c6a1c65SPeter Zijlstra 	}
2027c6a1c65SPeter Zijlstra 
2031491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
2040a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2050a102479SFrederic Weisbecker 			strerror(errno));
2068d3eca20SDavid Ahern 		rc = -1;
2078d3eca20SDavid Ahern 		goto out;
2080a102479SFrederic Weisbecker 	}
2090a102479SFrederic Weisbecker 
21018e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
2118d3eca20SDavid Ahern 		if (errno == EPERM) {
2128d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
21318e60939SNelson Elhage 			       "Consider increasing "
21418e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
21518e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
21653653d70SAdrian Hunter 			       "(current value: %u)\n", opts->mmap_pages);
2178d3eca20SDavid Ahern 			rc = -errno;
2188d3eca20SDavid Ahern 		} else {
2198d3eca20SDavid Ahern 			pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
2208d3eca20SDavid Ahern 			rc = -errno;
2218d3eca20SDavid Ahern 		}
2228d3eca20SDavid Ahern 		goto out;
22318e60939SNelson Elhage 	}
2240a27d7f9SArnaldo Carvalho de Melo 
225a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
2267b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
2278d3eca20SDavid Ahern out:
2288d3eca20SDavid Ahern 	return rc;
229a91e5431SArnaldo Carvalho de Melo }
230a91e5431SArnaldo Carvalho de Melo 
231*8c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec)
2326122e4e4SArnaldo Carvalho de Melo {
233f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
234f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
2357ab75cffSDavid Ahern 	u64 start = session->header.data_offset;
2366122e4e4SArnaldo Carvalho de Melo 
237f5fc1412SJiri Olsa 	u64 size = lseek(file->fd, 0, SEEK_CUR);
2389f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2399f591fd7SArnaldo Carvalho de Melo 		return 0;
2409f591fd7SArnaldo Carvalho de Melo 
2417ab75cffSDavid Ahern 	return __perf_session__process_events(session, start,
2427ab75cffSDavid Ahern 					      size - start,
2436122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
2446122e4e4SArnaldo Carvalho de Melo }
2456122e4e4SArnaldo Carvalho de Melo 
246*8c6f45a7SArnaldo Carvalho de Melo static void record__exit(int status, void *arg)
247f5970550SPeter Zijlstra {
248*8c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = arg;
249f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
250f5970550SPeter Zijlstra 
2518d3eca20SDavid Ahern 	if (status != 0)
2528d3eca20SDavid Ahern 		return;
2538d3eca20SDavid Ahern 
254f5fc1412SJiri Olsa 	if (!file->is_pipe) {
255d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
256d20deb64SArnaldo Carvalho de Melo 
257d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
258d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
259d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
260f5fc1412SJiri Olsa 					   file->fd, true);
261d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
262d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
263d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
264c7929e47STom Zanussi 	}
265f5970550SPeter Zijlstra }
266f5970550SPeter Zijlstra 
2678115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
268a1645ce1SZhang, Yanmin {
269a1645ce1SZhang, Yanmin 	int err;
27045694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
271a1645ce1SZhang, Yanmin 	/*
272a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
273a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
274a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
275a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
276a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
277a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
278a1645ce1SZhang, Yanmin 	 */
27945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
280743eb868SArnaldo Carvalho de Melo 					     machine);
281a1645ce1SZhang, Yanmin 	if (err < 0)
282a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
28323346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
284a1645ce1SZhang, Yanmin 
285a1645ce1SZhang, Yanmin 	/*
286a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
287a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
288a1645ce1SZhang, Yanmin 	 */
28945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
290743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
291a1645ce1SZhang, Yanmin 	if (err < 0)
29245694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
293743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
294a1645ce1SZhang, Yanmin 	if (err < 0)
295a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
29623346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
297a1645ce1SZhang, Yanmin }
298a1645ce1SZhang, Yanmin 
29998402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
30098402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
30198402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
30298402807SFrederic Weisbecker };
30398402807SFrederic Weisbecker 
304*8c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
30598402807SFrederic Weisbecker {
3060e2e63ddSPeter Zijlstra 	int i;
3078d3eca20SDavid Ahern 	int rc = 0;
30898402807SFrederic Weisbecker 
309d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
3108d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
311*8c6f45a7SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
3128d3eca20SDavid Ahern 				rc = -1;
3138d3eca20SDavid Ahern 				goto out;
3148d3eca20SDavid Ahern 			}
3158d3eca20SDavid Ahern 		}
31698402807SFrederic Weisbecker 	}
31798402807SFrederic Weisbecker 
3182eeaaa09SStephane Eranian 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
319*8c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
3208d3eca20SDavid Ahern 
3218d3eca20SDavid Ahern out:
3228d3eca20SDavid Ahern 	return rc;
32398402807SFrederic Weisbecker }
32498402807SFrederic Weisbecker 
325*8c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
32657706abcSDavid Ahern {
32757706abcSDavid Ahern 	struct perf_evlist *evsel_list = rec->evlist;
32857706abcSDavid Ahern 	struct perf_session *session = rec->session;
32957706abcSDavid Ahern 	int feat;
33057706abcSDavid Ahern 
33157706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
33257706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
33357706abcSDavid Ahern 
33457706abcSDavid Ahern 	if (rec->no_buildid)
33557706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
33657706abcSDavid Ahern 
33757706abcSDavid Ahern 	if (!have_tracepoints(&evsel_list->entries))
33857706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
33957706abcSDavid Ahern 
34057706abcSDavid Ahern 	if (!rec->opts.branch_stack)
34157706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
34257706abcSDavid Ahern }
34357706abcSDavid Ahern 
344*8c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
34586470930SIngo Molnar {
34657706abcSDavid Ahern 	int err;
3478b412664SPeter Zijlstra 	unsigned long waking = 0;
34846be604bSZhang, Yanmin 	const bool forks = argc > 0;
34923346f21SArnaldo Carvalho de Melo 	struct machine *machine;
35045694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
351d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
352d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
353f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
354d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3552711926aSJiri Olsa 	bool disabled = false;
35686470930SIngo Molnar 
357d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
35833e49ea7SAndi Kleen 
359*8c6f45a7SArnaldo Carvalho de Melo 	on_exit(record__sig_exit, rec);
360f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
361f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
36218483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
363804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
364f5970550SPeter Zijlstra 
365f5fc1412SJiri Olsa 	session = perf_session__new(file, false, NULL);
36694c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
367a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
368a9a70bbcSArnaldo Carvalho de Melo 		return -1;
369a9a70bbcSArnaldo Carvalho de Melo 	}
370a9a70bbcSArnaldo Carvalho de Melo 
371d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
372d20deb64SArnaldo Carvalho de Melo 
373*8c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
374330aa675SStephane Eranian 
375d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
3766ef73ec4SNamhyung Kim 		err = perf_evlist__prepare_workload(evsel_list, &opts->target,
377f5fc1412SJiri Olsa 						    argv, file->is_pipe,
37855e162eaSNamhyung Kim 						    true);
37935b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
38035b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
38135b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
382856e9660SPeter Zijlstra 		}
383856e9660SPeter Zijlstra 	}
384856e9660SPeter Zijlstra 
385*8c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
3868d3eca20SDavid Ahern 		err = -1;
3878d3eca20SDavid Ahern 		goto out_delete_session;
3888d3eca20SDavid Ahern 	}
38986470930SIngo Molnar 
390a8bb559bSNamhyung Kim 	if (!evsel_list->nr_groups)
391a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
392a8bb559bSNamhyung Kim 
393712a4b60SArnaldo Carvalho de Melo 	/*
394*8c6f45a7SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at record__exit()
395712a4b60SArnaldo Carvalho de Melo 	 */
396*8c6f45a7SArnaldo Carvalho de Melo 	on_exit(record__exit, rec);
397712a4b60SArnaldo Carvalho de Melo 
398f5fc1412SJiri Olsa 	if (file->is_pipe) {
399f5fc1412SJiri Olsa 		err = perf_header__write_pipe(file->fd);
400529870e3STom Zanussi 		if (err < 0)
4018d3eca20SDavid Ahern 			goto out_delete_session;
402563aecb2SJiri Olsa 	} else {
403a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
404f5fc1412SJiri Olsa 						 file->fd, false);
405d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
4068d3eca20SDavid Ahern 			goto out_delete_session;
407d5eed904SArnaldo Carvalho de Melo 	}
4087c6a1c65SPeter Zijlstra 
409d3665498SDavid Ahern 	if (!rec->no_buildid
410e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
411d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
412e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
4138d3eca20SDavid Ahern 		err = -1;
4148d3eca20SDavid Ahern 		goto out_delete_session;
415e20960c0SRobert Richter 	}
416e20960c0SRobert Richter 
41734ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
418743eb868SArnaldo Carvalho de Melo 
419f5fc1412SJiri Olsa 	if (file->is_pipe) {
42045694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
421a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
4222c46dbb5STom Zanussi 		if (err < 0) {
4232c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
4248d3eca20SDavid Ahern 			goto out_delete_session;
4252c46dbb5STom Zanussi 		}
426cd19a035STom Zanussi 
427361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
42863e0c771STom Zanussi 			/*
42963e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
43063e0c771STom Zanussi 			 * there were no tracepoints so its not really
43163e0c771STom Zanussi 			 * an error, just that we don't need to
43263e0c771STom Zanussi 			 * synthesize anything.  We really have to
43363e0c771STom Zanussi 			 * return this more properly and also
43463e0c771STom Zanussi 			 * propagate errors that now are calling die()
43563e0c771STom Zanussi 			 */
436f5fc1412SJiri Olsa 			err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list,
437743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
43863e0c771STom Zanussi 			if (err <= 0) {
43963e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
4408d3eca20SDavid Ahern 				goto out_delete_session;
44163e0c771STom Zanussi 			}
442f34b9001SDavid Ahern 			rec->bytes_written += err;
4432c46dbb5STom Zanussi 		}
44463e0c771STom Zanussi 	}
4452c46dbb5STom Zanussi 
44645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
447743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
44870162138SArnaldo Carvalho de Melo 	if (err < 0)
44945694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
450743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
451c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
452c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
453c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
454c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
45556b03f3cSArnaldo Carvalho de Melo 
45645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
457743eb868SArnaldo Carvalho de Melo 					     machine);
458c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
459c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
460c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
461c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
462c1a3a4b9SArnaldo Carvalho de Melo 
4637e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
464876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
4657e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
4667e383de4SArnaldo Carvalho de Melo 	}
467b7cece76SArnaldo Carvalho de Melo 
468a33fbd56SArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, evsel_list->threads,
46958d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
4708d3eca20SDavid Ahern 	if (err != 0)
4718d3eca20SDavid Ahern 		goto out_delete_session;
4728d3eca20SDavid Ahern 
473d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
47486470930SIngo Molnar 		struct sched_param param;
47586470930SIngo Molnar 
476d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
47786470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
4786beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
4798d3eca20SDavid Ahern 			err = -1;
4808d3eca20SDavid Ahern 			goto out_delete_session;
48186470930SIngo Molnar 		}
48286470930SIngo Molnar 	}
48386470930SIngo Molnar 
484774cb499SJiri Olsa 	/*
485774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
486774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
487774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
488774cb499SJiri Olsa 	 */
489602ad878SArnaldo Carvalho de Melo 	if (!target__none(&opts->target))
490764e16a3SDavid Ahern 		perf_evlist__enable(evsel_list);
491764e16a3SDavid Ahern 
492856e9660SPeter Zijlstra 	/*
493856e9660SPeter Zijlstra 	 * Let the child rip
494856e9660SPeter Zijlstra 	 */
495d4db3f16SArnaldo Carvalho de Melo 	if (forks)
49635b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
497856e9660SPeter Zijlstra 
498649c48a9SPeter Zijlstra 	for (;;) {
499d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
50086470930SIngo Molnar 
501*8c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
5028d3eca20SDavid Ahern 			err = -1;
5038d3eca20SDavid Ahern 			goto out_delete_session;
5048d3eca20SDavid Ahern 		}
50586470930SIngo Molnar 
506d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
507649c48a9SPeter Zijlstra 			if (done)
508649c48a9SPeter Zijlstra 				break;
5095c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
5108b412664SPeter Zijlstra 			waking++;
5118b412664SPeter Zijlstra 		}
5128b412664SPeter Zijlstra 
513774cb499SJiri Olsa 		/*
514774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
515774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
516774cb499SJiri Olsa 		 * disable events in this case.
517774cb499SJiri Olsa 		 */
518602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
5194152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
5202711926aSJiri Olsa 			disabled = true;
5212711926aSJiri Olsa 		}
5228b412664SPeter Zijlstra 	}
5238b412664SPeter Zijlstra 
52418483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
525b44308f5SArnaldo Carvalho de Melo 		return 0;
526b44308f5SArnaldo Carvalho de Melo 
5278b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
52886470930SIngo Molnar 
52986470930SIngo Molnar 	/*
53086470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
53186470930SIngo Molnar 	 */
53286470930SIngo Molnar 	fprintf(stderr,
5339486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
534d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
5356a4d98d7SJiri Olsa 		file->path,
536d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
53786470930SIngo Molnar 
53886470930SIngo Molnar 	return 0;
53939d17dacSArnaldo Carvalho de Melo 
54039d17dacSArnaldo Carvalho de Melo out_delete_session:
54139d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
54239d17dacSArnaldo Carvalho de Melo 	return err;
54386470930SIngo Molnar }
54486470930SIngo Molnar 
545bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
546bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
547bdfebd84SRoberto Agostino Vitillo 
548bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
549bdfebd84SRoberto Agostino Vitillo 
550bdfebd84SRoberto Agostino Vitillo struct branch_mode {
551bdfebd84SRoberto Agostino Vitillo 	const char *name;
552bdfebd84SRoberto Agostino Vitillo 	int mode;
553bdfebd84SRoberto Agostino Vitillo };
554bdfebd84SRoberto Agostino Vitillo 
555bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
556bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
557bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
558bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
559bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
560bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
561bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
562bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
5630126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
5640126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
5650126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
566bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
567bdfebd84SRoberto Agostino Vitillo };
568bdfebd84SRoberto Agostino Vitillo 
569bdfebd84SRoberto Agostino Vitillo static int
570a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
571bdfebd84SRoberto Agostino Vitillo {
572bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
573bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
574bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
575bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
576bdfebd84SRoberto Agostino Vitillo 
577bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
578bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
579a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
580bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
581bdfebd84SRoberto Agostino Vitillo 
582a5aabdacSStephane Eranian 	if (unset)
583a5aabdacSStephane Eranian 		return 0;
584bdfebd84SRoberto Agostino Vitillo 
585a5aabdacSStephane Eranian 	/*
586a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
587a5aabdacSStephane Eranian 	 */
588a5aabdacSStephane Eranian 	if (*mode)
589a5aabdacSStephane Eranian 		return -1;
590a5aabdacSStephane Eranian 
591a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
592a5aabdacSStephane Eranian 	if (str) {
593bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
594bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
595bdfebd84SRoberto Agostino Vitillo 		if (!s)
596bdfebd84SRoberto Agostino Vitillo 			return -1;
597bdfebd84SRoberto Agostino Vitillo 
598bdfebd84SRoberto Agostino Vitillo 		for (;;) {
599bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
600bdfebd84SRoberto Agostino Vitillo 			if (p)
601bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
602bdfebd84SRoberto Agostino Vitillo 
603bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
604bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
605bdfebd84SRoberto Agostino Vitillo 					break;
606bdfebd84SRoberto Agostino Vitillo 			}
607a5aabdacSStephane Eranian 			if (!br->name) {
608a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
609a5aabdacSStephane Eranian 					    " check man page\n", s);
610bdfebd84SRoberto Agostino Vitillo 				goto error;
611a5aabdacSStephane Eranian 			}
612bdfebd84SRoberto Agostino Vitillo 
613bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
614bdfebd84SRoberto Agostino Vitillo 
615bdfebd84SRoberto Agostino Vitillo 			if (!p)
616bdfebd84SRoberto Agostino Vitillo 				break;
617bdfebd84SRoberto Agostino Vitillo 
618bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
619bdfebd84SRoberto Agostino Vitillo 		}
620a5aabdacSStephane Eranian 	}
621bdfebd84SRoberto Agostino Vitillo 	ret = 0;
622bdfebd84SRoberto Agostino Vitillo 
623a5aabdacSStephane Eranian 	/* default to any branch */
624bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
625a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
626bdfebd84SRoberto Agostino Vitillo 	}
627bdfebd84SRoberto Agostino Vitillo error:
628bdfebd84SRoberto Agostino Vitillo 	free(os);
629bdfebd84SRoberto Agostino Vitillo 	return ret;
630bdfebd84SRoberto Agostino Vitillo }
631bdfebd84SRoberto Agostino Vitillo 
63289fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
63326d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size)
63426d33022SJiri Olsa {
63526d33022SJiri Olsa 	char *endptr;
63626d33022SJiri Olsa 	unsigned long size;
63726d33022SJiri Olsa 	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
63826d33022SJiri Olsa 
63926d33022SJiri Olsa 	size = strtoul(str, &endptr, 0);
64026d33022SJiri Olsa 
64126d33022SJiri Olsa 	do {
64226d33022SJiri Olsa 		if (*endptr)
64326d33022SJiri Olsa 			break;
64426d33022SJiri Olsa 
64526d33022SJiri Olsa 		size = round_up(size, sizeof(u64));
64626d33022SJiri Olsa 		if (!size || size > max_size)
64726d33022SJiri Olsa 			break;
64826d33022SJiri Olsa 
64926d33022SJiri Olsa 		*_size = size;
65026d33022SJiri Olsa 		return 0;
65126d33022SJiri Olsa 
65226d33022SJiri Olsa 	} while (0);
65326d33022SJiri Olsa 
65426d33022SJiri Olsa 	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
65526d33022SJiri Olsa 	       max_size, str);
65626d33022SJiri Olsa 	return -1;
65726d33022SJiri Olsa }
65889fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */
65926d33022SJiri Olsa 
66009b0fd45SJiri Olsa int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
66126d33022SJiri Olsa {
66226d33022SJiri Olsa 	char *tok, *name, *saveptr = NULL;
66326d33022SJiri Olsa 	char *buf;
66426d33022SJiri Olsa 	int ret = -1;
66526d33022SJiri Olsa 
66626d33022SJiri Olsa 	/* We need buffer that we know we can write to. */
66726d33022SJiri Olsa 	buf = malloc(strlen(arg) + 1);
66826d33022SJiri Olsa 	if (!buf)
66926d33022SJiri Olsa 		return -ENOMEM;
67026d33022SJiri Olsa 
67126d33022SJiri Olsa 	strcpy(buf, arg);
67226d33022SJiri Olsa 
67326d33022SJiri Olsa 	tok = strtok_r((char *)buf, ",", &saveptr);
67426d33022SJiri Olsa 	name = tok ? : (char *)buf;
67526d33022SJiri Olsa 
67626d33022SJiri Olsa 	do {
67726d33022SJiri Olsa 		/* Framepointer style */
67826d33022SJiri Olsa 		if (!strncmp(name, "fp", sizeof("fp"))) {
67926d33022SJiri Olsa 			if (!strtok_r(NULL, ",", &saveptr)) {
680c5ff78c3SArnaldo Carvalho de Melo 				opts->call_graph = CALLCHAIN_FP;
68126d33022SJiri Olsa 				ret = 0;
68226d33022SJiri Olsa 			} else
68326d33022SJiri Olsa 				pr_err("callchain: No more arguments "
68426d33022SJiri Olsa 				       "needed for -g fp\n");
68526d33022SJiri Olsa 			break;
68626d33022SJiri Olsa 
68789fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
68826d33022SJiri Olsa 		/* Dwarf style */
68926d33022SJiri Olsa 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
69061eaa3beSArnaldo Carvalho de Melo 			const unsigned long default_stack_dump_size = 8192;
69161eaa3beSArnaldo Carvalho de Melo 
69226d33022SJiri Olsa 			ret = 0;
693c5ff78c3SArnaldo Carvalho de Melo 			opts->call_graph = CALLCHAIN_DWARF;
694c5ff78c3SArnaldo Carvalho de Melo 			opts->stack_dump_size = default_stack_dump_size;
69526d33022SJiri Olsa 
69626d33022SJiri Olsa 			tok = strtok_r(NULL, ",", &saveptr);
69726d33022SJiri Olsa 			if (tok) {
69826d33022SJiri Olsa 				unsigned long size = 0;
69926d33022SJiri Olsa 
70026d33022SJiri Olsa 				ret = get_stack_size(tok, &size);
701c5ff78c3SArnaldo Carvalho de Melo 				opts->stack_dump_size = size;
70226d33022SJiri Olsa 			}
70389fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */
70426d33022SJiri Olsa 		} else {
70509b0fd45SJiri Olsa 			pr_err("callchain: Unknown --call-graph option "
70626d33022SJiri Olsa 			       "value: %s\n", arg);
70726d33022SJiri Olsa 			break;
70826d33022SJiri Olsa 		}
70926d33022SJiri Olsa 
71026d33022SJiri Olsa 	} while (0);
71126d33022SJiri Olsa 
71226d33022SJiri Olsa 	free(buf);
71309b0fd45SJiri Olsa 	return ret;
71409b0fd45SJiri Olsa }
71526d33022SJiri Olsa 
71609b0fd45SJiri Olsa static void callchain_debug(struct perf_record_opts *opts)
71709b0fd45SJiri Olsa {
718c5ff78c3SArnaldo Carvalho de Melo 	pr_debug("callchain: type %d\n", opts->call_graph);
71926d33022SJiri Olsa 
72009b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_DWARF)
72109b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
72209b0fd45SJiri Olsa 			 opts->stack_dump_size);
72309b0fd45SJiri Olsa }
72409b0fd45SJiri Olsa 
72509b0fd45SJiri Olsa int record_parse_callchain_opt(const struct option *opt,
72609b0fd45SJiri Olsa 			       const char *arg,
72709b0fd45SJiri Olsa 			       int unset)
72809b0fd45SJiri Olsa {
72909b0fd45SJiri Olsa 	struct perf_record_opts *opts = opt->value;
73009b0fd45SJiri Olsa 	int ret;
73109b0fd45SJiri Olsa 
73209b0fd45SJiri Olsa 	/* --no-call-graph */
73309b0fd45SJiri Olsa 	if (unset) {
73409b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_NONE;
73509b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
73609b0fd45SJiri Olsa 		return 0;
73709b0fd45SJiri Olsa 	}
73809b0fd45SJiri Olsa 
73909b0fd45SJiri Olsa 	ret = record_parse_callchain(arg, opts);
74009b0fd45SJiri Olsa 	if (!ret)
74109b0fd45SJiri Olsa 		callchain_debug(opts);
74209b0fd45SJiri Olsa 
74326d33022SJiri Olsa 	return ret;
74426d33022SJiri Olsa }
74526d33022SJiri Olsa 
74609b0fd45SJiri Olsa int record_callchain_opt(const struct option *opt,
74709b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
74809b0fd45SJiri Olsa 			 int unset __maybe_unused)
74909b0fd45SJiri Olsa {
75009b0fd45SJiri Olsa 	struct perf_record_opts *opts = opt->value;
75109b0fd45SJiri Olsa 
75209b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_NONE)
75309b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_FP;
75409b0fd45SJiri Olsa 
75509b0fd45SJiri Olsa 	callchain_debug(opts);
75609b0fd45SJiri Olsa 	return 0;
75709b0fd45SJiri Olsa }
75809b0fd45SJiri Olsa 
75986470930SIngo Molnar static const char * const record_usage[] = {
76086470930SIngo Molnar 	"perf record [<options>] [<command>]",
76186470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
76286470930SIngo Molnar 	NULL
76386470930SIngo Molnar };
76486470930SIngo Molnar 
765d20deb64SArnaldo Carvalho de Melo /*
766*8c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
767*8c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
768d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
769d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
770d20deb64SArnaldo Carvalho de Melo  *
771d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
772d20deb64SArnaldo Carvalho de Melo  *
773d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
774d20deb64SArnaldo Carvalho de Melo  */
775*8c6f45a7SArnaldo Carvalho de Melo static struct record record = {
776d20deb64SArnaldo Carvalho de Melo 	.opts = {
777d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
778d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
779d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
780447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
781d1cb9fceSNamhyung Kim 		.target		     = {
782d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
7833aa5939dSAdrian Hunter 			.default_per_cpu = true,
784d1cb9fceSNamhyung Kim 		},
785d20deb64SArnaldo Carvalho de Melo 	},
786d20deb64SArnaldo Carvalho de Melo };
7877865e817SFrederic Weisbecker 
78809b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
78961eaa3beSArnaldo Carvalho de Melo 
79089fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
79109b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
79261eaa3beSArnaldo Carvalho de Melo #else
79309b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp";
79461eaa3beSArnaldo Carvalho de Melo #endif
79561eaa3beSArnaldo Carvalho de Melo 
796d20deb64SArnaldo Carvalho de Melo /*
797d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
798d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
799d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
800d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
801d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
802d20deb64SArnaldo Carvalho de Melo  */
803bca647aaSTom Zanussi const struct option record_options[] = {
804d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
80586470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
806f120f9d5SJiri Olsa 		     parse_events_option),
807d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
808c171b552SLi Zefan 		     "event filter", parse_filter),
809bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
810d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
811bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
812d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
813d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
81486470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
815d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
816acac03faSKirill Smelkov 		    "collect data without buffering"),
817d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
818daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
819bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
82086470930SIngo Molnar 			    "system-wide collection from all CPUs"),
821bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
822c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
823d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
824f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
82586470930SIngo Molnar 		    "output file name"),
82669e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
82769e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
8282e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
829d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
830994a1f78SJiri Olsa 	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
831994a1f78SJiri Olsa 		     "number of mmap data pages",
832994a1f78SJiri Olsa 		     perf_evlist__parse_mmap_pages),
833d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
83443bece79SLin Ming 		    "put the counters into a counter group"),
83509b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
83609b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
83709b0fd45SJiri Olsa 			   &record_callchain_opt),
83809b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
83975d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
84009b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
841c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8423da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
843b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
844d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
845649c48a9SPeter Zijlstra 		    "per thread counts"),
846d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8474bba828dSAnton Blanchard 		    "Sample addresses"),
848d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8493e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
850d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
851649c48a9SPeter Zijlstra 		    "don't sample"),
852d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
853a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
854d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
855baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
856d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
857023695d9SStephane Eranian 		     "monitor event in cgroup name only",
858023695d9SStephane Eranian 		     parse_cgroups),
859bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
860bea03405SNamhyung Kim 		   "user to profile"),
861a5aabdacSStephane Eranian 
862a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
863a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
864a5aabdacSStephane Eranian 		     parse_branch_stack),
865a5aabdacSStephane Eranian 
866a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
867a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
868bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
86905484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
87005484298SAndi Kleen 		    "sample by weight (on special events only)"),
871475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
872475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
8733aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
8743aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
87586470930SIngo Molnar 	OPT_END()
87686470930SIngo Molnar };
87786470930SIngo Molnar 
8781d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
87986470930SIngo Molnar {
88069aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
881d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
882*8c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
88316ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
88486470930SIngo Molnar 
885334fe7a3SNamhyung Kim 	evsel_list = perf_evlist__new();
886361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
887361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
888361c99a6SArnaldo Carvalho de Melo 
889d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
890d20deb64SArnaldo Carvalho de Melo 
891bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
892a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
893602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
894bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
89586470930SIngo Molnar 
896bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
8973780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
898023695d9SStephane Eranian 			  " system-wide mode\n");
899023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
900023695d9SStephane Eranian 	}
901023695d9SStephane Eranian 
902655000e7SArnaldo Carvalho de Melo 	symbol__init();
903baa2f6ceSArnaldo Carvalho de Melo 
904ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
905646aaea6SArnaldo Carvalho de Melo 		pr_warning(
906646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
907ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
908646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
909646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
910646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
911646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
912646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
913ec80fde7SArnaldo Carvalho de Melo 
914d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
915a1ac1d3cSStephane Eranian 		disable_buildid_cache();
916655000e7SArnaldo Carvalho de Melo 
917361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
918361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
91969aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
92069aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
921bbd36e5eSPeter Zijlstra 	}
92286470930SIngo Molnar 
92369e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
92469e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
92569e7e5b0SAdrian Hunter 
926602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
92716ad2ffbSNamhyung Kim 	if (err) {
928602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
92916ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
93016ad2ffbSNamhyung Kim 	}
9314bd0f2d2SNamhyung Kim 
932602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
93316ad2ffbSNamhyung Kim 	if (err) {
93416ad2ffbSNamhyung Kim 		int saved_errno = errno;
93516ad2ffbSNamhyung Kim 
936602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9373780f488SNamhyung Kim 		ui__error("%s", errbuf);
93816ad2ffbSNamhyung Kim 
93916ad2ffbSNamhyung Kim 		err = -saved_errno;
9408fa60e1fSNamhyung Kim 		goto out_symbol_exit;
94116ad2ffbSNamhyung Kim 	}
9420d37aa34SArnaldo Carvalho de Melo 
94316ad2ffbSNamhyung Kim 	err = -ENOMEM;
944b809ac10SNamhyung Kim 	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
945dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
94669aad6f1SArnaldo Carvalho de Melo 
947714647bdSJiri Olsa 	if (perf_record_opts__config(&rec->opts)) {
94839d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
9495c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
9507e4ff9e3SMike Galbraith 	}
9517e4ff9e3SMike Galbraith 
952d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
9538fa60e1fSNamhyung Kim 
9548fa60e1fSNamhyung Kim 	perf_evlist__munmap(evsel_list);
9558fa60e1fSNamhyung Kim 	perf_evlist__close(evsel_list);
95639d17dacSArnaldo Carvalho de Melo out_free_fd:
9577e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
958d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
959d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
96039d17dacSArnaldo Carvalho de Melo 	return err;
96186470930SIngo Molnar }
962