xref: /openbmc/linux/tools/perf/builtin-record.c (revision a5aabdacde9caff54886ae454e0fad2f26929753)
186470930SIngo Molnar /*
286470930SIngo Molnar  * builtin-record.c
386470930SIngo Molnar  *
486470930SIngo Molnar  * Builtin record command: Record the profile of a workload
586470930SIngo Molnar  * (or a CPU, or a PID) into the perf.data output file - for
686470930SIngo Molnar  * later analysis via perf report.
786470930SIngo Molnar  */
8b8f46c5aSXiao Guangrong #define _FILE_OFFSET_BITS 64
9b8f46c5aSXiao Guangrong 
1086470930SIngo Molnar #include "builtin.h"
1186470930SIngo Molnar 
1286470930SIngo Molnar #include "perf.h"
1386470930SIngo Molnar 
146122e4e4SArnaldo Carvalho de Melo #include "util/build-id.h"
1586470930SIngo Molnar #include "util/util.h"
1686470930SIngo Molnar #include "util/parse-options.h"
1786470930SIngo Molnar #include "util/parse-events.h"
1886470930SIngo Molnar 
197c6a1c65SPeter Zijlstra #include "util/header.h"
2066e274f3SFrederic Weisbecker #include "util/event.h"
21361c99a6SArnaldo Carvalho de Melo #include "util/evlist.h"
2269aad6f1SArnaldo Carvalho de Melo #include "util/evsel.h"
238f28827aSFrederic Weisbecker #include "util/debug.h"
2494c744b6SArnaldo Carvalho de Melo #include "util/session.h"
2545694aa7SArnaldo Carvalho de Melo #include "util/tool.h"
268d06367fSArnaldo Carvalho de Melo #include "util/symbol.h"
27a12b51c4SPaul Mackerras #include "util/cpumap.h"
28fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h"
297c6a1c65SPeter Zijlstra 
3086470930SIngo Molnar #include <unistd.h>
3186470930SIngo Molnar #include <sched.h>
32a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h>
3386470930SIngo Molnar 
347865e817SFrederic Weisbecker enum write_mode_t {
357865e817SFrederic Weisbecker 	WRITE_FORCE,
367865e817SFrederic Weisbecker 	WRITE_APPEND
377865e817SFrederic Weisbecker };
387865e817SFrederic Weisbecker 
39d20deb64SArnaldo Carvalho de Melo struct perf_record {
4045694aa7SArnaldo Carvalho de Melo 	struct perf_tool	tool;
41d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts	opts;
42d20deb64SArnaldo Carvalho de Melo 	u64			bytes_written;
43d20deb64SArnaldo Carvalho de Melo 	const char		*output_name;
44d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist	*evlist;
45d20deb64SArnaldo Carvalho de Melo 	struct perf_session	*session;
46d20deb64SArnaldo Carvalho de Melo 	const char		*progname;
470d37aa34SArnaldo Carvalho de Melo 	const char		*uid_str;
48d20deb64SArnaldo Carvalho de Melo 	int			output;
49d20deb64SArnaldo Carvalho de Melo 	unsigned int		page_size;
50d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
51d20deb64SArnaldo Carvalho de Melo 	enum write_mode_t	write_mode;
52d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
53d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
54d20deb64SArnaldo Carvalho de Melo 	bool			force;
55d20deb64SArnaldo Carvalho de Melo 	bool			file_new;
56d20deb64SArnaldo Carvalho de Melo 	bool			append_file;
57d20deb64SArnaldo Carvalho de Melo 	long			samples;
58d20deb64SArnaldo Carvalho de Melo 	off_t			post_processing_offset;
590f82ebc4SArnaldo Carvalho de Melo };
6086470930SIngo Molnar 
61d20deb64SArnaldo Carvalho de Melo static void advance_output(struct perf_record *rec, size_t size)
629215545eSTom Zanussi {
63d20deb64SArnaldo Carvalho de Melo 	rec->bytes_written += size;
649215545eSTom Zanussi }
659215545eSTom Zanussi 
66d20deb64SArnaldo Carvalho de Melo static void write_output(struct perf_record *rec, void *buf, size_t size)
67f5970550SPeter Zijlstra {
68f5970550SPeter Zijlstra 	while (size) {
69d20deb64SArnaldo Carvalho de Melo 		int ret = write(rec->output, buf, size);
70f5970550SPeter Zijlstra 
71f5970550SPeter Zijlstra 		if (ret < 0)
72f5970550SPeter Zijlstra 			die("failed to write");
73f5970550SPeter Zijlstra 
74f5970550SPeter Zijlstra 		size -= ret;
75f5970550SPeter Zijlstra 		buf += ret;
76f5970550SPeter Zijlstra 
77d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written += ret;
78f5970550SPeter Zijlstra 	}
79f5970550SPeter Zijlstra }
80f5970550SPeter Zijlstra 
8145694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
82d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
838d50e5b4SArnaldo Carvalho de Melo 				     struct perf_sample *sample __used,
84743eb868SArnaldo Carvalho de Melo 				     struct machine *machine __used)
85234fbbf5SArnaldo Carvalho de Melo {
8645694aa7SArnaldo Carvalho de Melo 	struct perf_record *rec = container_of(tool, struct perf_record, tool);
87d20deb64SArnaldo Carvalho de Melo 	write_output(rec, event, event->header.size);
88234fbbf5SArnaldo Carvalho de Melo 	return 0;
89234fbbf5SArnaldo Carvalho de Melo }
90234fbbf5SArnaldo Carvalho de Melo 
91d20deb64SArnaldo Carvalho de Melo static void perf_record__mmap_read(struct perf_record *rec,
92d20deb64SArnaldo Carvalho de Melo 				   struct perf_mmap *md)
9386470930SIngo Molnar {
94744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
9586470930SIngo Molnar 	unsigned int old = md->prev;
96d20deb64SArnaldo Carvalho de Melo 	unsigned char *data = md->base + rec->page_size;
9786470930SIngo Molnar 	unsigned long size;
9886470930SIngo Molnar 	void *buf;
9986470930SIngo Molnar 
100dc82009aSArnaldo Carvalho de Melo 	if (old == head)
101dc82009aSArnaldo Carvalho de Melo 		return;
10286470930SIngo Molnar 
103d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
10486470930SIngo Molnar 
10586470930SIngo Molnar 	size = head - old;
10686470930SIngo Molnar 
10786470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
10886470930SIngo Molnar 		buf = &data[old & md->mask];
10986470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
11086470930SIngo Molnar 		old += size;
11186470930SIngo Molnar 
112d20deb64SArnaldo Carvalho de Melo 		write_output(rec, buf, size);
11386470930SIngo Molnar 	}
11486470930SIngo Molnar 
11586470930SIngo Molnar 	buf = &data[old & md->mask];
11686470930SIngo Molnar 	size = head - old;
11786470930SIngo Molnar 	old += size;
11886470930SIngo Molnar 
119d20deb64SArnaldo Carvalho de Melo 	write_output(rec, buf, size);
12086470930SIngo Molnar 
12186470930SIngo Molnar 	md->prev = old;
122115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
12386470930SIngo Molnar }
12486470930SIngo Molnar 
12586470930SIngo Molnar static volatile int done = 0;
126f7b7c26eSPeter Zijlstra static volatile int signr = -1;
12733e49ea7SAndi Kleen static volatile int child_finished = 0;
12886470930SIngo Molnar 
12986470930SIngo Molnar static void sig_handler(int sig)
13086470930SIngo Molnar {
13133e49ea7SAndi Kleen 	if (sig == SIGCHLD)
13233e49ea7SAndi Kleen 		child_finished = 1;
13333e49ea7SAndi Kleen 
13486470930SIngo Molnar 	done = 1;
135f7b7c26eSPeter Zijlstra 	signr = sig;
136f7b7c26eSPeter Zijlstra }
137f7b7c26eSPeter Zijlstra 
138d20deb64SArnaldo Carvalho de Melo static void perf_record__sig_exit(int exit_status __used, void *arg)
139f7b7c26eSPeter Zijlstra {
140d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
14133e49ea7SAndi Kleen 	int status;
14233e49ea7SAndi Kleen 
143d20deb64SArnaldo Carvalho de Melo 	if (rec->evlist->workload.pid > 0) {
14433e49ea7SAndi Kleen 		if (!child_finished)
145d20deb64SArnaldo Carvalho de Melo 			kill(rec->evlist->workload.pid, SIGTERM);
146933da83aSChris Wilson 
14733e49ea7SAndi Kleen 		wait(&status);
14833e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
149d20deb64SArnaldo Carvalho de Melo 			psignal(WTERMSIG(status), rec->progname);
15033e49ea7SAndi Kleen 	}
15133e49ea7SAndi Kleen 
15218483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
153f7b7c26eSPeter Zijlstra 		return;
154f7b7c26eSPeter Zijlstra 
155f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
156f7b7c26eSPeter Zijlstra 	kill(getpid(), signr);
15786470930SIngo Molnar }
15886470930SIngo Molnar 
159a91e5431SArnaldo Carvalho de Melo static bool perf_evlist__equal(struct perf_evlist *evlist,
160a91e5431SArnaldo Carvalho de Melo 			       struct perf_evlist *other)
161a91e5431SArnaldo Carvalho de Melo {
162a91e5431SArnaldo Carvalho de Melo 	struct perf_evsel *pos, *pair;
163a91e5431SArnaldo Carvalho de Melo 
164a91e5431SArnaldo Carvalho de Melo 	if (evlist->nr_entries != other->nr_entries)
165a91e5431SArnaldo Carvalho de Melo 		return false;
166a91e5431SArnaldo Carvalho de Melo 
167a91e5431SArnaldo Carvalho de Melo 	pair = list_entry(other->entries.next, struct perf_evsel, node);
168a91e5431SArnaldo Carvalho de Melo 
169a91e5431SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
170a91e5431SArnaldo Carvalho de Melo 		if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
171a91e5431SArnaldo Carvalho de Melo 			return false;
172a91e5431SArnaldo Carvalho de Melo 		pair = list_entry(pair->node.next, struct perf_evsel, node);
173a91e5431SArnaldo Carvalho de Melo 	}
174a91e5431SArnaldo Carvalho de Melo 
175a91e5431SArnaldo Carvalho de Melo 	return true;
176a91e5431SArnaldo Carvalho de Melo }
177a91e5431SArnaldo Carvalho de Melo 
178d20deb64SArnaldo Carvalho de Melo static void perf_record__open(struct perf_record *rec)
179dd7927f4SArnaldo Carvalho de Melo {
180727ab04eSArnaldo Carvalho de Melo 	struct perf_evsel *pos, *first;
181d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
182d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
183d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
184dd7927f4SArnaldo Carvalho de Melo 
185727ab04eSArnaldo Carvalho de Melo 	first = list_entry(evlist->entries.next, struct perf_evsel, node);
186727ab04eSArnaldo Carvalho de Melo 
187d20deb64SArnaldo Carvalho de Melo 	perf_evlist__config_attrs(evlist, opts);
1880f82ebc4SArnaldo Carvalho de Melo 
189dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
190dd7927f4SArnaldo Carvalho de Melo 		struct perf_event_attr *attr = &pos->attr;
191727ab04eSArnaldo Carvalho de Melo 		struct xyarray *group_fd = NULL;
192dd7927f4SArnaldo Carvalho de Melo 		/*
193dd7927f4SArnaldo Carvalho de Melo 		 * Check if parse_single_tracepoint_event has already asked for
194dd7927f4SArnaldo Carvalho de Melo 		 * PERF_SAMPLE_TIME.
195dd7927f4SArnaldo Carvalho de Melo 		 *
196dd7927f4SArnaldo Carvalho de Melo 		 * XXX this is kludgy but short term fix for problems introduced by
197dd7927f4SArnaldo Carvalho de Melo 		 * eac23d1c that broke 'perf script' by having different sample_types
198dd7927f4SArnaldo Carvalho de Melo 		 * when using multiple tracepoint events when we use a perf binary
199dd7927f4SArnaldo Carvalho de Melo 		 * that tries to use sample_id_all on an older kernel.
200dd7927f4SArnaldo Carvalho de Melo 		 *
201dd7927f4SArnaldo Carvalho de Melo 		 * We need to move counter creation to perf_session, support
202dd7927f4SArnaldo Carvalho de Melo 		 * different sample_types, etc.
203dd7927f4SArnaldo Carvalho de Melo 		 */
204dd7927f4SArnaldo Carvalho de Melo 		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
205dd7927f4SArnaldo Carvalho de Melo 
206d20deb64SArnaldo Carvalho de Melo 		if (opts->group && pos != first)
207727ab04eSArnaldo Carvalho de Melo 			group_fd = first->fd;
2080c978128SArnaldo Carvalho de Melo fallback_missing_features:
2090c978128SArnaldo Carvalho de Melo 		if (opts->exclude_guest_missing)
2100c978128SArnaldo Carvalho de Melo 			attr->exclude_guest = attr->exclude_host = 0;
2119c90a61cSArnaldo Carvalho de Melo retry_sample_id:
212808e1226SArnaldo Carvalho de Melo 		attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
2133da297a6SIngo Molnar try_again:
214ed80f581SArnaldo Carvalho de Melo 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
215d20deb64SArnaldo Carvalho de Melo 				     opts->group, group_fd) < 0) {
21686470930SIngo Molnar 			int err = errno;
21786470930SIngo Molnar 
218c286c419SArnaldo Carvalho de Melo 			if (err == EPERM || err == EACCES) {
219b8631e6eSArnaldo Carvalho de Melo 				ui__error_paranoid();
220c286c419SArnaldo Carvalho de Melo 				exit(EXIT_FAILURE);
221d20deb64SArnaldo Carvalho de Melo 			} else if (err ==  ENODEV && opts->cpu_list) {
222d6d901c2SZhang, Yanmin 				die("No such device - did you specify"
223d6d901c2SZhang, Yanmin 					" an out-of-range profile CPU?\n");
2240c978128SArnaldo Carvalho de Melo 			} else if (err == EINVAL) {
2250c978128SArnaldo Carvalho de Melo 				if (!opts->exclude_guest_missing &&
2260c978128SArnaldo Carvalho de Melo 				    (attr->exclude_guest || attr->exclude_host)) {
2270c978128SArnaldo Carvalho de Melo 					pr_debug("Old kernel, cannot exclude "
2280c978128SArnaldo Carvalho de Melo 						 "guest or host samples.\n");
2290c978128SArnaldo Carvalho de Melo 					opts->exclude_guest_missing = true;
2300c978128SArnaldo Carvalho de Melo 					goto fallback_missing_features;
231808e1226SArnaldo Carvalho de Melo 				} else if (!opts->sample_id_all_missing) {
2329c90a61cSArnaldo Carvalho de Melo 					/*
2339c90a61cSArnaldo Carvalho de Melo 					 * Old kernel, no attr->sample_id_type_all field
2349c90a61cSArnaldo Carvalho de Melo 					 */
235808e1226SArnaldo Carvalho de Melo 					opts->sample_id_all_missing = true;
236d20deb64SArnaldo Carvalho de Melo 					if (!opts->sample_time && !opts->raw_samples && !time_needed)
237eac23d1cSIan Munsie 						attr->sample_type &= ~PERF_SAMPLE_TIME;
238eac23d1cSIan Munsie 
2399c90a61cSArnaldo Carvalho de Melo 					goto retry_sample_id;
240d6d901c2SZhang, Yanmin 				}
2410c978128SArnaldo Carvalho de Melo 			}
2423da297a6SIngo Molnar 
2433da297a6SIngo Molnar 			/*
2443da297a6SIngo Molnar 			 * If it's cycles then fall back to hrtimer
2453da297a6SIngo Molnar 			 * based cpu-clock-tick sw counter, which
2463da297a6SIngo Molnar 			 * is always available even if no PMU support:
2473da297a6SIngo Molnar 			 */
2483da297a6SIngo Molnar 			if (attr->type == PERF_TYPE_HARDWARE
249f4dbfa8fSPeter Zijlstra 					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {
2503da297a6SIngo Molnar 
2513da297a6SIngo Molnar 				if (verbose)
252ca6a4258SDavid Ahern 					ui__warning("The cycles event is not supported, "
253ca6a4258SDavid Ahern 						    "trying to fall back to cpu-clock-ticks\n");
2543da297a6SIngo Molnar 				attr->type = PERF_TYPE_SOFTWARE;
255f4dbfa8fSPeter Zijlstra 				attr->config = PERF_COUNT_SW_CPU_CLOCK;
2563da297a6SIngo Molnar 				goto try_again;
2573da297a6SIngo Molnar 			}
258ca6a4258SDavid Ahern 
259ca6a4258SDavid Ahern 			if (err == ENOENT) {
260ca6a4258SDavid Ahern 				ui__warning("The %s event is not supported.\n",
261ca6a4258SDavid Ahern 					    event_name(pos));
262ca6a4258SDavid Ahern 				exit(EXIT_FAILURE);
263ca6a4258SDavid Ahern 			}
264ca6a4258SDavid Ahern 
26530c806a0SIngo Molnar 			printf("\n");
266d9cf837eSCorey Ashford 			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
267dd7927f4SArnaldo Carvalho de Melo 			      err, strerror(err));
268bfd45118SSimon Kaempflein 
269bfd45118SSimon Kaempflein #if defined(__i386__) || defined(__x86_64__)
270bfd45118SSimon Kaempflein 			if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
271d6d901c2SZhang, Yanmin 				die("No hardware sampling interrupt available."
272d6d901c2SZhang, Yanmin 				    " No APIC? If so then you can boot the kernel"
273d6d901c2SZhang, Yanmin 				    " with the \"lapic\" boot parameter to"
274d6d901c2SZhang, Yanmin 				    " force-enable it.\n");
275bfd45118SSimon Kaempflein #endif
276bfd45118SSimon Kaempflein 
277cdd6c482SIngo Molnar 			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
2787c6a1c65SPeter Zijlstra 		}
2797c6a1c65SPeter Zijlstra 	}
2807c6a1c65SPeter Zijlstra 
2810a102479SFrederic Weisbecker 	if (perf_evlist__set_filters(evlist)) {
2820a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2830a102479SFrederic Weisbecker 			strerror(errno));
2840a102479SFrederic Weisbecker 		exit(-1);
2850a102479SFrederic Weisbecker 	}
2860a102479SFrederic Weisbecker 
28718e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
28818e60939SNelson Elhage 		if (errno == EPERM)
28918e60939SNelson Elhage 			die("Permission error mapping pages.\n"
29018e60939SNelson Elhage 			    "Consider increasing "
29118e60939SNelson Elhage 			    "/proc/sys/kernel/perf_event_mlock_kb,\n"
29218e60939SNelson Elhage 			    "or try again with a smaller value of -m/--mmap_pages.\n"
29318e60939SNelson Elhage 			    "(current value: %d)\n", opts->mmap_pages);
29441d0d933SNelson Elhage 		else if (!is_power_of_2(opts->mmap_pages))
29541d0d933SNelson Elhage 			die("--mmap_pages/-m value must be a power of two.");
29641d0d933SNelson Elhage 
2970a27d7f9SArnaldo Carvalho de Melo 		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
29818e60939SNelson Elhage 	}
2990a27d7f9SArnaldo Carvalho de Melo 
300d20deb64SArnaldo Carvalho de Melo 	if (rec->file_new)
301a91e5431SArnaldo Carvalho de Melo 		session->evlist = evlist;
302a91e5431SArnaldo Carvalho de Melo 	else {
303a91e5431SArnaldo Carvalho de Melo 		if (!perf_evlist__equal(session->evlist, evlist)) {
304a91e5431SArnaldo Carvalho de Melo 			fprintf(stderr, "incompatible append\n");
305a91e5431SArnaldo Carvalho de Melo 			exit(-1);
306dd7927f4SArnaldo Carvalho de Melo 		}
30786470930SIngo Molnar  	}
30886470930SIngo Molnar 
309a91e5431SArnaldo Carvalho de Melo 	perf_session__update_sample_type(session);
310a91e5431SArnaldo Carvalho de Melo }
311a91e5431SArnaldo Carvalho de Melo 
312d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
3136122e4e4SArnaldo Carvalho de Melo {
314d20deb64SArnaldo Carvalho de Melo 	u64 size = lseek(rec->output, 0, SEEK_CUR);
3156122e4e4SArnaldo Carvalho de Melo 
3169f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
3179f591fd7SArnaldo Carvalho de Melo 		return 0;
3189f591fd7SArnaldo Carvalho de Melo 
319d20deb64SArnaldo Carvalho de Melo 	rec->session->fd = rec->output;
320d20deb64SArnaldo Carvalho de Melo 	return __perf_session__process_events(rec->session, rec->post_processing_offset,
321d20deb64SArnaldo Carvalho de Melo 					      size - rec->post_processing_offset,
3226122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
3236122e4e4SArnaldo Carvalho de Melo }
3246122e4e4SArnaldo Carvalho de Melo 
325d20deb64SArnaldo Carvalho de Melo static void perf_record__exit(int status __used, void *arg)
326f5970550SPeter Zijlstra {
327d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
328f5970550SPeter Zijlstra 
329d20deb64SArnaldo Carvalho de Melo 	if (!rec->opts.pipe_output) {
330d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
331d20deb64SArnaldo Carvalho de Melo 
332d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
333d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
334d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
335d20deb64SArnaldo Carvalho de Melo 					   rec->output, true);
336d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
337d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
338d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
339c7929e47STom Zanussi 	}
340f5970550SPeter Zijlstra }
341f5970550SPeter Zijlstra 
3428115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
343a1645ce1SZhang, Yanmin {
344a1645ce1SZhang, Yanmin 	int err;
34545694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
346a1645ce1SZhang, Yanmin 
34723346f21SArnaldo Carvalho de Melo 	if (machine__is_host(machine))
348a1645ce1SZhang, Yanmin 		return;
349a1645ce1SZhang, Yanmin 
350a1645ce1SZhang, Yanmin 	/*
351a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
352a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
353a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
354a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
355a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
356a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
357a1645ce1SZhang, Yanmin 	 */
35845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
359743eb868SArnaldo Carvalho de Melo 					     machine);
360a1645ce1SZhang, Yanmin 	if (err < 0)
361a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
36223346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
363a1645ce1SZhang, Yanmin 
364a1645ce1SZhang, Yanmin 	/*
365a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
366a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
367a1645ce1SZhang, Yanmin 	 */
36845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
369743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
370a1645ce1SZhang, Yanmin 	if (err < 0)
37145694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
372743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
373a1645ce1SZhang, Yanmin 	if (err < 0)
374a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
37523346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
376a1645ce1SZhang, Yanmin }
377a1645ce1SZhang, Yanmin 
37898402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
37998402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
38098402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
38198402807SFrederic Weisbecker };
38298402807SFrederic Weisbecker 
383d20deb64SArnaldo Carvalho de Melo static void perf_record__mmap_read_all(struct perf_record *rec)
38498402807SFrederic Weisbecker {
3850e2e63ddSPeter Zijlstra 	int i;
38698402807SFrederic Weisbecker 
387d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
388d20deb64SArnaldo Carvalho de Melo 		if (rec->evlist->mmap[i].base)
389d20deb64SArnaldo Carvalho de Melo 			perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
39098402807SFrederic Weisbecker 	}
39198402807SFrederic Weisbecker 
392d20deb64SArnaldo Carvalho de Melo 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
393d20deb64SArnaldo Carvalho de Melo 		write_output(rec, &finished_round_event, sizeof(finished_round_event));
39498402807SFrederic Weisbecker }
39598402807SFrederic Weisbecker 
396d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
39786470930SIngo Molnar {
39886470930SIngo Molnar 	struct stat st;
39986470930SIngo Molnar 	int flags;
400781ba9d2SRobert Richter 	int err, output, feat;
4018b412664SPeter Zijlstra 	unsigned long waking = 0;
40246be604bSZhang, Yanmin 	const bool forks = argc > 0;
40323346f21SArnaldo Carvalho de Melo 	struct machine *machine;
40445694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
405d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
406d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
407d20deb64SArnaldo Carvalho de Melo 	const char *output_name = rec->output_name;
408d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
40986470930SIngo Molnar 
410d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
41133e49ea7SAndi Kleen 
412d20deb64SArnaldo Carvalho de Melo 	rec->page_size = sysconf(_SC_PAGE_SIZE);
41386470930SIngo Molnar 
414d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
415f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
416f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
41718483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
418f5970550SPeter Zijlstra 
419d7065adbSFranck Bui-Huu 	if (!output_name) {
420d7065adbSFranck Bui-Huu 		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
421d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
422d7065adbSFranck Bui-Huu 		else
423d20deb64SArnaldo Carvalho de Melo 			rec->output_name = output_name = "perf.data";
424d7065adbSFranck Bui-Huu 	}
425d7065adbSFranck Bui-Huu 	if (output_name) {
426529870e3STom Zanussi 		if (!strcmp(output_name, "-"))
427d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
428529870e3STom Zanussi 		else if (!stat(output_name, &st) && st.st_size) {
429d20deb64SArnaldo Carvalho de Melo 			if (rec->write_mode == WRITE_FORCE) {
430b38d3464SArnaldo Carvalho de Melo 				char oldname[PATH_MAX];
431b38d3464SArnaldo Carvalho de Melo 				snprintf(oldname, sizeof(oldname), "%s.old",
432b38d3464SArnaldo Carvalho de Melo 					 output_name);
433b38d3464SArnaldo Carvalho de Melo 				unlink(oldname);
434b38d3464SArnaldo Carvalho de Melo 				rename(output_name, oldname);
435b38d3464SArnaldo Carvalho de Melo 			}
436d20deb64SArnaldo Carvalho de Melo 		} else if (rec->write_mode == WRITE_APPEND) {
437d20deb64SArnaldo Carvalho de Melo 			rec->write_mode = WRITE_FORCE;
438266e0e21SPierre Habouzit 		}
439d7065adbSFranck Bui-Huu 	}
44086470930SIngo Molnar 
441f887f301SXiao Guangrong 	flags = O_CREAT|O_RDWR;
442d20deb64SArnaldo Carvalho de Melo 	if (rec->write_mode == WRITE_APPEND)
443d20deb64SArnaldo Carvalho de Melo 		rec->file_new = 0;
44486470930SIngo Molnar 	else
44586470930SIngo Molnar 		flags |= O_TRUNC;
44686470930SIngo Molnar 
447d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output)
448529870e3STom Zanussi 		output = STDOUT_FILENO;
449529870e3STom Zanussi 	else
45086470930SIngo Molnar 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
45186470930SIngo Molnar 	if (output < 0) {
45286470930SIngo Molnar 		perror("failed to create output file");
45386470930SIngo Molnar 		exit(-1);
45486470930SIngo Molnar 	}
45586470930SIngo Molnar 
456d20deb64SArnaldo Carvalho de Melo 	rec->output = output;
457d20deb64SArnaldo Carvalho de Melo 
4587865e817SFrederic Weisbecker 	session = perf_session__new(output_name, O_WRONLY,
459d20deb64SArnaldo Carvalho de Melo 				    rec->write_mode == WRITE_FORCE, false, NULL);
46094c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
461a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
462a9a70bbcSArnaldo Carvalho de Melo 		return -1;
463a9a70bbcSArnaldo Carvalho de Melo 	}
464a9a70bbcSArnaldo Carvalho de Melo 
465d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
466d20deb64SArnaldo Carvalho de Melo 
467781ba9d2SRobert Richter 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
468781ba9d2SRobert Richter 		perf_header__set_feat(&session->header, feat);
469781ba9d2SRobert Richter 
470781ba9d2SRobert Richter 	if (rec->no_buildid)
471781ba9d2SRobert Richter 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
472781ba9d2SRobert Richter 
473781ba9d2SRobert Richter 	if (!have_tracepoints(&evsel_list->entries))
474781ba9d2SRobert Richter 		perf_header__clear_feat(&session->header, HEADER_TRACE_INFO);
475baa2f6ceSArnaldo Carvalho de Melo 
476d20deb64SArnaldo Carvalho de Melo 	if (!rec->file_new) {
477a91e5431SArnaldo Carvalho de Melo 		err = perf_session__read_header(session, output);
4784dc0a04bSArnaldo Carvalho de Melo 		if (err < 0)
47939d17dacSArnaldo Carvalho de Melo 			goto out_delete_session;
4804dc0a04bSArnaldo Carvalho de Melo 	}
4814dc0a04bSArnaldo Carvalho de Melo 
482d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
483d20deb64SArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(evsel_list, opts, argv);
48435b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
48535b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
48635b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
487856e9660SPeter Zijlstra 		}
488856e9660SPeter Zijlstra 	}
489856e9660SPeter Zijlstra 
490d20deb64SArnaldo Carvalho de Melo 	perf_record__open(rec);
49186470930SIngo Molnar 
492712a4b60SArnaldo Carvalho de Melo 	/*
493d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
494712a4b60SArnaldo Carvalho de Melo 	 */
495d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
496712a4b60SArnaldo Carvalho de Melo 
497d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
498529870e3STom Zanussi 		err = perf_header__write_pipe(output);
499529870e3STom Zanussi 		if (err < 0)
500529870e3STom Zanussi 			return err;
501d20deb64SArnaldo Carvalho de Melo 	} else if (rec->file_new) {
502a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
503361c99a6SArnaldo Carvalho de Melo 						 output, false);
504d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
505d5eed904SArnaldo Carvalho de Melo 			return err;
506d5eed904SArnaldo Carvalho de Melo 	}
5077c6a1c65SPeter Zijlstra 
508d3665498SDavid Ahern 	if (!rec->no_buildid
509e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
510d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
511e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
512e20960c0SRobert Richter 		return -1;
513e20960c0SRobert Richter 	}
514e20960c0SRobert Richter 
515d20deb64SArnaldo Carvalho de Melo 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
5166122e4e4SArnaldo Carvalho de Melo 
517743eb868SArnaldo Carvalho de Melo 	machine = perf_session__find_host_machine(session);
518743eb868SArnaldo Carvalho de Melo 	if (!machine) {
519743eb868SArnaldo Carvalho de Melo 		pr_err("Couldn't find native kernel information.\n");
520743eb868SArnaldo Carvalho de Melo 		return -1;
521743eb868SArnaldo Carvalho de Melo 	}
522743eb868SArnaldo Carvalho de Melo 
523d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
52445694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
525a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
5262c46dbb5STom Zanussi 		if (err < 0) {
5272c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
5282c46dbb5STom Zanussi 			return err;
5292c46dbb5STom Zanussi 		}
530cd19a035STom Zanussi 
53145694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_event_types(tool, process_synthesized_event,
532743eb868SArnaldo Carvalho de Melo 							 machine);
533cd19a035STom Zanussi 		if (err < 0) {
534cd19a035STom Zanussi 			pr_err("Couldn't synthesize event_types.\n");
535cd19a035STom Zanussi 			return err;
536cd19a035STom Zanussi 		}
5379215545eSTom Zanussi 
538361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
53963e0c771STom Zanussi 			/*
54063e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
54163e0c771STom Zanussi 			 * there were no tracepoints so its not really
54263e0c771STom Zanussi 			 * an error, just that we don't need to
54363e0c771STom Zanussi 			 * synthesize anything.  We really have to
54463e0c771STom Zanussi 			 * return this more properly and also
54563e0c771STom Zanussi 			 * propagate errors that now are calling die()
54663e0c771STom Zanussi 			 */
54745694aa7SArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
548743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
54963e0c771STom Zanussi 			if (err <= 0) {
55063e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
55163e0c771STom Zanussi 				return err;
55263e0c771STom Zanussi 			}
553d20deb64SArnaldo Carvalho de Melo 			advance_output(rec, err);
5542c46dbb5STom Zanussi 		}
55563e0c771STom Zanussi 	}
5562c46dbb5STom Zanussi 
55745694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
558743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
55970162138SArnaldo Carvalho de Melo 	if (err < 0)
56045694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
561743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
562c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
563c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
564c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
565c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
56656b03f3cSArnaldo Carvalho de Melo 
56745694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
568743eb868SArnaldo Carvalho de Melo 					     machine);
569c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
570c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
571c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
572c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
573c1a3a4b9SArnaldo Carvalho de Melo 
574a1645ce1SZhang, Yanmin 	if (perf_guest)
57545694aa7SArnaldo Carvalho de Melo 		perf_session__process_machines(session, tool,
5768115d60cSArnaldo Carvalho de Melo 					       perf_event__synthesize_guest_os);
577b7cece76SArnaldo Carvalho de Melo 
578d20deb64SArnaldo Carvalho de Melo 	if (!opts->system_wide)
57945694aa7SArnaldo Carvalho de Melo 		perf_event__synthesize_thread_map(tool, evsel_list->threads,
5808115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
581743eb868SArnaldo Carvalho de Melo 						  machine);
582234fbbf5SArnaldo Carvalho de Melo 	else
58345694aa7SArnaldo Carvalho de Melo 		perf_event__synthesize_threads(tool, process_synthesized_event,
584743eb868SArnaldo Carvalho de Melo 					       machine);
5857c6a1c65SPeter Zijlstra 
586d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
58786470930SIngo Molnar 		struct sched_param param;
58886470930SIngo Molnar 
589d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
59086470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5916beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
59286470930SIngo Molnar 			exit(-1);
59386470930SIngo Molnar 		}
59486470930SIngo Molnar 	}
59586470930SIngo Molnar 
596764e16a3SDavid Ahern 	perf_evlist__enable(evsel_list);
597764e16a3SDavid Ahern 
598856e9660SPeter Zijlstra 	/*
599856e9660SPeter Zijlstra 	 * Let the child rip
600856e9660SPeter Zijlstra 	 */
601d4db3f16SArnaldo Carvalho de Melo 	if (forks)
60235b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
603856e9660SPeter Zijlstra 
604649c48a9SPeter Zijlstra 	for (;;) {
605d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
60686470930SIngo Molnar 
607d20deb64SArnaldo Carvalho de Melo 		perf_record__mmap_read_all(rec);
60886470930SIngo Molnar 
609d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
610649c48a9SPeter Zijlstra 			if (done)
611649c48a9SPeter Zijlstra 				break;
6125c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
6138b412664SPeter Zijlstra 			waking++;
6148b412664SPeter Zijlstra 		}
6158b412664SPeter Zijlstra 
6164152ab37SArnaldo Carvalho de Melo 		if (done)
6174152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
6188b412664SPeter Zijlstra 	}
6198b412664SPeter Zijlstra 
62018483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
621b44308f5SArnaldo Carvalho de Melo 		return 0;
622b44308f5SArnaldo Carvalho de Melo 
6238b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
62486470930SIngo Molnar 
62586470930SIngo Molnar 	/*
62686470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
62786470930SIngo Molnar 	 */
62886470930SIngo Molnar 	fprintf(stderr,
6299486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
630d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
63186470930SIngo Molnar 		output_name,
632d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
63386470930SIngo Molnar 
63486470930SIngo Molnar 	return 0;
63539d17dacSArnaldo Carvalho de Melo 
63639d17dacSArnaldo Carvalho de Melo out_delete_session:
63739d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
63839d17dacSArnaldo Carvalho de Melo 	return err;
63986470930SIngo Molnar }
64086470930SIngo Molnar 
641bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
642bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
643bdfebd84SRoberto Agostino Vitillo 
644bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
645bdfebd84SRoberto Agostino Vitillo 
646bdfebd84SRoberto Agostino Vitillo struct branch_mode {
647bdfebd84SRoberto Agostino Vitillo 	const char *name;
648bdfebd84SRoberto Agostino Vitillo 	int mode;
649bdfebd84SRoberto Agostino Vitillo };
650bdfebd84SRoberto Agostino Vitillo 
651bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
652bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
653bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
654bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
655bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
656bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
657bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
658bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
659bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
660bdfebd84SRoberto Agostino Vitillo };
661bdfebd84SRoberto Agostino Vitillo 
662bdfebd84SRoberto Agostino Vitillo static int
663*a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
664bdfebd84SRoberto Agostino Vitillo {
665bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
666bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
667bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
668bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
669bdfebd84SRoberto Agostino Vitillo 
670bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
671bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
672*a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
673bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
674bdfebd84SRoberto Agostino Vitillo 
675*a5aabdacSStephane Eranian 	if (unset)
676*a5aabdacSStephane Eranian 		return 0;
677bdfebd84SRoberto Agostino Vitillo 
678*a5aabdacSStephane Eranian 	/*
679*a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
680*a5aabdacSStephane Eranian 	 */
681*a5aabdacSStephane Eranian 	if (*mode)
682*a5aabdacSStephane Eranian 		return -1;
683*a5aabdacSStephane Eranian 
684*a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
685*a5aabdacSStephane Eranian 	if (str) {
686bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
687bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
688bdfebd84SRoberto Agostino Vitillo 		if (!s)
689bdfebd84SRoberto Agostino Vitillo 			return -1;
690bdfebd84SRoberto Agostino Vitillo 
691bdfebd84SRoberto Agostino Vitillo 		for (;;) {
692bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
693bdfebd84SRoberto Agostino Vitillo 			if (p)
694bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
695bdfebd84SRoberto Agostino Vitillo 
696bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
697bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
698bdfebd84SRoberto Agostino Vitillo 					break;
699bdfebd84SRoberto Agostino Vitillo 			}
700*a5aabdacSStephane Eranian 			if (!br->name) {
701*a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
702*a5aabdacSStephane Eranian 					    " check man page\n", s);
703bdfebd84SRoberto Agostino Vitillo 				goto error;
704*a5aabdacSStephane Eranian 			}
705bdfebd84SRoberto Agostino Vitillo 
706bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
707bdfebd84SRoberto Agostino Vitillo 
708bdfebd84SRoberto Agostino Vitillo 			if (!p)
709bdfebd84SRoberto Agostino Vitillo 				break;
710bdfebd84SRoberto Agostino Vitillo 
711bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
712bdfebd84SRoberto Agostino Vitillo 		}
713*a5aabdacSStephane Eranian 	}
714bdfebd84SRoberto Agostino Vitillo 	ret = 0;
715bdfebd84SRoberto Agostino Vitillo 
716*a5aabdacSStephane Eranian 	/* default to any branch */
717bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
718*a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
719bdfebd84SRoberto Agostino Vitillo 	}
720bdfebd84SRoberto Agostino Vitillo error:
721bdfebd84SRoberto Agostino Vitillo 	free(os);
722bdfebd84SRoberto Agostino Vitillo 	return ret;
723bdfebd84SRoberto Agostino Vitillo }
724bdfebd84SRoberto Agostino Vitillo 
72586470930SIngo Molnar static const char * const record_usage[] = {
72686470930SIngo Molnar 	"perf record [<options>] [<command>]",
72786470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
72886470930SIngo Molnar 	NULL
72986470930SIngo Molnar };
73086470930SIngo Molnar 
731d20deb64SArnaldo Carvalho de Melo /*
732d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
733d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
734d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
735d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
736d20deb64SArnaldo Carvalho de Melo  *
737d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
738d20deb64SArnaldo Carvalho de Melo  *
739d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
740d20deb64SArnaldo Carvalho de Melo  */
741d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
742d20deb64SArnaldo Carvalho de Melo 	.opts = {
743d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
744d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
745d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
746d20deb64SArnaldo Carvalho de Melo 		.freq		     = 1000,
747d20deb64SArnaldo Carvalho de Melo 	},
748d20deb64SArnaldo Carvalho de Melo 	.write_mode = WRITE_FORCE,
749d20deb64SArnaldo Carvalho de Melo 	.file_new   = true,
750d20deb64SArnaldo Carvalho de Melo };
7517865e817SFrederic Weisbecker 
752d20deb64SArnaldo Carvalho de Melo /*
753d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
754d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
755d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
756d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
757d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
758d20deb64SArnaldo Carvalho de Melo  */
759bca647aaSTom Zanussi const struct option record_options[] = {
760d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
76186470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
762f120f9d5SJiri Olsa 		     parse_events_option),
763d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
764c171b552SLi Zefan 		     "event filter", parse_filter),
765b52956c9SDavid Ahern 	OPT_STRING('p', "pid", &record.opts.target_pid, "pid",
766d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
767b52956c9SDavid Ahern 	OPT_STRING('t', "tid", &record.opts.target_tid, "tid",
768d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
769d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
77086470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
771d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
772acac03faSKirill Smelkov 		    "collect data without buffering"),
773d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
774daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
775d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
77686470930SIngo Molnar 			    "system-wide collection from all CPUs"),
777d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('A', "append", &record.append_file,
77886470930SIngo Molnar 			    "append to the output file to do incremental profiling"),
779d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
780c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
781d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('f', "force", &record.force,
7827865e817SFrederic Weisbecker 			"overwrite existing data file (deprecated)"),
783d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
784d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('o', "output", &record.output_name, "file",
78586470930SIngo Molnar 		    "output file name"),
786d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
7872e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
788d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
789d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
79001c2d99bSArnaldo Carvalho de Melo 		     "number of mmap data pages"),
791d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
79243bece79SLin Ming 		    "put the counters into a counter group"),
793d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
7943efa1cc9SIngo Molnar 		    "do call-graph (stack chain/backtrace) recording"),
795c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
7963da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
797b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
798d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
799649c48a9SPeter Zijlstra 		    "per thread counts"),
800d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8014bba828dSAnton Blanchard 		    "Sample addresses"),
802d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8033e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
804d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
805649c48a9SPeter Zijlstra 		    "don't sample"),
806d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
807a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
808d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
809baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
810d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
811023695d9SStephane Eranian 		     "monitor event in cgroup name only",
812023695d9SStephane Eranian 		     parse_cgroups),
8130d37aa34SArnaldo Carvalho de Melo 	OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
814*a5aabdacSStephane Eranian 
815*a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
816*a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
817*a5aabdacSStephane Eranian 		     parse_branch_stack),
818*a5aabdacSStephane Eranian 
819*a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
820*a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
821bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
82286470930SIngo Molnar 	OPT_END()
82386470930SIngo Molnar };
82486470930SIngo Molnar 
825f37a291cSIngo Molnar int cmd_record(int argc, const char **argv, const char *prefix __used)
82686470930SIngo Molnar {
82769aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
82869aad6f1SArnaldo Carvalho de Melo 	struct perf_evsel *pos;
829d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
830d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
83186470930SIngo Molnar 
832fbe96f29SStephane Eranian 	perf_header__set_cmdline(argc, argv);
833fbe96f29SStephane Eranian 
8347e2ed097SArnaldo Carvalho de Melo 	evsel_list = perf_evlist__new(NULL, NULL);
835361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
836361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
837361c99a6SArnaldo Carvalho de Melo 
838d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
839d20deb64SArnaldo Carvalho de Melo 
840bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
841a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
842b52956c9SDavid Ahern 	if (!argc && !rec->opts.target_pid && !rec->opts.target_tid &&
8430d37aa34SArnaldo Carvalho de Melo 		!rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
844bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
84586470930SIngo Molnar 
846d20deb64SArnaldo Carvalho de Melo 	if (rec->force && rec->append_file) {
8477865e817SFrederic Weisbecker 		fprintf(stderr, "Can't overwrite and append at the same time."
8487865e817SFrederic Weisbecker 				" You need to choose between -f and -A");
849bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
850d20deb64SArnaldo Carvalho de Melo 	} else if (rec->append_file) {
851d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_APPEND;
8527865e817SFrederic Weisbecker 	} else {
853d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_FORCE;
8547865e817SFrederic Weisbecker 	}
8557865e817SFrederic Weisbecker 
856d20deb64SArnaldo Carvalho de Melo 	if (nr_cgroups && !rec->opts.system_wide) {
857023695d9SStephane Eranian 		fprintf(stderr, "cgroup monitoring only available in"
858023695d9SStephane Eranian 			" system-wide mode\n");
859023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
860023695d9SStephane Eranian 	}
861023695d9SStephane Eranian 
862655000e7SArnaldo Carvalho de Melo 	symbol__init();
863baa2f6ceSArnaldo Carvalho de Melo 
864ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
865646aaea6SArnaldo Carvalho de Melo 		pr_warning(
866646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
867ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
868646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
869646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
870646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
871646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
872646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
873ec80fde7SArnaldo Carvalho de Melo 
874d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
875a1ac1d3cSStephane Eranian 		disable_buildid_cache();
876655000e7SArnaldo Carvalho de Melo 
877361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
878361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
87969aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
88069aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
881bbd36e5eSPeter Zijlstra 	}
88286470930SIngo Molnar 
8830d37aa34SArnaldo Carvalho de Melo 	rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
8840d37aa34SArnaldo Carvalho de Melo 					 rec->opts.target_pid);
8850d37aa34SArnaldo Carvalho de Melo 	if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
8860d37aa34SArnaldo Carvalho de Melo 		goto out_free_fd;
8870d37aa34SArnaldo Carvalho de Melo 
888b52956c9SDavid Ahern 	if (rec->opts.target_pid)
889d20deb64SArnaldo Carvalho de Melo 		rec->opts.target_tid = rec->opts.target_pid;
890d6d901c2SZhang, Yanmin 
891d20deb64SArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
8920d37aa34SArnaldo Carvalho de Melo 				     rec->opts.target_tid, rec->opts.uid,
8930d37aa34SArnaldo Carvalho de Melo 				     rec->opts.cpu_list) < 0)
894dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
89569aad6f1SArnaldo Carvalho de Melo 
896361c99a6SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evsel_list->entries, node) {
897ad7f4e3fSArnaldo Carvalho de Melo 		if (perf_header__push_event(pos->attr.config, event_name(pos)))
898ad7f4e3fSArnaldo Carvalho de Melo 			goto out_free_fd;
899d6d901c2SZhang, Yanmin 	}
9005c581041SArnaldo Carvalho de Melo 
901d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_interval != ULLONG_MAX)
902d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.user_interval;
903d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_freq != UINT_MAX)
904d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = rec->opts.user_freq;
905f9212819SFrederic Weisbecker 
9067e4ff9e3SMike Galbraith 	/*
9077e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
9087e4ff9e3SMike Galbraith 	 */
909d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.default_interval)
910d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = 0;
911d20deb64SArnaldo Carvalho de Melo 	else if (rec->opts.freq) {
912d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.freq;
9137e4ff9e3SMike Galbraith 	} else {
9147e4ff9e3SMike Galbraith 		fprintf(stderr, "frequency and count are zero, aborting\n");
91539d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
9165c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
9177e4ff9e3SMike Galbraith 	}
9187e4ff9e3SMike Galbraith 
919d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
92039d17dacSArnaldo Carvalho de Melo out_free_fd:
9217e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
922d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
923d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
92439d17dacSArnaldo Carvalho de Melo 	return err;
92586470930SIngo Molnar }
926