xref: /openbmc/linux/tools/perf/builtin-record.c (revision 35b9d88ecd8c5fb720ba0dd325262f356d0b03e7)
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 
380f82ebc4SArnaldo Carvalho de Melo static struct perf_record_opts record_opts = {
390f82ebc4SArnaldo Carvalho de Melo 	.target_pid	     = -1,
400f82ebc4SArnaldo Carvalho de Melo 	.target_tid	     = -1,
410f82ebc4SArnaldo Carvalho de Melo 	.user_freq	     = UINT_MAX,
420f82ebc4SArnaldo Carvalho de Melo 	.user_interval	     = ULLONG_MAX,
430f82ebc4SArnaldo Carvalho de Melo 	.freq		     = 1000,
440f82ebc4SArnaldo Carvalho de Melo 	.sample_id_all_avail = true,
450f82ebc4SArnaldo Carvalho de Melo };
4686470930SIngo Molnar 
4786470930SIngo Molnar static unsigned int		page_size;
48800cd25cSFrederic Weisbecker static unsigned int		mmap_pages			= UINT_MAX;
4986470930SIngo Molnar static int			output;
50d7065adbSFranck Bui-Huu static const char		*output_name			= NULL;
5143bece79SLin Ming static bool			group				=  false;
521967936dSArnaldo Carvalho de Melo static int			realtime_prio			=      0;
537865e817SFrederic Weisbecker static enum write_mode_t	write_mode			= WRITE_FORCE;
54a1ac1d3cSStephane Eranian static bool			no_buildid			=  false;
55baa2f6ceSArnaldo Carvalho de Melo static bool			no_buildid_cache		=  false;
56361c99a6SArnaldo Carvalho de Melo static struct perf_evlist	*evsel_list;
5786470930SIngo Molnar 
5842e59d7dSIngo Molnar static long			samples				=      0;
5942e59d7dSIngo Molnar static u64			bytes_written			=      0;
6086470930SIngo Molnar 
61f5970550SPeter Zijlstra static int			file_new			=      1;
626122e4e4SArnaldo Carvalho de Melo static off_t			post_processing_offset;
637c6a1c65SPeter Zijlstra 
6494c744b6SArnaldo Carvalho de Melo static struct perf_session	*session;
6533e49ea7SAndi Kleen static const char               *progname;
66f5970550SPeter Zijlstra 
679215545eSTom Zanussi static void advance_output(size_t size)
689215545eSTom Zanussi {
699215545eSTom Zanussi 	bytes_written += size;
709215545eSTom Zanussi }
719215545eSTom Zanussi 
72f5970550SPeter Zijlstra static void write_output(void *buf, size_t size)
73f5970550SPeter Zijlstra {
74f5970550SPeter Zijlstra 	while (size) {
75f5970550SPeter Zijlstra 		int ret = write(output, buf, size);
76f5970550SPeter Zijlstra 
77f5970550SPeter Zijlstra 		if (ret < 0)
78f5970550SPeter Zijlstra 			die("failed to write");
79f5970550SPeter Zijlstra 
80f5970550SPeter Zijlstra 		size -= ret;
81f5970550SPeter Zijlstra 		buf += ret;
82f5970550SPeter Zijlstra 
83f5970550SPeter Zijlstra 		bytes_written += ret;
84f5970550SPeter Zijlstra 	}
85f5970550SPeter Zijlstra }
86f5970550SPeter Zijlstra 
878115d60cSArnaldo Carvalho de Melo static int process_synthesized_event(union perf_event *event,
888d50e5b4SArnaldo Carvalho de Melo 				     struct perf_sample *sample __used,
89d8f66248SArnaldo Carvalho de Melo 				     struct perf_session *self __used)
90234fbbf5SArnaldo Carvalho de Melo {
916122e4e4SArnaldo Carvalho de Melo 	write_output(event, event->header.size);
92234fbbf5SArnaldo Carvalho de Melo 	return 0;
93234fbbf5SArnaldo Carvalho de Melo }
94234fbbf5SArnaldo Carvalho de Melo 
95744bd8aaSArnaldo Carvalho de Melo static void mmap_read(struct perf_mmap *md)
9686470930SIngo Molnar {
97744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
9886470930SIngo Molnar 	unsigned int old = md->prev;
9986470930SIngo Molnar 	unsigned char *data = md->base + page_size;
10086470930SIngo Molnar 	unsigned long size;
10186470930SIngo Molnar 	void *buf;
10286470930SIngo Molnar 
103dc82009aSArnaldo Carvalho de Melo 	if (old == head)
104dc82009aSArnaldo Carvalho de Melo 		return;
10586470930SIngo Molnar 
10686470930SIngo Molnar 	samples++;
10786470930SIngo Molnar 
10886470930SIngo Molnar 	size = head - old;
10986470930SIngo Molnar 
11086470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
11186470930SIngo Molnar 		buf = &data[old & md->mask];
11286470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
11386470930SIngo Molnar 		old += size;
11486470930SIngo Molnar 
1156122e4e4SArnaldo Carvalho de Melo 		write_output(buf, size);
11686470930SIngo Molnar 	}
11786470930SIngo Molnar 
11886470930SIngo Molnar 	buf = &data[old & md->mask];
11986470930SIngo Molnar 	size = head - old;
12086470930SIngo Molnar 	old += size;
12186470930SIngo Molnar 
1226122e4e4SArnaldo Carvalho de Melo 	write_output(buf, size);
12386470930SIngo Molnar 
12486470930SIngo Molnar 	md->prev = old;
125115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
12686470930SIngo Molnar }
12786470930SIngo Molnar 
12886470930SIngo Molnar static volatile int done = 0;
129f7b7c26eSPeter Zijlstra static volatile int signr = -1;
13033e49ea7SAndi Kleen static volatile int child_finished = 0;
13186470930SIngo Molnar 
13286470930SIngo Molnar static void sig_handler(int sig)
13386470930SIngo Molnar {
13433e49ea7SAndi Kleen 	if (sig == SIGCHLD)
13533e49ea7SAndi Kleen 		child_finished = 1;
13633e49ea7SAndi Kleen 
13786470930SIngo Molnar 	done = 1;
138f7b7c26eSPeter Zijlstra 	signr = sig;
139f7b7c26eSPeter Zijlstra }
140f7b7c26eSPeter Zijlstra 
141f7b7c26eSPeter Zijlstra static void sig_atexit(void)
142f7b7c26eSPeter Zijlstra {
14333e49ea7SAndi Kleen 	int status;
14433e49ea7SAndi Kleen 
145*35b9d88eSArnaldo Carvalho de Melo 	if (evsel_list->workload.pid > 0) {
14633e49ea7SAndi Kleen 		if (!child_finished)
147*35b9d88eSArnaldo Carvalho de Melo 			kill(evsel_list->workload.pid, SIGTERM);
148933da83aSChris Wilson 
14933e49ea7SAndi Kleen 		wait(&status);
15033e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
15133e49ea7SAndi Kleen 			psignal(WTERMSIG(status), progname);
15233e49ea7SAndi Kleen 	}
15333e49ea7SAndi Kleen 
15418483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
155f7b7c26eSPeter Zijlstra 		return;
156f7b7c26eSPeter Zijlstra 
157f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
158f7b7c26eSPeter Zijlstra 	kill(getpid(), signr);
15986470930SIngo Molnar }
16086470930SIngo Molnar 
161a91e5431SArnaldo Carvalho de Melo static bool perf_evlist__equal(struct perf_evlist *evlist,
162a91e5431SArnaldo Carvalho de Melo 			       struct perf_evlist *other)
163a91e5431SArnaldo Carvalho de Melo {
164a91e5431SArnaldo Carvalho de Melo 	struct perf_evsel *pos, *pair;
165a91e5431SArnaldo Carvalho de Melo 
166a91e5431SArnaldo Carvalho de Melo 	if (evlist->nr_entries != other->nr_entries)
167a91e5431SArnaldo Carvalho de Melo 		return false;
168a91e5431SArnaldo Carvalho de Melo 
169a91e5431SArnaldo Carvalho de Melo 	pair = list_entry(other->entries.next, struct perf_evsel, node);
170a91e5431SArnaldo Carvalho de Melo 
171a91e5431SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
172a91e5431SArnaldo Carvalho de Melo 		if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
173a91e5431SArnaldo Carvalho de Melo 			return false;
174a91e5431SArnaldo Carvalho de Melo 		pair = list_entry(pair->node.next, struct perf_evsel, node);
175a91e5431SArnaldo Carvalho de Melo 	}
176a91e5431SArnaldo Carvalho de Melo 
177a91e5431SArnaldo Carvalho de Melo 	return true;
178a91e5431SArnaldo Carvalho de Melo }
179a91e5431SArnaldo Carvalho de Melo 
180dd7927f4SArnaldo Carvalho de Melo static void open_counters(struct perf_evlist *evlist)
181dd7927f4SArnaldo Carvalho de Melo {
182727ab04eSArnaldo Carvalho de Melo 	struct perf_evsel *pos, *first;
183dd7927f4SArnaldo Carvalho de Melo 
184727ab04eSArnaldo Carvalho de Melo 	first = list_entry(evlist->entries.next, struct perf_evsel, node);
185727ab04eSArnaldo Carvalho de Melo 
1860f82ebc4SArnaldo Carvalho de Melo 	perf_evlist__config_attrs(evlist, &record_opts);
1870f82ebc4SArnaldo Carvalho de Melo 
188dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
189dd7927f4SArnaldo Carvalho de Melo 		struct perf_event_attr *attr = &pos->attr;
190727ab04eSArnaldo Carvalho de Melo 		struct xyarray *group_fd = NULL;
191dd7927f4SArnaldo Carvalho de Melo 		/*
192dd7927f4SArnaldo Carvalho de Melo 		 * Check if parse_single_tracepoint_event has already asked for
193dd7927f4SArnaldo Carvalho de Melo 		 * PERF_SAMPLE_TIME.
194dd7927f4SArnaldo Carvalho de Melo 		 *
195dd7927f4SArnaldo Carvalho de Melo 		 * XXX this is kludgy but short term fix for problems introduced by
196dd7927f4SArnaldo Carvalho de Melo 		 * eac23d1c that broke 'perf script' by having different sample_types
197dd7927f4SArnaldo Carvalho de Melo 		 * when using multiple tracepoint events when we use a perf binary
198dd7927f4SArnaldo Carvalho de Melo 		 * that tries to use sample_id_all on an older kernel.
199dd7927f4SArnaldo Carvalho de Melo 		 *
200dd7927f4SArnaldo Carvalho de Melo 		 * We need to move counter creation to perf_session, support
201dd7927f4SArnaldo Carvalho de Melo 		 * different sample_types, etc.
202dd7927f4SArnaldo Carvalho de Melo 		 */
203dd7927f4SArnaldo Carvalho de Melo 		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
204dd7927f4SArnaldo Carvalho de Melo 
205727ab04eSArnaldo Carvalho de Melo 		if (group && pos != first)
206727ab04eSArnaldo Carvalho de Melo 			group_fd = first->fd;
2079c90a61cSArnaldo Carvalho de Melo retry_sample_id:
2080f82ebc4SArnaldo Carvalho de Melo 		attr->sample_id_all = record_opts.sample_id_all_avail ? 1 : 0;
2093da297a6SIngo Molnar try_again:
210727ab04eSArnaldo Carvalho de Melo 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group,
211727ab04eSArnaldo Carvalho de Melo 				     group_fd) < 0) {
21286470930SIngo Molnar 			int err = errno;
21386470930SIngo Molnar 
214c286c419SArnaldo Carvalho de Melo 			if (err == EPERM || err == EACCES) {
215b8631e6eSArnaldo Carvalho de Melo 				ui__error_paranoid();
216c286c419SArnaldo Carvalho de Melo 				exit(EXIT_FAILURE);
2170f82ebc4SArnaldo Carvalho de Melo 			} else if (err ==  ENODEV && record_opts.cpu_list) {
218d6d901c2SZhang, Yanmin 				die("No such device - did you specify"
219d6d901c2SZhang, Yanmin 					" an out-of-range profile CPU?\n");
2200f82ebc4SArnaldo Carvalho de Melo 			} else if (err == EINVAL && record_opts.sample_id_all_avail) {
2219c90a61cSArnaldo Carvalho de Melo 				/*
2229c90a61cSArnaldo Carvalho de Melo 				 * Old kernel, no attr->sample_id_type_all field
2239c90a61cSArnaldo Carvalho de Melo 				 */
2240f82ebc4SArnaldo Carvalho de Melo 				record_opts.sample_id_all_avail = false;
2250f82ebc4SArnaldo Carvalho de Melo 				if (!record_opts.sample_time && !record_opts.raw_samples && !time_needed)
226eac23d1cSIan Munsie 					attr->sample_type &= ~PERF_SAMPLE_TIME;
227eac23d1cSIan Munsie 
2289c90a61cSArnaldo Carvalho de Melo 				goto retry_sample_id;
229d6d901c2SZhang, Yanmin 			}
2303da297a6SIngo Molnar 
2313da297a6SIngo Molnar 			/*
2323da297a6SIngo Molnar 			 * If it's cycles then fall back to hrtimer
2333da297a6SIngo Molnar 			 * based cpu-clock-tick sw counter, which
2343da297a6SIngo Molnar 			 * is always available even if no PMU support:
2353da297a6SIngo Molnar 			 */
2363da297a6SIngo Molnar 			if (attr->type == PERF_TYPE_HARDWARE
237f4dbfa8fSPeter Zijlstra 					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {
2383da297a6SIngo Molnar 
2393da297a6SIngo Molnar 				if (verbose)
240ca6a4258SDavid Ahern 					ui__warning("The cycles event is not supported, "
241ca6a4258SDavid Ahern 						    "trying to fall back to cpu-clock-ticks\n");
2423da297a6SIngo Molnar 				attr->type = PERF_TYPE_SOFTWARE;
243f4dbfa8fSPeter Zijlstra 				attr->config = PERF_COUNT_SW_CPU_CLOCK;
2443da297a6SIngo Molnar 				goto try_again;
2453da297a6SIngo Molnar 			}
246ca6a4258SDavid Ahern 
247ca6a4258SDavid Ahern 			if (err == ENOENT) {
248ca6a4258SDavid Ahern 				ui__warning("The %s event is not supported.\n",
249ca6a4258SDavid Ahern 					    event_name(pos));
250ca6a4258SDavid Ahern 				exit(EXIT_FAILURE);
251ca6a4258SDavid Ahern 			}
252ca6a4258SDavid Ahern 
25330c806a0SIngo Molnar 			printf("\n");
254d9cf837eSCorey Ashford 			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
255dd7927f4SArnaldo Carvalho de Melo 			      err, strerror(err));
256bfd45118SSimon Kaempflein 
257bfd45118SSimon Kaempflein #if defined(__i386__) || defined(__x86_64__)
258bfd45118SSimon Kaempflein 			if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
259d6d901c2SZhang, Yanmin 				die("No hardware sampling interrupt available."
260d6d901c2SZhang, Yanmin 				    " No APIC? If so then you can boot the kernel"
261d6d901c2SZhang, Yanmin 				    " with the \"lapic\" boot parameter to"
262d6d901c2SZhang, Yanmin 				    " force-enable it.\n");
263bfd45118SSimon Kaempflein #endif
264bfd45118SSimon Kaempflein 
265cdd6c482SIngo Molnar 			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
2667c6a1c65SPeter Zijlstra 		}
2677c6a1c65SPeter Zijlstra 	}
2687c6a1c65SPeter Zijlstra 
2690a102479SFrederic Weisbecker 	if (perf_evlist__set_filters(evlist)) {
2700a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2710a102479SFrederic Weisbecker 			strerror(errno));
2720a102479SFrederic Weisbecker 		exit(-1);
2730a102479SFrederic Weisbecker 	}
2740a102479SFrederic Weisbecker 
2757e2ed097SArnaldo Carvalho de Melo 	if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
2760a27d7f9SArnaldo Carvalho de Melo 		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
2770a27d7f9SArnaldo Carvalho de Melo 
278a91e5431SArnaldo Carvalho de Melo 	if (file_new)
279a91e5431SArnaldo Carvalho de Melo 		session->evlist = evlist;
280a91e5431SArnaldo Carvalho de Melo 	else {
281a91e5431SArnaldo Carvalho de Melo 		if (!perf_evlist__equal(session->evlist, evlist)) {
282a91e5431SArnaldo Carvalho de Melo 			fprintf(stderr, "incompatible append\n");
283a91e5431SArnaldo Carvalho de Melo 			exit(-1);
284dd7927f4SArnaldo Carvalho de Melo 		}
28586470930SIngo Molnar  	}
28686470930SIngo Molnar 
287a91e5431SArnaldo Carvalho de Melo 	perf_session__update_sample_type(session);
288a91e5431SArnaldo Carvalho de Melo }
289a91e5431SArnaldo Carvalho de Melo 
2906122e4e4SArnaldo Carvalho de Melo static int process_buildids(void)
2916122e4e4SArnaldo Carvalho de Melo {
2926122e4e4SArnaldo Carvalho de Melo 	u64 size = lseek(output, 0, SEEK_CUR);
2936122e4e4SArnaldo Carvalho de Melo 
2949f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
2959f591fd7SArnaldo Carvalho de Melo 		return 0;
2969f591fd7SArnaldo Carvalho de Melo 
2976122e4e4SArnaldo Carvalho de Melo 	session->fd = output;
2986122e4e4SArnaldo Carvalho de Melo 	return __perf_session__process_events(session, post_processing_offset,
2996122e4e4SArnaldo Carvalho de Melo 					      size - post_processing_offset,
3006122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
3016122e4e4SArnaldo Carvalho de Melo }
3026122e4e4SArnaldo Carvalho de Melo 
303f5970550SPeter Zijlstra static void atexit_header(void)
304f5970550SPeter Zijlstra {
305*35b9d88eSArnaldo Carvalho de Melo 	if (!record_opts.pipe_output) {
30694c744b6SArnaldo Carvalho de Melo 		session->header.data_size += bytes_written;
307f5970550SPeter Zijlstra 
308baa2f6ceSArnaldo Carvalho de Melo 		if (!no_buildid)
3096122e4e4SArnaldo Carvalho de Melo 			process_buildids();
310a91e5431SArnaldo Carvalho de Melo 		perf_session__write_header(session, evsel_list, output, true);
31139d17dacSArnaldo Carvalho de Melo 		perf_session__delete(session);
312361c99a6SArnaldo Carvalho de Melo 		perf_evlist__delete(evsel_list);
313d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
314c7929e47STom Zanussi 	}
315f5970550SPeter Zijlstra }
316f5970550SPeter Zijlstra 
3178115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
318a1645ce1SZhang, Yanmin {
319a1645ce1SZhang, Yanmin 	int err;
32023346f21SArnaldo Carvalho de Melo 	struct perf_session *psession = data;
321a1645ce1SZhang, Yanmin 
32223346f21SArnaldo Carvalho de Melo 	if (machine__is_host(machine))
323a1645ce1SZhang, Yanmin 		return;
324a1645ce1SZhang, Yanmin 
325a1645ce1SZhang, Yanmin 	/*
326a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
327a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
328a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
329a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
330a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
331a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
332a1645ce1SZhang, Yanmin 	 */
3338115d60cSArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(process_synthesized_event,
33423346f21SArnaldo Carvalho de Melo 					     psession, machine);
335a1645ce1SZhang, Yanmin 	if (err < 0)
336a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
33723346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
338a1645ce1SZhang, Yanmin 
339a1645ce1SZhang, Yanmin 	/*
340a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
341a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
342a1645ce1SZhang, Yanmin 	 */
3438115d60cSArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
34423346f21SArnaldo Carvalho de Melo 						 psession, machine, "_text");
345a1645ce1SZhang, Yanmin 	if (err < 0)
3468115d60cSArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
3478115d60cSArnaldo Carvalho de Melo 							 psession, machine,
3488115d60cSArnaldo Carvalho de Melo 							 "_stext");
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 
35498402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
35598402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
35698402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
35798402807SFrederic Weisbecker };
35898402807SFrederic Weisbecker 
35998402807SFrederic Weisbecker static void mmap_read_all(void)
36098402807SFrederic Weisbecker {
3610e2e63ddSPeter Zijlstra 	int i;
36298402807SFrederic Weisbecker 
363aece948fSArnaldo Carvalho de Melo 	for (i = 0; i < evsel_list->nr_mmaps; i++) {
3640a27d7f9SArnaldo Carvalho de Melo 		if (evsel_list->mmap[i].base)
3650a27d7f9SArnaldo Carvalho de Melo 			mmap_read(&evsel_list->mmap[i]);
36698402807SFrederic Weisbecker 	}
36798402807SFrederic Weisbecker 
36898402807SFrederic Weisbecker 	if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
36998402807SFrederic Weisbecker 		write_output(&finished_round_event, sizeof(finished_round_event));
37098402807SFrederic Weisbecker }
37198402807SFrederic Weisbecker 
372d4db3f16SArnaldo Carvalho de Melo static int __cmd_record(int argc, const char **argv)
37386470930SIngo Molnar {
37486470930SIngo Molnar 	struct stat st;
37586470930SIngo Molnar 	int flags;
3764dc0a04bSArnaldo Carvalho de Melo 	int err;
3778b412664SPeter Zijlstra 	unsigned long waking = 0;
37846be604bSZhang, Yanmin 	const bool forks = argc > 0;
37923346f21SArnaldo Carvalho de Melo 	struct machine *machine;
38086470930SIngo Molnar 
38133e49ea7SAndi Kleen 	progname = argv[0];
38233e49ea7SAndi Kleen 
38386470930SIngo Molnar 	page_size = sysconf(_SC_PAGE_SIZE);
38486470930SIngo Molnar 
385f5970550SPeter Zijlstra 	atexit(sig_atexit);
386f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
387f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
38818483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
389f5970550SPeter Zijlstra 
390d7065adbSFranck Bui-Huu 	if (!output_name) {
391d7065adbSFranck Bui-Huu 		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
392*35b9d88eSArnaldo Carvalho de Melo 			record_opts.pipe_output = true;
393d7065adbSFranck Bui-Huu 		else
394d7065adbSFranck Bui-Huu 			output_name = "perf.data";
395d7065adbSFranck Bui-Huu 	}
396d7065adbSFranck Bui-Huu 	if (output_name) {
397529870e3STom Zanussi 		if (!strcmp(output_name, "-"))
398*35b9d88eSArnaldo Carvalho de Melo 			record_opts.pipe_output = true;
399529870e3STom Zanussi 		else if (!stat(output_name, &st) && st.st_size) {
4007865e817SFrederic Weisbecker 			if (write_mode == WRITE_FORCE) {
401b38d3464SArnaldo Carvalho de Melo 				char oldname[PATH_MAX];
402b38d3464SArnaldo Carvalho de Melo 				snprintf(oldname, sizeof(oldname), "%s.old",
403b38d3464SArnaldo Carvalho de Melo 					 output_name);
404b38d3464SArnaldo Carvalho de Melo 				unlink(oldname);
405b38d3464SArnaldo Carvalho de Melo 				rename(output_name, oldname);
406b38d3464SArnaldo Carvalho de Melo 			}
4077865e817SFrederic Weisbecker 		} else if (write_mode == WRITE_APPEND) {
4087865e817SFrederic Weisbecker 			write_mode = WRITE_FORCE;
409266e0e21SPierre Habouzit 		}
410d7065adbSFranck Bui-Huu 	}
41186470930SIngo Molnar 
412f887f301SXiao Guangrong 	flags = O_CREAT|O_RDWR;
4137865e817SFrederic Weisbecker 	if (write_mode == WRITE_APPEND)
414f5970550SPeter Zijlstra 		file_new = 0;
41586470930SIngo Molnar 	else
41686470930SIngo Molnar 		flags |= O_TRUNC;
41786470930SIngo Molnar 
418*35b9d88eSArnaldo Carvalho de Melo 	if (record_opts.pipe_output)
419529870e3STom Zanussi 		output = STDOUT_FILENO;
420529870e3STom Zanussi 	else
42186470930SIngo Molnar 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
42286470930SIngo Molnar 	if (output < 0) {
42386470930SIngo Molnar 		perror("failed to create output file");
42486470930SIngo Molnar 		exit(-1);
42586470930SIngo Molnar 	}
42686470930SIngo Molnar 
4277865e817SFrederic Weisbecker 	session = perf_session__new(output_name, O_WRONLY,
42821ef97f0SIan Munsie 				    write_mode == WRITE_FORCE, false, NULL);
42994c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
430a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
431a9a70bbcSArnaldo Carvalho de Melo 		return -1;
432a9a70bbcSArnaldo Carvalho de Melo 	}
433a9a70bbcSArnaldo Carvalho de Melo 
434baa2f6ceSArnaldo Carvalho de Melo 	if (!no_buildid)
435baa2f6ceSArnaldo Carvalho de Melo 		perf_header__set_feat(&session->header, HEADER_BUILD_ID);
436baa2f6ceSArnaldo Carvalho de Melo 
4374dc0a04bSArnaldo Carvalho de Melo 	if (!file_new) {
438a91e5431SArnaldo Carvalho de Melo 		err = perf_session__read_header(session, output);
4394dc0a04bSArnaldo Carvalho de Melo 		if (err < 0)
44039d17dacSArnaldo Carvalho de Melo 			goto out_delete_session;
4414dc0a04bSArnaldo Carvalho de Melo 	}
4424dc0a04bSArnaldo Carvalho de Melo 
443361c99a6SArnaldo Carvalho de Melo 	if (have_tracepoints(&evsel_list->entries))
44494c744b6SArnaldo Carvalho de Melo 		perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
44503456a15SFrederic Weisbecker 
446fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_HOSTNAME);
447fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_OSRELEASE);
448fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_ARCH);
449fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPUDESC);
450fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_NRCPUS);
451fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
452fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CMDLINE);
453fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_VERSION);
454fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
455fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
456fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
457fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPUID);
458fbe96f29SStephane Eranian 
459800cd25cSFrederic Weisbecker 	/* 512 kiB: default amount of unprivileged mlocked memory */
460800cd25cSFrederic Weisbecker 	if (mmap_pages == UINT_MAX)
461800cd25cSFrederic Weisbecker 		mmap_pages = (512 * 1024) / page_size;
462800cd25cSFrederic Weisbecker 
463d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
464*35b9d88eSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(evsel_list, &record_opts, argv);
465*35b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
466*35b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
467*35b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
468856e9660SPeter Zijlstra 		}
469856e9660SPeter Zijlstra 	}
470856e9660SPeter Zijlstra 
471dd7927f4SArnaldo Carvalho de Melo 	open_counters(evsel_list);
47286470930SIngo Molnar 
473712a4b60SArnaldo Carvalho de Melo 	/*
474712a4b60SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at atexit_header()
475712a4b60SArnaldo Carvalho de Melo 	 */
476712a4b60SArnaldo Carvalho de Melo 	atexit(atexit_header);
477712a4b60SArnaldo Carvalho de Melo 
478*35b9d88eSArnaldo Carvalho de Melo 	if (record_opts.pipe_output) {
479529870e3STom Zanussi 		err = perf_header__write_pipe(output);
480529870e3STom Zanussi 		if (err < 0)
481529870e3STom Zanussi 			return err;
482529870e3STom Zanussi 	} else if (file_new) {
483a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
484361c99a6SArnaldo Carvalho de Melo 						 output, false);
485d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
486d5eed904SArnaldo Carvalho de Melo 			return err;
487d5eed904SArnaldo Carvalho de Melo 	}
4887c6a1c65SPeter Zijlstra 
4896122e4e4SArnaldo Carvalho de Melo 	post_processing_offset = lseek(output, 0, SEEK_CUR);
4906122e4e4SArnaldo Carvalho de Melo 
491*35b9d88eSArnaldo Carvalho de Melo 	if (record_opts.pipe_output) {
492a91e5431SArnaldo Carvalho de Melo 		err = perf_session__synthesize_attrs(session,
493a91e5431SArnaldo Carvalho de Melo 						     process_synthesized_event);
4942c46dbb5STom Zanussi 		if (err < 0) {
4952c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
4962c46dbb5STom Zanussi 			return err;
4972c46dbb5STom Zanussi 		}
498cd19a035STom Zanussi 
4998115d60cSArnaldo Carvalho de Melo 		err = perf_event__synthesize_event_types(process_synthesized_event,
500cd19a035STom Zanussi 							 session);
501cd19a035STom Zanussi 		if (err < 0) {
502cd19a035STom Zanussi 			pr_err("Couldn't synthesize event_types.\n");
503cd19a035STom Zanussi 			return err;
504cd19a035STom Zanussi 		}
5059215545eSTom Zanussi 
506361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
50763e0c771STom Zanussi 			/*
50863e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
50963e0c771STom Zanussi 			 * there were no tracepoints so its not really
51063e0c771STom Zanussi 			 * an error, just that we don't need to
51163e0c771STom Zanussi 			 * synthesize anything.  We really have to
51263e0c771STom Zanussi 			 * return this more properly and also
51363e0c771STom Zanussi 			 * propagate errors that now are calling die()
51463e0c771STom Zanussi 			 */
5158115d60cSArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(output, evsel_list,
5169215545eSTom Zanussi 								  process_synthesized_event,
5179215545eSTom Zanussi 								  session);
51863e0c771STom Zanussi 			if (err <= 0) {
51963e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
52063e0c771STom Zanussi 				return err;
52163e0c771STom Zanussi 			}
5229215545eSTom Zanussi 			advance_output(err);
5232c46dbb5STom Zanussi 		}
52463e0c771STom Zanussi 	}
5252c46dbb5STom Zanussi 
52623346f21SArnaldo Carvalho de Melo 	machine = perf_session__find_host_machine(session);
52723346f21SArnaldo Carvalho de Melo 	if (!machine) {
528a1645ce1SZhang, Yanmin 		pr_err("Couldn't find native kernel information.\n");
529a1645ce1SZhang, Yanmin 		return -1;
530a1645ce1SZhang, Yanmin 	}
531a1645ce1SZhang, Yanmin 
5328115d60cSArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
53323346f21SArnaldo Carvalho de Melo 						 session, machine, "_text");
53470162138SArnaldo Carvalho de Melo 	if (err < 0)
5358115d60cSArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
53623346f21SArnaldo Carvalho de Melo 							 session, machine, "_stext");
537c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
538c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
539c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
540c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
54156b03f3cSArnaldo Carvalho de Melo 
5428115d60cSArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(process_synthesized_event,
54323346f21SArnaldo Carvalho de Melo 					     session, machine);
544c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
545c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
546c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
547c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
548c1a3a4b9SArnaldo Carvalho de Melo 
549a1645ce1SZhang, Yanmin 	if (perf_guest)
5508115d60cSArnaldo Carvalho de Melo 		perf_session__process_machines(session,
5518115d60cSArnaldo Carvalho de Melo 					       perf_event__synthesize_guest_os);
552b7cece76SArnaldo Carvalho de Melo 
5530f82ebc4SArnaldo Carvalho de Melo 	if (!record_opts.system_wide)
5547c940c18SArnaldo Carvalho de Melo 		perf_event__synthesize_thread_map(evsel_list->threads,
5558115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
556d8f66248SArnaldo Carvalho de Melo 						  session);
557234fbbf5SArnaldo Carvalho de Melo 	else
5588115d60cSArnaldo Carvalho de Melo 		perf_event__synthesize_threads(process_synthesized_event,
5598115d60cSArnaldo Carvalho de Melo 					       session);
5607c6a1c65SPeter Zijlstra 
56186470930SIngo Molnar 	if (realtime_prio) {
56286470930SIngo Molnar 		struct sched_param param;
56386470930SIngo Molnar 
56486470930SIngo Molnar 		param.sched_priority = realtime_prio;
56586470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5666beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
56786470930SIngo Molnar 			exit(-1);
56886470930SIngo Molnar 		}
56986470930SIngo Molnar 	}
57086470930SIngo Molnar 
571764e16a3SDavid Ahern 	perf_evlist__enable(evsel_list);
572764e16a3SDavid Ahern 
573856e9660SPeter Zijlstra 	/*
574856e9660SPeter Zijlstra 	 * Let the child rip
575856e9660SPeter Zijlstra 	 */
576d4db3f16SArnaldo Carvalho de Melo 	if (forks)
577*35b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
578856e9660SPeter Zijlstra 
579649c48a9SPeter Zijlstra 	for (;;) {
58086470930SIngo Molnar 		int hits = samples;
58186470930SIngo Molnar 
58298402807SFrederic Weisbecker 		mmap_read_all();
58386470930SIngo Molnar 
584649c48a9SPeter Zijlstra 		if (hits == samples) {
585649c48a9SPeter Zijlstra 			if (done)
586649c48a9SPeter Zijlstra 				break;
5875c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
5888b412664SPeter Zijlstra 			waking++;
5898b412664SPeter Zijlstra 		}
5908b412664SPeter Zijlstra 
5914152ab37SArnaldo Carvalho de Melo 		if (done)
5924152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
5938b412664SPeter Zijlstra 	}
5948b412664SPeter Zijlstra 
59518483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
596b44308f5SArnaldo Carvalho de Melo 		return 0;
597b44308f5SArnaldo Carvalho de Melo 
5988b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
59986470930SIngo Molnar 
60086470930SIngo Molnar 	/*
60186470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
60286470930SIngo Molnar 	 */
60386470930SIngo Molnar 	fprintf(stderr,
6049486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
60586470930SIngo Molnar 		(double)bytes_written / 1024.0 / 1024.0,
60686470930SIngo Molnar 		output_name,
60786470930SIngo Molnar 		bytes_written / 24);
60886470930SIngo Molnar 
60986470930SIngo Molnar 	return 0;
61039d17dacSArnaldo Carvalho de Melo 
61139d17dacSArnaldo Carvalho de Melo out_delete_session:
61239d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
61339d17dacSArnaldo Carvalho de Melo 	return err;
61486470930SIngo Molnar }
61586470930SIngo Molnar 
61686470930SIngo Molnar static const char * const record_usage[] = {
61786470930SIngo Molnar 	"perf record [<options>] [<command>]",
61886470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
61986470930SIngo Molnar 	NULL
62086470930SIngo Molnar };
62186470930SIngo Molnar 
6227865e817SFrederic Weisbecker static bool force, append_file;
6237865e817SFrederic Weisbecker 
624bca647aaSTom Zanussi const struct option record_options[] = {
625361c99a6SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &evsel_list, "event",
62686470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
627f120f9d5SJiri Olsa 		     parse_events_option),
628361c99a6SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &evsel_list, "filter",
629c171b552SLi Zefan 		     "event filter", parse_filter),
6300f82ebc4SArnaldo Carvalho de Melo 	OPT_INTEGER('p', "pid", &record_opts.target_pid,
631d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
6320f82ebc4SArnaldo Carvalho de Melo 	OPT_INTEGER('t', "tid", &record_opts.target_tid,
633d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
63486470930SIngo Molnar 	OPT_INTEGER('r', "realtime", &realtime_prio,
63586470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
6360f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record_opts.no_delay,
637acac03faSKirill Smelkov 		    "collect data without buffering"),
6380f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record_opts.raw_samples,
639daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
6400f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('a', "all-cpus", &record_opts.system_wide,
64186470930SIngo Molnar 			    "system-wide collection from all CPUs"),
64286470930SIngo Molnar 	OPT_BOOLEAN('A', "append", &append_file,
64386470930SIngo Molnar 			    "append to the output file to do incremental profiling"),
6440f82ebc4SArnaldo Carvalho de Melo 	OPT_STRING('C', "cpu", &record_opts.cpu_list, "cpu",
645c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
64686470930SIngo Molnar 	OPT_BOOLEAN('f', "force", &force,
6477865e817SFrederic Weisbecker 			"overwrite existing data file (deprecated)"),
6480f82ebc4SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record_opts.user_interval, "event period to sample"),
64986470930SIngo Molnar 	OPT_STRING('o', "output", &output_name, "file",
65086470930SIngo Molnar 		    "output file name"),
6510f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record_opts.no_inherit,
6522e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
6530f82ebc4SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record_opts.user_freq, "profile at this frequency"),
6541967936dSArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
65543bece79SLin Ming 	OPT_BOOLEAN(0, "group", &group,
65643bece79SLin Ming 		    "put the counters into a counter group"),
6570f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('g', "call-graph", &record_opts.call_graph,
6583efa1cc9SIngo Molnar 		    "do call-graph (stack chain/backtrace) recording"),
659c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
6603da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
661b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
6620f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record_opts.inherit_stat,
663649c48a9SPeter Zijlstra 		    "per thread counts"),
6640f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record_opts.sample_address,
6654bba828dSAnton Blanchard 		    "Sample addresses"),
6660f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record_opts.sample_time, "Sample timestamps"),
6670f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record_opts.no_samples,
668649c48a9SPeter Zijlstra 		    "don't sample"),
669baa2f6ceSArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache,
670a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
671baa2f6ceSArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &no_buildid,
672baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
673023695d9SStephane Eranian 	OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
674023695d9SStephane Eranian 		     "monitor event in cgroup name only",
675023695d9SStephane Eranian 		     parse_cgroups),
67686470930SIngo Molnar 	OPT_END()
67786470930SIngo Molnar };
67886470930SIngo Molnar 
679f37a291cSIngo Molnar int cmd_record(int argc, const char **argv, const char *prefix __used)
68086470930SIngo Molnar {
68169aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
68269aad6f1SArnaldo Carvalho de Melo 	struct perf_evsel *pos;
68386470930SIngo Molnar 
684fbe96f29SStephane Eranian 	perf_header__set_cmdline(argc, argv);
685fbe96f29SStephane Eranian 
6867e2ed097SArnaldo Carvalho de Melo 	evsel_list = perf_evlist__new(NULL, NULL);
687361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
688361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
689361c99a6SArnaldo Carvalho de Melo 
690bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
691a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
6920f82ebc4SArnaldo Carvalho de Melo 	if (!argc && record_opts.target_pid == -1 && record_opts.target_tid == -1 &&
6930f82ebc4SArnaldo Carvalho de Melo 		!record_opts.system_wide && !record_opts.cpu_list)
694bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
69586470930SIngo Molnar 
6967865e817SFrederic Weisbecker 	if (force && append_file) {
6977865e817SFrederic Weisbecker 		fprintf(stderr, "Can't overwrite and append at the same time."
6987865e817SFrederic Weisbecker 				" You need to choose between -f and -A");
699bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
7007865e817SFrederic Weisbecker 	} else if (append_file) {
7017865e817SFrederic Weisbecker 		write_mode = WRITE_APPEND;
7027865e817SFrederic Weisbecker 	} else {
7037865e817SFrederic Weisbecker 		write_mode = WRITE_FORCE;
7047865e817SFrederic Weisbecker 	}
7057865e817SFrederic Weisbecker 
7060f82ebc4SArnaldo Carvalho de Melo 	if (nr_cgroups && !record_opts.system_wide) {
707023695d9SStephane Eranian 		fprintf(stderr, "cgroup monitoring only available in"
708023695d9SStephane Eranian 			" system-wide mode\n");
709023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
710023695d9SStephane Eranian 	}
711023695d9SStephane Eranian 
712655000e7SArnaldo Carvalho de Melo 	symbol__init();
713baa2f6ceSArnaldo Carvalho de Melo 
714ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
715646aaea6SArnaldo Carvalho de Melo 		pr_warning(
716646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
717ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
718646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
719646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
720646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
721646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
722646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
723ec80fde7SArnaldo Carvalho de Melo 
724baa2f6ceSArnaldo Carvalho de Melo 	if (no_buildid_cache || no_buildid)
725a1ac1d3cSStephane Eranian 		disable_buildid_cache();
726655000e7SArnaldo Carvalho de Melo 
727361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
728361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
72969aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
73069aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
731bbd36e5eSPeter Zijlstra 	}
73286470930SIngo Molnar 
7330f82ebc4SArnaldo Carvalho de Melo 	if (record_opts.target_pid != -1)
7340f82ebc4SArnaldo Carvalho de Melo 		record_opts.target_tid = record_opts.target_pid;
735d6d901c2SZhang, Yanmin 
7360f82ebc4SArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(evsel_list, record_opts.target_pid,
7370f82ebc4SArnaldo Carvalho de Melo 				     record_opts.target_tid, record_opts.cpu_list) < 0)
738dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
73969aad6f1SArnaldo Carvalho de Melo 
740361c99a6SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evsel_list->entries, node) {
7417e2ed097SArnaldo Carvalho de Melo 		if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
7427e2ed097SArnaldo Carvalho de Melo 					 evsel_list->threads->nr) < 0)
74369aad6f1SArnaldo Carvalho de Melo 			goto out_free_fd;
744ad7f4e3fSArnaldo Carvalho de Melo 		if (perf_header__push_event(pos->attr.config, event_name(pos)))
745ad7f4e3fSArnaldo Carvalho de Melo 			goto out_free_fd;
746d6d901c2SZhang, Yanmin 	}
7475c581041SArnaldo Carvalho de Melo 
7487e2ed097SArnaldo Carvalho de Melo 	if (perf_evlist__alloc_pollfd(evsel_list) < 0)
74939d17dacSArnaldo Carvalho de Melo 		goto out_free_fd;
750d6d901c2SZhang, Yanmin 
7510f82ebc4SArnaldo Carvalho de Melo 	if (record_opts.user_interval != ULLONG_MAX)
7520f82ebc4SArnaldo Carvalho de Melo 		record_opts.default_interval = record_opts.user_interval;
7530f82ebc4SArnaldo Carvalho de Melo 	if (record_opts.user_freq != UINT_MAX)
7540f82ebc4SArnaldo Carvalho de Melo 		record_opts.freq = record_opts.user_freq;
755f9212819SFrederic Weisbecker 
7567e4ff9e3SMike Galbraith 	/*
7577e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
7587e4ff9e3SMike Galbraith 	 */
7590f82ebc4SArnaldo Carvalho de Melo 	if (record_opts.default_interval)
7600f82ebc4SArnaldo Carvalho de Melo 		record_opts.freq = 0;
7610f82ebc4SArnaldo Carvalho de Melo 	else if (record_opts.freq) {
7620f82ebc4SArnaldo Carvalho de Melo 		record_opts.default_interval = record_opts.freq;
7637e4ff9e3SMike Galbraith 	} else {
7647e4ff9e3SMike Galbraith 		fprintf(stderr, "frequency and count are zero, aborting\n");
76539d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
7665c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
7677e4ff9e3SMike Galbraith 	}
7687e4ff9e3SMike Galbraith 
76939d17dacSArnaldo Carvalho de Melo 	err = __cmd_record(argc, argv);
77039d17dacSArnaldo Carvalho de Melo out_free_fd:
7717e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
772d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
773d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
77439d17dacSArnaldo Carvalho de Melo 	return err;
77586470930SIngo Molnar }
776