xref: /openbmc/linux/tools/perf/builtin-record.c (revision 69e7e5b02bc6a9e5cf4a54911b27ca133cc1f99f)
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 
79a9986fadSDavid Ahern static int do_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) {
84410f1786SAdrian Hunter 		ssize_t 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 
100a9986fadSDavid Ahern static int write_output(struct perf_record *rec, void *buf, size_t size)
101a9986fadSDavid Ahern {
102a9986fadSDavid Ahern 	return do_write_output(rec, buf, size);
103a9986fadSDavid Ahern }
104a9986fadSDavid Ahern 
10545694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
106d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
1071d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
1081d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
109234fbbf5SArnaldo Carvalho de Melo {
11045694aa7SArnaldo Carvalho de Melo 	struct perf_record *rec = container_of(tool, struct perf_record, tool);
1118d3eca20SDavid Ahern 	if (write_output(rec, event, event->header.size) < 0)
1128d3eca20SDavid Ahern 		return -1;
1138d3eca20SDavid Ahern 
114234fbbf5SArnaldo Carvalho de Melo 	return 0;
115234fbbf5SArnaldo Carvalho de Melo }
116234fbbf5SArnaldo Carvalho de Melo 
1178d3eca20SDavid Ahern static int perf_record__mmap_read(struct perf_record *rec,
118d20deb64SArnaldo Carvalho de Melo 				   struct perf_mmap *md)
11986470930SIngo Molnar {
120744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
12186470930SIngo Molnar 	unsigned int old = md->prev;
122918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
12386470930SIngo Molnar 	unsigned long size;
12486470930SIngo Molnar 	void *buf;
1258d3eca20SDavid Ahern 	int rc = 0;
12686470930SIngo Molnar 
127dc82009aSArnaldo Carvalho de Melo 	if (old == head)
1288d3eca20SDavid Ahern 		return 0;
12986470930SIngo Molnar 
130d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
13186470930SIngo Molnar 
13286470930SIngo Molnar 	size = head - old;
13386470930SIngo Molnar 
13486470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
13586470930SIngo Molnar 		buf = &data[old & md->mask];
13686470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
13786470930SIngo Molnar 		old += size;
13886470930SIngo Molnar 
1398d3eca20SDavid Ahern 		if (write_output(rec, buf, size) < 0) {
1408d3eca20SDavid Ahern 			rc = -1;
1418d3eca20SDavid Ahern 			goto out;
1428d3eca20SDavid Ahern 		}
14386470930SIngo Molnar 	}
14486470930SIngo Molnar 
14586470930SIngo Molnar 	buf = &data[old & md->mask];
14686470930SIngo Molnar 	size = head - old;
14786470930SIngo Molnar 	old += size;
14886470930SIngo Molnar 
1498d3eca20SDavid Ahern 	if (write_output(rec, buf, size) < 0) {
1508d3eca20SDavid Ahern 		rc = -1;
1518d3eca20SDavid Ahern 		goto out;
1528d3eca20SDavid Ahern 	}
15386470930SIngo Molnar 
15486470930SIngo Molnar 	md->prev = old;
155115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
1568d3eca20SDavid Ahern 
1578d3eca20SDavid Ahern out:
1588d3eca20SDavid Ahern 	return rc;
15986470930SIngo Molnar }
16086470930SIngo Molnar 
16186470930SIngo Molnar static volatile int done = 0;
162f7b7c26eSPeter Zijlstra static volatile int signr = -1;
16333e49ea7SAndi Kleen static volatile int child_finished = 0;
16486470930SIngo Molnar 
16586470930SIngo Molnar static void sig_handler(int sig)
16686470930SIngo Molnar {
16733e49ea7SAndi Kleen 	if (sig == SIGCHLD)
16833e49ea7SAndi Kleen 		child_finished = 1;
16933e49ea7SAndi Kleen 
17086470930SIngo Molnar 	done = 1;
171f7b7c26eSPeter Zijlstra 	signr = sig;
172f7b7c26eSPeter Zijlstra }
173f7b7c26eSPeter Zijlstra 
1741d037ca1SIrina Tirdea static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
175f7b7c26eSPeter Zijlstra {
176d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
17733e49ea7SAndi Kleen 	int status;
17833e49ea7SAndi Kleen 
179d20deb64SArnaldo Carvalho de Melo 	if (rec->evlist->workload.pid > 0) {
18033e49ea7SAndi Kleen 		if (!child_finished)
181d20deb64SArnaldo Carvalho de Melo 			kill(rec->evlist->workload.pid, SIGTERM);
182933da83aSChris Wilson 
18333e49ea7SAndi Kleen 		wait(&status);
18433e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
185d20deb64SArnaldo Carvalho de Melo 			psignal(WTERMSIG(status), rec->progname);
18633e49ea7SAndi Kleen 	}
18733e49ea7SAndi Kleen 
18818483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
189f7b7c26eSPeter Zijlstra 		return;
190f7b7c26eSPeter Zijlstra 
191f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
19286470930SIngo Molnar }
19386470930SIngo Molnar 
1948d3eca20SDavid Ahern static int perf_record__open(struct perf_record *rec)
195dd7927f4SArnaldo Carvalho de Melo {
19656e52e85SArnaldo Carvalho de Melo 	char msg[512];
1976a4bb04cSJiri Olsa 	struct perf_evsel *pos;
198d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
199d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
200d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
2018d3eca20SDavid Ahern 	int rc = 0;
202dd7927f4SArnaldo Carvalho de Melo 
203f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
204cac21425SJiri Olsa 
205dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
2063da297a6SIngo Molnar try_again:
2076a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
20856e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2093da297a6SIngo Molnar 				if (verbose)
210c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2113da297a6SIngo Molnar 				goto try_again;
2123da297a6SIngo Molnar 			}
213ca6a4258SDavid Ahern 
21456e52e85SArnaldo Carvalho de Melo 			rc = -errno;
21556e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
21656e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
21756e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
2188d3eca20SDavid Ahern 			goto out;
2197c6a1c65SPeter Zijlstra 		}
2207c6a1c65SPeter Zijlstra 	}
2217c6a1c65SPeter Zijlstra 
2221491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
2230a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2240a102479SFrederic Weisbecker 			strerror(errno));
2258d3eca20SDavid Ahern 		rc = -1;
2268d3eca20SDavid Ahern 		goto out;
2270a102479SFrederic Weisbecker 	}
2280a102479SFrederic Weisbecker 
22918e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
2308d3eca20SDavid Ahern 		if (errno == EPERM) {
2318d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
23218e60939SNelson Elhage 			       "Consider increasing "
23318e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
23418e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
23518e60939SNelson Elhage 			       "(current value: %d)\n", opts->mmap_pages);
2368d3eca20SDavid Ahern 			rc = -errno;
2378d3eca20SDavid Ahern 		} else {
2388d3eca20SDavid Ahern 			pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
2398d3eca20SDavid Ahern 			rc = -errno;
2408d3eca20SDavid Ahern 		}
2418d3eca20SDavid Ahern 		goto out;
24218e60939SNelson Elhage 	}
2430a27d7f9SArnaldo Carvalho de Melo 
244a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
2457b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
2468d3eca20SDavid Ahern out:
2478d3eca20SDavid Ahern 	return rc;
248a91e5431SArnaldo Carvalho de Melo }
249a91e5431SArnaldo Carvalho de Melo 
250d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
2516122e4e4SArnaldo Carvalho de Melo {
252f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
253f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
2547ab75cffSDavid Ahern 	u64 start = session->header.data_offset;
2556122e4e4SArnaldo Carvalho de Melo 
256f5fc1412SJiri Olsa 	u64 size = lseek(file->fd, 0, SEEK_CUR);
2579f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2589f591fd7SArnaldo Carvalho de Melo 		return 0;
2599f591fd7SArnaldo Carvalho de Melo 
2607ab75cffSDavid Ahern 	return __perf_session__process_events(session, start,
2617ab75cffSDavid Ahern 					      size - start,
2626122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
2636122e4e4SArnaldo Carvalho de Melo }
2646122e4e4SArnaldo Carvalho de Melo 
2658d3eca20SDavid Ahern static void perf_record__exit(int status, void *arg)
266f5970550SPeter Zijlstra {
267d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
268f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
269f5970550SPeter Zijlstra 
2708d3eca20SDavid Ahern 	if (status != 0)
2718d3eca20SDavid Ahern 		return;
2728d3eca20SDavid Ahern 
273f5fc1412SJiri Olsa 	if (!file->is_pipe) {
274d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
275d20deb64SArnaldo Carvalho de Melo 
276d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
277d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
278d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
279f5fc1412SJiri Olsa 					   file->fd, true);
280d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
281d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
282d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
283c7929e47STom Zanussi 	}
284f5970550SPeter Zijlstra }
285f5970550SPeter Zijlstra 
2868115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
287a1645ce1SZhang, Yanmin {
288a1645ce1SZhang, Yanmin 	int err;
28945694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
290a1645ce1SZhang, Yanmin 	/*
291a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
292a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
293a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
294a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
295a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
296a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
297a1645ce1SZhang, Yanmin 	 */
29845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
299743eb868SArnaldo Carvalho de Melo 					     machine);
300a1645ce1SZhang, Yanmin 	if (err < 0)
301a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
30223346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
303a1645ce1SZhang, Yanmin 
304a1645ce1SZhang, Yanmin 	/*
305a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
306a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
307a1645ce1SZhang, Yanmin 	 */
30845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
309743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
310a1645ce1SZhang, Yanmin 	if (err < 0)
31145694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
312743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
313a1645ce1SZhang, Yanmin 	if (err < 0)
314a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
31523346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
316a1645ce1SZhang, Yanmin }
317a1645ce1SZhang, Yanmin 
31898402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
31998402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
32098402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
32198402807SFrederic Weisbecker };
32298402807SFrederic Weisbecker 
3238d3eca20SDavid Ahern static int perf_record__mmap_read_all(struct perf_record *rec)
32498402807SFrederic Weisbecker {
3250e2e63ddSPeter Zijlstra 	int i;
3268d3eca20SDavid Ahern 	int rc = 0;
32798402807SFrederic Weisbecker 
328d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
3298d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
3308d3eca20SDavid Ahern 			if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
3318d3eca20SDavid Ahern 				rc = -1;
3328d3eca20SDavid Ahern 				goto out;
3338d3eca20SDavid Ahern 			}
3348d3eca20SDavid Ahern 		}
33598402807SFrederic Weisbecker 	}
33698402807SFrederic Weisbecker 
3372eeaaa09SStephane Eranian 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
3388d3eca20SDavid Ahern 		rc = write_output(rec, &finished_round_event,
3398d3eca20SDavid Ahern 				  sizeof(finished_round_event));
3408d3eca20SDavid Ahern 
3418d3eca20SDavid Ahern out:
3428d3eca20SDavid Ahern 	return rc;
34398402807SFrederic Weisbecker }
34498402807SFrederic Weisbecker 
34557706abcSDavid Ahern static void perf_record__init_features(struct perf_record *rec)
34657706abcSDavid Ahern {
34757706abcSDavid Ahern 	struct perf_evlist *evsel_list = rec->evlist;
34857706abcSDavid Ahern 	struct perf_session *session = rec->session;
34957706abcSDavid Ahern 	int feat;
35057706abcSDavid Ahern 
35157706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
35257706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
35357706abcSDavid Ahern 
35457706abcSDavid Ahern 	if (rec->no_buildid)
35557706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
35657706abcSDavid Ahern 
35757706abcSDavid Ahern 	if (!have_tracepoints(&evsel_list->entries))
35857706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
35957706abcSDavid Ahern 
36057706abcSDavid Ahern 	if (!rec->opts.branch_stack)
36157706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
36257706abcSDavid Ahern }
36357706abcSDavid Ahern 
364d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
36586470930SIngo Molnar {
36657706abcSDavid Ahern 	int err;
3678b412664SPeter Zijlstra 	unsigned long waking = 0;
36846be604bSZhang, Yanmin 	const bool forks = argc > 0;
36923346f21SArnaldo Carvalho de Melo 	struct machine *machine;
37045694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
371d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
372d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
373f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
374d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3752711926aSJiri Olsa 	bool disabled = false;
37686470930SIngo Molnar 
377d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
37833e49ea7SAndi Kleen 
379d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
380f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
381f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
38218483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
383804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
384f5970550SPeter Zijlstra 
385f5fc1412SJiri Olsa 	session = perf_session__new(file, false, NULL);
38694c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
387a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
388a9a70bbcSArnaldo Carvalho de Melo 		return -1;
389a9a70bbcSArnaldo Carvalho de Melo 	}
390a9a70bbcSArnaldo Carvalho de Melo 
391d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
392d20deb64SArnaldo Carvalho de Melo 
39357706abcSDavid Ahern 	perf_record__init_features(rec);
394330aa675SStephane Eranian 
395d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
3966ef73ec4SNamhyung Kim 		err = perf_evlist__prepare_workload(evsel_list, &opts->target,
397f5fc1412SJiri Olsa 						    argv, file->is_pipe,
39855e162eaSNamhyung Kim 						    true);
39935b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
40035b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
40135b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
402856e9660SPeter Zijlstra 		}
403856e9660SPeter Zijlstra 	}
404856e9660SPeter Zijlstra 
4058d3eca20SDavid Ahern 	if (perf_record__open(rec) != 0) {
4068d3eca20SDavid Ahern 		err = -1;
4078d3eca20SDavid Ahern 		goto out_delete_session;
4088d3eca20SDavid Ahern 	}
40986470930SIngo Molnar 
410a8bb559bSNamhyung Kim 	if (!evsel_list->nr_groups)
411a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
412a8bb559bSNamhyung Kim 
413712a4b60SArnaldo Carvalho de Melo 	/*
414d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
415712a4b60SArnaldo Carvalho de Melo 	 */
416d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
417712a4b60SArnaldo Carvalho de Melo 
418f5fc1412SJiri Olsa 	if (file->is_pipe) {
419f5fc1412SJiri Olsa 		err = perf_header__write_pipe(file->fd);
420529870e3STom Zanussi 		if (err < 0)
4218d3eca20SDavid Ahern 			goto out_delete_session;
422563aecb2SJiri Olsa 	} else {
423a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
424f5fc1412SJiri Olsa 						 file->fd, false);
425d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
4268d3eca20SDavid Ahern 			goto out_delete_session;
427d5eed904SArnaldo Carvalho de Melo 	}
4287c6a1c65SPeter Zijlstra 
429d3665498SDavid Ahern 	if (!rec->no_buildid
430e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
431d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
432e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
4338d3eca20SDavid Ahern 		err = -1;
4348d3eca20SDavid Ahern 		goto out_delete_session;
435e20960c0SRobert Richter 	}
436e20960c0SRobert Richter 
43734ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
438743eb868SArnaldo Carvalho de Melo 
439f5fc1412SJiri Olsa 	if (file->is_pipe) {
44045694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
441a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
4422c46dbb5STom Zanussi 		if (err < 0) {
4432c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
4448d3eca20SDavid Ahern 			goto out_delete_session;
4452c46dbb5STom Zanussi 		}
446cd19a035STom Zanussi 
447361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
44863e0c771STom Zanussi 			/*
44963e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
45063e0c771STom Zanussi 			 * there were no tracepoints so its not really
45163e0c771STom Zanussi 			 * an error, just that we don't need to
45263e0c771STom Zanussi 			 * synthesize anything.  We really have to
45363e0c771STom Zanussi 			 * return this more properly and also
45463e0c771STom Zanussi 			 * propagate errors that now are calling die()
45563e0c771STom Zanussi 			 */
456f5fc1412SJiri Olsa 			err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list,
457743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
45863e0c771STom Zanussi 			if (err <= 0) {
45963e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
4608d3eca20SDavid Ahern 				goto out_delete_session;
46163e0c771STom Zanussi 			}
462f34b9001SDavid Ahern 			rec->bytes_written += err;
4632c46dbb5STom Zanussi 		}
46463e0c771STom Zanussi 	}
4652c46dbb5STom Zanussi 
46645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
467743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
46870162138SArnaldo Carvalho de Melo 	if (err < 0)
46945694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
470743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
471c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
472c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
473c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
474c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
47556b03f3cSArnaldo Carvalho de Melo 
47645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
477743eb868SArnaldo Carvalho de Melo 					     machine);
478c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
479c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
480c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
481c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
482c1a3a4b9SArnaldo Carvalho de Melo 
4837e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
484876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
4857e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
4867e383de4SArnaldo Carvalho de Melo 	}
487b7cece76SArnaldo Carvalho de Melo 
488a33fbd56SArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, evsel_list->threads,
48958d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
4908d3eca20SDavid Ahern 	if (err != 0)
4918d3eca20SDavid Ahern 		goto out_delete_session;
4928d3eca20SDavid Ahern 
493d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
49486470930SIngo Molnar 		struct sched_param param;
49586470930SIngo Molnar 
496d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
49786470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
4986beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
4998d3eca20SDavid Ahern 			err = -1;
5008d3eca20SDavid Ahern 			goto out_delete_session;
50186470930SIngo Molnar 		}
50286470930SIngo Molnar 	}
50386470930SIngo Molnar 
504774cb499SJiri Olsa 	/*
505774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
506774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
507774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
508774cb499SJiri Olsa 	 */
509602ad878SArnaldo Carvalho de Melo 	if (!target__none(&opts->target))
510764e16a3SDavid Ahern 		perf_evlist__enable(evsel_list);
511764e16a3SDavid Ahern 
512856e9660SPeter Zijlstra 	/*
513856e9660SPeter Zijlstra 	 * Let the child rip
514856e9660SPeter Zijlstra 	 */
515d4db3f16SArnaldo Carvalho de Melo 	if (forks)
51635b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
517856e9660SPeter Zijlstra 
518649c48a9SPeter Zijlstra 	for (;;) {
519d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
52086470930SIngo Molnar 
5218d3eca20SDavid Ahern 		if (perf_record__mmap_read_all(rec) < 0) {
5228d3eca20SDavid Ahern 			err = -1;
5238d3eca20SDavid Ahern 			goto out_delete_session;
5248d3eca20SDavid Ahern 		}
52586470930SIngo Molnar 
526d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
527649c48a9SPeter Zijlstra 			if (done)
528649c48a9SPeter Zijlstra 				break;
5295c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
5308b412664SPeter Zijlstra 			waking++;
5318b412664SPeter Zijlstra 		}
5328b412664SPeter Zijlstra 
533774cb499SJiri Olsa 		/*
534774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
535774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
536774cb499SJiri Olsa 		 * disable events in this case.
537774cb499SJiri Olsa 		 */
538602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
5394152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
5402711926aSJiri Olsa 			disabled = true;
5412711926aSJiri Olsa 		}
5428b412664SPeter Zijlstra 	}
5438b412664SPeter Zijlstra 
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 
65289fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_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 }
67889fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */
67926d33022SJiri Olsa 
68009b0fd45SJiri Olsa int record_parse_callchain(const char *arg, struct perf_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 
70789fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_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 			}
72389fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_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 
73609b0fd45SJiri Olsa static void callchain_debug(struct perf_record_opts *opts)
73709b0fd45SJiri Olsa {
738c5ff78c3SArnaldo Carvalho de Melo 	pr_debug("callchain: type %d\n", opts->call_graph);
73926d33022SJiri Olsa 
74009b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_DWARF)
74109b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
74209b0fd45SJiri Olsa 			 opts->stack_dump_size);
74309b0fd45SJiri Olsa }
74409b0fd45SJiri Olsa 
74509b0fd45SJiri Olsa int record_parse_callchain_opt(const struct option *opt,
74609b0fd45SJiri Olsa 			       const char *arg,
74709b0fd45SJiri Olsa 			       int unset)
74809b0fd45SJiri Olsa {
74909b0fd45SJiri Olsa 	struct perf_record_opts *opts = opt->value;
75009b0fd45SJiri Olsa 	int ret;
75109b0fd45SJiri Olsa 
75209b0fd45SJiri Olsa 	/* --no-call-graph */
75309b0fd45SJiri Olsa 	if (unset) {
75409b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_NONE;
75509b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
75609b0fd45SJiri Olsa 		return 0;
75709b0fd45SJiri Olsa 	}
75809b0fd45SJiri Olsa 
75909b0fd45SJiri Olsa 	ret = record_parse_callchain(arg, opts);
76009b0fd45SJiri Olsa 	if (!ret)
76109b0fd45SJiri Olsa 		callchain_debug(opts);
76209b0fd45SJiri Olsa 
76326d33022SJiri Olsa 	return ret;
76426d33022SJiri Olsa }
76526d33022SJiri Olsa 
76609b0fd45SJiri Olsa int record_callchain_opt(const struct option *opt,
76709b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
76809b0fd45SJiri Olsa 			 int unset __maybe_unused)
76909b0fd45SJiri Olsa {
77009b0fd45SJiri Olsa 	struct perf_record_opts *opts = opt->value;
77109b0fd45SJiri Olsa 
77209b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_NONE)
77309b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_FP;
77409b0fd45SJiri Olsa 
77509b0fd45SJiri Olsa 	callchain_debug(opts);
77609b0fd45SJiri Olsa 	return 0;
77709b0fd45SJiri Olsa }
77809b0fd45SJiri Olsa 
77986470930SIngo Molnar static const char * const record_usage[] = {
78086470930SIngo Molnar 	"perf record [<options>] [<command>]",
78186470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
78286470930SIngo Molnar 	NULL
78386470930SIngo Molnar };
78486470930SIngo Molnar 
785d20deb64SArnaldo Carvalho de Melo /*
786d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
787d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
788d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
789d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
790d20deb64SArnaldo Carvalho de Melo  *
791d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
792d20deb64SArnaldo Carvalho de Melo  *
793d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
794d20deb64SArnaldo Carvalho de Melo  */
795d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
796d20deb64SArnaldo Carvalho de Melo 	.opts = {
797d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
798d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
799d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
800447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
801d1cb9fceSNamhyung Kim 		.target		     = {
802d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
8033aa5939dSAdrian Hunter 			.default_per_cpu = true,
804d1cb9fceSNamhyung Kim 		},
805d20deb64SArnaldo Carvalho de Melo 	},
806d20deb64SArnaldo Carvalho de Melo };
8077865e817SFrederic Weisbecker 
80809b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
80961eaa3beSArnaldo Carvalho de Melo 
81089fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
81109b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
81261eaa3beSArnaldo Carvalho de Melo #else
81309b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp";
81461eaa3beSArnaldo Carvalho de Melo #endif
81561eaa3beSArnaldo Carvalho de Melo 
816d20deb64SArnaldo Carvalho de Melo /*
817d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
818d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
819d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
820d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
821d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
822d20deb64SArnaldo Carvalho de Melo  */
823bca647aaSTom Zanussi const struct option record_options[] = {
824d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
82586470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
826f120f9d5SJiri Olsa 		     parse_events_option),
827d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
828c171b552SLi Zefan 		     "event filter", parse_filter),
829bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
830d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
831bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
832d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
833d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
83486470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
835d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
836acac03faSKirill Smelkov 		    "collect data without buffering"),
837d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
838daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
839bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
84086470930SIngo Molnar 			    "system-wide collection from all CPUs"),
841bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
842c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
843d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
844f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
84586470930SIngo Molnar 		    "output file name"),
846*69e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
847*69e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
8482e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
849d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
850994a1f78SJiri Olsa 	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
851994a1f78SJiri Olsa 		     "number of mmap data pages",
852994a1f78SJiri Olsa 		     perf_evlist__parse_mmap_pages),
853d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
85443bece79SLin Ming 		    "put the counters into a counter group"),
85509b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
85609b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
85709b0fd45SJiri Olsa 			   &record_callchain_opt),
85809b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
85975d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
86009b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
861c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8623da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
863b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
864d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
865649c48a9SPeter Zijlstra 		    "per thread counts"),
866d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8674bba828dSAnton Blanchard 		    "Sample addresses"),
868d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8693e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
870d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
871649c48a9SPeter Zijlstra 		    "don't sample"),
872d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
873a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
874d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
875baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
876d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
877023695d9SStephane Eranian 		     "monitor event in cgroup name only",
878023695d9SStephane Eranian 		     parse_cgroups),
879bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
880bea03405SNamhyung Kim 		   "user to profile"),
881a5aabdacSStephane Eranian 
882a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
883a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
884a5aabdacSStephane Eranian 		     parse_branch_stack),
885a5aabdacSStephane Eranian 
886a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
887a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
888bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
88905484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
89005484298SAndi Kleen 		    "sample by weight (on special events only)"),
891475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
892475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
8933aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
8943aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
89586470930SIngo Molnar 	OPT_END()
89686470930SIngo Molnar };
89786470930SIngo Molnar 
8981d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
89986470930SIngo Molnar {
90069aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
901d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
902d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
90316ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
90486470930SIngo Molnar 
905334fe7a3SNamhyung Kim 	evsel_list = perf_evlist__new();
906361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
907361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
908361c99a6SArnaldo Carvalho de Melo 
909d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
910d20deb64SArnaldo Carvalho de Melo 
911bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
912a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
913602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
914bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
91586470930SIngo Molnar 
916bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
9173780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
918023695d9SStephane Eranian 			  " system-wide mode\n");
919023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
920023695d9SStephane Eranian 	}
921023695d9SStephane Eranian 
922655000e7SArnaldo Carvalho de Melo 	symbol__init();
923baa2f6ceSArnaldo Carvalho de Melo 
924ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
925646aaea6SArnaldo Carvalho de Melo 		pr_warning(
926646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
927ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
928646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
929646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
930646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
931646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
932646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
933ec80fde7SArnaldo Carvalho de Melo 
934d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
935a1ac1d3cSStephane Eranian 		disable_buildid_cache();
936655000e7SArnaldo Carvalho de Melo 
937361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
938361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
93969aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
94069aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
941bbd36e5eSPeter Zijlstra 	}
94286470930SIngo Molnar 
943*69e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
944*69e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
945*69e7e5b0SAdrian Hunter 
946602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
94716ad2ffbSNamhyung Kim 	if (err) {
948602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
94916ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
95016ad2ffbSNamhyung Kim 	}
9514bd0f2d2SNamhyung Kim 
952602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
95316ad2ffbSNamhyung Kim 	if (err) {
95416ad2ffbSNamhyung Kim 		int saved_errno = errno;
95516ad2ffbSNamhyung Kim 
956602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9573780f488SNamhyung Kim 		ui__error("%s", errbuf);
95816ad2ffbSNamhyung Kim 
95916ad2ffbSNamhyung Kim 		err = -saved_errno;
9608fa60e1fSNamhyung Kim 		goto out_symbol_exit;
96116ad2ffbSNamhyung Kim 	}
9620d37aa34SArnaldo Carvalho de Melo 
96316ad2ffbSNamhyung Kim 	err = -ENOMEM;
964b809ac10SNamhyung Kim 	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
965dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
96669aad6f1SArnaldo Carvalho de Melo 
967714647bdSJiri Olsa 	if (perf_record_opts__config(&rec->opts)) {
96839d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
9695c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
9707e4ff9e3SMike Galbraith 	}
9717e4ff9e3SMike Galbraith 
972d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
9738fa60e1fSNamhyung Kim 
9748fa60e1fSNamhyung Kim 	perf_evlist__munmap(evsel_list);
9758fa60e1fSNamhyung Kim 	perf_evlist__close(evsel_list);
97639d17dacSArnaldo Carvalho de Melo out_free_fd:
9777e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
978d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
979d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
98039d17dacSArnaldo Carvalho de Melo 	return err;
98186470930SIngo Molnar }
982