xref: /openbmc/linux/tools/perf/builtin-record.c (revision 475eeab9f3c1579c8da89667496084db4867bf7c)
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 	long			samples;
78d20deb64SArnaldo Carvalho de Melo 	off_t			post_processing_offset;
790f82ebc4SArnaldo Carvalho de Melo };
8086470930SIngo Molnar 
81d20deb64SArnaldo Carvalho de Melo static void advance_output(struct perf_record *rec, size_t size)
829215545eSTom Zanussi {
83d20deb64SArnaldo Carvalho de Melo 	rec->bytes_written += size;
849215545eSTom Zanussi }
859215545eSTom Zanussi 
868d3eca20SDavid Ahern static int write_output(struct perf_record *rec, void *buf, size_t size)
87f5970550SPeter Zijlstra {
88f5970550SPeter Zijlstra 	while (size) {
89d20deb64SArnaldo Carvalho de Melo 		int ret = write(rec->output, buf, size);
90f5970550SPeter Zijlstra 
918d3eca20SDavid Ahern 		if (ret < 0) {
928d3eca20SDavid Ahern 			pr_err("failed to write\n");
938d3eca20SDavid Ahern 			return -1;
948d3eca20SDavid Ahern 		}
95f5970550SPeter Zijlstra 
96f5970550SPeter Zijlstra 		size -= ret;
97f5970550SPeter Zijlstra 		buf += ret;
98f5970550SPeter Zijlstra 
99d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written += ret;
100f5970550SPeter Zijlstra 	}
1018d3eca20SDavid Ahern 
1028d3eca20SDavid Ahern 	return 0;
103f5970550SPeter Zijlstra }
104f5970550SPeter Zijlstra 
10545694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
106d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
1071d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
1081d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
109234fbbf5SArnaldo Carvalho de Melo {
11045694aa7SArnaldo Carvalho de Melo 	struct perf_record *rec = container_of(tool, struct perf_record, tool);
1118d3eca20SDavid Ahern 	if (write_output(rec, event, event->header.size) < 0)
1128d3eca20SDavid Ahern 		return -1;
1138d3eca20SDavid Ahern 
114234fbbf5SArnaldo Carvalho de Melo 	return 0;
115234fbbf5SArnaldo Carvalho de Melo }
116234fbbf5SArnaldo Carvalho de Melo 
1178d3eca20SDavid Ahern static int perf_record__mmap_read(struct perf_record *rec,
118d20deb64SArnaldo Carvalho de Melo 				   struct perf_mmap *md)
11986470930SIngo Molnar {
120744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
12186470930SIngo Molnar 	unsigned int old = md->prev;
122d20deb64SArnaldo Carvalho de Melo 	unsigned char *data = md->base + rec->page_size;
12386470930SIngo Molnar 	unsigned long size;
12486470930SIngo Molnar 	void *buf;
1258d3eca20SDavid Ahern 	int rc = 0;
12686470930SIngo Molnar 
127dc82009aSArnaldo Carvalho de Melo 	if (old == head)
1288d3eca20SDavid Ahern 		return 0;
12986470930SIngo Molnar 
130d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
13186470930SIngo Molnar 
13286470930SIngo Molnar 	size = head - old;
13386470930SIngo Molnar 
13486470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
13586470930SIngo Molnar 		buf = &data[old & md->mask];
13686470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
13786470930SIngo Molnar 		old += size;
13886470930SIngo Molnar 
1398d3eca20SDavid Ahern 		if (write_output(rec, buf, size) < 0) {
1408d3eca20SDavid Ahern 			rc = -1;
1418d3eca20SDavid Ahern 			goto out;
1428d3eca20SDavid Ahern 		}
14386470930SIngo Molnar 	}
14486470930SIngo Molnar 
14586470930SIngo Molnar 	buf = &data[old & md->mask];
14686470930SIngo Molnar 	size = head - old;
14786470930SIngo Molnar 	old += size;
14886470930SIngo Molnar 
1498d3eca20SDavid Ahern 	if (write_output(rec, buf, size) < 0) {
1508d3eca20SDavid Ahern 		rc = -1;
1518d3eca20SDavid Ahern 		goto out;
1528d3eca20SDavid Ahern 	}
15386470930SIngo Molnar 
15486470930SIngo Molnar 	md->prev = old;
155115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
1568d3eca20SDavid Ahern 
1578d3eca20SDavid Ahern out:
1588d3eca20SDavid Ahern 	return rc;
15986470930SIngo Molnar }
16086470930SIngo Molnar 
16186470930SIngo Molnar static volatile int done = 0;
162f7b7c26eSPeter Zijlstra static volatile int signr = -1;
16333e49ea7SAndi Kleen static volatile int child_finished = 0;
16486470930SIngo Molnar 
16586470930SIngo Molnar static void sig_handler(int sig)
16686470930SIngo Molnar {
16733e49ea7SAndi Kleen 	if (sig == SIGCHLD)
16833e49ea7SAndi Kleen 		child_finished = 1;
16933e49ea7SAndi Kleen 
17086470930SIngo Molnar 	done = 1;
171f7b7c26eSPeter Zijlstra 	signr = sig;
172f7b7c26eSPeter Zijlstra }
173f7b7c26eSPeter Zijlstra 
1741d037ca1SIrina Tirdea static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
175f7b7c26eSPeter Zijlstra {
176d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
17733e49ea7SAndi Kleen 	int status;
17833e49ea7SAndi Kleen 
179d20deb64SArnaldo Carvalho de Melo 	if (rec->evlist->workload.pid > 0) {
18033e49ea7SAndi Kleen 		if (!child_finished)
181d20deb64SArnaldo Carvalho de Melo 			kill(rec->evlist->workload.pid, SIGTERM);
182933da83aSChris Wilson 
18333e49ea7SAndi Kleen 		wait(&status);
18433e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
185d20deb64SArnaldo Carvalho de Melo 			psignal(WTERMSIG(status), rec->progname);
18633e49ea7SAndi Kleen 	}
18733e49ea7SAndi Kleen 
18818483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
189f7b7c26eSPeter Zijlstra 		return;
190f7b7c26eSPeter Zijlstra 
191f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
19286470930SIngo Molnar }
19386470930SIngo Molnar 
1948d3eca20SDavid Ahern static int perf_record__open(struct perf_record *rec)
195dd7927f4SArnaldo Carvalho de Melo {
19656e52e85SArnaldo Carvalho de Melo 	char msg[512];
1976a4bb04cSJiri Olsa 	struct perf_evsel *pos;
198d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
199d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
200d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
2018d3eca20SDavid Ahern 	int rc = 0;
202dd7927f4SArnaldo Carvalho de Melo 
203f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
204cac21425SJiri Olsa 
205dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
2063da297a6SIngo Molnar try_again:
2076a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
20856e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2093da297a6SIngo Molnar 				if (verbose)
210c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2113da297a6SIngo Molnar 				goto try_again;
2123da297a6SIngo Molnar 			}
213ca6a4258SDavid Ahern 
21456e52e85SArnaldo Carvalho de Melo 			rc = -errno;
21556e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
21656e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
21756e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
2188d3eca20SDavid Ahern 			goto out;
2197c6a1c65SPeter Zijlstra 		}
2207c6a1c65SPeter Zijlstra 	}
2217c6a1c65SPeter Zijlstra 
2221491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
2230a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2240a102479SFrederic Weisbecker 			strerror(errno));
2258d3eca20SDavid Ahern 		rc = -1;
2268d3eca20SDavid Ahern 		goto out;
2270a102479SFrederic Weisbecker 	}
2280a102479SFrederic Weisbecker 
22918e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
2308d3eca20SDavid Ahern 		if (errno == EPERM) {
2318d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
23218e60939SNelson Elhage 			       "Consider increasing "
23318e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
23418e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
23518e60939SNelson Elhage 			       "(current value: %d)\n", opts->mmap_pages);
2368d3eca20SDavid Ahern 			rc = -errno;
2370089fa98SJiri Olsa 		} else if (!is_power_of_2(opts->mmap_pages) &&
2380089fa98SJiri Olsa 			   (opts->mmap_pages != UINT_MAX)) {
2398d3eca20SDavid Ahern 			pr_err("--mmap_pages/-m value must be a power of two.");
2408d3eca20SDavid Ahern 			rc = -EINVAL;
2418d3eca20SDavid Ahern 		} else {
2428d3eca20SDavid Ahern 			pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
2438d3eca20SDavid Ahern 			rc = -errno;
2448d3eca20SDavid Ahern 		}
2458d3eca20SDavid Ahern 		goto out;
24618e60939SNelson Elhage 	}
2470a27d7f9SArnaldo Carvalho de Melo 
248a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
2497b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
2508d3eca20SDavid Ahern out:
2518d3eca20SDavid Ahern 	return rc;
252a91e5431SArnaldo Carvalho de Melo }
253a91e5431SArnaldo Carvalho de Melo 
254d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
2556122e4e4SArnaldo Carvalho de Melo {
256d20deb64SArnaldo Carvalho de Melo 	u64 size = lseek(rec->output, 0, SEEK_CUR);
2576122e4e4SArnaldo Carvalho de Melo 
2589f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2599f591fd7SArnaldo Carvalho de Melo 		return 0;
2609f591fd7SArnaldo Carvalho de Melo 
261d20deb64SArnaldo Carvalho de Melo 	rec->session->fd = rec->output;
262d20deb64SArnaldo Carvalho de Melo 	return __perf_session__process_events(rec->session, rec->post_processing_offset,
263d20deb64SArnaldo Carvalho de Melo 					      size - rec->post_processing_offset,
2646122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
2656122e4e4SArnaldo Carvalho de Melo }
2666122e4e4SArnaldo Carvalho de Melo 
2678d3eca20SDavid Ahern static void perf_record__exit(int status, void *arg)
268f5970550SPeter Zijlstra {
269d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
270f5970550SPeter Zijlstra 
2718d3eca20SDavid Ahern 	if (status != 0)
2728d3eca20SDavid Ahern 		return;
2738d3eca20SDavid Ahern 
274d20deb64SArnaldo Carvalho de Melo 	if (!rec->opts.pipe_output) {
275d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
276d20deb64SArnaldo Carvalho de Melo 
277d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
278d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
279d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
280d20deb64SArnaldo Carvalho de Melo 					   rec->output, true);
281d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
282d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
283d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
284c7929e47STom Zanussi 	}
285f5970550SPeter Zijlstra }
286f5970550SPeter Zijlstra 
2878115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
288a1645ce1SZhang, Yanmin {
289a1645ce1SZhang, Yanmin 	int err;
29045694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
291a1645ce1SZhang, Yanmin 	/*
292a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
293a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
294a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
295a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
296a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
297a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
298a1645ce1SZhang, Yanmin 	 */
29945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
300743eb868SArnaldo Carvalho de Melo 					     machine);
301a1645ce1SZhang, Yanmin 	if (err < 0)
302a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
30323346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
304a1645ce1SZhang, Yanmin 
305a1645ce1SZhang, Yanmin 	/*
306a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
307a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
308a1645ce1SZhang, Yanmin 	 */
30945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
310743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
311a1645ce1SZhang, Yanmin 	if (err < 0)
31245694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
313743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
314a1645ce1SZhang, Yanmin 	if (err < 0)
315a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
31623346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
317a1645ce1SZhang, Yanmin }
318a1645ce1SZhang, Yanmin 
31998402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
32098402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
32198402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
32298402807SFrederic Weisbecker };
32398402807SFrederic Weisbecker 
3248d3eca20SDavid Ahern static int perf_record__mmap_read_all(struct perf_record *rec)
32598402807SFrederic Weisbecker {
3260e2e63ddSPeter Zijlstra 	int i;
3278d3eca20SDavid Ahern 	int rc = 0;
32898402807SFrederic Weisbecker 
329d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
3308d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
3318d3eca20SDavid Ahern 			if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
3328d3eca20SDavid Ahern 				rc = -1;
3338d3eca20SDavid Ahern 				goto out;
3348d3eca20SDavid Ahern 			}
3358d3eca20SDavid Ahern 		}
33698402807SFrederic Weisbecker 	}
33798402807SFrederic Weisbecker 
3382eeaaa09SStephane Eranian 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
3398d3eca20SDavid Ahern 		rc = write_output(rec, &finished_round_event,
3408d3eca20SDavid Ahern 				  sizeof(finished_round_event));
3418d3eca20SDavid Ahern 
3428d3eca20SDavid Ahern out:
3438d3eca20SDavid Ahern 	return rc;
34498402807SFrederic Weisbecker }
34598402807SFrederic Weisbecker 
346d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
34786470930SIngo Molnar {
34886470930SIngo Molnar 	struct stat st;
34986470930SIngo Molnar 	int flags;
350781ba9d2SRobert Richter 	int err, output, feat;
3518b412664SPeter Zijlstra 	unsigned long waking = 0;
35246be604bSZhang, Yanmin 	const bool forks = argc > 0;
35323346f21SArnaldo Carvalho de Melo 	struct machine *machine;
35445694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
355d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
356d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
357d20deb64SArnaldo Carvalho de Melo 	const char *output_name = rec->output_name;
358d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3592711926aSJiri Olsa 	bool disabled = false;
36086470930SIngo Molnar 
361d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
36233e49ea7SAndi Kleen 
363d20deb64SArnaldo Carvalho de Melo 	rec->page_size = sysconf(_SC_PAGE_SIZE);
36486470930SIngo Molnar 
365d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
366f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
367f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
36818483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
369804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
370f5970550SPeter Zijlstra 
371d7065adbSFranck Bui-Huu 	if (!output_name) {
372d7065adbSFranck Bui-Huu 		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
373d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
374d7065adbSFranck Bui-Huu 		else
375d20deb64SArnaldo Carvalho de Melo 			rec->output_name = output_name = "perf.data";
376d7065adbSFranck Bui-Huu 	}
377d7065adbSFranck Bui-Huu 	if (output_name) {
378529870e3STom Zanussi 		if (!strcmp(output_name, "-"))
379d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
380529870e3STom Zanussi 		else if (!stat(output_name, &st) && st.st_size) {
381b38d3464SArnaldo Carvalho de Melo 			char oldname[PATH_MAX];
382b38d3464SArnaldo Carvalho de Melo 			snprintf(oldname, sizeof(oldname), "%s.old",
383b38d3464SArnaldo Carvalho de Melo 				 output_name);
384b38d3464SArnaldo Carvalho de Melo 			unlink(oldname);
385b38d3464SArnaldo Carvalho de Melo 			rename(output_name, oldname);
386b38d3464SArnaldo Carvalho de Melo 		}
387d7065adbSFranck Bui-Huu 	}
38886470930SIngo Molnar 
389563aecb2SJiri Olsa 	flags = O_CREAT|O_RDWR|O_TRUNC;
39086470930SIngo Molnar 
391d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output)
392529870e3STom Zanussi 		output = STDOUT_FILENO;
393529870e3STom Zanussi 	else
39486470930SIngo Molnar 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
39586470930SIngo Molnar 	if (output < 0) {
39686470930SIngo Molnar 		perror("failed to create output file");
3978d3eca20SDavid Ahern 		return -1;
39886470930SIngo Molnar 	}
39986470930SIngo Molnar 
400d20deb64SArnaldo Carvalho de Melo 	rec->output = output;
401d20deb64SArnaldo Carvalho de Melo 
4027865e817SFrederic Weisbecker 	session = perf_session__new(output_name, O_WRONLY,
403563aecb2SJiri Olsa 				    true, false, NULL);
40494c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
405a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
406a9a70bbcSArnaldo Carvalho de Melo 		return -1;
407a9a70bbcSArnaldo Carvalho de Melo 	}
408a9a70bbcSArnaldo Carvalho de Melo 
409d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
410d20deb64SArnaldo Carvalho de Melo 
411781ba9d2SRobert Richter 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
412781ba9d2SRobert Richter 		perf_header__set_feat(&session->header, feat);
413781ba9d2SRobert Richter 
414781ba9d2SRobert Richter 	if (rec->no_buildid)
415781ba9d2SRobert Richter 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
416781ba9d2SRobert Richter 
417781ba9d2SRobert Richter 	if (!have_tracepoints(&evsel_list->entries))
4182eeaaa09SStephane Eranian 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
419baa2f6ceSArnaldo Carvalho de Melo 
420330aa675SStephane Eranian 	if (!rec->opts.branch_stack)
421330aa675SStephane Eranian 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
422330aa675SStephane Eranian 
423d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
4246ef73ec4SNamhyung Kim 		err = perf_evlist__prepare_workload(evsel_list, &opts->target,
42555e162eaSNamhyung Kim 						    argv, opts->pipe_output,
42655e162eaSNamhyung Kim 						    true);
42735b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
42835b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
42935b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
430856e9660SPeter Zijlstra 		}
431856e9660SPeter Zijlstra 	}
432856e9660SPeter Zijlstra 
4338d3eca20SDavid Ahern 	if (perf_record__open(rec) != 0) {
4348d3eca20SDavid Ahern 		err = -1;
4358d3eca20SDavid Ahern 		goto out_delete_session;
4368d3eca20SDavid Ahern 	}
43786470930SIngo Molnar 
438a8bb559bSNamhyung Kim 	if (!evsel_list->nr_groups)
439a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
440a8bb559bSNamhyung Kim 
441712a4b60SArnaldo Carvalho de Melo 	/*
442d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
443712a4b60SArnaldo Carvalho de Melo 	 */
444d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
445712a4b60SArnaldo Carvalho de Melo 
446d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
447529870e3STom Zanussi 		err = perf_header__write_pipe(output);
448529870e3STom Zanussi 		if (err < 0)
4498d3eca20SDavid Ahern 			goto out_delete_session;
450563aecb2SJiri Olsa 	} else {
451a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
452361c99a6SArnaldo Carvalho de Melo 						 output, false);
453d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
4548d3eca20SDavid Ahern 			goto out_delete_session;
455d5eed904SArnaldo Carvalho de Melo 	}
4567c6a1c65SPeter Zijlstra 
457d3665498SDavid Ahern 	if (!rec->no_buildid
458e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
459d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
460e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
4618d3eca20SDavid Ahern 		err = -1;
4628d3eca20SDavid Ahern 		goto out_delete_session;
463e20960c0SRobert Richter 	}
464e20960c0SRobert Richter 
465d20deb64SArnaldo Carvalho de Melo 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
4666122e4e4SArnaldo Carvalho de Melo 
46734ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
468743eb868SArnaldo Carvalho de Melo 
469d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
47045694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
471a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
4722c46dbb5STom Zanussi 		if (err < 0) {
4732c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
4748d3eca20SDavid Ahern 			goto out_delete_session;
4752c46dbb5STom Zanussi 		}
476cd19a035STom Zanussi 
477361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
47863e0c771STom Zanussi 			/*
47963e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
48063e0c771STom Zanussi 			 * there were no tracepoints so its not really
48163e0c771STom Zanussi 			 * an error, just that we don't need to
48263e0c771STom Zanussi 			 * synthesize anything.  We really have to
48363e0c771STom Zanussi 			 * return this more properly and also
48463e0c771STom Zanussi 			 * propagate errors that now are calling die()
48563e0c771STom Zanussi 			 */
48645694aa7SArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
487743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
48863e0c771STom Zanussi 			if (err <= 0) {
48963e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
4908d3eca20SDavid Ahern 				goto out_delete_session;
49163e0c771STom Zanussi 			}
492d20deb64SArnaldo Carvalho de Melo 			advance_output(rec, err);
4932c46dbb5STom Zanussi 		}
49463e0c771STom Zanussi 	}
4952c46dbb5STom Zanussi 
49645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
497743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
49870162138SArnaldo Carvalho de Melo 	if (err < 0)
49945694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
500743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
501c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
502c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
503c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
504c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
50556b03f3cSArnaldo Carvalho de Melo 
50645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
507743eb868SArnaldo Carvalho de Melo 					     machine);
508c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
509c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
510c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
511c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
512c1a3a4b9SArnaldo Carvalho de Melo 
5137e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
514876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
5157e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
5167e383de4SArnaldo Carvalho de Melo 	}
517b7cece76SArnaldo Carvalho de Melo 
518e4dd45feSJiri Olsa 	if (perf_target__has_task(&opts->target))
5198d3eca20SDavid Ahern 		err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
5208115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
521743eb868SArnaldo Carvalho de Melo 						  machine);
522e4dd45feSJiri Olsa 	else if (perf_target__has_cpu(&opts->target))
5238d3eca20SDavid Ahern 		err = perf_event__synthesize_threads(tool, process_synthesized_event,
524743eb868SArnaldo Carvalho de Melo 					       machine);
525e4dd45feSJiri Olsa 	else /* command specified */
526e4dd45feSJiri Olsa 		err = 0;
5277c6a1c65SPeter Zijlstra 
5288d3eca20SDavid Ahern 	if (err != 0)
5298d3eca20SDavid Ahern 		goto out_delete_session;
5308d3eca20SDavid Ahern 
531d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
53286470930SIngo Molnar 		struct sched_param param;
53386470930SIngo Molnar 
534d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
53586470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5366beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
5378d3eca20SDavid Ahern 			err = -1;
5388d3eca20SDavid Ahern 			goto out_delete_session;
53986470930SIngo Molnar 		}
54086470930SIngo Molnar 	}
54186470930SIngo Molnar 
542774cb499SJiri Olsa 	/*
543774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
544774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
545774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
546774cb499SJiri Olsa 	 */
547774cb499SJiri Olsa 	if (!perf_target__none(&opts->target))
548764e16a3SDavid Ahern 		perf_evlist__enable(evsel_list);
549764e16a3SDavid Ahern 
550856e9660SPeter Zijlstra 	/*
551856e9660SPeter Zijlstra 	 * Let the child rip
552856e9660SPeter Zijlstra 	 */
553d4db3f16SArnaldo Carvalho de Melo 	if (forks)
55435b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
555856e9660SPeter Zijlstra 
556649c48a9SPeter Zijlstra 	for (;;) {
557d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
55886470930SIngo Molnar 
5598d3eca20SDavid Ahern 		if (perf_record__mmap_read_all(rec) < 0) {
5608d3eca20SDavid Ahern 			err = -1;
5618d3eca20SDavid Ahern 			goto out_delete_session;
5628d3eca20SDavid Ahern 		}
56386470930SIngo Molnar 
564d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
565649c48a9SPeter Zijlstra 			if (done)
566649c48a9SPeter Zijlstra 				break;
5675c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
5688b412664SPeter Zijlstra 			waking++;
5698b412664SPeter Zijlstra 		}
5708b412664SPeter Zijlstra 
571774cb499SJiri Olsa 		/*
572774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
573774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
574774cb499SJiri Olsa 		 * disable events in this case.
575774cb499SJiri Olsa 		 */
5762711926aSJiri Olsa 		if (done && !disabled && !perf_target__none(&opts->target)) {
5774152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
5782711926aSJiri Olsa 			disabled = true;
5792711926aSJiri Olsa 		}
5808b412664SPeter Zijlstra 	}
5818b412664SPeter Zijlstra 
58218483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
583b44308f5SArnaldo Carvalho de Melo 		return 0;
584b44308f5SArnaldo Carvalho de Melo 
5858b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
58686470930SIngo Molnar 
58786470930SIngo Molnar 	/*
58886470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
58986470930SIngo Molnar 	 */
59086470930SIngo Molnar 	fprintf(stderr,
5919486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
592d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
59386470930SIngo Molnar 		output_name,
594d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
59586470930SIngo Molnar 
59686470930SIngo Molnar 	return 0;
59739d17dacSArnaldo Carvalho de Melo 
59839d17dacSArnaldo Carvalho de Melo out_delete_session:
59939d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
60039d17dacSArnaldo Carvalho de Melo 	return err;
60186470930SIngo Molnar }
60286470930SIngo Molnar 
603bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
604bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
605bdfebd84SRoberto Agostino Vitillo 
606bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
607bdfebd84SRoberto Agostino Vitillo 
608bdfebd84SRoberto Agostino Vitillo struct branch_mode {
609bdfebd84SRoberto Agostino Vitillo 	const char *name;
610bdfebd84SRoberto Agostino Vitillo 	int mode;
611bdfebd84SRoberto Agostino Vitillo };
612bdfebd84SRoberto Agostino Vitillo 
613bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
614bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
615bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
616bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
617bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
618bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
619bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
620bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
6210126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
6220126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
6230126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
624bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
625bdfebd84SRoberto Agostino Vitillo };
626bdfebd84SRoberto Agostino Vitillo 
627bdfebd84SRoberto Agostino Vitillo static int
628a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
629bdfebd84SRoberto Agostino Vitillo {
630bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
631bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
632bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
633bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
634bdfebd84SRoberto Agostino Vitillo 
635bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
636bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
637a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
638bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
639bdfebd84SRoberto Agostino Vitillo 
640a5aabdacSStephane Eranian 	if (unset)
641a5aabdacSStephane Eranian 		return 0;
642bdfebd84SRoberto Agostino Vitillo 
643a5aabdacSStephane Eranian 	/*
644a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
645a5aabdacSStephane Eranian 	 */
646a5aabdacSStephane Eranian 	if (*mode)
647a5aabdacSStephane Eranian 		return -1;
648a5aabdacSStephane Eranian 
649a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
650a5aabdacSStephane Eranian 	if (str) {
651bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
652bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
653bdfebd84SRoberto Agostino Vitillo 		if (!s)
654bdfebd84SRoberto Agostino Vitillo 			return -1;
655bdfebd84SRoberto Agostino Vitillo 
656bdfebd84SRoberto Agostino Vitillo 		for (;;) {
657bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
658bdfebd84SRoberto Agostino Vitillo 			if (p)
659bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
660bdfebd84SRoberto Agostino Vitillo 
661bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
662bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
663bdfebd84SRoberto Agostino Vitillo 					break;
664bdfebd84SRoberto Agostino Vitillo 			}
665a5aabdacSStephane Eranian 			if (!br->name) {
666a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
667a5aabdacSStephane Eranian 					    " check man page\n", s);
668bdfebd84SRoberto Agostino Vitillo 				goto error;
669a5aabdacSStephane Eranian 			}
670bdfebd84SRoberto Agostino Vitillo 
671bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
672bdfebd84SRoberto Agostino Vitillo 
673bdfebd84SRoberto Agostino Vitillo 			if (!p)
674bdfebd84SRoberto Agostino Vitillo 				break;
675bdfebd84SRoberto Agostino Vitillo 
676bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
677bdfebd84SRoberto Agostino Vitillo 		}
678a5aabdacSStephane Eranian 	}
679bdfebd84SRoberto Agostino Vitillo 	ret = 0;
680bdfebd84SRoberto Agostino Vitillo 
681a5aabdacSStephane Eranian 	/* default to any branch */
682bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
683a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
684bdfebd84SRoberto Agostino Vitillo 	}
685bdfebd84SRoberto Agostino Vitillo error:
686bdfebd84SRoberto Agostino Vitillo 	free(os);
687bdfebd84SRoberto Agostino Vitillo 	return ret;
688bdfebd84SRoberto Agostino Vitillo }
689bdfebd84SRoberto Agostino Vitillo 
69095485b1cSNamhyung Kim #ifdef LIBUNWIND_SUPPORT
69126d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size)
69226d33022SJiri Olsa {
69326d33022SJiri Olsa 	char *endptr;
69426d33022SJiri Olsa 	unsigned long size;
69526d33022SJiri Olsa 	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
69626d33022SJiri Olsa 
69726d33022SJiri Olsa 	size = strtoul(str, &endptr, 0);
69826d33022SJiri Olsa 
69926d33022SJiri Olsa 	do {
70026d33022SJiri Olsa 		if (*endptr)
70126d33022SJiri Olsa 			break;
70226d33022SJiri Olsa 
70326d33022SJiri Olsa 		size = round_up(size, sizeof(u64));
70426d33022SJiri Olsa 		if (!size || size > max_size)
70526d33022SJiri Olsa 			break;
70626d33022SJiri Olsa 
70726d33022SJiri Olsa 		*_size = size;
70826d33022SJiri Olsa 		return 0;
70926d33022SJiri Olsa 
71026d33022SJiri Olsa 	} while (0);
71126d33022SJiri Olsa 
71226d33022SJiri Olsa 	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
71326d33022SJiri Olsa 	       max_size, str);
71426d33022SJiri Olsa 	return -1;
71526d33022SJiri Olsa }
71695485b1cSNamhyung Kim #endif /* LIBUNWIND_SUPPORT */
71726d33022SJiri Olsa 
71875d9a108SArnaldo Carvalho de Melo int record_parse_callchain_opt(const struct option *opt,
71975d9a108SArnaldo Carvalho de Melo 			       const char *arg, int unset)
72026d33022SJiri Olsa {
721c5ff78c3SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = opt->value;
72226d33022SJiri Olsa 	char *tok, *name, *saveptr = NULL;
72326d33022SJiri Olsa 	char *buf;
72426d33022SJiri Olsa 	int ret = -1;
72526d33022SJiri Olsa 
72626d33022SJiri Olsa 	/* --no-call-graph */
72726d33022SJiri Olsa 	if (unset)
72826d33022SJiri Olsa 		return 0;
72926d33022SJiri Olsa 
73026d33022SJiri Olsa 	/* We specified default option if none is provided. */
73126d33022SJiri Olsa 	BUG_ON(!arg);
73226d33022SJiri Olsa 
73326d33022SJiri Olsa 	/* We need buffer that we know we can write to. */
73426d33022SJiri Olsa 	buf = malloc(strlen(arg) + 1);
73526d33022SJiri Olsa 	if (!buf)
73626d33022SJiri Olsa 		return -ENOMEM;
73726d33022SJiri Olsa 
73826d33022SJiri Olsa 	strcpy(buf, arg);
73926d33022SJiri Olsa 
74026d33022SJiri Olsa 	tok = strtok_r((char *)buf, ",", &saveptr);
74126d33022SJiri Olsa 	name = tok ? : (char *)buf;
74226d33022SJiri Olsa 
74326d33022SJiri Olsa 	do {
74426d33022SJiri Olsa 		/* Framepointer style */
74526d33022SJiri Olsa 		if (!strncmp(name, "fp", sizeof("fp"))) {
74626d33022SJiri Olsa 			if (!strtok_r(NULL, ",", &saveptr)) {
747c5ff78c3SArnaldo Carvalho de Melo 				opts->call_graph = CALLCHAIN_FP;
74826d33022SJiri Olsa 				ret = 0;
74926d33022SJiri Olsa 			} else
75026d33022SJiri Olsa 				pr_err("callchain: No more arguments "
75126d33022SJiri Olsa 				       "needed for -g fp\n");
75226d33022SJiri Olsa 			break;
75326d33022SJiri Olsa 
75495485b1cSNamhyung Kim #ifdef LIBUNWIND_SUPPORT
75526d33022SJiri Olsa 		/* Dwarf style */
75626d33022SJiri Olsa 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
75761eaa3beSArnaldo Carvalho de Melo 			const unsigned long default_stack_dump_size = 8192;
75861eaa3beSArnaldo Carvalho de Melo 
75926d33022SJiri Olsa 			ret = 0;
760c5ff78c3SArnaldo Carvalho de Melo 			opts->call_graph = CALLCHAIN_DWARF;
761c5ff78c3SArnaldo Carvalho de Melo 			opts->stack_dump_size = default_stack_dump_size;
76226d33022SJiri Olsa 
76326d33022SJiri Olsa 			tok = strtok_r(NULL, ",", &saveptr);
76426d33022SJiri Olsa 			if (tok) {
76526d33022SJiri Olsa 				unsigned long size = 0;
76626d33022SJiri Olsa 
76726d33022SJiri Olsa 				ret = get_stack_size(tok, &size);
768c5ff78c3SArnaldo Carvalho de Melo 				opts->stack_dump_size = size;
76926d33022SJiri Olsa 			}
77026d33022SJiri Olsa 
77126d33022SJiri Olsa 			if (!ret)
77226d33022SJiri Olsa 				pr_debug("callchain: stack dump size %d\n",
773c5ff78c3SArnaldo Carvalho de Melo 					 opts->stack_dump_size);
77495485b1cSNamhyung Kim #endif /* LIBUNWIND_SUPPORT */
77526d33022SJiri Olsa 		} else {
77626d33022SJiri Olsa 			pr_err("callchain: Unknown -g option "
77726d33022SJiri Olsa 			       "value: %s\n", arg);
77826d33022SJiri Olsa 			break;
77926d33022SJiri Olsa 		}
78026d33022SJiri Olsa 
78126d33022SJiri Olsa 	} while (0);
78226d33022SJiri Olsa 
78326d33022SJiri Olsa 	free(buf);
78426d33022SJiri Olsa 
78526d33022SJiri Olsa 	if (!ret)
786c5ff78c3SArnaldo Carvalho de Melo 		pr_debug("callchain: type %d\n", opts->call_graph);
78726d33022SJiri Olsa 
78826d33022SJiri Olsa 	return ret;
78926d33022SJiri Olsa }
79026d33022SJiri Olsa 
79186470930SIngo Molnar static const char * const record_usage[] = {
79286470930SIngo Molnar 	"perf record [<options>] [<command>]",
79386470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
79486470930SIngo Molnar 	NULL
79586470930SIngo Molnar };
79686470930SIngo Molnar 
797d20deb64SArnaldo Carvalho de Melo /*
798d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
799d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
800d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
801d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
802d20deb64SArnaldo Carvalho de Melo  *
803d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
804d20deb64SArnaldo Carvalho de Melo  *
805d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
806d20deb64SArnaldo Carvalho de Melo  */
807d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
808d20deb64SArnaldo Carvalho de Melo 	.opts = {
809d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
810d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
811d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
812447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
813d1cb9fceSNamhyung Kim 		.target		     = {
814d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
815d1cb9fceSNamhyung Kim 		},
816d20deb64SArnaldo Carvalho de Melo 	},
817d20deb64SArnaldo Carvalho de Melo };
8187865e817SFrederic Weisbecker 
81961eaa3beSArnaldo Carvalho de Melo #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
82061eaa3beSArnaldo Carvalho de Melo 
82161eaa3beSArnaldo Carvalho de Melo #ifdef LIBUNWIND_SUPPORT
82275d9a108SArnaldo Carvalho de Melo const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
82361eaa3beSArnaldo Carvalho de Melo #else
82475d9a108SArnaldo Carvalho de Melo const char record_callchain_help[] = CALLCHAIN_HELP "[fp]";
82561eaa3beSArnaldo Carvalho de Melo #endif
82661eaa3beSArnaldo Carvalho de Melo 
827d20deb64SArnaldo Carvalho de Melo /*
828d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
829d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
830d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
831d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
832d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
833d20deb64SArnaldo Carvalho de Melo  */
834bca647aaSTom Zanussi const struct option record_options[] = {
835d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
83686470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
837f120f9d5SJiri Olsa 		     parse_events_option),
838d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
839c171b552SLi Zefan 		     "event filter", parse_filter),
840bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
841d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
842bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
843d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
844d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
84586470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
846d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
847acac03faSKirill Smelkov 		    "collect data without buffering"),
848d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
849daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
850bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
85186470930SIngo Molnar 			    "system-wide collection from all CPUs"),
852bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
853c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
854d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
855d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('o', "output", &record.output_name, "file",
85686470930SIngo Molnar 		    "output file name"),
857d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
8582e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
859d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
860d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
86101c2d99bSArnaldo Carvalho de Melo 		     "number of mmap data pages"),
862d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
86343bece79SLin Ming 		    "put the counters into a counter group"),
864c5ff78c3SArnaldo Carvalho de Melo 	OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts,
86575d9a108SArnaldo Carvalho de Melo 			     "mode[,dump_size]", record_callchain_help,
86675d9a108SArnaldo Carvalho de Melo 			     &record_parse_callchain_opt, "fp"),
867c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8683da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
869b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
870d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
871649c48a9SPeter Zijlstra 		    "per thread counts"),
872d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8734bba828dSAnton Blanchard 		    "Sample addresses"),
874d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8753e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
876d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
877649c48a9SPeter Zijlstra 		    "don't sample"),
878d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
879a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
880d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
881baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
882d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
883023695d9SStephane Eranian 		     "monitor event in cgroup name only",
884023695d9SStephane Eranian 		     parse_cgroups),
885bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
886bea03405SNamhyung Kim 		   "user to profile"),
887a5aabdacSStephane Eranian 
888a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
889a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
890a5aabdacSStephane Eranian 		     parse_branch_stack),
891a5aabdacSStephane Eranian 
892a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
893a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
894bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
89505484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
89605484298SAndi Kleen 		    "sample by weight (on special events only)"),
897*475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
898*475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
89986470930SIngo Molnar 	OPT_END()
90086470930SIngo Molnar };
90186470930SIngo Molnar 
9021d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
90386470930SIngo Molnar {
90469aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
905d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
906d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
90716ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
90886470930SIngo Molnar 
909334fe7a3SNamhyung Kim 	evsel_list = perf_evlist__new();
910361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
911361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
912361c99a6SArnaldo Carvalho de Melo 
913d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
914d20deb64SArnaldo Carvalho de Melo 
915bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
916a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
917d67356e7SNamhyung Kim 	if (!argc && perf_target__none(&rec->opts.target))
918bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
91986470930SIngo Molnar 
920bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
9213780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
922023695d9SStephane Eranian 			  " system-wide mode\n");
923023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
924023695d9SStephane Eranian 	}
925023695d9SStephane Eranian 
926655000e7SArnaldo Carvalho de Melo 	symbol__init();
927baa2f6ceSArnaldo Carvalho de Melo 
928ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
929646aaea6SArnaldo Carvalho de Melo 		pr_warning(
930646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
931ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
932646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
933646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
934646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
935646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
936646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
937ec80fde7SArnaldo Carvalho de Melo 
938d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
939a1ac1d3cSStephane Eranian 		disable_buildid_cache();
940655000e7SArnaldo Carvalho de Melo 
941361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
942361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
94369aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
94469aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
945bbd36e5eSPeter Zijlstra 	}
94686470930SIngo Molnar 
94716ad2ffbSNamhyung Kim 	err = perf_target__validate(&rec->opts.target);
94816ad2ffbSNamhyung Kim 	if (err) {
94916ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
95016ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
95116ad2ffbSNamhyung Kim 	}
9524bd0f2d2SNamhyung Kim 
95316ad2ffbSNamhyung Kim 	err = perf_target__parse_uid(&rec->opts.target);
95416ad2ffbSNamhyung Kim 	if (err) {
95516ad2ffbSNamhyung Kim 		int saved_errno = errno;
95616ad2ffbSNamhyung Kim 
95716ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9583780f488SNamhyung Kim 		ui__error("%s", errbuf);
95916ad2ffbSNamhyung Kim 
96016ad2ffbSNamhyung Kim 		err = -saved_errno;
9618fa60e1fSNamhyung Kim 		goto out_symbol_exit;
96216ad2ffbSNamhyung Kim 	}
9630d37aa34SArnaldo Carvalho de Melo 
96416ad2ffbSNamhyung Kim 	err = -ENOMEM;
965b809ac10SNamhyung Kim 	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
966dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
96769aad6f1SArnaldo Carvalho de Melo 
968d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_interval != ULLONG_MAX)
969d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.user_interval;
970d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_freq != UINT_MAX)
971d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = rec->opts.user_freq;
972f9212819SFrederic Weisbecker 
9737e4ff9e3SMike Galbraith 	/*
9747e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
9757e4ff9e3SMike Galbraith 	 */
976d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.default_interval)
977d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = 0;
978d20deb64SArnaldo Carvalho de Melo 	else if (rec->opts.freq) {
979d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.freq;
9807e4ff9e3SMike Galbraith 	} else {
9813780f488SNamhyung Kim 		ui__error("frequency and count are zero, aborting\n");
98239d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
9835c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
9847e4ff9e3SMike Galbraith 	}
9857e4ff9e3SMike Galbraith 
986d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
9878fa60e1fSNamhyung Kim 
9888fa60e1fSNamhyung Kim 	perf_evlist__munmap(evsel_list);
9898fa60e1fSNamhyung Kim 	perf_evlist__close(evsel_list);
99039d17dacSArnaldo Carvalho de Melo out_free_fd:
9917e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
992d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
993d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
99439d17dacSArnaldo Carvalho de Melo 	return err;
99586470930SIngo Molnar }
996