xref: /openbmc/linux/tools/perf/builtin-record.c (revision d20deb64e0490ee9442b5181bc08a62d2cadcb90)
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"
258d06367fSArnaldo Carvalho de Melo #include "util/symbol.h"
26a12b51c4SPaul Mackerras #include "util/cpumap.h"
27fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h"
287c6a1c65SPeter Zijlstra 
2986470930SIngo Molnar #include <unistd.h>
3086470930SIngo Molnar #include <sched.h>
31a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3286470930SIngo Molnar 
337865e817SFrederic Weisbecker enum write_mode_t {
347865e817SFrederic Weisbecker 	WRITE_FORCE,
357865e817SFrederic Weisbecker 	WRITE_APPEND
367865e817SFrederic Weisbecker };
377865e817SFrederic Weisbecker 
38*d20deb64SArnaldo Carvalho de Melo struct perf_record {
39*d20deb64SArnaldo Carvalho de Melo 	struct perf_event_ops	ops;
40*d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts	opts;
41*d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
42*d20deb64SArnaldo Carvalho de Melo 	const char		*output_name;
43*d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
44*d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
45*d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
46*d20deb64SArnaldo Carvalho de Melo 	int			output;
47*d20deb64SArnaldo Carvalho de Melo 	unsigned int		page_size;
48*d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
49*d20deb64SArnaldo Carvalho de Melo 	enum write_mode_t	write_mode;
50*d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
51*d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
52*d20deb64SArnaldo Carvalho de Melo 	bool			force;
53*d20deb64SArnaldo Carvalho de Melo 	bool			file_new;
54*d20deb64SArnaldo Carvalho de Melo 	bool			append_file;
55*d20deb64SArnaldo Carvalho de Melo 	long			samples;
56*d20deb64SArnaldo Carvalho de Melo 	off_t			post_processing_offset;
570f82ebc4SArnaldo Carvalho de Melo };
5886470930SIngo Molnar 
59*d20deb64SArnaldo Carvalho de Melo static void advance_output(struct perf_record *rec, size_t size)
609215545eSTom Zanussi {
61*d20deb64SArnaldo Carvalho de Melo 	rec->bytes_written += size;
629215545eSTom Zanussi }
639215545eSTom Zanussi 
64*d20deb64SArnaldo Carvalho de Melo static void write_output(struct perf_record *rec, void *buf, size_t size)
65f5970550SPeter Zijlstra {
66f5970550SPeter Zijlstra 	while (size) {
67*d20deb64SArnaldo Carvalho de Melo 		int ret = write(rec->output, buf, size);
68f5970550SPeter Zijlstra 
69f5970550SPeter Zijlstra 		if (ret < 0)
70f5970550SPeter Zijlstra 			die("failed to write");
71f5970550SPeter Zijlstra 
72f5970550SPeter Zijlstra 		size -= ret;
73f5970550SPeter Zijlstra 		buf += ret;
74f5970550SPeter Zijlstra 
75*d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written += ret;
76f5970550SPeter Zijlstra 	}
77f5970550SPeter Zijlstra }
78f5970550SPeter Zijlstra 
79*d20deb64SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_event_ops *ops,
80*d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
818d50e5b4SArnaldo Carvalho de Melo 				     struct perf_sample *sample __used,
82d8f66248SArnaldo Carvalho de Melo 				     struct perf_session *self __used)
83234fbbf5SArnaldo Carvalho de Melo {
84*d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = container_of(ops, struct perf_record, ops);
85*d20deb64SArnaldo Carvalho de Melo 	write_output(rec, event, event->header.size);
86234fbbf5SArnaldo Carvalho de Melo 	return 0;
87234fbbf5SArnaldo Carvalho de Melo }
88234fbbf5SArnaldo Carvalho de Melo 
89*d20deb64SArnaldo Carvalho de Melo static void perf_record__mmap_read(struct perf_record *rec,
90*d20deb64SArnaldo Carvalho de Melo 				   struct perf_mmap *md)
9186470930SIngo Molnar {
92744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
9386470930SIngo Molnar 	unsigned int old = md->prev;
94*d20deb64SArnaldo Carvalho de Melo 	unsigned char *data = md->base + rec->page_size;
9586470930SIngo Molnar 	unsigned long size;
9686470930SIngo Molnar 	void *buf;
9786470930SIngo Molnar 
98dc82009aSArnaldo Carvalho de Melo 	if (old == head)
99dc82009aSArnaldo Carvalho de Melo 		return;
10086470930SIngo Molnar 
101*d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
10286470930SIngo Molnar 
10386470930SIngo Molnar 	size = head - old;
10486470930SIngo Molnar 
10586470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
10686470930SIngo Molnar 		buf = &data[old & md->mask];
10786470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
10886470930SIngo Molnar 		old += size;
10986470930SIngo Molnar 
110*d20deb64SArnaldo Carvalho de Melo 		write_output(rec, buf, size);
11186470930SIngo Molnar 	}
11286470930SIngo Molnar 
11386470930SIngo Molnar 	buf = &data[old & md->mask];
11486470930SIngo Molnar 	size = head - old;
11586470930SIngo Molnar 	old += size;
11686470930SIngo Molnar 
117*d20deb64SArnaldo Carvalho de Melo 	write_output(rec, buf, size);
11886470930SIngo Molnar 
11986470930SIngo Molnar 	md->prev = old;
120115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
12186470930SIngo Molnar }
12286470930SIngo Molnar 
12386470930SIngo Molnar static volatile int done = 0;
124f7b7c26eSPeter Zijlstra static volatile int signr = -1;
12533e49ea7SAndi Kleen static volatile int child_finished = 0;
12686470930SIngo Molnar 
12786470930SIngo Molnar static void sig_handler(int sig)
12886470930SIngo Molnar {
12933e49ea7SAndi Kleen 	if (sig == SIGCHLD)
13033e49ea7SAndi Kleen 		child_finished = 1;
13133e49ea7SAndi Kleen 
13286470930SIngo Molnar 	done = 1;
133f7b7c26eSPeter Zijlstra 	signr = sig;
134f7b7c26eSPeter Zijlstra }
135f7b7c26eSPeter Zijlstra 
136*d20deb64SArnaldo Carvalho de Melo static void perf_record__sig_exit(int exit_status __used, void *arg)
137f7b7c26eSPeter Zijlstra {
138*d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
13933e49ea7SAndi Kleen 	int status;
14033e49ea7SAndi Kleen 
141*d20deb64SArnaldo Carvalho de Melo 	if (rec->evlist->workload.pid > 0) {
14233e49ea7SAndi Kleen 		if (!child_finished)
143*d20deb64SArnaldo Carvalho de Melo 			kill(rec->evlist->workload.pid, SIGTERM);
144933da83aSChris Wilson 
14533e49ea7SAndi Kleen 		wait(&status);
14633e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
147*d20deb64SArnaldo Carvalho de Melo 			psignal(WTERMSIG(status), rec->progname);
14833e49ea7SAndi Kleen 	}
14933e49ea7SAndi Kleen 
15018483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
151f7b7c26eSPeter Zijlstra 		return;
152f7b7c26eSPeter Zijlstra 
153f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
154f7b7c26eSPeter Zijlstra 	kill(getpid(), signr);
15586470930SIngo Molnar }
15686470930SIngo Molnar 
157a91e5431SArnaldo Carvalho de Melo static bool perf_evlist__equal(struct perf_evlist *evlist,
158a91e5431SArnaldo Carvalho de Melo 			       struct perf_evlist *other)
159a91e5431SArnaldo Carvalho de Melo {
160a91e5431SArnaldo Carvalho de Melo 	struct perf_evsel *pos, *pair;
161a91e5431SArnaldo Carvalho de Melo 
162a91e5431SArnaldo Carvalho de Melo 	if (evlist->nr_entries != other->nr_entries)
163a91e5431SArnaldo Carvalho de Melo 		return false;
164a91e5431SArnaldo Carvalho de Melo 
165a91e5431SArnaldo Carvalho de Melo 	pair = list_entry(other->entries.next, struct perf_evsel, node);
166a91e5431SArnaldo Carvalho de Melo 
167a91e5431SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
168a91e5431SArnaldo Carvalho de Melo 		if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
169a91e5431SArnaldo Carvalho de Melo 			return false;
170a91e5431SArnaldo Carvalho de Melo 		pair = list_entry(pair->node.next, struct perf_evsel, node);
171a91e5431SArnaldo Carvalho de Melo 	}
172a91e5431SArnaldo Carvalho de Melo 
173a91e5431SArnaldo Carvalho de Melo 	return true;
174a91e5431SArnaldo Carvalho de Melo }
175a91e5431SArnaldo Carvalho de Melo 
176*d20deb64SArnaldo Carvalho de Melo static void perf_record__open(struct perf_record *rec)
177dd7927f4SArnaldo Carvalho de Melo {
178727ab04eSArnaldo Carvalho de Melo 	struct perf_evsel *pos, *first;
179*d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
180*d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
181*d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
182dd7927f4SArnaldo Carvalho de Melo 
183727ab04eSArnaldo Carvalho de Melo 	first = list_entry(evlist->entries.next, struct perf_evsel, node);
184727ab04eSArnaldo Carvalho de Melo 
185*d20deb64SArnaldo Carvalho de Melo 	perf_evlist__config_attrs(evlist, opts);
1860f82ebc4SArnaldo Carvalho de Melo 
187dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
188dd7927f4SArnaldo Carvalho de Melo 		struct perf_event_attr *attr = &pos->attr;
189727ab04eSArnaldo Carvalho de Melo 		struct xyarray *group_fd = NULL;
190dd7927f4SArnaldo Carvalho de Melo 		/*
191dd7927f4SArnaldo Carvalho de Melo 		 * Check if parse_single_tracepoint_event has already asked for
192dd7927f4SArnaldo Carvalho de Melo 		 * PERF_SAMPLE_TIME.
193dd7927f4SArnaldo Carvalho de Melo 		 *
194dd7927f4SArnaldo Carvalho de Melo 		 * XXX this is kludgy but short term fix for problems introduced by
195dd7927f4SArnaldo Carvalho de Melo 		 * eac23d1c that broke 'perf script' by having different sample_types
196dd7927f4SArnaldo Carvalho de Melo 		 * when using multiple tracepoint events when we use a perf binary
197dd7927f4SArnaldo Carvalho de Melo 		 * that tries to use sample_id_all on an older kernel.
198dd7927f4SArnaldo Carvalho de Melo 		 *
199dd7927f4SArnaldo Carvalho de Melo 		 * We need to move counter creation to perf_session, support
200dd7927f4SArnaldo Carvalho de Melo 		 * different sample_types, etc.
201dd7927f4SArnaldo Carvalho de Melo 		 */
202dd7927f4SArnaldo Carvalho de Melo 		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
203dd7927f4SArnaldo Carvalho de Melo 
204*d20deb64SArnaldo Carvalho de Melo 		if (opts->group && pos != first)
205727ab04eSArnaldo Carvalho de Melo 			group_fd = first->fd;
2069c90a61cSArnaldo Carvalho de Melo retry_sample_id:
207*d20deb64SArnaldo Carvalho de Melo 		attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
2083da297a6SIngo Molnar try_again:
209ed80f581SArnaldo Carvalho de Melo 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
210*d20deb64SArnaldo Carvalho de Melo 				     opts->group, group_fd) < 0) {
21186470930SIngo Molnar 			int err = errno;
21286470930SIngo Molnar 
213c286c419SArnaldo Carvalho de Melo 			if (err == EPERM || err == EACCES) {
214b8631e6eSArnaldo Carvalho de Melo 				ui__error_paranoid();
215c286c419SArnaldo Carvalho de Melo 				exit(EXIT_FAILURE);
216*d20deb64SArnaldo Carvalho de Melo 			} else if (err ==  ENODEV && opts->cpu_list) {
217d6d901c2SZhang, Yanmin 				die("No such device - did you specify"
218d6d901c2SZhang, Yanmin 					" an out-of-range profile CPU?\n");
219*d20deb64SArnaldo Carvalho de Melo 			} else if (err == EINVAL && opts->sample_id_all_avail) {
2209c90a61cSArnaldo Carvalho de Melo 				/*
2219c90a61cSArnaldo Carvalho de Melo 				 * Old kernel, no attr->sample_id_type_all field
2229c90a61cSArnaldo Carvalho de Melo 				 */
223*d20deb64SArnaldo Carvalho de Melo 				opts->sample_id_all_avail = false;
224*d20deb64SArnaldo Carvalho de Melo 				if (!opts->sample_time && !opts->raw_samples && !time_needed)
225eac23d1cSIan Munsie 					attr->sample_type &= ~PERF_SAMPLE_TIME;
226eac23d1cSIan Munsie 
2279c90a61cSArnaldo Carvalho de Melo 				goto retry_sample_id;
228d6d901c2SZhang, Yanmin 			}
2293da297a6SIngo Molnar 
2303da297a6SIngo Molnar 			/*
2313da297a6SIngo Molnar 			 * If it's cycles then fall back to hrtimer
2323da297a6SIngo Molnar 			 * based cpu-clock-tick sw counter, which
2333da297a6SIngo Molnar 			 * is always available even if no PMU support:
2343da297a6SIngo Molnar 			 */
2353da297a6SIngo Molnar 			if (attr->type == PERF_TYPE_HARDWARE
236f4dbfa8fSPeter Zijlstra 					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {
2373da297a6SIngo Molnar 
2383da297a6SIngo Molnar 				if (verbose)
239ca6a4258SDavid Ahern 					ui__warning("The cycles event is not supported, "
240ca6a4258SDavid Ahern 						    "trying to fall back to cpu-clock-ticks\n");
2413da297a6SIngo Molnar 				attr->type = PERF_TYPE_SOFTWARE;
242f4dbfa8fSPeter Zijlstra 				attr->config = PERF_COUNT_SW_CPU_CLOCK;
2433da297a6SIngo Molnar 				goto try_again;
2443da297a6SIngo Molnar 			}
245ca6a4258SDavid Ahern 
246ca6a4258SDavid Ahern 			if (err == ENOENT) {
247ca6a4258SDavid Ahern 				ui__warning("The %s event is not supported.\n",
248ca6a4258SDavid Ahern 					    event_name(pos));
249ca6a4258SDavid Ahern 				exit(EXIT_FAILURE);
250ca6a4258SDavid Ahern 			}
251ca6a4258SDavid Ahern 
25230c806a0SIngo Molnar 			printf("\n");
253d9cf837eSCorey Ashford 			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
254dd7927f4SArnaldo Carvalho de Melo 			      err, strerror(err));
255bfd45118SSimon Kaempflein 
256bfd45118SSimon Kaempflein #if defined(__i386__) || defined(__x86_64__)
257bfd45118SSimon Kaempflein 			if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
258d6d901c2SZhang, Yanmin 				die("No hardware sampling interrupt available."
259d6d901c2SZhang, Yanmin 				    " No APIC? If so then you can boot the kernel"
260d6d901c2SZhang, Yanmin 				    " with the \"lapic\" boot parameter to"
261d6d901c2SZhang, Yanmin 				    " force-enable it.\n");
262bfd45118SSimon Kaempflein #endif
263bfd45118SSimon Kaempflein 
264cdd6c482SIngo Molnar 			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
2657c6a1c65SPeter Zijlstra 		}
2667c6a1c65SPeter Zijlstra 	}
2677c6a1c65SPeter Zijlstra 
2680a102479SFrederic Weisbecker 	if (perf_evlist__set_filters(evlist)) {
2690a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2700a102479SFrederic Weisbecker 			strerror(errno));
2710a102479SFrederic Weisbecker 		exit(-1);
2720a102479SFrederic Weisbecker 	}
2730a102479SFrederic Weisbecker 
274*d20deb64SArnaldo Carvalho de Melo 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0)
2750a27d7f9SArnaldo Carvalho de Melo 		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
2760a27d7f9SArnaldo Carvalho de Melo 
277*d20deb64SArnaldo Carvalho de Melo 	if (rec->file_new)
278a91e5431SArnaldo Carvalho de Melo 		session->evlist = evlist;
279a91e5431SArnaldo Carvalho de Melo 	else {
280a91e5431SArnaldo Carvalho de Melo 		if (!perf_evlist__equal(session->evlist, evlist)) {
281a91e5431SArnaldo Carvalho de Melo 			fprintf(stderr, "incompatible append\n");
282a91e5431SArnaldo Carvalho de Melo 			exit(-1);
283dd7927f4SArnaldo Carvalho de Melo 		}
28486470930SIngo Molnar  	}
28586470930SIngo Molnar 
286a91e5431SArnaldo Carvalho de Melo 	perf_session__update_sample_type(session);
287a91e5431SArnaldo Carvalho de Melo }
288a91e5431SArnaldo Carvalho de Melo 
289*d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
2906122e4e4SArnaldo Carvalho de Melo {
291*d20deb64SArnaldo Carvalho de Melo 	u64 size = lseek(rec->output, 0, SEEK_CUR);
2926122e4e4SArnaldo Carvalho de Melo 
2939f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2949f591fd7SArnaldo Carvalho de Melo 		return 0;
2959f591fd7SArnaldo Carvalho de Melo 
296*d20deb64SArnaldo Carvalho de Melo 	rec->session->fd = rec->output;
297*d20deb64SArnaldo Carvalho de Melo 	return __perf_session__process_events(rec->session, rec->post_processing_offset,
298*d20deb64SArnaldo Carvalho de Melo 					      size - rec->post_processing_offset,
2996122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
3006122e4e4SArnaldo Carvalho de Melo }
3016122e4e4SArnaldo Carvalho de Melo 
302*d20deb64SArnaldo Carvalho de Melo static void perf_record__exit(int status __used, void *arg)
303f5970550SPeter Zijlstra {
304*d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
305f5970550SPeter Zijlstra 
306*d20deb64SArnaldo Carvalho de Melo 	if (!rec->opts.pipe_output) {
307*d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
308*d20deb64SArnaldo Carvalho de Melo 
309*d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
310*d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
311*d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
312*d20deb64SArnaldo Carvalho de Melo 					   rec->output, true);
313*d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
314*d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
315d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
316c7929e47STom Zanussi 	}
317f5970550SPeter Zijlstra }
318f5970550SPeter Zijlstra 
3198115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
320a1645ce1SZhang, Yanmin {
321a1645ce1SZhang, Yanmin 	int err;
322*d20deb64SArnaldo Carvalho de Melo 	struct perf_event_ops *ops = data;
323*d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = container_of(ops, struct perf_record, ops);
324*d20deb64SArnaldo Carvalho de Melo 	struct perf_session *psession = rec->session;
325a1645ce1SZhang, Yanmin 
32623346f21SArnaldo Carvalho de Melo 	if (machine__is_host(machine))
327a1645ce1SZhang, Yanmin 		return;
328a1645ce1SZhang, Yanmin 
329a1645ce1SZhang, Yanmin 	/*
330a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
331a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
332a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
333a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
334a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
335a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
336a1645ce1SZhang, Yanmin 	 */
337*d20deb64SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(ops, process_synthesized_event,
33823346f21SArnaldo Carvalho de Melo 					     psession, machine);
339a1645ce1SZhang, Yanmin 	if (err < 0)
340a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
34123346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
342a1645ce1SZhang, Yanmin 
343a1645ce1SZhang, Yanmin 	/*
344a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
345a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
346a1645ce1SZhang, Yanmin 	 */
347*d20deb64SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
34823346f21SArnaldo Carvalho de Melo 						 psession, machine, "_text");
349a1645ce1SZhang, Yanmin 	if (err < 0)
350*d20deb64SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
3518115d60cSArnaldo Carvalho de Melo 							 psession, machine,
3528115d60cSArnaldo Carvalho de Melo 							 "_stext");
353a1645ce1SZhang, Yanmin 	if (err < 0)
354a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
35523346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
356a1645ce1SZhang, Yanmin }
357a1645ce1SZhang, Yanmin 
35898402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
35998402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
36098402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
36198402807SFrederic Weisbecker };
36298402807SFrederic Weisbecker 
363*d20deb64SArnaldo Carvalho de Melo static void perf_record__mmap_read_all(struct perf_record *rec)
36498402807SFrederic Weisbecker {
3650e2e63ddSPeter Zijlstra 	int i;
36698402807SFrederic Weisbecker 
367*d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
368*d20deb64SArnaldo Carvalho de Melo 		if (rec->evlist->mmap[i].base)
369*d20deb64SArnaldo Carvalho de Melo 			perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
37098402807SFrederic Weisbecker 	}
37198402807SFrederic Weisbecker 
372*d20deb64SArnaldo Carvalho de Melo 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
373*d20deb64SArnaldo Carvalho de Melo 		write_output(rec, &finished_round_event, sizeof(finished_round_event));
37498402807SFrederic Weisbecker }
37598402807SFrederic Weisbecker 
376*d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
37786470930SIngo Molnar {
37886470930SIngo Molnar 	struct stat st;
37986470930SIngo Molnar 	int flags;
380*d20deb64SArnaldo Carvalho de Melo 	int err, output;
3818b412664SPeter Zijlstra 	unsigned long waking = 0;
38246be604bSZhang, Yanmin 	const bool forks = argc > 0;
38323346f21SArnaldo Carvalho de Melo 	struct machine *machine;
384*d20deb64SArnaldo Carvalho de Melo 	struct perf_event_ops *ops = &rec->ops;
385*d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
386*d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
387*d20deb64SArnaldo Carvalho de Melo 	const char *output_name = rec->output_name;
388*d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
38986470930SIngo Molnar 
390*d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
39133e49ea7SAndi Kleen 
392*d20deb64SArnaldo Carvalho de Melo 	rec->page_size = sysconf(_SC_PAGE_SIZE);
39386470930SIngo Molnar 
394*d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
395f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
396f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
39718483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
398f5970550SPeter Zijlstra 
399d7065adbSFranck Bui-Huu 	if (!output_name) {
400d7065adbSFranck Bui-Huu 		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
401*d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
402d7065adbSFranck Bui-Huu 		else
403*d20deb64SArnaldo Carvalho de Melo 			rec->output_name = output_name = "perf.data";
404d7065adbSFranck Bui-Huu 	}
405d7065adbSFranck Bui-Huu 	if (output_name) {
406529870e3STom Zanussi 		if (!strcmp(output_name, "-"))
407*d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
408529870e3STom Zanussi 		else if (!stat(output_name, &st) && st.st_size) {
409*d20deb64SArnaldo Carvalho de Melo 			if (rec->write_mode == WRITE_FORCE) {
410b38d3464SArnaldo Carvalho de Melo 				char oldname[PATH_MAX];
411b38d3464SArnaldo Carvalho de Melo 				snprintf(oldname, sizeof(oldname), "%s.old",
412b38d3464SArnaldo Carvalho de Melo 					 output_name);
413b38d3464SArnaldo Carvalho de Melo 				unlink(oldname);
414b38d3464SArnaldo Carvalho de Melo 				rename(output_name, oldname);
415b38d3464SArnaldo Carvalho de Melo 			}
416*d20deb64SArnaldo Carvalho de Melo 		} else if (rec->write_mode == WRITE_APPEND) {
417*d20deb64SArnaldo Carvalho de Melo 			rec->write_mode = WRITE_FORCE;
418266e0e21SPierre Habouzit 		}
419d7065adbSFranck Bui-Huu 	}
42086470930SIngo Molnar 
421f887f301SXiao Guangrong 	flags = O_CREAT|O_RDWR;
422*d20deb64SArnaldo Carvalho de Melo 	if (rec->write_mode == WRITE_APPEND)
423*d20deb64SArnaldo Carvalho de Melo 		rec->file_new = 0;
42486470930SIngo Molnar 	else
42586470930SIngo Molnar 		flags |= O_TRUNC;
42686470930SIngo Molnar 
427*d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output)
428529870e3STom Zanussi 		output = STDOUT_FILENO;
429529870e3STom Zanussi 	else
43086470930SIngo Molnar 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
43186470930SIngo Molnar 	if (output < 0) {
43286470930SIngo Molnar 		perror("failed to create output file");
43386470930SIngo Molnar 		exit(-1);
43486470930SIngo Molnar 	}
43586470930SIngo Molnar 
436*d20deb64SArnaldo Carvalho de Melo 	rec->output = output;
437*d20deb64SArnaldo Carvalho de Melo 
4387865e817SFrederic Weisbecker 	session = perf_session__new(output_name, O_WRONLY,
439*d20deb64SArnaldo Carvalho de Melo 				    rec->write_mode == WRITE_FORCE, false, NULL);
44094c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
441a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
442a9a70bbcSArnaldo Carvalho de Melo 		return -1;
443a9a70bbcSArnaldo Carvalho de Melo 	}
444a9a70bbcSArnaldo Carvalho de Melo 
445*d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
446*d20deb64SArnaldo Carvalho de Melo 
447*d20deb64SArnaldo Carvalho de Melo 	if (!rec->no_buildid)
448baa2f6ceSArnaldo Carvalho de Melo 		perf_header__set_feat(&session->header, HEADER_BUILD_ID);
449baa2f6ceSArnaldo Carvalho de Melo 
450*d20deb64SArnaldo Carvalho de Melo 	if (!rec->file_new) {
451a91e5431SArnaldo Carvalho de Melo 		err = perf_session__read_header(session, output);
4524dc0a04bSArnaldo Carvalho de Melo 		if (err < 0)
45339d17dacSArnaldo Carvalho de Melo 			goto out_delete_session;
4544dc0a04bSArnaldo Carvalho de Melo 	}
4554dc0a04bSArnaldo Carvalho de Melo 
456361c99a6SArnaldo Carvalho de Melo 	if (have_tracepoints(&evsel_list->entries))
45794c744b6SArnaldo Carvalho de Melo 		perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
45803456a15SFrederic Weisbecker 
459fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_HOSTNAME);
460fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_OSRELEASE);
461fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_ARCH);
462fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPUDESC);
463fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_NRCPUS);
464fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
465fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CMDLINE);
466fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_VERSION);
467fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
468fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
469fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
470fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPUID);
471fbe96f29SStephane Eranian 
472d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
473*d20deb64SArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(evsel_list, opts, argv);
47435b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
47535b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
47635b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
477856e9660SPeter Zijlstra 		}
478856e9660SPeter Zijlstra 	}
479856e9660SPeter Zijlstra 
480*d20deb64SArnaldo Carvalho de Melo 	perf_record__open(rec);
48186470930SIngo Molnar 
482712a4b60SArnaldo Carvalho de Melo 	/*
483*d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
484712a4b60SArnaldo Carvalho de Melo 	 */
485*d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
486712a4b60SArnaldo Carvalho de Melo 
487*d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
488529870e3STom Zanussi 		err = perf_header__write_pipe(output);
489529870e3STom Zanussi 		if (err < 0)
490529870e3STom Zanussi 			return err;
491*d20deb64SArnaldo Carvalho de Melo 	} else if (rec->file_new) {
492a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
493361c99a6SArnaldo Carvalho de Melo 						 output, false);
494d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
495d5eed904SArnaldo Carvalho de Melo 			return err;
496d5eed904SArnaldo Carvalho de Melo 	}
4977c6a1c65SPeter Zijlstra 
498*d20deb64SArnaldo Carvalho de Melo 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
4996122e4e4SArnaldo Carvalho de Melo 
500*d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
501*d20deb64SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(ops, session,
502a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
5032c46dbb5STom Zanussi 		if (err < 0) {
5042c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
5052c46dbb5STom Zanussi 			return err;
5062c46dbb5STom Zanussi 		}
507cd19a035STom Zanussi 
508*d20deb64SArnaldo Carvalho de Melo 		err = perf_event__synthesize_event_types(ops, process_synthesized_event,
509cd19a035STom Zanussi 							 session);
510cd19a035STom Zanussi 		if (err < 0) {
511cd19a035STom Zanussi 			pr_err("Couldn't synthesize event_types.\n");
512cd19a035STom Zanussi 			return err;
513cd19a035STom Zanussi 		}
5149215545eSTom Zanussi 
515361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
51663e0c771STom Zanussi 			/*
51763e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
51863e0c771STom Zanussi 			 * there were no tracepoints so its not really
51963e0c771STom Zanussi 			 * an error, just that we don't need to
52063e0c771STom Zanussi 			 * synthesize anything.  We really have to
52163e0c771STom Zanussi 			 * return this more properly and also
52263e0c771STom Zanussi 			 * propagate errors that now are calling die()
52363e0c771STom Zanussi 			 */
524*d20deb64SArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(ops, output, evsel_list,
5259215545eSTom Zanussi 								  process_synthesized_event,
5269215545eSTom Zanussi 								  session);
52763e0c771STom Zanussi 			if (err <= 0) {
52863e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
52963e0c771STom Zanussi 				return err;
53063e0c771STom Zanussi 			}
531*d20deb64SArnaldo Carvalho de Melo 			advance_output(rec, err);
5322c46dbb5STom Zanussi 		}
53363e0c771STom Zanussi 	}
5342c46dbb5STom Zanussi 
53523346f21SArnaldo Carvalho de Melo 	machine = perf_session__find_host_machine(session);
53623346f21SArnaldo Carvalho de Melo 	if (!machine) {
537a1645ce1SZhang, Yanmin 		pr_err("Couldn't find native kernel information.\n");
538a1645ce1SZhang, Yanmin 		return -1;
539a1645ce1SZhang, Yanmin 	}
540a1645ce1SZhang, Yanmin 
541*d20deb64SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
54223346f21SArnaldo Carvalho de Melo 						 session, machine, "_text");
54370162138SArnaldo Carvalho de Melo 	if (err < 0)
544*d20deb64SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
54523346f21SArnaldo Carvalho de Melo 							 session, machine, "_stext");
546c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
547c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
548c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
549c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
55056b03f3cSArnaldo Carvalho de Melo 
551*d20deb64SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(ops, process_synthesized_event,
55223346f21SArnaldo Carvalho de Melo 					     session, machine);
553c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
554c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
555c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
556c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
557c1a3a4b9SArnaldo Carvalho de Melo 
558a1645ce1SZhang, Yanmin 	if (perf_guest)
559*d20deb64SArnaldo Carvalho de Melo 		perf_session__process_machines(session, ops,
5608115d60cSArnaldo Carvalho de Melo 					       perf_event__synthesize_guest_os);
561b7cece76SArnaldo Carvalho de Melo 
562*d20deb64SArnaldo Carvalho de Melo 	if (!opts->system_wide)
563*d20deb64SArnaldo Carvalho de Melo 		perf_event__synthesize_thread_map(ops, evsel_list->threads,
5648115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
565d8f66248SArnaldo Carvalho de Melo 						  session);
566234fbbf5SArnaldo Carvalho de Melo 	else
567*d20deb64SArnaldo Carvalho de Melo 		perf_event__synthesize_threads(ops, process_synthesized_event,
5688115d60cSArnaldo Carvalho de Melo 					       session);
5697c6a1c65SPeter Zijlstra 
570*d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
57186470930SIngo Molnar 		struct sched_param param;
57286470930SIngo Molnar 
573*d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
57486470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5756beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
57686470930SIngo Molnar 			exit(-1);
57786470930SIngo Molnar 		}
57886470930SIngo Molnar 	}
57986470930SIngo Molnar 
580764e16a3SDavid Ahern 	perf_evlist__enable(evsel_list);
581764e16a3SDavid Ahern 
582856e9660SPeter Zijlstra 	/*
583856e9660SPeter Zijlstra 	 * Let the child rip
584856e9660SPeter Zijlstra 	 */
585d4db3f16SArnaldo Carvalho de Melo 	if (forks)
58635b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
587856e9660SPeter Zijlstra 
588649c48a9SPeter Zijlstra 	for (;;) {
589*d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
59086470930SIngo Molnar 
591*d20deb64SArnaldo Carvalho de Melo 		perf_record__mmap_read_all(rec);
59286470930SIngo Molnar 
593*d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
594649c48a9SPeter Zijlstra 			if (done)
595649c48a9SPeter Zijlstra 				break;
5965c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
5978b412664SPeter Zijlstra 			waking++;
5988b412664SPeter Zijlstra 		}
5998b412664SPeter Zijlstra 
6004152ab37SArnaldo Carvalho de Melo 		if (done)
6014152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
6028b412664SPeter Zijlstra 	}
6038b412664SPeter Zijlstra 
60418483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
605b44308f5SArnaldo Carvalho de Melo 		return 0;
606b44308f5SArnaldo Carvalho de Melo 
6078b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
60886470930SIngo Molnar 
60986470930SIngo Molnar 	/*
61086470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
61186470930SIngo Molnar 	 */
61286470930SIngo Molnar 	fprintf(stderr,
6139486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
614*d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
61586470930SIngo Molnar 		output_name,
616*d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
61786470930SIngo Molnar 
61886470930SIngo Molnar 	return 0;
61939d17dacSArnaldo Carvalho de Melo 
62039d17dacSArnaldo Carvalho de Melo out_delete_session:
62139d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
62239d17dacSArnaldo Carvalho de Melo 	return err;
62386470930SIngo Molnar }
62486470930SIngo Molnar 
62586470930SIngo Molnar static const char * const record_usage[] = {
62686470930SIngo Molnar 	"perf record [<options>] [<command>]",
62786470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
62886470930SIngo Molnar 	NULL
62986470930SIngo Molnar };
63086470930SIngo Molnar 
631*d20deb64SArnaldo Carvalho de Melo /*
632*d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
633*d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
634*d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
635*d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
636*d20deb64SArnaldo Carvalho de Melo  *
637*d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
638*d20deb64SArnaldo Carvalho de Melo  *
639*d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
640*d20deb64SArnaldo Carvalho de Melo  */
641*d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
642*d20deb64SArnaldo Carvalho de Melo 	.opts = {
643*d20deb64SArnaldo Carvalho de Melo 		.target_pid	     = -1,
644*d20deb64SArnaldo Carvalho de Melo 		.target_tid	     = -1,
645*d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
646*d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
647*d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
648*d20deb64SArnaldo Carvalho de Melo 		.freq		     = 1000,
649*d20deb64SArnaldo Carvalho de Melo 		.sample_id_all_avail = true,
650*d20deb64SArnaldo Carvalho de Melo 	},
651*d20deb64SArnaldo Carvalho de Melo 	.write_mode = WRITE_FORCE,
652*d20deb64SArnaldo Carvalho de Melo 	.file_new   = true,
653*d20deb64SArnaldo Carvalho de Melo };
6547865e817SFrederic Weisbecker 
655*d20deb64SArnaldo Carvalho de Melo /*
656*d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
657*d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
658*d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
659*d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
660*d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
661*d20deb64SArnaldo Carvalho de Melo  */
662bca647aaSTom Zanussi const struct option record_options[] = {
663*d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
66486470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
665f120f9d5SJiri Olsa 		     parse_events_option),
666*d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
667c171b552SLi Zefan 		     "event filter", parse_filter),
668*d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('p', "pid", &record.opts.target_pid,
669d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
670*d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('t', "tid", &record.opts.target_tid,
671d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
672*d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
67386470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
674*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
675acac03faSKirill Smelkov 		    "collect data without buffering"),
676*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
677daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
678*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
67986470930SIngo Molnar 			    "system-wide collection from all CPUs"),
680*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('A', "append", &record.append_file,
68186470930SIngo Molnar 			    "append to the output file to do incremental profiling"),
682*d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
683c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
684*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('f', "force", &record.force,
6857865e817SFrederic Weisbecker 			"overwrite existing data file (deprecated)"),
686*d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
687*d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('o', "output", &record.output_name, "file",
68886470930SIngo Molnar 		    "output file name"),
689*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
6902e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
691*d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
692*d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
69301c2d99bSArnaldo Carvalho de Melo 		     "number of mmap data pages"),
694*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
69543bece79SLin Ming 		    "put the counters into a counter group"),
696*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
6973efa1cc9SIngo Molnar 		    "do call-graph (stack chain/backtrace) recording"),
698c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
6993da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
700b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
701*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
702649c48a9SPeter Zijlstra 		    "per thread counts"),
703*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
7044bba828dSAnton Blanchard 		    "Sample addresses"),
705*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
706*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
707649c48a9SPeter Zijlstra 		    "don't sample"),
708*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
709a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
710*d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
711baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
712*d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
713023695d9SStephane Eranian 		     "monitor event in cgroup name only",
714023695d9SStephane Eranian 		     parse_cgroups),
71586470930SIngo Molnar 	OPT_END()
71686470930SIngo Molnar };
71786470930SIngo Molnar 
718f37a291cSIngo Molnar int cmd_record(int argc, const char **argv, const char *prefix __used)
71986470930SIngo Molnar {
72069aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
72169aad6f1SArnaldo Carvalho de Melo 	struct perf_evsel *pos;
722*d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
723*d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
72486470930SIngo Molnar 
725fbe96f29SStephane Eranian 	perf_header__set_cmdline(argc, argv);
726fbe96f29SStephane Eranian 
7277e2ed097SArnaldo Carvalho de Melo 	evsel_list = perf_evlist__new(NULL, NULL);
728361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
729361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
730361c99a6SArnaldo Carvalho de Melo 
731*d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
732*d20deb64SArnaldo Carvalho de Melo 
733bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
734a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
735*d20deb64SArnaldo Carvalho de Melo 	if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
736*d20deb64SArnaldo Carvalho de Melo 		!rec->opts.system_wide && !rec->opts.cpu_list)
737bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
73886470930SIngo Molnar 
739*d20deb64SArnaldo Carvalho de Melo 	if (rec->force && rec->append_file) {
7407865e817SFrederic Weisbecker 		fprintf(stderr, "Can't overwrite and append at the same time."
7417865e817SFrederic Weisbecker 				" You need to choose between -f and -A");
742bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
743*d20deb64SArnaldo Carvalho de Melo 	} else if (rec->append_file) {
744*d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_APPEND;
7457865e817SFrederic Weisbecker 	} else {
746*d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_FORCE;
7477865e817SFrederic Weisbecker 	}
7487865e817SFrederic Weisbecker 
749*d20deb64SArnaldo Carvalho de Melo 	if (nr_cgroups && !rec->opts.system_wide) {
750023695d9SStephane Eranian 		fprintf(stderr, "cgroup monitoring only available in"
751023695d9SStephane Eranian 			" system-wide mode\n");
752023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
753023695d9SStephane Eranian 	}
754023695d9SStephane Eranian 
755655000e7SArnaldo Carvalho de Melo 	symbol__init();
756baa2f6ceSArnaldo Carvalho de Melo 
757ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
758646aaea6SArnaldo Carvalho de Melo 		pr_warning(
759646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
760ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
761646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
762646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
763646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
764646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
765646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
766ec80fde7SArnaldo Carvalho de Melo 
767*d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
768a1ac1d3cSStephane Eranian 		disable_buildid_cache();
769655000e7SArnaldo Carvalho de Melo 
770361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
771361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
77269aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
77369aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
774bbd36e5eSPeter Zijlstra 	}
77586470930SIngo Molnar 
776*d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.target_pid != -1)
777*d20deb64SArnaldo Carvalho de Melo 		rec->opts.target_tid = rec->opts.target_pid;
778d6d901c2SZhang, Yanmin 
779*d20deb64SArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
780*d20deb64SArnaldo Carvalho de Melo 				     rec->opts.target_tid, rec->opts.cpu_list) < 0)
781dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
78269aad6f1SArnaldo Carvalho de Melo 
783361c99a6SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evsel_list->entries, node) {
7847e2ed097SArnaldo Carvalho de Melo 		if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
7857e2ed097SArnaldo Carvalho de Melo 					 evsel_list->threads->nr) < 0)
78669aad6f1SArnaldo Carvalho de Melo 			goto out_free_fd;
787ad7f4e3fSArnaldo Carvalho de Melo 		if (perf_header__push_event(pos->attr.config, event_name(pos)))
788ad7f4e3fSArnaldo Carvalho de Melo 			goto out_free_fd;
789d6d901c2SZhang, Yanmin 	}
7905c581041SArnaldo Carvalho de Melo 
7917e2ed097SArnaldo Carvalho de Melo 	if (perf_evlist__alloc_pollfd(evsel_list) < 0)
79239d17dacSArnaldo Carvalho de Melo 		goto out_free_fd;
793d6d901c2SZhang, Yanmin 
794*d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_interval != ULLONG_MAX)
795*d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.user_interval;
796*d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_freq != UINT_MAX)
797*d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = rec->opts.user_freq;
798f9212819SFrederic Weisbecker 
7997e4ff9e3SMike Galbraith 	/*
8007e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
8017e4ff9e3SMike Galbraith 	 */
802*d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.default_interval)
803*d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = 0;
804*d20deb64SArnaldo Carvalho de Melo 	else if (rec->opts.freq) {
805*d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.freq;
8067e4ff9e3SMike Galbraith 	} else {
8077e4ff9e3SMike Galbraith 		fprintf(stderr, "frequency and count are zero, aborting\n");
80839d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
8095c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
8107e4ff9e3SMike Galbraith 	}
8117e4ff9e3SMike Galbraith 
812*d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
81339d17dacSArnaldo Carvalho de Melo out_free_fd:
8147e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
815d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
816d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
81739d17dacSArnaldo Carvalho de Melo 	return err;
81886470930SIngo Molnar }
819