xref: /openbmc/linux/tools/perf/builtin-record.c (revision 0d37aa34f8806bb443dd3c8621fd9bdbb50c58bb)
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;
47*0d37aa34SArnaldo 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;
389d20deb64SArnaldo Carvalho de Melo 	int err, output;
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 
456d20deb64SArnaldo Carvalho de Melo 	if (!rec->no_buildid)
457baa2f6ceSArnaldo Carvalho de Melo 		perf_header__set_feat(&session->header, HEADER_BUILD_ID);
458baa2f6ceSArnaldo Carvalho de Melo 
459d20deb64SArnaldo Carvalho de Melo 	if (!rec->file_new) {
460a91e5431SArnaldo Carvalho de Melo 		err = perf_session__read_header(session, output);
4614dc0a04bSArnaldo Carvalho de Melo 		if (err < 0)
46239d17dacSArnaldo Carvalho de Melo 			goto out_delete_session;
4634dc0a04bSArnaldo Carvalho de Melo 	}
4644dc0a04bSArnaldo Carvalho de Melo 
465361c99a6SArnaldo Carvalho de Melo 	if (have_tracepoints(&evsel_list->entries))
46694c744b6SArnaldo Carvalho de Melo 		perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
46703456a15SFrederic Weisbecker 
468fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_HOSTNAME);
469fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_OSRELEASE);
470fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_ARCH);
471fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPUDESC);
472fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_NRCPUS);
473fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
474fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CMDLINE);
475fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_VERSION);
476fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
477fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
478fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
479fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPUID);
480fbe96f29SStephane Eranian 
481d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
482d20deb64SArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(evsel_list, opts, argv);
48335b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
48435b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
48535b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
486856e9660SPeter Zijlstra 		}
487856e9660SPeter Zijlstra 	}
488856e9660SPeter Zijlstra 
489d20deb64SArnaldo Carvalho de Melo 	perf_record__open(rec);
49086470930SIngo Molnar 
491712a4b60SArnaldo Carvalho de Melo 	/*
492d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
493712a4b60SArnaldo Carvalho de Melo 	 */
494d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
495712a4b60SArnaldo Carvalho de Melo 
496d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
497529870e3STom Zanussi 		err = perf_header__write_pipe(output);
498529870e3STom Zanussi 		if (err < 0)
499529870e3STom Zanussi 			return err;
500d20deb64SArnaldo Carvalho de Melo 	} else if (rec->file_new) {
501a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
502361c99a6SArnaldo Carvalho de Melo 						 output, false);
503d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
504d5eed904SArnaldo Carvalho de Melo 			return err;
505d5eed904SArnaldo Carvalho de Melo 	}
5067c6a1c65SPeter Zijlstra 
507e20960c0SRobert Richter 	if (!!rec->no_buildid
508e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
509e20960c0SRobert Richter 		pr_err("Couldn't generating buildids. "
510e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
511e20960c0SRobert Richter 		return -1;
512e20960c0SRobert Richter 	}
513e20960c0SRobert Richter 
514d20deb64SArnaldo Carvalho de Melo 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
5156122e4e4SArnaldo Carvalho de Melo 
516743eb868SArnaldo Carvalho de Melo 	machine = perf_session__find_host_machine(session);
517743eb868SArnaldo Carvalho de Melo 	if (!machine) {
518743eb868SArnaldo Carvalho de Melo 		pr_err("Couldn't find native kernel information.\n");
519743eb868SArnaldo Carvalho de Melo 		return -1;
520743eb868SArnaldo Carvalho de Melo 	}
521743eb868SArnaldo Carvalho de Melo 
522d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
52345694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
524a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
5252c46dbb5STom Zanussi 		if (err < 0) {
5262c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
5272c46dbb5STom Zanussi 			return err;
5282c46dbb5STom Zanussi 		}
529cd19a035STom Zanussi 
53045694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_event_types(tool, process_synthesized_event,
531743eb868SArnaldo Carvalho de Melo 							 machine);
532cd19a035STom Zanussi 		if (err < 0) {
533cd19a035STom Zanussi 			pr_err("Couldn't synthesize event_types.\n");
534cd19a035STom Zanussi 			return err;
535cd19a035STom Zanussi 		}
5369215545eSTom Zanussi 
537361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
53863e0c771STom Zanussi 			/*
53963e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
54063e0c771STom Zanussi 			 * there were no tracepoints so its not really
54163e0c771STom Zanussi 			 * an error, just that we don't need to
54263e0c771STom Zanussi 			 * synthesize anything.  We really have to
54363e0c771STom Zanussi 			 * return this more properly and also
54463e0c771STom Zanussi 			 * propagate errors that now are calling die()
54563e0c771STom Zanussi 			 */
54645694aa7SArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
547743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
54863e0c771STom Zanussi 			if (err <= 0) {
54963e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
55063e0c771STom Zanussi 				return err;
55163e0c771STom Zanussi 			}
552d20deb64SArnaldo Carvalho de Melo 			advance_output(rec, err);
5532c46dbb5STom Zanussi 		}
55463e0c771STom Zanussi 	}
5552c46dbb5STom Zanussi 
55645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
557743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
55870162138SArnaldo Carvalho de Melo 	if (err < 0)
55945694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
560743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
561c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
562c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
563c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
564c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
56556b03f3cSArnaldo Carvalho de Melo 
56645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
567743eb868SArnaldo Carvalho de Melo 					     machine);
568c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
569c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
570c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
571c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
572c1a3a4b9SArnaldo Carvalho de Melo 
573a1645ce1SZhang, Yanmin 	if (perf_guest)
57445694aa7SArnaldo Carvalho de Melo 		perf_session__process_machines(session, tool,
5758115d60cSArnaldo Carvalho de Melo 					       perf_event__synthesize_guest_os);
576b7cece76SArnaldo Carvalho de Melo 
577d20deb64SArnaldo Carvalho de Melo 	if (!opts->system_wide)
57845694aa7SArnaldo Carvalho de Melo 		perf_event__synthesize_thread_map(tool, evsel_list->threads,
5798115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
580743eb868SArnaldo Carvalho de Melo 						  machine);
581234fbbf5SArnaldo Carvalho de Melo 	else
58245694aa7SArnaldo Carvalho de Melo 		perf_event__synthesize_threads(tool, process_synthesized_event,
583743eb868SArnaldo Carvalho de Melo 					       machine);
5847c6a1c65SPeter Zijlstra 
585d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
58686470930SIngo Molnar 		struct sched_param param;
58786470930SIngo Molnar 
588d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
58986470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5906beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
59186470930SIngo Molnar 			exit(-1);
59286470930SIngo Molnar 		}
59386470930SIngo Molnar 	}
59486470930SIngo Molnar 
595764e16a3SDavid Ahern 	perf_evlist__enable(evsel_list);
596764e16a3SDavid Ahern 
597856e9660SPeter Zijlstra 	/*
598856e9660SPeter Zijlstra 	 * Let the child rip
599856e9660SPeter Zijlstra 	 */
600d4db3f16SArnaldo Carvalho de Melo 	if (forks)
60135b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
602856e9660SPeter Zijlstra 
603649c48a9SPeter Zijlstra 	for (;;) {
604d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
60586470930SIngo Molnar 
606d20deb64SArnaldo Carvalho de Melo 		perf_record__mmap_read_all(rec);
60786470930SIngo Molnar 
608d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
609649c48a9SPeter Zijlstra 			if (done)
610649c48a9SPeter Zijlstra 				break;
6115c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
6128b412664SPeter Zijlstra 			waking++;
6138b412664SPeter Zijlstra 		}
6148b412664SPeter Zijlstra 
6154152ab37SArnaldo Carvalho de Melo 		if (done)
6164152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
6178b412664SPeter Zijlstra 	}
6188b412664SPeter Zijlstra 
61918483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
620b44308f5SArnaldo Carvalho de Melo 		return 0;
621b44308f5SArnaldo Carvalho de Melo 
6228b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
62386470930SIngo Molnar 
62486470930SIngo Molnar 	/*
62586470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
62686470930SIngo Molnar 	 */
62786470930SIngo Molnar 	fprintf(stderr,
6289486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
629d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
63086470930SIngo Molnar 		output_name,
631d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
63286470930SIngo Molnar 
63386470930SIngo Molnar 	return 0;
63439d17dacSArnaldo Carvalho de Melo 
63539d17dacSArnaldo Carvalho de Melo out_delete_session:
63639d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
63739d17dacSArnaldo Carvalho de Melo 	return err;
63886470930SIngo Molnar }
63986470930SIngo Molnar 
64086470930SIngo Molnar static const char * const record_usage[] = {
64186470930SIngo Molnar 	"perf record [<options>] [<command>]",
64286470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
64386470930SIngo Molnar 	NULL
64486470930SIngo Molnar };
64586470930SIngo Molnar 
646d20deb64SArnaldo Carvalho de Melo /*
647d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
648d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
649d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
650d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
651d20deb64SArnaldo Carvalho de Melo  *
652d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
653d20deb64SArnaldo Carvalho de Melo  *
654d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
655d20deb64SArnaldo Carvalho de Melo  */
656d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
657d20deb64SArnaldo Carvalho de Melo 	.opts = {
658d20deb64SArnaldo Carvalho de Melo 		.target_pid	     = -1,
659d20deb64SArnaldo Carvalho de Melo 		.target_tid	     = -1,
660d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
661d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
662d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
663d20deb64SArnaldo Carvalho de Melo 		.freq		     = 1000,
664d20deb64SArnaldo Carvalho de Melo 		.sample_id_all_avail = true,
665d20deb64SArnaldo Carvalho de Melo 	},
666d20deb64SArnaldo Carvalho de Melo 	.write_mode = WRITE_FORCE,
667d20deb64SArnaldo Carvalho de Melo 	.file_new   = true,
668d20deb64SArnaldo Carvalho de Melo };
6697865e817SFrederic Weisbecker 
670d20deb64SArnaldo Carvalho de Melo /*
671d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
672d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
673d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
674d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
675d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
676d20deb64SArnaldo Carvalho de Melo  */
677bca647aaSTom Zanussi const struct option record_options[] = {
678d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
67986470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
680f120f9d5SJiri Olsa 		     parse_events_option),
681d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
682c171b552SLi Zefan 		     "event filter", parse_filter),
683d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('p', "pid", &record.opts.target_pid,
684d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
685d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('t', "tid", &record.opts.target_tid,
686d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
687d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
68886470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
689d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
690acac03faSKirill Smelkov 		    "collect data without buffering"),
691d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
692daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
693d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
69486470930SIngo Molnar 			    "system-wide collection from all CPUs"),
695d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('A', "append", &record.append_file,
69686470930SIngo Molnar 			    "append to the output file to do incremental profiling"),
697d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
698c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
699d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('f', "force", &record.force,
7007865e817SFrederic Weisbecker 			"overwrite existing data file (deprecated)"),
701d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
702d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('o', "output", &record.output_name, "file",
70386470930SIngo Molnar 		    "output file name"),
704d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
7052e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
706d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
707d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
70801c2d99bSArnaldo Carvalho de Melo 		     "number of mmap data pages"),
709d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
71043bece79SLin Ming 		    "put the counters into a counter group"),
711d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
7123efa1cc9SIngo Molnar 		    "do call-graph (stack chain/backtrace) recording"),
713c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
7143da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
715b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
716d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
717649c48a9SPeter Zijlstra 		    "per thread counts"),
718d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
7194bba828dSAnton Blanchard 		    "Sample addresses"),
720d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
7213e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
722d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
723649c48a9SPeter Zijlstra 		    "don't sample"),
724d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
725a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
726d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
727baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
728d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
729023695d9SStephane Eranian 		     "monitor event in cgroup name only",
730023695d9SStephane Eranian 		     parse_cgroups),
731*0d37aa34SArnaldo Carvalho de Melo 	OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
73286470930SIngo Molnar 	OPT_END()
73386470930SIngo Molnar };
73486470930SIngo Molnar 
735f37a291cSIngo Molnar int cmd_record(int argc, const char **argv, const char *prefix __used)
73686470930SIngo Molnar {
73769aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
73869aad6f1SArnaldo Carvalho de Melo 	struct perf_evsel *pos;
739d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
740d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
74186470930SIngo Molnar 
742fbe96f29SStephane Eranian 	perf_header__set_cmdline(argc, argv);
743fbe96f29SStephane Eranian 
7447e2ed097SArnaldo Carvalho de Melo 	evsel_list = perf_evlist__new(NULL, NULL);
745361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
746361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
747361c99a6SArnaldo Carvalho de Melo 
748d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
749d20deb64SArnaldo Carvalho de Melo 
750bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
751a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
752d20deb64SArnaldo Carvalho de Melo 	if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
753*0d37aa34SArnaldo Carvalho de Melo 		!rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
754bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
75586470930SIngo Molnar 
756d20deb64SArnaldo Carvalho de Melo 	if (rec->force && rec->append_file) {
7577865e817SFrederic Weisbecker 		fprintf(stderr, "Can't overwrite and append at the same time."
7587865e817SFrederic Weisbecker 				" You need to choose between -f and -A");
759bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
760d20deb64SArnaldo Carvalho de Melo 	} else if (rec->append_file) {
761d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_APPEND;
7627865e817SFrederic Weisbecker 	} else {
763d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_FORCE;
7647865e817SFrederic Weisbecker 	}
7657865e817SFrederic Weisbecker 
766d20deb64SArnaldo Carvalho de Melo 	if (nr_cgroups && !rec->opts.system_wide) {
767023695d9SStephane Eranian 		fprintf(stderr, "cgroup monitoring only available in"
768023695d9SStephane Eranian 			" system-wide mode\n");
769023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
770023695d9SStephane Eranian 	}
771023695d9SStephane Eranian 
772655000e7SArnaldo Carvalho de Melo 	symbol__init();
773baa2f6ceSArnaldo Carvalho de Melo 
774ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
775646aaea6SArnaldo Carvalho de Melo 		pr_warning(
776646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
777ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
778646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
779646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
780646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
781646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
782646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
783ec80fde7SArnaldo Carvalho de Melo 
784d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
785a1ac1d3cSStephane Eranian 		disable_buildid_cache();
786655000e7SArnaldo Carvalho de Melo 
787361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
788361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
78969aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
79069aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
791bbd36e5eSPeter Zijlstra 	}
79286470930SIngo Molnar 
793*0d37aa34SArnaldo Carvalho de Melo 	rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
794*0d37aa34SArnaldo Carvalho de Melo 					 rec->opts.target_pid);
795*0d37aa34SArnaldo Carvalho de Melo 	if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
796*0d37aa34SArnaldo Carvalho de Melo 		goto out_free_fd;
797*0d37aa34SArnaldo Carvalho de Melo 
798d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.target_pid != -1)
799d20deb64SArnaldo Carvalho de Melo 		rec->opts.target_tid = rec->opts.target_pid;
800d6d901c2SZhang, Yanmin 
801d20deb64SArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
802*0d37aa34SArnaldo Carvalho de Melo 				     rec->opts.target_tid, rec->opts.uid,
803*0d37aa34SArnaldo Carvalho de Melo 				     rec->opts.cpu_list) < 0)
804dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
80569aad6f1SArnaldo Carvalho de Melo 
806361c99a6SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evsel_list->entries, node) {
807ad7f4e3fSArnaldo Carvalho de Melo 		if (perf_header__push_event(pos->attr.config, event_name(pos)))
808ad7f4e3fSArnaldo Carvalho de Melo 			goto out_free_fd;
809d6d901c2SZhang, Yanmin 	}
8105c581041SArnaldo Carvalho de Melo 
811d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_interval != ULLONG_MAX)
812d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.user_interval;
813d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_freq != UINT_MAX)
814d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = rec->opts.user_freq;
815f9212819SFrederic Weisbecker 
8167e4ff9e3SMike Galbraith 	/*
8177e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
8187e4ff9e3SMike Galbraith 	 */
819d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.default_interval)
820d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = 0;
821d20deb64SArnaldo Carvalho de Melo 	else if (rec->opts.freq) {
822d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.freq;
8237e4ff9e3SMike Galbraith 	} else {
8247e4ff9e3SMike Galbraith 		fprintf(stderr, "frequency and count are zero, aborting\n");
82539d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
8265c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
8277e4ff9e3SMike Galbraith 	}
8287e4ff9e3SMike Galbraith 
829d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
83039d17dacSArnaldo Carvalho de Melo out_free_fd:
8317e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
832d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
833d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
83439d17dacSArnaldo Carvalho de Melo 	return err;
83586470930SIngo Molnar }
836