xref: /openbmc/linux/tools/perf/builtin-record.c (revision 727ab04edbc4767711a7aeff5e00249b267ed4c1)
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 
383de29cabSStephane Eranian static u64			user_interval			= ULLONG_MAX;
393de29cabSStephane Eranian static u64			default_interval		=      0;
4086470930SIngo Molnar 
4186470930SIngo Molnar static unsigned int		page_size;
42800cd25cSFrederic Weisbecker static unsigned int		mmap_pages			= UINT_MAX;
43f9212819SFrederic Weisbecker static unsigned int		user_freq 			= UINT_MAX;
4442e59d7dSIngo Molnar static int			freq				=   1000;
4586470930SIngo Molnar static int			output;
46529870e3STom Zanussi static int			pipe_output			=      0;
47d7065adbSFranck Bui-Huu static const char		*output_name			= NULL;
4843bece79SLin Ming static bool			group				=  false;
491967936dSArnaldo Carvalho de Melo static int			realtime_prio			=      0;
50acac03faSKirill Smelkov static bool			nodelay				=  false;
51c0555642SIan Munsie static bool			raw_samples			=  false;
529c90a61cSArnaldo Carvalho de Melo static bool			sample_id_all_avail		=   true;
53c0555642SIan Munsie static bool			system_wide			=  false;
5486470930SIngo Molnar static pid_t			target_pid			=     -1;
55d6d901c2SZhang, Yanmin static pid_t			target_tid			=     -1;
56933da83aSChris Wilson static pid_t			child_pid			=     -1;
572e6cdf99SStephane Eranian static bool			no_inherit			=  false;
587865e817SFrederic Weisbecker static enum write_mode_t	write_mode			= WRITE_FORCE;
59c0555642SIan Munsie static bool			call_graph			=  false;
60c0555642SIan Munsie static bool			inherit_stat			=  false;
61c0555642SIan Munsie static bool			no_samples			=  false;
62c0555642SIan Munsie static bool			sample_address			=  false;
639c90a61cSArnaldo Carvalho de Melo static bool			sample_time			=  false;
64a1ac1d3cSStephane Eranian static bool			no_buildid			=  false;
65baa2f6ceSArnaldo Carvalho de Melo static bool			no_buildid_cache		=  false;
66361c99a6SArnaldo Carvalho de Melo static struct perf_evlist	*evsel_list;
6786470930SIngo Molnar 
6842e59d7dSIngo Molnar static long			samples				=      0;
6942e59d7dSIngo Molnar static u64			bytes_written			=      0;
7086470930SIngo Molnar 
71f5970550SPeter Zijlstra static int			file_new			=      1;
726122e4e4SArnaldo Carvalho de Melo static off_t			post_processing_offset;
737c6a1c65SPeter Zijlstra 
7494c744b6SArnaldo Carvalho de Melo static struct perf_session	*session;
75c45c6ea2SStephane Eranian static const char		*cpu_list;
7633e49ea7SAndi Kleen static const char               *progname;
77f5970550SPeter Zijlstra 
789215545eSTom Zanussi static void advance_output(size_t size)
799215545eSTom Zanussi {
809215545eSTom Zanussi 	bytes_written += size;
819215545eSTom Zanussi }
829215545eSTom Zanussi 
83f5970550SPeter Zijlstra static void write_output(void *buf, size_t size)
84f5970550SPeter Zijlstra {
85f5970550SPeter Zijlstra 	while (size) {
86f5970550SPeter Zijlstra 		int ret = write(output, buf, size);
87f5970550SPeter Zijlstra 
88f5970550SPeter Zijlstra 		if (ret < 0)
89f5970550SPeter Zijlstra 			die("failed to write");
90f5970550SPeter Zijlstra 
91f5970550SPeter Zijlstra 		size -= ret;
92f5970550SPeter Zijlstra 		buf += ret;
93f5970550SPeter Zijlstra 
94f5970550SPeter Zijlstra 		bytes_written += ret;
95f5970550SPeter Zijlstra 	}
96f5970550SPeter Zijlstra }
97f5970550SPeter Zijlstra 
988115d60cSArnaldo Carvalho de Melo static int process_synthesized_event(union perf_event *event,
998d50e5b4SArnaldo Carvalho de Melo 				     struct perf_sample *sample __used,
100d8f66248SArnaldo Carvalho de Melo 				     struct perf_session *self __used)
101234fbbf5SArnaldo Carvalho de Melo {
1026122e4e4SArnaldo Carvalho de Melo 	write_output(event, event->header.size);
103234fbbf5SArnaldo Carvalho de Melo 	return 0;
104234fbbf5SArnaldo Carvalho de Melo }
105234fbbf5SArnaldo Carvalho de Melo 
106744bd8aaSArnaldo Carvalho de Melo static void mmap_read(struct perf_mmap *md)
10786470930SIngo Molnar {
108744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
10986470930SIngo Molnar 	unsigned int old = md->prev;
11086470930SIngo Molnar 	unsigned char *data = md->base + page_size;
11186470930SIngo Molnar 	unsigned long size;
11286470930SIngo Molnar 	void *buf;
11386470930SIngo Molnar 
114dc82009aSArnaldo Carvalho de Melo 	if (old == head)
115dc82009aSArnaldo Carvalho de Melo 		return;
11686470930SIngo Molnar 
11786470930SIngo Molnar 	samples++;
11886470930SIngo Molnar 
11986470930SIngo Molnar 	size = head - old;
12086470930SIngo Molnar 
12186470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
12286470930SIngo Molnar 		buf = &data[old & md->mask];
12386470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
12486470930SIngo Molnar 		old += size;
12586470930SIngo Molnar 
1266122e4e4SArnaldo Carvalho de Melo 		write_output(buf, size);
12786470930SIngo Molnar 	}
12886470930SIngo Molnar 
12986470930SIngo Molnar 	buf = &data[old & md->mask];
13086470930SIngo Molnar 	size = head - old;
13186470930SIngo Molnar 	old += size;
13286470930SIngo Molnar 
1336122e4e4SArnaldo Carvalho de Melo 	write_output(buf, size);
13486470930SIngo Molnar 
13586470930SIngo Molnar 	md->prev = old;
136115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
13786470930SIngo Molnar }
13886470930SIngo Molnar 
13986470930SIngo Molnar static volatile int done = 0;
140f7b7c26eSPeter Zijlstra static volatile int signr = -1;
14133e49ea7SAndi Kleen static volatile int child_finished = 0;
14286470930SIngo Molnar 
14386470930SIngo Molnar static void sig_handler(int sig)
14486470930SIngo Molnar {
14533e49ea7SAndi Kleen 	if (sig == SIGCHLD)
14633e49ea7SAndi Kleen 		child_finished = 1;
14733e49ea7SAndi Kleen 
14886470930SIngo Molnar 	done = 1;
149f7b7c26eSPeter Zijlstra 	signr = sig;
150f7b7c26eSPeter Zijlstra }
151f7b7c26eSPeter Zijlstra 
152f7b7c26eSPeter Zijlstra static void sig_atexit(void)
153f7b7c26eSPeter Zijlstra {
15433e49ea7SAndi Kleen 	int status;
15533e49ea7SAndi Kleen 
15633e49ea7SAndi Kleen 	if (child_pid > 0) {
15733e49ea7SAndi Kleen 		if (!child_finished)
158933da83aSChris Wilson 			kill(child_pid, SIGTERM);
159933da83aSChris Wilson 
16033e49ea7SAndi Kleen 		wait(&status);
16133e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
16233e49ea7SAndi Kleen 			psignal(WTERMSIG(status), progname);
16333e49ea7SAndi Kleen 	}
16433e49ea7SAndi Kleen 
16518483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
166f7b7c26eSPeter Zijlstra 		return;
167f7b7c26eSPeter Zijlstra 
168f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
169f7b7c26eSPeter Zijlstra 	kill(getpid(), signr);
17086470930SIngo Molnar }
17186470930SIngo Molnar 
172dd7927f4SArnaldo Carvalho de Melo static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
173dd7927f4SArnaldo Carvalho de Melo {
174dd7927f4SArnaldo Carvalho de Melo 	struct perf_event_attr *attr = &evsel->attr;
175dd7927f4SArnaldo Carvalho de Melo 	int track = !evsel->idx; /* only the first counter needs these */
1767c6a1c65SPeter Zijlstra 
177764e16a3SDavid Ahern 	attr->disabled		= 1;
1785d2cd909SArnaldo Carvalho de Melo 	attr->inherit		= !no_inherit;
1797c6a1c65SPeter Zijlstra 	attr->read_format	= PERF_FORMAT_TOTAL_TIME_ENABLED |
1807c6a1c65SPeter Zijlstra 				  PERF_FORMAT_TOTAL_TIME_RUNNING |
1817c6a1c65SPeter Zijlstra 				  PERF_FORMAT_ID;
18286470930SIngo Molnar 
1833a9f131fSFrederic Weisbecker 	attr->sample_type	|= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1843efa1cc9SIngo Molnar 
185361c99a6SArnaldo Carvalho de Melo 	if (evlist->nr_entries > 1)
1868907fd60SEric B Munson 		attr->sample_type |= PERF_SAMPLE_ID;
1878907fd60SEric B Munson 
188f9212819SFrederic Weisbecker 	/*
189f9212819SFrederic Weisbecker 	 * We default some events to a 1 default interval. But keep
190f9212819SFrederic Weisbecker 	 * it a weak assumption overridable by the user.
191f9212819SFrederic Weisbecker 	 */
192f9212819SFrederic Weisbecker 	if (!attr->sample_period || (user_freq != UINT_MAX &&
1933de29cabSStephane Eranian 				     user_interval != ULLONG_MAX)) {
19486470930SIngo Molnar 		if (freq) {
195ea1900e5SPeter Zijlstra 			attr->sample_type	|= PERF_SAMPLE_PERIOD;
19686470930SIngo Molnar 			attr->freq		= 1;
19786470930SIngo Molnar 			attr->sample_freq	= freq;
198f9212819SFrederic Weisbecker 		} else {
199f9212819SFrederic Weisbecker 			attr->sample_period = default_interval;
200f9212819SFrederic Weisbecker 		}
20186470930SIngo Molnar 	}
2023efa1cc9SIngo Molnar 
203649c48a9SPeter Zijlstra 	if (no_samples)
204649c48a9SPeter Zijlstra 		attr->sample_freq = 0;
205649c48a9SPeter Zijlstra 
206649c48a9SPeter Zijlstra 	if (inherit_stat)
207649c48a9SPeter Zijlstra 		attr->inherit_stat = 1;
208649c48a9SPeter Zijlstra 
2093af9e859SEric B Munson 	if (sample_address) {
2104bba828dSAnton Blanchard 		attr->sample_type	|= PERF_SAMPLE_ADDR;
2113af9e859SEric B Munson 		attr->mmap_data = track;
2123af9e859SEric B Munson 	}
2134bba828dSAnton Blanchard 
2143efa1cc9SIngo Molnar 	if (call_graph)
2153efa1cc9SIngo Molnar 		attr->sample_type	|= PERF_SAMPLE_CALLCHAIN;
2163efa1cc9SIngo Molnar 
217f60f3593SArun Sharma 	if (system_wide)
218f60f3593SArun Sharma 		attr->sample_type	|= PERF_SAMPLE_CPU;
219f60f3593SArun Sharma 
220a43d3f08SArnaldo Carvalho de Melo 	if (sample_id_all_avail &&
221a43d3f08SArnaldo Carvalho de Melo 	    (sample_time || system_wide || !no_inherit || cpu_list))
2229c90a61cSArnaldo Carvalho de Melo 		attr->sample_type	|= PERF_SAMPLE_TIME;
2239c90a61cSArnaldo Carvalho de Melo 
224cd6feeeaSIngo Molnar 	if (raw_samples) {
2256ddf259dSIngo Molnar 		attr->sample_type	|= PERF_SAMPLE_TIME;
226daac07b2SFrederic Weisbecker 		attr->sample_type	|= PERF_SAMPLE_RAW;
227cd6feeeaSIngo Molnar 		attr->sample_type	|= PERF_SAMPLE_CPU;
228cd6feeeaSIngo Molnar 	}
229f413cdb8SFrederic Weisbecker 
230acac03faSKirill Smelkov 	if (nodelay) {
231acac03faSKirill Smelkov 		attr->watermark = 0;
232acac03faSKirill Smelkov 		attr->wakeup_events = 1;
233acac03faSKirill Smelkov 	}
234acac03faSKirill Smelkov 
23586470930SIngo Molnar 	attr->mmap		= track;
23686470930SIngo Molnar 	attr->comm		= track;
237dd7927f4SArnaldo Carvalho de Melo 
2382e6cdf99SStephane Eranian 	if (target_pid == -1 && target_tid == -1 && !system_wide) {
2394502d77cSPeter Zijlstra 		attr->disabled = 1;
240bedbfdeaSEric B Munson 		attr->enable_on_exec = 1;
24146be604bSZhang, Yanmin 	}
242dd7927f4SArnaldo Carvalho de Melo }
243dd7927f4SArnaldo Carvalho de Melo 
244a91e5431SArnaldo Carvalho de Melo static bool perf_evlist__equal(struct perf_evlist *evlist,
245a91e5431SArnaldo Carvalho de Melo 			       struct perf_evlist *other)
246a91e5431SArnaldo Carvalho de Melo {
247a91e5431SArnaldo Carvalho de Melo 	struct perf_evsel *pos, *pair;
248a91e5431SArnaldo Carvalho de Melo 
249a91e5431SArnaldo Carvalho de Melo 	if (evlist->nr_entries != other->nr_entries)
250a91e5431SArnaldo Carvalho de Melo 		return false;
251a91e5431SArnaldo Carvalho de Melo 
252a91e5431SArnaldo Carvalho de Melo 	pair = list_entry(other->entries.next, struct perf_evsel, node);
253a91e5431SArnaldo Carvalho de Melo 
254a91e5431SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
255a91e5431SArnaldo Carvalho de Melo 		if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
256a91e5431SArnaldo Carvalho de Melo 			return false;
257a91e5431SArnaldo Carvalho de Melo 		pair = list_entry(pair->node.next, struct perf_evsel, node);
258a91e5431SArnaldo Carvalho de Melo 	}
259a91e5431SArnaldo Carvalho de Melo 
260a91e5431SArnaldo Carvalho de Melo 	return true;
261a91e5431SArnaldo Carvalho de Melo }
262a91e5431SArnaldo Carvalho de Melo 
263dd7927f4SArnaldo Carvalho de Melo static void open_counters(struct perf_evlist *evlist)
264dd7927f4SArnaldo Carvalho de Melo {
265*727ab04eSArnaldo Carvalho de Melo 	struct perf_evsel *pos, *first;
266dd7927f4SArnaldo Carvalho de Melo 
2675d2cd909SArnaldo Carvalho de Melo 	if (evlist->cpus->map[0] < 0)
2685d2cd909SArnaldo Carvalho de Melo 		no_inherit = true;
2695d2cd909SArnaldo Carvalho de Melo 
270*727ab04eSArnaldo Carvalho de Melo 	first = list_entry(evlist->entries.next, struct perf_evsel, node);
271*727ab04eSArnaldo Carvalho de Melo 
272dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
273dd7927f4SArnaldo Carvalho de Melo 		struct perf_event_attr *attr = &pos->attr;
274*727ab04eSArnaldo Carvalho de Melo 		struct xyarray *group_fd = NULL;
275dd7927f4SArnaldo Carvalho de Melo 		/*
276dd7927f4SArnaldo Carvalho de Melo 		 * Check if parse_single_tracepoint_event has already asked for
277dd7927f4SArnaldo Carvalho de Melo 		 * PERF_SAMPLE_TIME.
278dd7927f4SArnaldo Carvalho de Melo 		 *
279dd7927f4SArnaldo Carvalho de Melo 		 * XXX this is kludgy but short term fix for problems introduced by
280dd7927f4SArnaldo Carvalho de Melo 		 * eac23d1c that broke 'perf script' by having different sample_types
281dd7927f4SArnaldo Carvalho de Melo 		 * when using multiple tracepoint events when we use a perf binary
282dd7927f4SArnaldo Carvalho de Melo 		 * that tries to use sample_id_all on an older kernel.
283dd7927f4SArnaldo Carvalho de Melo 		 *
284dd7927f4SArnaldo Carvalho de Melo 		 * We need to move counter creation to perf_session, support
285dd7927f4SArnaldo Carvalho de Melo 		 * different sample_types, etc.
286dd7927f4SArnaldo Carvalho de Melo 		 */
287dd7927f4SArnaldo Carvalho de Melo 		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
288dd7927f4SArnaldo Carvalho de Melo 
289*727ab04eSArnaldo Carvalho de Melo 		if (group && pos != first)
290*727ab04eSArnaldo Carvalho de Melo 			group_fd = first->fd;
291*727ab04eSArnaldo Carvalho de Melo 
292dd7927f4SArnaldo Carvalho de Melo 		config_attr(pos, evlist);
2939c90a61cSArnaldo Carvalho de Melo retry_sample_id:
2949c90a61cSArnaldo Carvalho de Melo 		attr->sample_id_all = sample_id_all_avail ? 1 : 0;
2953da297a6SIngo Molnar try_again:
296*727ab04eSArnaldo Carvalho de Melo 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group,
297*727ab04eSArnaldo Carvalho de Melo 				     group_fd) < 0) {
29886470930SIngo Molnar 			int err = errno;
29986470930SIngo Molnar 
300c286c419SArnaldo Carvalho de Melo 			if (err == EPERM || err == EACCES) {
301c286c419SArnaldo Carvalho de Melo 				ui__warning_paranoid();
302c286c419SArnaldo Carvalho de Melo 				exit(EXIT_FAILURE);
303c286c419SArnaldo Carvalho de Melo 			} else if (err ==  ENODEV && cpu_list) {
304d6d901c2SZhang, Yanmin 				die("No such device - did you specify"
305d6d901c2SZhang, Yanmin 					" an out-of-range profile CPU?\n");
3069c90a61cSArnaldo Carvalho de Melo 			} else if (err == EINVAL && sample_id_all_avail) {
3079c90a61cSArnaldo Carvalho de Melo 				/*
3089c90a61cSArnaldo Carvalho de Melo 				 * Old kernel, no attr->sample_id_type_all field
3099c90a61cSArnaldo Carvalho de Melo 				 */
3109c90a61cSArnaldo Carvalho de Melo 				sample_id_all_avail = false;
311a43d3f08SArnaldo Carvalho de Melo 				if (!sample_time && !raw_samples && !time_needed)
312eac23d1cSIan Munsie 					attr->sample_type &= ~PERF_SAMPLE_TIME;
313eac23d1cSIan Munsie 
3149c90a61cSArnaldo Carvalho de Melo 				goto retry_sample_id;
315d6d901c2SZhang, Yanmin 			}
3163da297a6SIngo Molnar 
3173da297a6SIngo Molnar 			/*
3183da297a6SIngo Molnar 			 * If it's cycles then fall back to hrtimer
3193da297a6SIngo Molnar 			 * based cpu-clock-tick sw counter, which
3203da297a6SIngo Molnar 			 * is always available even if no PMU support:
3213da297a6SIngo Molnar 			 */
3223da297a6SIngo Molnar 			if (attr->type == PERF_TYPE_HARDWARE
323f4dbfa8fSPeter Zijlstra 					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {
3243da297a6SIngo Molnar 
3253da297a6SIngo Molnar 				if (verbose)
326ca6a4258SDavid Ahern 					ui__warning("The cycles event is not supported, "
327ca6a4258SDavid Ahern 						    "trying to fall back to cpu-clock-ticks\n");
3283da297a6SIngo Molnar 				attr->type = PERF_TYPE_SOFTWARE;
329f4dbfa8fSPeter Zijlstra 				attr->config = PERF_COUNT_SW_CPU_CLOCK;
3303da297a6SIngo Molnar 				goto try_again;
3313da297a6SIngo Molnar 			}
332ca6a4258SDavid Ahern 
333ca6a4258SDavid Ahern 			if (err == ENOENT) {
334ca6a4258SDavid Ahern 				ui__warning("The %s event is not supported.\n",
335ca6a4258SDavid Ahern 					    event_name(pos));
336ca6a4258SDavid Ahern 				exit(EXIT_FAILURE);
337ca6a4258SDavid Ahern 			}
338ca6a4258SDavid Ahern 
33930c806a0SIngo Molnar 			printf("\n");
340d9cf837eSCorey Ashford 			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
341dd7927f4SArnaldo Carvalho de Melo 			      err, strerror(err));
342bfd45118SSimon Kaempflein 
343bfd45118SSimon Kaempflein #if defined(__i386__) || defined(__x86_64__)
344bfd45118SSimon Kaempflein 			if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
345d6d901c2SZhang, Yanmin 				die("No hardware sampling interrupt available."
346d6d901c2SZhang, Yanmin 				    " No APIC? If so then you can boot the kernel"
347d6d901c2SZhang, Yanmin 				    " with the \"lapic\" boot parameter to"
348d6d901c2SZhang, Yanmin 				    " force-enable it.\n");
349bfd45118SSimon Kaempflein #endif
350bfd45118SSimon Kaempflein 
351cdd6c482SIngo Molnar 			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
3527c6a1c65SPeter Zijlstra 		}
3537c6a1c65SPeter Zijlstra 	}
3547c6a1c65SPeter Zijlstra 
3550a102479SFrederic Weisbecker 	if (perf_evlist__set_filters(evlist)) {
3560a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
3570a102479SFrederic Weisbecker 			strerror(errno));
3580a102479SFrederic Weisbecker 		exit(-1);
3590a102479SFrederic Weisbecker 	}
3600a102479SFrederic Weisbecker 
3617e2ed097SArnaldo Carvalho de Melo 	if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
3620a27d7f9SArnaldo Carvalho de Melo 		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
3630a27d7f9SArnaldo Carvalho de Melo 
364a91e5431SArnaldo Carvalho de Melo 	if (file_new)
365a91e5431SArnaldo Carvalho de Melo 		session->evlist = evlist;
366a91e5431SArnaldo Carvalho de Melo 	else {
367a91e5431SArnaldo Carvalho de Melo 		if (!perf_evlist__equal(session->evlist, evlist)) {
368a91e5431SArnaldo Carvalho de Melo 			fprintf(stderr, "incompatible append\n");
369a91e5431SArnaldo Carvalho de Melo 			exit(-1);
370dd7927f4SArnaldo Carvalho de Melo 		}
37186470930SIngo Molnar  	}
37286470930SIngo Molnar 
373a91e5431SArnaldo Carvalho de Melo 	perf_session__update_sample_type(session);
374a91e5431SArnaldo Carvalho de Melo }
375a91e5431SArnaldo Carvalho de Melo 
3766122e4e4SArnaldo Carvalho de Melo static int process_buildids(void)
3776122e4e4SArnaldo Carvalho de Melo {
3786122e4e4SArnaldo Carvalho de Melo 	u64 size = lseek(output, 0, SEEK_CUR);
3796122e4e4SArnaldo Carvalho de Melo 
3809f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
3819f591fd7SArnaldo Carvalho de Melo 		return 0;
3829f591fd7SArnaldo Carvalho de Melo 
3836122e4e4SArnaldo Carvalho de Melo 	session->fd = output;
3846122e4e4SArnaldo Carvalho de Melo 	return __perf_session__process_events(session, post_processing_offset,
3856122e4e4SArnaldo Carvalho de Melo 					      size - post_processing_offset,
3866122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
3876122e4e4SArnaldo Carvalho de Melo }
3886122e4e4SArnaldo Carvalho de Melo 
389f5970550SPeter Zijlstra static void atexit_header(void)
390f5970550SPeter Zijlstra {
391c7929e47STom Zanussi 	if (!pipe_output) {
39294c744b6SArnaldo Carvalho de Melo 		session->header.data_size += bytes_written;
393f5970550SPeter Zijlstra 
394baa2f6ceSArnaldo Carvalho de Melo 		if (!no_buildid)
3956122e4e4SArnaldo Carvalho de Melo 			process_buildids();
396a91e5431SArnaldo Carvalho de Melo 		perf_session__write_header(session, evsel_list, output, true);
39739d17dacSArnaldo Carvalho de Melo 		perf_session__delete(session);
398361c99a6SArnaldo Carvalho de Melo 		perf_evlist__delete(evsel_list);
399d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
400c7929e47STom Zanussi 	}
401f5970550SPeter Zijlstra }
402f5970550SPeter Zijlstra 
4038115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
404a1645ce1SZhang, Yanmin {
405a1645ce1SZhang, Yanmin 	int err;
40623346f21SArnaldo Carvalho de Melo 	struct perf_session *psession = data;
407a1645ce1SZhang, Yanmin 
40823346f21SArnaldo Carvalho de Melo 	if (machine__is_host(machine))
409a1645ce1SZhang, Yanmin 		return;
410a1645ce1SZhang, Yanmin 
411a1645ce1SZhang, Yanmin 	/*
412a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
413a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
414a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
415a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
416a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
417a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
418a1645ce1SZhang, Yanmin 	 */
4198115d60cSArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(process_synthesized_event,
42023346f21SArnaldo Carvalho de Melo 					     psession, machine);
421a1645ce1SZhang, Yanmin 	if (err < 0)
422a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
42323346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
424a1645ce1SZhang, Yanmin 
425a1645ce1SZhang, Yanmin 	/*
426a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
427a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
428a1645ce1SZhang, Yanmin 	 */
4298115d60cSArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
43023346f21SArnaldo Carvalho de Melo 						 psession, machine, "_text");
431a1645ce1SZhang, Yanmin 	if (err < 0)
4328115d60cSArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
4338115d60cSArnaldo Carvalho de Melo 							 psession, machine,
4348115d60cSArnaldo Carvalho de Melo 							 "_stext");
435a1645ce1SZhang, Yanmin 	if (err < 0)
436a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
43723346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
438a1645ce1SZhang, Yanmin }
439a1645ce1SZhang, Yanmin 
44098402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
44198402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
44298402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
44398402807SFrederic Weisbecker };
44498402807SFrederic Weisbecker 
44598402807SFrederic Weisbecker static void mmap_read_all(void)
44698402807SFrederic Weisbecker {
4470e2e63ddSPeter Zijlstra 	int i;
44898402807SFrederic Weisbecker 
449aece948fSArnaldo Carvalho de Melo 	for (i = 0; i < evsel_list->nr_mmaps; i++) {
4500a27d7f9SArnaldo Carvalho de Melo 		if (evsel_list->mmap[i].base)
4510a27d7f9SArnaldo Carvalho de Melo 			mmap_read(&evsel_list->mmap[i]);
45298402807SFrederic Weisbecker 	}
45398402807SFrederic Weisbecker 
45498402807SFrederic Weisbecker 	if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
45598402807SFrederic Weisbecker 		write_output(&finished_round_event, sizeof(finished_round_event));
45698402807SFrederic Weisbecker }
45798402807SFrederic Weisbecker 
458d4db3f16SArnaldo Carvalho de Melo static int __cmd_record(int argc, const char **argv)
45986470930SIngo Molnar {
46086470930SIngo Molnar 	struct stat st;
46186470930SIngo Molnar 	int flags;
4624dc0a04bSArnaldo Carvalho de Melo 	int err;
4638b412664SPeter Zijlstra 	unsigned long waking = 0;
464856e9660SPeter Zijlstra 	int child_ready_pipe[2], go_pipe[2];
46546be604bSZhang, Yanmin 	const bool forks = argc > 0;
466856e9660SPeter Zijlstra 	char buf;
46723346f21SArnaldo Carvalho de Melo 	struct machine *machine;
46886470930SIngo Molnar 
46933e49ea7SAndi Kleen 	progname = argv[0];
47033e49ea7SAndi Kleen 
47186470930SIngo Molnar 	page_size = sysconf(_SC_PAGE_SIZE);
47286470930SIngo Molnar 
473f5970550SPeter Zijlstra 	atexit(sig_atexit);
474f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
475f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
47618483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
477f5970550SPeter Zijlstra 
478d4db3f16SArnaldo Carvalho de Melo 	if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
479856e9660SPeter Zijlstra 		perror("failed to create pipes");
480856e9660SPeter Zijlstra 		exit(-1);
481856e9660SPeter Zijlstra 	}
482856e9660SPeter Zijlstra 
483d7065adbSFranck Bui-Huu 	if (!output_name) {
484d7065adbSFranck Bui-Huu 		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
485d7065adbSFranck Bui-Huu 			pipe_output = 1;
486d7065adbSFranck Bui-Huu 		else
487d7065adbSFranck Bui-Huu 			output_name = "perf.data";
488d7065adbSFranck Bui-Huu 	}
489d7065adbSFranck Bui-Huu 	if (output_name) {
490529870e3STom Zanussi 		if (!strcmp(output_name, "-"))
491529870e3STom Zanussi 			pipe_output = 1;
492529870e3STom Zanussi 		else if (!stat(output_name, &st) && st.st_size) {
4937865e817SFrederic Weisbecker 			if (write_mode == WRITE_FORCE) {
494b38d3464SArnaldo Carvalho de Melo 				char oldname[PATH_MAX];
495b38d3464SArnaldo Carvalho de Melo 				snprintf(oldname, sizeof(oldname), "%s.old",
496b38d3464SArnaldo Carvalho de Melo 					 output_name);
497b38d3464SArnaldo Carvalho de Melo 				unlink(oldname);
498b38d3464SArnaldo Carvalho de Melo 				rename(output_name, oldname);
499b38d3464SArnaldo Carvalho de Melo 			}
5007865e817SFrederic Weisbecker 		} else if (write_mode == WRITE_APPEND) {
5017865e817SFrederic Weisbecker 			write_mode = WRITE_FORCE;
502266e0e21SPierre Habouzit 		}
503d7065adbSFranck Bui-Huu 	}
50486470930SIngo Molnar 
505f887f301SXiao Guangrong 	flags = O_CREAT|O_RDWR;
5067865e817SFrederic Weisbecker 	if (write_mode == WRITE_APPEND)
507f5970550SPeter Zijlstra 		file_new = 0;
50886470930SIngo Molnar 	else
50986470930SIngo Molnar 		flags |= O_TRUNC;
51086470930SIngo Molnar 
511529870e3STom Zanussi 	if (pipe_output)
512529870e3STom Zanussi 		output = STDOUT_FILENO;
513529870e3STom Zanussi 	else
51486470930SIngo Molnar 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
51586470930SIngo Molnar 	if (output < 0) {
51686470930SIngo Molnar 		perror("failed to create output file");
51786470930SIngo Molnar 		exit(-1);
51886470930SIngo Molnar 	}
51986470930SIngo Molnar 
5207865e817SFrederic Weisbecker 	session = perf_session__new(output_name, O_WRONLY,
52121ef97f0SIan Munsie 				    write_mode == WRITE_FORCE, false, NULL);
52294c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
523a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
524a9a70bbcSArnaldo Carvalho de Melo 		return -1;
525a9a70bbcSArnaldo Carvalho de Melo 	}
526a9a70bbcSArnaldo Carvalho de Melo 
527baa2f6ceSArnaldo Carvalho de Melo 	if (!no_buildid)
528baa2f6ceSArnaldo Carvalho de Melo 		perf_header__set_feat(&session->header, HEADER_BUILD_ID);
529baa2f6ceSArnaldo Carvalho de Melo 
5304dc0a04bSArnaldo Carvalho de Melo 	if (!file_new) {
531a91e5431SArnaldo Carvalho de Melo 		err = perf_session__read_header(session, output);
5324dc0a04bSArnaldo Carvalho de Melo 		if (err < 0)
53339d17dacSArnaldo Carvalho de Melo 			goto out_delete_session;
5344dc0a04bSArnaldo Carvalho de Melo 	}
5354dc0a04bSArnaldo Carvalho de Melo 
536361c99a6SArnaldo Carvalho de Melo 	if (have_tracepoints(&evsel_list->entries))
53794c744b6SArnaldo Carvalho de Melo 		perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
53803456a15SFrederic Weisbecker 
539fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_HOSTNAME);
540fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_OSRELEASE);
541fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_ARCH);
542fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPUDESC);
543fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_NRCPUS);
544fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
545fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CMDLINE);
546fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_VERSION);
547fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
548fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
549fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
550fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPUID);
551fbe96f29SStephane Eranian 
552800cd25cSFrederic Weisbecker 	/* 512 kiB: default amount of unprivileged mlocked memory */
553800cd25cSFrederic Weisbecker 	if (mmap_pages == UINT_MAX)
554800cd25cSFrederic Weisbecker 		mmap_pages = (512 * 1024) / page_size;
555800cd25cSFrederic Weisbecker 
556d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
55746be604bSZhang, Yanmin 		child_pid = fork();
5582fb750e8SBorislav Petkov 		if (child_pid < 0) {
559856e9660SPeter Zijlstra 			perror("failed to fork");
560856e9660SPeter Zijlstra 			exit(-1);
561856e9660SPeter Zijlstra 		}
5627c6a1c65SPeter Zijlstra 
56346be604bSZhang, Yanmin 		if (!child_pid) {
564529870e3STom Zanussi 			if (pipe_output)
565529870e3STom Zanussi 				dup2(2, 1);
566856e9660SPeter Zijlstra 			close(child_ready_pipe[0]);
567856e9660SPeter Zijlstra 			close(go_pipe[1]);
568856e9660SPeter Zijlstra 			fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
569856e9660SPeter Zijlstra 
570856e9660SPeter Zijlstra 			/*
571856e9660SPeter Zijlstra 			 * Do a dummy execvp to get the PLT entry resolved,
572856e9660SPeter Zijlstra 			 * so we avoid the resolver overhead on the real
573856e9660SPeter Zijlstra 			 * execvp call.
574856e9660SPeter Zijlstra 			 */
575856e9660SPeter Zijlstra 			execvp("", (char **)argv);
576856e9660SPeter Zijlstra 
577856e9660SPeter Zijlstra 			/*
578856e9660SPeter Zijlstra 			 * Tell the parent we're ready to go
579856e9660SPeter Zijlstra 			 */
580856e9660SPeter Zijlstra 			close(child_ready_pipe[1]);
581856e9660SPeter Zijlstra 
582856e9660SPeter Zijlstra 			/*
583856e9660SPeter Zijlstra 			 * Wait until the parent tells us to go.
584856e9660SPeter Zijlstra 			 */
585856e9660SPeter Zijlstra 			if (read(go_pipe[0], &buf, 1) == -1)
586856e9660SPeter Zijlstra 				perror("unable to read pipe");
587856e9660SPeter Zijlstra 
588856e9660SPeter Zijlstra 			execvp(argv[0], (char **)argv);
589856e9660SPeter Zijlstra 
590856e9660SPeter Zijlstra 			perror(argv[0]);
59118483b81SArnaldo Carvalho de Melo 			kill(getppid(), SIGUSR1);
592856e9660SPeter Zijlstra 			exit(-1);
593856e9660SPeter Zijlstra 		}
594856e9660SPeter Zijlstra 
595d6d901c2SZhang, Yanmin 		if (!system_wide && target_tid == -1 && target_pid == -1)
5967e2ed097SArnaldo Carvalho de Melo 			evsel_list->threads->map[0] = child_pid;
597d6d901c2SZhang, Yanmin 
598856e9660SPeter Zijlstra 		close(child_ready_pipe[1]);
599856e9660SPeter Zijlstra 		close(go_pipe[0]);
600856e9660SPeter Zijlstra 		/*
601856e9660SPeter Zijlstra 		 * wait for child to settle
602856e9660SPeter Zijlstra 		 */
603856e9660SPeter Zijlstra 		if (read(child_ready_pipe[0], &buf, 1) == -1) {
604856e9660SPeter Zijlstra 			perror("unable to read pipe");
605856e9660SPeter Zijlstra 			exit(-1);
606856e9660SPeter Zijlstra 		}
607856e9660SPeter Zijlstra 		close(child_ready_pipe[0]);
608856e9660SPeter Zijlstra 	}
609856e9660SPeter Zijlstra 
610dd7927f4SArnaldo Carvalho de Melo 	open_counters(evsel_list);
61186470930SIngo Molnar 
612712a4b60SArnaldo Carvalho de Melo 	/*
613712a4b60SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at atexit_header()
614712a4b60SArnaldo Carvalho de Melo 	 */
615712a4b60SArnaldo Carvalho de Melo 	atexit(atexit_header);
616712a4b60SArnaldo Carvalho de Melo 
617529870e3STom Zanussi 	if (pipe_output) {
618529870e3STom Zanussi 		err = perf_header__write_pipe(output);
619529870e3STom Zanussi 		if (err < 0)
620529870e3STom Zanussi 			return err;
621529870e3STom Zanussi 	} else if (file_new) {
622a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
623361c99a6SArnaldo Carvalho de Melo 						 output, false);
624d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
625d5eed904SArnaldo Carvalho de Melo 			return err;
626d5eed904SArnaldo Carvalho de Melo 	}
6277c6a1c65SPeter Zijlstra 
6286122e4e4SArnaldo Carvalho de Melo 	post_processing_offset = lseek(output, 0, SEEK_CUR);
6296122e4e4SArnaldo Carvalho de Melo 
6302c46dbb5STom Zanussi 	if (pipe_output) {
631a91e5431SArnaldo Carvalho de Melo 		err = perf_session__synthesize_attrs(session,
632a91e5431SArnaldo Carvalho de Melo 						     process_synthesized_event);
6332c46dbb5STom Zanussi 		if (err < 0) {
6342c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
6352c46dbb5STom Zanussi 			return err;
6362c46dbb5STom Zanussi 		}
637cd19a035STom Zanussi 
6388115d60cSArnaldo Carvalho de Melo 		err = perf_event__synthesize_event_types(process_synthesized_event,
639cd19a035STom Zanussi 							 session);
640cd19a035STom Zanussi 		if (err < 0) {
641cd19a035STom Zanussi 			pr_err("Couldn't synthesize event_types.\n");
642cd19a035STom Zanussi 			return err;
643cd19a035STom Zanussi 		}
6449215545eSTom Zanussi 
645361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
64663e0c771STom Zanussi 			/*
64763e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
64863e0c771STom Zanussi 			 * there were no tracepoints so its not really
64963e0c771STom Zanussi 			 * an error, just that we don't need to
65063e0c771STom Zanussi 			 * synthesize anything.  We really have to
65163e0c771STom Zanussi 			 * return this more properly and also
65263e0c771STom Zanussi 			 * propagate errors that now are calling die()
65363e0c771STom Zanussi 			 */
6548115d60cSArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(output, evsel_list,
6559215545eSTom Zanussi 								  process_synthesized_event,
6569215545eSTom Zanussi 								  session);
65763e0c771STom Zanussi 			if (err <= 0) {
65863e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
65963e0c771STom Zanussi 				return err;
66063e0c771STom Zanussi 			}
6619215545eSTom Zanussi 			advance_output(err);
6622c46dbb5STom Zanussi 		}
66363e0c771STom Zanussi 	}
6642c46dbb5STom Zanussi 
66523346f21SArnaldo Carvalho de Melo 	machine = perf_session__find_host_machine(session);
66623346f21SArnaldo Carvalho de Melo 	if (!machine) {
667a1645ce1SZhang, Yanmin 		pr_err("Couldn't find native kernel information.\n");
668a1645ce1SZhang, Yanmin 		return -1;
669a1645ce1SZhang, Yanmin 	}
670a1645ce1SZhang, Yanmin 
6718115d60cSArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
67223346f21SArnaldo Carvalho de Melo 						 session, machine, "_text");
67370162138SArnaldo Carvalho de Melo 	if (err < 0)
6748115d60cSArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
67523346f21SArnaldo Carvalho de Melo 							 session, machine, "_stext");
676c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
677c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
678c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
679c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
68056b03f3cSArnaldo Carvalho de Melo 
6818115d60cSArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(process_synthesized_event,
68223346f21SArnaldo Carvalho de Melo 					     session, machine);
683c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
684c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
685c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
686c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
687c1a3a4b9SArnaldo Carvalho de Melo 
688a1645ce1SZhang, Yanmin 	if (perf_guest)
6898115d60cSArnaldo Carvalho de Melo 		perf_session__process_machines(session,
6908115d60cSArnaldo Carvalho de Melo 					       perf_event__synthesize_guest_os);
691b7cece76SArnaldo Carvalho de Melo 
692cf103a14SStephane Eranian 	if (!system_wide)
6937c940c18SArnaldo Carvalho de Melo 		perf_event__synthesize_thread_map(evsel_list->threads,
6948115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
695d8f66248SArnaldo Carvalho de Melo 						  session);
696234fbbf5SArnaldo Carvalho de Melo 	else
6978115d60cSArnaldo Carvalho de Melo 		perf_event__synthesize_threads(process_synthesized_event,
6988115d60cSArnaldo Carvalho de Melo 					       session);
6997c6a1c65SPeter Zijlstra 
70086470930SIngo Molnar 	if (realtime_prio) {
70186470930SIngo Molnar 		struct sched_param param;
70286470930SIngo Molnar 
70386470930SIngo Molnar 		param.sched_priority = realtime_prio;
70486470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
7056beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
70686470930SIngo Molnar 			exit(-1);
70786470930SIngo Molnar 		}
70886470930SIngo Molnar 	}
70986470930SIngo Molnar 
710764e16a3SDavid Ahern 	perf_evlist__enable(evsel_list);
711764e16a3SDavid Ahern 
712856e9660SPeter Zijlstra 	/*
713856e9660SPeter Zijlstra 	 * Let the child rip
714856e9660SPeter Zijlstra 	 */
715d4db3f16SArnaldo Carvalho de Melo 	if (forks)
716856e9660SPeter Zijlstra 		close(go_pipe[1]);
717856e9660SPeter Zijlstra 
718649c48a9SPeter Zijlstra 	for (;;) {
71986470930SIngo Molnar 		int hits = samples;
72086470930SIngo Molnar 
72198402807SFrederic Weisbecker 		mmap_read_all();
72286470930SIngo Molnar 
723649c48a9SPeter Zijlstra 		if (hits == samples) {
724649c48a9SPeter Zijlstra 			if (done)
725649c48a9SPeter Zijlstra 				break;
7265c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
7278b412664SPeter Zijlstra 			waking++;
7288b412664SPeter Zijlstra 		}
7298b412664SPeter Zijlstra 
7304152ab37SArnaldo Carvalho de Melo 		if (done)
7314152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
7328b412664SPeter Zijlstra 	}
7338b412664SPeter Zijlstra 
73418483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
735b44308f5SArnaldo Carvalho de Melo 		return 0;
736b44308f5SArnaldo Carvalho de Melo 
7378b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
73886470930SIngo Molnar 
73986470930SIngo Molnar 	/*
74086470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
74186470930SIngo Molnar 	 */
74286470930SIngo Molnar 	fprintf(stderr,
7439486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
74486470930SIngo Molnar 		(double)bytes_written / 1024.0 / 1024.0,
74586470930SIngo Molnar 		output_name,
74686470930SIngo Molnar 		bytes_written / 24);
74786470930SIngo Molnar 
74886470930SIngo Molnar 	return 0;
74939d17dacSArnaldo Carvalho de Melo 
75039d17dacSArnaldo Carvalho de Melo out_delete_session:
75139d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
75239d17dacSArnaldo Carvalho de Melo 	return err;
75386470930SIngo Molnar }
75486470930SIngo Molnar 
75586470930SIngo Molnar static const char * const record_usage[] = {
75686470930SIngo Molnar 	"perf record [<options>] [<command>]",
75786470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
75886470930SIngo Molnar 	NULL
75986470930SIngo Molnar };
76086470930SIngo Molnar 
7617865e817SFrederic Weisbecker static bool force, append_file;
7627865e817SFrederic Weisbecker 
763bca647aaSTom Zanussi const struct option record_options[] = {
764361c99a6SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &evsel_list, "event",
76586470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
766f120f9d5SJiri Olsa 		     parse_events_option),
767361c99a6SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &evsel_list, "filter",
768c171b552SLi Zefan 		     "event filter", parse_filter),
76986470930SIngo Molnar 	OPT_INTEGER('p', "pid", &target_pid,
770d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
771d6d901c2SZhang, Yanmin 	OPT_INTEGER('t', "tid", &target_tid,
772d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
77386470930SIngo Molnar 	OPT_INTEGER('r', "realtime", &realtime_prio,
77486470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
775acac03faSKirill Smelkov 	OPT_BOOLEAN('D', "no-delay", &nodelay,
776acac03faSKirill Smelkov 		    "collect data without buffering"),
777daac07b2SFrederic Weisbecker 	OPT_BOOLEAN('R', "raw-samples", &raw_samples,
778daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
77986470930SIngo Molnar 	OPT_BOOLEAN('a', "all-cpus", &system_wide,
78086470930SIngo Molnar 			    "system-wide collection from all CPUs"),
78186470930SIngo Molnar 	OPT_BOOLEAN('A', "append", &append_file,
78286470930SIngo Molnar 			    "append to the output file to do incremental profiling"),
783c45c6ea2SStephane Eranian 	OPT_STRING('C', "cpu", &cpu_list, "cpu",
784c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
78586470930SIngo Molnar 	OPT_BOOLEAN('f', "force", &force,
7867865e817SFrederic Weisbecker 			"overwrite existing data file (deprecated)"),
7873de29cabSStephane Eranian 	OPT_U64('c', "count", &user_interval, "event period to sample"),
78886470930SIngo Molnar 	OPT_STRING('o', "output", &output_name, "file",
78986470930SIngo Molnar 		    "output file name"),
7902e6cdf99SStephane Eranian 	OPT_BOOLEAN('i', "no-inherit", &no_inherit,
7912e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
7921967936dSArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"),
7931967936dSArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
79443bece79SLin Ming 	OPT_BOOLEAN(0, "group", &group,
79543bece79SLin Ming 		    "put the counters into a counter group"),
7963efa1cc9SIngo Molnar 	OPT_BOOLEAN('g', "call-graph", &call_graph,
7973efa1cc9SIngo Molnar 		    "do call-graph (stack chain/backtrace) recording"),
798c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
7993da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
800b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
801649c48a9SPeter Zijlstra 	OPT_BOOLEAN('s', "stat", &inherit_stat,
802649c48a9SPeter Zijlstra 		    "per thread counts"),
8034bba828dSAnton Blanchard 	OPT_BOOLEAN('d', "data", &sample_address,
8044bba828dSAnton Blanchard 		    "Sample addresses"),
8059c90a61cSArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"),
806649c48a9SPeter Zijlstra 	OPT_BOOLEAN('n', "no-samples", &no_samples,
807649c48a9SPeter Zijlstra 		    "don't sample"),
808baa2f6ceSArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache,
809a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
810baa2f6ceSArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &no_buildid,
811baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
812023695d9SStephane Eranian 	OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
813023695d9SStephane Eranian 		     "monitor event in cgroup name only",
814023695d9SStephane Eranian 		     parse_cgroups),
81586470930SIngo Molnar 	OPT_END()
81686470930SIngo Molnar };
81786470930SIngo Molnar 
818f37a291cSIngo Molnar int cmd_record(int argc, const char **argv, const char *prefix __used)
81986470930SIngo Molnar {
82069aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
82169aad6f1SArnaldo Carvalho de Melo 	struct perf_evsel *pos;
82286470930SIngo Molnar 
823fbe96f29SStephane Eranian 	perf_header__set_cmdline(argc, argv);
824fbe96f29SStephane Eranian 
8257e2ed097SArnaldo Carvalho de Melo 	evsel_list = perf_evlist__new(NULL, NULL);
826361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
827361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
828361c99a6SArnaldo Carvalho de Melo 
829bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
830a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
831d6d901c2SZhang, Yanmin 	if (!argc && target_pid == -1 && target_tid == -1 &&
832c45c6ea2SStephane Eranian 		!system_wide && !cpu_list)
833bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
83486470930SIngo Molnar 
8357865e817SFrederic Weisbecker 	if (force && append_file) {
8367865e817SFrederic Weisbecker 		fprintf(stderr, "Can't overwrite and append at the same time."
8377865e817SFrederic Weisbecker 				" You need to choose between -f and -A");
838bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
8397865e817SFrederic Weisbecker 	} else if (append_file) {
8407865e817SFrederic Weisbecker 		write_mode = WRITE_APPEND;
8417865e817SFrederic Weisbecker 	} else {
8427865e817SFrederic Weisbecker 		write_mode = WRITE_FORCE;
8437865e817SFrederic Weisbecker 	}
8447865e817SFrederic Weisbecker 
845023695d9SStephane Eranian 	if (nr_cgroups && !system_wide) {
846023695d9SStephane Eranian 		fprintf(stderr, "cgroup monitoring only available in"
847023695d9SStephane Eranian 			" system-wide mode\n");
848023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
849023695d9SStephane Eranian 	}
850023695d9SStephane Eranian 
851655000e7SArnaldo Carvalho de Melo 	symbol__init();
852baa2f6ceSArnaldo Carvalho de Melo 
853ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
854646aaea6SArnaldo Carvalho de Melo 		pr_warning(
855646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
856ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
857646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
858646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
859646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
860646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
861646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
862ec80fde7SArnaldo Carvalho de Melo 
863baa2f6ceSArnaldo Carvalho de Melo 	if (no_buildid_cache || no_buildid)
864a1ac1d3cSStephane Eranian 		disable_buildid_cache();
865655000e7SArnaldo Carvalho de Melo 
866361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
867361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
86869aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
86969aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
870bbd36e5eSPeter Zijlstra 	}
87186470930SIngo Molnar 
8725c98d466SArnaldo Carvalho de Melo 	if (target_pid != -1)
873d6d901c2SZhang, Yanmin 		target_tid = target_pid;
874d6d901c2SZhang, Yanmin 
8757e2ed097SArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(evsel_list, target_pid,
8767e2ed097SArnaldo Carvalho de Melo 				     target_tid, cpu_list) < 0)
877dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
87869aad6f1SArnaldo Carvalho de Melo 
879361c99a6SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evsel_list->entries, node) {
8807e2ed097SArnaldo Carvalho de Melo 		if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
8817e2ed097SArnaldo Carvalho de Melo 					 evsel_list->threads->nr) < 0)
88269aad6f1SArnaldo Carvalho de Melo 			goto out_free_fd;
883ad7f4e3fSArnaldo Carvalho de Melo 		if (perf_header__push_event(pos->attr.config, event_name(pos)))
884ad7f4e3fSArnaldo Carvalho de Melo 			goto out_free_fd;
885d6d901c2SZhang, Yanmin 	}
8865c581041SArnaldo Carvalho de Melo 
8877e2ed097SArnaldo Carvalho de Melo 	if (perf_evlist__alloc_pollfd(evsel_list) < 0)
88839d17dacSArnaldo Carvalho de Melo 		goto out_free_fd;
889d6d901c2SZhang, Yanmin 
8903de29cabSStephane Eranian 	if (user_interval != ULLONG_MAX)
891f9212819SFrederic Weisbecker 		default_interval = user_interval;
892f9212819SFrederic Weisbecker 	if (user_freq != UINT_MAX)
893f9212819SFrederic Weisbecker 		freq = user_freq;
894f9212819SFrederic Weisbecker 
8957e4ff9e3SMike Galbraith 	/*
8967e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
8977e4ff9e3SMike Galbraith 	 */
8987e4ff9e3SMike Galbraith 	if (default_interval)
8997e4ff9e3SMike Galbraith 		freq = 0;
9007e4ff9e3SMike Galbraith 	else if (freq) {
9017e4ff9e3SMike Galbraith 		default_interval = freq;
9027e4ff9e3SMike Galbraith 	} else {
9037e4ff9e3SMike Galbraith 		fprintf(stderr, "frequency and count are zero, aborting\n");
90439d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
9055c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
9067e4ff9e3SMike Galbraith 	}
9077e4ff9e3SMike Galbraith 
90839d17dacSArnaldo Carvalho de Melo 	err = __cmd_record(argc, argv);
90939d17dacSArnaldo Carvalho de Melo out_free_fd:
9107e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
911d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
912d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
91339d17dacSArnaldo Carvalho de Melo 	return err;
91486470930SIngo Molnar }
915