xref: /openbmc/linux/tools/perf/builtin-record.c (revision ffa91880a992ec1aaee4b4f7c9ddffda0c277ba9)
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 
658c6f45a7SArnaldo Carvalho de Melo struct record {
6645694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
67b4006796SArnaldo Carvalho de Melo 	struct 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 
798c6f45a7SArnaldo 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 {
958c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = container_of(tool, struct record, tool);
968c6f45a7SArnaldo Carvalho de Melo 	return record__write(rec, event, event->header.size);
97234fbbf5SArnaldo Carvalho de Melo }
98234fbbf5SArnaldo Carvalho de Melo 
998c6f45a7SArnaldo 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 
1208c6f45a7SArnaldo 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 
1308c6f45a7SArnaldo 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 
1558c6f45a7SArnaldo Carvalho de Melo static void record__sig_exit(int exit_status __maybe_unused, void *arg)
156f7b7c26eSPeter Zijlstra {
1578c6f45a7SArnaldo 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 
1758c6f45a7SArnaldo 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;
181b4006796SArnaldo Carvalho de Melo 	struct 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 
1860050f7aaSArnaldo Carvalho de Melo 	evlist__for_each(evlist, pos) {
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 
2318c6f45a7SArnaldo 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 
2468c6f45a7SArnaldo Carvalho de Melo static void record__exit(int status, void *arg)
247f5970550SPeter Zijlstra {
2488c6f45a7SArnaldo 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,
2900ae617beSAdrian Hunter 						 machine);
291a1645ce1SZhang, Yanmin 	if (err < 0)
292a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
29323346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
294a1645ce1SZhang, Yanmin }
295a1645ce1SZhang, Yanmin 
29698402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
29798402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
29898402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
29998402807SFrederic Weisbecker };
30098402807SFrederic Weisbecker 
3018c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec)
30298402807SFrederic Weisbecker {
3030e2e63ddSPeter Zijlstra 	int i;
3048d3eca20SDavid Ahern 	int rc = 0;
30598402807SFrederic Weisbecker 
306d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
3078d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
3088c6f45a7SArnaldo Carvalho de Melo 			if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
3098d3eca20SDavid Ahern 				rc = -1;
3108d3eca20SDavid Ahern 				goto out;
3118d3eca20SDavid Ahern 			}
3128d3eca20SDavid Ahern 		}
31398402807SFrederic Weisbecker 	}
31498402807SFrederic Weisbecker 
3152eeaaa09SStephane Eranian 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
3168c6f45a7SArnaldo Carvalho de Melo 		rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
3178d3eca20SDavid Ahern 
3188d3eca20SDavid Ahern out:
3198d3eca20SDavid Ahern 	return rc;
32098402807SFrederic Weisbecker }
32198402807SFrederic Weisbecker 
3228c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec)
32357706abcSDavid Ahern {
32457706abcSDavid Ahern 	struct perf_session *session = rec->session;
32557706abcSDavid Ahern 	int feat;
32657706abcSDavid Ahern 
32757706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
32857706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
32957706abcSDavid Ahern 
33057706abcSDavid Ahern 	if (rec->no_buildid)
33157706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
33257706abcSDavid Ahern 
3333e2be2daSArnaldo Carvalho de Melo 	if (!have_tracepoints(&rec->evlist->entries))
33457706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
33557706abcSDavid Ahern 
33657706abcSDavid Ahern 	if (!rec->opts.branch_stack)
33757706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
33857706abcSDavid Ahern }
33957706abcSDavid Ahern 
340f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno;
341f33cbe72SArnaldo Carvalho de Melo 
342f33cbe72SArnaldo Carvalho de Melo /*
343f33cbe72SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload will send a SIGUSR1
344f33cbe72SArnaldo Carvalho de Melo  * if the fork fails, since we asked by setting its
345f33cbe72SArnaldo Carvalho de Melo  * want_signal to true.
346f33cbe72SArnaldo Carvalho de Melo  */
347f33cbe72SArnaldo Carvalho de Melo static void workload_exec_failed_signal(int signo, siginfo_t *info,
348f33cbe72SArnaldo Carvalho de Melo 					void *ucontext __maybe_unused)
349f33cbe72SArnaldo Carvalho de Melo {
350f33cbe72SArnaldo Carvalho de Melo 	workload_exec_errno = info->si_value.sival_int;
351f33cbe72SArnaldo Carvalho de Melo 	done = 1;
352f33cbe72SArnaldo Carvalho de Melo 	signr = signo;
353f33cbe72SArnaldo Carvalho de Melo 	child_finished = 1;
354f33cbe72SArnaldo Carvalho de Melo }
355f33cbe72SArnaldo Carvalho de Melo 
3568c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv)
35786470930SIngo Molnar {
35857706abcSDavid Ahern 	int err;
3598b412664SPeter Zijlstra 	unsigned long waking = 0;
36046be604bSZhang, Yanmin 	const bool forks = argc > 0;
36123346f21SArnaldo Carvalho de Melo 	struct machine *machine;
36245694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
363b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = &rec->opts;
364f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
365d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3662711926aSJiri Olsa 	bool disabled = false;
36786470930SIngo Molnar 
368d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
36933e49ea7SAndi Kleen 
3708c6f45a7SArnaldo Carvalho de Melo 	on_exit(record__sig_exit, rec);
371f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
372f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
373804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
374f5970550SPeter Zijlstra 
375f5fc1412SJiri Olsa 	session = perf_session__new(file, false, NULL);
37694c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
377*ffa91880SAdrien BAK 		pr_err("Perf session creation failed.\n");
378a9a70bbcSArnaldo Carvalho de Melo 		return -1;
379a9a70bbcSArnaldo Carvalho de Melo 	}
380a9a70bbcSArnaldo Carvalho de Melo 
381d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
382d20deb64SArnaldo Carvalho de Melo 
3838c6f45a7SArnaldo Carvalho de Melo 	record__init_features(rec);
384330aa675SStephane Eranian 
385d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
3863e2be2daSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
387f5fc1412SJiri Olsa 						    argv, file->is_pipe,
388735f7e0bSArnaldo Carvalho de Melo 						    workload_exec_failed_signal);
38935b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
39035b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
39135b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
392856e9660SPeter Zijlstra 		}
393856e9660SPeter Zijlstra 	}
394856e9660SPeter Zijlstra 
3958c6f45a7SArnaldo Carvalho de Melo 	if (record__open(rec) != 0) {
3968d3eca20SDavid Ahern 		err = -1;
3978d3eca20SDavid Ahern 		goto out_delete_session;
3988d3eca20SDavid Ahern 	}
39986470930SIngo Molnar 
4003e2be2daSArnaldo Carvalho de Melo 	if (!rec->evlist->nr_groups)
401a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
402a8bb559bSNamhyung Kim 
403712a4b60SArnaldo Carvalho de Melo 	/*
4048c6f45a7SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at record__exit()
405712a4b60SArnaldo Carvalho de Melo 	 */
4068c6f45a7SArnaldo Carvalho de Melo 	on_exit(record__exit, rec);
407712a4b60SArnaldo Carvalho de Melo 
408f5fc1412SJiri Olsa 	if (file->is_pipe) {
409f5fc1412SJiri Olsa 		err = perf_header__write_pipe(file->fd);
410529870e3STom Zanussi 		if (err < 0)
4118d3eca20SDavid Ahern 			goto out_delete_session;
412563aecb2SJiri Olsa 	} else {
4133e2be2daSArnaldo Carvalho de Melo 		err = perf_session__write_header(session, rec->evlist,
414f5fc1412SJiri Olsa 						 file->fd, false);
415d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
4168d3eca20SDavid Ahern 			goto out_delete_session;
417d5eed904SArnaldo Carvalho de Melo 	}
4187c6a1c65SPeter Zijlstra 
419d3665498SDavid Ahern 	if (!rec->no_buildid
420e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
421d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
422e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
4238d3eca20SDavid Ahern 		err = -1;
4248d3eca20SDavid Ahern 		goto out_delete_session;
425e20960c0SRobert Richter 	}
426e20960c0SRobert Richter 
42734ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
428743eb868SArnaldo Carvalho de Melo 
429f5fc1412SJiri Olsa 	if (file->is_pipe) {
43045694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
431a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
4322c46dbb5STom Zanussi 		if (err < 0) {
4332c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
4348d3eca20SDavid Ahern 			goto out_delete_session;
4352c46dbb5STom Zanussi 		}
436cd19a035STom Zanussi 
4373e2be2daSArnaldo Carvalho de Melo 		if (have_tracepoints(&rec->evlist->entries)) {
43863e0c771STom Zanussi 			/*
43963e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
44063e0c771STom Zanussi 			 * there were no tracepoints so its not really
44163e0c771STom Zanussi 			 * an error, just that we don't need to
44263e0c771STom Zanussi 			 * synthesize anything.  We really have to
44363e0c771STom Zanussi 			 * return this more properly and also
44463e0c771STom Zanussi 			 * propagate errors that now are calling die()
44563e0c771STom Zanussi 			 */
4463e2be2daSArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist,
447743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
44863e0c771STom Zanussi 			if (err <= 0) {
44963e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
4508d3eca20SDavid Ahern 				goto out_delete_session;
45163e0c771STom Zanussi 			}
452f34b9001SDavid Ahern 			rec->bytes_written += err;
4532c46dbb5STom Zanussi 		}
45463e0c771STom Zanussi 	}
4552c46dbb5STom Zanussi 
45645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
4570ae617beSAdrian Hunter 						 machine);
458c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
459c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
460c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
461c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
46256b03f3cSArnaldo Carvalho de Melo 
46345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
464743eb868SArnaldo Carvalho de Melo 					     machine);
465c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
466c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
467c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
468c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
469c1a3a4b9SArnaldo Carvalho de Melo 
4707e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
471876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
4727e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
4737e383de4SArnaldo Carvalho de Melo 	}
474b7cece76SArnaldo Carvalho de Melo 
4753e2be2daSArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
47658d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
4778d3eca20SDavid Ahern 	if (err != 0)
4788d3eca20SDavid Ahern 		goto out_delete_session;
4798d3eca20SDavid Ahern 
480d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
48186470930SIngo Molnar 		struct sched_param param;
48286470930SIngo Molnar 
483d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
48486470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
4856beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
4868d3eca20SDavid Ahern 			err = -1;
4878d3eca20SDavid Ahern 			goto out_delete_session;
48886470930SIngo Molnar 		}
48986470930SIngo Molnar 	}
49086470930SIngo Molnar 
491774cb499SJiri Olsa 	/*
492774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
493774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
494774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
495774cb499SJiri Olsa 	 */
4966619a53eSAndi Kleen 	if (!target__none(&opts->target) && !opts->initial_delay)
4973e2be2daSArnaldo Carvalho de Melo 		perf_evlist__enable(rec->evlist);
498764e16a3SDavid Ahern 
499856e9660SPeter Zijlstra 	/*
500856e9660SPeter Zijlstra 	 * Let the child rip
501856e9660SPeter Zijlstra 	 */
502735f7e0bSArnaldo Carvalho de Melo 	if (forks)
5033e2be2daSArnaldo Carvalho de Melo 		perf_evlist__start_workload(rec->evlist);
504856e9660SPeter Zijlstra 
5056619a53eSAndi Kleen 	if (opts->initial_delay) {
5066619a53eSAndi Kleen 		usleep(opts->initial_delay * 1000);
5076619a53eSAndi Kleen 		perf_evlist__enable(rec->evlist);
5086619a53eSAndi Kleen 	}
5096619a53eSAndi Kleen 
510649c48a9SPeter Zijlstra 	for (;;) {
511d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
51286470930SIngo Molnar 
5138c6f45a7SArnaldo Carvalho de Melo 		if (record__mmap_read_all(rec) < 0) {
5148d3eca20SDavid Ahern 			err = -1;
5158d3eca20SDavid Ahern 			goto out_delete_session;
5168d3eca20SDavid Ahern 		}
51786470930SIngo Molnar 
518d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
519649c48a9SPeter Zijlstra 			if (done)
520649c48a9SPeter Zijlstra 				break;
5213e2be2daSArnaldo Carvalho de Melo 			err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1);
5228b412664SPeter Zijlstra 			waking++;
5238b412664SPeter Zijlstra 		}
5248b412664SPeter Zijlstra 
525774cb499SJiri Olsa 		/*
526774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
527774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
528774cb499SJiri Olsa 		 * disable events in this case.
529774cb499SJiri Olsa 		 */
530602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
5313e2be2daSArnaldo Carvalho de Melo 			perf_evlist__disable(rec->evlist);
5322711926aSJiri Olsa 			disabled = true;
5332711926aSJiri Olsa 		}
5348b412664SPeter Zijlstra 	}
5358b412664SPeter Zijlstra 
536f33cbe72SArnaldo Carvalho de Melo 	if (forks && workload_exec_errno) {
537f33cbe72SArnaldo Carvalho de Melo 		char msg[512];
538f33cbe72SArnaldo Carvalho de Melo 		const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
539f33cbe72SArnaldo Carvalho de Melo 		pr_err("Workload failed: %s\n", emsg);
540f33cbe72SArnaldo Carvalho de Melo 		err = -1;
541f33cbe72SArnaldo Carvalho de Melo 		goto out_delete_session;
542f33cbe72SArnaldo Carvalho de Melo 	}
543f33cbe72SArnaldo Carvalho de Melo 
54418483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
545b44308f5SArnaldo Carvalho de Melo 		return 0;
546b44308f5SArnaldo Carvalho de Melo 
5478b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
54886470930SIngo Molnar 
54986470930SIngo Molnar 	/*
55086470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
55186470930SIngo Molnar 	 */
55286470930SIngo Molnar 	fprintf(stderr,
5539486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
554d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
5556a4d98d7SJiri Olsa 		file->path,
556d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
55786470930SIngo Molnar 
55886470930SIngo Molnar 	return 0;
55939d17dacSArnaldo Carvalho de Melo 
56039d17dacSArnaldo Carvalho de Melo out_delete_session:
56139d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
56239d17dacSArnaldo Carvalho de Melo 	return err;
56386470930SIngo Molnar }
56486470930SIngo Molnar 
565bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
566bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
567bdfebd84SRoberto Agostino Vitillo 
568bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
569bdfebd84SRoberto Agostino Vitillo 
570bdfebd84SRoberto Agostino Vitillo struct branch_mode {
571bdfebd84SRoberto Agostino Vitillo 	const char *name;
572bdfebd84SRoberto Agostino Vitillo 	int mode;
573bdfebd84SRoberto Agostino Vitillo };
574bdfebd84SRoberto Agostino Vitillo 
575bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
576bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
577bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
578bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
579bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
580bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
581bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
582bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
5830126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
5840126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
5850126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
586bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
587bdfebd84SRoberto Agostino Vitillo };
588bdfebd84SRoberto Agostino Vitillo 
589bdfebd84SRoberto Agostino Vitillo static int
590a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
591bdfebd84SRoberto Agostino Vitillo {
592bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
593bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
594bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
595bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
596bdfebd84SRoberto Agostino Vitillo 
597bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
598bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
599a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
600bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
601bdfebd84SRoberto Agostino Vitillo 
602a5aabdacSStephane Eranian 	if (unset)
603a5aabdacSStephane Eranian 		return 0;
604bdfebd84SRoberto Agostino Vitillo 
605a5aabdacSStephane Eranian 	/*
606a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
607a5aabdacSStephane Eranian 	 */
608a5aabdacSStephane Eranian 	if (*mode)
609a5aabdacSStephane Eranian 		return -1;
610a5aabdacSStephane Eranian 
611a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
612a5aabdacSStephane Eranian 	if (str) {
613bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
614bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
615bdfebd84SRoberto Agostino Vitillo 		if (!s)
616bdfebd84SRoberto Agostino Vitillo 			return -1;
617bdfebd84SRoberto Agostino Vitillo 
618bdfebd84SRoberto Agostino Vitillo 		for (;;) {
619bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
620bdfebd84SRoberto Agostino Vitillo 			if (p)
621bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
622bdfebd84SRoberto Agostino Vitillo 
623bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
624bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
625bdfebd84SRoberto Agostino Vitillo 					break;
626bdfebd84SRoberto Agostino Vitillo 			}
627a5aabdacSStephane Eranian 			if (!br->name) {
628a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
629a5aabdacSStephane Eranian 					    " check man page\n", s);
630bdfebd84SRoberto Agostino Vitillo 				goto error;
631a5aabdacSStephane Eranian 			}
632bdfebd84SRoberto Agostino Vitillo 
633bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
634bdfebd84SRoberto Agostino Vitillo 
635bdfebd84SRoberto Agostino Vitillo 			if (!p)
636bdfebd84SRoberto Agostino Vitillo 				break;
637bdfebd84SRoberto Agostino Vitillo 
638bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
639bdfebd84SRoberto Agostino Vitillo 		}
640a5aabdacSStephane Eranian 	}
641bdfebd84SRoberto Agostino Vitillo 	ret = 0;
642bdfebd84SRoberto Agostino Vitillo 
643a5aabdacSStephane Eranian 	/* default to any branch */
644bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
645a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
646bdfebd84SRoberto Agostino Vitillo 	}
647bdfebd84SRoberto Agostino Vitillo error:
648bdfebd84SRoberto Agostino Vitillo 	free(os);
649bdfebd84SRoberto Agostino Vitillo 	return ret;
650bdfebd84SRoberto Agostino Vitillo }
651bdfebd84SRoberto Agostino Vitillo 
6529ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
65326d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size)
65426d33022SJiri Olsa {
65526d33022SJiri Olsa 	char *endptr;
65626d33022SJiri Olsa 	unsigned long size;
65726d33022SJiri Olsa 	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
65826d33022SJiri Olsa 
65926d33022SJiri Olsa 	size = strtoul(str, &endptr, 0);
66026d33022SJiri Olsa 
66126d33022SJiri Olsa 	do {
66226d33022SJiri Olsa 		if (*endptr)
66326d33022SJiri Olsa 			break;
66426d33022SJiri Olsa 
66526d33022SJiri Olsa 		size = round_up(size, sizeof(u64));
66626d33022SJiri Olsa 		if (!size || size > max_size)
66726d33022SJiri Olsa 			break;
66826d33022SJiri Olsa 
66926d33022SJiri Olsa 		*_size = size;
67026d33022SJiri Olsa 		return 0;
67126d33022SJiri Olsa 
67226d33022SJiri Olsa 	} while (0);
67326d33022SJiri Olsa 
67426d33022SJiri Olsa 	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
67526d33022SJiri Olsa 	       max_size, str);
67626d33022SJiri Olsa 	return -1;
67726d33022SJiri Olsa }
6789ff125d1SJiri Olsa #endif /* HAVE_DWARF_UNWIND_SUPPORT */
67926d33022SJiri Olsa 
680b4006796SArnaldo Carvalho de Melo int record_parse_callchain(const char *arg, struct record_opts *opts)
68126d33022SJiri Olsa {
68226d33022SJiri Olsa 	char *tok, *name, *saveptr = NULL;
68326d33022SJiri Olsa 	char *buf;
68426d33022SJiri Olsa 	int ret = -1;
68526d33022SJiri Olsa 
68626d33022SJiri Olsa 	/* We need buffer that we know we can write to. */
68726d33022SJiri Olsa 	buf = malloc(strlen(arg) + 1);
68826d33022SJiri Olsa 	if (!buf)
68926d33022SJiri Olsa 		return -ENOMEM;
69026d33022SJiri Olsa 
69126d33022SJiri Olsa 	strcpy(buf, arg);
69226d33022SJiri Olsa 
69326d33022SJiri Olsa 	tok = strtok_r((char *)buf, ",", &saveptr);
69426d33022SJiri Olsa 	name = tok ? : (char *)buf;
69526d33022SJiri Olsa 
69626d33022SJiri Olsa 	do {
69726d33022SJiri Olsa 		/* Framepointer style */
69826d33022SJiri Olsa 		if (!strncmp(name, "fp", sizeof("fp"))) {
69926d33022SJiri Olsa 			if (!strtok_r(NULL, ",", &saveptr)) {
700c5ff78c3SArnaldo Carvalho de Melo 				opts->call_graph = CALLCHAIN_FP;
70126d33022SJiri Olsa 				ret = 0;
70226d33022SJiri Olsa 			} else
70326d33022SJiri Olsa 				pr_err("callchain: No more arguments "
70426d33022SJiri Olsa 				       "needed for -g fp\n");
70526d33022SJiri Olsa 			break;
70626d33022SJiri Olsa 
7079ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
70826d33022SJiri Olsa 		/* Dwarf style */
70926d33022SJiri Olsa 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
71061eaa3beSArnaldo Carvalho de Melo 			const unsigned long default_stack_dump_size = 8192;
71161eaa3beSArnaldo Carvalho de Melo 
71226d33022SJiri Olsa 			ret = 0;
713c5ff78c3SArnaldo Carvalho de Melo 			opts->call_graph = CALLCHAIN_DWARF;
714c5ff78c3SArnaldo Carvalho de Melo 			opts->stack_dump_size = default_stack_dump_size;
71526d33022SJiri Olsa 
71626d33022SJiri Olsa 			tok = strtok_r(NULL, ",", &saveptr);
71726d33022SJiri Olsa 			if (tok) {
71826d33022SJiri Olsa 				unsigned long size = 0;
71926d33022SJiri Olsa 
72026d33022SJiri Olsa 				ret = get_stack_size(tok, &size);
721c5ff78c3SArnaldo Carvalho de Melo 				opts->stack_dump_size = size;
72226d33022SJiri Olsa 			}
7239ff125d1SJiri Olsa #endif /* HAVE_DWARF_UNWIND_SUPPORT */
72426d33022SJiri Olsa 		} else {
72509b0fd45SJiri Olsa 			pr_err("callchain: Unknown --call-graph option "
72626d33022SJiri Olsa 			       "value: %s\n", arg);
72726d33022SJiri Olsa 			break;
72826d33022SJiri Olsa 		}
72926d33022SJiri Olsa 
73026d33022SJiri Olsa 	} while (0);
73126d33022SJiri Olsa 
73226d33022SJiri Olsa 	free(buf);
73309b0fd45SJiri Olsa 	return ret;
73409b0fd45SJiri Olsa }
73526d33022SJiri Olsa 
736b4006796SArnaldo Carvalho de Melo static void callchain_debug(struct record_opts *opts)
73709b0fd45SJiri Olsa {
738a601fdffSJiri Olsa 	static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
739a601fdffSJiri Olsa 
740a601fdffSJiri Olsa 	pr_debug("callchain: type %s\n", str[opts->call_graph]);
74126d33022SJiri Olsa 
74209b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_DWARF)
74309b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
74409b0fd45SJiri Olsa 			 opts->stack_dump_size);
74509b0fd45SJiri Olsa }
74609b0fd45SJiri Olsa 
74709b0fd45SJiri Olsa int record_parse_callchain_opt(const struct option *opt,
74809b0fd45SJiri Olsa 			       const char *arg,
74909b0fd45SJiri Olsa 			       int unset)
75009b0fd45SJiri Olsa {
751b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = opt->value;
75209b0fd45SJiri Olsa 	int ret;
75309b0fd45SJiri Olsa 
754eb853e80SJiri Olsa 	opts->call_graph_enabled = !unset;
755eb853e80SJiri Olsa 
75609b0fd45SJiri Olsa 	/* --no-call-graph */
75709b0fd45SJiri Olsa 	if (unset) {
75809b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_NONE;
75909b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
76009b0fd45SJiri Olsa 		return 0;
76109b0fd45SJiri Olsa 	}
76209b0fd45SJiri Olsa 
76309b0fd45SJiri Olsa 	ret = record_parse_callchain(arg, opts);
76409b0fd45SJiri Olsa 	if (!ret)
76509b0fd45SJiri Olsa 		callchain_debug(opts);
76609b0fd45SJiri Olsa 
76726d33022SJiri Olsa 	return ret;
76826d33022SJiri Olsa }
76926d33022SJiri Olsa 
77009b0fd45SJiri Olsa int record_callchain_opt(const struct option *opt,
77109b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
77209b0fd45SJiri Olsa 			 int unset __maybe_unused)
77309b0fd45SJiri Olsa {
774b4006796SArnaldo Carvalho de Melo 	struct record_opts *opts = opt->value;
77509b0fd45SJiri Olsa 
776eb853e80SJiri Olsa 	opts->call_graph_enabled = !unset;
777eb853e80SJiri Olsa 
77809b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_NONE)
77909b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_FP;
78009b0fd45SJiri Olsa 
78109b0fd45SJiri Olsa 	callchain_debug(opts);
78209b0fd45SJiri Olsa 	return 0;
78309b0fd45SJiri Olsa }
78409b0fd45SJiri Olsa 
785eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb)
786eb853e80SJiri Olsa {
787eb853e80SJiri Olsa 	struct record *rec = cb;
788eb853e80SJiri Olsa 
789eb853e80SJiri Olsa 	if (!strcmp(var, "record.call-graph"))
790eb853e80SJiri Olsa 		return record_parse_callchain(value, &rec->opts);
791eb853e80SJiri Olsa 
792eb853e80SJiri Olsa 	return perf_default_config(var, value, cb);
793eb853e80SJiri Olsa }
794eb853e80SJiri Olsa 
79586470930SIngo Molnar static const char * const record_usage[] = {
79686470930SIngo Molnar 	"perf record [<options>] [<command>]",
79786470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
79886470930SIngo Molnar 	NULL
79986470930SIngo Molnar };
80086470930SIngo Molnar 
801d20deb64SArnaldo Carvalho de Melo /*
8028c6f45a7SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a record__new
8038c6f45a7SArnaldo Carvalho de Melo  * because we need to have access to it in record__exit, that is called
804d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
805d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
806d20deb64SArnaldo Carvalho de Melo  *
807d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
808d20deb64SArnaldo Carvalho de Melo  *
809d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
810d20deb64SArnaldo Carvalho de Melo  */
8118c6f45a7SArnaldo Carvalho de Melo static struct record record = {
812d20deb64SArnaldo Carvalho de Melo 	.opts = {
813d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
814d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
815d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
816447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
817d1cb9fceSNamhyung Kim 		.target		     = {
818d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
8193aa5939dSAdrian Hunter 			.default_per_cpu = true,
820d1cb9fceSNamhyung Kim 		},
821d20deb64SArnaldo Carvalho de Melo 	},
822d20deb64SArnaldo Carvalho de Melo };
8237865e817SFrederic Weisbecker 
82409b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
82561eaa3beSArnaldo Carvalho de Melo 
8269ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT
82709b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
82861eaa3beSArnaldo Carvalho de Melo #else
82909b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp";
83061eaa3beSArnaldo Carvalho de Melo #endif
83161eaa3beSArnaldo Carvalho de Melo 
832d20deb64SArnaldo Carvalho de Melo /*
833d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
834d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
835b4006796SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use record_opts,
836d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
837d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
838d20deb64SArnaldo Carvalho de Melo  */
839bca647aaSTom Zanussi const struct option record_options[] = {
840d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
84186470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
842f120f9d5SJiri Olsa 		     parse_events_option),
843d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
844c171b552SLi Zefan 		     "event filter", parse_filter),
845bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
846d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
847bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
848d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
849d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
85086470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
851509051eaSArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
852acac03faSKirill Smelkov 		    "collect data without buffering"),
853d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
854daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
855bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
85686470930SIngo Molnar 			    "system-wide collection from all CPUs"),
857bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
858c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
859d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
860f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
86186470930SIngo Molnar 		    "output file name"),
86269e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
86369e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
8642e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
865d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
866994a1f78SJiri Olsa 	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
867994a1f78SJiri Olsa 		     "number of mmap data pages",
868994a1f78SJiri Olsa 		     perf_evlist__parse_mmap_pages),
869d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
87043bece79SLin Ming 		    "put the counters into a counter group"),
87109b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
87209b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
87309b0fd45SJiri Olsa 			   &record_callchain_opt),
87409b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
87575d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
87609b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
877c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8783da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
879b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
880d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
881649c48a9SPeter Zijlstra 		    "per thread counts"),
882d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8834bba828dSAnton Blanchard 		    "Sample addresses"),
884d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8853e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
886d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
887649c48a9SPeter Zijlstra 		    "don't sample"),
888d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
889a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
890d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
891baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
892d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
893023695d9SStephane Eranian 		     "monitor event in cgroup name only",
894023695d9SStephane Eranian 		     parse_cgroups),
895a6205a35SArnaldo Carvalho de Melo 	OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
8966619a53eSAndi Kleen 		  "ms to wait before starting measurement after program start"),
897bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
898bea03405SNamhyung Kim 		   "user to profile"),
899a5aabdacSStephane Eranian 
900a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
901a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
902a5aabdacSStephane Eranian 		     parse_branch_stack),
903a5aabdacSStephane Eranian 
904a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
905a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
906bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
90705484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
90805484298SAndi Kleen 		    "sample by weight (on special events only)"),
909475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
910475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
9113aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
9123aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
91386470930SIngo Molnar 	OPT_END()
91486470930SIngo Molnar };
91586470930SIngo Molnar 
9161d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
91786470930SIngo Molnar {
91869aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
9198c6f45a7SArnaldo Carvalho de Melo 	struct record *rec = &record;
92016ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
92186470930SIngo Molnar 
9223e2be2daSArnaldo Carvalho de Melo 	rec->evlist = perf_evlist__new();
9233e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist == NULL)
924361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
925361c99a6SArnaldo Carvalho de Melo 
926eb853e80SJiri Olsa 	perf_config(perf_record_config, rec);
927eb853e80SJiri Olsa 
928bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
929a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
930602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
931bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
93286470930SIngo Molnar 
933bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
9343780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
935023695d9SStephane Eranian 			  " system-wide mode\n");
936023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
937023695d9SStephane Eranian 	}
938023695d9SStephane Eranian 
939655000e7SArnaldo Carvalho de Melo 	symbol__init();
940baa2f6ceSArnaldo Carvalho de Melo 
941ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
942646aaea6SArnaldo Carvalho de Melo 		pr_warning(
943646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
944ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
945646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
946646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
947646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
948646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
949646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
950ec80fde7SArnaldo Carvalho de Melo 
951d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
952a1ac1d3cSStephane Eranian 		disable_buildid_cache();
953655000e7SArnaldo Carvalho de Melo 
9543e2be2daSArnaldo Carvalho de Melo 	if (rec->evlist->nr_entries == 0 &&
9553e2be2daSArnaldo Carvalho de Melo 	    perf_evlist__add_default(rec->evlist) < 0) {
95669aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
95769aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
958bbd36e5eSPeter Zijlstra 	}
95986470930SIngo Molnar 
96069e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
96169e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
96269e7e5b0SAdrian Hunter 
963602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
96416ad2ffbSNamhyung Kim 	if (err) {
965602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
96616ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
96716ad2ffbSNamhyung Kim 	}
9684bd0f2d2SNamhyung Kim 
969602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
97016ad2ffbSNamhyung Kim 	if (err) {
97116ad2ffbSNamhyung Kim 		int saved_errno = errno;
97216ad2ffbSNamhyung Kim 
973602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9743780f488SNamhyung Kim 		ui__error("%s", errbuf);
97516ad2ffbSNamhyung Kim 
97616ad2ffbSNamhyung Kim 		err = -saved_errno;
9778fa60e1fSNamhyung Kim 		goto out_symbol_exit;
97816ad2ffbSNamhyung Kim 	}
9790d37aa34SArnaldo Carvalho de Melo 
98016ad2ffbSNamhyung Kim 	err = -ENOMEM;
9813e2be2daSArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
982dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
98369aad6f1SArnaldo Carvalho de Melo 
984b4006796SArnaldo Carvalho de Melo 	if (record_opts__config(&rec->opts)) {
98539d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
98603ad9747SArnaldo Carvalho de Melo 		goto out_symbol_exit;
9877e4ff9e3SMike Galbraith 	}
9887e4ff9e3SMike Galbraith 
989d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
990d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
991d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
99239d17dacSArnaldo Carvalho de Melo 	return err;
99386470930SIngo Molnar }
994