xref: /openbmc/linux/tools/perf/builtin-record.c (revision d3665498955779e56453501a16f4ad084f798802)
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;
470d37aa34SArnaldo Carvalho de Melo 	const char		*uid_str;
48d20deb64SArnaldo Carvalho de Melo 	int			output;
49d20deb64SArnaldo Carvalho de Melo 	unsigned int		page_size;
50d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
51d20deb64SArnaldo Carvalho de Melo 	enum write_mode_t	write_mode;
52d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
53d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
54d20deb64SArnaldo Carvalho de Melo 	bool			force;
55d20deb64SArnaldo Carvalho de Melo 	bool			file_new;
56d20deb64SArnaldo Carvalho de Melo 	bool			append_file;
57d20deb64SArnaldo Carvalho de Melo 	long			samples;
58d20deb64SArnaldo Carvalho de Melo 	off_t			post_processing_offset;
590f82ebc4SArnaldo Carvalho de Melo };
6086470930SIngo Molnar 
61d20deb64SArnaldo Carvalho de Melo static void advance_output(struct perf_record *rec, size_t size)
629215545eSTom Zanussi {
63d20deb64SArnaldo Carvalho de Melo 	rec->bytes_written += size;
649215545eSTom Zanussi }
659215545eSTom Zanussi 
66d20deb64SArnaldo Carvalho de Melo static void write_output(struct perf_record *rec, void *buf, size_t size)
67f5970550SPeter Zijlstra {
68f5970550SPeter Zijlstra 	while (size) {
69d20deb64SArnaldo Carvalho de Melo 		int ret = write(rec->output, buf, size);
70f5970550SPeter Zijlstra 
71f5970550SPeter Zijlstra 		if (ret < 0)
72f5970550SPeter Zijlstra 			die("failed to write");
73f5970550SPeter Zijlstra 
74f5970550SPeter Zijlstra 		size -= ret;
75f5970550SPeter Zijlstra 		buf += ret;
76f5970550SPeter Zijlstra 
77d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written += ret;
78f5970550SPeter Zijlstra 	}
79f5970550SPeter Zijlstra }
80f5970550SPeter Zijlstra 
8145694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
82d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
838d50e5b4SArnaldo Carvalho de Melo 				     struct perf_sample *sample __used,
84743eb868SArnaldo Carvalho de Melo 				     struct machine *machine __used)
85234fbbf5SArnaldo Carvalho de Melo {
8645694aa7SArnaldo Carvalho de Melo 	struct perf_record *rec = container_of(tool, struct perf_record, tool);
87d20deb64SArnaldo Carvalho de Melo 	write_output(rec, event, event->header.size);
88234fbbf5SArnaldo Carvalho de Melo 	return 0;
89234fbbf5SArnaldo Carvalho de Melo }
90234fbbf5SArnaldo Carvalho de Melo 
91d20deb64SArnaldo Carvalho de Melo static void perf_record__mmap_read(struct perf_record *rec,
92d20deb64SArnaldo Carvalho de Melo 				   struct perf_mmap *md)
9386470930SIngo Molnar {
94744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
9586470930SIngo Molnar 	unsigned int old = md->prev;
96d20deb64SArnaldo Carvalho de Melo 	unsigned char *data = md->base + rec->page_size;
9786470930SIngo Molnar 	unsigned long size;
9886470930SIngo Molnar 	void *buf;
9986470930SIngo Molnar 
100dc82009aSArnaldo Carvalho de Melo 	if (old == head)
101dc82009aSArnaldo Carvalho de Melo 		return;
10286470930SIngo Molnar 
103d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
10486470930SIngo Molnar 
10586470930SIngo Molnar 	size = head - old;
10686470930SIngo Molnar 
10786470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
10886470930SIngo Molnar 		buf = &data[old & md->mask];
10986470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
11086470930SIngo Molnar 		old += size;
11186470930SIngo Molnar 
112d20deb64SArnaldo Carvalho de Melo 		write_output(rec, buf, size);
11386470930SIngo Molnar 	}
11486470930SIngo Molnar 
11586470930SIngo Molnar 	buf = &data[old & md->mask];
11686470930SIngo Molnar 	size = head - old;
11786470930SIngo Molnar 	old += size;
11886470930SIngo Molnar 
119d20deb64SArnaldo Carvalho de Melo 	write_output(rec, buf, size);
12086470930SIngo Molnar 
12186470930SIngo Molnar 	md->prev = old;
122115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
12386470930SIngo Molnar }
12486470930SIngo Molnar 
12586470930SIngo Molnar static volatile int done = 0;
126f7b7c26eSPeter Zijlstra static volatile int signr = -1;
12733e49ea7SAndi Kleen static volatile int child_finished = 0;
12886470930SIngo Molnar 
12986470930SIngo Molnar static void sig_handler(int sig)
13086470930SIngo Molnar {
13133e49ea7SAndi Kleen 	if (sig == SIGCHLD)
13233e49ea7SAndi Kleen 		child_finished = 1;
13333e49ea7SAndi Kleen 
13486470930SIngo Molnar 	done = 1;
135f7b7c26eSPeter Zijlstra 	signr = sig;
136f7b7c26eSPeter Zijlstra }
137f7b7c26eSPeter Zijlstra 
138d20deb64SArnaldo Carvalho de Melo static void perf_record__sig_exit(int exit_status __used, void *arg)
139f7b7c26eSPeter Zijlstra {
140d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
14133e49ea7SAndi Kleen 	int status;
14233e49ea7SAndi Kleen 
143d20deb64SArnaldo Carvalho de Melo 	if (rec->evlist->workload.pid > 0) {
14433e49ea7SAndi Kleen 		if (!child_finished)
145d20deb64SArnaldo Carvalho de Melo 			kill(rec->evlist->workload.pid, SIGTERM);
146933da83aSChris Wilson 
14733e49ea7SAndi Kleen 		wait(&status);
14833e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
149d20deb64SArnaldo Carvalho de Melo 			psignal(WTERMSIG(status), rec->progname);
15033e49ea7SAndi Kleen 	}
15133e49ea7SAndi Kleen 
15218483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
153f7b7c26eSPeter Zijlstra 		return;
154f7b7c26eSPeter Zijlstra 
155f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
156f7b7c26eSPeter Zijlstra 	kill(getpid(), signr);
15786470930SIngo Molnar }
15886470930SIngo Molnar 
159a91e5431SArnaldo Carvalho de Melo static bool perf_evlist__equal(struct perf_evlist *evlist,
160a91e5431SArnaldo Carvalho de Melo 			       struct perf_evlist *other)
161a91e5431SArnaldo Carvalho de Melo {
162a91e5431SArnaldo Carvalho de Melo 	struct perf_evsel *pos, *pair;
163a91e5431SArnaldo Carvalho de Melo 
164a91e5431SArnaldo Carvalho de Melo 	if (evlist->nr_entries != other->nr_entries)
165a91e5431SArnaldo Carvalho de Melo 		return false;
166a91e5431SArnaldo Carvalho de Melo 
167a91e5431SArnaldo Carvalho de Melo 	pair = list_entry(other->entries.next, struct perf_evsel, node);
168a91e5431SArnaldo Carvalho de Melo 
169a91e5431SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
170a91e5431SArnaldo Carvalho de Melo 		if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
171a91e5431SArnaldo Carvalho de Melo 			return false;
172a91e5431SArnaldo Carvalho de Melo 		pair = list_entry(pair->node.next, struct perf_evsel, node);
173a91e5431SArnaldo Carvalho de Melo 	}
174a91e5431SArnaldo Carvalho de Melo 
175a91e5431SArnaldo Carvalho de Melo 	return true;
176a91e5431SArnaldo Carvalho de Melo }
177a91e5431SArnaldo Carvalho de Melo 
178d20deb64SArnaldo Carvalho de Melo static void perf_record__open(struct perf_record *rec)
179dd7927f4SArnaldo Carvalho de Melo {
180727ab04eSArnaldo Carvalho de Melo 	struct perf_evsel *pos, *first;
181d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
182d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
183d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
184dd7927f4SArnaldo Carvalho de Melo 
185727ab04eSArnaldo Carvalho de Melo 	first = list_entry(evlist->entries.next, struct perf_evsel, node);
186727ab04eSArnaldo Carvalho de Melo 
187d20deb64SArnaldo Carvalho de Melo 	perf_evlist__config_attrs(evlist, opts);
1880f82ebc4SArnaldo Carvalho de Melo 
189dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
190dd7927f4SArnaldo Carvalho de Melo 		struct perf_event_attr *attr = &pos->attr;
191727ab04eSArnaldo Carvalho de Melo 		struct xyarray *group_fd = NULL;
192dd7927f4SArnaldo Carvalho de Melo 		/*
193dd7927f4SArnaldo Carvalho de Melo 		 * Check if parse_single_tracepoint_event has already asked for
194dd7927f4SArnaldo Carvalho de Melo 		 * PERF_SAMPLE_TIME.
195dd7927f4SArnaldo Carvalho de Melo 		 *
196dd7927f4SArnaldo Carvalho de Melo 		 * XXX this is kludgy but short term fix for problems introduced by
197dd7927f4SArnaldo Carvalho de Melo 		 * eac23d1c that broke 'perf script' by having different sample_types
198dd7927f4SArnaldo Carvalho de Melo 		 * when using multiple tracepoint events when we use a perf binary
199dd7927f4SArnaldo Carvalho de Melo 		 * that tries to use sample_id_all on an older kernel.
200dd7927f4SArnaldo Carvalho de Melo 		 *
201dd7927f4SArnaldo Carvalho de Melo 		 * We need to move counter creation to perf_session, support
202dd7927f4SArnaldo Carvalho de Melo 		 * different sample_types, etc.
203dd7927f4SArnaldo Carvalho de Melo 		 */
204dd7927f4SArnaldo Carvalho de Melo 		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
205dd7927f4SArnaldo Carvalho de Melo 
206d20deb64SArnaldo Carvalho de Melo 		if (opts->group && pos != first)
207727ab04eSArnaldo Carvalho de Melo 			group_fd = first->fd;
2089c90a61cSArnaldo Carvalho de Melo retry_sample_id:
209d20deb64SArnaldo Carvalho de Melo 		attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
2103da297a6SIngo Molnar try_again:
211ed80f581SArnaldo Carvalho de Melo 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
212d20deb64SArnaldo Carvalho de Melo 				     opts->group, group_fd) < 0) {
21386470930SIngo Molnar 			int err = errno;
21486470930SIngo Molnar 
215c286c419SArnaldo Carvalho de Melo 			if (err == EPERM || err == EACCES) {
216b8631e6eSArnaldo Carvalho de Melo 				ui__error_paranoid();
217c286c419SArnaldo Carvalho de Melo 				exit(EXIT_FAILURE);
218d20deb64SArnaldo Carvalho de Melo 			} else if (err ==  ENODEV && opts->cpu_list) {
219d6d901c2SZhang, Yanmin 				die("No such device - did you specify"
220d6d901c2SZhang, Yanmin 					" an out-of-range profile CPU?\n");
221d20deb64SArnaldo Carvalho de Melo 			} else if (err == EINVAL && opts->sample_id_all_avail) {
2229c90a61cSArnaldo Carvalho de Melo 				/*
2239c90a61cSArnaldo Carvalho de Melo 				 * Old kernel, no attr->sample_id_type_all field
2249c90a61cSArnaldo Carvalho de Melo 				 */
225d20deb64SArnaldo Carvalho de Melo 				opts->sample_id_all_avail = false;
226d20deb64SArnaldo Carvalho de Melo 				if (!opts->sample_time && !opts->raw_samples && !time_needed)
227eac23d1cSIan Munsie 					attr->sample_type &= ~PERF_SAMPLE_TIME;
228eac23d1cSIan Munsie 
2299c90a61cSArnaldo Carvalho de Melo 				goto retry_sample_id;
230d6d901c2SZhang, Yanmin 			}
2313da297a6SIngo Molnar 
2323da297a6SIngo Molnar 			/*
2333da297a6SIngo Molnar 			 * If it's cycles then fall back to hrtimer
2343da297a6SIngo Molnar 			 * based cpu-clock-tick sw counter, which
2353da297a6SIngo Molnar 			 * is always available even if no PMU support:
2363da297a6SIngo Molnar 			 */
2373da297a6SIngo Molnar 			if (attr->type == PERF_TYPE_HARDWARE
238f4dbfa8fSPeter Zijlstra 					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {
2393da297a6SIngo Molnar 
2403da297a6SIngo Molnar 				if (verbose)
241ca6a4258SDavid Ahern 					ui__warning("The cycles event is not supported, "
242ca6a4258SDavid Ahern 						    "trying to fall back to cpu-clock-ticks\n");
2433da297a6SIngo Molnar 				attr->type = PERF_TYPE_SOFTWARE;
244f4dbfa8fSPeter Zijlstra 				attr->config = PERF_COUNT_SW_CPU_CLOCK;
2453da297a6SIngo Molnar 				goto try_again;
2463da297a6SIngo Molnar 			}
247ca6a4258SDavid Ahern 
248ca6a4258SDavid Ahern 			if (err == ENOENT) {
249ca6a4258SDavid Ahern 				ui__warning("The %s event is not supported.\n",
250ca6a4258SDavid Ahern 					    event_name(pos));
251ca6a4258SDavid Ahern 				exit(EXIT_FAILURE);
252ca6a4258SDavid Ahern 			}
253ca6a4258SDavid Ahern 
25430c806a0SIngo Molnar 			printf("\n");
255d9cf837eSCorey Ashford 			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
256dd7927f4SArnaldo Carvalho de Melo 			      err, strerror(err));
257bfd45118SSimon Kaempflein 
258bfd45118SSimon Kaempflein #if defined(__i386__) || defined(__x86_64__)
259bfd45118SSimon Kaempflein 			if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
260d6d901c2SZhang, Yanmin 				die("No hardware sampling interrupt available."
261d6d901c2SZhang, Yanmin 				    " No APIC? If so then you can boot the kernel"
262d6d901c2SZhang, Yanmin 				    " with the \"lapic\" boot parameter to"
263d6d901c2SZhang, Yanmin 				    " force-enable it.\n");
264bfd45118SSimon Kaempflein #endif
265bfd45118SSimon Kaempflein 
266cdd6c482SIngo Molnar 			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
2677c6a1c65SPeter Zijlstra 		}
2687c6a1c65SPeter Zijlstra 	}
2697c6a1c65SPeter Zijlstra 
2700a102479SFrederic Weisbecker 	if (perf_evlist__set_filters(evlist)) {
2710a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2720a102479SFrederic Weisbecker 			strerror(errno));
2730a102479SFrederic Weisbecker 		exit(-1);
2740a102479SFrederic Weisbecker 	}
2750a102479SFrederic Weisbecker 
27618e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
27718e60939SNelson Elhage 		if (errno == EPERM)
27818e60939SNelson Elhage 			die("Permission error mapping pages.\n"
27918e60939SNelson Elhage 			    "Consider increasing "
28018e60939SNelson Elhage 			    "/proc/sys/kernel/perf_event_mlock_kb,\n"
28118e60939SNelson Elhage 			    "or try again with a smaller value of -m/--mmap_pages.\n"
28218e60939SNelson Elhage 			    "(current value: %d)\n", opts->mmap_pages);
28341d0d933SNelson Elhage 		else if (!is_power_of_2(opts->mmap_pages))
28441d0d933SNelson Elhage 			die("--mmap_pages/-m value must be a power of two.");
28541d0d933SNelson Elhage 
2860a27d7f9SArnaldo Carvalho de Melo 		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
28718e60939SNelson Elhage 	}
2880a27d7f9SArnaldo Carvalho de Melo 
289d20deb64SArnaldo Carvalho de Melo 	if (rec->file_new)
290a91e5431SArnaldo Carvalho de Melo 		session->evlist = evlist;
291a91e5431SArnaldo Carvalho de Melo 	else {
292a91e5431SArnaldo Carvalho de Melo 		if (!perf_evlist__equal(session->evlist, evlist)) {
293a91e5431SArnaldo Carvalho de Melo 			fprintf(stderr, "incompatible append\n");
294a91e5431SArnaldo Carvalho de Melo 			exit(-1);
295dd7927f4SArnaldo Carvalho de Melo 		}
29686470930SIngo Molnar  	}
29786470930SIngo Molnar 
298a91e5431SArnaldo Carvalho de Melo 	perf_session__update_sample_type(session);
299a91e5431SArnaldo Carvalho de Melo }
300a91e5431SArnaldo Carvalho de Melo 
301d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
3026122e4e4SArnaldo Carvalho de Melo {
303d20deb64SArnaldo Carvalho de Melo 	u64 size = lseek(rec->output, 0, SEEK_CUR);
3046122e4e4SArnaldo Carvalho de Melo 
3059f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
3069f591fd7SArnaldo Carvalho de Melo 		return 0;
3079f591fd7SArnaldo Carvalho de Melo 
308d20deb64SArnaldo Carvalho de Melo 	rec->session->fd = rec->output;
309d20deb64SArnaldo Carvalho de Melo 	return __perf_session__process_events(rec->session, rec->post_processing_offset,
310d20deb64SArnaldo Carvalho de Melo 					      size - rec->post_processing_offset,
3116122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
3126122e4e4SArnaldo Carvalho de Melo }
3136122e4e4SArnaldo Carvalho de Melo 
314d20deb64SArnaldo Carvalho de Melo static void perf_record__exit(int status __used, void *arg)
315f5970550SPeter Zijlstra {
316d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
317f5970550SPeter Zijlstra 
318d20deb64SArnaldo Carvalho de Melo 	if (!rec->opts.pipe_output) {
319d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
320d20deb64SArnaldo Carvalho de Melo 
321d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
322d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
323d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
324d20deb64SArnaldo Carvalho de Melo 					   rec->output, true);
325d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
326d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
327d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
328c7929e47STom Zanussi 	}
329f5970550SPeter Zijlstra }
330f5970550SPeter Zijlstra 
3318115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
332a1645ce1SZhang, Yanmin {
333a1645ce1SZhang, Yanmin 	int err;
33445694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
335a1645ce1SZhang, Yanmin 
33623346f21SArnaldo Carvalho de Melo 	if (machine__is_host(machine))
337a1645ce1SZhang, Yanmin 		return;
338a1645ce1SZhang, Yanmin 
339a1645ce1SZhang, Yanmin 	/*
340a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
341a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
342a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
343a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
344a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
345a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
346a1645ce1SZhang, Yanmin 	 */
34745694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
348743eb868SArnaldo Carvalho de Melo 					     machine);
349a1645ce1SZhang, Yanmin 	if (err < 0)
350a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
35123346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
352a1645ce1SZhang, Yanmin 
353a1645ce1SZhang, Yanmin 	/*
354a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
355a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
356a1645ce1SZhang, Yanmin 	 */
35745694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
358743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
359a1645ce1SZhang, Yanmin 	if (err < 0)
36045694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
361743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
362a1645ce1SZhang, Yanmin 	if (err < 0)
363a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
36423346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
365a1645ce1SZhang, Yanmin }
366a1645ce1SZhang, Yanmin 
36798402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
36898402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
36998402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
37098402807SFrederic Weisbecker };
37198402807SFrederic Weisbecker 
372d20deb64SArnaldo Carvalho de Melo static void perf_record__mmap_read_all(struct perf_record *rec)
37398402807SFrederic Weisbecker {
3740e2e63ddSPeter Zijlstra 	int i;
37598402807SFrederic Weisbecker 
376d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
377d20deb64SArnaldo Carvalho de Melo 		if (rec->evlist->mmap[i].base)
378d20deb64SArnaldo Carvalho de Melo 			perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
37998402807SFrederic Weisbecker 	}
38098402807SFrederic Weisbecker 
381d20deb64SArnaldo Carvalho de Melo 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
382d20deb64SArnaldo Carvalho de Melo 		write_output(rec, &finished_round_event, sizeof(finished_round_event));
38398402807SFrederic Weisbecker }
38498402807SFrederic Weisbecker 
385d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
38686470930SIngo Molnar {
38786470930SIngo Molnar 	struct stat st;
38886470930SIngo Molnar 	int flags;
389781ba9d2SRobert Richter 	int err, output, feat;
3908b412664SPeter Zijlstra 	unsigned long waking = 0;
39146be604bSZhang, Yanmin 	const bool forks = argc > 0;
39223346f21SArnaldo Carvalho de Melo 	struct machine *machine;
39345694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
394d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
395d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
396d20deb64SArnaldo Carvalho de Melo 	const char *output_name = rec->output_name;
397d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
39886470930SIngo Molnar 
399d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
40033e49ea7SAndi Kleen 
401d20deb64SArnaldo Carvalho de Melo 	rec->page_size = sysconf(_SC_PAGE_SIZE);
40286470930SIngo Molnar 
403d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
404f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
405f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
40618483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
407f5970550SPeter Zijlstra 
408d7065adbSFranck Bui-Huu 	if (!output_name) {
409d7065adbSFranck Bui-Huu 		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
410d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
411d7065adbSFranck Bui-Huu 		else
412d20deb64SArnaldo Carvalho de Melo 			rec->output_name = output_name = "perf.data";
413d7065adbSFranck Bui-Huu 	}
414d7065adbSFranck Bui-Huu 	if (output_name) {
415529870e3STom Zanussi 		if (!strcmp(output_name, "-"))
416d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
417529870e3STom Zanussi 		else if (!stat(output_name, &st) && st.st_size) {
418d20deb64SArnaldo Carvalho de Melo 			if (rec->write_mode == WRITE_FORCE) {
419b38d3464SArnaldo Carvalho de Melo 				char oldname[PATH_MAX];
420b38d3464SArnaldo Carvalho de Melo 				snprintf(oldname, sizeof(oldname), "%s.old",
421b38d3464SArnaldo Carvalho de Melo 					 output_name);
422b38d3464SArnaldo Carvalho de Melo 				unlink(oldname);
423b38d3464SArnaldo Carvalho de Melo 				rename(output_name, oldname);
424b38d3464SArnaldo Carvalho de Melo 			}
425d20deb64SArnaldo Carvalho de Melo 		} else if (rec->write_mode == WRITE_APPEND) {
426d20deb64SArnaldo Carvalho de Melo 			rec->write_mode = WRITE_FORCE;
427266e0e21SPierre Habouzit 		}
428d7065adbSFranck Bui-Huu 	}
42986470930SIngo Molnar 
430f887f301SXiao Guangrong 	flags = O_CREAT|O_RDWR;
431d20deb64SArnaldo Carvalho de Melo 	if (rec->write_mode == WRITE_APPEND)
432d20deb64SArnaldo Carvalho de Melo 		rec->file_new = 0;
43386470930SIngo Molnar 	else
43486470930SIngo Molnar 		flags |= O_TRUNC;
43586470930SIngo Molnar 
436d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output)
437529870e3STom Zanussi 		output = STDOUT_FILENO;
438529870e3STom Zanussi 	else
43986470930SIngo Molnar 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
44086470930SIngo Molnar 	if (output < 0) {
44186470930SIngo Molnar 		perror("failed to create output file");
44286470930SIngo Molnar 		exit(-1);
44386470930SIngo Molnar 	}
44486470930SIngo Molnar 
445d20deb64SArnaldo Carvalho de Melo 	rec->output = output;
446d20deb64SArnaldo Carvalho de Melo 
4477865e817SFrederic Weisbecker 	session = perf_session__new(output_name, O_WRONLY,
448d20deb64SArnaldo Carvalho de Melo 				    rec->write_mode == WRITE_FORCE, false, NULL);
44994c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
450a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
451a9a70bbcSArnaldo Carvalho de Melo 		return -1;
452a9a70bbcSArnaldo Carvalho de Melo 	}
453a9a70bbcSArnaldo Carvalho de Melo 
454d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
455d20deb64SArnaldo Carvalho de Melo 
456781ba9d2SRobert Richter 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
457781ba9d2SRobert Richter 		perf_header__set_feat(&session->header, feat);
458781ba9d2SRobert Richter 
459781ba9d2SRobert Richter 	if (rec->no_buildid)
460781ba9d2SRobert Richter 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
461781ba9d2SRobert Richter 
462781ba9d2SRobert Richter 	if (!have_tracepoints(&evsel_list->entries))
463781ba9d2SRobert Richter 		perf_header__clear_feat(&session->header, HEADER_TRACE_INFO);
464baa2f6ceSArnaldo Carvalho de Melo 
465d20deb64SArnaldo Carvalho de Melo 	if (!rec->file_new) {
466a91e5431SArnaldo Carvalho de Melo 		err = perf_session__read_header(session, output);
4674dc0a04bSArnaldo Carvalho de Melo 		if (err < 0)
46839d17dacSArnaldo Carvalho de Melo 			goto out_delete_session;
4694dc0a04bSArnaldo Carvalho de Melo 	}
4704dc0a04bSArnaldo Carvalho de Melo 
471d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
472d20deb64SArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(evsel_list, opts, argv);
47335b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
47435b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
47535b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
476856e9660SPeter Zijlstra 		}
477856e9660SPeter Zijlstra 	}
478856e9660SPeter Zijlstra 
479d20deb64SArnaldo Carvalho de Melo 	perf_record__open(rec);
48086470930SIngo Molnar 
481712a4b60SArnaldo Carvalho de Melo 	/*
482d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
483712a4b60SArnaldo Carvalho de Melo 	 */
484d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
485712a4b60SArnaldo Carvalho de Melo 
486d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
487529870e3STom Zanussi 		err = perf_header__write_pipe(output);
488529870e3STom Zanussi 		if (err < 0)
489529870e3STom Zanussi 			return err;
490d20deb64SArnaldo Carvalho de Melo 	} else if (rec->file_new) {
491a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
492361c99a6SArnaldo Carvalho de Melo 						 output, false);
493d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
494d5eed904SArnaldo Carvalho de Melo 			return err;
495d5eed904SArnaldo Carvalho de Melo 	}
4967c6a1c65SPeter Zijlstra 
497*d3665498SDavid Ahern 	if (!rec->no_buildid
498e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
499*d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
500e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
501e20960c0SRobert Richter 		return -1;
502e20960c0SRobert Richter 	}
503e20960c0SRobert Richter 
504d20deb64SArnaldo Carvalho de Melo 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
5056122e4e4SArnaldo Carvalho de Melo 
506743eb868SArnaldo Carvalho de Melo 	machine = perf_session__find_host_machine(session);
507743eb868SArnaldo Carvalho de Melo 	if (!machine) {
508743eb868SArnaldo Carvalho de Melo 		pr_err("Couldn't find native kernel information.\n");
509743eb868SArnaldo Carvalho de Melo 		return -1;
510743eb868SArnaldo Carvalho de Melo 	}
511743eb868SArnaldo Carvalho de Melo 
512d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
51345694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
514a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
5152c46dbb5STom Zanussi 		if (err < 0) {
5162c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
5172c46dbb5STom Zanussi 			return err;
5182c46dbb5STom Zanussi 		}
519cd19a035STom Zanussi 
52045694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_event_types(tool, process_synthesized_event,
521743eb868SArnaldo Carvalho de Melo 							 machine);
522cd19a035STom Zanussi 		if (err < 0) {
523cd19a035STom Zanussi 			pr_err("Couldn't synthesize event_types.\n");
524cd19a035STom Zanussi 			return err;
525cd19a035STom Zanussi 		}
5269215545eSTom Zanussi 
527361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
52863e0c771STom Zanussi 			/*
52963e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
53063e0c771STom Zanussi 			 * there were no tracepoints so its not really
53163e0c771STom Zanussi 			 * an error, just that we don't need to
53263e0c771STom Zanussi 			 * synthesize anything.  We really have to
53363e0c771STom Zanussi 			 * return this more properly and also
53463e0c771STom Zanussi 			 * propagate errors that now are calling die()
53563e0c771STom Zanussi 			 */
53645694aa7SArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
537743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
53863e0c771STom Zanussi 			if (err <= 0) {
53963e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
54063e0c771STom Zanussi 				return err;
54163e0c771STom Zanussi 			}
542d20deb64SArnaldo Carvalho de Melo 			advance_output(rec, err);
5432c46dbb5STom Zanussi 		}
54463e0c771STom Zanussi 	}
5452c46dbb5STom Zanussi 
54645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
547743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
54870162138SArnaldo Carvalho de Melo 	if (err < 0)
54945694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
550743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
551c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
552c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
553c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
554c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
55556b03f3cSArnaldo Carvalho de Melo 
55645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
557743eb868SArnaldo Carvalho de Melo 					     machine);
558c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
559c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
560c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
561c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
562c1a3a4b9SArnaldo Carvalho de Melo 
563a1645ce1SZhang, Yanmin 	if (perf_guest)
56445694aa7SArnaldo Carvalho de Melo 		perf_session__process_machines(session, tool,
5658115d60cSArnaldo Carvalho de Melo 					       perf_event__synthesize_guest_os);
566b7cece76SArnaldo Carvalho de Melo 
567d20deb64SArnaldo Carvalho de Melo 	if (!opts->system_wide)
56845694aa7SArnaldo Carvalho de Melo 		perf_event__synthesize_thread_map(tool, evsel_list->threads,
5698115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
570743eb868SArnaldo Carvalho de Melo 						  machine);
571234fbbf5SArnaldo Carvalho de Melo 	else
57245694aa7SArnaldo Carvalho de Melo 		perf_event__synthesize_threads(tool, process_synthesized_event,
573743eb868SArnaldo Carvalho de Melo 					       machine);
5747c6a1c65SPeter Zijlstra 
575d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
57686470930SIngo Molnar 		struct sched_param param;
57786470930SIngo Molnar 
578d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
57986470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5806beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
58186470930SIngo Molnar 			exit(-1);
58286470930SIngo Molnar 		}
58386470930SIngo Molnar 	}
58486470930SIngo Molnar 
585764e16a3SDavid Ahern 	perf_evlist__enable(evsel_list);
586764e16a3SDavid Ahern 
587856e9660SPeter Zijlstra 	/*
588856e9660SPeter Zijlstra 	 * Let the child rip
589856e9660SPeter Zijlstra 	 */
590d4db3f16SArnaldo Carvalho de Melo 	if (forks)
59135b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
592856e9660SPeter Zijlstra 
593649c48a9SPeter Zijlstra 	for (;;) {
594d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
59586470930SIngo Molnar 
596d20deb64SArnaldo Carvalho de Melo 		perf_record__mmap_read_all(rec);
59786470930SIngo Molnar 
598d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
599649c48a9SPeter Zijlstra 			if (done)
600649c48a9SPeter Zijlstra 				break;
6015c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
6028b412664SPeter Zijlstra 			waking++;
6038b412664SPeter Zijlstra 		}
6048b412664SPeter Zijlstra 
6054152ab37SArnaldo Carvalho de Melo 		if (done)
6064152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
6078b412664SPeter Zijlstra 	}
6088b412664SPeter Zijlstra 
60918483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
610b44308f5SArnaldo Carvalho de Melo 		return 0;
611b44308f5SArnaldo Carvalho de Melo 
6128b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
61386470930SIngo Molnar 
61486470930SIngo Molnar 	/*
61586470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
61686470930SIngo Molnar 	 */
61786470930SIngo Molnar 	fprintf(stderr,
6189486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
619d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
62086470930SIngo Molnar 		output_name,
621d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
62286470930SIngo Molnar 
62386470930SIngo Molnar 	return 0;
62439d17dacSArnaldo Carvalho de Melo 
62539d17dacSArnaldo Carvalho de Melo out_delete_session:
62639d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
62739d17dacSArnaldo Carvalho de Melo 	return err;
62886470930SIngo Molnar }
62986470930SIngo Molnar 
63086470930SIngo Molnar static const char * const record_usage[] = {
63186470930SIngo Molnar 	"perf record [<options>] [<command>]",
63286470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
63386470930SIngo Molnar 	NULL
63486470930SIngo Molnar };
63586470930SIngo Molnar 
636d20deb64SArnaldo Carvalho de Melo /*
637d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
638d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
639d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
640d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
641d20deb64SArnaldo Carvalho de Melo  *
642d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
643d20deb64SArnaldo Carvalho de Melo  *
644d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
645d20deb64SArnaldo Carvalho de Melo  */
646d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
647d20deb64SArnaldo Carvalho de Melo 	.opts = {
648d20deb64SArnaldo Carvalho de Melo 		.target_pid	     = -1,
649d20deb64SArnaldo Carvalho de Melo 		.target_tid	     = -1,
650d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
651d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
652d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
653d20deb64SArnaldo Carvalho de Melo 		.freq		     = 1000,
654d20deb64SArnaldo Carvalho de Melo 		.sample_id_all_avail = true,
655d20deb64SArnaldo Carvalho de Melo 	},
656d20deb64SArnaldo Carvalho de Melo 	.write_mode = WRITE_FORCE,
657d20deb64SArnaldo Carvalho de Melo 	.file_new   = true,
658d20deb64SArnaldo Carvalho de Melo };
6597865e817SFrederic Weisbecker 
660d20deb64SArnaldo Carvalho de Melo /*
661d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
662d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
663d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
664d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
665d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
666d20deb64SArnaldo Carvalho de Melo  */
667bca647aaSTom Zanussi const struct option record_options[] = {
668d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
66986470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
670f120f9d5SJiri Olsa 		     parse_events_option),
671d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
672c171b552SLi Zefan 		     "event filter", parse_filter),
673d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('p', "pid", &record.opts.target_pid,
674d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
675d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('t', "tid", &record.opts.target_tid,
676d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
677d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
67886470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
679d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
680acac03faSKirill Smelkov 		    "collect data without buffering"),
681d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
682daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
683d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
68486470930SIngo Molnar 			    "system-wide collection from all CPUs"),
685d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('A', "append", &record.append_file,
68686470930SIngo Molnar 			    "append to the output file to do incremental profiling"),
687d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
688c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
689d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('f', "force", &record.force,
6907865e817SFrederic Weisbecker 			"overwrite existing data file (deprecated)"),
691d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
692d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('o', "output", &record.output_name, "file",
69386470930SIngo Molnar 		    "output file name"),
694d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
6952e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
696d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
697d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
69801c2d99bSArnaldo Carvalho de Melo 		     "number of mmap data pages"),
699d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
70043bece79SLin Ming 		    "put the counters into a counter group"),
701d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
7023efa1cc9SIngo Molnar 		    "do call-graph (stack chain/backtrace) recording"),
703c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
7043da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
705b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
706d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
707649c48a9SPeter Zijlstra 		    "per thread counts"),
708d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
7094bba828dSAnton Blanchard 		    "Sample addresses"),
710d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
7113e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
712d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
713649c48a9SPeter Zijlstra 		    "don't sample"),
714d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
715a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
716d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
717baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
718d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
719023695d9SStephane Eranian 		     "monitor event in cgroup name only",
720023695d9SStephane Eranian 		     parse_cgroups),
7210d37aa34SArnaldo Carvalho de Melo 	OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
72286470930SIngo Molnar 	OPT_END()
72386470930SIngo Molnar };
72486470930SIngo Molnar 
725f37a291cSIngo Molnar int cmd_record(int argc, const char **argv, const char *prefix __used)
72686470930SIngo Molnar {
72769aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
72869aad6f1SArnaldo Carvalho de Melo 	struct perf_evsel *pos;
729d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
730d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
73186470930SIngo Molnar 
732fbe96f29SStephane Eranian 	perf_header__set_cmdline(argc, argv);
733fbe96f29SStephane Eranian 
7347e2ed097SArnaldo Carvalho de Melo 	evsel_list = perf_evlist__new(NULL, NULL);
735361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
736361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
737361c99a6SArnaldo Carvalho de Melo 
738d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
739d20deb64SArnaldo Carvalho de Melo 
740bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
741a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
742d20deb64SArnaldo Carvalho de Melo 	if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
7430d37aa34SArnaldo Carvalho de Melo 		!rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
744bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
74586470930SIngo Molnar 
746d20deb64SArnaldo Carvalho de Melo 	if (rec->force && rec->append_file) {
7477865e817SFrederic Weisbecker 		fprintf(stderr, "Can't overwrite and append at the same time."
7487865e817SFrederic Weisbecker 				" You need to choose between -f and -A");
749bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
750d20deb64SArnaldo Carvalho de Melo 	} else if (rec->append_file) {
751d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_APPEND;
7527865e817SFrederic Weisbecker 	} else {
753d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_FORCE;
7547865e817SFrederic Weisbecker 	}
7557865e817SFrederic Weisbecker 
756d20deb64SArnaldo Carvalho de Melo 	if (nr_cgroups && !rec->opts.system_wide) {
757023695d9SStephane Eranian 		fprintf(stderr, "cgroup monitoring only available in"
758023695d9SStephane Eranian 			" system-wide mode\n");
759023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
760023695d9SStephane Eranian 	}
761023695d9SStephane Eranian 
762655000e7SArnaldo Carvalho de Melo 	symbol__init();
763baa2f6ceSArnaldo Carvalho de Melo 
764ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
765646aaea6SArnaldo Carvalho de Melo 		pr_warning(
766646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
767ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
768646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
769646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
770646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
771646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
772646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
773ec80fde7SArnaldo Carvalho de Melo 
774d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
775a1ac1d3cSStephane Eranian 		disable_buildid_cache();
776655000e7SArnaldo Carvalho de Melo 
777361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
778361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
77969aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
78069aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
781bbd36e5eSPeter Zijlstra 	}
78286470930SIngo Molnar 
7830d37aa34SArnaldo Carvalho de Melo 	rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
7840d37aa34SArnaldo Carvalho de Melo 					 rec->opts.target_pid);
7850d37aa34SArnaldo Carvalho de Melo 	if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
7860d37aa34SArnaldo Carvalho de Melo 		goto out_free_fd;
7870d37aa34SArnaldo Carvalho de Melo 
788d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.target_pid != -1)
789d20deb64SArnaldo Carvalho de Melo 		rec->opts.target_tid = rec->opts.target_pid;
790d6d901c2SZhang, Yanmin 
791d20deb64SArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
7920d37aa34SArnaldo Carvalho de Melo 				     rec->opts.target_tid, rec->opts.uid,
7930d37aa34SArnaldo Carvalho de Melo 				     rec->opts.cpu_list) < 0)
794dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
79569aad6f1SArnaldo Carvalho de Melo 
796361c99a6SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evsel_list->entries, node) {
797ad7f4e3fSArnaldo Carvalho de Melo 		if (perf_header__push_event(pos->attr.config, event_name(pos)))
798ad7f4e3fSArnaldo Carvalho de Melo 			goto out_free_fd;
799d6d901c2SZhang, Yanmin 	}
8005c581041SArnaldo Carvalho de Melo 
801d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_interval != ULLONG_MAX)
802d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.user_interval;
803d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_freq != UINT_MAX)
804d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = rec->opts.user_freq;
805f9212819SFrederic Weisbecker 
8067e4ff9e3SMike Galbraith 	/*
8077e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
8087e4ff9e3SMike Galbraith 	 */
809d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.default_interval)
810d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = 0;
811d20deb64SArnaldo Carvalho de Melo 	else if (rec->opts.freq) {
812d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.freq;
8137e4ff9e3SMike Galbraith 	} else {
8147e4ff9e3SMike Galbraith 		fprintf(stderr, "frequency and count are zero, aborting\n");
81539d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
8165c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
8177e4ff9e3SMike Galbraith 	}
8187e4ff9e3SMike Galbraith 
819d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
82039d17dacSArnaldo Carvalho de Melo out_free_fd:
8217e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
822d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
823d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
82439d17dacSArnaldo Carvalho de Melo 	return err;
82586470930SIngo Molnar }
826