xref: /openbmc/linux/tools/perf/builtin-record.c (revision 6233dd5efdf9e2c2da1b003cfb70307b7b2028e8)
186470930SIngo Molnar /*
286470930SIngo Molnar  * builtin-record.c
386470930SIngo Molnar  *
486470930SIngo Molnar  * Builtin record command: Record the profile of a workload
586470930SIngo Molnar  * (or a CPU, or a PID) into the perf.data output file - for
686470930SIngo Molnar  * later analysis via perf report.
786470930SIngo Molnar  */
886470930SIngo Molnar #include "builtin.h"
986470930SIngo Molnar 
1086470930SIngo Molnar #include "perf.h"
1186470930SIngo Molnar 
126122e4e4SArnaldo Carvalho de Melo #include "util/build-id.h"
1386470930SIngo Molnar #include "util/util.h"
1486470930SIngo Molnar #include "util/parse-options.h"
1586470930SIngo Molnar #include "util/parse-events.h"
1686470930SIngo Molnar 
177c6a1c65SPeter Zijlstra #include "util/header.h"
1866e274f3SFrederic Weisbecker #include "util/event.h"
19361c99a6SArnaldo Carvalho de Melo #include "util/evlist.h"
2069aad6f1SArnaldo Carvalho de Melo #include "util/evsel.h"
218f28827aSFrederic Weisbecker #include "util/debug.h"
2294c744b6SArnaldo Carvalho de Melo #include "util/session.h"
2345694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
248d06367fSArnaldo Carvalho de Melo #include "util/symbol.h"
25a12b51c4SPaul Mackerras #include "util/cpumap.h"
26fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h"
27f5fc1412SJiri Olsa #include "util/data.h"
287c6a1c65SPeter Zijlstra 
2986470930SIngo Molnar #include <unistd.h>
3086470930SIngo Molnar #include <sched.h>
31a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3286470930SIngo Molnar 
3389fe808aSIngo Molnar #ifndef HAVE_ON_EXIT_SUPPORT
3478da39faSBernhard Rosenkraenzer #ifndef ATEXIT_MAX
3578da39faSBernhard Rosenkraenzer #define ATEXIT_MAX 32
3678da39faSBernhard Rosenkraenzer #endif
3778da39faSBernhard Rosenkraenzer static int __on_exit_count = 0;
3878da39faSBernhard Rosenkraenzer typedef void (*on_exit_func_t) (int, void *);
3978da39faSBernhard Rosenkraenzer static on_exit_func_t __on_exit_funcs[ATEXIT_MAX];
4078da39faSBernhard Rosenkraenzer static void *__on_exit_args[ATEXIT_MAX];
4178da39faSBernhard Rosenkraenzer static int __exitcode = 0;
4278da39faSBernhard Rosenkraenzer static void __handle_on_exit_funcs(void);
4378da39faSBernhard Rosenkraenzer static int on_exit(on_exit_func_t function, void *arg);
4478da39faSBernhard Rosenkraenzer #define exit(x) (exit)(__exitcode = (x))
4578da39faSBernhard Rosenkraenzer 
4678da39faSBernhard Rosenkraenzer static int on_exit(on_exit_func_t function, void *arg)
4778da39faSBernhard Rosenkraenzer {
4878da39faSBernhard Rosenkraenzer 	if (__on_exit_count == ATEXIT_MAX)
4978da39faSBernhard Rosenkraenzer 		return -ENOMEM;
5078da39faSBernhard Rosenkraenzer 	else if (__on_exit_count == 0)
5178da39faSBernhard Rosenkraenzer 		atexit(__handle_on_exit_funcs);
5278da39faSBernhard Rosenkraenzer 	__on_exit_funcs[__on_exit_count] = function;
5378da39faSBernhard Rosenkraenzer 	__on_exit_args[__on_exit_count++] = arg;
5478da39faSBernhard Rosenkraenzer 	return 0;
5578da39faSBernhard Rosenkraenzer }
5678da39faSBernhard Rosenkraenzer 
5778da39faSBernhard Rosenkraenzer static void __handle_on_exit_funcs(void)
5878da39faSBernhard Rosenkraenzer {
5978da39faSBernhard Rosenkraenzer 	int i;
6078da39faSBernhard Rosenkraenzer 	for (i = 0; i < __on_exit_count; i++)
6178da39faSBernhard Rosenkraenzer 		__on_exit_funcs[i] (__exitcode, __on_exit_args[i]);
6278da39faSBernhard Rosenkraenzer }
6378da39faSBernhard Rosenkraenzer #endif
6478da39faSBernhard Rosenkraenzer 
65d20deb64SArnaldo Carvalho de Melo struct perf_record {
6645694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
67d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts	opts;
68d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
69f5fc1412SJiri Olsa 	struct perf_data_file	file;
70d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
71d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
72d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
73d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
74d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
75d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
76d20deb64SArnaldo Carvalho de Melo 	long			samples;
770f82ebc4SArnaldo Carvalho de Melo };
7886470930SIngo Molnar 
79*6233dd5eSJiri Olsa static int perf_record__write(struct perf_record *rec, void *buf, size_t size)
80f5970550SPeter Zijlstra {
81f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
82f5fc1412SJiri Olsa 
83f5970550SPeter Zijlstra 	while (size) {
84410f1786SAdrian Hunter 		ssize_t ret = write(file->fd, buf, size);
85f5970550SPeter Zijlstra 
868d3eca20SDavid Ahern 		if (ret < 0) {
874f624685SAdrian Hunter 			pr_err("failed to write perf data, error: %m\n");
888d3eca20SDavid Ahern 			return -1;
898d3eca20SDavid Ahern 		}
90f5970550SPeter Zijlstra 
91f5970550SPeter Zijlstra 		size -= ret;
92f5970550SPeter Zijlstra 		buf += ret;
93f5970550SPeter Zijlstra 
94d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written += ret;
95f5970550SPeter Zijlstra 	}
968d3eca20SDavid Ahern 
978d3eca20SDavid Ahern 	return 0;
98f5970550SPeter Zijlstra }
99f5970550SPeter Zijlstra 
10045694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
101d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
1021d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
1031d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
104234fbbf5SArnaldo Carvalho de Melo {
10545694aa7SArnaldo Carvalho de Melo 	struct perf_record *rec = container_of(tool, struct perf_record, tool);
106*6233dd5eSJiri Olsa 	return perf_record__write(rec, event, event->header.size);
107234fbbf5SArnaldo Carvalho de Melo }
108234fbbf5SArnaldo Carvalho de Melo 
1098d3eca20SDavid Ahern static int perf_record__mmap_read(struct perf_record *rec,
110d20deb64SArnaldo Carvalho de Melo 				   struct perf_mmap *md)
11186470930SIngo Molnar {
112744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
11386470930SIngo Molnar 	unsigned int old = md->prev;
114918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
11586470930SIngo Molnar 	unsigned long size;
11686470930SIngo Molnar 	void *buf;
1178d3eca20SDavid Ahern 	int rc = 0;
11886470930SIngo Molnar 
119dc82009aSArnaldo Carvalho de Melo 	if (old == head)
1208d3eca20SDavid Ahern 		return 0;
12186470930SIngo Molnar 
122d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
12386470930SIngo Molnar 
12486470930SIngo Molnar 	size = head - old;
12586470930SIngo Molnar 
12686470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
12786470930SIngo Molnar 		buf = &data[old & md->mask];
12886470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
12986470930SIngo Molnar 		old += size;
13086470930SIngo Molnar 
131*6233dd5eSJiri Olsa 		if (perf_record__write(rec, buf, size) < 0) {
1328d3eca20SDavid Ahern 			rc = -1;
1338d3eca20SDavid Ahern 			goto out;
1348d3eca20SDavid Ahern 		}
13586470930SIngo Molnar 	}
13686470930SIngo Molnar 
13786470930SIngo Molnar 	buf = &data[old & md->mask];
13886470930SIngo Molnar 	size = head - old;
13986470930SIngo Molnar 	old += size;
14086470930SIngo Molnar 
141*6233dd5eSJiri Olsa 	if (perf_record__write(rec, buf, size) < 0) {
1428d3eca20SDavid Ahern 		rc = -1;
1438d3eca20SDavid Ahern 		goto out;
1448d3eca20SDavid Ahern 	}
14586470930SIngo Molnar 
14686470930SIngo Molnar 	md->prev = old;
147115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
1488d3eca20SDavid Ahern 
1498d3eca20SDavid Ahern out:
1508d3eca20SDavid Ahern 	return rc;
15186470930SIngo Molnar }
15286470930SIngo Molnar 
15386470930SIngo Molnar static volatile int done = 0;
154f7b7c26eSPeter Zijlstra static volatile int signr = -1;
15533e49ea7SAndi Kleen static volatile int child_finished = 0;
15686470930SIngo Molnar 
15786470930SIngo Molnar static void sig_handler(int sig)
15886470930SIngo Molnar {
15933e49ea7SAndi Kleen 	if (sig == SIGCHLD)
16033e49ea7SAndi Kleen 		child_finished = 1;
16133e49ea7SAndi Kleen 
16286470930SIngo Molnar 	done = 1;
163f7b7c26eSPeter Zijlstra 	signr = sig;
164f7b7c26eSPeter Zijlstra }
165f7b7c26eSPeter Zijlstra 
1661d037ca1SIrina Tirdea static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
167f7b7c26eSPeter Zijlstra {
168d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
16933e49ea7SAndi Kleen 	int status;
17033e49ea7SAndi Kleen 
171d20deb64SArnaldo Carvalho de Melo 	if (rec->evlist->workload.pid > 0) {
17233e49ea7SAndi Kleen 		if (!child_finished)
173d20deb64SArnaldo Carvalho de Melo 			kill(rec->evlist->workload.pid, SIGTERM);
174933da83aSChris Wilson 
17533e49ea7SAndi Kleen 		wait(&status);
17633e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
177d20deb64SArnaldo Carvalho de Melo 			psignal(WTERMSIG(status), rec->progname);
17833e49ea7SAndi Kleen 	}
17933e49ea7SAndi Kleen 
18018483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
181f7b7c26eSPeter Zijlstra 		return;
182f7b7c26eSPeter Zijlstra 
183f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
18486470930SIngo Molnar }
18586470930SIngo Molnar 
1868d3eca20SDavid Ahern static int perf_record__open(struct perf_record *rec)
187dd7927f4SArnaldo Carvalho de Melo {
18856e52e85SArnaldo Carvalho de Melo 	char msg[512];
1896a4bb04cSJiri Olsa 	struct perf_evsel *pos;
190d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
191d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
192d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
1938d3eca20SDavid Ahern 	int rc = 0;
194dd7927f4SArnaldo Carvalho de Melo 
195f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
196cac21425SJiri Olsa 
197dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
1983da297a6SIngo Molnar try_again:
1996a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
20056e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
2013da297a6SIngo Molnar 				if (verbose)
202c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
2033da297a6SIngo Molnar 				goto try_again;
2043da297a6SIngo Molnar 			}
205ca6a4258SDavid Ahern 
20656e52e85SArnaldo Carvalho de Melo 			rc = -errno;
20756e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
20856e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
20956e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
2108d3eca20SDavid Ahern 			goto out;
2117c6a1c65SPeter Zijlstra 		}
2127c6a1c65SPeter Zijlstra 	}
2137c6a1c65SPeter Zijlstra 
2141491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
2150a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2160a102479SFrederic Weisbecker 			strerror(errno));
2178d3eca20SDavid Ahern 		rc = -1;
2188d3eca20SDavid Ahern 		goto out;
2190a102479SFrederic Weisbecker 	}
2200a102479SFrederic Weisbecker 
22118e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
2228d3eca20SDavid Ahern 		if (errno == EPERM) {
2238d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
22418e60939SNelson Elhage 			       "Consider increasing "
22518e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
22618e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
22718e60939SNelson Elhage 			       "(current value: %d)\n", opts->mmap_pages);
2288d3eca20SDavid Ahern 			rc = -errno;
2298d3eca20SDavid Ahern 		} else {
2308d3eca20SDavid Ahern 			pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
2318d3eca20SDavid Ahern 			rc = -errno;
2328d3eca20SDavid Ahern 		}
2338d3eca20SDavid Ahern 		goto out;
23418e60939SNelson Elhage 	}
2350a27d7f9SArnaldo Carvalho de Melo 
236a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
2377b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
2388d3eca20SDavid Ahern out:
2398d3eca20SDavid Ahern 	return rc;
240a91e5431SArnaldo Carvalho de Melo }
241a91e5431SArnaldo Carvalho de Melo 
242d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
2436122e4e4SArnaldo Carvalho de Melo {
244f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
245f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
2467ab75cffSDavid Ahern 	u64 start = session->header.data_offset;
2476122e4e4SArnaldo Carvalho de Melo 
248f5fc1412SJiri Olsa 	u64 size = lseek(file->fd, 0, SEEK_CUR);
2499f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2509f591fd7SArnaldo Carvalho de Melo 		return 0;
2519f591fd7SArnaldo Carvalho de Melo 
2527ab75cffSDavid Ahern 	return __perf_session__process_events(session, start,
2537ab75cffSDavid Ahern 					      size - start,
2546122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
2556122e4e4SArnaldo Carvalho de Melo }
2566122e4e4SArnaldo Carvalho de Melo 
2578d3eca20SDavid Ahern static void perf_record__exit(int status, void *arg)
258f5970550SPeter Zijlstra {
259d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
260f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
261f5970550SPeter Zijlstra 
2628d3eca20SDavid Ahern 	if (status != 0)
2638d3eca20SDavid Ahern 		return;
2648d3eca20SDavid Ahern 
265f5fc1412SJiri Olsa 	if (!file->is_pipe) {
266d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
267d20deb64SArnaldo Carvalho de Melo 
268d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
269d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
270d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
271f5fc1412SJiri Olsa 					   file->fd, true);
272d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
273d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
274d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
275c7929e47STom Zanussi 	}
276f5970550SPeter Zijlstra }
277f5970550SPeter Zijlstra 
2788115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
279a1645ce1SZhang, Yanmin {
280a1645ce1SZhang, Yanmin 	int err;
28145694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
282a1645ce1SZhang, Yanmin 	/*
283a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
284a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
285a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
286a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
287a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
288a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
289a1645ce1SZhang, Yanmin 	 */
29045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
291743eb868SArnaldo Carvalho de Melo 					     machine);
292a1645ce1SZhang, Yanmin 	if (err < 0)
293a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
29423346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
295a1645ce1SZhang, Yanmin 
296a1645ce1SZhang, Yanmin 	/*
297a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
298a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
299a1645ce1SZhang, Yanmin 	 */
30045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
301743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
302a1645ce1SZhang, Yanmin 	if (err < 0)
30345694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
304743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
305a1645ce1SZhang, Yanmin 	if (err < 0)
306a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
30723346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
308a1645ce1SZhang, Yanmin }
309a1645ce1SZhang, Yanmin 
31098402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
31198402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
31298402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
31398402807SFrederic Weisbecker };
31498402807SFrederic Weisbecker 
3158d3eca20SDavid Ahern static int perf_record__mmap_read_all(struct perf_record *rec)
31698402807SFrederic Weisbecker {
3170e2e63ddSPeter Zijlstra 	int i;
3188d3eca20SDavid Ahern 	int rc = 0;
31998402807SFrederic Weisbecker 
320d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
3218d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
3228d3eca20SDavid Ahern 			if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
3238d3eca20SDavid Ahern 				rc = -1;
3248d3eca20SDavid Ahern 				goto out;
3258d3eca20SDavid Ahern 			}
3268d3eca20SDavid Ahern 		}
32798402807SFrederic Weisbecker 	}
32898402807SFrederic Weisbecker 
3292eeaaa09SStephane Eranian 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
330*6233dd5eSJiri Olsa 		rc = perf_record__write(rec, &finished_round_event,
3318d3eca20SDavid Ahern 					sizeof(finished_round_event));
3328d3eca20SDavid Ahern 
3338d3eca20SDavid Ahern out:
3348d3eca20SDavid Ahern 	return rc;
33598402807SFrederic Weisbecker }
33698402807SFrederic Weisbecker 
33757706abcSDavid Ahern static void perf_record__init_features(struct perf_record *rec)
33857706abcSDavid Ahern {
33957706abcSDavid Ahern 	struct perf_evlist *evsel_list = rec->evlist;
34057706abcSDavid Ahern 	struct perf_session *session = rec->session;
34157706abcSDavid Ahern 	int feat;
34257706abcSDavid Ahern 
34357706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
34457706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
34557706abcSDavid Ahern 
34657706abcSDavid Ahern 	if (rec->no_buildid)
34757706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
34857706abcSDavid Ahern 
34957706abcSDavid Ahern 	if (!have_tracepoints(&evsel_list->entries))
35057706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
35157706abcSDavid Ahern 
35257706abcSDavid Ahern 	if (!rec->opts.branch_stack)
35357706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
35457706abcSDavid Ahern }
35557706abcSDavid Ahern 
356d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
35786470930SIngo Molnar {
35857706abcSDavid Ahern 	int err;
3598b412664SPeter Zijlstra 	unsigned long waking = 0;
36046be604bSZhang, Yanmin 	const bool forks = argc > 0;
36123346f21SArnaldo Carvalho de Melo 	struct machine *machine;
36245694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
363d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
364d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
365f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
366d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3672711926aSJiri Olsa 	bool disabled = false;
36886470930SIngo Molnar 
369d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
37033e49ea7SAndi Kleen 
371d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
372f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
373f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
37418483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
375804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
376f5970550SPeter Zijlstra 
377f5fc1412SJiri Olsa 	session = perf_session__new(file, false, NULL);
37894c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
379a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
380a9a70bbcSArnaldo Carvalho de Melo 		return -1;
381a9a70bbcSArnaldo Carvalho de Melo 	}
382a9a70bbcSArnaldo Carvalho de Melo 
383d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
384d20deb64SArnaldo Carvalho de Melo 
38557706abcSDavid Ahern 	perf_record__init_features(rec);
386330aa675SStephane Eranian 
387d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
3886ef73ec4SNamhyung Kim 		err = perf_evlist__prepare_workload(evsel_list, &opts->target,
389f5fc1412SJiri Olsa 						    argv, file->is_pipe,
39055e162eaSNamhyung Kim 						    true);
39135b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
39235b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
39335b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
394856e9660SPeter Zijlstra 		}
395856e9660SPeter Zijlstra 	}
396856e9660SPeter Zijlstra 
3978d3eca20SDavid Ahern 	if (perf_record__open(rec) != 0) {
3988d3eca20SDavid Ahern 		err = -1;
3998d3eca20SDavid Ahern 		goto out_delete_session;
4008d3eca20SDavid Ahern 	}
40186470930SIngo Molnar 
402a8bb559bSNamhyung Kim 	if (!evsel_list->nr_groups)
403a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
404a8bb559bSNamhyung Kim 
405712a4b60SArnaldo Carvalho de Melo 	/*
406d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
407712a4b60SArnaldo Carvalho de Melo 	 */
408d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
409712a4b60SArnaldo Carvalho de Melo 
410f5fc1412SJiri Olsa 	if (file->is_pipe) {
411f5fc1412SJiri Olsa 		err = perf_header__write_pipe(file->fd);
412529870e3STom Zanussi 		if (err < 0)
4138d3eca20SDavid Ahern 			goto out_delete_session;
414563aecb2SJiri Olsa 	} else {
415a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
416f5fc1412SJiri Olsa 						 file->fd, false);
417d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
4188d3eca20SDavid Ahern 			goto out_delete_session;
419d5eed904SArnaldo Carvalho de Melo 	}
4207c6a1c65SPeter Zijlstra 
421d3665498SDavid Ahern 	if (!rec->no_buildid
422e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
423d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
424e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
4258d3eca20SDavid Ahern 		err = -1;
4268d3eca20SDavid Ahern 		goto out_delete_session;
427e20960c0SRobert Richter 	}
428e20960c0SRobert Richter 
42934ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
430743eb868SArnaldo Carvalho de Melo 
431f5fc1412SJiri Olsa 	if (file->is_pipe) {
43245694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
433a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
4342c46dbb5STom Zanussi 		if (err < 0) {
4352c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
4368d3eca20SDavid Ahern 			goto out_delete_session;
4372c46dbb5STom Zanussi 		}
438cd19a035STom Zanussi 
439361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
44063e0c771STom Zanussi 			/*
44163e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
44263e0c771STom Zanussi 			 * there were no tracepoints so its not really
44363e0c771STom Zanussi 			 * an error, just that we don't need to
44463e0c771STom Zanussi 			 * synthesize anything.  We really have to
44563e0c771STom Zanussi 			 * return this more properly and also
44663e0c771STom Zanussi 			 * propagate errors that now are calling die()
44763e0c771STom Zanussi 			 */
448f5fc1412SJiri Olsa 			err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list,
449743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
45063e0c771STom Zanussi 			if (err <= 0) {
45163e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
4528d3eca20SDavid Ahern 				goto out_delete_session;
45363e0c771STom Zanussi 			}
454f34b9001SDavid Ahern 			rec->bytes_written += err;
4552c46dbb5STom Zanussi 		}
45663e0c771STom Zanussi 	}
4572c46dbb5STom Zanussi 
45845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
459743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
46070162138SArnaldo Carvalho de Melo 	if (err < 0)
46145694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
462743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
463c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
464c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
465c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
466c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
46756b03f3cSArnaldo Carvalho de Melo 
46845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
469743eb868SArnaldo Carvalho de Melo 					     machine);
470c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
471c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
472c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
473c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
474c1a3a4b9SArnaldo Carvalho de Melo 
4757e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
476876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
4777e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
4787e383de4SArnaldo Carvalho de Melo 	}
479b7cece76SArnaldo Carvalho de Melo 
480a33fbd56SArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, evsel_list->threads,
48158d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
4828d3eca20SDavid Ahern 	if (err != 0)
4838d3eca20SDavid Ahern 		goto out_delete_session;
4848d3eca20SDavid Ahern 
485d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
48686470930SIngo Molnar 		struct sched_param param;
48786470930SIngo Molnar 
488d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
48986470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
4906beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
4918d3eca20SDavid Ahern 			err = -1;
4928d3eca20SDavid Ahern 			goto out_delete_session;
49386470930SIngo Molnar 		}
49486470930SIngo Molnar 	}
49586470930SIngo Molnar 
496774cb499SJiri Olsa 	/*
497774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
498774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
499774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
500774cb499SJiri Olsa 	 */
501602ad878SArnaldo Carvalho de Melo 	if (!target__none(&opts->target))
502764e16a3SDavid Ahern 		perf_evlist__enable(evsel_list);
503764e16a3SDavid Ahern 
504856e9660SPeter Zijlstra 	/*
505856e9660SPeter Zijlstra 	 * Let the child rip
506856e9660SPeter Zijlstra 	 */
507d4db3f16SArnaldo Carvalho de Melo 	if (forks)
50835b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
509856e9660SPeter Zijlstra 
510649c48a9SPeter Zijlstra 	for (;;) {
511d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
51286470930SIngo Molnar 
5138d3eca20SDavid Ahern 		if (perf_record__mmap_read_all(rec) < 0) {
5148d3eca20SDavid Ahern 			err = -1;
5158d3eca20SDavid Ahern 			goto out_delete_session;
5168d3eca20SDavid Ahern 		}
51786470930SIngo Molnar 
518d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
519649c48a9SPeter Zijlstra 			if (done)
520649c48a9SPeter Zijlstra 				break;
5215c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
5228b412664SPeter Zijlstra 			waking++;
5238b412664SPeter Zijlstra 		}
5248b412664SPeter Zijlstra 
525774cb499SJiri Olsa 		/*
526774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
527774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
528774cb499SJiri Olsa 		 * disable events in this case.
529774cb499SJiri Olsa 		 */
530602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
5314152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
5322711926aSJiri Olsa 			disabled = true;
5332711926aSJiri Olsa 		}
5348b412664SPeter Zijlstra 	}
5358b412664SPeter Zijlstra 
53618483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
537b44308f5SArnaldo Carvalho de Melo 		return 0;
538b44308f5SArnaldo Carvalho de Melo 
5398b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
54086470930SIngo Molnar 
54186470930SIngo Molnar 	/*
54286470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
54386470930SIngo Molnar 	 */
54486470930SIngo Molnar 	fprintf(stderr,
5459486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
546d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
5476a4d98d7SJiri Olsa 		file->path,
548d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
54986470930SIngo Molnar 
55086470930SIngo Molnar 	return 0;
55139d17dacSArnaldo Carvalho de Melo 
55239d17dacSArnaldo Carvalho de Melo out_delete_session:
55339d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
55439d17dacSArnaldo Carvalho de Melo 	return err;
55586470930SIngo Molnar }
55686470930SIngo Molnar 
557bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
558bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
559bdfebd84SRoberto Agostino Vitillo 
560bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
561bdfebd84SRoberto Agostino Vitillo 
562bdfebd84SRoberto Agostino Vitillo struct branch_mode {
563bdfebd84SRoberto Agostino Vitillo 	const char *name;
564bdfebd84SRoberto Agostino Vitillo 	int mode;
565bdfebd84SRoberto Agostino Vitillo };
566bdfebd84SRoberto Agostino Vitillo 
567bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
568bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
569bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
570bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
571bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
572bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
573bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
574bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
5750126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
5760126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
5770126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
578bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
579bdfebd84SRoberto Agostino Vitillo };
580bdfebd84SRoberto Agostino Vitillo 
581bdfebd84SRoberto Agostino Vitillo static int
582a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
583bdfebd84SRoberto Agostino Vitillo {
584bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
585bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
586bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
587bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
588bdfebd84SRoberto Agostino Vitillo 
589bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
590bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
591a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
592bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
593bdfebd84SRoberto Agostino Vitillo 
594a5aabdacSStephane Eranian 	if (unset)
595a5aabdacSStephane Eranian 		return 0;
596bdfebd84SRoberto Agostino Vitillo 
597a5aabdacSStephane Eranian 	/*
598a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
599a5aabdacSStephane Eranian 	 */
600a5aabdacSStephane Eranian 	if (*mode)
601a5aabdacSStephane Eranian 		return -1;
602a5aabdacSStephane Eranian 
603a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
604a5aabdacSStephane Eranian 	if (str) {
605bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
606bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
607bdfebd84SRoberto Agostino Vitillo 		if (!s)
608bdfebd84SRoberto Agostino Vitillo 			return -1;
609bdfebd84SRoberto Agostino Vitillo 
610bdfebd84SRoberto Agostino Vitillo 		for (;;) {
611bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
612bdfebd84SRoberto Agostino Vitillo 			if (p)
613bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
614bdfebd84SRoberto Agostino Vitillo 
615bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
616bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
617bdfebd84SRoberto Agostino Vitillo 					break;
618bdfebd84SRoberto Agostino Vitillo 			}
619a5aabdacSStephane Eranian 			if (!br->name) {
620a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
621a5aabdacSStephane Eranian 					    " check man page\n", s);
622bdfebd84SRoberto Agostino Vitillo 				goto error;
623a5aabdacSStephane Eranian 			}
624bdfebd84SRoberto Agostino Vitillo 
625bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
626bdfebd84SRoberto Agostino Vitillo 
627bdfebd84SRoberto Agostino Vitillo 			if (!p)
628bdfebd84SRoberto Agostino Vitillo 				break;
629bdfebd84SRoberto Agostino Vitillo 
630bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
631bdfebd84SRoberto Agostino Vitillo 		}
632a5aabdacSStephane Eranian 	}
633bdfebd84SRoberto Agostino Vitillo 	ret = 0;
634bdfebd84SRoberto Agostino Vitillo 
635a5aabdacSStephane Eranian 	/* default to any branch */
636bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
637a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
638bdfebd84SRoberto Agostino Vitillo 	}
639bdfebd84SRoberto Agostino Vitillo error:
640bdfebd84SRoberto Agostino Vitillo 	free(os);
641bdfebd84SRoberto Agostino Vitillo 	return ret;
642bdfebd84SRoberto Agostino Vitillo }
643bdfebd84SRoberto Agostino Vitillo 
64489fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
64526d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size)
64626d33022SJiri Olsa {
64726d33022SJiri Olsa 	char *endptr;
64826d33022SJiri Olsa 	unsigned long size;
64926d33022SJiri Olsa 	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
65026d33022SJiri Olsa 
65126d33022SJiri Olsa 	size = strtoul(str, &endptr, 0);
65226d33022SJiri Olsa 
65326d33022SJiri Olsa 	do {
65426d33022SJiri Olsa 		if (*endptr)
65526d33022SJiri Olsa 			break;
65626d33022SJiri Olsa 
65726d33022SJiri Olsa 		size = round_up(size, sizeof(u64));
65826d33022SJiri Olsa 		if (!size || size > max_size)
65926d33022SJiri Olsa 			break;
66026d33022SJiri Olsa 
66126d33022SJiri Olsa 		*_size = size;
66226d33022SJiri Olsa 		return 0;
66326d33022SJiri Olsa 
66426d33022SJiri Olsa 	} while (0);
66526d33022SJiri Olsa 
66626d33022SJiri Olsa 	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
66726d33022SJiri Olsa 	       max_size, str);
66826d33022SJiri Olsa 	return -1;
66926d33022SJiri Olsa }
67089fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */
67126d33022SJiri Olsa 
67209b0fd45SJiri Olsa int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
67326d33022SJiri Olsa {
67426d33022SJiri Olsa 	char *tok, *name, *saveptr = NULL;
67526d33022SJiri Olsa 	char *buf;
67626d33022SJiri Olsa 	int ret = -1;
67726d33022SJiri Olsa 
67826d33022SJiri Olsa 	/* We need buffer that we know we can write to. */
67926d33022SJiri Olsa 	buf = malloc(strlen(arg) + 1);
68026d33022SJiri Olsa 	if (!buf)
68126d33022SJiri Olsa 		return -ENOMEM;
68226d33022SJiri Olsa 
68326d33022SJiri Olsa 	strcpy(buf, arg);
68426d33022SJiri Olsa 
68526d33022SJiri Olsa 	tok = strtok_r((char *)buf, ",", &saveptr);
68626d33022SJiri Olsa 	name = tok ? : (char *)buf;
68726d33022SJiri Olsa 
68826d33022SJiri Olsa 	do {
68926d33022SJiri Olsa 		/* Framepointer style */
69026d33022SJiri Olsa 		if (!strncmp(name, "fp", sizeof("fp"))) {
69126d33022SJiri Olsa 			if (!strtok_r(NULL, ",", &saveptr)) {
692c5ff78c3SArnaldo Carvalho de Melo 				opts->call_graph = CALLCHAIN_FP;
69326d33022SJiri Olsa 				ret = 0;
69426d33022SJiri Olsa 			} else
69526d33022SJiri Olsa 				pr_err("callchain: No more arguments "
69626d33022SJiri Olsa 				       "needed for -g fp\n");
69726d33022SJiri Olsa 			break;
69826d33022SJiri Olsa 
69989fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
70026d33022SJiri Olsa 		/* Dwarf style */
70126d33022SJiri Olsa 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
70261eaa3beSArnaldo Carvalho de Melo 			const unsigned long default_stack_dump_size = 8192;
70361eaa3beSArnaldo Carvalho de Melo 
70426d33022SJiri Olsa 			ret = 0;
705c5ff78c3SArnaldo Carvalho de Melo 			opts->call_graph = CALLCHAIN_DWARF;
706c5ff78c3SArnaldo Carvalho de Melo 			opts->stack_dump_size = default_stack_dump_size;
70726d33022SJiri Olsa 
70826d33022SJiri Olsa 			tok = strtok_r(NULL, ",", &saveptr);
70926d33022SJiri Olsa 			if (tok) {
71026d33022SJiri Olsa 				unsigned long size = 0;
71126d33022SJiri Olsa 
71226d33022SJiri Olsa 				ret = get_stack_size(tok, &size);
713c5ff78c3SArnaldo Carvalho de Melo 				opts->stack_dump_size = size;
71426d33022SJiri Olsa 			}
71589fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */
71626d33022SJiri Olsa 		} else {
71709b0fd45SJiri Olsa 			pr_err("callchain: Unknown --call-graph option "
71826d33022SJiri Olsa 			       "value: %s\n", arg);
71926d33022SJiri Olsa 			break;
72026d33022SJiri Olsa 		}
72126d33022SJiri Olsa 
72226d33022SJiri Olsa 	} while (0);
72326d33022SJiri Olsa 
72426d33022SJiri Olsa 	free(buf);
72509b0fd45SJiri Olsa 	return ret;
72609b0fd45SJiri Olsa }
72726d33022SJiri Olsa 
72809b0fd45SJiri Olsa static void callchain_debug(struct perf_record_opts *opts)
72909b0fd45SJiri Olsa {
730c5ff78c3SArnaldo Carvalho de Melo 	pr_debug("callchain: type %d\n", opts->call_graph);
73126d33022SJiri Olsa 
73209b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_DWARF)
73309b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
73409b0fd45SJiri Olsa 			 opts->stack_dump_size);
73509b0fd45SJiri Olsa }
73609b0fd45SJiri Olsa 
73709b0fd45SJiri Olsa int record_parse_callchain_opt(const struct option *opt,
73809b0fd45SJiri Olsa 			       const char *arg,
73909b0fd45SJiri Olsa 			       int unset)
74009b0fd45SJiri Olsa {
74109b0fd45SJiri Olsa 	struct perf_record_opts *opts = opt->value;
74209b0fd45SJiri Olsa 	int ret;
74309b0fd45SJiri Olsa 
74409b0fd45SJiri Olsa 	/* --no-call-graph */
74509b0fd45SJiri Olsa 	if (unset) {
74609b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_NONE;
74709b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
74809b0fd45SJiri Olsa 		return 0;
74909b0fd45SJiri Olsa 	}
75009b0fd45SJiri Olsa 
75109b0fd45SJiri Olsa 	ret = record_parse_callchain(arg, opts);
75209b0fd45SJiri Olsa 	if (!ret)
75309b0fd45SJiri Olsa 		callchain_debug(opts);
75409b0fd45SJiri Olsa 
75526d33022SJiri Olsa 	return ret;
75626d33022SJiri Olsa }
75726d33022SJiri Olsa 
75809b0fd45SJiri Olsa int record_callchain_opt(const struct option *opt,
75909b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
76009b0fd45SJiri Olsa 			 int unset __maybe_unused)
76109b0fd45SJiri Olsa {
76209b0fd45SJiri Olsa 	struct perf_record_opts *opts = opt->value;
76309b0fd45SJiri Olsa 
76409b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_NONE)
76509b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_FP;
76609b0fd45SJiri Olsa 
76709b0fd45SJiri Olsa 	callchain_debug(opts);
76809b0fd45SJiri Olsa 	return 0;
76909b0fd45SJiri Olsa }
77009b0fd45SJiri Olsa 
77186470930SIngo Molnar static const char * const record_usage[] = {
77286470930SIngo Molnar 	"perf record [<options>] [<command>]",
77386470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
77486470930SIngo Molnar 	NULL
77586470930SIngo Molnar };
77686470930SIngo Molnar 
777d20deb64SArnaldo Carvalho de Melo /*
778d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
779d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
780d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
781d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
782d20deb64SArnaldo Carvalho de Melo  *
783d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
784d20deb64SArnaldo Carvalho de Melo  *
785d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
786d20deb64SArnaldo Carvalho de Melo  */
787d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
788d20deb64SArnaldo Carvalho de Melo 	.opts = {
789d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
790d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
791d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
792447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
793d1cb9fceSNamhyung Kim 		.target		     = {
794d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
7953aa5939dSAdrian Hunter 			.default_per_cpu = true,
796d1cb9fceSNamhyung Kim 		},
797d20deb64SArnaldo Carvalho de Melo 	},
798d20deb64SArnaldo Carvalho de Melo };
7997865e817SFrederic Weisbecker 
80009b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
80161eaa3beSArnaldo Carvalho de Melo 
80289fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
80309b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
80461eaa3beSArnaldo Carvalho de Melo #else
80509b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp";
80661eaa3beSArnaldo Carvalho de Melo #endif
80761eaa3beSArnaldo Carvalho de Melo 
808d20deb64SArnaldo Carvalho de Melo /*
809d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
810d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
811d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
812d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
813d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
814d20deb64SArnaldo Carvalho de Melo  */
815bca647aaSTom Zanussi const struct option record_options[] = {
816d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
81786470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
818f120f9d5SJiri Olsa 		     parse_events_option),
819d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
820c171b552SLi Zefan 		     "event filter", parse_filter),
821bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
822d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
823bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
824d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
825d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
82686470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
827d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
828acac03faSKirill Smelkov 		    "collect data without buffering"),
829d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
830daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
831bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
83286470930SIngo Molnar 			    "system-wide collection from all CPUs"),
833bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
834c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
835d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
836f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
83786470930SIngo Molnar 		    "output file name"),
83869e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
83969e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
8402e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
841d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
842994a1f78SJiri Olsa 	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
843994a1f78SJiri Olsa 		     "number of mmap data pages",
844994a1f78SJiri Olsa 		     perf_evlist__parse_mmap_pages),
845d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
84643bece79SLin Ming 		    "put the counters into a counter group"),
84709b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
84809b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
84909b0fd45SJiri Olsa 			   &record_callchain_opt),
85009b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
85175d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
85209b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
853c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8543da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
855b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
856d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
857649c48a9SPeter Zijlstra 		    "per thread counts"),
858d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8594bba828dSAnton Blanchard 		    "Sample addresses"),
860d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8613e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
862d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
863649c48a9SPeter Zijlstra 		    "don't sample"),
864d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
865a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
866d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
867baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
868d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
869023695d9SStephane Eranian 		     "monitor event in cgroup name only",
870023695d9SStephane Eranian 		     parse_cgroups),
871bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
872bea03405SNamhyung Kim 		   "user to profile"),
873a5aabdacSStephane Eranian 
874a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
875a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
876a5aabdacSStephane Eranian 		     parse_branch_stack),
877a5aabdacSStephane Eranian 
878a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
879a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
880bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
88105484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
88205484298SAndi Kleen 		    "sample by weight (on special events only)"),
883475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
884475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
8853aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
8863aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
88786470930SIngo Molnar 	OPT_END()
88886470930SIngo Molnar };
88986470930SIngo Molnar 
8901d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
89186470930SIngo Molnar {
89269aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
893d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
894d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
89516ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
89686470930SIngo Molnar 
897334fe7a3SNamhyung Kim 	evsel_list = perf_evlist__new();
898361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
899361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
900361c99a6SArnaldo Carvalho de Melo 
901d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
902d20deb64SArnaldo Carvalho de Melo 
903bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
904a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
905602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
906bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
90786470930SIngo Molnar 
908bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
9093780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
910023695d9SStephane Eranian 			  " system-wide mode\n");
911023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
912023695d9SStephane Eranian 	}
913023695d9SStephane Eranian 
914655000e7SArnaldo Carvalho de Melo 	symbol__init();
915baa2f6ceSArnaldo Carvalho de Melo 
916ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
917646aaea6SArnaldo Carvalho de Melo 		pr_warning(
918646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
919ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
920646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
921646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
922646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
923646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
924646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
925ec80fde7SArnaldo Carvalho de Melo 
926d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
927a1ac1d3cSStephane Eranian 		disable_buildid_cache();
928655000e7SArnaldo Carvalho de Melo 
929361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
930361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
93169aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
93269aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
933bbd36e5eSPeter Zijlstra 	}
93486470930SIngo Molnar 
93569e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
93669e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
93769e7e5b0SAdrian Hunter 
938602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
93916ad2ffbSNamhyung Kim 	if (err) {
940602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
94116ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
94216ad2ffbSNamhyung Kim 	}
9434bd0f2d2SNamhyung Kim 
944602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
94516ad2ffbSNamhyung Kim 	if (err) {
94616ad2ffbSNamhyung Kim 		int saved_errno = errno;
94716ad2ffbSNamhyung Kim 
948602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9493780f488SNamhyung Kim 		ui__error("%s", errbuf);
95016ad2ffbSNamhyung Kim 
95116ad2ffbSNamhyung Kim 		err = -saved_errno;
9528fa60e1fSNamhyung Kim 		goto out_symbol_exit;
95316ad2ffbSNamhyung Kim 	}
9540d37aa34SArnaldo Carvalho de Melo 
95516ad2ffbSNamhyung Kim 	err = -ENOMEM;
956b809ac10SNamhyung Kim 	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
957dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
95869aad6f1SArnaldo Carvalho de Melo 
959714647bdSJiri Olsa 	if (perf_record_opts__config(&rec->opts)) {
96039d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
9615c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
9627e4ff9e3SMike Galbraith 	}
9637e4ff9e3SMike Galbraith 
964d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
9658fa60e1fSNamhyung Kim 
9668fa60e1fSNamhyung Kim 	perf_evlist__munmap(evsel_list);
9678fa60e1fSNamhyung Kim 	perf_evlist__close(evsel_list);
96839d17dacSArnaldo Carvalho de Melo out_free_fd:
9697e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
970d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
971d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
97239d17dacSArnaldo Carvalho de Melo 	return err;
97386470930SIngo Molnar }
974