xref: /openbmc/linux/tools/perf/builtin-record.c (revision 918512b435e15fefe609d236e0ecd62cb8f389c9)
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"
277c6a1c65SPeter Zijlstra 
2886470930SIngo Molnar #include <unistd.h>
2986470930SIngo Molnar #include <sched.h>
30a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3186470930SIngo Molnar 
3289fe808aSIngo Molnar #ifndef HAVE_ON_EXIT_SUPPORT
3378da39faSBernhard Rosenkraenzer #ifndef ATEXIT_MAX
3478da39faSBernhard Rosenkraenzer #define ATEXIT_MAX 32
3578da39faSBernhard Rosenkraenzer #endif
3678da39faSBernhard Rosenkraenzer static int __on_exit_count = 0;
3778da39faSBernhard Rosenkraenzer typedef void (*on_exit_func_t) (int, void *);
3878da39faSBernhard Rosenkraenzer static on_exit_func_t __on_exit_funcs[ATEXIT_MAX];
3978da39faSBernhard Rosenkraenzer static void *__on_exit_args[ATEXIT_MAX];
4078da39faSBernhard Rosenkraenzer static int __exitcode = 0;
4178da39faSBernhard Rosenkraenzer static void __handle_on_exit_funcs(void);
4278da39faSBernhard Rosenkraenzer static int on_exit(on_exit_func_t function, void *arg);
4378da39faSBernhard Rosenkraenzer #define exit(x) (exit)(__exitcode = (x))
4478da39faSBernhard Rosenkraenzer 
4578da39faSBernhard Rosenkraenzer static int on_exit(on_exit_func_t function, void *arg)
4678da39faSBernhard Rosenkraenzer {
4778da39faSBernhard Rosenkraenzer 	if (__on_exit_count == ATEXIT_MAX)
4878da39faSBernhard Rosenkraenzer 		return -ENOMEM;
4978da39faSBernhard Rosenkraenzer 	else if (__on_exit_count == 0)
5078da39faSBernhard Rosenkraenzer 		atexit(__handle_on_exit_funcs);
5178da39faSBernhard Rosenkraenzer 	__on_exit_funcs[__on_exit_count] = function;
5278da39faSBernhard Rosenkraenzer 	__on_exit_args[__on_exit_count++] = arg;
5378da39faSBernhard Rosenkraenzer 	return 0;
5478da39faSBernhard Rosenkraenzer }
5578da39faSBernhard Rosenkraenzer 
5678da39faSBernhard Rosenkraenzer static void __handle_on_exit_funcs(void)
5778da39faSBernhard Rosenkraenzer {
5878da39faSBernhard Rosenkraenzer 	int i;
5978da39faSBernhard Rosenkraenzer 	for (i = 0; i < __on_exit_count; i++)
6078da39faSBernhard Rosenkraenzer 		__on_exit_funcs[i] (__exitcode, __on_exit_args[i]);
6178da39faSBernhard Rosenkraenzer }
6278da39faSBernhard Rosenkraenzer #endif
6378da39faSBernhard Rosenkraenzer 
64d20deb64SArnaldo Carvalho de Melo struct perf_record {
6545694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
66d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts	opts;
67d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
68d20deb64SArnaldo Carvalho de Melo 	const char		*output_name;
69d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
70d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
71d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
72d20deb64SArnaldo Carvalho de Melo 	int			output;
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 {
87f5970550SPeter Zijlstra 	while (size) {
88d20deb64SArnaldo Carvalho de Melo 		int ret = write(rec->output, buf, size);
89f5970550SPeter Zijlstra 
908d3eca20SDavid Ahern 		if (ret < 0) {
918d3eca20SDavid Ahern 			pr_err("failed to write\n");
928d3eca20SDavid Ahern 			return -1;
938d3eca20SDavid Ahern 		}
94f5970550SPeter Zijlstra 
95f5970550SPeter Zijlstra 		size -= ret;
96f5970550SPeter Zijlstra 		buf += ret;
97f5970550SPeter Zijlstra 
98d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written += ret;
99f5970550SPeter Zijlstra 	}
1008d3eca20SDavid Ahern 
1018d3eca20SDavid Ahern 	return 0;
102f5970550SPeter Zijlstra }
103f5970550SPeter Zijlstra 
10445694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
105d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
1061d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
1071d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
108234fbbf5SArnaldo Carvalho de Melo {
10945694aa7SArnaldo Carvalho de Melo 	struct perf_record *rec = container_of(tool, struct perf_record, tool);
1108d3eca20SDavid Ahern 	if (write_output(rec, event, event->header.size) < 0)
1118d3eca20SDavid Ahern 		return -1;
1128d3eca20SDavid Ahern 
113234fbbf5SArnaldo Carvalho de Melo 	return 0;
114234fbbf5SArnaldo Carvalho de Melo }
115234fbbf5SArnaldo Carvalho de Melo 
1168d3eca20SDavid Ahern static int perf_record__mmap_read(struct perf_record *rec,
117d20deb64SArnaldo Carvalho de Melo 				   struct perf_mmap *md)
11886470930SIngo Molnar {
119744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
12086470930SIngo Molnar 	unsigned int old = md->prev;
121*918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
12286470930SIngo Molnar 	unsigned long size;
12386470930SIngo Molnar 	void *buf;
1248d3eca20SDavid Ahern 	int rc = 0;
12586470930SIngo Molnar 
126dc82009aSArnaldo Carvalho de Melo 	if (old == head)
1278d3eca20SDavid Ahern 		return 0;
12886470930SIngo Molnar 
129d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
13086470930SIngo Molnar 
13186470930SIngo Molnar 	size = head - old;
13286470930SIngo Molnar 
13386470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
13486470930SIngo Molnar 		buf = &data[old & md->mask];
13586470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
13686470930SIngo Molnar 		old += size;
13786470930SIngo Molnar 
1388d3eca20SDavid Ahern 		if (write_output(rec, buf, size) < 0) {
1398d3eca20SDavid Ahern 			rc = -1;
1408d3eca20SDavid Ahern 			goto out;
1418d3eca20SDavid Ahern 		}
14286470930SIngo Molnar 	}
14386470930SIngo Molnar 
14486470930SIngo Molnar 	buf = &data[old & md->mask];
14586470930SIngo Molnar 	size = head - old;
14686470930SIngo Molnar 	old += size;
14786470930SIngo Molnar 
1488d3eca20SDavid Ahern 	if (write_output(rec, buf, size) < 0) {
1498d3eca20SDavid Ahern 		rc = -1;
1508d3eca20SDavid Ahern 		goto out;
1518d3eca20SDavid Ahern 	}
15286470930SIngo Molnar 
15386470930SIngo Molnar 	md->prev = old;
154115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
1558d3eca20SDavid Ahern 
1568d3eca20SDavid Ahern out:
1578d3eca20SDavid Ahern 	return rc;
15886470930SIngo Molnar }
15986470930SIngo Molnar 
16086470930SIngo Molnar static volatile int done = 0;
161f7b7c26eSPeter Zijlstra static volatile int signr = -1;
16233e49ea7SAndi Kleen static volatile int child_finished = 0;
16386470930SIngo Molnar 
16486470930SIngo Molnar static void sig_handler(int sig)
16586470930SIngo Molnar {
16633e49ea7SAndi Kleen 	if (sig == SIGCHLD)
16733e49ea7SAndi Kleen 		child_finished = 1;
16833e49ea7SAndi Kleen 
16986470930SIngo Molnar 	done = 1;
170f7b7c26eSPeter Zijlstra 	signr = sig;
171f7b7c26eSPeter Zijlstra }
172f7b7c26eSPeter Zijlstra 
1731d037ca1SIrina Tirdea static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
174f7b7c26eSPeter Zijlstra {
175d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
17633e49ea7SAndi Kleen 	int status;
17733e49ea7SAndi Kleen 
178d20deb64SArnaldo Carvalho de Melo 	if (rec->evlist->workload.pid > 0) {
17933e49ea7SAndi Kleen 		if (!child_finished)
180d20deb64SArnaldo Carvalho de Melo 			kill(rec->evlist->workload.pid, SIGTERM);
181933da83aSChris Wilson 
18233e49ea7SAndi Kleen 		wait(&status);
18333e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
184d20deb64SArnaldo Carvalho de Melo 			psignal(WTERMSIG(status), rec->progname);
18533e49ea7SAndi Kleen 	}
18633e49ea7SAndi Kleen 
18718483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
188f7b7c26eSPeter Zijlstra 		return;
189f7b7c26eSPeter Zijlstra 
190f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
19186470930SIngo Molnar }
19286470930SIngo Molnar 
1938d3eca20SDavid Ahern static int perf_record__open(struct perf_record *rec)
194dd7927f4SArnaldo Carvalho de Melo {
19556e52e85SArnaldo Carvalho de Melo 	char msg[512];
1966a4bb04cSJiri Olsa 	struct perf_evsel *pos;
197d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
198d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
199d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
2008d3eca20SDavid Ahern 	int rc = 0;
201dd7927f4SArnaldo Carvalho de Melo 
202f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
203cac21425SJiri Olsa 
204dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
2053da297a6SIngo Molnar try_again:
2066a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
20756e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2083da297a6SIngo Molnar 				if (verbose)
209c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2103da297a6SIngo Molnar 				goto try_again;
2113da297a6SIngo Molnar 			}
212ca6a4258SDavid Ahern 
21356e52e85SArnaldo Carvalho de Melo 			rc = -errno;
21456e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
21556e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
21656e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
2178d3eca20SDavid Ahern 			goto out;
2187c6a1c65SPeter Zijlstra 		}
2197c6a1c65SPeter Zijlstra 	}
2207c6a1c65SPeter Zijlstra 
2211491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
2220a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2230a102479SFrederic Weisbecker 			strerror(errno));
2248d3eca20SDavid Ahern 		rc = -1;
2258d3eca20SDavid Ahern 		goto out;
2260a102479SFrederic Weisbecker 	}
2270a102479SFrederic Weisbecker 
22818e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
2298d3eca20SDavid Ahern 		if (errno == EPERM) {
2308d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
23118e60939SNelson Elhage 			       "Consider increasing "
23218e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
23318e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
23418e60939SNelson Elhage 			       "(current value: %d)\n", opts->mmap_pages);
2358d3eca20SDavid Ahern 			rc = -errno;
2360089fa98SJiri Olsa 		} else if (!is_power_of_2(opts->mmap_pages) &&
2370089fa98SJiri Olsa 			   (opts->mmap_pages != UINT_MAX)) {
2388d3eca20SDavid Ahern 			pr_err("--mmap_pages/-m value must be a power of two.");
2398d3eca20SDavid Ahern 			rc = -EINVAL;
2408d3eca20SDavid Ahern 		} else {
2418d3eca20SDavid Ahern 			pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
2428d3eca20SDavid Ahern 			rc = -errno;
2438d3eca20SDavid Ahern 		}
2448d3eca20SDavid Ahern 		goto out;
24518e60939SNelson Elhage 	}
2460a27d7f9SArnaldo Carvalho de Melo 
247a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
2487b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
2498d3eca20SDavid Ahern out:
2508d3eca20SDavid Ahern 	return rc;
251a91e5431SArnaldo Carvalho de Melo }
252a91e5431SArnaldo Carvalho de Melo 
253d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
2546122e4e4SArnaldo Carvalho de Melo {
255d20deb64SArnaldo Carvalho de Melo 	u64 size = lseek(rec->output, 0, SEEK_CUR);
2566122e4e4SArnaldo Carvalho de Melo 
2579f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2589f591fd7SArnaldo Carvalho de Melo 		return 0;
2599f591fd7SArnaldo Carvalho de Melo 
260d20deb64SArnaldo Carvalho de Melo 	rec->session->fd = rec->output;
261d20deb64SArnaldo Carvalho de Melo 	return __perf_session__process_events(rec->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;
269f5970550SPeter Zijlstra 
2708d3eca20SDavid Ahern 	if (status != 0)
2718d3eca20SDavid Ahern 		return;
2728d3eca20SDavid Ahern 
273d20deb64SArnaldo Carvalho de Melo 	if (!rec->opts.pipe_output) {
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,
279d20deb64SArnaldo Carvalho de Melo 					   rec->output, 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 
345d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
34686470930SIngo Molnar {
34786470930SIngo Molnar 	struct stat st;
34886470930SIngo Molnar 	int flags;
349781ba9d2SRobert Richter 	int err, output, feat;
3508b412664SPeter Zijlstra 	unsigned long waking = 0;
35146be604bSZhang, Yanmin 	const bool forks = argc > 0;
35223346f21SArnaldo Carvalho de Melo 	struct machine *machine;
35345694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
354d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
355d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
356d20deb64SArnaldo Carvalho de Melo 	const char *output_name = rec->output_name;
357d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3582711926aSJiri Olsa 	bool disabled = false;
35986470930SIngo Molnar 
360d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
36133e49ea7SAndi Kleen 
362d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
363f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
364f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
36518483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
366804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
367f5970550SPeter Zijlstra 
368d7065adbSFranck Bui-Huu 	if (!output_name) {
369d7065adbSFranck Bui-Huu 		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
370d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
371d7065adbSFranck Bui-Huu 		else
372d20deb64SArnaldo Carvalho de Melo 			rec->output_name = output_name = "perf.data";
373d7065adbSFranck Bui-Huu 	}
374d7065adbSFranck Bui-Huu 	if (output_name) {
375529870e3STom Zanussi 		if (!strcmp(output_name, "-"))
376d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
377529870e3STom Zanussi 		else if (!stat(output_name, &st) && st.st_size) {
378b38d3464SArnaldo Carvalho de Melo 			char oldname[PATH_MAX];
379b38d3464SArnaldo Carvalho de Melo 			snprintf(oldname, sizeof(oldname), "%s.old",
380b38d3464SArnaldo Carvalho de Melo 				 output_name);
381b38d3464SArnaldo Carvalho de Melo 			unlink(oldname);
382b38d3464SArnaldo Carvalho de Melo 			rename(output_name, oldname);
383b38d3464SArnaldo Carvalho de Melo 		}
384d7065adbSFranck Bui-Huu 	}
38586470930SIngo Molnar 
386563aecb2SJiri Olsa 	flags = O_CREAT|O_RDWR|O_TRUNC;
38786470930SIngo Molnar 
388d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output)
389529870e3STom Zanussi 		output = STDOUT_FILENO;
390529870e3STom Zanussi 	else
39186470930SIngo Molnar 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
39286470930SIngo Molnar 	if (output < 0) {
39386470930SIngo Molnar 		perror("failed to create output file");
3948d3eca20SDavid Ahern 		return -1;
39586470930SIngo Molnar 	}
39686470930SIngo Molnar 
397d20deb64SArnaldo Carvalho de Melo 	rec->output = output;
398d20deb64SArnaldo Carvalho de Melo 
3997865e817SFrederic Weisbecker 	session = perf_session__new(output_name, O_WRONLY,
400563aecb2SJiri Olsa 				    true, false, NULL);
40194c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
402a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
403a9a70bbcSArnaldo Carvalho de Melo 		return -1;
404a9a70bbcSArnaldo Carvalho de Melo 	}
405a9a70bbcSArnaldo Carvalho de Melo 
406d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
407d20deb64SArnaldo Carvalho de Melo 
408781ba9d2SRobert Richter 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
409781ba9d2SRobert Richter 		perf_header__set_feat(&session->header, feat);
410781ba9d2SRobert Richter 
411781ba9d2SRobert Richter 	if (rec->no_buildid)
412781ba9d2SRobert Richter 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
413781ba9d2SRobert Richter 
414781ba9d2SRobert Richter 	if (!have_tracepoints(&evsel_list->entries))
4152eeaaa09SStephane Eranian 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
416baa2f6ceSArnaldo Carvalho de Melo 
417330aa675SStephane Eranian 	if (!rec->opts.branch_stack)
418330aa675SStephane Eranian 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
419330aa675SStephane Eranian 
420d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
4216ef73ec4SNamhyung Kim 		err = perf_evlist__prepare_workload(evsel_list, &opts->target,
42255e162eaSNamhyung Kim 						    argv, opts->pipe_output,
42355e162eaSNamhyung Kim 						    true);
42435b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
42535b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
42635b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
427856e9660SPeter Zijlstra 		}
428856e9660SPeter Zijlstra 	}
429856e9660SPeter Zijlstra 
4308d3eca20SDavid Ahern 	if (perf_record__open(rec) != 0) {
4318d3eca20SDavid Ahern 		err = -1;
4328d3eca20SDavid Ahern 		goto out_delete_session;
4338d3eca20SDavid Ahern 	}
43486470930SIngo Molnar 
435a8bb559bSNamhyung Kim 	if (!evsel_list->nr_groups)
436a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
437a8bb559bSNamhyung Kim 
438712a4b60SArnaldo Carvalho de Melo 	/*
439d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
440712a4b60SArnaldo Carvalho de Melo 	 */
441d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
442712a4b60SArnaldo Carvalho de Melo 
443d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
444529870e3STom Zanussi 		err = perf_header__write_pipe(output);
445529870e3STom Zanussi 		if (err < 0)
4468d3eca20SDavid Ahern 			goto out_delete_session;
447563aecb2SJiri Olsa 	} else {
448a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
449361c99a6SArnaldo Carvalho de Melo 						 output, false);
450d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
4518d3eca20SDavid Ahern 			goto out_delete_session;
452d5eed904SArnaldo Carvalho de Melo 	}
4537c6a1c65SPeter Zijlstra 
454d3665498SDavid Ahern 	if (!rec->no_buildid
455e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
456d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
457e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
4588d3eca20SDavid Ahern 		err = -1;
4598d3eca20SDavid Ahern 		goto out_delete_session;
460e20960c0SRobert Richter 	}
461e20960c0SRobert Richter 
462d20deb64SArnaldo Carvalho de Melo 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
4636122e4e4SArnaldo Carvalho de Melo 
46434ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
465743eb868SArnaldo Carvalho de Melo 
466d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
46745694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
468a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
4692c46dbb5STom Zanussi 		if (err < 0) {
4702c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
4718d3eca20SDavid Ahern 			goto out_delete_session;
4722c46dbb5STom Zanussi 		}
473cd19a035STom Zanussi 
474361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
47563e0c771STom Zanussi 			/*
47663e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
47763e0c771STom Zanussi 			 * there were no tracepoints so its not really
47863e0c771STom Zanussi 			 * an error, just that we don't need to
47963e0c771STom Zanussi 			 * synthesize anything.  We really have to
48063e0c771STom Zanussi 			 * return this more properly and also
48163e0c771STom Zanussi 			 * propagate errors that now are calling die()
48263e0c771STom Zanussi 			 */
48345694aa7SArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
484743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
48563e0c771STom Zanussi 			if (err <= 0) {
48663e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
4878d3eca20SDavid Ahern 				goto out_delete_session;
48863e0c771STom Zanussi 			}
489d20deb64SArnaldo Carvalho de Melo 			advance_output(rec, err);
4902c46dbb5STom Zanussi 		}
49163e0c771STom Zanussi 	}
4922c46dbb5STom Zanussi 
49345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
494743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
49570162138SArnaldo Carvalho de Melo 	if (err < 0)
49645694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
497743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
498c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
499c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
500c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
501c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
50256b03f3cSArnaldo Carvalho de Melo 
50345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
504743eb868SArnaldo Carvalho de Melo 					     machine);
505c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
506c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
507c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
508c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
509c1a3a4b9SArnaldo Carvalho de Melo 
5107e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
511876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
5127e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
5137e383de4SArnaldo Carvalho de Melo 	}
514b7cece76SArnaldo Carvalho de Melo 
515e4dd45feSJiri Olsa 	if (perf_target__has_task(&opts->target))
5168d3eca20SDavid Ahern 		err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
5178115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
518743eb868SArnaldo Carvalho de Melo 						  machine);
519e4dd45feSJiri Olsa 	else if (perf_target__has_cpu(&opts->target))
5208d3eca20SDavid Ahern 		err = perf_event__synthesize_threads(tool, process_synthesized_event,
521743eb868SArnaldo Carvalho de Melo 					       machine);
522e4dd45feSJiri Olsa 	else /* command specified */
523e4dd45feSJiri Olsa 		err = 0;
5247c6a1c65SPeter Zijlstra 
5258d3eca20SDavid Ahern 	if (err != 0)
5268d3eca20SDavid Ahern 		goto out_delete_session;
5278d3eca20SDavid Ahern 
528d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
52986470930SIngo Molnar 		struct sched_param param;
53086470930SIngo Molnar 
531d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
53286470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5336beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
5348d3eca20SDavid Ahern 			err = -1;
5358d3eca20SDavid Ahern 			goto out_delete_session;
53686470930SIngo Molnar 		}
53786470930SIngo Molnar 	}
53886470930SIngo Molnar 
539774cb499SJiri Olsa 	/*
540774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
541774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
542774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
543774cb499SJiri Olsa 	 */
544774cb499SJiri Olsa 	if (!perf_target__none(&opts->target))
545764e16a3SDavid Ahern 		perf_evlist__enable(evsel_list);
546764e16a3SDavid Ahern 
547856e9660SPeter Zijlstra 	/*
548856e9660SPeter Zijlstra 	 * Let the child rip
549856e9660SPeter Zijlstra 	 */
550d4db3f16SArnaldo Carvalho de Melo 	if (forks)
55135b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
552856e9660SPeter Zijlstra 
553649c48a9SPeter Zijlstra 	for (;;) {
554d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
55586470930SIngo Molnar 
5568d3eca20SDavid Ahern 		if (perf_record__mmap_read_all(rec) < 0) {
5578d3eca20SDavid Ahern 			err = -1;
5588d3eca20SDavid Ahern 			goto out_delete_session;
5598d3eca20SDavid Ahern 		}
56086470930SIngo Molnar 
561d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
562649c48a9SPeter Zijlstra 			if (done)
563649c48a9SPeter Zijlstra 				break;
5645c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
5658b412664SPeter Zijlstra 			waking++;
5668b412664SPeter Zijlstra 		}
5678b412664SPeter Zijlstra 
568774cb499SJiri Olsa 		/*
569774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
570774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
571774cb499SJiri Olsa 		 * disable events in this case.
572774cb499SJiri Olsa 		 */
5732711926aSJiri Olsa 		if (done && !disabled && !perf_target__none(&opts->target)) {
5744152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
5752711926aSJiri Olsa 			disabled = true;
5762711926aSJiri Olsa 		}
5778b412664SPeter Zijlstra 	}
5788b412664SPeter Zijlstra 
57918483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
580b44308f5SArnaldo Carvalho de Melo 		return 0;
581b44308f5SArnaldo Carvalho de Melo 
5828b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
58386470930SIngo Molnar 
58486470930SIngo Molnar 	/*
58586470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
58686470930SIngo Molnar 	 */
58786470930SIngo Molnar 	fprintf(stderr,
5889486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
589d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
59086470930SIngo Molnar 		output_name,
591d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
59286470930SIngo Molnar 
59386470930SIngo Molnar 	return 0;
59439d17dacSArnaldo Carvalho de Melo 
59539d17dacSArnaldo Carvalho de Melo out_delete_session:
59639d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
59739d17dacSArnaldo Carvalho de Melo 	return err;
59886470930SIngo Molnar }
59986470930SIngo Molnar 
600bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
601bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
602bdfebd84SRoberto Agostino Vitillo 
603bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
604bdfebd84SRoberto Agostino Vitillo 
605bdfebd84SRoberto Agostino Vitillo struct branch_mode {
606bdfebd84SRoberto Agostino Vitillo 	const char *name;
607bdfebd84SRoberto Agostino Vitillo 	int mode;
608bdfebd84SRoberto Agostino Vitillo };
609bdfebd84SRoberto Agostino Vitillo 
610bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
611bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
612bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
613bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
614bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
615bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
616bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
617bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
6180126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
6190126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
6200126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
621bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
622bdfebd84SRoberto Agostino Vitillo };
623bdfebd84SRoberto Agostino Vitillo 
624bdfebd84SRoberto Agostino Vitillo static int
625a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
626bdfebd84SRoberto Agostino Vitillo {
627bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
628bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
629bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
630bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
631bdfebd84SRoberto Agostino Vitillo 
632bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
633bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
634a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
635bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
636bdfebd84SRoberto Agostino Vitillo 
637a5aabdacSStephane Eranian 	if (unset)
638a5aabdacSStephane Eranian 		return 0;
639bdfebd84SRoberto Agostino Vitillo 
640a5aabdacSStephane Eranian 	/*
641a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
642a5aabdacSStephane Eranian 	 */
643a5aabdacSStephane Eranian 	if (*mode)
644a5aabdacSStephane Eranian 		return -1;
645a5aabdacSStephane Eranian 
646a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
647a5aabdacSStephane Eranian 	if (str) {
648bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
649bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
650bdfebd84SRoberto Agostino Vitillo 		if (!s)
651bdfebd84SRoberto Agostino Vitillo 			return -1;
652bdfebd84SRoberto Agostino Vitillo 
653bdfebd84SRoberto Agostino Vitillo 		for (;;) {
654bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
655bdfebd84SRoberto Agostino Vitillo 			if (p)
656bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
657bdfebd84SRoberto Agostino Vitillo 
658bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
659bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
660bdfebd84SRoberto Agostino Vitillo 					break;
661bdfebd84SRoberto Agostino Vitillo 			}
662a5aabdacSStephane Eranian 			if (!br->name) {
663a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
664a5aabdacSStephane Eranian 					    " check man page\n", s);
665bdfebd84SRoberto Agostino Vitillo 				goto error;
666a5aabdacSStephane Eranian 			}
667bdfebd84SRoberto Agostino Vitillo 
668bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
669bdfebd84SRoberto Agostino Vitillo 
670bdfebd84SRoberto Agostino Vitillo 			if (!p)
671bdfebd84SRoberto Agostino Vitillo 				break;
672bdfebd84SRoberto Agostino Vitillo 
673bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
674bdfebd84SRoberto Agostino Vitillo 		}
675a5aabdacSStephane Eranian 	}
676bdfebd84SRoberto Agostino Vitillo 	ret = 0;
677bdfebd84SRoberto Agostino Vitillo 
678a5aabdacSStephane Eranian 	/* default to any branch */
679bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
680a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
681bdfebd84SRoberto Agostino Vitillo 	}
682bdfebd84SRoberto Agostino Vitillo error:
683bdfebd84SRoberto Agostino Vitillo 	free(os);
684bdfebd84SRoberto Agostino Vitillo 	return ret;
685bdfebd84SRoberto Agostino Vitillo }
686bdfebd84SRoberto Agostino Vitillo 
68789fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
68826d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size)
68926d33022SJiri Olsa {
69026d33022SJiri Olsa 	char *endptr;
69126d33022SJiri Olsa 	unsigned long size;
69226d33022SJiri Olsa 	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
69326d33022SJiri Olsa 
69426d33022SJiri Olsa 	size = strtoul(str, &endptr, 0);
69526d33022SJiri Olsa 
69626d33022SJiri Olsa 	do {
69726d33022SJiri Olsa 		if (*endptr)
69826d33022SJiri Olsa 			break;
69926d33022SJiri Olsa 
70026d33022SJiri Olsa 		size = round_up(size, sizeof(u64));
70126d33022SJiri Olsa 		if (!size || size > max_size)
70226d33022SJiri Olsa 			break;
70326d33022SJiri Olsa 
70426d33022SJiri Olsa 		*_size = size;
70526d33022SJiri Olsa 		return 0;
70626d33022SJiri Olsa 
70726d33022SJiri Olsa 	} while (0);
70826d33022SJiri Olsa 
70926d33022SJiri Olsa 	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
71026d33022SJiri Olsa 	       max_size, str);
71126d33022SJiri Olsa 	return -1;
71226d33022SJiri Olsa }
71389fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */
71426d33022SJiri Olsa 
71575d9a108SArnaldo Carvalho de Melo int record_parse_callchain_opt(const struct option *opt,
71675d9a108SArnaldo Carvalho de Melo 			       const char *arg, int unset)
71726d33022SJiri Olsa {
718c5ff78c3SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = opt->value;
71926d33022SJiri Olsa 	char *tok, *name, *saveptr = NULL;
72026d33022SJiri Olsa 	char *buf;
72126d33022SJiri Olsa 	int ret = -1;
72226d33022SJiri Olsa 
72326d33022SJiri Olsa 	/* --no-call-graph */
72426d33022SJiri Olsa 	if (unset)
72526d33022SJiri Olsa 		return 0;
72626d33022SJiri Olsa 
72726d33022SJiri Olsa 	/* We specified default option if none is provided. */
72826d33022SJiri Olsa 	BUG_ON(!arg);
72926d33022SJiri Olsa 
73026d33022SJiri Olsa 	/* We need buffer that we know we can write to. */
73126d33022SJiri Olsa 	buf = malloc(strlen(arg) + 1);
73226d33022SJiri Olsa 	if (!buf)
73326d33022SJiri Olsa 		return -ENOMEM;
73426d33022SJiri Olsa 
73526d33022SJiri Olsa 	strcpy(buf, arg);
73626d33022SJiri Olsa 
73726d33022SJiri Olsa 	tok = strtok_r((char *)buf, ",", &saveptr);
73826d33022SJiri Olsa 	name = tok ? : (char *)buf;
73926d33022SJiri Olsa 
74026d33022SJiri Olsa 	do {
74126d33022SJiri Olsa 		/* Framepointer style */
74226d33022SJiri Olsa 		if (!strncmp(name, "fp", sizeof("fp"))) {
74326d33022SJiri Olsa 			if (!strtok_r(NULL, ",", &saveptr)) {
744c5ff78c3SArnaldo Carvalho de Melo 				opts->call_graph = CALLCHAIN_FP;
74526d33022SJiri Olsa 				ret = 0;
74626d33022SJiri Olsa 			} else
74726d33022SJiri Olsa 				pr_err("callchain: No more arguments "
74826d33022SJiri Olsa 				       "needed for -g fp\n");
74926d33022SJiri Olsa 			break;
75026d33022SJiri Olsa 
75189fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
75226d33022SJiri Olsa 		/* Dwarf style */
75326d33022SJiri Olsa 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
75461eaa3beSArnaldo Carvalho de Melo 			const unsigned long default_stack_dump_size = 8192;
75561eaa3beSArnaldo Carvalho de Melo 
75626d33022SJiri Olsa 			ret = 0;
757c5ff78c3SArnaldo Carvalho de Melo 			opts->call_graph = CALLCHAIN_DWARF;
758c5ff78c3SArnaldo Carvalho de Melo 			opts->stack_dump_size = default_stack_dump_size;
75926d33022SJiri Olsa 
76026d33022SJiri Olsa 			tok = strtok_r(NULL, ",", &saveptr);
76126d33022SJiri Olsa 			if (tok) {
76226d33022SJiri Olsa 				unsigned long size = 0;
76326d33022SJiri Olsa 
76426d33022SJiri Olsa 				ret = get_stack_size(tok, &size);
765c5ff78c3SArnaldo Carvalho de Melo 				opts->stack_dump_size = size;
76626d33022SJiri Olsa 			}
76726d33022SJiri Olsa 
76826d33022SJiri Olsa 			if (!ret)
76926d33022SJiri Olsa 				pr_debug("callchain: stack dump size %d\n",
770c5ff78c3SArnaldo Carvalho de Melo 					 opts->stack_dump_size);
77189fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */
77226d33022SJiri Olsa 		} else {
77326d33022SJiri Olsa 			pr_err("callchain: Unknown -g option "
77426d33022SJiri Olsa 			       "value: %s\n", arg);
77526d33022SJiri Olsa 			break;
77626d33022SJiri Olsa 		}
77726d33022SJiri Olsa 
77826d33022SJiri Olsa 	} while (0);
77926d33022SJiri Olsa 
78026d33022SJiri Olsa 	free(buf);
78126d33022SJiri Olsa 
78226d33022SJiri Olsa 	if (!ret)
783c5ff78c3SArnaldo Carvalho de Melo 		pr_debug("callchain: type %d\n", opts->call_graph);
78426d33022SJiri Olsa 
78526d33022SJiri Olsa 	return ret;
78626d33022SJiri Olsa }
78726d33022SJiri Olsa 
78886470930SIngo Molnar static const char * const record_usage[] = {
78986470930SIngo Molnar 	"perf record [<options>] [<command>]",
79086470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
79186470930SIngo Molnar 	NULL
79286470930SIngo Molnar };
79386470930SIngo Molnar 
794d20deb64SArnaldo Carvalho de Melo /*
795d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
796d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
797d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
798d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
799d20deb64SArnaldo Carvalho de Melo  *
800d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
801d20deb64SArnaldo Carvalho de Melo  *
802d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
803d20deb64SArnaldo Carvalho de Melo  */
804d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
805d20deb64SArnaldo Carvalho de Melo 	.opts = {
806d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
807d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
808d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
809447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
810d1cb9fceSNamhyung Kim 		.target		     = {
811d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
812d1cb9fceSNamhyung Kim 		},
813d20deb64SArnaldo Carvalho de Melo 	},
814d20deb64SArnaldo Carvalho de Melo };
8157865e817SFrederic Weisbecker 
81661eaa3beSArnaldo Carvalho de Melo #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
81761eaa3beSArnaldo Carvalho de Melo 
81889fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
81975d9a108SArnaldo Carvalho de Melo const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
82061eaa3beSArnaldo Carvalho de Melo #else
82175d9a108SArnaldo Carvalho de Melo const char record_callchain_help[] = CALLCHAIN_HELP "[fp]";
82261eaa3beSArnaldo Carvalho de Melo #endif
82361eaa3beSArnaldo Carvalho de Melo 
824d20deb64SArnaldo Carvalho de Melo /*
825d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
826d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
827d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
828d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
829d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
830d20deb64SArnaldo Carvalho de Melo  */
831bca647aaSTom Zanussi const struct option record_options[] = {
832d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
83386470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
834f120f9d5SJiri Olsa 		     parse_events_option),
835d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
836c171b552SLi Zefan 		     "event filter", parse_filter),
837bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
838d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
839bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
840d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
841d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
84286470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
843d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
844acac03faSKirill Smelkov 		    "collect data without buffering"),
845d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
846daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
847bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
84886470930SIngo Molnar 			    "system-wide collection from all CPUs"),
849bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
850c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
851d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
852d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('o', "output", &record.output_name, "file",
85386470930SIngo Molnar 		    "output file name"),
854d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
8552e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
856d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
857d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
85801c2d99bSArnaldo Carvalho de Melo 		     "number of mmap data pages"),
859d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
86043bece79SLin Ming 		    "put the counters into a counter group"),
861c5ff78c3SArnaldo Carvalho de Melo 	OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts,
86275d9a108SArnaldo Carvalho de Melo 			     "mode[,dump_size]", record_callchain_help,
86375d9a108SArnaldo Carvalho de Melo 			     &record_parse_callchain_opt, "fp"),
864c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8653da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
866b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
867d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
868649c48a9SPeter Zijlstra 		    "per thread counts"),
869d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8704bba828dSAnton Blanchard 		    "Sample addresses"),
871d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8723e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
873d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
874649c48a9SPeter Zijlstra 		    "don't sample"),
875d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
876a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
877d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
878baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
879d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
880023695d9SStephane Eranian 		     "monitor event in cgroup name only",
881023695d9SStephane Eranian 		     parse_cgroups),
882bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
883bea03405SNamhyung Kim 		   "user to profile"),
884a5aabdacSStephane Eranian 
885a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
886a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
887a5aabdacSStephane Eranian 		     parse_branch_stack),
888a5aabdacSStephane Eranian 
889a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
890a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
891bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
89205484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
89305484298SAndi Kleen 		    "sample by weight (on special events only)"),
894475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
895475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
89686470930SIngo Molnar 	OPT_END()
89786470930SIngo Molnar };
89886470930SIngo Molnar 
8991d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
90086470930SIngo Molnar {
90169aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
902d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
903d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
90416ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
90586470930SIngo Molnar 
906334fe7a3SNamhyung Kim 	evsel_list = perf_evlist__new();
907361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
908361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
909361c99a6SArnaldo Carvalho de Melo 
910d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
911d20deb64SArnaldo Carvalho de Melo 
912bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
913a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
914d67356e7SNamhyung Kim 	if (!argc && perf_target__none(&rec->opts.target))
915bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
91686470930SIngo Molnar 
917bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
9183780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
919023695d9SStephane Eranian 			  " system-wide mode\n");
920023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
921023695d9SStephane Eranian 	}
922023695d9SStephane Eranian 
923655000e7SArnaldo Carvalho de Melo 	symbol__init();
924baa2f6ceSArnaldo Carvalho de Melo 
925ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
926646aaea6SArnaldo Carvalho de Melo 		pr_warning(
927646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
928ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
929646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
930646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
931646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
932646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
933646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
934ec80fde7SArnaldo Carvalho de Melo 
935d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
936a1ac1d3cSStephane Eranian 		disable_buildid_cache();
937655000e7SArnaldo Carvalho de Melo 
938361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
939361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
94069aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
94169aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
942bbd36e5eSPeter Zijlstra 	}
94386470930SIngo Molnar 
94416ad2ffbSNamhyung Kim 	err = perf_target__validate(&rec->opts.target);
94516ad2ffbSNamhyung Kim 	if (err) {
94616ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
94716ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
94816ad2ffbSNamhyung Kim 	}
9494bd0f2d2SNamhyung Kim 
95016ad2ffbSNamhyung Kim 	err = perf_target__parse_uid(&rec->opts.target);
95116ad2ffbSNamhyung Kim 	if (err) {
95216ad2ffbSNamhyung Kim 		int saved_errno = errno;
95316ad2ffbSNamhyung Kim 
95416ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9553780f488SNamhyung Kim 		ui__error("%s", errbuf);
95616ad2ffbSNamhyung Kim 
95716ad2ffbSNamhyung Kim 		err = -saved_errno;
9588fa60e1fSNamhyung Kim 		goto out_symbol_exit;
95916ad2ffbSNamhyung Kim 	}
9600d37aa34SArnaldo Carvalho de Melo 
96116ad2ffbSNamhyung Kim 	err = -ENOMEM;
962b809ac10SNamhyung Kim 	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
963dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
96469aad6f1SArnaldo Carvalho de Melo 
965d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_interval != ULLONG_MAX)
966d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.user_interval;
967d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_freq != UINT_MAX)
968d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = rec->opts.user_freq;
969f9212819SFrederic Weisbecker 
9707e4ff9e3SMike Galbraith 	/*
9717e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
9727e4ff9e3SMike Galbraith 	 */
973d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.default_interval)
974d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = 0;
975d20deb64SArnaldo Carvalho de Melo 	else if (rec->opts.freq) {
976d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.freq;
9777e4ff9e3SMike Galbraith 	} else {
9783780f488SNamhyung Kim 		ui__error("frequency and count are zero, aborting\n");
97939d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
9805c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
9817e4ff9e3SMike Galbraith 	}
9827e4ff9e3SMike Galbraith 
983d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
9848fa60e1fSNamhyung Kim 
9858fa60e1fSNamhyung Kim 	perf_evlist__munmap(evsel_list);
9868fa60e1fSNamhyung Kim 	perf_evlist__close(evsel_list);
98739d17dacSArnaldo Carvalho de Melo out_free_fd:
9887e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
989d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
990d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
99139d17dacSArnaldo Carvalho de Melo 	return err;
99286470930SIngo Molnar }
993