xref: /openbmc/linux/tools/perf/builtin-record.c (revision 61eaa3be152afcbfb862a10f81341f96371c3ce3)
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  */
8b8f46c5aSXiao Guangrong #define _FILE_OFFSET_BITS 64
9b8f46c5aSXiao Guangrong 
1086470930SIngo Molnar #include "builtin.h"
1186470930SIngo Molnar 
1286470930SIngo Molnar #include "perf.h"
1386470930SIngo Molnar 
146122e4e4SArnaldo Carvalho de Melo #include "util/build-id.h"
1586470930SIngo Molnar #include "util/util.h"
1686470930SIngo Molnar #include "util/parse-options.h"
1786470930SIngo Molnar #include "util/parse-events.h"
1886470930SIngo Molnar 
197c6a1c65SPeter Zijlstra #include "util/header.h"
2066e274f3SFrederic Weisbecker #include "util/event.h"
21361c99a6SArnaldo Carvalho de Melo #include "util/evlist.h"
2269aad6f1SArnaldo Carvalho de Melo #include "util/evsel.h"
238f28827aSFrederic Weisbecker #include "util/debug.h"
2494c744b6SArnaldo Carvalho de Melo #include "util/session.h"
2545694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
268d06367fSArnaldo Carvalho de Melo #include "util/symbol.h"
27a12b51c4SPaul Mackerras #include "util/cpumap.h"
28fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h"
297c6a1c65SPeter Zijlstra 
3086470930SIngo Molnar #include <unistd.h>
3186470930SIngo Molnar #include <sched.h>
32a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3386470930SIngo Molnar 
347865e817SFrederic Weisbecker enum write_mode_t {
357865e817SFrederic Weisbecker 	WRITE_FORCE,
367865e817SFrederic Weisbecker 	WRITE_APPEND
377865e817SFrederic Weisbecker };
387865e817SFrederic Weisbecker 
39d20deb64SArnaldo Carvalho de Melo struct perf_record {
4045694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
41d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts	opts;
42d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
43d20deb64SArnaldo Carvalho de Melo 	const char		*output_name;
44d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
45d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
46d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
47d20deb64SArnaldo Carvalho de Melo 	int			output;
48d20deb64SArnaldo Carvalho de Melo 	unsigned int		page_size;
49d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
50d20deb64SArnaldo Carvalho de Melo 	enum write_mode_t	write_mode;
51d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
52d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
53d20deb64SArnaldo Carvalho de Melo 	bool			force;
54d20deb64SArnaldo Carvalho de Melo 	bool			file_new;
55d20deb64SArnaldo Carvalho de Melo 	bool			append_file;
56d20deb64SArnaldo Carvalho de Melo 	long			samples;
57d20deb64SArnaldo Carvalho de Melo 	off_t			post_processing_offset;
580f82ebc4SArnaldo Carvalho de Melo };
5986470930SIngo Molnar 
60d20deb64SArnaldo Carvalho de Melo static void advance_output(struct perf_record *rec, size_t size)
619215545eSTom Zanussi {
62d20deb64SArnaldo Carvalho de Melo 	rec->bytes_written += size;
639215545eSTom Zanussi }
649215545eSTom Zanussi 
658d3eca20SDavid Ahern static int write_output(struct perf_record *rec, void *buf, size_t size)
66f5970550SPeter Zijlstra {
67f5970550SPeter Zijlstra 	while (size) {
68d20deb64SArnaldo Carvalho de Melo 		int ret = write(rec->output, buf, size);
69f5970550SPeter Zijlstra 
708d3eca20SDavid Ahern 		if (ret < 0) {
718d3eca20SDavid Ahern 			pr_err("failed to write\n");
728d3eca20SDavid Ahern 			return -1;
738d3eca20SDavid Ahern 		}
74f5970550SPeter Zijlstra 
75f5970550SPeter Zijlstra 		size -= ret;
76f5970550SPeter Zijlstra 		buf += ret;
77f5970550SPeter Zijlstra 
78d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written += ret;
79f5970550SPeter Zijlstra 	}
808d3eca20SDavid Ahern 
818d3eca20SDavid Ahern 	return 0;
82f5970550SPeter Zijlstra }
83f5970550SPeter Zijlstra 
8445694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
85d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
861d037ca1SIrina Tirdea 				     struct perf_sample *sample __maybe_unused,
871d037ca1SIrina Tirdea 				     struct machine *machine __maybe_unused)
88234fbbf5SArnaldo Carvalho de Melo {
8945694aa7SArnaldo Carvalho de Melo 	struct perf_record *rec = container_of(tool, struct perf_record, tool);
908d3eca20SDavid Ahern 	if (write_output(rec, event, event->header.size) < 0)
918d3eca20SDavid Ahern 		return -1;
928d3eca20SDavid Ahern 
93234fbbf5SArnaldo Carvalho de Melo 	return 0;
94234fbbf5SArnaldo Carvalho de Melo }
95234fbbf5SArnaldo Carvalho de Melo 
968d3eca20SDavid Ahern static int perf_record__mmap_read(struct perf_record *rec,
97d20deb64SArnaldo Carvalho de Melo 				   struct perf_mmap *md)
9886470930SIngo Molnar {
99744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
10086470930SIngo Molnar 	unsigned int old = md->prev;
101d20deb64SArnaldo Carvalho de Melo 	unsigned char *data = md->base + rec->page_size;
10286470930SIngo Molnar 	unsigned long size;
10386470930SIngo Molnar 	void *buf;
1048d3eca20SDavid Ahern 	int rc = 0;
10586470930SIngo Molnar 
106dc82009aSArnaldo Carvalho de Melo 	if (old == head)
1078d3eca20SDavid Ahern 		return 0;
10886470930SIngo Molnar 
109d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
11086470930SIngo Molnar 
11186470930SIngo Molnar 	size = head - old;
11286470930SIngo Molnar 
11386470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
11486470930SIngo Molnar 		buf = &data[old & md->mask];
11586470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
11686470930SIngo Molnar 		old += size;
11786470930SIngo Molnar 
1188d3eca20SDavid Ahern 		if (write_output(rec, buf, size) < 0) {
1198d3eca20SDavid Ahern 			rc = -1;
1208d3eca20SDavid Ahern 			goto out;
1218d3eca20SDavid Ahern 		}
12286470930SIngo Molnar 	}
12386470930SIngo Molnar 
12486470930SIngo Molnar 	buf = &data[old & md->mask];
12586470930SIngo Molnar 	size = head - old;
12686470930SIngo Molnar 	old += size;
12786470930SIngo Molnar 
1288d3eca20SDavid Ahern 	if (write_output(rec, buf, size) < 0) {
1298d3eca20SDavid Ahern 		rc = -1;
1308d3eca20SDavid Ahern 		goto out;
1318d3eca20SDavid Ahern 	}
13286470930SIngo Molnar 
13386470930SIngo Molnar 	md->prev = old;
134115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
1358d3eca20SDavid Ahern 
1368d3eca20SDavid Ahern out:
1378d3eca20SDavid Ahern 	return rc;
13886470930SIngo Molnar }
13986470930SIngo Molnar 
14086470930SIngo Molnar static volatile int done = 0;
141f7b7c26eSPeter Zijlstra static volatile int signr = -1;
14233e49ea7SAndi Kleen static volatile int child_finished = 0;
14386470930SIngo Molnar 
14486470930SIngo Molnar static void sig_handler(int sig)
14586470930SIngo Molnar {
14633e49ea7SAndi Kleen 	if (sig == SIGCHLD)
14733e49ea7SAndi Kleen 		child_finished = 1;
14833e49ea7SAndi Kleen 
14986470930SIngo Molnar 	done = 1;
150f7b7c26eSPeter Zijlstra 	signr = sig;
151f7b7c26eSPeter Zijlstra }
152f7b7c26eSPeter Zijlstra 
1531d037ca1SIrina Tirdea static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
154f7b7c26eSPeter Zijlstra {
155d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
15633e49ea7SAndi Kleen 	int status;
15733e49ea7SAndi Kleen 
158d20deb64SArnaldo Carvalho de Melo 	if (rec->evlist->workload.pid > 0) {
15933e49ea7SAndi Kleen 		if (!child_finished)
160d20deb64SArnaldo Carvalho de Melo 			kill(rec->evlist->workload.pid, SIGTERM);
161933da83aSChris Wilson 
16233e49ea7SAndi Kleen 		wait(&status);
16333e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
164d20deb64SArnaldo Carvalho de Melo 			psignal(WTERMSIG(status), rec->progname);
16533e49ea7SAndi Kleen 	}
16633e49ea7SAndi Kleen 
16718483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
168f7b7c26eSPeter Zijlstra 		return;
169f7b7c26eSPeter Zijlstra 
170f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
171f7b7c26eSPeter Zijlstra 	kill(getpid(), signr);
17286470930SIngo Molnar }
17386470930SIngo Molnar 
174a91e5431SArnaldo Carvalho de Melo static bool perf_evlist__equal(struct perf_evlist *evlist,
175a91e5431SArnaldo Carvalho de Melo 			       struct perf_evlist *other)
176a91e5431SArnaldo Carvalho de Melo {
177a91e5431SArnaldo Carvalho de Melo 	struct perf_evsel *pos, *pair;
178a91e5431SArnaldo Carvalho de Melo 
179a91e5431SArnaldo Carvalho de Melo 	if (evlist->nr_entries != other->nr_entries)
180a91e5431SArnaldo Carvalho de Melo 		return false;
181a91e5431SArnaldo Carvalho de Melo 
1820c21f736SArnaldo Carvalho de Melo 	pair = perf_evlist__first(other);
183a91e5431SArnaldo Carvalho de Melo 
184a91e5431SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
185a91e5431SArnaldo Carvalho de Melo 		if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
186a91e5431SArnaldo Carvalho de Melo 			return false;
1870c21f736SArnaldo Carvalho de Melo 		pair = perf_evsel__next(pair);
188a91e5431SArnaldo Carvalho de Melo 	}
189a91e5431SArnaldo Carvalho de Melo 
190a91e5431SArnaldo Carvalho de Melo 	return true;
191a91e5431SArnaldo Carvalho de Melo }
192a91e5431SArnaldo Carvalho de Melo 
1938d3eca20SDavid Ahern static int perf_record__open(struct perf_record *rec)
194dd7927f4SArnaldo Carvalho de Melo {
1956a4bb04cSJiri Olsa 	struct perf_evsel *pos;
196d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
197d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
198d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
1998d3eca20SDavid Ahern 	int rc = 0;
200dd7927f4SArnaldo Carvalho de Melo 
201d20deb64SArnaldo Carvalho de Melo 	perf_evlist__config_attrs(evlist, opts);
2020f82ebc4SArnaldo Carvalho de Melo 
2036a4bb04cSJiri Olsa 	if (opts->group)
20463dab225SArnaldo Carvalho de Melo 		perf_evlist__set_leader(evlist);
2056a4bb04cSJiri Olsa 
206dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
207dd7927f4SArnaldo Carvalho de Melo 		struct perf_event_attr *attr = &pos->attr;
208dd7927f4SArnaldo Carvalho de Melo 		/*
209dd7927f4SArnaldo Carvalho de Melo 		 * Check if parse_single_tracepoint_event has already asked for
210dd7927f4SArnaldo Carvalho de Melo 		 * PERF_SAMPLE_TIME.
211dd7927f4SArnaldo Carvalho de Melo 		 *
212dd7927f4SArnaldo Carvalho de Melo 		 * XXX this is kludgy but short term fix for problems introduced by
213dd7927f4SArnaldo Carvalho de Melo 		 * eac23d1c that broke 'perf script' by having different sample_types
214dd7927f4SArnaldo Carvalho de Melo 		 * when using multiple tracepoint events when we use a perf binary
215dd7927f4SArnaldo Carvalho de Melo 		 * that tries to use sample_id_all on an older kernel.
216dd7927f4SArnaldo Carvalho de Melo 		 *
217dd7927f4SArnaldo Carvalho de Melo 		 * We need to move counter creation to perf_session, support
218dd7927f4SArnaldo Carvalho de Melo 		 * different sample_types, etc.
219dd7927f4SArnaldo Carvalho de Melo 		 */
220dd7927f4SArnaldo Carvalho de Melo 		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
221dd7927f4SArnaldo Carvalho de Melo 
2220c978128SArnaldo Carvalho de Melo fallback_missing_features:
2230c978128SArnaldo Carvalho de Melo 		if (opts->exclude_guest_missing)
2240c978128SArnaldo Carvalho de Melo 			attr->exclude_guest = attr->exclude_host = 0;
2259c90a61cSArnaldo Carvalho de Melo retry_sample_id:
226808e1226SArnaldo Carvalho de Melo 		attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
2273da297a6SIngo Molnar try_again:
2286a4bb04cSJiri Olsa 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
22986470930SIngo Molnar 			int err = errno;
23086470930SIngo Molnar 
231c286c419SArnaldo Carvalho de Melo 			if (err == EPERM || err == EACCES) {
232b8631e6eSArnaldo Carvalho de Melo 				ui__error_paranoid();
2338d3eca20SDavid Ahern 				rc = -err;
2348d3eca20SDavid Ahern 				goto out;
235bea03405SNamhyung Kim 			} else if (err ==  ENODEV && opts->target.cpu_list) {
2368d3eca20SDavid Ahern 				pr_err("No such device - did you specify"
237d6d901c2SZhang, Yanmin 				       " an out-of-range profile CPU?\n");
2388d3eca20SDavid Ahern 				rc = -err;
2398d3eca20SDavid Ahern 				goto out;
2400c978128SArnaldo Carvalho de Melo 			} else if (err == EINVAL) {
2410c978128SArnaldo Carvalho de Melo 				if (!opts->exclude_guest_missing &&
2420c978128SArnaldo Carvalho de Melo 				    (attr->exclude_guest || attr->exclude_host)) {
2430c978128SArnaldo Carvalho de Melo 					pr_debug("Old kernel, cannot exclude "
2440c978128SArnaldo Carvalho de Melo 						 "guest or host samples.\n");
2450c978128SArnaldo Carvalho de Melo 					opts->exclude_guest_missing = true;
2460c978128SArnaldo Carvalho de Melo 					goto fallback_missing_features;
247808e1226SArnaldo Carvalho de Melo 				} else if (!opts->sample_id_all_missing) {
2489c90a61cSArnaldo Carvalho de Melo 					/*
2499c90a61cSArnaldo Carvalho de Melo 					 * Old kernel, no attr->sample_id_type_all field
2509c90a61cSArnaldo Carvalho de Melo 					 */
251808e1226SArnaldo Carvalho de Melo 					opts->sample_id_all_missing = true;
252d20deb64SArnaldo Carvalho de Melo 					if (!opts->sample_time && !opts->raw_samples && !time_needed)
253eac23d1cSIan Munsie 						attr->sample_type &= ~PERF_SAMPLE_TIME;
254eac23d1cSIan Munsie 
2559c90a61cSArnaldo Carvalho de Melo 					goto retry_sample_id;
256d6d901c2SZhang, Yanmin 				}
2570c978128SArnaldo Carvalho de Melo 			}
2583da297a6SIngo Molnar 
2593da297a6SIngo Molnar 			/*
2603da297a6SIngo Molnar 			 * If it's cycles then fall back to hrtimer
2613da297a6SIngo Molnar 			 * based cpu-clock-tick sw counter, which
262028d455bSDavid Ahern 			 * is always available even if no PMU support.
263028d455bSDavid Ahern 			 *
264028d455bSDavid Ahern 			 * PPC returns ENXIO until 2.6.37 (behavior changed
265028d455bSDavid Ahern 			 * with commit b0a873e).
2663da297a6SIngo Molnar 			 */
267028d455bSDavid Ahern 			if ((err == ENOENT || err == ENXIO)
268028d455bSDavid Ahern 					&& attr->type == PERF_TYPE_HARDWARE
269f4dbfa8fSPeter Zijlstra 					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {
2703da297a6SIngo Molnar 
2713da297a6SIngo Molnar 				if (verbose)
272ca6a4258SDavid Ahern 					ui__warning("The cycles event is not supported, "
273ca6a4258SDavid Ahern 						    "trying to fall back to cpu-clock-ticks\n");
2743da297a6SIngo Molnar 				attr->type = PERF_TYPE_SOFTWARE;
275f4dbfa8fSPeter Zijlstra 				attr->config = PERF_COUNT_SW_CPU_CLOCK;
276d1cae34dSDavid Ahern 				if (pos->name) {
277d1cae34dSDavid Ahern 					free(pos->name);
278d1cae34dSDavid Ahern 					pos->name = NULL;
279d1cae34dSDavid Ahern 				}
2803da297a6SIngo Molnar 				goto try_again;
2813da297a6SIngo Molnar 			}
282ca6a4258SDavid Ahern 
283ca6a4258SDavid Ahern 			if (err == ENOENT) {
2843780f488SNamhyung Kim 				ui__error("The %s event is not supported.\n",
2857289f83cSArnaldo Carvalho de Melo 					  perf_evsel__name(pos));
2868d3eca20SDavid Ahern 				rc = -err;
2878d3eca20SDavid Ahern 				goto out;
288ca6a4258SDavid Ahern 			}
289ca6a4258SDavid Ahern 
29030c806a0SIngo Molnar 			printf("\n");
2911863fbbbSStephane Eranian 			error("sys_perf_event_open() syscall returned with %d "
2921863fbbbSStephane Eranian 			      "(%s) for event %s. /bin/dmesg may provide "
2931863fbbbSStephane Eranian 			      "additional information.\n",
2941863fbbbSStephane Eranian 			      err, strerror(err), perf_evsel__name(pos));
295bfd45118SSimon Kaempflein 
296bfd45118SSimon Kaempflein #if defined(__i386__) || defined(__x86_64__)
2978d3eca20SDavid Ahern 			if (attr->type == PERF_TYPE_HARDWARE &&
2988d3eca20SDavid Ahern 			    err == EOPNOTSUPP) {
2998d3eca20SDavid Ahern 				pr_err("No hardware sampling interrupt available."
300d6d901c2SZhang, Yanmin 				       " No APIC? If so then you can boot the kernel"
301d6d901c2SZhang, Yanmin 				       " with the \"lapic\" boot parameter to"
302d6d901c2SZhang, Yanmin 				       " force-enable it.\n");
3038d3eca20SDavid Ahern 				rc = -err;
3048d3eca20SDavid Ahern 				goto out;
3058d3eca20SDavid Ahern 			}
306bfd45118SSimon Kaempflein #endif
307bfd45118SSimon Kaempflein 
3088d3eca20SDavid Ahern 			pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
3098d3eca20SDavid Ahern 			rc = -err;
3108d3eca20SDavid Ahern 			goto out;
3117c6a1c65SPeter Zijlstra 		}
3127c6a1c65SPeter Zijlstra 	}
3137c6a1c65SPeter Zijlstra 
3141491a632SArnaldo Carvalho de Melo 	if (perf_evlist__apply_filters(evlist)) {
3150a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
3160a102479SFrederic Weisbecker 			strerror(errno));
3178d3eca20SDavid Ahern 		rc = -1;
3188d3eca20SDavid Ahern 		goto out;
3190a102479SFrederic Weisbecker 	}
3200a102479SFrederic Weisbecker 
32118e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
3228d3eca20SDavid Ahern 		if (errno == EPERM) {
3238d3eca20SDavid Ahern 			pr_err("Permission error mapping pages.\n"
32418e60939SNelson Elhage 			       "Consider increasing "
32518e60939SNelson Elhage 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
32618e60939SNelson Elhage 			       "or try again with a smaller value of -m/--mmap_pages.\n"
32718e60939SNelson Elhage 			       "(current value: %d)\n", opts->mmap_pages);
3288d3eca20SDavid Ahern 			rc = -errno;
3298d3eca20SDavid Ahern 		} else if (!is_power_of_2(opts->mmap_pages)) {
3308d3eca20SDavid Ahern 			pr_err("--mmap_pages/-m value must be a power of two.");
3318d3eca20SDavid Ahern 			rc = -EINVAL;
3328d3eca20SDavid Ahern 		} else {
3338d3eca20SDavid Ahern 			pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
3348d3eca20SDavid Ahern 			rc = -errno;
3358d3eca20SDavid Ahern 		}
3368d3eca20SDavid Ahern 		goto out;
33718e60939SNelson Elhage 	}
3380a27d7f9SArnaldo Carvalho de Melo 
339d20deb64SArnaldo Carvalho de Melo 	if (rec->file_new)
340a91e5431SArnaldo Carvalho de Melo 		session->evlist = evlist;
341a91e5431SArnaldo Carvalho de Melo 	else {
342a91e5431SArnaldo Carvalho de Melo 		if (!perf_evlist__equal(session->evlist, evlist)) {
343a91e5431SArnaldo Carvalho de Melo 			fprintf(stderr, "incompatible append\n");
3448d3eca20SDavid Ahern 			rc = -1;
3458d3eca20SDavid Ahern 			goto out;
346dd7927f4SArnaldo Carvalho de Melo 		}
34786470930SIngo Molnar  	}
34886470930SIngo Molnar 
3497b56cce2SArnaldo Carvalho de Melo 	perf_session__set_id_hdr_size(session);
3508d3eca20SDavid Ahern out:
3518d3eca20SDavid Ahern 	return rc;
352a91e5431SArnaldo Carvalho de Melo }
353a91e5431SArnaldo Carvalho de Melo 
354d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
3556122e4e4SArnaldo Carvalho de Melo {
356d20deb64SArnaldo Carvalho de Melo 	u64 size = lseek(rec->output, 0, SEEK_CUR);
3576122e4e4SArnaldo Carvalho de Melo 
3589f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
3599f591fd7SArnaldo Carvalho de Melo 		return 0;
3609f591fd7SArnaldo Carvalho de Melo 
361d20deb64SArnaldo Carvalho de Melo 	rec->session->fd = rec->output;
362d20deb64SArnaldo Carvalho de Melo 	return __perf_session__process_events(rec->session, rec->post_processing_offset,
363d20deb64SArnaldo Carvalho de Melo 					      size - rec->post_processing_offset,
3646122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
3656122e4e4SArnaldo Carvalho de Melo }
3666122e4e4SArnaldo Carvalho de Melo 
3678d3eca20SDavid Ahern static void perf_record__exit(int status, void *arg)
368f5970550SPeter Zijlstra {
369d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
370f5970550SPeter Zijlstra 
3718d3eca20SDavid Ahern 	if (status != 0)
3728d3eca20SDavid Ahern 		return;
3738d3eca20SDavid Ahern 
374d20deb64SArnaldo Carvalho de Melo 	if (!rec->opts.pipe_output) {
375d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
376d20deb64SArnaldo Carvalho de Melo 
377d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
378d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
379d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
380d20deb64SArnaldo Carvalho de Melo 					   rec->output, true);
381d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
382d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
383d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
384c7929e47STom Zanussi 	}
385f5970550SPeter Zijlstra }
386f5970550SPeter Zijlstra 
3878115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
388a1645ce1SZhang, Yanmin {
389a1645ce1SZhang, Yanmin 	int err;
39045694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
391a1645ce1SZhang, Yanmin 
39223346f21SArnaldo Carvalho de Melo 	if (machine__is_host(machine))
393a1645ce1SZhang, Yanmin 		return;
394a1645ce1SZhang, Yanmin 
395a1645ce1SZhang, Yanmin 	/*
396a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
397a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
398a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
399a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
400a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
401a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
402a1645ce1SZhang, Yanmin 	 */
40345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
404743eb868SArnaldo Carvalho de Melo 					     machine);
405a1645ce1SZhang, Yanmin 	if (err < 0)
406a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
40723346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
408a1645ce1SZhang, Yanmin 
409a1645ce1SZhang, Yanmin 	/*
410a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
411a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
412a1645ce1SZhang, Yanmin 	 */
41345694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
414743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
415a1645ce1SZhang, Yanmin 	if (err < 0)
41645694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
417743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
418a1645ce1SZhang, Yanmin 	if (err < 0)
419a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
42023346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
421a1645ce1SZhang, Yanmin }
422a1645ce1SZhang, Yanmin 
42398402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
42498402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
42598402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
42698402807SFrederic Weisbecker };
42798402807SFrederic Weisbecker 
4288d3eca20SDavid Ahern static int perf_record__mmap_read_all(struct perf_record *rec)
42998402807SFrederic Weisbecker {
4300e2e63ddSPeter Zijlstra 	int i;
4318d3eca20SDavid Ahern 	int rc = 0;
43298402807SFrederic Weisbecker 
433d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
4348d3eca20SDavid Ahern 		if (rec->evlist->mmap[i].base) {
4358d3eca20SDavid Ahern 			if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
4368d3eca20SDavid Ahern 				rc = -1;
4378d3eca20SDavid Ahern 				goto out;
4388d3eca20SDavid Ahern 			}
4398d3eca20SDavid Ahern 		}
44098402807SFrederic Weisbecker 	}
44198402807SFrederic Weisbecker 
4422eeaaa09SStephane Eranian 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
4438d3eca20SDavid Ahern 		rc = write_output(rec, &finished_round_event,
4448d3eca20SDavid Ahern 				  sizeof(finished_round_event));
4458d3eca20SDavid Ahern 
4468d3eca20SDavid Ahern out:
4478d3eca20SDavid Ahern 	return rc;
44898402807SFrederic Weisbecker }
44998402807SFrederic Weisbecker 
450d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
45186470930SIngo Molnar {
45286470930SIngo Molnar 	struct stat st;
45386470930SIngo Molnar 	int flags;
454781ba9d2SRobert Richter 	int err, output, feat;
4558b412664SPeter Zijlstra 	unsigned long waking = 0;
45646be604bSZhang, Yanmin 	const bool forks = argc > 0;
45723346f21SArnaldo Carvalho de Melo 	struct machine *machine;
45845694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
459d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
460d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
461d20deb64SArnaldo Carvalho de Melo 	const char *output_name = rec->output_name;
462d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
46386470930SIngo Molnar 
464d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
46533e49ea7SAndi Kleen 
466d20deb64SArnaldo Carvalho de Melo 	rec->page_size = sysconf(_SC_PAGE_SIZE);
46786470930SIngo Molnar 
468d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
469f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
470f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
47118483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
472f5970550SPeter Zijlstra 
473d7065adbSFranck Bui-Huu 	if (!output_name) {
474d7065adbSFranck Bui-Huu 		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
475d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
476d7065adbSFranck Bui-Huu 		else
477d20deb64SArnaldo Carvalho de Melo 			rec->output_name = output_name = "perf.data";
478d7065adbSFranck Bui-Huu 	}
479d7065adbSFranck Bui-Huu 	if (output_name) {
480529870e3STom Zanussi 		if (!strcmp(output_name, "-"))
481d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
482529870e3STom Zanussi 		else if (!stat(output_name, &st) && st.st_size) {
483d20deb64SArnaldo Carvalho de Melo 			if (rec->write_mode == WRITE_FORCE) {
484b38d3464SArnaldo Carvalho de Melo 				char oldname[PATH_MAX];
485b38d3464SArnaldo Carvalho de Melo 				snprintf(oldname, sizeof(oldname), "%s.old",
486b38d3464SArnaldo Carvalho de Melo 					 output_name);
487b38d3464SArnaldo Carvalho de Melo 				unlink(oldname);
488b38d3464SArnaldo Carvalho de Melo 				rename(output_name, oldname);
489b38d3464SArnaldo Carvalho de Melo 			}
490d20deb64SArnaldo Carvalho de Melo 		} else if (rec->write_mode == WRITE_APPEND) {
491d20deb64SArnaldo Carvalho de Melo 			rec->write_mode = WRITE_FORCE;
492266e0e21SPierre Habouzit 		}
493d7065adbSFranck Bui-Huu 	}
49486470930SIngo Molnar 
495f887f301SXiao Guangrong 	flags = O_CREAT|O_RDWR;
496d20deb64SArnaldo Carvalho de Melo 	if (rec->write_mode == WRITE_APPEND)
497d20deb64SArnaldo Carvalho de Melo 		rec->file_new = 0;
49886470930SIngo Molnar 	else
49986470930SIngo Molnar 		flags |= O_TRUNC;
50086470930SIngo Molnar 
501d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output)
502529870e3STom Zanussi 		output = STDOUT_FILENO;
503529870e3STom Zanussi 	else
50486470930SIngo Molnar 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
50586470930SIngo Molnar 	if (output < 0) {
50686470930SIngo Molnar 		perror("failed to create output file");
5078d3eca20SDavid Ahern 		return -1;
50886470930SIngo Molnar 	}
50986470930SIngo Molnar 
510d20deb64SArnaldo Carvalho de Melo 	rec->output = output;
511d20deb64SArnaldo Carvalho de Melo 
5127865e817SFrederic Weisbecker 	session = perf_session__new(output_name, O_WRONLY,
513d20deb64SArnaldo Carvalho de Melo 				    rec->write_mode == WRITE_FORCE, false, NULL);
51494c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
515a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
516a9a70bbcSArnaldo Carvalho de Melo 		return -1;
517a9a70bbcSArnaldo Carvalho de Melo 	}
518a9a70bbcSArnaldo Carvalho de Melo 
519d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
520d20deb64SArnaldo Carvalho de Melo 
521781ba9d2SRobert Richter 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
522781ba9d2SRobert Richter 		perf_header__set_feat(&session->header, feat);
523781ba9d2SRobert Richter 
524781ba9d2SRobert Richter 	if (rec->no_buildid)
525781ba9d2SRobert Richter 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
526781ba9d2SRobert Richter 
527781ba9d2SRobert Richter 	if (!have_tracepoints(&evsel_list->entries))
5282eeaaa09SStephane Eranian 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
529baa2f6ceSArnaldo Carvalho de Melo 
530330aa675SStephane Eranian 	if (!rec->opts.branch_stack)
531330aa675SStephane Eranian 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
532330aa675SStephane Eranian 
533d20deb64SArnaldo Carvalho de Melo 	if (!rec->file_new) {
534a91e5431SArnaldo Carvalho de Melo 		err = perf_session__read_header(session, output);
5354dc0a04bSArnaldo Carvalho de Melo 		if (err < 0)
53639d17dacSArnaldo Carvalho de Melo 			goto out_delete_session;
5374dc0a04bSArnaldo Carvalho de Melo 	}
5384dc0a04bSArnaldo Carvalho de Melo 
539d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
540d20deb64SArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(evsel_list, opts, argv);
54135b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
54235b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
54335b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
544856e9660SPeter Zijlstra 		}
545856e9660SPeter Zijlstra 	}
546856e9660SPeter Zijlstra 
5478d3eca20SDavid Ahern 	if (perf_record__open(rec) != 0) {
5488d3eca20SDavid Ahern 		err = -1;
5498d3eca20SDavid Ahern 		goto out_delete_session;
5508d3eca20SDavid Ahern 	}
55186470930SIngo Molnar 
552712a4b60SArnaldo Carvalho de Melo 	/*
553d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
554712a4b60SArnaldo Carvalho de Melo 	 */
555d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
556712a4b60SArnaldo Carvalho de Melo 
557d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
558529870e3STom Zanussi 		err = perf_header__write_pipe(output);
559529870e3STom Zanussi 		if (err < 0)
5608d3eca20SDavid Ahern 			goto out_delete_session;
561d20deb64SArnaldo Carvalho de Melo 	} else if (rec->file_new) {
562a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
563361c99a6SArnaldo Carvalho de Melo 						 output, false);
564d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
5658d3eca20SDavid Ahern 			goto out_delete_session;
566d5eed904SArnaldo Carvalho de Melo 	}
5677c6a1c65SPeter Zijlstra 
568d3665498SDavid Ahern 	if (!rec->no_buildid
569e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
570d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
571e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
5728d3eca20SDavid Ahern 		err = -1;
5738d3eca20SDavid Ahern 		goto out_delete_session;
574e20960c0SRobert Richter 	}
575e20960c0SRobert Richter 
576d20deb64SArnaldo Carvalho de Melo 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
5776122e4e4SArnaldo Carvalho de Melo 
578743eb868SArnaldo Carvalho de Melo 	machine = perf_session__find_host_machine(session);
579743eb868SArnaldo Carvalho de Melo 	if (!machine) {
580743eb868SArnaldo Carvalho de Melo 		pr_err("Couldn't find native kernel information.\n");
5818d3eca20SDavid Ahern 		err = -1;
5828d3eca20SDavid Ahern 		goto out_delete_session;
583743eb868SArnaldo Carvalho de Melo 	}
584743eb868SArnaldo Carvalho de Melo 
585d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
58645694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
587a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
5882c46dbb5STom Zanussi 		if (err < 0) {
5892c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
5908d3eca20SDavid Ahern 			goto out_delete_session;
5912c46dbb5STom Zanussi 		}
592cd19a035STom Zanussi 
59345694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_event_types(tool, process_synthesized_event,
594743eb868SArnaldo Carvalho de Melo 							 machine);
595cd19a035STom Zanussi 		if (err < 0) {
596cd19a035STom Zanussi 			pr_err("Couldn't synthesize event_types.\n");
5978d3eca20SDavid Ahern 			goto out_delete_session;
598cd19a035STom Zanussi 		}
5999215545eSTom Zanussi 
600361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
60163e0c771STom Zanussi 			/*
60263e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
60363e0c771STom Zanussi 			 * there were no tracepoints so its not really
60463e0c771STom Zanussi 			 * an error, just that we don't need to
60563e0c771STom Zanussi 			 * synthesize anything.  We really have to
60663e0c771STom Zanussi 			 * return this more properly and also
60763e0c771STom Zanussi 			 * propagate errors that now are calling die()
60863e0c771STom Zanussi 			 */
60945694aa7SArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
610743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
61163e0c771STom Zanussi 			if (err <= 0) {
61263e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
6138d3eca20SDavid Ahern 				goto out_delete_session;
61463e0c771STom Zanussi 			}
615d20deb64SArnaldo Carvalho de Melo 			advance_output(rec, err);
6162c46dbb5STom Zanussi 		}
61763e0c771STom Zanussi 	}
6182c46dbb5STom Zanussi 
61945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
620743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
62170162138SArnaldo Carvalho de Melo 	if (err < 0)
62245694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
623743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
624c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
625c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
626c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
627c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
62856b03f3cSArnaldo Carvalho de Melo 
62945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
630743eb868SArnaldo Carvalho de Melo 					     machine);
631c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
632c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
633c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
634c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
635c1a3a4b9SArnaldo Carvalho de Melo 
636a1645ce1SZhang, Yanmin 	if (perf_guest)
63745694aa7SArnaldo Carvalho de Melo 		perf_session__process_machines(session, tool,
6388115d60cSArnaldo Carvalho de Melo 					       perf_event__synthesize_guest_os);
639b7cece76SArnaldo Carvalho de Melo 
640bea03405SNamhyung Kim 	if (!opts->target.system_wide)
6418d3eca20SDavid Ahern 		err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
6428115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
643743eb868SArnaldo Carvalho de Melo 						  machine);
644234fbbf5SArnaldo Carvalho de Melo 	else
6458d3eca20SDavid Ahern 		err = perf_event__synthesize_threads(tool, process_synthesized_event,
646743eb868SArnaldo Carvalho de Melo 					       machine);
6477c6a1c65SPeter Zijlstra 
6488d3eca20SDavid Ahern 	if (err != 0)
6498d3eca20SDavid Ahern 		goto out_delete_session;
6508d3eca20SDavid Ahern 
651d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
65286470930SIngo Molnar 		struct sched_param param;
65386470930SIngo Molnar 
654d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
65586470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
6566beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
6578d3eca20SDavid Ahern 			err = -1;
6588d3eca20SDavid Ahern 			goto out_delete_session;
65986470930SIngo Molnar 		}
66086470930SIngo Molnar 	}
66186470930SIngo Molnar 
662764e16a3SDavid Ahern 	perf_evlist__enable(evsel_list);
663764e16a3SDavid Ahern 
664856e9660SPeter Zijlstra 	/*
665856e9660SPeter Zijlstra 	 * Let the child rip
666856e9660SPeter Zijlstra 	 */
667d4db3f16SArnaldo Carvalho de Melo 	if (forks)
66835b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
669856e9660SPeter Zijlstra 
670649c48a9SPeter Zijlstra 	for (;;) {
671d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
67286470930SIngo Molnar 
6738d3eca20SDavid Ahern 		if (perf_record__mmap_read_all(rec) < 0) {
6748d3eca20SDavid Ahern 			err = -1;
6758d3eca20SDavid Ahern 			goto out_delete_session;
6768d3eca20SDavid Ahern 		}
67786470930SIngo Molnar 
678d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
679649c48a9SPeter Zijlstra 			if (done)
680649c48a9SPeter Zijlstra 				break;
6815c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
6828b412664SPeter Zijlstra 			waking++;
6838b412664SPeter Zijlstra 		}
6848b412664SPeter Zijlstra 
6854152ab37SArnaldo Carvalho de Melo 		if (done)
6864152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
6878b412664SPeter Zijlstra 	}
6888b412664SPeter Zijlstra 
68918483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
690b44308f5SArnaldo Carvalho de Melo 		return 0;
691b44308f5SArnaldo Carvalho de Melo 
6928b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
69386470930SIngo Molnar 
69486470930SIngo Molnar 	/*
69586470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
69686470930SIngo Molnar 	 */
69786470930SIngo Molnar 	fprintf(stderr,
6989486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
699d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
70086470930SIngo Molnar 		output_name,
701d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
70286470930SIngo Molnar 
70386470930SIngo Molnar 	return 0;
70439d17dacSArnaldo Carvalho de Melo 
70539d17dacSArnaldo Carvalho de Melo out_delete_session:
70639d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
70739d17dacSArnaldo Carvalho de Melo 	return err;
70886470930SIngo Molnar }
70986470930SIngo Molnar 
710bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
711bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
712bdfebd84SRoberto Agostino Vitillo 
713bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
714bdfebd84SRoberto Agostino Vitillo 
715bdfebd84SRoberto Agostino Vitillo struct branch_mode {
716bdfebd84SRoberto Agostino Vitillo 	const char *name;
717bdfebd84SRoberto Agostino Vitillo 	int mode;
718bdfebd84SRoberto Agostino Vitillo };
719bdfebd84SRoberto Agostino Vitillo 
720bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
721bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
722bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
723bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
724bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
725bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
726bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
727bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
728bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
729bdfebd84SRoberto Agostino Vitillo };
730bdfebd84SRoberto Agostino Vitillo 
731bdfebd84SRoberto Agostino Vitillo static int
732a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
733bdfebd84SRoberto Agostino Vitillo {
734bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
735bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
736bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
737bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
738bdfebd84SRoberto Agostino Vitillo 
739bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
740bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
741a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
742bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
743bdfebd84SRoberto Agostino Vitillo 
744a5aabdacSStephane Eranian 	if (unset)
745a5aabdacSStephane Eranian 		return 0;
746bdfebd84SRoberto Agostino Vitillo 
747a5aabdacSStephane Eranian 	/*
748a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
749a5aabdacSStephane Eranian 	 */
750a5aabdacSStephane Eranian 	if (*mode)
751a5aabdacSStephane Eranian 		return -1;
752a5aabdacSStephane Eranian 
753a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
754a5aabdacSStephane Eranian 	if (str) {
755bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
756bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
757bdfebd84SRoberto Agostino Vitillo 		if (!s)
758bdfebd84SRoberto Agostino Vitillo 			return -1;
759bdfebd84SRoberto Agostino Vitillo 
760bdfebd84SRoberto Agostino Vitillo 		for (;;) {
761bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
762bdfebd84SRoberto Agostino Vitillo 			if (p)
763bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
764bdfebd84SRoberto Agostino Vitillo 
765bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
766bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
767bdfebd84SRoberto Agostino Vitillo 					break;
768bdfebd84SRoberto Agostino Vitillo 			}
769a5aabdacSStephane Eranian 			if (!br->name) {
770a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
771a5aabdacSStephane Eranian 					    " check man page\n", s);
772bdfebd84SRoberto Agostino Vitillo 				goto error;
773a5aabdacSStephane Eranian 			}
774bdfebd84SRoberto Agostino Vitillo 
775bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
776bdfebd84SRoberto Agostino Vitillo 
777bdfebd84SRoberto Agostino Vitillo 			if (!p)
778bdfebd84SRoberto Agostino Vitillo 				break;
779bdfebd84SRoberto Agostino Vitillo 
780bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
781bdfebd84SRoberto Agostino Vitillo 		}
782a5aabdacSStephane Eranian 	}
783bdfebd84SRoberto Agostino Vitillo 	ret = 0;
784bdfebd84SRoberto Agostino Vitillo 
785a5aabdacSStephane Eranian 	/* default to any branch */
786bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
787a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
788bdfebd84SRoberto Agostino Vitillo 	}
789bdfebd84SRoberto Agostino Vitillo error:
790bdfebd84SRoberto Agostino Vitillo 	free(os);
791bdfebd84SRoberto Agostino Vitillo 	return ret;
792bdfebd84SRoberto Agostino Vitillo }
793bdfebd84SRoberto Agostino Vitillo 
79495485b1cSNamhyung Kim #ifdef LIBUNWIND_SUPPORT
79526d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size)
79626d33022SJiri Olsa {
79726d33022SJiri Olsa 	char *endptr;
79826d33022SJiri Olsa 	unsigned long size;
79926d33022SJiri Olsa 	unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
80026d33022SJiri Olsa 
80126d33022SJiri Olsa 	size = strtoul(str, &endptr, 0);
80226d33022SJiri Olsa 
80326d33022SJiri Olsa 	do {
80426d33022SJiri Olsa 		if (*endptr)
80526d33022SJiri Olsa 			break;
80626d33022SJiri Olsa 
80726d33022SJiri Olsa 		size = round_up(size, sizeof(u64));
80826d33022SJiri Olsa 		if (!size || size > max_size)
80926d33022SJiri Olsa 			break;
81026d33022SJiri Olsa 
81126d33022SJiri Olsa 		*_size = size;
81226d33022SJiri Olsa 		return 0;
81326d33022SJiri Olsa 
81426d33022SJiri Olsa 	} while (0);
81526d33022SJiri Olsa 
81626d33022SJiri Olsa 	pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
81726d33022SJiri Olsa 	       max_size, str);
81826d33022SJiri Olsa 	return -1;
81926d33022SJiri Olsa }
82095485b1cSNamhyung Kim #endif /* LIBUNWIND_SUPPORT */
82126d33022SJiri Olsa 
82226d33022SJiri Olsa static int
8231d037ca1SIrina Tirdea parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
82426d33022SJiri Olsa 		    int unset)
82526d33022SJiri Olsa {
82626d33022SJiri Olsa 	struct perf_record *rec = (struct perf_record *)opt->value;
82726d33022SJiri Olsa 	char *tok, *name, *saveptr = NULL;
82826d33022SJiri Olsa 	char *buf;
82926d33022SJiri Olsa 	int ret = -1;
83026d33022SJiri Olsa 
83126d33022SJiri Olsa 	/* --no-call-graph */
83226d33022SJiri Olsa 	if (unset)
83326d33022SJiri Olsa 		return 0;
83426d33022SJiri Olsa 
83526d33022SJiri Olsa 	/* We specified default option if none is provided. */
83626d33022SJiri Olsa 	BUG_ON(!arg);
83726d33022SJiri Olsa 
83826d33022SJiri Olsa 	/* We need buffer that we know we can write to. */
83926d33022SJiri Olsa 	buf = malloc(strlen(arg) + 1);
84026d33022SJiri Olsa 	if (!buf)
84126d33022SJiri Olsa 		return -ENOMEM;
84226d33022SJiri Olsa 
84326d33022SJiri Olsa 	strcpy(buf, arg);
84426d33022SJiri Olsa 
84526d33022SJiri Olsa 	tok = strtok_r((char *)buf, ",", &saveptr);
84626d33022SJiri Olsa 	name = tok ? : (char *)buf;
84726d33022SJiri Olsa 
84826d33022SJiri Olsa 	do {
84926d33022SJiri Olsa 		/* Framepointer style */
85026d33022SJiri Olsa 		if (!strncmp(name, "fp", sizeof("fp"))) {
85126d33022SJiri Olsa 			if (!strtok_r(NULL, ",", &saveptr)) {
85226d33022SJiri Olsa 				rec->opts.call_graph = CALLCHAIN_FP;
85326d33022SJiri Olsa 				ret = 0;
85426d33022SJiri Olsa 			} else
85526d33022SJiri Olsa 				pr_err("callchain: No more arguments "
85626d33022SJiri Olsa 				       "needed for -g fp\n");
85726d33022SJiri Olsa 			break;
85826d33022SJiri Olsa 
85995485b1cSNamhyung Kim #ifdef LIBUNWIND_SUPPORT
86026d33022SJiri Olsa 		/* Dwarf style */
86126d33022SJiri Olsa 		} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
862*61eaa3beSArnaldo Carvalho de Melo 			const unsigned long default_stack_dump_size = 8192;
863*61eaa3beSArnaldo Carvalho de Melo 
86426d33022SJiri Olsa 			ret = 0;
86526d33022SJiri Olsa 			rec->opts.call_graph = CALLCHAIN_DWARF;
86626d33022SJiri Olsa 			rec->opts.stack_dump_size = default_stack_dump_size;
86726d33022SJiri Olsa 
86826d33022SJiri Olsa 			tok = strtok_r(NULL, ",", &saveptr);
86926d33022SJiri Olsa 			if (tok) {
87026d33022SJiri Olsa 				unsigned long size = 0;
87126d33022SJiri Olsa 
87226d33022SJiri Olsa 				ret = get_stack_size(tok, &size);
87326d33022SJiri Olsa 				rec->opts.stack_dump_size = size;
87426d33022SJiri Olsa 			}
87526d33022SJiri Olsa 
87626d33022SJiri Olsa 			if (!ret)
87726d33022SJiri Olsa 				pr_debug("callchain: stack dump size %d\n",
87826d33022SJiri Olsa 					 rec->opts.stack_dump_size);
87995485b1cSNamhyung Kim #endif /* LIBUNWIND_SUPPORT */
88026d33022SJiri Olsa 		} else {
88126d33022SJiri Olsa 			pr_err("callchain: Unknown -g option "
88226d33022SJiri Olsa 			       "value: %s\n", arg);
88326d33022SJiri Olsa 			break;
88426d33022SJiri Olsa 		}
88526d33022SJiri Olsa 
88626d33022SJiri Olsa 	} while (0);
88726d33022SJiri Olsa 
88826d33022SJiri Olsa 	free(buf);
88926d33022SJiri Olsa 
89026d33022SJiri Olsa 	if (!ret)
89126d33022SJiri Olsa 		pr_debug("callchain: type %d\n", rec->opts.call_graph);
89226d33022SJiri Olsa 
89326d33022SJiri Olsa 	return ret;
89426d33022SJiri Olsa }
89526d33022SJiri Olsa 
89686470930SIngo Molnar static const char * const record_usage[] = {
89786470930SIngo Molnar 	"perf record [<options>] [<command>]",
89886470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
89986470930SIngo Molnar 	NULL
90086470930SIngo Molnar };
90186470930SIngo Molnar 
902d20deb64SArnaldo Carvalho de Melo /*
903d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
904d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
905d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
906d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
907d20deb64SArnaldo Carvalho de Melo  *
908d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
909d20deb64SArnaldo Carvalho de Melo  *
910d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
911d20deb64SArnaldo Carvalho de Melo  */
912d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
913d20deb64SArnaldo Carvalho de Melo 	.opts = {
914d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
915d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
916d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
917447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
918d1cb9fceSNamhyung Kim 		.target		     = {
919d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
920d1cb9fceSNamhyung Kim 		},
921d20deb64SArnaldo Carvalho de Melo 	},
922d20deb64SArnaldo Carvalho de Melo 	.write_mode = WRITE_FORCE,
923d20deb64SArnaldo Carvalho de Melo 	.file_new   = true,
924d20deb64SArnaldo Carvalho de Melo };
9257865e817SFrederic Weisbecker 
926*61eaa3beSArnaldo Carvalho de Melo #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
927*61eaa3beSArnaldo Carvalho de Melo 
928*61eaa3beSArnaldo Carvalho de Melo #ifdef LIBUNWIND_SUPPORT
929*61eaa3beSArnaldo Carvalho de Melo static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
930*61eaa3beSArnaldo Carvalho de Melo #else
931*61eaa3beSArnaldo Carvalho de Melo static const char callchain_help[] = CALLCHAIN_HELP "[fp]";
932*61eaa3beSArnaldo Carvalho de Melo #endif
933*61eaa3beSArnaldo Carvalho de Melo 
934d20deb64SArnaldo Carvalho de Melo /*
935d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
936d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
937d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
938d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
939d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
940d20deb64SArnaldo Carvalho de Melo  */
941bca647aaSTom Zanussi const struct option record_options[] = {
942d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
94386470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
944f120f9d5SJiri Olsa 		     parse_events_option),
945d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
946c171b552SLi Zefan 		     "event filter", parse_filter),
947bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
948d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
949bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
950d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
951d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
95286470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
953d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
954acac03faSKirill Smelkov 		    "collect data without buffering"),
955d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
956daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
957bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
95886470930SIngo Molnar 			    "system-wide collection from all CPUs"),
959d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('A', "append", &record.append_file,
96086470930SIngo Molnar 			    "append to the output file to do incremental profiling"),
961bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
962c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
963d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('f', "force", &record.force,
9647865e817SFrederic Weisbecker 			"overwrite existing data file (deprecated)"),
965d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
966d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('o', "output", &record.output_name, "file",
96786470930SIngo Molnar 		    "output file name"),
968d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
9692e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
970d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
971d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
97201c2d99bSArnaldo Carvalho de Melo 		     "number of mmap data pages"),
973d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
97443bece79SLin Ming 		    "put the counters into a counter group"),
97526d33022SJiri Olsa 	OPT_CALLBACK_DEFAULT('g', "call-graph", &record, "mode[,dump_size]",
97626d33022SJiri Olsa 			     callchain_help, &parse_callchain_opt,
97726d33022SJiri Olsa 			     "fp"),
978c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
9793da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
980b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
981d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
982649c48a9SPeter Zijlstra 		    "per thread counts"),
983d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
9844bba828dSAnton Blanchard 		    "Sample addresses"),
985d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
9863e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
987d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
988649c48a9SPeter Zijlstra 		    "don't sample"),
989d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
990a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
991d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
992baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
993d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
994023695d9SStephane Eranian 		     "monitor event in cgroup name only",
995023695d9SStephane Eranian 		     parse_cgroups),
996bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
997bea03405SNamhyung Kim 		   "user to profile"),
998a5aabdacSStephane Eranian 
999a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
1000a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
1001a5aabdacSStephane Eranian 		     parse_branch_stack),
1002a5aabdacSStephane Eranian 
1003a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
1004a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
1005bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
100686470930SIngo Molnar 	OPT_END()
100786470930SIngo Molnar };
100886470930SIngo Molnar 
10091d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
101086470930SIngo Molnar {
101169aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
101269aad6f1SArnaldo Carvalho de Melo 	struct perf_evsel *pos;
1013d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
1014d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
101516ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
101686470930SIngo Molnar 
10177e2ed097SArnaldo Carvalho de Melo 	evsel_list = perf_evlist__new(NULL, NULL);
1018361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
1019361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
1020361c99a6SArnaldo Carvalho de Melo 
1021d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
1022d20deb64SArnaldo Carvalho de Melo 
1023bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
1024a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
1025d67356e7SNamhyung Kim 	if (!argc && perf_target__none(&rec->opts.target))
1026bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
102786470930SIngo Molnar 
1028d20deb64SArnaldo Carvalho de Melo 	if (rec->force && rec->append_file) {
10293780f488SNamhyung Kim 		ui__error("Can't overwrite and append at the same time."
10307865e817SFrederic Weisbecker 			  " You need to choose between -f and -A");
1031bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
1032d20deb64SArnaldo Carvalho de Melo 	} else if (rec->append_file) {
1033d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_APPEND;
10347865e817SFrederic Weisbecker 	} else {
1035d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_FORCE;
10367865e817SFrederic Weisbecker 	}
10377865e817SFrederic Weisbecker 
1038bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
10393780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
1040023695d9SStephane Eranian 			  " system-wide mode\n");
1041023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
1042023695d9SStephane Eranian 	}
1043023695d9SStephane Eranian 
1044655000e7SArnaldo Carvalho de Melo 	symbol__init();
1045baa2f6ceSArnaldo Carvalho de Melo 
1046ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
1047646aaea6SArnaldo Carvalho de Melo 		pr_warning(
1048646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
1049ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
1050646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
1051646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
1052646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
1053646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
1054646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
1055ec80fde7SArnaldo Carvalho de Melo 
1056d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
1057a1ac1d3cSStephane Eranian 		disable_buildid_cache();
1058655000e7SArnaldo Carvalho de Melo 
1059361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
1060361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
106169aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
106269aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
1063bbd36e5eSPeter Zijlstra 	}
106486470930SIngo Molnar 
106516ad2ffbSNamhyung Kim 	err = perf_target__validate(&rec->opts.target);
106616ad2ffbSNamhyung Kim 	if (err) {
106716ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
106816ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
106916ad2ffbSNamhyung Kim 	}
10704bd0f2d2SNamhyung Kim 
107116ad2ffbSNamhyung Kim 	err = perf_target__parse_uid(&rec->opts.target);
107216ad2ffbSNamhyung Kim 	if (err) {
107316ad2ffbSNamhyung Kim 		int saved_errno = errno;
107416ad2ffbSNamhyung Kim 
107516ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
10763780f488SNamhyung Kim 		ui__error("%s", errbuf);
107716ad2ffbSNamhyung Kim 
107816ad2ffbSNamhyung Kim 		err = -saved_errno;
10790d37aa34SArnaldo Carvalho de Melo 		goto out_free_fd;
108016ad2ffbSNamhyung Kim 	}
10810d37aa34SArnaldo Carvalho de Melo 
108216ad2ffbSNamhyung Kim 	err = -ENOMEM;
1083b809ac10SNamhyung Kim 	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
1084dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
108569aad6f1SArnaldo Carvalho de Melo 
1086361c99a6SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evsel_list->entries, node) {
10877289f83cSArnaldo Carvalho de Melo 		if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
1088ad7f4e3fSArnaldo Carvalho de Melo 			goto out_free_fd;
1089d6d901c2SZhang, Yanmin 	}
10905c581041SArnaldo Carvalho de Melo 
1091d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_interval != ULLONG_MAX)
1092d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.user_interval;
1093d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_freq != UINT_MAX)
1094d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = rec->opts.user_freq;
1095f9212819SFrederic Weisbecker 
10967e4ff9e3SMike Galbraith 	/*
10977e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
10987e4ff9e3SMike Galbraith 	 */
1099d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.default_interval)
1100d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = 0;
1101d20deb64SArnaldo Carvalho de Melo 	else if (rec->opts.freq) {
1102d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.freq;
11037e4ff9e3SMike Galbraith 	} else {
11043780f488SNamhyung Kim 		ui__error("frequency and count are zero, aborting\n");
110539d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
11065c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
11077e4ff9e3SMike Galbraith 	}
11087e4ff9e3SMike Galbraith 
1109d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
111039d17dacSArnaldo Carvalho de Melo out_free_fd:
11117e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
1112d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
1113d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
111439d17dacSArnaldo Carvalho de Melo 	return err;
111586470930SIngo Molnar }
1116