xref: /openbmc/linux/tools/perf/builtin-record.c (revision 563aecb2e63a16f86c7daabfdcfee23f3e7c5955)
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 
3278da39faSBernhard Rosenkraenzer #ifndef HAVE_ON_EXIT
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 	unsigned int		page_size;
74d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
75d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
76d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
77d20deb64SArnaldo Carvalho de Melo 	bool			force;
78d20deb64SArnaldo Carvalho de Melo 	long			samples;
79d20deb64SArnaldo Carvalho de Melo 	off_t			post_processing_offset;
800f82ebc4SArnaldo Carvalho de Melo };
8186470930SIngo Molnar 
82d20deb64SArnaldo Carvalho de Melo static void advance_output(struct perf_record *rec, size_t size)
839215545eSTom Zanussi {
84d20deb64SArnaldo Carvalho de Melo 	rec->bytes_written += size;
859215545eSTom Zanussi }
869215545eSTom Zanussi 
878d3eca20SDavid Ahern static int write_output(struct perf_record *rec, void *buf, size_t size)
88f5970550SPeter Zijlstra {
89f5970550SPeter Zijlstra 	while (size) {
90d20deb64SArnaldo Carvalho de Melo 		int ret = write(rec->output, buf, size);
91f5970550SPeter Zijlstra 
928d3eca20SDavid Ahern 		if (ret < 0) {
938d3eca20SDavid Ahern 			pr_err("failed to write\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;
123d20deb64SArnaldo Carvalho de Melo 	unsigned char *data = md->base + rec->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;
2380089fa98SJiri Olsa 		} else if (!is_power_of_2(opts->mmap_pages) &&
2390089fa98SJiri Olsa 			   (opts->mmap_pages != UINT_MAX)) {
2408d3eca20SDavid Ahern 			pr_err("--mmap_pages/-m value must be a power of two.");
2418d3eca20SDavid Ahern 			rc = -EINVAL;
2428d3eca20SDavid Ahern 		} else {
2438d3eca20SDavid Ahern 			pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
2448d3eca20SDavid Ahern 			rc = -errno;
2458d3eca20SDavid Ahern 		}
2468d3eca20SDavid Ahern 		goto out;
24718e60939SNelson Elhage 	}
2480a27d7f9SArnaldo Carvalho de Melo 
249a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
2507b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
2518d3eca20SDavid Ahern out:
2528d3eca20SDavid Ahern 	return rc;
253a91e5431SArnaldo Carvalho de Melo }
254a91e5431SArnaldo Carvalho de Melo 
255d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
2566122e4e4SArnaldo Carvalho de Melo {
257d20deb64SArnaldo Carvalho de Melo 	u64 size = lseek(rec->output, 0, SEEK_CUR);
2586122e4e4SArnaldo Carvalho de Melo 
2599f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2609f591fd7SArnaldo Carvalho de Melo 		return 0;
2619f591fd7SArnaldo Carvalho de Melo 
262d20deb64SArnaldo Carvalho de Melo 	rec->session->fd = rec->output;
263d20deb64SArnaldo Carvalho de Melo 	return __perf_session__process_events(rec->session, rec->post_processing_offset,
264d20deb64SArnaldo Carvalho de Melo 					      size - rec->post_processing_offset,
2656122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
2666122e4e4SArnaldo Carvalho de Melo }
2676122e4e4SArnaldo Carvalho de Melo 
2688d3eca20SDavid Ahern static void perf_record__exit(int status, void *arg)
269f5970550SPeter Zijlstra {
270d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
271f5970550SPeter Zijlstra 
2728d3eca20SDavid Ahern 	if (status != 0)
2738d3eca20SDavid Ahern 		return;
2748d3eca20SDavid Ahern 
275d20deb64SArnaldo Carvalho de Melo 	if (!rec->opts.pipe_output) {
276d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
277d20deb64SArnaldo Carvalho de Melo 
278d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
279d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
280d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
281d20deb64SArnaldo Carvalho de Melo 					   rec->output, true);
282d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
283d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
284d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
285c7929e47STom Zanussi 	}
286f5970550SPeter Zijlstra }
287f5970550SPeter Zijlstra 
2888115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
289a1645ce1SZhang, Yanmin {
290a1645ce1SZhang, Yanmin 	int err;
29145694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
292a1645ce1SZhang, Yanmin 	/*
293a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
294a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
295a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
296a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
297a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
298a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
299a1645ce1SZhang, Yanmin 	 */
30045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
301743eb868SArnaldo Carvalho de Melo 					     machine);
302a1645ce1SZhang, Yanmin 	if (err < 0)
303a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
30423346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
305a1645ce1SZhang, Yanmin 
306a1645ce1SZhang, Yanmin 	/*
307a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
308a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
309a1645ce1SZhang, Yanmin 	 */
31045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
311743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
312a1645ce1SZhang, Yanmin 	if (err < 0)
31345694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
314743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
315a1645ce1SZhang, Yanmin 	if (err < 0)
316a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
31723346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
318a1645ce1SZhang, Yanmin }
319a1645ce1SZhang, Yanmin 
32098402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
32198402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
32298402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
32398402807SFrederic Weisbecker };
32498402807SFrederic Weisbecker 
3258d3eca20SDavid Ahern static int perf_record__mmap_read_all(struct perf_record *rec)
32698402807SFrederic Weisbecker {
3270e2e63ddSPeter Zijlstra 	int i;
3288d3eca20SDavid Ahern 	int rc = 0;
32998402807SFrederic Weisbecker 
330d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
3318d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
3328d3eca20SDavid Ahern 			if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
3338d3eca20SDavid Ahern 				rc = -1;
3348d3eca20SDavid Ahern 				goto out;
3358d3eca20SDavid Ahern 			}
3368d3eca20SDavid Ahern 		}
33798402807SFrederic Weisbecker 	}
33898402807SFrederic Weisbecker 
3392eeaaa09SStephane Eranian 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
3408d3eca20SDavid Ahern 		rc = write_output(rec, &finished_round_event,
3418d3eca20SDavid Ahern 				  sizeof(finished_round_event));
3428d3eca20SDavid Ahern 
3438d3eca20SDavid Ahern out:
3448d3eca20SDavid Ahern 	return rc;
34598402807SFrederic Weisbecker }
34698402807SFrederic Weisbecker 
347d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
34886470930SIngo Molnar {
34986470930SIngo Molnar 	struct stat st;
35086470930SIngo Molnar 	int flags;
351781ba9d2SRobert Richter 	int err, output, feat;
3528b412664SPeter Zijlstra 	unsigned long waking = 0;
35346be604bSZhang, Yanmin 	const bool forks = argc > 0;
35423346f21SArnaldo Carvalho de Melo 	struct machine *machine;
35545694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
356d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
357d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
358d20deb64SArnaldo Carvalho de Melo 	const char *output_name = rec->output_name;
359d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3602711926aSJiri Olsa 	bool disabled = false;
36186470930SIngo Molnar 
362d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
36333e49ea7SAndi Kleen 
364d20deb64SArnaldo Carvalho de Melo 	rec->page_size = sysconf(_SC_PAGE_SIZE);
36586470930SIngo Molnar 
366d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
367f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
368f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
36918483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
370804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
371f5970550SPeter Zijlstra 
372d7065adbSFranck Bui-Huu 	if (!output_name) {
373d7065adbSFranck Bui-Huu 		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
374d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
375d7065adbSFranck Bui-Huu 		else
376d20deb64SArnaldo Carvalho de Melo 			rec->output_name = output_name = "perf.data";
377d7065adbSFranck Bui-Huu 	}
378d7065adbSFranck Bui-Huu 	if (output_name) {
379529870e3STom Zanussi 		if (!strcmp(output_name, "-"))
380d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
381529870e3STom Zanussi 		else if (!stat(output_name, &st) && st.st_size) {
382b38d3464SArnaldo Carvalho de Melo 			char oldname[PATH_MAX];
383b38d3464SArnaldo Carvalho de Melo 			snprintf(oldname, sizeof(oldname), "%s.old",
384b38d3464SArnaldo Carvalho de Melo 				 output_name);
385b38d3464SArnaldo Carvalho de Melo 			unlink(oldname);
386b38d3464SArnaldo Carvalho de Melo 			rename(output_name, oldname);
387b38d3464SArnaldo Carvalho de Melo 		}
388d7065adbSFranck Bui-Huu 	}
38986470930SIngo Molnar 
390*563aecb2SJiri Olsa 	flags = O_CREAT|O_RDWR|O_TRUNC;
39186470930SIngo Molnar 
392d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output)
393529870e3STom Zanussi 		output = STDOUT_FILENO;
394529870e3STom Zanussi 	else
39586470930SIngo Molnar 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
39686470930SIngo Molnar 	if (output < 0) {
39786470930SIngo Molnar 		perror("failed to create output file");
3988d3eca20SDavid Ahern 		return -1;
39986470930SIngo Molnar 	}
40086470930SIngo Molnar 
401d20deb64SArnaldo Carvalho de Melo 	rec->output = output;
402d20deb64SArnaldo Carvalho de Melo 
4037865e817SFrederic Weisbecker 	session = perf_session__new(output_name, O_WRONLY,
404*563aecb2SJiri Olsa 				    true, false, NULL);
40594c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
406a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
407a9a70bbcSArnaldo Carvalho de Melo 		return -1;
408a9a70bbcSArnaldo Carvalho de Melo 	}
409a9a70bbcSArnaldo Carvalho de Melo 
410d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
411d20deb64SArnaldo Carvalho de Melo 
412781ba9d2SRobert Richter 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
413781ba9d2SRobert Richter 		perf_header__set_feat(&session->header, feat);
414781ba9d2SRobert Richter 
415781ba9d2SRobert Richter 	if (rec->no_buildid)
416781ba9d2SRobert Richter 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
417781ba9d2SRobert Richter 
418781ba9d2SRobert Richter 	if (!have_tracepoints(&evsel_list->entries))
4192eeaaa09SStephane Eranian 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
420baa2f6ceSArnaldo Carvalho de Melo 
421330aa675SStephane Eranian 	if (!rec->opts.branch_stack)
422330aa675SStephane Eranian 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
423330aa675SStephane Eranian 
424d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
4256ef73ec4SNamhyung Kim 		err = perf_evlist__prepare_workload(evsel_list, &opts->target,
42655e162eaSNamhyung Kim 						    argv, opts->pipe_output,
42755e162eaSNamhyung Kim 						    true);
42835b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
42935b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
43035b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
431856e9660SPeter Zijlstra 		}
432856e9660SPeter Zijlstra 	}
433856e9660SPeter Zijlstra 
4348d3eca20SDavid Ahern 	if (perf_record__open(rec) != 0) {
4358d3eca20SDavid Ahern 		err = -1;
4368d3eca20SDavid Ahern 		goto out_delete_session;
4378d3eca20SDavid Ahern 	}
43886470930SIngo Molnar 
439a8bb559bSNamhyung Kim 	if (!evsel_list->nr_groups)
440a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
441a8bb559bSNamhyung Kim 
442712a4b60SArnaldo Carvalho de Melo 	/*
443d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
444712a4b60SArnaldo Carvalho de Melo 	 */
445d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
446712a4b60SArnaldo Carvalho de Melo 
447d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
448529870e3STom Zanussi 		err = perf_header__write_pipe(output);
449529870e3STom Zanussi 		if (err < 0)
4508d3eca20SDavid Ahern 			goto out_delete_session;
451*563aecb2SJiri Olsa 	} else {
452a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
453361c99a6SArnaldo Carvalho de Melo 						 output, false);
454d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
4558d3eca20SDavid Ahern 			goto out_delete_session;
456d5eed904SArnaldo Carvalho de Melo 	}
4577c6a1c65SPeter Zijlstra 
458d3665498SDavid Ahern 	if (!rec->no_buildid
459e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
460d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
461e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
4628d3eca20SDavid Ahern 		err = -1;
4638d3eca20SDavid Ahern 		goto out_delete_session;
464e20960c0SRobert Richter 	}
465e20960c0SRobert Richter 
466d20deb64SArnaldo Carvalho de Melo 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
4676122e4e4SArnaldo Carvalho de Melo 
46834ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
469743eb868SArnaldo Carvalho de Melo 
470d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
47145694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
472a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
4732c46dbb5STom Zanussi 		if (err < 0) {
4742c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
4758d3eca20SDavid Ahern 			goto out_delete_session;
4762c46dbb5STom Zanussi 		}
477cd19a035STom Zanussi 
47845694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_event_types(tool, process_synthesized_event,
479743eb868SArnaldo Carvalho de Melo 							 machine);
480cd19a035STom Zanussi 		if (err < 0) {
481cd19a035STom Zanussi 			pr_err("Couldn't synthesize event_types.\n");
4828d3eca20SDavid Ahern 			goto out_delete_session;
483cd19a035STom Zanussi 		}
4849215545eSTom Zanussi 
485361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
48663e0c771STom Zanussi 			/*
48763e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
48863e0c771STom Zanussi 			 * there were no tracepoints so its not really
48963e0c771STom Zanussi 			 * an error, just that we don't need to
49063e0c771STom Zanussi 			 * synthesize anything.  We really have to
49163e0c771STom Zanussi 			 * return this more properly and also
49263e0c771STom Zanussi 			 * propagate errors that now are calling die()
49363e0c771STom Zanussi 			 */
49445694aa7SArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
495743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
49663e0c771STom Zanussi 			if (err <= 0) {
49763e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
4988d3eca20SDavid Ahern 				goto out_delete_session;
49963e0c771STom Zanussi 			}
500d20deb64SArnaldo Carvalho de Melo 			advance_output(rec, err);
5012c46dbb5STom Zanussi 		}
50263e0c771STom Zanussi 	}
5032c46dbb5STom Zanussi 
50445694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
505743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
50670162138SArnaldo Carvalho de Melo 	if (err < 0)
50745694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
508743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
509c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
510c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
511c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
512c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
51356b03f3cSArnaldo Carvalho de Melo 
51445694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
515743eb868SArnaldo Carvalho de Melo 					     machine);
516c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
517c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
518c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
519c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
520c1a3a4b9SArnaldo Carvalho de Melo 
5217e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
522876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
5237e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
5247e383de4SArnaldo Carvalho de Melo 	}
525b7cece76SArnaldo Carvalho de Melo 
526e4dd45feSJiri Olsa 	if (perf_target__has_task(&opts->target))
5278d3eca20SDavid Ahern 		err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
5288115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
529743eb868SArnaldo Carvalho de Melo 						  machine);
530e4dd45feSJiri Olsa 	else if (perf_target__has_cpu(&opts->target))
5318d3eca20SDavid Ahern 		err = perf_event__synthesize_threads(tool, process_synthesized_event,
532743eb868SArnaldo Carvalho de Melo 					       machine);
533e4dd45feSJiri Olsa 	else /* command specified */
534e4dd45feSJiri Olsa 		err = 0;
5357c6a1c65SPeter Zijlstra 
5368d3eca20SDavid Ahern 	if (err != 0)
5378d3eca20SDavid Ahern 		goto out_delete_session;
5388d3eca20SDavid Ahern 
539d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
54086470930SIngo Molnar 		struct sched_param param;
54186470930SIngo Molnar 
542d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
54386470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5446beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
5458d3eca20SDavid Ahern 			err = -1;
5468d3eca20SDavid Ahern 			goto out_delete_session;
54786470930SIngo Molnar 		}
54886470930SIngo Molnar 	}
54986470930SIngo Molnar 
550774cb499SJiri Olsa 	/*
551774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
552774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
553774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
554774cb499SJiri Olsa 	 */
555774cb499SJiri Olsa 	if (!perf_target__none(&opts->target))
556764e16a3SDavid Ahern 		perf_evlist__enable(evsel_list);
557764e16a3SDavid Ahern 
558856e9660SPeter Zijlstra 	/*
559856e9660SPeter Zijlstra 	 * Let the child rip
560856e9660SPeter Zijlstra 	 */
561d4db3f16SArnaldo Carvalho de Melo 	if (forks)
56235b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
563856e9660SPeter Zijlstra 
564649c48a9SPeter Zijlstra 	for (;;) {
565d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
56686470930SIngo Molnar 
5678d3eca20SDavid Ahern 		if (perf_record__mmap_read_all(rec) < 0) {
5688d3eca20SDavid Ahern 			err = -1;
5698d3eca20SDavid Ahern 			goto out_delete_session;
5708d3eca20SDavid Ahern 		}
57186470930SIngo Molnar 
572d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
573649c48a9SPeter Zijlstra 			if (done)
574649c48a9SPeter Zijlstra 				break;
5755c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
5768b412664SPeter Zijlstra 			waking++;
5778b412664SPeter Zijlstra 		}
5788b412664SPeter Zijlstra 
579774cb499SJiri Olsa 		/*
580774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
581774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
582774cb499SJiri Olsa 		 * disable events in this case.
583774cb499SJiri Olsa 		 */
5842711926aSJiri Olsa 		if (done && !disabled && !perf_target__none(&opts->target)) {
5854152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
5862711926aSJiri Olsa 			disabled = true;
5872711926aSJiri Olsa 		}
5888b412664SPeter Zijlstra 	}
5898b412664SPeter Zijlstra 
59018483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
591b44308f5SArnaldo Carvalho de Melo 		return 0;
592b44308f5SArnaldo Carvalho de Melo 
5938b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
59486470930SIngo Molnar 
59586470930SIngo Molnar 	/*
59686470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
59786470930SIngo Molnar 	 */
59886470930SIngo Molnar 	fprintf(stderr,
5999486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
600d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
60186470930SIngo Molnar 		output_name,
602d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
60386470930SIngo Molnar 
60486470930SIngo Molnar 	return 0;
60539d17dacSArnaldo Carvalho de Melo 
60639d17dacSArnaldo Carvalho de Melo out_delete_session:
60739d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
60839d17dacSArnaldo Carvalho de Melo 	return err;
60986470930SIngo Molnar }
61086470930SIngo Molnar 
611bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
612bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
613bdfebd84SRoberto Agostino Vitillo 
614bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
615bdfebd84SRoberto Agostino Vitillo 
616bdfebd84SRoberto Agostino Vitillo struct branch_mode {
617bdfebd84SRoberto Agostino Vitillo 	const char *name;
618bdfebd84SRoberto Agostino Vitillo 	int mode;
619bdfebd84SRoberto Agostino Vitillo };
620bdfebd84SRoberto Agostino Vitillo 
621bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
622bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
623bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
624bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
625bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
626bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
627bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
628bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
629bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
630bdfebd84SRoberto Agostino Vitillo };
631bdfebd84SRoberto Agostino Vitillo 
632bdfebd84SRoberto Agostino Vitillo static int
633a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
634bdfebd84SRoberto Agostino Vitillo {
635bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
636bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
637bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
638bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
639bdfebd84SRoberto Agostino Vitillo 
640bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
641bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
642a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
643bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
644bdfebd84SRoberto Agostino Vitillo 
645a5aabdacSStephane Eranian 	if (unset)
646a5aabdacSStephane Eranian 		return 0;
647bdfebd84SRoberto Agostino Vitillo 
648a5aabdacSStephane Eranian 	/*
649a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
650a5aabdacSStephane Eranian 	 */
651a5aabdacSStephane Eranian 	if (*mode)
652a5aabdacSStephane Eranian 		return -1;
653a5aabdacSStephane Eranian 
654a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
655a5aabdacSStephane Eranian 	if (str) {
656bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
657bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
658bdfebd84SRoberto Agostino Vitillo 		if (!s)
659bdfebd84SRoberto Agostino Vitillo 			return -1;
660bdfebd84SRoberto Agostino Vitillo 
661bdfebd84SRoberto Agostino Vitillo 		for (;;) {
662bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
663bdfebd84SRoberto Agostino Vitillo 			if (p)
664bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
665bdfebd84SRoberto Agostino Vitillo 
666bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
667bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
668bdfebd84SRoberto Agostino Vitillo 					break;
669bdfebd84SRoberto Agostino Vitillo 			}
670a5aabdacSStephane Eranian 			if (!br->name) {
671a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
672a5aabdacSStephane Eranian 					    " check man page\n", s);
673bdfebd84SRoberto Agostino Vitillo 				goto error;
674a5aabdacSStephane Eranian 			}
675bdfebd84SRoberto Agostino Vitillo 
676bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
677bdfebd84SRoberto Agostino Vitillo 
678bdfebd84SRoberto Agostino Vitillo 			if (!p)
679bdfebd84SRoberto Agostino Vitillo 				break;
680bdfebd84SRoberto Agostino Vitillo 
681bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
682bdfebd84SRoberto Agostino Vitillo 		}
683a5aabdacSStephane Eranian 	}
684bdfebd84SRoberto Agostino Vitillo 	ret = 0;
685bdfebd84SRoberto Agostino Vitillo 
686a5aabdacSStephane Eranian 	/* default to any branch */
687bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
688a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
689bdfebd84SRoberto Agostino Vitillo 	}
690bdfebd84SRoberto Agostino Vitillo error:
691bdfebd84SRoberto Agostino Vitillo 	free(os);
692bdfebd84SRoberto Agostino Vitillo 	return ret;
693bdfebd84SRoberto Agostino Vitillo }
694bdfebd84SRoberto Agostino Vitillo 
69595485b1cSNamhyung Kim #ifdef LIBUNWIND_SUPPORT
69626d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size)
69726d33022SJiri Olsa {
69826d33022SJiri Olsa 	char *endptr;
69926d33022SJiri Olsa 	unsigned long size;
70026d33022SJiri Olsa 	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
70126d33022SJiri Olsa 
70226d33022SJiri Olsa 	size = strtoul(str, &endptr, 0);
70326d33022SJiri Olsa 
70426d33022SJiri Olsa 	do {
70526d33022SJiri Olsa 		if (*endptr)
70626d33022SJiri Olsa 			break;
70726d33022SJiri Olsa 
70826d33022SJiri Olsa 		size = round_up(size, sizeof(u64));
70926d33022SJiri Olsa 		if (!size || size > max_size)
71026d33022SJiri Olsa 			break;
71126d33022SJiri Olsa 
71226d33022SJiri Olsa 		*_size = size;
71326d33022SJiri Olsa 		return 0;
71426d33022SJiri Olsa 
71526d33022SJiri Olsa 	} while (0);
71626d33022SJiri Olsa 
71726d33022SJiri Olsa 	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
71826d33022SJiri Olsa 	       max_size, str);
71926d33022SJiri Olsa 	return -1;
72026d33022SJiri Olsa }
72195485b1cSNamhyung Kim #endif /* LIBUNWIND_SUPPORT */
72226d33022SJiri Olsa 
72375d9a108SArnaldo Carvalho de Melo int record_parse_callchain_opt(const struct option *opt,
72475d9a108SArnaldo Carvalho de Melo 			       const char *arg, int unset)
72526d33022SJiri Olsa {
726c5ff78c3SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = opt->value;
72726d33022SJiri Olsa 	char *tok, *name, *saveptr = NULL;
72826d33022SJiri Olsa 	char *buf;
72926d33022SJiri Olsa 	int ret = -1;
73026d33022SJiri Olsa 
73126d33022SJiri Olsa 	/* --no-call-graph */
73226d33022SJiri Olsa 	if (unset)
73326d33022SJiri Olsa 		return 0;
73426d33022SJiri Olsa 
73526d33022SJiri Olsa 	/* We specified default option if none is provided. */
73626d33022SJiri Olsa 	BUG_ON(!arg);
73726d33022SJiri Olsa 
73826d33022SJiri Olsa 	/* We need buffer that we know we can write to. */
73926d33022SJiri Olsa 	buf = malloc(strlen(arg) + 1);
74026d33022SJiri Olsa 	if (!buf)
74126d33022SJiri Olsa 		return -ENOMEM;
74226d33022SJiri Olsa 
74326d33022SJiri Olsa 	strcpy(buf, arg);
74426d33022SJiri Olsa 
74526d33022SJiri Olsa 	tok = strtok_r((char *)buf, ",", &saveptr);
74626d33022SJiri Olsa 	name = tok ? : (char *)buf;
74726d33022SJiri Olsa 
74826d33022SJiri Olsa 	do {
74926d33022SJiri Olsa 		/* Framepointer style */
75026d33022SJiri Olsa 		if (!strncmp(name, "fp", sizeof("fp"))) {
75126d33022SJiri Olsa 			if (!strtok_r(NULL, ",", &saveptr)) {
752c5ff78c3SArnaldo Carvalho de Melo 				opts->call_graph = CALLCHAIN_FP;
75326d33022SJiri Olsa 				ret = 0;
75426d33022SJiri Olsa 			} else
75526d33022SJiri Olsa 				pr_err("callchain: No more arguments "
75626d33022SJiri Olsa 				       "needed for -g fp\n");
75726d33022SJiri Olsa 			break;
75826d33022SJiri Olsa 
75995485b1cSNamhyung Kim #ifdef LIBUNWIND_SUPPORT
76026d33022SJiri Olsa 		/* Dwarf style */
76126d33022SJiri Olsa 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
76261eaa3beSArnaldo Carvalho de Melo 			const unsigned long default_stack_dump_size = 8192;
76361eaa3beSArnaldo Carvalho de Melo 
76426d33022SJiri Olsa 			ret = 0;
765c5ff78c3SArnaldo Carvalho de Melo 			opts->call_graph = CALLCHAIN_DWARF;
766c5ff78c3SArnaldo Carvalho de Melo 			opts->stack_dump_size = default_stack_dump_size;
76726d33022SJiri Olsa 
76826d33022SJiri Olsa 			tok = strtok_r(NULL, ",", &saveptr);
76926d33022SJiri Olsa 			if (tok) {
77026d33022SJiri Olsa 				unsigned long size = 0;
77126d33022SJiri Olsa 
77226d33022SJiri Olsa 				ret = get_stack_size(tok, &size);
773c5ff78c3SArnaldo Carvalho de Melo 				opts->stack_dump_size = size;
77426d33022SJiri Olsa 			}
77526d33022SJiri Olsa 
77626d33022SJiri Olsa 			if (!ret)
77726d33022SJiri Olsa 				pr_debug("callchain: stack dump size %d\n",
778c5ff78c3SArnaldo Carvalho de Melo 					 opts->stack_dump_size);
77995485b1cSNamhyung Kim #endif /* LIBUNWIND_SUPPORT */
78026d33022SJiri Olsa 		} else {
78126d33022SJiri Olsa 			pr_err("callchain: Unknown -g option "
78226d33022SJiri Olsa 			       "value: %s\n", arg);
78326d33022SJiri Olsa 			break;
78426d33022SJiri Olsa 		}
78526d33022SJiri Olsa 
78626d33022SJiri Olsa 	} while (0);
78726d33022SJiri Olsa 
78826d33022SJiri Olsa 	free(buf);
78926d33022SJiri Olsa 
79026d33022SJiri Olsa 	if (!ret)
791c5ff78c3SArnaldo Carvalho de Melo 		pr_debug("callchain: type %d\n", opts->call_graph);
79226d33022SJiri Olsa 
79326d33022SJiri Olsa 	return ret;
79426d33022SJiri Olsa }
79526d33022SJiri Olsa 
79686470930SIngo Molnar static const char * const record_usage[] = {
79786470930SIngo Molnar 	"perf record [<options>] [<command>]",
79886470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
79986470930SIngo Molnar 	NULL
80086470930SIngo Molnar };
80186470930SIngo Molnar 
802d20deb64SArnaldo Carvalho de Melo /*
803d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
804d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
805d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
806d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
807d20deb64SArnaldo Carvalho de Melo  *
808d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
809d20deb64SArnaldo Carvalho de Melo  *
810d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
811d20deb64SArnaldo Carvalho de Melo  */
812d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
813d20deb64SArnaldo Carvalho de Melo 	.opts = {
814d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
815d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
816d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
817447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
818d1cb9fceSNamhyung Kim 		.target		     = {
819d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
820d1cb9fceSNamhyung Kim 		},
821d20deb64SArnaldo Carvalho de Melo 	},
822d20deb64SArnaldo Carvalho de Melo };
8237865e817SFrederic Weisbecker 
82461eaa3beSArnaldo Carvalho de Melo #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
82561eaa3beSArnaldo Carvalho de Melo 
82661eaa3beSArnaldo Carvalho de Melo #ifdef LIBUNWIND_SUPPORT
82775d9a108SArnaldo Carvalho de Melo const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
82861eaa3beSArnaldo Carvalho de Melo #else
82975d9a108SArnaldo Carvalho de Melo const char record_callchain_help[] = CALLCHAIN_HELP "[fp]";
83061eaa3beSArnaldo Carvalho de Melo #endif
83161eaa3beSArnaldo Carvalho de Melo 
832d20deb64SArnaldo Carvalho de Melo /*
833d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
834d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
835d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
836d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
837d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
838d20deb64SArnaldo Carvalho de Melo  */
839bca647aaSTom Zanussi const struct option record_options[] = {
840d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
84186470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
842f120f9d5SJiri Olsa 		     parse_events_option),
843d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
844c171b552SLi Zefan 		     "event filter", parse_filter),
845bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
846d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
847bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
848d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
849d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
85086470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
851d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
852acac03faSKirill Smelkov 		    "collect data without buffering"),
853d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
854daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
855bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
85686470930SIngo Molnar 			    "system-wide collection from all CPUs"),
857bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
858c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
859d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('f', "force", &record.force,
8607865e817SFrederic Weisbecker 			"overwrite existing data file (deprecated)"),
861d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
862d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('o', "output", &record.output_name, "file",
86386470930SIngo Molnar 		    "output file name"),
864d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
8652e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
866d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
867d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
86801c2d99bSArnaldo Carvalho de Melo 		     "number of mmap data pages"),
869d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
87043bece79SLin Ming 		    "put the counters into a counter group"),
871c5ff78c3SArnaldo Carvalho de Melo 	OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts,
87275d9a108SArnaldo Carvalho de Melo 			     "mode[,dump_size]", record_callchain_help,
87375d9a108SArnaldo Carvalho de Melo 			     &record_parse_callchain_opt, "fp"),
874c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8753da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
876b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
877d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
878649c48a9SPeter Zijlstra 		    "per thread counts"),
879d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8804bba828dSAnton Blanchard 		    "Sample addresses"),
881d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8823e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
883d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
884649c48a9SPeter Zijlstra 		    "don't sample"),
885d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
886a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
887d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
888baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
889d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
890023695d9SStephane Eranian 		     "monitor event in cgroup name only",
891023695d9SStephane Eranian 		     parse_cgroups),
892bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
893bea03405SNamhyung Kim 		   "user to profile"),
894a5aabdacSStephane Eranian 
895a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
896a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
897a5aabdacSStephane Eranian 		     parse_branch_stack),
898a5aabdacSStephane Eranian 
899a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
900a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
901bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
90205484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
90305484298SAndi Kleen 		    "sample by weight (on special events only)"),
90486470930SIngo Molnar 	OPT_END()
90586470930SIngo Molnar };
90686470930SIngo Molnar 
9071d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
90886470930SIngo Molnar {
90969aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
91069aad6f1SArnaldo Carvalho de Melo 	struct perf_evsel *pos;
911d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
912d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
91316ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
91486470930SIngo Molnar 
915334fe7a3SNamhyung Kim 	evsel_list = perf_evlist__new();
916361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
917361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
918361c99a6SArnaldo Carvalho de Melo 
919d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
920d20deb64SArnaldo Carvalho de Melo 
921bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
922a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
923d67356e7SNamhyung Kim 	if (!argc && perf_target__none(&rec->opts.target))
924bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
92586470930SIngo Molnar 
926bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
9273780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
928023695d9SStephane Eranian 			  " system-wide mode\n");
929023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
930023695d9SStephane Eranian 	}
931023695d9SStephane Eranian 
932655000e7SArnaldo Carvalho de Melo 	symbol__init();
933baa2f6ceSArnaldo Carvalho de Melo 
934ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
935646aaea6SArnaldo Carvalho de Melo 		pr_warning(
936646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
937ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
938646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
939646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
940646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
941646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
942646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
943ec80fde7SArnaldo Carvalho de Melo 
944d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
945a1ac1d3cSStephane Eranian 		disable_buildid_cache();
946655000e7SArnaldo Carvalho de Melo 
947361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
948361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
94969aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
95069aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
951bbd36e5eSPeter Zijlstra 	}
95286470930SIngo Molnar 
95316ad2ffbSNamhyung Kim 	err = perf_target__validate(&rec->opts.target);
95416ad2ffbSNamhyung Kim 	if (err) {
95516ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
95616ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
95716ad2ffbSNamhyung Kim 	}
9584bd0f2d2SNamhyung Kim 
95916ad2ffbSNamhyung Kim 	err = perf_target__parse_uid(&rec->opts.target);
96016ad2ffbSNamhyung Kim 	if (err) {
96116ad2ffbSNamhyung Kim 		int saved_errno = errno;
96216ad2ffbSNamhyung Kim 
96316ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9643780f488SNamhyung Kim 		ui__error("%s", errbuf);
96516ad2ffbSNamhyung Kim 
96616ad2ffbSNamhyung Kim 		err = -saved_errno;
9678fa60e1fSNamhyung Kim 		goto out_symbol_exit;
96816ad2ffbSNamhyung Kim 	}
9690d37aa34SArnaldo Carvalho de Melo 
97016ad2ffbSNamhyung Kim 	err = -ENOMEM;
971b809ac10SNamhyung Kim 	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
972dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
97369aad6f1SArnaldo Carvalho de Melo 
974361c99a6SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evsel_list->entries, node) {
9757289f83cSArnaldo Carvalho de Melo 		if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
976ad7f4e3fSArnaldo Carvalho de Melo 			goto out_free_fd;
977d6d901c2SZhang, Yanmin 	}
9785c581041SArnaldo Carvalho de Melo 
979d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_interval != ULLONG_MAX)
980d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.user_interval;
981d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_freq != UINT_MAX)
982d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = rec->opts.user_freq;
983f9212819SFrederic Weisbecker 
9847e4ff9e3SMike Galbraith 	/*
9857e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
9867e4ff9e3SMike Galbraith 	 */
987d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.default_interval)
988d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = 0;
989d20deb64SArnaldo Carvalho de Melo 	else if (rec->opts.freq) {
990d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.freq;
9917e4ff9e3SMike Galbraith 	} else {
9923780f488SNamhyung Kim 		ui__error("frequency and count are zero, aborting\n");
99339d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
9945c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
9957e4ff9e3SMike Galbraith 	}
9967e4ff9e3SMike Galbraith 
997d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
9988fa60e1fSNamhyung Kim 
9998fa60e1fSNamhyung Kim 	perf_evlist__munmap(evsel_list);
10008fa60e1fSNamhyung Kim 	perf_evlist__close(evsel_list);
100139d17dacSArnaldo Carvalho de Melo out_free_fd:
10027e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
1003d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
1004d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
100539d17dacSArnaldo Carvalho de Melo 	return err;
100686470930SIngo Molnar }
1007