xref: /openbmc/linux/tools/perf/builtin-record.c (revision cf8b2e6941091d2034f19c1799f8d6407bd565a4)
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*cf8b2e69SArnaldo Carvalho de Melo static int perf_record__write(struct perf_record *rec, void *bf, size_t size)
80f5970550SPeter Zijlstra {
81*cf8b2e69SArnaldo Carvalho de Melo 	if (perf_data_file__write(rec->session->file, bf, size) < 0) {
824f624685SAdrian Hunter 		pr_err("failed to write perf data, error: %m\n");
838d3eca20SDavid Ahern 		return -1;
848d3eca20SDavid Ahern 	}
85f5970550SPeter Zijlstra 
86*cf8b2e69SArnaldo Carvalho de Melo 	rec->bytes_written += size;
878d3eca20SDavid Ahern 	return 0;
88f5970550SPeter Zijlstra }
89f5970550SPeter Zijlstra 
9045694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
91d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
921d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
931d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
94234fbbf5SArnaldo Carvalho de Melo {
9545694aa7SArnaldo Carvalho de Melo 	struct perf_record *rec = container_of(tool, struct perf_record, tool);
966233dd5eSJiri Olsa 	return perf_record__write(rec, event, event->header.size);
97234fbbf5SArnaldo Carvalho de Melo }
98234fbbf5SArnaldo Carvalho de Melo 
998d3eca20SDavid Ahern static int perf_record__mmap_read(struct perf_record *rec,
100d20deb64SArnaldo Carvalho de Melo 				   struct perf_mmap *md)
10186470930SIngo Molnar {
102744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
10386470930SIngo Molnar 	unsigned int old = md->prev;
104918512b4SJiri Olsa 	unsigned char *data = md->base + page_size;
10586470930SIngo Molnar 	unsigned long size;
10686470930SIngo Molnar 	void *buf;
1078d3eca20SDavid Ahern 	int rc = 0;
10886470930SIngo Molnar 
109dc82009aSArnaldo Carvalho de Melo 	if (old == head)
1108d3eca20SDavid Ahern 		return 0;
11186470930SIngo Molnar 
112d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
11386470930SIngo Molnar 
11486470930SIngo Molnar 	size = head - old;
11586470930SIngo Molnar 
11686470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
11786470930SIngo Molnar 		buf = &data[old & md->mask];
11886470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
11986470930SIngo Molnar 		old += size;
12086470930SIngo Molnar 
1216233dd5eSJiri Olsa 		if (perf_record__write(rec, buf, size) < 0) {
1228d3eca20SDavid Ahern 			rc = -1;
1238d3eca20SDavid Ahern 			goto out;
1248d3eca20SDavid Ahern 		}
12586470930SIngo Molnar 	}
12686470930SIngo Molnar 
12786470930SIngo Molnar 	buf = &data[old & md->mask];
12886470930SIngo Molnar 	size = head - old;
12986470930SIngo Molnar 	old += size;
13086470930SIngo Molnar 
1316233dd5eSJiri Olsa 	if (perf_record__write(rec, buf, size) < 0) {
1328d3eca20SDavid Ahern 		rc = -1;
1338d3eca20SDavid Ahern 		goto out;
1348d3eca20SDavid Ahern 	}
13586470930SIngo Molnar 
13686470930SIngo Molnar 	md->prev = old;
137115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
1388d3eca20SDavid Ahern 
1398d3eca20SDavid Ahern out:
1408d3eca20SDavid Ahern 	return rc;
14186470930SIngo Molnar }
14286470930SIngo Molnar 
14386470930SIngo Molnar static volatile int done = 0;
144f7b7c26eSPeter Zijlstra static volatile int signr = -1;
14533e49ea7SAndi Kleen static volatile int child_finished = 0;
14686470930SIngo Molnar 
14786470930SIngo Molnar static void sig_handler(int sig)
14886470930SIngo Molnar {
14933e49ea7SAndi Kleen 	if (sig == SIGCHLD)
15033e49ea7SAndi Kleen 		child_finished = 1;
15133e49ea7SAndi Kleen 
15286470930SIngo Molnar 	done = 1;
153f7b7c26eSPeter Zijlstra 	signr = sig;
154f7b7c26eSPeter Zijlstra }
155f7b7c26eSPeter Zijlstra 
1561d037ca1SIrina Tirdea static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
157f7b7c26eSPeter Zijlstra {
158d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
15933e49ea7SAndi Kleen 	int status;
16033e49ea7SAndi Kleen 
161d20deb64SArnaldo Carvalho de Melo 	if (rec->evlist->workload.pid > 0) {
16233e49ea7SAndi Kleen 		if (!child_finished)
163d20deb64SArnaldo Carvalho de Melo 			kill(rec->evlist->workload.pid, SIGTERM);
164933da83aSChris Wilson 
16533e49ea7SAndi Kleen 		wait(&status);
16633e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
167d20deb64SArnaldo Carvalho de Melo 			psignal(WTERMSIG(status), rec->progname);
16833e49ea7SAndi Kleen 	}
16933e49ea7SAndi Kleen 
17018483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
171f7b7c26eSPeter Zijlstra 		return;
172f7b7c26eSPeter Zijlstra 
173f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
17486470930SIngo Molnar }
17586470930SIngo Molnar 
1768d3eca20SDavid Ahern static int perf_record__open(struct perf_record *rec)
177dd7927f4SArnaldo Carvalho de Melo {
17856e52e85SArnaldo Carvalho de Melo 	char msg[512];
1796a4bb04cSJiri Olsa 	struct perf_evsel *pos;
180d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
181d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
182d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
1838d3eca20SDavid Ahern 	int rc = 0;
184dd7927f4SArnaldo Carvalho de Melo 
185f77a9518SArnaldo Carvalho de Melo 	perf_evlist__config(evlist, opts);
186cac21425SJiri Olsa 
187dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
1883da297a6SIngo Molnar try_again:
1896a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
19056e52e85SArnaldo Carvalho de Melo 			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
1913da297a6SIngo Molnar 				if (verbose)
192c0a54341SArnaldo Carvalho de Melo 					ui__warning("%s\n", msg);
1933da297a6SIngo Molnar 				goto try_again;
1943da297a6SIngo Molnar 			}
195ca6a4258SDavid Ahern 
19656e52e85SArnaldo Carvalho de Melo 			rc = -errno;
19756e52e85SArnaldo Carvalho de Melo 			perf_evsel__open_strerror(pos, &opts->target,
19856e52e85SArnaldo Carvalho de Melo 						  errno, msg, sizeof(msg));
19956e52e85SArnaldo Carvalho de Melo 			ui__error("%s\n", msg);
2008d3eca20SDavid Ahern 			goto out;
2017c6a1c65SPeter Zijlstra 		}
2027c6a1c65SPeter Zijlstra 	}
2037c6a1c65SPeter Zijlstra 
2041491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
2050a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2060a102479SFrederic Weisbecker 			strerror(errno));
2078d3eca20SDavid Ahern 		rc = -1;
2088d3eca20SDavid Ahern 		goto out;
2090a102479SFrederic Weisbecker 	}
2100a102479SFrederic Weisbecker 
21118e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
2128d3eca20SDavid Ahern 		if (errno == EPERM) {
2138d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
21418e60939SNelson Elhage 			       "Consider increasing "
21518e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
21618e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
21753653d70SAdrian Hunter 			       "(current value: %u)\n", opts->mmap_pages);
2188d3eca20SDavid Ahern 			rc = -errno;
2198d3eca20SDavid Ahern 		} else {
2208d3eca20SDavid Ahern 			pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
2218d3eca20SDavid Ahern 			rc = -errno;
2228d3eca20SDavid Ahern 		}
2238d3eca20SDavid Ahern 		goto out;
22418e60939SNelson Elhage 	}
2250a27d7f9SArnaldo Carvalho de Melo 
226a91e5431SArnaldo Carvalho de Melo 	session->evlist = evlist;
2277b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
2288d3eca20SDavid Ahern out:
2298d3eca20SDavid Ahern 	return rc;
230a91e5431SArnaldo Carvalho de Melo }
231a91e5431SArnaldo Carvalho de Melo 
232d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
2336122e4e4SArnaldo Carvalho de Melo {
234f5fc1412SJiri Olsa 	struct perf_data_file *file  = &rec->file;
235f5fc1412SJiri Olsa 	struct perf_session *session = rec->session;
2367ab75cffSDavid Ahern 	u64 start = session->header.data_offset;
2376122e4e4SArnaldo Carvalho de Melo 
238f5fc1412SJiri Olsa 	u64 size = lseek(file->fd, 0, SEEK_CUR);
2399f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2409f591fd7SArnaldo Carvalho de Melo 		return 0;
2419f591fd7SArnaldo Carvalho de Melo 
2427ab75cffSDavid Ahern 	return __perf_session__process_events(session, start,
2437ab75cffSDavid Ahern 					      size - start,
2446122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
2456122e4e4SArnaldo Carvalho de Melo }
2466122e4e4SArnaldo Carvalho de Melo 
2478d3eca20SDavid Ahern static void perf_record__exit(int status, void *arg)
248f5970550SPeter Zijlstra {
249d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
250f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
251f5970550SPeter Zijlstra 
2528d3eca20SDavid Ahern 	if (status != 0)
2538d3eca20SDavid Ahern 		return;
2548d3eca20SDavid Ahern 
255f5fc1412SJiri Olsa 	if (!file->is_pipe) {
256d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
257d20deb64SArnaldo Carvalho de Melo 
258d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
259d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
260d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
261f5fc1412SJiri Olsa 					   file->fd, true);
262d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
263d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
264d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
265c7929e47STom Zanussi 	}
266f5970550SPeter Zijlstra }
267f5970550SPeter Zijlstra 
2688115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
269a1645ce1SZhang, Yanmin {
270a1645ce1SZhang, Yanmin 	int err;
27145694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
272a1645ce1SZhang, Yanmin 	/*
273a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
274a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
275a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
276a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
277a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
278a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
279a1645ce1SZhang, Yanmin 	 */
28045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
281743eb868SArnaldo Carvalho de Melo 					     machine);
282a1645ce1SZhang, Yanmin 	if (err < 0)
283a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
28423346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
285a1645ce1SZhang, Yanmin 
286a1645ce1SZhang, Yanmin 	/*
287a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
288a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
289a1645ce1SZhang, Yanmin 	 */
29045694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
291743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
292a1645ce1SZhang, Yanmin 	if (err < 0)
29345694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
294743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
295a1645ce1SZhang, Yanmin 	if (err < 0)
296a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
29723346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
298a1645ce1SZhang, Yanmin }
299a1645ce1SZhang, Yanmin 
30098402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
30198402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
30298402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
30398402807SFrederic Weisbecker };
30498402807SFrederic Weisbecker 
3058d3eca20SDavid Ahern static int perf_record__mmap_read_all(struct perf_record *rec)
30698402807SFrederic Weisbecker {
3070e2e63ddSPeter Zijlstra 	int i;
3088d3eca20SDavid Ahern 	int rc = 0;
30998402807SFrederic Weisbecker 
310d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
3118d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
3128d3eca20SDavid Ahern 			if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
3138d3eca20SDavid Ahern 				rc = -1;
3148d3eca20SDavid Ahern 				goto out;
3158d3eca20SDavid Ahern 			}
3168d3eca20SDavid Ahern 		}
31798402807SFrederic Weisbecker 	}
31898402807SFrederic Weisbecker 
3192eeaaa09SStephane Eranian 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
3206233dd5eSJiri Olsa 		rc = perf_record__write(rec, &finished_round_event,
3218d3eca20SDavid Ahern 					sizeof(finished_round_event));
3228d3eca20SDavid Ahern 
3238d3eca20SDavid Ahern out:
3248d3eca20SDavid Ahern 	return rc;
32598402807SFrederic Weisbecker }
32698402807SFrederic Weisbecker 
32757706abcSDavid Ahern static void perf_record__init_features(struct perf_record *rec)
32857706abcSDavid Ahern {
32957706abcSDavid Ahern 	struct perf_evlist *evsel_list = rec->evlist;
33057706abcSDavid Ahern 	struct perf_session *session = rec->session;
33157706abcSDavid Ahern 	int feat;
33257706abcSDavid Ahern 
33357706abcSDavid Ahern 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
33457706abcSDavid Ahern 		perf_header__set_feat(&session->header, feat);
33557706abcSDavid Ahern 
33657706abcSDavid Ahern 	if (rec->no_buildid)
33757706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
33857706abcSDavid Ahern 
33957706abcSDavid Ahern 	if (!have_tracepoints(&evsel_list->entries))
34057706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
34157706abcSDavid Ahern 
34257706abcSDavid Ahern 	if (!rec->opts.branch_stack)
34357706abcSDavid Ahern 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
34457706abcSDavid Ahern }
34557706abcSDavid Ahern 
346d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
34786470930SIngo Molnar {
34857706abcSDavid Ahern 	int err;
3498b412664SPeter Zijlstra 	unsigned long waking = 0;
35046be604bSZhang, Yanmin 	const bool forks = argc > 0;
35123346f21SArnaldo Carvalho de Melo 	struct machine *machine;
35245694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
353d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
354d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
355f5fc1412SJiri Olsa 	struct perf_data_file *file = &rec->file;
356d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
3572711926aSJiri Olsa 	bool disabled = false;
35886470930SIngo Molnar 
359d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
36033e49ea7SAndi Kleen 
361d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
362f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
363f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
36418483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
365804f7ac7SDavid Ahern 	signal(SIGTERM, sig_handler);
366f5970550SPeter Zijlstra 
367f5fc1412SJiri Olsa 	session = perf_session__new(file, false, NULL);
36894c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
369a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
370a9a70bbcSArnaldo Carvalho de Melo 		return -1;
371a9a70bbcSArnaldo Carvalho de Melo 	}
372a9a70bbcSArnaldo Carvalho de Melo 
373d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
374d20deb64SArnaldo Carvalho de Melo 
37557706abcSDavid Ahern 	perf_record__init_features(rec);
376330aa675SStephane Eranian 
377d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
3786ef73ec4SNamhyung Kim 		err = perf_evlist__prepare_workload(evsel_list, &opts->target,
379f5fc1412SJiri Olsa 						    argv, file->is_pipe,
38055e162eaSNamhyung Kim 						    true);
38135b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
38235b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
38335b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
384856e9660SPeter Zijlstra 		}
385856e9660SPeter Zijlstra 	}
386856e9660SPeter Zijlstra 
3878d3eca20SDavid Ahern 	if (perf_record__open(rec) != 0) {
3888d3eca20SDavid Ahern 		err = -1;
3898d3eca20SDavid Ahern 		goto out_delete_session;
3908d3eca20SDavid Ahern 	}
39186470930SIngo Molnar 
392a8bb559bSNamhyung Kim 	if (!evsel_list->nr_groups)
393a8bb559bSNamhyung Kim 		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
394a8bb559bSNamhyung Kim 
395712a4b60SArnaldo Carvalho de Melo 	/*
396d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
397712a4b60SArnaldo Carvalho de Melo 	 */
398d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
399712a4b60SArnaldo Carvalho de Melo 
400f5fc1412SJiri Olsa 	if (file->is_pipe) {
401f5fc1412SJiri Olsa 		err = perf_header__write_pipe(file->fd);
402529870e3STom Zanussi 		if (err < 0)
4038d3eca20SDavid Ahern 			goto out_delete_session;
404563aecb2SJiri Olsa 	} else {
405a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
406f5fc1412SJiri Olsa 						 file->fd, false);
407d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
4088d3eca20SDavid Ahern 			goto out_delete_session;
409d5eed904SArnaldo Carvalho de Melo 	}
4107c6a1c65SPeter Zijlstra 
411d3665498SDavid Ahern 	if (!rec->no_buildid
412e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
413d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
414e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
4158d3eca20SDavid Ahern 		err = -1;
4168d3eca20SDavid Ahern 		goto out_delete_session;
417e20960c0SRobert Richter 	}
418e20960c0SRobert Richter 
41934ba5122SArnaldo Carvalho de Melo 	machine = &session->machines.host;
420743eb868SArnaldo Carvalho de Melo 
421f5fc1412SJiri Olsa 	if (file->is_pipe) {
42245694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
423a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
4242c46dbb5STom Zanussi 		if (err < 0) {
4252c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
4268d3eca20SDavid Ahern 			goto out_delete_session;
4272c46dbb5STom Zanussi 		}
428cd19a035STom Zanussi 
429361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
43063e0c771STom Zanussi 			/*
43163e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
43263e0c771STom Zanussi 			 * there were no tracepoints so its not really
43363e0c771STom Zanussi 			 * an error, just that we don't need to
43463e0c771STom Zanussi 			 * synthesize anything.  We really have to
43563e0c771STom Zanussi 			 * return this more properly and also
43663e0c771STom Zanussi 			 * propagate errors that now are calling die()
43763e0c771STom Zanussi 			 */
438f5fc1412SJiri Olsa 			err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list,
439743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
44063e0c771STom Zanussi 			if (err <= 0) {
44163e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
4428d3eca20SDavid Ahern 				goto out_delete_session;
44363e0c771STom Zanussi 			}
444f34b9001SDavid Ahern 			rec->bytes_written += err;
4452c46dbb5STom Zanussi 		}
44663e0c771STom Zanussi 	}
4472c46dbb5STom Zanussi 
44845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
449743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
45070162138SArnaldo Carvalho de Melo 	if (err < 0)
45145694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
452743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
453c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
454c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
455c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
456c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
45756b03f3cSArnaldo Carvalho de Melo 
45845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
459743eb868SArnaldo Carvalho de Melo 					     machine);
460c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
461c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
462c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
463c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
464c1a3a4b9SArnaldo Carvalho de Melo 
4657e383de4SArnaldo Carvalho de Melo 	if (perf_guest) {
466876650e6SArnaldo Carvalho de Melo 		machines__process_guests(&session->machines,
4677e383de4SArnaldo Carvalho de Melo 					 perf_event__synthesize_guest_os, tool);
4687e383de4SArnaldo Carvalho de Melo 	}
469b7cece76SArnaldo Carvalho de Melo 
470a33fbd56SArnaldo Carvalho de Melo 	err = __machine__synthesize_threads(machine, tool, &opts->target, evsel_list->threads,
47158d925dcSArnaldo Carvalho de Melo 					    process_synthesized_event, opts->sample_address);
4728d3eca20SDavid Ahern 	if (err != 0)
4738d3eca20SDavid Ahern 		goto out_delete_session;
4748d3eca20SDavid Ahern 
475d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
47686470930SIngo Molnar 		struct sched_param param;
47786470930SIngo Molnar 
478d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
47986470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
4806beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
4818d3eca20SDavid Ahern 			err = -1;
4828d3eca20SDavid Ahern 			goto out_delete_session;
48386470930SIngo Molnar 		}
48486470930SIngo Molnar 	}
48586470930SIngo Molnar 
486774cb499SJiri Olsa 	/*
487774cb499SJiri Olsa 	 * When perf is starting the traced process, all the events
488774cb499SJiri Olsa 	 * (apart from group members) have enable_on_exec=1 set,
489774cb499SJiri Olsa 	 * so don't spoil it by prematurely enabling them.
490774cb499SJiri Olsa 	 */
491602ad878SArnaldo Carvalho de Melo 	if (!target__none(&opts->target))
492764e16a3SDavid Ahern 		perf_evlist__enable(evsel_list);
493764e16a3SDavid Ahern 
494856e9660SPeter Zijlstra 	/*
495856e9660SPeter Zijlstra 	 * Let the child rip
496856e9660SPeter Zijlstra 	 */
497d4db3f16SArnaldo Carvalho de Melo 	if (forks)
49835b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
499856e9660SPeter Zijlstra 
500649c48a9SPeter Zijlstra 	for (;;) {
501d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
50286470930SIngo Molnar 
5038d3eca20SDavid Ahern 		if (perf_record__mmap_read_all(rec) < 0) {
5048d3eca20SDavid Ahern 			err = -1;
5058d3eca20SDavid Ahern 			goto out_delete_session;
5068d3eca20SDavid Ahern 		}
50786470930SIngo Molnar 
508d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
509649c48a9SPeter Zijlstra 			if (done)
510649c48a9SPeter Zijlstra 				break;
5115c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
5128b412664SPeter Zijlstra 			waking++;
5138b412664SPeter Zijlstra 		}
5148b412664SPeter Zijlstra 
515774cb499SJiri Olsa 		/*
516774cb499SJiri Olsa 		 * When perf is starting the traced process, at the end events
517774cb499SJiri Olsa 		 * die with the process and we wait for that. Thus no need to
518774cb499SJiri Olsa 		 * disable events in this case.
519774cb499SJiri Olsa 		 */
520602ad878SArnaldo Carvalho de Melo 		if (done && !disabled && !target__none(&opts->target)) {
5214152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
5222711926aSJiri Olsa 			disabled = true;
5232711926aSJiri Olsa 		}
5248b412664SPeter Zijlstra 	}
5258b412664SPeter Zijlstra 
52618483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
527b44308f5SArnaldo Carvalho de Melo 		return 0;
528b44308f5SArnaldo Carvalho de Melo 
5298b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
53086470930SIngo Molnar 
53186470930SIngo Molnar 	/*
53286470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
53386470930SIngo Molnar 	 */
53486470930SIngo Molnar 	fprintf(stderr,
5359486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
536d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
5376a4d98d7SJiri Olsa 		file->path,
538d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
53986470930SIngo Molnar 
54086470930SIngo Molnar 	return 0;
54139d17dacSArnaldo Carvalho de Melo 
54239d17dacSArnaldo Carvalho de Melo out_delete_session:
54339d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
54439d17dacSArnaldo Carvalho de Melo 	return err;
54586470930SIngo Molnar }
54686470930SIngo Molnar 
547bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
548bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
549bdfebd84SRoberto Agostino Vitillo 
550bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
551bdfebd84SRoberto Agostino Vitillo 
552bdfebd84SRoberto Agostino Vitillo struct branch_mode {
553bdfebd84SRoberto Agostino Vitillo 	const char *name;
554bdfebd84SRoberto Agostino Vitillo 	int mode;
555bdfebd84SRoberto Agostino Vitillo };
556bdfebd84SRoberto Agostino Vitillo 
557bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
558bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
559bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
560bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
561bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
562bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
563bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
564bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
5650126d493SAndi Kleen 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
5660126d493SAndi Kleen 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
5670126d493SAndi Kleen 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
568bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
569bdfebd84SRoberto Agostino Vitillo };
570bdfebd84SRoberto Agostino Vitillo 
571bdfebd84SRoberto Agostino Vitillo static int
572a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
573bdfebd84SRoberto Agostino Vitillo {
574bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
575bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
576bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
577bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
578bdfebd84SRoberto Agostino Vitillo 
579bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
580bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
581a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
582bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
583bdfebd84SRoberto Agostino Vitillo 
584a5aabdacSStephane Eranian 	if (unset)
585a5aabdacSStephane Eranian 		return 0;
586bdfebd84SRoberto Agostino Vitillo 
587a5aabdacSStephane Eranian 	/*
588a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
589a5aabdacSStephane Eranian 	 */
590a5aabdacSStephane Eranian 	if (*mode)
591a5aabdacSStephane Eranian 		return -1;
592a5aabdacSStephane Eranian 
593a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
594a5aabdacSStephane Eranian 	if (str) {
595bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
596bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
597bdfebd84SRoberto Agostino Vitillo 		if (!s)
598bdfebd84SRoberto Agostino Vitillo 			return -1;
599bdfebd84SRoberto Agostino Vitillo 
600bdfebd84SRoberto Agostino Vitillo 		for (;;) {
601bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
602bdfebd84SRoberto Agostino Vitillo 			if (p)
603bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
604bdfebd84SRoberto Agostino Vitillo 
605bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
606bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
607bdfebd84SRoberto Agostino Vitillo 					break;
608bdfebd84SRoberto Agostino Vitillo 			}
609a5aabdacSStephane Eranian 			if (!br->name) {
610a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
611a5aabdacSStephane Eranian 					    " check man page\n", s);
612bdfebd84SRoberto Agostino Vitillo 				goto error;
613a5aabdacSStephane Eranian 			}
614bdfebd84SRoberto Agostino Vitillo 
615bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
616bdfebd84SRoberto Agostino Vitillo 
617bdfebd84SRoberto Agostino Vitillo 			if (!p)
618bdfebd84SRoberto Agostino Vitillo 				break;
619bdfebd84SRoberto Agostino Vitillo 
620bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
621bdfebd84SRoberto Agostino Vitillo 		}
622a5aabdacSStephane Eranian 	}
623bdfebd84SRoberto Agostino Vitillo 	ret = 0;
624bdfebd84SRoberto Agostino Vitillo 
625a5aabdacSStephane Eranian 	/* default to any branch */
626bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
627a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
628bdfebd84SRoberto Agostino Vitillo 	}
629bdfebd84SRoberto Agostino Vitillo error:
630bdfebd84SRoberto Agostino Vitillo 	free(os);
631bdfebd84SRoberto Agostino Vitillo 	return ret;
632bdfebd84SRoberto Agostino Vitillo }
633bdfebd84SRoberto Agostino Vitillo 
63489fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
63526d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size)
63626d33022SJiri Olsa {
63726d33022SJiri Olsa 	char *endptr;
63826d33022SJiri Olsa 	unsigned long size;
63926d33022SJiri Olsa 	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
64026d33022SJiri Olsa 
64126d33022SJiri Olsa 	size = strtoul(str, &endptr, 0);
64226d33022SJiri Olsa 
64326d33022SJiri Olsa 	do {
64426d33022SJiri Olsa 		if (*endptr)
64526d33022SJiri Olsa 			break;
64626d33022SJiri Olsa 
64726d33022SJiri Olsa 		size = round_up(size, sizeof(u64));
64826d33022SJiri Olsa 		if (!size || size > max_size)
64926d33022SJiri Olsa 			break;
65026d33022SJiri Olsa 
65126d33022SJiri Olsa 		*_size = size;
65226d33022SJiri Olsa 		return 0;
65326d33022SJiri Olsa 
65426d33022SJiri Olsa 	} while (0);
65526d33022SJiri Olsa 
65626d33022SJiri Olsa 	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
65726d33022SJiri Olsa 	       max_size, str);
65826d33022SJiri Olsa 	return -1;
65926d33022SJiri Olsa }
66089fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */
66126d33022SJiri Olsa 
66209b0fd45SJiri Olsa int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
66326d33022SJiri Olsa {
66426d33022SJiri Olsa 	char *tok, *name, *saveptr = NULL;
66526d33022SJiri Olsa 	char *buf;
66626d33022SJiri Olsa 	int ret = -1;
66726d33022SJiri Olsa 
66826d33022SJiri Olsa 	/* We need buffer that we know we can write to. */
66926d33022SJiri Olsa 	buf = malloc(strlen(arg) + 1);
67026d33022SJiri Olsa 	if (!buf)
67126d33022SJiri Olsa 		return -ENOMEM;
67226d33022SJiri Olsa 
67326d33022SJiri Olsa 	strcpy(buf, arg);
67426d33022SJiri Olsa 
67526d33022SJiri Olsa 	tok = strtok_r((char *)buf, ",", &saveptr);
67626d33022SJiri Olsa 	name = tok ? : (char *)buf;
67726d33022SJiri Olsa 
67826d33022SJiri Olsa 	do {
67926d33022SJiri Olsa 		/* Framepointer style */
68026d33022SJiri Olsa 		if (!strncmp(name, "fp", sizeof("fp"))) {
68126d33022SJiri Olsa 			if (!strtok_r(NULL, ",", &saveptr)) {
682c5ff78c3SArnaldo Carvalho de Melo 				opts->call_graph = CALLCHAIN_FP;
68326d33022SJiri Olsa 				ret = 0;
68426d33022SJiri Olsa 			} else
68526d33022SJiri Olsa 				pr_err("callchain: No more arguments "
68626d33022SJiri Olsa 				       "needed for -g fp\n");
68726d33022SJiri Olsa 			break;
68826d33022SJiri Olsa 
68989fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
69026d33022SJiri Olsa 		/* Dwarf style */
69126d33022SJiri Olsa 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
69261eaa3beSArnaldo Carvalho de Melo 			const unsigned long default_stack_dump_size = 8192;
69361eaa3beSArnaldo Carvalho de Melo 
69426d33022SJiri Olsa 			ret = 0;
695c5ff78c3SArnaldo Carvalho de Melo 			opts->call_graph = CALLCHAIN_DWARF;
696c5ff78c3SArnaldo Carvalho de Melo 			opts->stack_dump_size = default_stack_dump_size;
69726d33022SJiri Olsa 
69826d33022SJiri Olsa 			tok = strtok_r(NULL, ",", &saveptr);
69926d33022SJiri Olsa 			if (tok) {
70026d33022SJiri Olsa 				unsigned long size = 0;
70126d33022SJiri Olsa 
70226d33022SJiri Olsa 				ret = get_stack_size(tok, &size);
703c5ff78c3SArnaldo Carvalho de Melo 				opts->stack_dump_size = size;
70426d33022SJiri Olsa 			}
70589fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */
70626d33022SJiri Olsa 		} else {
70709b0fd45SJiri Olsa 			pr_err("callchain: Unknown --call-graph option "
70826d33022SJiri Olsa 			       "value: %s\n", arg);
70926d33022SJiri Olsa 			break;
71026d33022SJiri Olsa 		}
71126d33022SJiri Olsa 
71226d33022SJiri Olsa 	} while (0);
71326d33022SJiri Olsa 
71426d33022SJiri Olsa 	free(buf);
71509b0fd45SJiri Olsa 	return ret;
71609b0fd45SJiri Olsa }
71726d33022SJiri Olsa 
71809b0fd45SJiri Olsa static void callchain_debug(struct perf_record_opts *opts)
71909b0fd45SJiri Olsa {
720c5ff78c3SArnaldo Carvalho de Melo 	pr_debug("callchain: type %d\n", opts->call_graph);
72126d33022SJiri Olsa 
72209b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_DWARF)
72309b0fd45SJiri Olsa 		pr_debug("callchain: stack dump size %d\n",
72409b0fd45SJiri Olsa 			 opts->stack_dump_size);
72509b0fd45SJiri Olsa }
72609b0fd45SJiri Olsa 
72709b0fd45SJiri Olsa int record_parse_callchain_opt(const struct option *opt,
72809b0fd45SJiri Olsa 			       const char *arg,
72909b0fd45SJiri Olsa 			       int unset)
73009b0fd45SJiri Olsa {
73109b0fd45SJiri Olsa 	struct perf_record_opts *opts = opt->value;
73209b0fd45SJiri Olsa 	int ret;
73309b0fd45SJiri Olsa 
73409b0fd45SJiri Olsa 	/* --no-call-graph */
73509b0fd45SJiri Olsa 	if (unset) {
73609b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_NONE;
73709b0fd45SJiri Olsa 		pr_debug("callchain: disabled\n");
73809b0fd45SJiri Olsa 		return 0;
73909b0fd45SJiri Olsa 	}
74009b0fd45SJiri Olsa 
74109b0fd45SJiri Olsa 	ret = record_parse_callchain(arg, opts);
74209b0fd45SJiri Olsa 	if (!ret)
74309b0fd45SJiri Olsa 		callchain_debug(opts);
74409b0fd45SJiri Olsa 
74526d33022SJiri Olsa 	return ret;
74626d33022SJiri Olsa }
74726d33022SJiri Olsa 
74809b0fd45SJiri Olsa int record_callchain_opt(const struct option *opt,
74909b0fd45SJiri Olsa 			 const char *arg __maybe_unused,
75009b0fd45SJiri Olsa 			 int unset __maybe_unused)
75109b0fd45SJiri Olsa {
75209b0fd45SJiri Olsa 	struct perf_record_opts *opts = opt->value;
75309b0fd45SJiri Olsa 
75409b0fd45SJiri Olsa 	if (opts->call_graph == CALLCHAIN_NONE)
75509b0fd45SJiri Olsa 		opts->call_graph = CALLCHAIN_FP;
75609b0fd45SJiri Olsa 
75709b0fd45SJiri Olsa 	callchain_debug(opts);
75809b0fd45SJiri Olsa 	return 0;
75909b0fd45SJiri Olsa }
76009b0fd45SJiri Olsa 
76186470930SIngo Molnar static const char * const record_usage[] = {
76286470930SIngo Molnar 	"perf record [<options>] [<command>]",
76386470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
76486470930SIngo Molnar 	NULL
76586470930SIngo Molnar };
76686470930SIngo Molnar 
767d20deb64SArnaldo Carvalho de Melo /*
768d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
769d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
770d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
771d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
772d20deb64SArnaldo Carvalho de Melo  *
773d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
774d20deb64SArnaldo Carvalho de Melo  *
775d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
776d20deb64SArnaldo Carvalho de Melo  */
777d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
778d20deb64SArnaldo Carvalho de Melo 	.opts = {
779d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
780d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
781d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
782447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
783d1cb9fceSNamhyung Kim 		.target		     = {
784d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
7853aa5939dSAdrian Hunter 			.default_per_cpu = true,
786d1cb9fceSNamhyung Kim 		},
787d20deb64SArnaldo Carvalho de Melo 	},
788d20deb64SArnaldo Carvalho de Melo };
7897865e817SFrederic Weisbecker 
79009b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
79161eaa3beSArnaldo Carvalho de Melo 
79289fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT
79309b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
79461eaa3beSArnaldo Carvalho de Melo #else
79509b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp";
79661eaa3beSArnaldo Carvalho de Melo #endif
79761eaa3beSArnaldo Carvalho de Melo 
798d20deb64SArnaldo Carvalho de Melo /*
799d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
800d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
801d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
802d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
803d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
804d20deb64SArnaldo Carvalho de Melo  */
805bca647aaSTom Zanussi const struct option record_options[] = {
806d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
80786470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
808f120f9d5SJiri Olsa 		     parse_events_option),
809d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
810c171b552SLi Zefan 		     "event filter", parse_filter),
811bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
812d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
813bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
814d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
815d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
81686470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
817d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
818acac03faSKirill Smelkov 		    "collect data without buffering"),
819d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
820daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
821bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
82286470930SIngo Molnar 			    "system-wide collection from all CPUs"),
823bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
824c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
825d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
826f5fc1412SJiri Olsa 	OPT_STRING('o', "output", &record.file.path, "file",
82786470930SIngo Molnar 		    "output file name"),
82869e7e5b0SAdrian Hunter 	OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
82969e7e5b0SAdrian Hunter 			&record.opts.no_inherit_set,
8302e6cdf99SStephane Eranian 			"child tasks do not inherit counters"),
831d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
832994a1f78SJiri Olsa 	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
833994a1f78SJiri Olsa 		     "number of mmap data pages",
834994a1f78SJiri Olsa 		     perf_evlist__parse_mmap_pages),
835d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
83643bece79SLin Ming 		    "put the counters into a counter group"),
83709b0fd45SJiri Olsa 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
83809b0fd45SJiri Olsa 			   NULL, "enables call-graph recording" ,
83909b0fd45SJiri Olsa 			   &record_callchain_opt),
84009b0fd45SJiri Olsa 	OPT_CALLBACK(0, "call-graph", &record.opts,
84175d9a108SArnaldo Carvalho de Melo 		     "mode[,dump_size]", record_callchain_help,
84209b0fd45SJiri Olsa 		     &record_parse_callchain_opt),
843c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8443da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
845b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
846d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
847649c48a9SPeter Zijlstra 		    "per thread counts"),
848d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8494bba828dSAnton Blanchard 		    "Sample addresses"),
850d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8513e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
852d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
853649c48a9SPeter Zijlstra 		    "don't sample"),
854d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
855a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
856d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
857baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
858d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
859023695d9SStephane Eranian 		     "monitor event in cgroup name only",
860023695d9SStephane Eranian 		     parse_cgroups),
861bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
862bea03405SNamhyung Kim 		   "user to profile"),
863a5aabdacSStephane Eranian 
864a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
865a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
866a5aabdacSStephane Eranian 		     parse_branch_stack),
867a5aabdacSStephane Eranian 
868a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
869a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
870bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
87105484298SAndi Kleen 	OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
87205484298SAndi Kleen 		    "sample by weight (on special events only)"),
873475eeab9SAndi Kleen 	OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
874475eeab9SAndi Kleen 		    "sample transaction flags (special events only)"),
8753aa5939dSAdrian Hunter 	OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
8763aa5939dSAdrian Hunter 		    "use per-thread mmaps"),
87786470930SIngo Molnar 	OPT_END()
87886470930SIngo Molnar };
87986470930SIngo Molnar 
8801d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
88186470930SIngo Molnar {
88269aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
883d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
884d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
88516ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
88686470930SIngo Molnar 
887334fe7a3SNamhyung Kim 	evsel_list = perf_evlist__new();
888361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
889361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
890361c99a6SArnaldo Carvalho de Melo 
891d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
892d20deb64SArnaldo Carvalho de Melo 
893bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
894a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
895602ad878SArnaldo Carvalho de Melo 	if (!argc && target__none(&rec->opts.target))
896bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
89786470930SIngo Molnar 
898bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
8993780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
900023695d9SStephane Eranian 			  " system-wide mode\n");
901023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
902023695d9SStephane Eranian 	}
903023695d9SStephane Eranian 
904655000e7SArnaldo Carvalho de Melo 	symbol__init();
905baa2f6ceSArnaldo Carvalho de Melo 
906ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
907646aaea6SArnaldo Carvalho de Melo 		pr_warning(
908646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
909ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
910646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
911646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
912646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
913646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
914646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
915ec80fde7SArnaldo Carvalho de Melo 
916d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
917a1ac1d3cSStephane Eranian 		disable_buildid_cache();
918655000e7SArnaldo Carvalho de Melo 
919361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
920361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
92169aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
92269aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
923bbd36e5eSPeter Zijlstra 	}
92486470930SIngo Molnar 
92569e7e5b0SAdrian Hunter 	if (rec->opts.target.tid && !rec->opts.no_inherit_set)
92669e7e5b0SAdrian Hunter 		rec->opts.no_inherit = true;
92769e7e5b0SAdrian Hunter 
928602ad878SArnaldo Carvalho de Melo 	err = target__validate(&rec->opts.target);
92916ad2ffbSNamhyung Kim 	if (err) {
930602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
93116ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
93216ad2ffbSNamhyung Kim 	}
9334bd0f2d2SNamhyung Kim 
934602ad878SArnaldo Carvalho de Melo 	err = target__parse_uid(&rec->opts.target);
93516ad2ffbSNamhyung Kim 	if (err) {
93616ad2ffbSNamhyung Kim 		int saved_errno = errno;
93716ad2ffbSNamhyung Kim 
938602ad878SArnaldo Carvalho de Melo 		target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9393780f488SNamhyung Kim 		ui__error("%s", errbuf);
94016ad2ffbSNamhyung Kim 
94116ad2ffbSNamhyung Kim 		err = -saved_errno;
9428fa60e1fSNamhyung Kim 		goto out_symbol_exit;
94316ad2ffbSNamhyung Kim 	}
9440d37aa34SArnaldo Carvalho de Melo 
94516ad2ffbSNamhyung Kim 	err = -ENOMEM;
946b809ac10SNamhyung Kim 	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
947dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
94869aad6f1SArnaldo Carvalho de Melo 
949714647bdSJiri Olsa 	if (perf_record_opts__config(&rec->opts)) {
95039d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
9515c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
9527e4ff9e3SMike Galbraith 	}
9537e4ff9e3SMike Galbraith 
954d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
9558fa60e1fSNamhyung Kim 
9568fa60e1fSNamhyung Kim 	perf_evlist__munmap(evsel_list);
9578fa60e1fSNamhyung Kim 	perf_evlist__close(evsel_list);
95839d17dacSArnaldo Carvalho de Melo out_free_fd:
9597e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
960d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
961d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
96239d17dacSArnaldo Carvalho de Melo 	return err;
96386470930SIngo Molnar }
964