xref: /openbmc/linux/tools/perf/builtin-record.c (revision 6a4d98d787b38a130a67e78b64182b419899623a)
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;
77d20deb64SArnaldo Carvalho de Melo 	off_t			post_processing_offset;
780f82ebc4SArnaldo Carvalho de Melo };
7986470930SIngo Molnar 
80d20deb64SArnaldo Carvalho de Melo static void advance_output(struct perf_record *rec, size_t size)
819215545eSTom Zanussi {
82d20deb64SArnaldo Carvalho de Melo 	rec->bytes_written += size;
839215545eSTom Zanussi }
849215545eSTom Zanussi 
858d3eca20SDavid Ahern static int write_output(struct perf_record *rec, void *buf, size_t size)
86f5970550SPeter Zijlstra {
87f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
88f5fc1412SJiri Olsa 
89f5970550SPeter Zijlstra 	while (size) {
90f5fc1412SJiri Olsa 		int ret = write(file->fd, buf, size);
91f5970550SPeter Zijlstra 
928d3eca20SDavid Ahern 		if (ret < 0) {
934f624685SAdrian Hunter 			pr_err("failed to write perf data, error: %m\n");
948d3eca20SDavid Ahern 			return -1;
958d3eca20SDavid Ahern 		}
96f5970550SPeter Zijlstra 
97f5970550SPeter Zijlstra 		size -= ret;
98f5970550SPeter Zijlstra 		buf += ret;
99f5970550SPeter Zijlstra 
100d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written += ret;
101f5970550SPeter Zijlstra 	}
1028d3eca20SDavid Ahern 
1038d3eca20SDavid Ahern 	return 0;
104f5970550SPeter Zijlstra }
105f5970550SPeter Zijlstra 
10645694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
107d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
1081d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
1091d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
110234fbbf5SArnaldo Carvalho de Melo {
11145694aa7SArnaldo Carvalho de Melo 	struct perf_record *rec = container_of(tool, struct perf_record, tool);
1128d3eca20SDavid Ahern 	if (write_output(rec, event, event->header.size) < 0)
1138d3eca20SDavid Ahern 		return -1;
1148d3eca20SDavid Ahern 
115234fbbf5SArnaldo Carvalho de Melo 	return 0;
116234fbbf5SArnaldo Carvalho de Melo }
117234fbbf5SArnaldo Carvalho de Melo 
1188d3eca20SDavid Ahern static int perf_record__mmap_read(struct perf_record *rec,
119d20deb64SArnaldo Carvalho de Melo 				   struct perf_mmap *md)
12086470930SIngo Molnar {
121744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
12286470930SIngo Molnar 	unsigned int old = md->prev;
123918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
12486470930SIngo Molnar 	unsigned long size;
12586470930SIngo Molnar 	void *buf;
1268d3eca20SDavid Ahern 	int rc = 0;
12786470930SIngo Molnar 
128dc82009aSArnaldo Carvalho de Melo 	if (old == head)
1298d3eca20SDavid Ahern 		return 0;
13086470930SIngo Molnar 
131d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
13286470930SIngo Molnar 
13386470930SIngo Molnar 	size = head - old;
13486470930SIngo Molnar 
13586470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
13686470930SIngo Molnar 		buf = &data[old & md->mask];
13786470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
13886470930SIngo Molnar 		old += size;
13986470930SIngo Molnar 
1408d3eca20SDavid Ahern 		if (write_output(rec, buf, size) < 0) {
1418d3eca20SDavid Ahern 			rc = -1;
1428d3eca20SDavid Ahern 			goto out;
1438d3eca20SDavid Ahern 		}
14486470930SIngo Molnar 	}
14586470930SIngo Molnar 
14686470930SIngo Molnar 	buf = &data[old & md->mask];
14786470930SIngo Molnar 	size = head - old;
14886470930SIngo Molnar 	old += size;
14986470930SIngo Molnar 
1508d3eca20SDavid Ahern 	if (write_output(rec, buf, size) < 0) {
1518d3eca20SDavid Ahern 		rc = -1;
1528d3eca20SDavid Ahern 		goto out;
1538d3eca20SDavid Ahern 	}
15486470930SIngo Molnar 
15586470930SIngo Molnar 	md->prev = old;
156115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
1578d3eca20SDavid Ahern 
1588d3eca20SDavid Ahern out:
1598d3eca20SDavid Ahern 	return rc;
16086470930SIngo Molnar }
16186470930SIngo Molnar 
16286470930SIngo Molnar static volatile int done = 0;
163f7b7c26eSPeter Zijlstra static volatile int signr = -1;
16433e49ea7SAndi Kleen static volatile int child_finished = 0;
16586470930SIngo Molnar 
16686470930SIngo Molnar static void sig_handler(int sig)
16786470930SIngo Molnar {
16833e49ea7SAndi Kleen 	if (sig == SIGCHLD)
16933e49ea7SAndi Kleen 		child_finished = 1;
17033e49ea7SAndi Kleen 
17186470930SIngo Molnar 	done = 1;
172f7b7c26eSPeter Zijlstra 	signr = sig;
173f7b7c26eSPeter Zijlstra }
174f7b7c26eSPeter Zijlstra 
1751d037ca1SIrina Tirdea static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
176f7b7c26eSPeter Zijlstra {
177d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
17833e49ea7SAndi Kleen 	int status;
17933e49ea7SAndi Kleen 
180d20deb64SArnaldo Carvalho de Melo 	if (rec->evlist->workload.pid > 0) {
18133e49ea7SAndi Kleen 		if (!child_finished)
182d20deb64SArnaldo Carvalho de Melo 			kill(rec->evlist->workload.pid, SIGTERM);
183933da83aSChris Wilson 
18433e49ea7SAndi Kleen 		wait(&status);
18533e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
186d20deb64SArnaldo Carvalho de Melo 			psignal(WTERMSIG(status), rec->progname);
18733e49ea7SAndi Kleen 	}
18833e49ea7SAndi Kleen 
18918483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
190f7b7c26eSPeter Zijlstra 		return;
191f7b7c26eSPeter Zijlstra 
192f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
19386470930SIngo Molnar }
19486470930SIngo Molnar 
1958d3eca20SDavid Ahern static int perf_record__open(struct perf_record *rec)
196dd7927f4SArnaldo Carvalho de Melo {
19756e52e85SArnaldo Carvalho de Melo 	char msg[512];
1986a4bb04cSJiri Olsa 	struct perf_evsel *pos;
199d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
200d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
201d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
2028d3eca20SDavid Ahern 	int rc = 0;
203dd7927f4SArnaldo Carvalho de Melo 
204f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
205cac21425SJiri Olsa 
206dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
2073da297a6SIngo Molnar try_again:
2086a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
20956e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2103da297a6SIngo Molnar 				if (verbose)
211c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2123da297a6SIngo Molnar 				goto try_again;
2133da297a6SIngo Molnar 			}
214ca6a4258SDavid Ahern 
21556e52e85SArnaldo Carvalho de Melo 			rc = -errno;
21656e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
21756e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
21856e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
2198d3eca20SDavid Ahern 			goto out;
2207c6a1c65SPeter Zijlstra 		}
2217c6a1c65SPeter Zijlstra 	}
2227c6a1c65SPeter Zijlstra 
2231491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
2240a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2250a102479SFrederic Weisbecker 			strerror(errno));
2268d3eca20SDavid Ahern 		rc = -1;
2278d3eca20SDavid Ahern 		goto out;
2280a102479SFrederic Weisbecker 	}
2290a102479SFrederic Weisbecker 
23018e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
2318d3eca20SDavid Ahern 		if (errno == EPERM) {
2328d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
23318e60939SNelson Elhage 			       "Consider increasing "
23418e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
23518e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
23618e60939SNelson Elhage 			       "(current value: %d)\n", opts->mmap_pages);
2378d3eca20SDavid Ahern 			rc = -errno;
2388d3eca20SDavid Ahern 		} else {
2398d3eca20SDavid Ahern 			pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
2408d3eca20SDavid Ahern 			rc = -errno;
2418d3eca20SDavid Ahern 		}
2428d3eca20SDavid Ahern 		goto out;
24318e60939SNelson Elhage 	}
2440a27d7f9SArnaldo Carvalho de Melo 
245a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
2467b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
2478d3eca20SDavid Ahern out:
2488d3eca20SDavid Ahern 	return rc;
249a91e5431SArnaldo Carvalho de Melo }
250a91e5431SArnaldo Carvalho de Melo 
251d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
2526122e4e4SArnaldo Carvalho de Melo {
253f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
254f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
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 
260f5fc1412SJiri Olsa 	session->fd = file->fd;
261f5fc1412SJiri Olsa 	return __perf_session__process_events(session, rec->post_processing_offset,
262d20deb64SArnaldo Carvalho de Melo 					      size - rec->post_processing_offset,
2636122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
2646122e4e4SArnaldo Carvalho de Melo }
2656122e4e4SArnaldo Carvalho de Melo 
2668d3eca20SDavid Ahern static void perf_record__exit(int status, void *arg)
267f5970550SPeter Zijlstra {
268d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
269f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
270f5970550SPeter Zijlstra 
2718d3eca20SDavid Ahern 	if (status != 0)
2728d3eca20SDavid Ahern 		return;
2738d3eca20SDavid Ahern 
274f5fc1412SJiri Olsa 	if (!file->is_pipe) {
275d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
276d20deb64SArnaldo Carvalho de Melo 
277d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
278d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
279d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
280f5fc1412SJiri Olsa 					   file->fd, true);
281d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
282d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
283d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
284c7929e47STom Zanussi 	}
285f5970550SPeter Zijlstra }
286f5970550SPeter Zijlstra 
2878115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
288a1645ce1SZhang, Yanmin {
289a1645ce1SZhang, Yanmin 	int err;
29045694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
291a1645ce1SZhang, Yanmin 	/*
292a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
293a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
294a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
295a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
296a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
297a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
298a1645ce1SZhang, Yanmin 	 */
29945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
300743eb868SArnaldo Carvalho de Melo 					     machine);
301a1645ce1SZhang, Yanmin 	if (err < 0)
302a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
30323346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
304a1645ce1SZhang, Yanmin 
305a1645ce1SZhang, Yanmin 	/*
306a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
307a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
308a1645ce1SZhang, Yanmin 	 */
30945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
310743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
311a1645ce1SZhang, Yanmin 	if (err < 0)
31245694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
313743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
314a1645ce1SZhang, Yanmin 	if (err < 0)
315a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
31623346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
317a1645ce1SZhang, Yanmin }
318a1645ce1SZhang, Yanmin 
31998402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
32098402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
32198402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
32298402807SFrederic Weisbecker };
32398402807SFrederic Weisbecker 
3248d3eca20SDavid Ahern static int perf_record__mmap_read_all(struct perf_record *rec)
32598402807SFrederic Weisbecker {
3260e2e63ddSPeter Zijlstra 	int i;
3278d3eca20SDavid Ahern 	int rc = 0;
32898402807SFrederic Weisbecker 
329d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
3308d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
3318d3eca20SDavid Ahern 			if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
3328d3eca20SDavid Ahern 				rc = -1;
3338d3eca20SDavid Ahern 				goto out;
3348d3eca20SDavid Ahern 			}
3358d3eca20SDavid Ahern 		}
33698402807SFrederic Weisbecker 	}
33798402807SFrederic Weisbecker 
3382eeaaa09SStephane Eranian 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
3398d3eca20SDavid Ahern 		rc = write_output(rec, &finished_round_event,
3408d3eca20SDavid Ahern 				  sizeof(finished_round_event));
3418d3eca20SDavid Ahern 
3428d3eca20SDavid Ahern out:
3438d3eca20SDavid Ahern 	return rc;
34498402807SFrederic Weisbecker }
34598402807SFrederic Weisbecker 
346d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
34786470930SIngo Molnar {
348f5fc1412SJiri Olsa 	int err, feat;
3498b412664SPeter Zijlstra 	unsigned long waking = 0;
35046be604bSZhang, Yanmin 	const bool forks = argc > 0;
35123346f21SArnaldo Carvalho de Melo 	struct machine *machine;
35245694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
353d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
354d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
355f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
356d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3572711926aSJiri Olsa 	bool disabled = false;
35886470930SIngo Molnar 
359d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
36033e49ea7SAndi Kleen 
361d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
362f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
363f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
36418483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
365804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
366f5970550SPeter Zijlstra 
367f5fc1412SJiri Olsa 	session = perf_session__new(file, false, NULL);
36894c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
369a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
370a9a70bbcSArnaldo Carvalho de Melo 		return -1;
371a9a70bbcSArnaldo Carvalho de Melo 	}
372a9a70bbcSArnaldo Carvalho de Melo 
373d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
374d20deb64SArnaldo Carvalho de Melo 
375781ba9d2SRobert Richter 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
376781ba9d2SRobert Richter 		perf_header__set_feat(&session->header, feat);
377781ba9d2SRobert Richter 
378781ba9d2SRobert Richter 	if (rec->no_buildid)
379781ba9d2SRobert Richter 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
380781ba9d2SRobert Richter 
381781ba9d2SRobert Richter 	if (!have_tracepoints(&evsel_list->entries))
3822eeaaa09SStephane Eranian 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
383baa2f6ceSArnaldo Carvalho de Melo 
384330aa675SStephane Eranian 	if (!rec->opts.branch_stack)
385330aa675SStephane Eranian 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
386330aa675SStephane Eranian 
387d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
3886ef73ec4SNamhyung Kim 		err = perf_evlist__prepare_workload(evsel_list, &opts->target,
389f5fc1412SJiri Olsa 						    argv, file->is_pipe,
39055e162eaSNamhyung Kim 						    true);
39135b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
39235b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
39335b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
394856e9660SPeter Zijlstra 		}
395856e9660SPeter Zijlstra 	}
396856e9660SPeter Zijlstra 
3978d3eca20SDavid Ahern 	if (perf_record__open(rec) != 0) {
3988d3eca20SDavid Ahern 		err = -1;
3998d3eca20SDavid Ahern 		goto out_delete_session;
4008d3eca20SDavid Ahern 	}
40186470930SIngo Molnar 
402a8bb559bSNamhyung Kim 	if (!evsel_list->nr_groups)
403a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
404a8bb559bSNamhyung Kim 
405712a4b60SArnaldo Carvalho de Melo 	/*
406d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
407712a4b60SArnaldo Carvalho de Melo 	 */
408d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
409712a4b60SArnaldo Carvalho de Melo 
410f5fc1412SJiri Olsa 	if (file->is_pipe) {
411f5fc1412SJiri Olsa 		err = perf_header__write_pipe(file->fd);
412529870e3STom Zanussi 		if (err < 0)
4138d3eca20SDavid Ahern 			goto out_delete_session;
414563aecb2SJiri Olsa 	} else {
415a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
416f5fc1412SJiri Olsa 						 file->fd, false);
417d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
4188d3eca20SDavid Ahern 			goto out_delete_session;
419d5eed904SArnaldo Carvalho de Melo 	}
4207c6a1c65SPeter Zijlstra 
421d3665498SDavid Ahern 	if (!rec->no_buildid
422e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
423d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
424e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
4258d3eca20SDavid Ahern 		err = -1;
4268d3eca20SDavid Ahern 		goto out_delete_session;
427e20960c0SRobert Richter 	}
428e20960c0SRobert Richter 
429f5fc1412SJiri Olsa 	rec->post_processing_offset = lseek(file->fd, 0, SEEK_CUR);
4306122e4e4SArnaldo Carvalho de Melo 
43134ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
432743eb868SArnaldo Carvalho de Melo 
433f5fc1412SJiri Olsa 	if (file->is_pipe) {
43445694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
435a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
4362c46dbb5STom Zanussi 		if (err < 0) {
4372c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
4388d3eca20SDavid Ahern 			goto out_delete_session;
4392c46dbb5STom Zanussi 		}
440cd19a035STom Zanussi 
441361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
44263e0c771STom Zanussi 			/*
44363e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
44463e0c771STom Zanussi 			 * there were no tracepoints so its not really
44563e0c771STom Zanussi 			 * an error, just that we don't need to
44663e0c771STom Zanussi 			 * synthesize anything.  We really have to
44763e0c771STom Zanussi 			 * return this more properly and also
44863e0c771STom Zanussi 			 * propagate errors that now are calling die()
44963e0c771STom Zanussi 			 */
450f5fc1412SJiri Olsa 			err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list,
451743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
45263e0c771STom Zanussi 			if (err <= 0) {
45363e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
4548d3eca20SDavid Ahern 				goto out_delete_session;
45563e0c771STom Zanussi 			}
456d20deb64SArnaldo Carvalho de Melo 			advance_output(rec, err);
4572c46dbb5STom Zanussi 		}
45863e0c771STom Zanussi 	}
4592c46dbb5STom Zanussi 
46045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
461743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
46270162138SArnaldo Carvalho de Melo 	if (err < 0)
46345694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
464743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
465c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
466c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
467c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
468c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
46956b03f3cSArnaldo Carvalho de Melo 
47045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
471743eb868SArnaldo Carvalho de Melo 					     machine);
472c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
473c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
474c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
475c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
476c1a3a4b9SArnaldo Carvalho de Melo 
4777e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
478876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
4797e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
4807e383de4SArnaldo Carvalho de Melo 	}
481b7cece76SArnaldo Carvalho de Melo 
482e4dd45feSJiri Olsa 	if (perf_target__has_task(&opts->target))
4838d3eca20SDavid Ahern 		err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
4848115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
485743eb868SArnaldo Carvalho de Melo 						  machine);
486e4dd45feSJiri Olsa 	else if (perf_target__has_cpu(&opts->target))
4878d3eca20SDavid Ahern 		err = perf_event__synthesize_threads(tool, process_synthesized_event,
488743eb868SArnaldo Carvalho de Melo 					       machine);
489e4dd45feSJiri Olsa 	else /* command specified */
490e4dd45feSJiri Olsa 		err = 0;
4917c6a1c65SPeter Zijlstra 
4928d3eca20SDavid Ahern 	if (err != 0)
4938d3eca20SDavid Ahern 		goto out_delete_session;
4948d3eca20SDavid Ahern 
495d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
49686470930SIngo Molnar 		struct sched_param param;
49786470930SIngo Molnar 
498d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
49986470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5006beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
5018d3eca20SDavid Ahern 			err = -1;
5028d3eca20SDavid Ahern 			goto out_delete_session;
50386470930SIngo Molnar 		}
50486470930SIngo Molnar 	}
50586470930SIngo Molnar 
506774cb499SJiri Olsa 	/*
507774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
508774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
509774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
510774cb499SJiri Olsa 	 */
511774cb499SJiri Olsa 	if (!perf_target__none(&opts->target))
512764e16a3SDavid Ahern 		perf_evlist__enable(evsel_list);
513764e16a3SDavid Ahern 
514856e9660SPeter Zijlstra 	/*
515856e9660SPeter Zijlstra 	 * Let the child rip
516856e9660SPeter Zijlstra 	 */
517d4db3f16SArnaldo Carvalho de Melo 	if (forks)
51835b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
519856e9660SPeter Zijlstra 
520649c48a9SPeter Zijlstra 	for (;;) {
521d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
52286470930SIngo Molnar 
5238d3eca20SDavid Ahern 		if (perf_record__mmap_read_all(rec) < 0) {
5248d3eca20SDavid Ahern 			err = -1;
5258d3eca20SDavid Ahern 			goto out_delete_session;
5268d3eca20SDavid Ahern 		}
52786470930SIngo Molnar 
528d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
529649c48a9SPeter Zijlstra 			if (done)
530649c48a9SPeter Zijlstra 				break;
5315c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
5328b412664SPeter Zijlstra 			waking++;
5338b412664SPeter Zijlstra 		}
5348b412664SPeter Zijlstra 
535774cb499SJiri Olsa 		/*
536774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
537774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
538774cb499SJiri Olsa 		 * disable events in this case.
539774cb499SJiri Olsa 		 */
5402711926aSJiri Olsa 		if (done && !disabled && !perf_target__none(&opts->target)) {
5414152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
5422711926aSJiri Olsa 			disabled = true;
5432711926aSJiri Olsa 		}
5448b412664SPeter Zijlstra 	}
5458b412664SPeter Zijlstra 
54618483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
547b44308f5SArnaldo Carvalho de Melo 		return 0;
548b44308f5SArnaldo Carvalho de Melo 
5498b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
55086470930SIngo Molnar 
55186470930SIngo Molnar 	/*
55286470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
55386470930SIngo Molnar 	 */
55486470930SIngo Molnar 	fprintf(stderr,
5559486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
556d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
557*6a4d98d7SJiri Olsa 		file->path,
558d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
55986470930SIngo Molnar 
56086470930SIngo Molnar 	return 0;
56139d17dacSArnaldo Carvalho de Melo 
56239d17dacSArnaldo Carvalho de Melo out_delete_session:
56339d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
56439d17dacSArnaldo Carvalho de Melo 	return err;
56586470930SIngo Molnar }
56686470930SIngo Molnar 
567bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
568bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
569bdfebd84SRoberto Agostino Vitillo 
570bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
571bdfebd84SRoberto Agostino Vitillo 
572bdfebd84SRoberto Agostino Vitillo struct branch_mode {
573bdfebd84SRoberto Agostino Vitillo 	const char *name;
574bdfebd84SRoberto Agostino Vitillo 	int mode;
575bdfebd84SRoberto Agostino Vitillo };
576bdfebd84SRoberto Agostino Vitillo 
577bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
578bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
579bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
580bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
581bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
582bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
583bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
584bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
5850126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
5860126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
5870126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
588bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
589bdfebd84SRoberto Agostino Vitillo };
590bdfebd84SRoberto Agostino Vitillo 
591bdfebd84SRoberto Agostino Vitillo static int
592a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
593bdfebd84SRoberto Agostino Vitillo {
594bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
595bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
596bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
597bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
598bdfebd84SRoberto Agostino Vitillo 
599bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
600bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
601a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
602bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
603bdfebd84SRoberto Agostino Vitillo 
604a5aabdacSStephane Eranian 	if (unset)
605a5aabdacSStephane Eranian 		return 0;
606bdfebd84SRoberto Agostino Vitillo 
607a5aabdacSStephane Eranian 	/*
608a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
609a5aabdacSStephane Eranian 	 */
610a5aabdacSStephane Eranian 	if (*mode)
611a5aabdacSStephane Eranian 		return -1;
612a5aabdacSStephane Eranian 
613a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
614a5aabdacSStephane Eranian 	if (str) {
615bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
616bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
617bdfebd84SRoberto Agostino Vitillo 		if (!s)
618bdfebd84SRoberto Agostino Vitillo 			return -1;
619bdfebd84SRoberto Agostino Vitillo 
620bdfebd84SRoberto Agostino Vitillo 		for (;;) {
621bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
622bdfebd84SRoberto Agostino Vitillo 			if (p)
623bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
624bdfebd84SRoberto Agostino Vitillo 
625bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
626bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
627bdfebd84SRoberto Agostino Vitillo 					break;
628bdfebd84SRoberto Agostino Vitillo 			}
629a5aabdacSStephane Eranian 			if (!br->name) {
630a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
631a5aabdacSStephane Eranian 					    " check man page\n", s);
632bdfebd84SRoberto Agostino Vitillo 				goto error;
633a5aabdacSStephane Eranian 			}
634bdfebd84SRoberto Agostino Vitillo 
635bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
636bdfebd84SRoberto Agostino Vitillo 
637bdfebd84SRoberto Agostino Vitillo 			if (!p)
638bdfebd84SRoberto Agostino Vitillo 				break;
639bdfebd84SRoberto Agostino Vitillo 
640bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
641bdfebd84SRoberto Agostino Vitillo 		}
642a5aabdacSStephane Eranian 	}
643bdfebd84SRoberto Agostino Vitillo 	ret = 0;
644bdfebd84SRoberto Agostino Vitillo 
645a5aabdacSStephane Eranian 	/* default to any branch */
646bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
647a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
648bdfebd84SRoberto Agostino Vitillo 	}
649bdfebd84SRoberto Agostino Vitillo error:
650bdfebd84SRoberto Agostino Vitillo 	free(os);
651bdfebd84SRoberto Agostino Vitillo 	return ret;
652bdfebd84SRoberto Agostino Vitillo }
653bdfebd84SRoberto Agostino Vitillo 
65489fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
65526d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size)
65626d33022SJiri Olsa {
65726d33022SJiri Olsa 	char *endptr;
65826d33022SJiri Olsa 	unsigned long size;
65926d33022SJiri Olsa 	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
66026d33022SJiri Olsa 
66126d33022SJiri Olsa 	size = strtoul(str, &endptr, 0);
66226d33022SJiri Olsa 
66326d33022SJiri Olsa 	do {
66426d33022SJiri Olsa 		if (*endptr)
66526d33022SJiri Olsa 			break;
66626d33022SJiri Olsa 
66726d33022SJiri Olsa 		size = round_up(size, sizeof(u64));
66826d33022SJiri Olsa 		if (!size || size > max_size)
66926d33022SJiri Olsa 			break;
67026d33022SJiri Olsa 
67126d33022SJiri Olsa 		*_size = size;
67226d33022SJiri Olsa 		return 0;
67326d33022SJiri Olsa 
67426d33022SJiri Olsa 	} while (0);
67526d33022SJiri Olsa 
67626d33022SJiri Olsa 	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
67726d33022SJiri Olsa 	       max_size, str);
67826d33022SJiri Olsa 	return -1;
67926d33022SJiri Olsa }
68089fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */
68126d33022SJiri Olsa 
68275d9a108SArnaldo Carvalho de Melo int record_parse_callchain_opt(const struct option *opt,
68375d9a108SArnaldo Carvalho de Melo 			       const char *arg, int unset)
68426d33022SJiri Olsa {
685c5ff78c3SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = opt->value;
68626d33022SJiri Olsa 	char *tok, *name, *saveptr = NULL;
68726d33022SJiri Olsa 	char *buf;
68826d33022SJiri Olsa 	int ret = -1;
68926d33022SJiri Olsa 
69026d33022SJiri Olsa 	/* --no-call-graph */
69126d33022SJiri Olsa 	if (unset)
69226d33022SJiri Olsa 		return 0;
69326d33022SJiri Olsa 
69426d33022SJiri Olsa 	/* We specified default option if none is provided. */
69526d33022SJiri Olsa 	BUG_ON(!arg);
69626d33022SJiri Olsa 
69726d33022SJiri Olsa 	/* We need buffer that we know we can write to. */
69826d33022SJiri Olsa 	buf = malloc(strlen(arg) + 1);
69926d33022SJiri Olsa 	if (!buf)
70026d33022SJiri Olsa 		return -ENOMEM;
70126d33022SJiri Olsa 
70226d33022SJiri Olsa 	strcpy(buf, arg);
70326d33022SJiri Olsa 
70426d33022SJiri Olsa 	tok = strtok_r((char *)buf, ",", &saveptr);
70526d33022SJiri Olsa 	name = tok ? : (char *)buf;
70626d33022SJiri Olsa 
70726d33022SJiri Olsa 	do {
70826d33022SJiri Olsa 		/* Framepointer style */
70926d33022SJiri Olsa 		if (!strncmp(name, "fp", sizeof("fp"))) {
71026d33022SJiri Olsa 			if (!strtok_r(NULL, ",", &saveptr)) {
711c5ff78c3SArnaldo Carvalho de Melo 				opts->call_graph = CALLCHAIN_FP;
71226d33022SJiri Olsa 				ret = 0;
71326d33022SJiri Olsa 			} else
71426d33022SJiri Olsa 				pr_err("callchain: No more arguments "
71526d33022SJiri Olsa 				       "needed for -g fp\n");
71626d33022SJiri Olsa 			break;
71726d33022SJiri Olsa 
71889fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
71926d33022SJiri Olsa 		/* Dwarf style */
72026d33022SJiri Olsa 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
72161eaa3beSArnaldo Carvalho de Melo 			const unsigned long default_stack_dump_size = 8192;
72261eaa3beSArnaldo Carvalho de Melo 
72326d33022SJiri Olsa 			ret = 0;
724c5ff78c3SArnaldo Carvalho de Melo 			opts->call_graph = CALLCHAIN_DWARF;
725c5ff78c3SArnaldo Carvalho de Melo 			opts->stack_dump_size = default_stack_dump_size;
72626d33022SJiri Olsa 
72726d33022SJiri Olsa 			tok = strtok_r(NULL, ",", &saveptr);
72826d33022SJiri Olsa 			if (tok) {
72926d33022SJiri Olsa 				unsigned long size = 0;
73026d33022SJiri Olsa 
73126d33022SJiri Olsa 				ret = get_stack_size(tok, &size);
732c5ff78c3SArnaldo Carvalho de Melo 				opts->stack_dump_size = size;
73326d33022SJiri Olsa 			}
73426d33022SJiri Olsa 
73526d33022SJiri Olsa 			if (!ret)
73626d33022SJiri Olsa 				pr_debug("callchain: stack dump size %d\n",
737c5ff78c3SArnaldo Carvalho de Melo 					 opts->stack_dump_size);
73889fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */
73926d33022SJiri Olsa 		} else {
74026d33022SJiri Olsa 			pr_err("callchain: Unknown -g option "
74126d33022SJiri Olsa 			       "value: %s\n", arg);
74226d33022SJiri Olsa 			break;
74326d33022SJiri Olsa 		}
74426d33022SJiri Olsa 
74526d33022SJiri Olsa 	} while (0);
74626d33022SJiri Olsa 
74726d33022SJiri Olsa 	free(buf);
74826d33022SJiri Olsa 
74926d33022SJiri Olsa 	if (!ret)
750c5ff78c3SArnaldo Carvalho de Melo 		pr_debug("callchain: type %d\n", opts->call_graph);
75126d33022SJiri Olsa 
75226d33022SJiri Olsa 	return ret;
75326d33022SJiri Olsa }
75426d33022SJiri Olsa 
75586470930SIngo Molnar static const char * const record_usage[] = {
75686470930SIngo Molnar 	"perf record [<options>] [<command>]",
75786470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
75886470930SIngo Molnar 	NULL
75986470930SIngo Molnar };
76086470930SIngo Molnar 
761d20deb64SArnaldo Carvalho de Melo /*
762d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
763d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
764d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
765d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
766d20deb64SArnaldo Carvalho de Melo  *
767d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
768d20deb64SArnaldo Carvalho de Melo  *
769d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
770d20deb64SArnaldo Carvalho de Melo  */
771d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
772d20deb64SArnaldo Carvalho de Melo 	.opts = {
773d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
774d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
775d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
776447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
777d1cb9fceSNamhyung Kim 		.target		     = {
778d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
779d1cb9fceSNamhyung Kim 		},
780d20deb64SArnaldo Carvalho de Melo 	},
781d20deb64SArnaldo Carvalho de Melo };
7827865e817SFrederic Weisbecker 
78361eaa3beSArnaldo Carvalho de Melo #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
78461eaa3beSArnaldo Carvalho de Melo 
78589fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
78675d9a108SArnaldo Carvalho de Melo const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
78761eaa3beSArnaldo Carvalho de Melo #else
78875d9a108SArnaldo Carvalho de Melo const char record_callchain_help[] = CALLCHAIN_HELP "[fp]";
78961eaa3beSArnaldo Carvalho de Melo #endif
79061eaa3beSArnaldo Carvalho de Melo 
791d20deb64SArnaldo Carvalho de Melo /*
792d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
793d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
794d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
795d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
796d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
797d20deb64SArnaldo Carvalho de Melo  */
798bca647aaSTom Zanussi const struct option record_options[] = {
799d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
80086470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
801f120f9d5SJiri Olsa 		     parse_events_option),
802d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
803c171b552SLi Zefan 		     "event filter", parse_filter),
804bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
805d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
806bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
807d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
808d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
80986470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
810d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
811acac03faSKirill Smelkov 		    "collect data without buffering"),
812d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
813daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
814bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
81586470930SIngo Molnar 			    "system-wide collection from all CPUs"),
816bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
817c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
818d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
819f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
82086470930SIngo Molnar 		    "output file name"),
821d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
8222e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
823d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
824994a1f78SJiri Olsa 	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
825994a1f78SJiri Olsa 		     "number of mmap data pages",
826994a1f78SJiri Olsa 		     perf_evlist__parse_mmap_pages),
827d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
82843bece79SLin Ming 		    "put the counters into a counter group"),
829c5ff78c3SArnaldo Carvalho de Melo 	OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts,
83075d9a108SArnaldo Carvalho de Melo 			     "mode[,dump_size]", record_callchain_help,
83175d9a108SArnaldo Carvalho de Melo 			     &record_parse_callchain_opt, "fp"),
832c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8333da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
834b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
835d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
836649c48a9SPeter Zijlstra 		    "per thread counts"),
837d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8384bba828dSAnton Blanchard 		    "Sample addresses"),
839d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8403e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
841d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
842649c48a9SPeter Zijlstra 		    "don't sample"),
843d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
844a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
845d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
846baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
847d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
848023695d9SStephane Eranian 		     "monitor event in cgroup name only",
849023695d9SStephane Eranian 		     parse_cgroups),
850bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
851bea03405SNamhyung Kim 		   "user to profile"),
852a5aabdacSStephane Eranian 
853a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
854a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
855a5aabdacSStephane Eranian 		     parse_branch_stack),
856a5aabdacSStephane Eranian 
857a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
858a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
859bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
86005484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
86105484298SAndi Kleen 		    "sample by weight (on special events only)"),
862475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
863475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
86486470930SIngo Molnar 	OPT_END()
86586470930SIngo Molnar };
86686470930SIngo Molnar 
8671d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
86886470930SIngo Molnar {
86969aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
870d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
871d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
87216ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
87386470930SIngo Molnar 
874334fe7a3SNamhyung Kim 	evsel_list = perf_evlist__new();
875361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
876361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
877361c99a6SArnaldo Carvalho de Melo 
878d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
879d20deb64SArnaldo Carvalho de Melo 
880bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
881a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
882d67356e7SNamhyung Kim 	if (!argc && perf_target__none(&rec->opts.target))
883bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
88486470930SIngo Molnar 
885bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
8863780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
887023695d9SStephane Eranian 			  " system-wide mode\n");
888023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
889023695d9SStephane Eranian 	}
890023695d9SStephane Eranian 
891655000e7SArnaldo Carvalho de Melo 	symbol__init();
892baa2f6ceSArnaldo Carvalho de Melo 
893ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
894646aaea6SArnaldo Carvalho de Melo 		pr_warning(
895646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
896ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
897646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
898646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
899646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
900646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
901646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
902ec80fde7SArnaldo Carvalho de Melo 
903d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
904a1ac1d3cSStephane Eranian 		disable_buildid_cache();
905655000e7SArnaldo Carvalho de Melo 
906361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
907361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
90869aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
90969aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
910bbd36e5eSPeter Zijlstra 	}
91186470930SIngo Molnar 
91216ad2ffbSNamhyung Kim 	err = perf_target__validate(&rec->opts.target);
91316ad2ffbSNamhyung Kim 	if (err) {
91416ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
91516ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
91616ad2ffbSNamhyung Kim 	}
9174bd0f2d2SNamhyung Kim 
91816ad2ffbSNamhyung Kim 	err = perf_target__parse_uid(&rec->opts.target);
91916ad2ffbSNamhyung Kim 	if (err) {
92016ad2ffbSNamhyung Kim 		int saved_errno = errno;
92116ad2ffbSNamhyung Kim 
92216ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9233780f488SNamhyung Kim 		ui__error("%s", errbuf);
92416ad2ffbSNamhyung Kim 
92516ad2ffbSNamhyung Kim 		err = -saved_errno;
9268fa60e1fSNamhyung Kim 		goto out_symbol_exit;
92716ad2ffbSNamhyung Kim 	}
9280d37aa34SArnaldo Carvalho de Melo 
92916ad2ffbSNamhyung Kim 	err = -ENOMEM;
930b809ac10SNamhyung Kim 	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
931dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
93269aad6f1SArnaldo Carvalho de Melo 
933d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_interval != ULLONG_MAX)
934d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.user_interval;
935d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_freq != UINT_MAX)
936d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = rec->opts.user_freq;
937f9212819SFrederic Weisbecker 
9387e4ff9e3SMike Galbraith 	/*
9397e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
9407e4ff9e3SMike Galbraith 	 */
941d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.default_interval)
942d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = 0;
943d20deb64SArnaldo Carvalho de Melo 	else if (rec->opts.freq) {
944d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.freq;
9457e4ff9e3SMike Galbraith 	} else {
9463780f488SNamhyung Kim 		ui__error("frequency and count are zero, aborting\n");
94739d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
9485c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
9497e4ff9e3SMike Galbraith 	}
9507e4ff9e3SMike Galbraith 
951d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
9528fa60e1fSNamhyung Kim 
9538fa60e1fSNamhyung Kim 	perf_evlist__munmap(evsel_list);
9548fa60e1fSNamhyung Kim 	perf_evlist__close(evsel_list);
95539d17dacSArnaldo Carvalho de Melo out_free_fd:
9567e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
957d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
958d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
95939d17dacSArnaldo Carvalho de Melo 	return err;
96086470930SIngo Molnar }
961