xref: /openbmc/linux/tools/perf/builtin-record.c (revision ed80f5813fd6ecc6d74250681910a4214f699d4e)
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 
3801c2d99bSArnaldo Carvalho de Melo struct perf_record_opts record_opts = {
390f82ebc4SArnaldo Carvalho de Melo 	.target_pid	     = -1,
400f82ebc4SArnaldo Carvalho de Melo 	.target_tid	     = -1,
4101c2d99bSArnaldo Carvalho de Melo 	.mmap_pages	     = UINT_MAX,
420f82ebc4SArnaldo Carvalho de Melo 	.user_freq	     = UINT_MAX,
430f82ebc4SArnaldo Carvalho de Melo 	.user_interval	     = ULLONG_MAX,
440f82ebc4SArnaldo Carvalho de Melo 	.freq		     = 1000,
450f82ebc4SArnaldo Carvalho de Melo 	.sample_id_all_avail = true,
460f82ebc4SArnaldo Carvalho de Melo };
4786470930SIngo Molnar 
4886470930SIngo Molnar static unsigned int		page_size;
4986470930SIngo Molnar static int			output;
50d7065adbSFranck Bui-Huu static const char		*output_name			= NULL;
511967936dSArnaldo Carvalho de Melo static int			realtime_prio			=      0;
527865e817SFrederic Weisbecker static enum write_mode_t	write_mode			= WRITE_FORCE;
53a1ac1d3cSStephane Eranian static bool			no_buildid			=  false;
54baa2f6ceSArnaldo Carvalho de Melo static bool			no_buildid_cache		=  false;
55361c99a6SArnaldo Carvalho de Melo static struct perf_evlist	*evsel_list;
5686470930SIngo Molnar 
5742e59d7dSIngo Molnar static long			samples				=      0;
5842e59d7dSIngo Molnar static u64			bytes_written			=      0;
5986470930SIngo Molnar 
60f5970550SPeter Zijlstra static int			file_new			=      1;
616122e4e4SArnaldo Carvalho de Melo static off_t			post_processing_offset;
627c6a1c65SPeter Zijlstra 
6394c744b6SArnaldo Carvalho de Melo static struct perf_session	*session;
6433e49ea7SAndi Kleen static const char               *progname;
65f5970550SPeter Zijlstra 
669215545eSTom Zanussi static void advance_output(size_t size)
679215545eSTom Zanussi {
689215545eSTom Zanussi 	bytes_written += size;
699215545eSTom Zanussi }
709215545eSTom Zanussi 
71f5970550SPeter Zijlstra static void write_output(void *buf, size_t size)
72f5970550SPeter Zijlstra {
73f5970550SPeter Zijlstra 	while (size) {
74f5970550SPeter Zijlstra 		int ret = write(output, buf, size);
75f5970550SPeter Zijlstra 
76f5970550SPeter Zijlstra 		if (ret < 0)
77f5970550SPeter Zijlstra 			die("failed to write");
78f5970550SPeter Zijlstra 
79f5970550SPeter Zijlstra 		size -= ret;
80f5970550SPeter Zijlstra 		buf += ret;
81f5970550SPeter Zijlstra 
82f5970550SPeter Zijlstra 		bytes_written += ret;
83f5970550SPeter Zijlstra 	}
84f5970550SPeter Zijlstra }
85f5970550SPeter Zijlstra 
868115d60cSArnaldo Carvalho de Melo static int process_synthesized_event(union perf_event *event,
878d50e5b4SArnaldo Carvalho de Melo 				     struct perf_sample *sample __used,
88d8f66248SArnaldo Carvalho de Melo 				     struct perf_session *self __used)
89234fbbf5SArnaldo Carvalho de Melo {
906122e4e4SArnaldo Carvalho de Melo 	write_output(event, event->header.size);
91234fbbf5SArnaldo Carvalho de Melo 	return 0;
92234fbbf5SArnaldo Carvalho de Melo }
93234fbbf5SArnaldo Carvalho de Melo 
94744bd8aaSArnaldo Carvalho de Melo static void mmap_read(struct perf_mmap *md)
9586470930SIngo Molnar {
96744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
9786470930SIngo Molnar 	unsigned int old = md->prev;
9886470930SIngo Molnar 	unsigned char *data = md->base + page_size;
9986470930SIngo Molnar 	unsigned long size;
10086470930SIngo Molnar 	void *buf;
10186470930SIngo Molnar 
102dc82009aSArnaldo Carvalho de Melo 	if (old == head)
103dc82009aSArnaldo Carvalho de Melo 		return;
10486470930SIngo Molnar 
10586470930SIngo Molnar 	samples++;
10686470930SIngo Molnar 
10786470930SIngo Molnar 	size = head - old;
10886470930SIngo Molnar 
10986470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
11086470930SIngo Molnar 		buf = &data[old & md->mask];
11186470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
11286470930SIngo Molnar 		old += size;
11386470930SIngo Molnar 
1146122e4e4SArnaldo Carvalho de Melo 		write_output(buf, size);
11586470930SIngo Molnar 	}
11686470930SIngo Molnar 
11786470930SIngo Molnar 	buf = &data[old & md->mask];
11886470930SIngo Molnar 	size = head - old;
11986470930SIngo Molnar 	old += size;
12086470930SIngo Molnar 
1216122e4e4SArnaldo Carvalho de Melo 	write_output(buf, size);
12286470930SIngo Molnar 
12386470930SIngo Molnar 	md->prev = old;
124115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
12586470930SIngo Molnar }
12686470930SIngo Molnar 
12786470930SIngo Molnar static volatile int done = 0;
128f7b7c26eSPeter Zijlstra static volatile int signr = -1;
12933e49ea7SAndi Kleen static volatile int child_finished = 0;
13086470930SIngo Molnar 
13186470930SIngo Molnar static void sig_handler(int sig)
13286470930SIngo Molnar {
13333e49ea7SAndi Kleen 	if (sig == SIGCHLD)
13433e49ea7SAndi Kleen 		child_finished = 1;
13533e49ea7SAndi Kleen 
13686470930SIngo Molnar 	done = 1;
137f7b7c26eSPeter Zijlstra 	signr = sig;
138f7b7c26eSPeter Zijlstra }
139f7b7c26eSPeter Zijlstra 
140f7b7c26eSPeter Zijlstra static void sig_atexit(void)
141f7b7c26eSPeter Zijlstra {
14233e49ea7SAndi Kleen 	int status;
14333e49ea7SAndi Kleen 
14435b9d88eSArnaldo Carvalho de Melo 	if (evsel_list->workload.pid > 0) {
14533e49ea7SAndi Kleen 		if (!child_finished)
14635b9d88eSArnaldo Carvalho de Melo 			kill(evsel_list->workload.pid, SIGTERM);
147933da83aSChris Wilson 
14833e49ea7SAndi Kleen 		wait(&status);
14933e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
15033e49ea7SAndi Kleen 			psignal(WTERMSIG(status), progname);
15133e49ea7SAndi Kleen 	}
15233e49ea7SAndi Kleen 
15318483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
154f7b7c26eSPeter Zijlstra 		return;
155f7b7c26eSPeter Zijlstra 
156f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
157f7b7c26eSPeter Zijlstra 	kill(getpid(), signr);
15886470930SIngo Molnar }
15986470930SIngo Molnar 
160a91e5431SArnaldo Carvalho de Melo static bool perf_evlist__equal(struct perf_evlist *evlist,
161a91e5431SArnaldo Carvalho de Melo 			       struct perf_evlist *other)
162a91e5431SArnaldo Carvalho de Melo {
163a91e5431SArnaldo Carvalho de Melo 	struct perf_evsel *pos, *pair;
164a91e5431SArnaldo Carvalho de Melo 
165a91e5431SArnaldo Carvalho de Melo 	if (evlist->nr_entries != other->nr_entries)
166a91e5431SArnaldo Carvalho de Melo 		return false;
167a91e5431SArnaldo Carvalho de Melo 
168a91e5431SArnaldo Carvalho de Melo 	pair = list_entry(other->entries.next, struct perf_evsel, node);
169a91e5431SArnaldo Carvalho de Melo 
170a91e5431SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
171a91e5431SArnaldo Carvalho de Melo 		if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
172a91e5431SArnaldo Carvalho de Melo 			return false;
173a91e5431SArnaldo Carvalho de Melo 		pair = list_entry(pair->node.next, struct perf_evsel, node);
174a91e5431SArnaldo Carvalho de Melo 	}
175a91e5431SArnaldo Carvalho de Melo 
176a91e5431SArnaldo Carvalho de Melo 	return true;
177a91e5431SArnaldo Carvalho de Melo }
178a91e5431SArnaldo Carvalho de Melo 
179dd7927f4SArnaldo Carvalho de Melo static void open_counters(struct perf_evlist *evlist)
180dd7927f4SArnaldo Carvalho de Melo {
181727ab04eSArnaldo Carvalho de Melo 	struct perf_evsel *pos, *first;
182dd7927f4SArnaldo Carvalho de Melo 
183727ab04eSArnaldo Carvalho de Melo 	first = list_entry(evlist->entries.next, struct perf_evsel, node);
184727ab04eSArnaldo Carvalho de Melo 
1850f82ebc4SArnaldo Carvalho de Melo 	perf_evlist__config_attrs(evlist, &record_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*ed80f581SArnaldo Carvalho de Melo 		if (record_opts.group && pos != first)
205727ab04eSArnaldo Carvalho de Melo 			group_fd = first->fd;
2069c90a61cSArnaldo Carvalho de Melo retry_sample_id:
2070f82ebc4SArnaldo Carvalho de Melo 		attr->sample_id_all = record_opts.sample_id_all_avail ? 1 : 0;
2083da297a6SIngo Molnar try_again:
209*ed80f581SArnaldo Carvalho de Melo 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
210*ed80f581SArnaldo Carvalho de Melo 				     record_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);
2160f82ebc4SArnaldo Carvalho de Melo 			} else if (err ==  ENODEV && record_opts.cpu_list) {
217d6d901c2SZhang, Yanmin 				die("No such device - did you specify"
218d6d901c2SZhang, Yanmin 					" an out-of-range profile CPU?\n");
2190f82ebc4SArnaldo Carvalho de Melo 			} else if (err == EINVAL && record_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 				 */
2230f82ebc4SArnaldo Carvalho de Melo 				record_opts.sample_id_all_avail = false;
2240f82ebc4SArnaldo Carvalho de Melo 				if (!record_opts.sample_time && !record_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 
27401c2d99bSArnaldo Carvalho de Melo 	if (perf_evlist__mmap(evlist, record_opts.mmap_pages, false) < 0)
2750a27d7f9SArnaldo Carvalho de Melo 		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
2760a27d7f9SArnaldo Carvalho de Melo 
277a91e5431SArnaldo Carvalho de Melo 	if (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 
2896122e4e4SArnaldo Carvalho de Melo static int process_buildids(void)
2906122e4e4SArnaldo Carvalho de Melo {
2916122e4e4SArnaldo Carvalho de Melo 	u64 size = lseek(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 
2966122e4e4SArnaldo Carvalho de Melo 	session->fd = output;
2976122e4e4SArnaldo Carvalho de Melo 	return __perf_session__process_events(session, post_processing_offset,
2986122e4e4SArnaldo Carvalho de Melo 					      size - post_processing_offset,
2996122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
3006122e4e4SArnaldo Carvalho de Melo }
3016122e4e4SArnaldo Carvalho de Melo 
302f5970550SPeter Zijlstra static void atexit_header(void)
303f5970550SPeter Zijlstra {
30435b9d88eSArnaldo Carvalho de Melo 	if (!record_opts.pipe_output) {
30594c744b6SArnaldo Carvalho de Melo 		session->header.data_size += bytes_written;
306f5970550SPeter Zijlstra 
307baa2f6ceSArnaldo Carvalho de Melo 		if (!no_buildid)
3086122e4e4SArnaldo Carvalho de Melo 			process_buildids();
309a91e5431SArnaldo Carvalho de Melo 		perf_session__write_header(session, evsel_list, output, true);
31039d17dacSArnaldo Carvalho de Melo 		perf_session__delete(session);
311361c99a6SArnaldo Carvalho de Melo 		perf_evlist__delete(evsel_list);
312d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
313c7929e47STom Zanussi 	}
314f5970550SPeter Zijlstra }
315f5970550SPeter Zijlstra 
3168115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
317a1645ce1SZhang, Yanmin {
318a1645ce1SZhang, Yanmin 	int err;
31923346f21SArnaldo Carvalho de Melo 	struct perf_session *psession = data;
320a1645ce1SZhang, Yanmin 
32123346f21SArnaldo Carvalho de Melo 	if (machine__is_host(machine))
322a1645ce1SZhang, Yanmin 		return;
323a1645ce1SZhang, Yanmin 
324a1645ce1SZhang, Yanmin 	/*
325a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
326a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
327a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
328a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
329a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
330a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
331a1645ce1SZhang, Yanmin 	 */
3328115d60cSArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(process_synthesized_event,
33323346f21SArnaldo Carvalho de Melo 					     psession, machine);
334a1645ce1SZhang, Yanmin 	if (err < 0)
335a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
33623346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
337a1645ce1SZhang, Yanmin 
338a1645ce1SZhang, Yanmin 	/*
339a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
340a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
341a1645ce1SZhang, Yanmin 	 */
3428115d60cSArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
34323346f21SArnaldo Carvalho de Melo 						 psession, machine, "_text");
344a1645ce1SZhang, Yanmin 	if (err < 0)
3458115d60cSArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
3468115d60cSArnaldo Carvalho de Melo 							 psession, machine,
3478115d60cSArnaldo Carvalho de Melo 							 "_stext");
348a1645ce1SZhang, Yanmin 	if (err < 0)
349a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
35023346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
351a1645ce1SZhang, Yanmin }
352a1645ce1SZhang, Yanmin 
35398402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
35498402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
35598402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
35698402807SFrederic Weisbecker };
35798402807SFrederic Weisbecker 
35898402807SFrederic Weisbecker static void mmap_read_all(void)
35998402807SFrederic Weisbecker {
3600e2e63ddSPeter Zijlstra 	int i;
36198402807SFrederic Weisbecker 
362aece948fSArnaldo Carvalho de Melo 	for (i = 0; i < evsel_list->nr_mmaps; i++) {
3630a27d7f9SArnaldo Carvalho de Melo 		if (evsel_list->mmap[i].base)
3640a27d7f9SArnaldo Carvalho de Melo 			mmap_read(&evsel_list->mmap[i]);
36598402807SFrederic Weisbecker 	}
36698402807SFrederic Weisbecker 
36798402807SFrederic Weisbecker 	if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
36898402807SFrederic Weisbecker 		write_output(&finished_round_event, sizeof(finished_round_event));
36998402807SFrederic Weisbecker }
37098402807SFrederic Weisbecker 
371d4db3f16SArnaldo Carvalho de Melo static int __cmd_record(int argc, const char **argv)
37286470930SIngo Molnar {
37386470930SIngo Molnar 	struct stat st;
37486470930SIngo Molnar 	int flags;
3754dc0a04bSArnaldo Carvalho de Melo 	int err;
3768b412664SPeter Zijlstra 	unsigned long waking = 0;
37746be604bSZhang, Yanmin 	const bool forks = argc > 0;
37823346f21SArnaldo Carvalho de Melo 	struct machine *machine;
37986470930SIngo Molnar 
38033e49ea7SAndi Kleen 	progname = argv[0];
38133e49ea7SAndi Kleen 
38286470930SIngo Molnar 	page_size = sysconf(_SC_PAGE_SIZE);
38386470930SIngo Molnar 
384f5970550SPeter Zijlstra 	atexit(sig_atexit);
385f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
386f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
38718483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
388f5970550SPeter Zijlstra 
389d7065adbSFranck Bui-Huu 	if (!output_name) {
390d7065adbSFranck Bui-Huu 		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
39135b9d88eSArnaldo Carvalho de Melo 			record_opts.pipe_output = true;
392d7065adbSFranck Bui-Huu 		else
393d7065adbSFranck Bui-Huu 			output_name = "perf.data";
394d7065adbSFranck Bui-Huu 	}
395d7065adbSFranck Bui-Huu 	if (output_name) {
396529870e3STom Zanussi 		if (!strcmp(output_name, "-"))
39735b9d88eSArnaldo Carvalho de Melo 			record_opts.pipe_output = true;
398529870e3STom Zanussi 		else if (!stat(output_name, &st) && st.st_size) {
3997865e817SFrederic Weisbecker 			if (write_mode == WRITE_FORCE) {
400b38d3464SArnaldo Carvalho de Melo 				char oldname[PATH_MAX];
401b38d3464SArnaldo Carvalho de Melo 				snprintf(oldname, sizeof(oldname), "%s.old",
402b38d3464SArnaldo Carvalho de Melo 					 output_name);
403b38d3464SArnaldo Carvalho de Melo 				unlink(oldname);
404b38d3464SArnaldo Carvalho de Melo 				rename(output_name, oldname);
405b38d3464SArnaldo Carvalho de Melo 			}
4067865e817SFrederic Weisbecker 		} else if (write_mode == WRITE_APPEND) {
4077865e817SFrederic Weisbecker 			write_mode = WRITE_FORCE;
408266e0e21SPierre Habouzit 		}
409d7065adbSFranck Bui-Huu 	}
41086470930SIngo Molnar 
411f887f301SXiao Guangrong 	flags = O_CREAT|O_RDWR;
4127865e817SFrederic Weisbecker 	if (write_mode == WRITE_APPEND)
413f5970550SPeter Zijlstra 		file_new = 0;
41486470930SIngo Molnar 	else
41586470930SIngo Molnar 		flags |= O_TRUNC;
41686470930SIngo Molnar 
41735b9d88eSArnaldo Carvalho de Melo 	if (record_opts.pipe_output)
418529870e3STom Zanussi 		output = STDOUT_FILENO;
419529870e3STom Zanussi 	else
42086470930SIngo Molnar 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
42186470930SIngo Molnar 	if (output < 0) {
42286470930SIngo Molnar 		perror("failed to create output file");
42386470930SIngo Molnar 		exit(-1);
42486470930SIngo Molnar 	}
42586470930SIngo Molnar 
4267865e817SFrederic Weisbecker 	session = perf_session__new(output_name, O_WRONLY,
42721ef97f0SIan Munsie 				    write_mode == WRITE_FORCE, false, NULL);
42894c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
429a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
430a9a70bbcSArnaldo Carvalho de Melo 		return -1;
431a9a70bbcSArnaldo Carvalho de Melo 	}
432a9a70bbcSArnaldo Carvalho de Melo 
433baa2f6ceSArnaldo Carvalho de Melo 	if (!no_buildid)
434baa2f6ceSArnaldo Carvalho de Melo 		perf_header__set_feat(&session->header, HEADER_BUILD_ID);
435baa2f6ceSArnaldo Carvalho de Melo 
4364dc0a04bSArnaldo Carvalho de Melo 	if (!file_new) {
437a91e5431SArnaldo Carvalho de Melo 		err = perf_session__read_header(session, output);
4384dc0a04bSArnaldo Carvalho de Melo 		if (err < 0)
43939d17dacSArnaldo Carvalho de Melo 			goto out_delete_session;
4404dc0a04bSArnaldo Carvalho de Melo 	}
4414dc0a04bSArnaldo Carvalho de Melo 
442361c99a6SArnaldo Carvalho de Melo 	if (have_tracepoints(&evsel_list->entries))
44394c744b6SArnaldo Carvalho de Melo 		perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
44403456a15SFrederic Weisbecker 
445fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_HOSTNAME);
446fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_OSRELEASE);
447fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_ARCH);
448fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPUDESC);
449fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_NRCPUS);
450fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
451fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CMDLINE);
452fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_VERSION);
453fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
454fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
455fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
456fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPUID);
457fbe96f29SStephane Eranian 
458d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
45935b9d88eSArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(evsel_list, &record_opts, argv);
46035b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
46135b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
46235b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
463856e9660SPeter Zijlstra 		}
464856e9660SPeter Zijlstra 	}
465856e9660SPeter Zijlstra 
466dd7927f4SArnaldo Carvalho de Melo 	open_counters(evsel_list);
46786470930SIngo Molnar 
468712a4b60SArnaldo Carvalho de Melo 	/*
469712a4b60SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at atexit_header()
470712a4b60SArnaldo Carvalho de Melo 	 */
471712a4b60SArnaldo Carvalho de Melo 	atexit(atexit_header);
472712a4b60SArnaldo Carvalho de Melo 
47335b9d88eSArnaldo Carvalho de Melo 	if (record_opts.pipe_output) {
474529870e3STom Zanussi 		err = perf_header__write_pipe(output);
475529870e3STom Zanussi 		if (err < 0)
476529870e3STom Zanussi 			return err;
477529870e3STom Zanussi 	} else if (file_new) {
478a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
479361c99a6SArnaldo Carvalho de Melo 						 output, false);
480d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
481d5eed904SArnaldo Carvalho de Melo 			return err;
482d5eed904SArnaldo Carvalho de Melo 	}
4837c6a1c65SPeter Zijlstra 
4846122e4e4SArnaldo Carvalho de Melo 	post_processing_offset = lseek(output, 0, SEEK_CUR);
4856122e4e4SArnaldo Carvalho de Melo 
48635b9d88eSArnaldo Carvalho de Melo 	if (record_opts.pipe_output) {
487a91e5431SArnaldo Carvalho de Melo 		err = perf_session__synthesize_attrs(session,
488a91e5431SArnaldo Carvalho de Melo 						     process_synthesized_event);
4892c46dbb5STom Zanussi 		if (err < 0) {
4902c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
4912c46dbb5STom Zanussi 			return err;
4922c46dbb5STom Zanussi 		}
493cd19a035STom Zanussi 
4948115d60cSArnaldo Carvalho de Melo 		err = perf_event__synthesize_event_types(process_synthesized_event,
495cd19a035STom Zanussi 							 session);
496cd19a035STom Zanussi 		if (err < 0) {
497cd19a035STom Zanussi 			pr_err("Couldn't synthesize event_types.\n");
498cd19a035STom Zanussi 			return err;
499cd19a035STom Zanussi 		}
5009215545eSTom Zanussi 
501361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
50263e0c771STom Zanussi 			/*
50363e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
50463e0c771STom Zanussi 			 * there were no tracepoints so its not really
50563e0c771STom Zanussi 			 * an error, just that we don't need to
50663e0c771STom Zanussi 			 * synthesize anything.  We really have to
50763e0c771STom Zanussi 			 * return this more properly and also
50863e0c771STom Zanussi 			 * propagate errors that now are calling die()
50963e0c771STom Zanussi 			 */
5108115d60cSArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(output, evsel_list,
5119215545eSTom Zanussi 								  process_synthesized_event,
5129215545eSTom Zanussi 								  session);
51363e0c771STom Zanussi 			if (err <= 0) {
51463e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
51563e0c771STom Zanussi 				return err;
51663e0c771STom Zanussi 			}
5179215545eSTom Zanussi 			advance_output(err);
5182c46dbb5STom Zanussi 		}
51963e0c771STom Zanussi 	}
5202c46dbb5STom Zanussi 
52123346f21SArnaldo Carvalho de Melo 	machine = perf_session__find_host_machine(session);
52223346f21SArnaldo Carvalho de Melo 	if (!machine) {
523a1645ce1SZhang, Yanmin 		pr_err("Couldn't find native kernel information.\n");
524a1645ce1SZhang, Yanmin 		return -1;
525a1645ce1SZhang, Yanmin 	}
526a1645ce1SZhang, Yanmin 
5278115d60cSArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
52823346f21SArnaldo Carvalho de Melo 						 session, machine, "_text");
52970162138SArnaldo Carvalho de Melo 	if (err < 0)
5308115d60cSArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
53123346f21SArnaldo Carvalho de Melo 							 session, machine, "_stext");
532c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
533c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
534c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
535c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
53656b03f3cSArnaldo Carvalho de Melo 
5378115d60cSArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(process_synthesized_event,
53823346f21SArnaldo Carvalho de Melo 					     session, machine);
539c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
540c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
541c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
542c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
543c1a3a4b9SArnaldo Carvalho de Melo 
544a1645ce1SZhang, Yanmin 	if (perf_guest)
5458115d60cSArnaldo Carvalho de Melo 		perf_session__process_machines(session,
5468115d60cSArnaldo Carvalho de Melo 					       perf_event__synthesize_guest_os);
547b7cece76SArnaldo Carvalho de Melo 
5480f82ebc4SArnaldo Carvalho de Melo 	if (!record_opts.system_wide)
5497c940c18SArnaldo Carvalho de Melo 		perf_event__synthesize_thread_map(evsel_list->threads,
5508115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
551d8f66248SArnaldo Carvalho de Melo 						  session);
552234fbbf5SArnaldo Carvalho de Melo 	else
5538115d60cSArnaldo Carvalho de Melo 		perf_event__synthesize_threads(process_synthesized_event,
5548115d60cSArnaldo Carvalho de Melo 					       session);
5557c6a1c65SPeter Zijlstra 
55686470930SIngo Molnar 	if (realtime_prio) {
55786470930SIngo Molnar 		struct sched_param param;
55886470930SIngo Molnar 
55986470930SIngo Molnar 		param.sched_priority = realtime_prio;
56086470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5616beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
56286470930SIngo Molnar 			exit(-1);
56386470930SIngo Molnar 		}
56486470930SIngo Molnar 	}
56586470930SIngo Molnar 
566764e16a3SDavid Ahern 	perf_evlist__enable(evsel_list);
567764e16a3SDavid Ahern 
568856e9660SPeter Zijlstra 	/*
569856e9660SPeter Zijlstra 	 * Let the child rip
570856e9660SPeter Zijlstra 	 */
571d4db3f16SArnaldo Carvalho de Melo 	if (forks)
57235b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
573856e9660SPeter Zijlstra 
574649c48a9SPeter Zijlstra 	for (;;) {
57586470930SIngo Molnar 		int hits = samples;
57686470930SIngo Molnar 
57798402807SFrederic Weisbecker 		mmap_read_all();
57886470930SIngo Molnar 
579649c48a9SPeter Zijlstra 		if (hits == samples) {
580649c48a9SPeter Zijlstra 			if (done)
581649c48a9SPeter Zijlstra 				break;
5825c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
5838b412664SPeter Zijlstra 			waking++;
5848b412664SPeter Zijlstra 		}
5858b412664SPeter Zijlstra 
5864152ab37SArnaldo Carvalho de Melo 		if (done)
5874152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
5888b412664SPeter Zijlstra 	}
5898b412664SPeter Zijlstra 
59018483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
591b44308f5SArnaldo Carvalho de Melo 		return 0;
592b44308f5SArnaldo Carvalho de Melo 
5938b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
59486470930SIngo Molnar 
59586470930SIngo Molnar 	/*
59686470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
59786470930SIngo Molnar 	 */
59886470930SIngo Molnar 	fprintf(stderr,
5999486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
60086470930SIngo Molnar 		(double)bytes_written / 1024.0 / 1024.0,
60186470930SIngo Molnar 		output_name,
60286470930SIngo Molnar 		bytes_written / 24);
60386470930SIngo Molnar 
60486470930SIngo Molnar 	return 0;
60539d17dacSArnaldo Carvalho de Melo 
60639d17dacSArnaldo Carvalho de Melo out_delete_session:
60739d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
60839d17dacSArnaldo Carvalho de Melo 	return err;
60986470930SIngo Molnar }
61086470930SIngo Molnar 
61186470930SIngo Molnar static const char * const record_usage[] = {
61286470930SIngo Molnar 	"perf record [<options>] [<command>]",
61386470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
61486470930SIngo Molnar 	NULL
61586470930SIngo Molnar };
61686470930SIngo Molnar 
6177865e817SFrederic Weisbecker static bool force, append_file;
6187865e817SFrederic Weisbecker 
619bca647aaSTom Zanussi const struct option record_options[] = {
620361c99a6SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &evsel_list, "event",
62186470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
622f120f9d5SJiri Olsa 		     parse_events_option),
623361c99a6SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &evsel_list, "filter",
624c171b552SLi Zefan 		     "event filter", parse_filter),
6250f82ebc4SArnaldo Carvalho de Melo 	OPT_INTEGER('p', "pid", &record_opts.target_pid,
626d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
6270f82ebc4SArnaldo Carvalho de Melo 	OPT_INTEGER('t', "tid", &record_opts.target_tid,
628d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
62986470930SIngo Molnar 	OPT_INTEGER('r', "realtime", &realtime_prio,
63086470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
6310f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record_opts.no_delay,
632acac03faSKirill Smelkov 		    "collect data without buffering"),
6330f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record_opts.raw_samples,
634daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
6350f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('a', "all-cpus", &record_opts.system_wide,
63686470930SIngo Molnar 			    "system-wide collection from all CPUs"),
63786470930SIngo Molnar 	OPT_BOOLEAN('A', "append", &append_file,
63886470930SIngo Molnar 			    "append to the output file to do incremental profiling"),
6390f82ebc4SArnaldo Carvalho de Melo 	OPT_STRING('C', "cpu", &record_opts.cpu_list, "cpu",
640c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
64186470930SIngo Molnar 	OPT_BOOLEAN('f', "force", &force,
6427865e817SFrederic Weisbecker 			"overwrite existing data file (deprecated)"),
6430f82ebc4SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record_opts.user_interval, "event period to sample"),
64486470930SIngo Molnar 	OPT_STRING('o', "output", &output_name, "file",
64586470930SIngo Molnar 		    "output file name"),
6460f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record_opts.no_inherit,
6472e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
6480f82ebc4SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record_opts.user_freq, "profile at this frequency"),
64901c2d99bSArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &record_opts.mmap_pages,
65001c2d99bSArnaldo Carvalho de Melo 		     "number of mmap data pages"),
651*ed80f581SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record_opts.group,
65243bece79SLin Ming 		    "put the counters into a counter group"),
6530f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('g', "call-graph", &record_opts.call_graph,
6543efa1cc9SIngo Molnar 		    "do call-graph (stack chain/backtrace) recording"),
655c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
6563da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
657b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
6580f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record_opts.inherit_stat,
659649c48a9SPeter Zijlstra 		    "per thread counts"),
6600f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record_opts.sample_address,
6614bba828dSAnton Blanchard 		    "Sample addresses"),
6620f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record_opts.sample_time, "Sample timestamps"),
6630f82ebc4SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record_opts.no_samples,
664649c48a9SPeter Zijlstra 		    "don't sample"),
665baa2f6ceSArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache,
666a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
667baa2f6ceSArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &no_buildid,
668baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
669023695d9SStephane Eranian 	OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
670023695d9SStephane Eranian 		     "monitor event in cgroup name only",
671023695d9SStephane Eranian 		     parse_cgroups),
67286470930SIngo Molnar 	OPT_END()
67386470930SIngo Molnar };
67486470930SIngo Molnar 
675f37a291cSIngo Molnar int cmd_record(int argc, const char **argv, const char *prefix __used)
67686470930SIngo Molnar {
67769aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
67869aad6f1SArnaldo Carvalho de Melo 	struct perf_evsel *pos;
67986470930SIngo Molnar 
680fbe96f29SStephane Eranian 	perf_header__set_cmdline(argc, argv);
681fbe96f29SStephane Eranian 
6827e2ed097SArnaldo Carvalho de Melo 	evsel_list = perf_evlist__new(NULL, NULL);
683361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
684361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
685361c99a6SArnaldo Carvalho de Melo 
686bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
687a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
6880f82ebc4SArnaldo Carvalho de Melo 	if (!argc && record_opts.target_pid == -1 && record_opts.target_tid == -1 &&
6890f82ebc4SArnaldo Carvalho de Melo 		!record_opts.system_wide && !record_opts.cpu_list)
690bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
69186470930SIngo Molnar 
6927865e817SFrederic Weisbecker 	if (force && append_file) {
6937865e817SFrederic Weisbecker 		fprintf(stderr, "Can't overwrite and append at the same time."
6947865e817SFrederic Weisbecker 				" You need to choose between -f and -A");
695bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
6967865e817SFrederic Weisbecker 	} else if (append_file) {
6977865e817SFrederic Weisbecker 		write_mode = WRITE_APPEND;
6987865e817SFrederic Weisbecker 	} else {
6997865e817SFrederic Weisbecker 		write_mode = WRITE_FORCE;
7007865e817SFrederic Weisbecker 	}
7017865e817SFrederic Weisbecker 
7020f82ebc4SArnaldo Carvalho de Melo 	if (nr_cgroups && !record_opts.system_wide) {
703023695d9SStephane Eranian 		fprintf(stderr, "cgroup monitoring only available in"
704023695d9SStephane Eranian 			" system-wide mode\n");
705023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
706023695d9SStephane Eranian 	}
707023695d9SStephane Eranian 
708655000e7SArnaldo Carvalho de Melo 	symbol__init();
709baa2f6ceSArnaldo Carvalho de Melo 
710ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
711646aaea6SArnaldo Carvalho de Melo 		pr_warning(
712646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
713ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
714646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
715646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
716646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
717646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
718646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
719ec80fde7SArnaldo Carvalho de Melo 
720baa2f6ceSArnaldo Carvalho de Melo 	if (no_buildid_cache || no_buildid)
721a1ac1d3cSStephane Eranian 		disable_buildid_cache();
722655000e7SArnaldo Carvalho de Melo 
723361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
724361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
72569aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
72669aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
727bbd36e5eSPeter Zijlstra 	}
72886470930SIngo Molnar 
7290f82ebc4SArnaldo Carvalho de Melo 	if (record_opts.target_pid != -1)
7300f82ebc4SArnaldo Carvalho de Melo 		record_opts.target_tid = record_opts.target_pid;
731d6d901c2SZhang, Yanmin 
7320f82ebc4SArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(evsel_list, record_opts.target_pid,
7330f82ebc4SArnaldo Carvalho de Melo 				     record_opts.target_tid, record_opts.cpu_list) < 0)
734dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
73569aad6f1SArnaldo Carvalho de Melo 
736361c99a6SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evsel_list->entries, node) {
7377e2ed097SArnaldo Carvalho de Melo 		if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
7387e2ed097SArnaldo Carvalho de Melo 					 evsel_list->threads->nr) < 0)
73969aad6f1SArnaldo Carvalho de Melo 			goto out_free_fd;
740ad7f4e3fSArnaldo Carvalho de Melo 		if (perf_header__push_event(pos->attr.config, event_name(pos)))
741ad7f4e3fSArnaldo Carvalho de Melo 			goto out_free_fd;
742d6d901c2SZhang, Yanmin 	}
7435c581041SArnaldo Carvalho de Melo 
7447e2ed097SArnaldo Carvalho de Melo 	if (perf_evlist__alloc_pollfd(evsel_list) < 0)
74539d17dacSArnaldo Carvalho de Melo 		goto out_free_fd;
746d6d901c2SZhang, Yanmin 
7470f82ebc4SArnaldo Carvalho de Melo 	if (record_opts.user_interval != ULLONG_MAX)
7480f82ebc4SArnaldo Carvalho de Melo 		record_opts.default_interval = record_opts.user_interval;
7490f82ebc4SArnaldo Carvalho de Melo 	if (record_opts.user_freq != UINT_MAX)
7500f82ebc4SArnaldo Carvalho de Melo 		record_opts.freq = record_opts.user_freq;
751f9212819SFrederic Weisbecker 
7527e4ff9e3SMike Galbraith 	/*
7537e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
7547e4ff9e3SMike Galbraith 	 */
7550f82ebc4SArnaldo Carvalho de Melo 	if (record_opts.default_interval)
7560f82ebc4SArnaldo Carvalho de Melo 		record_opts.freq = 0;
7570f82ebc4SArnaldo Carvalho de Melo 	else if (record_opts.freq) {
7580f82ebc4SArnaldo Carvalho de Melo 		record_opts.default_interval = record_opts.freq;
7597e4ff9e3SMike Galbraith 	} else {
7607e4ff9e3SMike Galbraith 		fprintf(stderr, "frequency and count are zero, aborting\n");
76139d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
7625c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
7637e4ff9e3SMike Galbraith 	}
7647e4ff9e3SMike Galbraith 
76539d17dacSArnaldo Carvalho de Melo 	err = __cmd_record(argc, argv);
76639d17dacSArnaldo Carvalho de Melo out_free_fd:
7677e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
768d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
769d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
77039d17dacSArnaldo Carvalho de Melo 	return err;
77186470930SIngo Molnar }
772