xref: /openbmc/linux/tools/perf/builtin-record.c (revision 7ab75cffd6a1b2195944b8522673522f09e7fcb0)
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 
65d20deb64SArnaldo Carvalho de Melo struct perf_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 
798d3eca20SDavid Ahern static int write_output(struct perf_record *rec, void *buf, size_t size)
80f5970550SPeter Zijlstra {
81f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
82f5fc1412SJiri Olsa 
83f5970550SPeter Zijlstra 	while (size) {
84f5fc1412SJiri Olsa 		int ret = write(file->fd, buf, size);
85f5970550SPeter Zijlstra 
868d3eca20SDavid Ahern 		if (ret < 0) {
874f624685SAdrian Hunter 			pr_err("failed to write perf data, error: %m\n");
888d3eca20SDavid Ahern 			return -1;
898d3eca20SDavid Ahern 		}
90f5970550SPeter Zijlstra 
91f5970550SPeter Zijlstra 		size -= ret;
92f5970550SPeter Zijlstra 		buf += ret;
93f5970550SPeter Zijlstra 
94d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written += ret;
95f5970550SPeter Zijlstra 	}
968d3eca20SDavid Ahern 
978d3eca20SDavid Ahern 	return 0;
98f5970550SPeter Zijlstra }
99f5970550SPeter Zijlstra 
10045694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
101d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
1021d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
1031d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
104234fbbf5SArnaldo Carvalho de Melo {
10545694aa7SArnaldo Carvalho de Melo 	struct perf_record *rec = container_of(tool, struct perf_record, tool);
1068d3eca20SDavid Ahern 	if (write_output(rec, event, event->header.size) < 0)
1078d3eca20SDavid Ahern 		return -1;
1088d3eca20SDavid Ahern 
109234fbbf5SArnaldo Carvalho de Melo 	return 0;
110234fbbf5SArnaldo Carvalho de Melo }
111234fbbf5SArnaldo Carvalho de Melo 
1128d3eca20SDavid Ahern static int perf_record__mmap_read(struct perf_record *rec,
113d20deb64SArnaldo Carvalho de Melo 				   struct perf_mmap *md)
11486470930SIngo Molnar {
115744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
11686470930SIngo Molnar 	unsigned int old = md->prev;
117918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
11886470930SIngo Molnar 	unsigned long size;
11986470930SIngo Molnar 	void *buf;
1208d3eca20SDavid Ahern 	int rc = 0;
12186470930SIngo Molnar 
122dc82009aSArnaldo Carvalho de Melo 	if (old == head)
1238d3eca20SDavid Ahern 		return 0;
12486470930SIngo Molnar 
125d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
12686470930SIngo Molnar 
12786470930SIngo Molnar 	size = head - old;
12886470930SIngo Molnar 
12986470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
13086470930SIngo Molnar 		buf = &data[old & md->mask];
13186470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
13286470930SIngo Molnar 		old += size;
13386470930SIngo Molnar 
1348d3eca20SDavid Ahern 		if (write_output(rec, buf, size) < 0) {
1358d3eca20SDavid Ahern 			rc = -1;
1368d3eca20SDavid Ahern 			goto out;
1378d3eca20SDavid Ahern 		}
13886470930SIngo Molnar 	}
13986470930SIngo Molnar 
14086470930SIngo Molnar 	buf = &data[old & md->mask];
14186470930SIngo Molnar 	size = head - old;
14286470930SIngo Molnar 	old += size;
14386470930SIngo Molnar 
1448d3eca20SDavid Ahern 	if (write_output(rec, buf, size) < 0) {
1458d3eca20SDavid Ahern 		rc = -1;
1468d3eca20SDavid Ahern 		goto out;
1478d3eca20SDavid Ahern 	}
14886470930SIngo Molnar 
14986470930SIngo Molnar 	md->prev = old;
150115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
1518d3eca20SDavid Ahern 
1528d3eca20SDavid Ahern out:
1538d3eca20SDavid Ahern 	return rc;
15486470930SIngo Molnar }
15586470930SIngo Molnar 
15686470930SIngo Molnar static volatile int done = 0;
157f7b7c26eSPeter Zijlstra static volatile int signr = -1;
15833e49ea7SAndi Kleen static volatile int child_finished = 0;
15986470930SIngo Molnar 
16086470930SIngo Molnar static void sig_handler(int sig)
16186470930SIngo Molnar {
16233e49ea7SAndi Kleen 	if (sig == SIGCHLD)
16333e49ea7SAndi Kleen 		child_finished = 1;
16433e49ea7SAndi Kleen 
16586470930SIngo Molnar 	done = 1;
166f7b7c26eSPeter Zijlstra 	signr = sig;
167f7b7c26eSPeter Zijlstra }
168f7b7c26eSPeter Zijlstra 
1691d037ca1SIrina Tirdea static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
170f7b7c26eSPeter Zijlstra {
171d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
17233e49ea7SAndi Kleen 	int status;
17333e49ea7SAndi Kleen 
174d20deb64SArnaldo Carvalho de Melo 	if (rec->evlist->workload.pid > 0) {
17533e49ea7SAndi Kleen 		if (!child_finished)
176d20deb64SArnaldo Carvalho de Melo 			kill(rec->evlist->workload.pid, SIGTERM);
177933da83aSChris Wilson 
17833e49ea7SAndi Kleen 		wait(&status);
17933e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
180d20deb64SArnaldo Carvalho de Melo 			psignal(WTERMSIG(status), rec->progname);
18133e49ea7SAndi Kleen 	}
18233e49ea7SAndi Kleen 
18318483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
184f7b7c26eSPeter Zijlstra 		return;
185f7b7c26eSPeter Zijlstra 
186f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
18786470930SIngo Molnar }
18886470930SIngo Molnar 
1898d3eca20SDavid Ahern static int perf_record__open(struct perf_record *rec)
190dd7927f4SArnaldo Carvalho de Melo {
19156e52e85SArnaldo Carvalho de Melo 	char msg[512];
1926a4bb04cSJiri Olsa 	struct perf_evsel *pos;
193d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
194d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
195d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
1968d3eca20SDavid Ahern 	int rc = 0;
197dd7927f4SArnaldo Carvalho de Melo 
198f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
199cac21425SJiri Olsa 
200dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
2013da297a6SIngo Molnar try_again:
2026a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
20356e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2043da297a6SIngo Molnar 				if (verbose)
205c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2063da297a6SIngo Molnar 				goto try_again;
2073da297a6SIngo Molnar 			}
208ca6a4258SDavid Ahern 
20956e52e85SArnaldo Carvalho de Melo 			rc = -errno;
21056e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
21156e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
21256e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
2138d3eca20SDavid Ahern 			goto out;
2147c6a1c65SPeter Zijlstra 		}
2157c6a1c65SPeter Zijlstra 	}
2167c6a1c65SPeter Zijlstra 
2171491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
2180a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2190a102479SFrederic Weisbecker 			strerror(errno));
2208d3eca20SDavid Ahern 		rc = -1;
2218d3eca20SDavid Ahern 		goto out;
2220a102479SFrederic Weisbecker 	}
2230a102479SFrederic Weisbecker 
22418e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
2258d3eca20SDavid Ahern 		if (errno == EPERM) {
2268d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
22718e60939SNelson Elhage 			       "Consider increasing "
22818e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
22918e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
23018e60939SNelson Elhage 			       "(current value: %d)\n", opts->mmap_pages);
2318d3eca20SDavid Ahern 			rc = -errno;
2328d3eca20SDavid Ahern 		} else {
2338d3eca20SDavid Ahern 			pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
2348d3eca20SDavid Ahern 			rc = -errno;
2358d3eca20SDavid Ahern 		}
2368d3eca20SDavid Ahern 		goto out;
23718e60939SNelson Elhage 	}
2380a27d7f9SArnaldo Carvalho de Melo 
239a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
2407b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
2418d3eca20SDavid Ahern out:
2428d3eca20SDavid Ahern 	return rc;
243a91e5431SArnaldo Carvalho de Melo }
244a91e5431SArnaldo Carvalho de Melo 
245d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
2466122e4e4SArnaldo Carvalho de Melo {
247f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
248f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
249*7ab75cffSDavid Ahern 	u64 start = session->header.data_offset;
2506122e4e4SArnaldo Carvalho de Melo 
251f5fc1412SJiri Olsa 	u64 size = lseek(file->fd, 0, SEEK_CUR);
2529f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2539f591fd7SArnaldo Carvalho de Melo 		return 0;
2549f591fd7SArnaldo Carvalho de Melo 
255*7ab75cffSDavid Ahern 	return __perf_session__process_events(session, start,
256*7ab75cffSDavid Ahern 					      size - start,
2576122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
2586122e4e4SArnaldo Carvalho de Melo }
2596122e4e4SArnaldo Carvalho de Melo 
2608d3eca20SDavid Ahern static void perf_record__exit(int status, void *arg)
261f5970550SPeter Zijlstra {
262d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
263f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
264f5970550SPeter Zijlstra 
2658d3eca20SDavid Ahern 	if (status != 0)
2668d3eca20SDavid Ahern 		return;
2678d3eca20SDavid Ahern 
268f5fc1412SJiri Olsa 	if (!file->is_pipe) {
269d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
270d20deb64SArnaldo Carvalho de Melo 
271d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
272d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
273d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
274f5fc1412SJiri Olsa 					   file->fd, true);
275d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
276d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
277d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
278c7929e47STom Zanussi 	}
279f5970550SPeter Zijlstra }
280f5970550SPeter Zijlstra 
2818115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
282a1645ce1SZhang, Yanmin {
283a1645ce1SZhang, Yanmin 	int err;
28445694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
285a1645ce1SZhang, Yanmin 	/*
286a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
287a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
288a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
289a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
290a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
291a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
292a1645ce1SZhang, Yanmin 	 */
29345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
294743eb868SArnaldo Carvalho de Melo 					     machine);
295a1645ce1SZhang, Yanmin 	if (err < 0)
296a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
29723346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
298a1645ce1SZhang, Yanmin 
299a1645ce1SZhang, Yanmin 	/*
300a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
301a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
302a1645ce1SZhang, Yanmin 	 */
30345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
304743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
305a1645ce1SZhang, Yanmin 	if (err < 0)
30645694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
307743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
308a1645ce1SZhang, Yanmin 	if (err < 0)
309a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
31023346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
311a1645ce1SZhang, Yanmin }
312a1645ce1SZhang, Yanmin 
31398402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
31498402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
31598402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
31698402807SFrederic Weisbecker };
31798402807SFrederic Weisbecker 
3188d3eca20SDavid Ahern static int perf_record__mmap_read_all(struct perf_record *rec)
31998402807SFrederic Weisbecker {
3200e2e63ddSPeter Zijlstra 	int i;
3218d3eca20SDavid Ahern 	int rc = 0;
32298402807SFrederic Weisbecker 
323d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
3248d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
3258d3eca20SDavid Ahern 			if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
3268d3eca20SDavid Ahern 				rc = -1;
3278d3eca20SDavid Ahern 				goto out;
3288d3eca20SDavid Ahern 			}
3298d3eca20SDavid Ahern 		}
33098402807SFrederic Weisbecker 	}
33198402807SFrederic Weisbecker 
3322eeaaa09SStephane Eranian 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
3338d3eca20SDavid Ahern 		rc = write_output(rec, &finished_round_event,
3348d3eca20SDavid Ahern 				  sizeof(finished_round_event));
3358d3eca20SDavid Ahern 
3368d3eca20SDavid Ahern out:
3378d3eca20SDavid Ahern 	return rc;
33898402807SFrederic Weisbecker }
33998402807SFrederic Weisbecker 
34057706abcSDavid Ahern static void perf_record__init_features(struct perf_record *rec)
34157706abcSDavid Ahern {
34257706abcSDavid Ahern 	struct perf_evlist *evsel_list = rec->evlist;
34357706abcSDavid Ahern 	struct perf_session *session = rec->session;
34457706abcSDavid Ahern 	int feat;
34557706abcSDavid Ahern 
34657706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
34757706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
34857706abcSDavid Ahern 
34957706abcSDavid Ahern 	if (rec->no_buildid)
35057706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
35157706abcSDavid Ahern 
35257706abcSDavid Ahern 	if (!have_tracepoints(&evsel_list->entries))
35357706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
35457706abcSDavid Ahern 
35557706abcSDavid Ahern 	if (!rec->opts.branch_stack)
35657706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
35757706abcSDavid Ahern }
35857706abcSDavid Ahern 
359d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
36086470930SIngo Molnar {
36157706abcSDavid Ahern 	int err;
3628b412664SPeter Zijlstra 	unsigned long waking = 0;
36346be604bSZhang, Yanmin 	const bool forks = argc > 0;
36423346f21SArnaldo Carvalho de Melo 	struct machine *machine;
36545694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
366d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
367d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
368f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
369d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3702711926aSJiri Olsa 	bool disabled = false;
37186470930SIngo Molnar 
372d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
37333e49ea7SAndi Kleen 
374d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
375f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
376f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
37718483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
378804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
379f5970550SPeter Zijlstra 
380f5fc1412SJiri Olsa 	session = perf_session__new(file, false, NULL);
38194c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
382a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
383a9a70bbcSArnaldo Carvalho de Melo 		return -1;
384a9a70bbcSArnaldo Carvalho de Melo 	}
385a9a70bbcSArnaldo Carvalho de Melo 
386d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
387d20deb64SArnaldo Carvalho de Melo 
38857706abcSDavid Ahern 	perf_record__init_features(rec);
389330aa675SStephane Eranian 
390d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
3916ef73ec4SNamhyung Kim 		err = perf_evlist__prepare_workload(evsel_list, &opts->target,
392f5fc1412SJiri Olsa 						    argv, file->is_pipe,
39355e162eaSNamhyung Kim 						    true);
39435b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
39535b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
39635b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
397856e9660SPeter Zijlstra 		}
398856e9660SPeter Zijlstra 	}
399856e9660SPeter Zijlstra 
4008d3eca20SDavid Ahern 	if (perf_record__open(rec) != 0) {
4018d3eca20SDavid Ahern 		err = -1;
4028d3eca20SDavid Ahern 		goto out_delete_session;
4038d3eca20SDavid Ahern 	}
40486470930SIngo Molnar 
405a8bb559bSNamhyung Kim 	if (!evsel_list->nr_groups)
406a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
407a8bb559bSNamhyung Kim 
408712a4b60SArnaldo Carvalho de Melo 	/*
409d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
410712a4b60SArnaldo Carvalho de Melo 	 */
411d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
412712a4b60SArnaldo Carvalho de Melo 
413f5fc1412SJiri Olsa 	if (file->is_pipe) {
414f5fc1412SJiri Olsa 		err = perf_header__write_pipe(file->fd);
415529870e3STom Zanussi 		if (err < 0)
4168d3eca20SDavid Ahern 			goto out_delete_session;
417563aecb2SJiri Olsa 	} else {
418a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
419f5fc1412SJiri Olsa 						 file->fd, false);
420d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
4218d3eca20SDavid Ahern 			goto out_delete_session;
422d5eed904SArnaldo Carvalho de Melo 	}
4237c6a1c65SPeter Zijlstra 
424d3665498SDavid Ahern 	if (!rec->no_buildid
425e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
426d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
427e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
4288d3eca20SDavid Ahern 		err = -1;
4298d3eca20SDavid Ahern 		goto out_delete_session;
430e20960c0SRobert Richter 	}
431e20960c0SRobert Richter 
43234ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
433743eb868SArnaldo Carvalho de Melo 
434f5fc1412SJiri Olsa 	if (file->is_pipe) {
43545694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
436a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
4372c46dbb5STom Zanussi 		if (err < 0) {
4382c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
4398d3eca20SDavid Ahern 			goto out_delete_session;
4402c46dbb5STom Zanussi 		}
441cd19a035STom Zanussi 
442361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
44363e0c771STom Zanussi 			/*
44463e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
44563e0c771STom Zanussi 			 * there were no tracepoints so its not really
44663e0c771STom Zanussi 			 * an error, just that we don't need to
44763e0c771STom Zanussi 			 * synthesize anything.  We really have to
44863e0c771STom Zanussi 			 * return this more properly and also
44963e0c771STom Zanussi 			 * propagate errors that now are calling die()
45063e0c771STom Zanussi 			 */
451f5fc1412SJiri Olsa 			err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list,
452743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
45363e0c771STom Zanussi 			if (err <= 0) {
45463e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
4558d3eca20SDavid Ahern 				goto out_delete_session;
45663e0c771STom Zanussi 			}
457f34b9001SDavid Ahern 			rec->bytes_written += err;
4582c46dbb5STom Zanussi 		}
45963e0c771STom Zanussi 	}
4602c46dbb5STom Zanussi 
46145694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
462743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
46370162138SArnaldo Carvalho de Melo 	if (err < 0)
46445694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
465743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
466c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
467c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
468c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
469c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
47056b03f3cSArnaldo Carvalho de Melo 
47145694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
472743eb868SArnaldo Carvalho de Melo 					     machine);
473c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
474c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
475c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
476c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
477c1a3a4b9SArnaldo Carvalho de Melo 
4787e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
479876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
4807e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
4817e383de4SArnaldo Carvalho de Melo 	}
482b7cece76SArnaldo Carvalho de Melo 
483e4dd45feSJiri Olsa 	if (perf_target__has_task(&opts->target))
4848d3eca20SDavid Ahern 		err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
4858115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
486743eb868SArnaldo Carvalho de Melo 						  machine);
487e4dd45feSJiri Olsa 	else if (perf_target__has_cpu(&opts->target))
4888d3eca20SDavid Ahern 		err = perf_event__synthesize_threads(tool, process_synthesized_event,
489743eb868SArnaldo Carvalho de Melo 					       machine);
490e4dd45feSJiri Olsa 	else /* command specified */
491e4dd45feSJiri Olsa 		err = 0;
4927c6a1c65SPeter Zijlstra 
4938d3eca20SDavid Ahern 	if (err != 0)
4948d3eca20SDavid Ahern 		goto out_delete_session;
4958d3eca20SDavid Ahern 
496d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
49786470930SIngo Molnar 		struct sched_param param;
49886470930SIngo Molnar 
499d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
50086470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5016beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
5028d3eca20SDavid Ahern 			err = -1;
5038d3eca20SDavid Ahern 			goto out_delete_session;
50486470930SIngo Molnar 		}
50586470930SIngo Molnar 	}
50686470930SIngo Molnar 
507774cb499SJiri Olsa 	/*
508774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
509774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
510774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
511774cb499SJiri Olsa 	 */
512774cb499SJiri Olsa 	if (!perf_target__none(&opts->target))
513764e16a3SDavid Ahern 		perf_evlist__enable(evsel_list);
514764e16a3SDavid Ahern 
515856e9660SPeter Zijlstra 	/*
516856e9660SPeter Zijlstra 	 * Let the child rip
517856e9660SPeter Zijlstra 	 */
518d4db3f16SArnaldo Carvalho de Melo 	if (forks)
51935b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
520856e9660SPeter Zijlstra 
521649c48a9SPeter Zijlstra 	for (;;) {
522d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
52386470930SIngo Molnar 
5248d3eca20SDavid Ahern 		if (perf_record__mmap_read_all(rec) < 0) {
5258d3eca20SDavid Ahern 			err = -1;
5268d3eca20SDavid Ahern 			goto out_delete_session;
5278d3eca20SDavid Ahern 		}
52886470930SIngo Molnar 
529d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
530649c48a9SPeter Zijlstra 			if (done)
531649c48a9SPeter Zijlstra 				break;
5325c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
5338b412664SPeter Zijlstra 			waking++;
5348b412664SPeter Zijlstra 		}
5358b412664SPeter Zijlstra 
536774cb499SJiri Olsa 		/*
537774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
538774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
539774cb499SJiri Olsa 		 * disable events in this case.
540774cb499SJiri Olsa 		 */
5412711926aSJiri Olsa 		if (done && !disabled && !perf_target__none(&opts->target)) {
5424152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
5432711926aSJiri Olsa 			disabled = true;
5442711926aSJiri Olsa 		}
5458b412664SPeter Zijlstra 	}
5468b412664SPeter Zijlstra 
54718483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
548b44308f5SArnaldo Carvalho de Melo 		return 0;
549b44308f5SArnaldo Carvalho de Melo 
5508b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
55186470930SIngo Molnar 
55286470930SIngo Molnar 	/*
55386470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
55486470930SIngo Molnar 	 */
55586470930SIngo Molnar 	fprintf(stderr,
5569486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
557d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
5586a4d98d7SJiri Olsa 		file->path,
559d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
56086470930SIngo Molnar 
56186470930SIngo Molnar 	return 0;
56239d17dacSArnaldo Carvalho de Melo 
56339d17dacSArnaldo Carvalho de Melo out_delete_session:
56439d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
56539d17dacSArnaldo Carvalho de Melo 	return err;
56686470930SIngo Molnar }
56786470930SIngo Molnar 
568bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
569bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
570bdfebd84SRoberto Agostino Vitillo 
571bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
572bdfebd84SRoberto Agostino Vitillo 
573bdfebd84SRoberto Agostino Vitillo struct branch_mode {
574bdfebd84SRoberto Agostino Vitillo 	const char *name;
575bdfebd84SRoberto Agostino Vitillo 	int mode;
576bdfebd84SRoberto Agostino Vitillo };
577bdfebd84SRoberto Agostino Vitillo 
578bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
579bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
580bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
581bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
582bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
583bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
584bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
585bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
5860126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
5870126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
5880126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
589bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
590bdfebd84SRoberto Agostino Vitillo };
591bdfebd84SRoberto Agostino Vitillo 
592bdfebd84SRoberto Agostino Vitillo static int
593a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
594bdfebd84SRoberto Agostino Vitillo {
595bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
596bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
597bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
598bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
599bdfebd84SRoberto Agostino Vitillo 
600bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
601bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
602a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
603bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
604bdfebd84SRoberto Agostino Vitillo 
605a5aabdacSStephane Eranian 	if (unset)
606a5aabdacSStephane Eranian 		return 0;
607bdfebd84SRoberto Agostino Vitillo 
608a5aabdacSStephane Eranian 	/*
609a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
610a5aabdacSStephane Eranian 	 */
611a5aabdacSStephane Eranian 	if (*mode)
612a5aabdacSStephane Eranian 		return -1;
613a5aabdacSStephane Eranian 
614a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
615a5aabdacSStephane Eranian 	if (str) {
616bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
617bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
618bdfebd84SRoberto Agostino Vitillo 		if (!s)
619bdfebd84SRoberto Agostino Vitillo 			return -1;
620bdfebd84SRoberto Agostino Vitillo 
621bdfebd84SRoberto Agostino Vitillo 		for (;;) {
622bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
623bdfebd84SRoberto Agostino Vitillo 			if (p)
624bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
625bdfebd84SRoberto Agostino Vitillo 
626bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
627bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
628bdfebd84SRoberto Agostino Vitillo 					break;
629bdfebd84SRoberto Agostino Vitillo 			}
630a5aabdacSStephane Eranian 			if (!br->name) {
631a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
632a5aabdacSStephane Eranian 					    " check man page\n", s);
633bdfebd84SRoberto Agostino Vitillo 				goto error;
634a5aabdacSStephane Eranian 			}
635bdfebd84SRoberto Agostino Vitillo 
636bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
637bdfebd84SRoberto Agostino Vitillo 
638bdfebd84SRoberto Agostino Vitillo 			if (!p)
639bdfebd84SRoberto Agostino Vitillo 				break;
640bdfebd84SRoberto Agostino Vitillo 
641bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
642bdfebd84SRoberto Agostino Vitillo 		}
643a5aabdacSStephane Eranian 	}
644bdfebd84SRoberto Agostino Vitillo 	ret = 0;
645bdfebd84SRoberto Agostino Vitillo 
646a5aabdacSStephane Eranian 	/* default to any branch */
647bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
648a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
649bdfebd84SRoberto Agostino Vitillo 	}
650bdfebd84SRoberto Agostino Vitillo error:
651bdfebd84SRoberto Agostino Vitillo 	free(os);
652bdfebd84SRoberto Agostino Vitillo 	return ret;
653bdfebd84SRoberto Agostino Vitillo }
654bdfebd84SRoberto Agostino Vitillo 
65589fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
65626d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size)
65726d33022SJiri Olsa {
65826d33022SJiri Olsa 	char *endptr;
65926d33022SJiri Olsa 	unsigned long size;
66026d33022SJiri Olsa 	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
66126d33022SJiri Olsa 
66226d33022SJiri Olsa 	size = strtoul(str, &endptr, 0);
66326d33022SJiri Olsa 
66426d33022SJiri Olsa 	do {
66526d33022SJiri Olsa 		if (*endptr)
66626d33022SJiri Olsa 			break;
66726d33022SJiri Olsa 
66826d33022SJiri Olsa 		size = round_up(size, sizeof(u64));
66926d33022SJiri Olsa 		if (!size || size > max_size)
67026d33022SJiri Olsa 			break;
67126d33022SJiri Olsa 
67226d33022SJiri Olsa 		*_size = size;
67326d33022SJiri Olsa 		return 0;
67426d33022SJiri Olsa 
67526d33022SJiri Olsa 	} while (0);
67626d33022SJiri Olsa 
67726d33022SJiri Olsa 	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
67826d33022SJiri Olsa 	       max_size, str);
67926d33022SJiri Olsa 	return -1;
68026d33022SJiri Olsa }
68189fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */
68226d33022SJiri Olsa 
68309b0fd45SJiri Olsa int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
68426d33022SJiri Olsa {
68526d33022SJiri Olsa 	char *tok, *name, *saveptr = NULL;
68626d33022SJiri Olsa 	char *buf;
68726d33022SJiri Olsa 	int ret = -1;
68826d33022SJiri Olsa 
68926d33022SJiri Olsa 	/* We need buffer that we know we can write to. */
69026d33022SJiri Olsa 	buf = malloc(strlen(arg) + 1);
69126d33022SJiri Olsa 	if (!buf)
69226d33022SJiri Olsa 		return -ENOMEM;
69326d33022SJiri Olsa 
69426d33022SJiri Olsa 	strcpy(buf, arg);
69526d33022SJiri Olsa 
69626d33022SJiri Olsa 	tok = strtok_r((char *)buf, ",", &saveptr);
69726d33022SJiri Olsa 	name = tok ? : (char *)buf;
69826d33022SJiri Olsa 
69926d33022SJiri Olsa 	do {
70026d33022SJiri Olsa 		/* Framepointer style */
70126d33022SJiri Olsa 		if (!strncmp(name, "fp", sizeof("fp"))) {
70226d33022SJiri Olsa 			if (!strtok_r(NULL, ",", &saveptr)) {
703c5ff78c3SArnaldo Carvalho de Melo 				opts->call_graph = CALLCHAIN_FP;
70426d33022SJiri Olsa 				ret = 0;
70526d33022SJiri Olsa 			} else
70626d33022SJiri Olsa 				pr_err("callchain: No more arguments "
70726d33022SJiri Olsa 				       "needed for -g fp\n");
70826d33022SJiri Olsa 			break;
70926d33022SJiri Olsa 
71089fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
71126d33022SJiri Olsa 		/* Dwarf style */
71226d33022SJiri Olsa 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
71361eaa3beSArnaldo Carvalho de Melo 			const unsigned long default_stack_dump_size = 8192;
71461eaa3beSArnaldo Carvalho de Melo 
71526d33022SJiri Olsa 			ret = 0;
716c5ff78c3SArnaldo Carvalho de Melo 			opts->call_graph = CALLCHAIN_DWARF;
717c5ff78c3SArnaldo Carvalho de Melo 			opts->stack_dump_size = default_stack_dump_size;
71826d33022SJiri Olsa 
71926d33022SJiri Olsa 			tok = strtok_r(NULL, ",", &saveptr);
72026d33022SJiri Olsa 			if (tok) {
72126d33022SJiri Olsa 				unsigned long size = 0;
72226d33022SJiri Olsa 
72326d33022SJiri Olsa 				ret = get_stack_size(tok, &size);
724c5ff78c3SArnaldo Carvalho de Melo 				opts->stack_dump_size = size;
72526d33022SJiri Olsa 			}
72689fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */
72726d33022SJiri Olsa 		} else {
72809b0fd45SJiri Olsa 			pr_err("callchain: Unknown --call-graph option "
72926d33022SJiri Olsa 			       "value: %s\n", arg);
73026d33022SJiri Olsa 			break;
73126d33022SJiri Olsa 		}
73226d33022SJiri Olsa 
73326d33022SJiri Olsa 	} while (0);
73426d33022SJiri Olsa 
73526d33022SJiri Olsa 	free(buf);
73609b0fd45SJiri Olsa 	return ret;
73709b0fd45SJiri Olsa }
73826d33022SJiri Olsa 
73909b0fd45SJiri Olsa static void callchain_debug(struct perf_record_opts *opts)
74009b0fd45SJiri Olsa {
741c5ff78c3SArnaldo Carvalho de Melo 	pr_debug("callchain: type %d\n", opts->call_graph);
74226d33022SJiri Olsa 
74309b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_DWARF)
74409b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
74509b0fd45SJiri Olsa 			 opts->stack_dump_size);
74609b0fd45SJiri Olsa }
74709b0fd45SJiri Olsa 
74809b0fd45SJiri Olsa int record_parse_callchain_opt(const struct option *opt,
74909b0fd45SJiri Olsa 			       const char *arg,
75009b0fd45SJiri Olsa 			       int unset)
75109b0fd45SJiri Olsa {
75209b0fd45SJiri Olsa 	struct perf_record_opts *opts = opt->value;
75309b0fd45SJiri Olsa 	int ret;
75409b0fd45SJiri Olsa 
75509b0fd45SJiri Olsa 	/* --no-call-graph */
75609b0fd45SJiri Olsa 	if (unset) {
75709b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_NONE;
75809b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
75909b0fd45SJiri Olsa 		return 0;
76009b0fd45SJiri Olsa 	}
76109b0fd45SJiri Olsa 
76209b0fd45SJiri Olsa 	ret = record_parse_callchain(arg, opts);
76309b0fd45SJiri Olsa 	if (!ret)
76409b0fd45SJiri Olsa 		callchain_debug(opts);
76509b0fd45SJiri Olsa 
76626d33022SJiri Olsa 	return ret;
76726d33022SJiri Olsa }
76826d33022SJiri Olsa 
76909b0fd45SJiri Olsa int record_callchain_opt(const struct option *opt,
77009b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
77109b0fd45SJiri Olsa 			 int unset __maybe_unused)
77209b0fd45SJiri Olsa {
77309b0fd45SJiri Olsa 	struct perf_record_opts *opts = opt->value;
77409b0fd45SJiri Olsa 
77509b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_NONE)
77609b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_FP;
77709b0fd45SJiri Olsa 
77809b0fd45SJiri Olsa 	callchain_debug(opts);
77909b0fd45SJiri Olsa 	return 0;
78009b0fd45SJiri Olsa }
78109b0fd45SJiri Olsa 
78286470930SIngo Molnar static const char * const record_usage[] = {
78386470930SIngo Molnar 	"perf record [<options>] [<command>]",
78486470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
78586470930SIngo Molnar 	NULL
78686470930SIngo Molnar };
78786470930SIngo Molnar 
788d20deb64SArnaldo Carvalho de Melo /*
789d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
790d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
791d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
792d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
793d20deb64SArnaldo Carvalho de Melo  *
794d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
795d20deb64SArnaldo Carvalho de Melo  *
796d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
797d20deb64SArnaldo Carvalho de Melo  */
798d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
799d20deb64SArnaldo Carvalho de Melo 	.opts = {
800d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
801d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
802d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
803447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
804d1cb9fceSNamhyung Kim 		.target		     = {
805d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
806d1cb9fceSNamhyung Kim 		},
807d20deb64SArnaldo Carvalho de Melo 	},
808d20deb64SArnaldo Carvalho de Melo };
8097865e817SFrederic Weisbecker 
81009b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
81161eaa3beSArnaldo Carvalho de Melo 
81289fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
81309b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
81461eaa3beSArnaldo Carvalho de Melo #else
81509b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp";
81661eaa3beSArnaldo Carvalho de Melo #endif
81761eaa3beSArnaldo Carvalho de Melo 
818d20deb64SArnaldo Carvalho de Melo /*
819d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
820d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
821d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
822d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
823d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
824d20deb64SArnaldo Carvalho de Melo  */
825bca647aaSTom Zanussi const struct option record_options[] = {
826d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
82786470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
828f120f9d5SJiri Olsa 		     parse_events_option),
829d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
830c171b552SLi Zefan 		     "event filter", parse_filter),
831bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
832d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
833bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
834d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
835d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
83686470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
837d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
838acac03faSKirill Smelkov 		    "collect data without buffering"),
839d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
840daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
841bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
84286470930SIngo Molnar 			    "system-wide collection from all CPUs"),
843bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
844c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
845d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
846f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
84786470930SIngo Molnar 		    "output file name"),
848d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
8492e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
850d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
851994a1f78SJiri Olsa 	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
852994a1f78SJiri Olsa 		     "number of mmap data pages",
853994a1f78SJiri Olsa 		     perf_evlist__parse_mmap_pages),
854d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
85543bece79SLin Ming 		    "put the counters into a counter group"),
85609b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
85709b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
85809b0fd45SJiri Olsa 			   &record_callchain_opt),
85909b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
86075d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
86109b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
862c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8633da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
864b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
865d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
866649c48a9SPeter Zijlstra 		    "per thread counts"),
867d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8684bba828dSAnton Blanchard 		    "Sample addresses"),
869d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8703e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
871d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
872649c48a9SPeter Zijlstra 		    "don't sample"),
873d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
874a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
875d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
876baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
877d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
878023695d9SStephane Eranian 		     "monitor event in cgroup name only",
879023695d9SStephane Eranian 		     parse_cgroups),
880bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
881bea03405SNamhyung Kim 		   "user to profile"),
882a5aabdacSStephane Eranian 
883a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
884a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
885a5aabdacSStephane Eranian 		     parse_branch_stack),
886a5aabdacSStephane Eranian 
887a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
888a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
889bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
89005484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
89105484298SAndi Kleen 		    "sample by weight (on special events only)"),
892475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
893475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
89486470930SIngo Molnar 	OPT_END()
89586470930SIngo Molnar };
89686470930SIngo Molnar 
8971d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
89886470930SIngo Molnar {
89969aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
900d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
901d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
90216ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
90386470930SIngo Molnar 
904334fe7a3SNamhyung Kim 	evsel_list = perf_evlist__new();
905361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
906361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
907361c99a6SArnaldo Carvalho de Melo 
908d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
909d20deb64SArnaldo Carvalho de Melo 
910bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
911a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
912d67356e7SNamhyung Kim 	if (!argc && perf_target__none(&rec->opts.target))
913bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
91486470930SIngo Molnar 
915bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
9163780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
917023695d9SStephane Eranian 			  " system-wide mode\n");
918023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
919023695d9SStephane Eranian 	}
920023695d9SStephane Eranian 
921655000e7SArnaldo Carvalho de Melo 	symbol__init();
922baa2f6ceSArnaldo Carvalho de Melo 
923ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
924646aaea6SArnaldo Carvalho de Melo 		pr_warning(
925646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
926ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
927646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
928646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
929646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
930646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
931646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
932ec80fde7SArnaldo Carvalho de Melo 
933d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
934a1ac1d3cSStephane Eranian 		disable_buildid_cache();
935655000e7SArnaldo Carvalho de Melo 
936361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
937361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
93869aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
93969aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
940bbd36e5eSPeter Zijlstra 	}
94186470930SIngo Molnar 
94216ad2ffbSNamhyung Kim 	err = perf_target__validate(&rec->opts.target);
94316ad2ffbSNamhyung Kim 	if (err) {
94416ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
94516ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
94616ad2ffbSNamhyung Kim 	}
9474bd0f2d2SNamhyung Kim 
94816ad2ffbSNamhyung Kim 	err = perf_target__parse_uid(&rec->opts.target);
94916ad2ffbSNamhyung Kim 	if (err) {
95016ad2ffbSNamhyung Kim 		int saved_errno = errno;
95116ad2ffbSNamhyung Kim 
95216ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9533780f488SNamhyung Kim 		ui__error("%s", errbuf);
95416ad2ffbSNamhyung Kim 
95516ad2ffbSNamhyung Kim 		err = -saved_errno;
9568fa60e1fSNamhyung Kim 		goto out_symbol_exit;
95716ad2ffbSNamhyung Kim 	}
9580d37aa34SArnaldo Carvalho de Melo 
95916ad2ffbSNamhyung Kim 	err = -ENOMEM;
960b809ac10SNamhyung Kim 	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
961dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
96269aad6f1SArnaldo Carvalho de Melo 
963714647bdSJiri Olsa 	if (perf_record_opts__config(&rec->opts)) {
96439d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
9655c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
9667e4ff9e3SMike Galbraith 	}
9677e4ff9e3SMike Galbraith 
968d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
9698fa60e1fSNamhyung Kim 
9708fa60e1fSNamhyung Kim 	perf_evlist__munmap(evsel_list);
9718fa60e1fSNamhyung Kim 	perf_evlist__close(evsel_list);
97239d17dacSArnaldo Carvalho de Melo out_free_fd:
9737e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
974d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
975d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
97639d17dacSArnaldo Carvalho de Melo 	return err;
97786470930SIngo Molnar }
978