xref: /openbmc/linux/tools/perf/builtin-record.c (revision 7289f83cceb437ca56c77eb45b8b1cda15e2e476)
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;
47d20deb64SArnaldo Carvalho de Melo 	int			output;
48d20deb64SArnaldo Carvalho de Melo 	unsigned int		page_size;
49d20deb64SArnaldo Carvalho de Melo 	int			realtime_prio;
50d20deb64SArnaldo Carvalho de Melo 	enum write_mode_t	write_mode;
51d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid;
52d20deb64SArnaldo Carvalho de Melo 	bool			no_buildid_cache;
53d20deb64SArnaldo Carvalho de Melo 	bool			force;
54d20deb64SArnaldo Carvalho de Melo 	bool			file_new;
55d20deb64SArnaldo Carvalho de Melo 	bool			append_file;
56d20deb64SArnaldo Carvalho de Melo 	long			samples;
57d20deb64SArnaldo Carvalho de Melo 	off_t			post_processing_offset;
580f82ebc4SArnaldo Carvalho de Melo };
5986470930SIngo Molnar 
60d20deb64SArnaldo Carvalho de Melo static void advance_output(struct perf_record *rec, size_t size)
619215545eSTom Zanussi {
62d20deb64SArnaldo Carvalho de Melo 	rec->bytes_written += size;
639215545eSTom Zanussi }
649215545eSTom Zanussi 
65d20deb64SArnaldo Carvalho de Melo static void write_output(struct perf_record *rec, void *buf, size_t size)
66f5970550SPeter Zijlstra {
67f5970550SPeter Zijlstra 	while (size) {
68d20deb64SArnaldo Carvalho de Melo 		int ret = write(rec->output, buf, size);
69f5970550SPeter Zijlstra 
70f5970550SPeter Zijlstra 		if (ret < 0)
71f5970550SPeter Zijlstra 			die("failed to write");
72f5970550SPeter Zijlstra 
73f5970550SPeter Zijlstra 		size -= ret;
74f5970550SPeter Zijlstra 		buf += ret;
75f5970550SPeter Zijlstra 
76d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written += ret;
77f5970550SPeter Zijlstra 	}
78f5970550SPeter Zijlstra }
79f5970550SPeter Zijlstra 
8045694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool,
81d20deb64SArnaldo Carvalho de Melo 				     union perf_event *event,
828d50e5b4SArnaldo Carvalho de Melo 				     struct perf_sample *sample __used,
83743eb868SArnaldo Carvalho de Melo 				     struct machine *machine __used)
84234fbbf5SArnaldo Carvalho de Melo {
8545694aa7SArnaldo Carvalho de Melo 	struct perf_record *rec = container_of(tool, struct perf_record, tool);
86d20deb64SArnaldo Carvalho de Melo 	write_output(rec, event, event->header.size);
87234fbbf5SArnaldo Carvalho de Melo 	return 0;
88234fbbf5SArnaldo Carvalho de Melo }
89234fbbf5SArnaldo Carvalho de Melo 
90d20deb64SArnaldo Carvalho de Melo static void perf_record__mmap_read(struct perf_record *rec,
91d20deb64SArnaldo Carvalho de Melo 				   struct perf_mmap *md)
9286470930SIngo Molnar {
93744bd8aaSArnaldo Carvalho de Melo 	unsigned int head = perf_mmap__read_head(md);
9486470930SIngo Molnar 	unsigned int old = md->prev;
95d20deb64SArnaldo Carvalho de Melo 	unsigned char *data = md->base + rec->page_size;
9686470930SIngo Molnar 	unsigned long size;
9786470930SIngo Molnar 	void *buf;
9886470930SIngo Molnar 
99dc82009aSArnaldo Carvalho de Melo 	if (old == head)
100dc82009aSArnaldo Carvalho de Melo 		return;
10186470930SIngo Molnar 
102d20deb64SArnaldo Carvalho de Melo 	rec->samples++;
10386470930SIngo Molnar 
10486470930SIngo Molnar 	size = head - old;
10586470930SIngo Molnar 
10686470930SIngo Molnar 	if ((old & md->mask) + size != (head & md->mask)) {
10786470930SIngo Molnar 		buf = &data[old & md->mask];
10886470930SIngo Molnar 		size = md->mask + 1 - (old & md->mask);
10986470930SIngo Molnar 		old += size;
11086470930SIngo Molnar 
111d20deb64SArnaldo Carvalho de Melo 		write_output(rec, buf, size);
11286470930SIngo Molnar 	}
11386470930SIngo Molnar 
11486470930SIngo Molnar 	buf = &data[old & md->mask];
11586470930SIngo Molnar 	size = head - old;
11686470930SIngo Molnar 	old += size;
11786470930SIngo Molnar 
118d20deb64SArnaldo Carvalho de Melo 	write_output(rec, buf, size);
11986470930SIngo Molnar 
12086470930SIngo Molnar 	md->prev = old;
121115d2d89SArnaldo Carvalho de Melo 	perf_mmap__write_tail(md, old);
12286470930SIngo Molnar }
12386470930SIngo Molnar 
12486470930SIngo Molnar static volatile int done = 0;
125f7b7c26eSPeter Zijlstra static volatile int signr = -1;
12633e49ea7SAndi Kleen static volatile int child_finished = 0;
12786470930SIngo Molnar 
12886470930SIngo Molnar static void sig_handler(int sig)
12986470930SIngo Molnar {
13033e49ea7SAndi Kleen 	if (sig == SIGCHLD)
13133e49ea7SAndi Kleen 		child_finished = 1;
13233e49ea7SAndi Kleen 
13386470930SIngo Molnar 	done = 1;
134f7b7c26eSPeter Zijlstra 	signr = sig;
135f7b7c26eSPeter Zijlstra }
136f7b7c26eSPeter Zijlstra 
137d20deb64SArnaldo Carvalho de Melo static void perf_record__sig_exit(int exit_status __used, void *arg)
138f7b7c26eSPeter Zijlstra {
139d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
14033e49ea7SAndi Kleen 	int status;
14133e49ea7SAndi Kleen 
142d20deb64SArnaldo Carvalho de Melo 	if (rec->evlist->workload.pid > 0) {
14333e49ea7SAndi Kleen 		if (!child_finished)
144d20deb64SArnaldo Carvalho de Melo 			kill(rec->evlist->workload.pid, SIGTERM);
145933da83aSChris Wilson 
14633e49ea7SAndi Kleen 		wait(&status);
14733e49ea7SAndi Kleen 		if (WIFSIGNALED(status))
148d20deb64SArnaldo Carvalho de Melo 			psignal(WTERMSIG(status), rec->progname);
14933e49ea7SAndi Kleen 	}
15033e49ea7SAndi Kleen 
15118483b81SArnaldo Carvalho de Melo 	if (signr == -1 || signr == SIGUSR1)
152f7b7c26eSPeter Zijlstra 		return;
153f7b7c26eSPeter Zijlstra 
154f7b7c26eSPeter Zijlstra 	signal(signr, SIG_DFL);
155f7b7c26eSPeter Zijlstra 	kill(getpid(), signr);
15686470930SIngo Molnar }
15786470930SIngo Molnar 
158a91e5431SArnaldo Carvalho de Melo static bool perf_evlist__equal(struct perf_evlist *evlist,
159a91e5431SArnaldo Carvalho de Melo 			       struct perf_evlist *other)
160a91e5431SArnaldo Carvalho de Melo {
161a91e5431SArnaldo Carvalho de Melo 	struct perf_evsel *pos, *pair;
162a91e5431SArnaldo Carvalho de Melo 
163a91e5431SArnaldo Carvalho de Melo 	if (evlist->nr_entries != other->nr_entries)
164a91e5431SArnaldo Carvalho de Melo 		return false;
165a91e5431SArnaldo Carvalho de Melo 
166a91e5431SArnaldo Carvalho de Melo 	pair = list_entry(other->entries.next, struct perf_evsel, node);
167a91e5431SArnaldo Carvalho de Melo 
168a91e5431SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
169a91e5431SArnaldo Carvalho de Melo 		if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
170a91e5431SArnaldo Carvalho de Melo 			return false;
171a91e5431SArnaldo Carvalho de Melo 		pair = list_entry(pair->node.next, struct perf_evsel, node);
172a91e5431SArnaldo Carvalho de Melo 	}
173a91e5431SArnaldo Carvalho de Melo 
174a91e5431SArnaldo Carvalho de Melo 	return true;
175a91e5431SArnaldo Carvalho de Melo }
176a91e5431SArnaldo Carvalho de Melo 
177d20deb64SArnaldo Carvalho de Melo static void perf_record__open(struct perf_record *rec)
178dd7927f4SArnaldo Carvalho de Melo {
179727ab04eSArnaldo Carvalho de Melo 	struct perf_evsel *pos, *first;
180d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evlist = rec->evlist;
181d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session = rec->session;
182d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
183dd7927f4SArnaldo Carvalho de Melo 
184727ab04eSArnaldo Carvalho de Melo 	first = list_entry(evlist->entries.next, struct perf_evsel, node);
185727ab04eSArnaldo Carvalho de Melo 
186d20deb64SArnaldo Carvalho de Melo 	perf_evlist__config_attrs(evlist, opts);
1870f82ebc4SArnaldo Carvalho de Melo 
188dd7927f4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evlist->entries, node) {
189dd7927f4SArnaldo Carvalho de Melo 		struct perf_event_attr *attr = &pos->attr;
190727ab04eSArnaldo Carvalho de Melo 		struct xyarray *group_fd = NULL;
191dd7927f4SArnaldo Carvalho de Melo 		/*
192dd7927f4SArnaldo Carvalho de Melo 		 * Check if parse_single_tracepoint_event has already asked for
193dd7927f4SArnaldo Carvalho de Melo 		 * PERF_SAMPLE_TIME.
194dd7927f4SArnaldo Carvalho de Melo 		 *
195dd7927f4SArnaldo Carvalho de Melo 		 * XXX this is kludgy but short term fix for problems introduced by
196dd7927f4SArnaldo Carvalho de Melo 		 * eac23d1c that broke 'perf script' by having different sample_types
197dd7927f4SArnaldo Carvalho de Melo 		 * when using multiple tracepoint events when we use a perf binary
198dd7927f4SArnaldo Carvalho de Melo 		 * that tries to use sample_id_all on an older kernel.
199dd7927f4SArnaldo Carvalho de Melo 		 *
200dd7927f4SArnaldo Carvalho de Melo 		 * We need to move counter creation to perf_session, support
201dd7927f4SArnaldo Carvalho de Melo 		 * different sample_types, etc.
202dd7927f4SArnaldo Carvalho de Melo 		 */
203dd7927f4SArnaldo Carvalho de Melo 		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
204dd7927f4SArnaldo Carvalho de Melo 
205d20deb64SArnaldo Carvalho de Melo 		if (opts->group && pos != first)
206727ab04eSArnaldo Carvalho de Melo 			group_fd = first->fd;
2070c978128SArnaldo Carvalho de Melo fallback_missing_features:
2080c978128SArnaldo Carvalho de Melo 		if (opts->exclude_guest_missing)
2090c978128SArnaldo Carvalho de Melo 			attr->exclude_guest = attr->exclude_host = 0;
2109c90a61cSArnaldo Carvalho de Melo retry_sample_id:
211808e1226SArnaldo Carvalho de Melo 		attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
2123da297a6SIngo Molnar try_again:
213ed80f581SArnaldo Carvalho de Melo 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
214d20deb64SArnaldo Carvalho de Melo 				     opts->group, group_fd) < 0) {
21586470930SIngo Molnar 			int err = errno;
21686470930SIngo Molnar 
217c286c419SArnaldo Carvalho de Melo 			if (err == EPERM || err == EACCES) {
218b8631e6eSArnaldo Carvalho de Melo 				ui__error_paranoid();
219c286c419SArnaldo Carvalho de Melo 				exit(EXIT_FAILURE);
220bea03405SNamhyung Kim 			} else if (err ==  ENODEV && opts->target.cpu_list) {
221d6d901c2SZhang, Yanmin 				die("No such device - did you specify"
222d6d901c2SZhang, Yanmin 					" an out-of-range profile CPU?\n");
2230c978128SArnaldo Carvalho de Melo 			} else if (err == EINVAL) {
2240c978128SArnaldo Carvalho de Melo 				if (!opts->exclude_guest_missing &&
2250c978128SArnaldo Carvalho de Melo 				    (attr->exclude_guest || attr->exclude_host)) {
2260c978128SArnaldo Carvalho de Melo 					pr_debug("Old kernel, cannot exclude "
2270c978128SArnaldo Carvalho de Melo 						 "guest or host samples.\n");
2280c978128SArnaldo Carvalho de Melo 					opts->exclude_guest_missing = true;
2290c978128SArnaldo Carvalho de Melo 					goto fallback_missing_features;
230808e1226SArnaldo Carvalho de Melo 				} else if (!opts->sample_id_all_missing) {
2319c90a61cSArnaldo Carvalho de Melo 					/*
2329c90a61cSArnaldo Carvalho de Melo 					 * Old kernel, no attr->sample_id_type_all field
2339c90a61cSArnaldo Carvalho de Melo 					 */
234808e1226SArnaldo Carvalho de Melo 					opts->sample_id_all_missing = true;
235d20deb64SArnaldo Carvalho de Melo 					if (!opts->sample_time && !opts->raw_samples && !time_needed)
236eac23d1cSIan Munsie 						attr->sample_type &= ~PERF_SAMPLE_TIME;
237eac23d1cSIan Munsie 
2389c90a61cSArnaldo Carvalho de Melo 					goto retry_sample_id;
239d6d901c2SZhang, Yanmin 				}
2400c978128SArnaldo Carvalho de Melo 			}
2413da297a6SIngo Molnar 
2423da297a6SIngo Molnar 			/*
2433da297a6SIngo Molnar 			 * If it's cycles then fall back to hrtimer
2443da297a6SIngo Molnar 			 * based cpu-clock-tick sw counter, which
245028d455bSDavid Ahern 			 * is always available even if no PMU support.
246028d455bSDavid Ahern 			 *
247028d455bSDavid Ahern 			 * PPC returns ENXIO until 2.6.37 (behavior changed
248028d455bSDavid Ahern 			 * with commit b0a873e).
2493da297a6SIngo Molnar 			 */
250028d455bSDavid Ahern 			if ((err == ENOENT || err == ENXIO)
251028d455bSDavid Ahern 					&& attr->type == PERF_TYPE_HARDWARE
252f4dbfa8fSPeter Zijlstra 					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {
2533da297a6SIngo Molnar 
2543da297a6SIngo Molnar 				if (verbose)
255ca6a4258SDavid Ahern 					ui__warning("The cycles event is not supported, "
256ca6a4258SDavid Ahern 						    "trying to fall back to cpu-clock-ticks\n");
2573da297a6SIngo Molnar 				attr->type = PERF_TYPE_SOFTWARE;
258f4dbfa8fSPeter Zijlstra 				attr->config = PERF_COUNT_SW_CPU_CLOCK;
259d1cae34dSDavid Ahern 				if (pos->name) {
260d1cae34dSDavid Ahern 					free(pos->name);
261d1cae34dSDavid Ahern 					pos->name = NULL;
262d1cae34dSDavid Ahern 				}
2633da297a6SIngo Molnar 				goto try_again;
2643da297a6SIngo Molnar 			}
265ca6a4258SDavid Ahern 
266ca6a4258SDavid Ahern 			if (err == ENOENT) {
2673780f488SNamhyung Kim 				ui__error("The %s event is not supported.\n",
268*7289f83cSArnaldo Carvalho de Melo 					  perf_evsel__name(pos));
269ca6a4258SDavid Ahern 				exit(EXIT_FAILURE);
270ca6a4258SDavid Ahern 			}
271ca6a4258SDavid Ahern 
27230c806a0SIngo Molnar 			printf("\n");
273d9cf837eSCorey Ashford 			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
274dd7927f4SArnaldo Carvalho de Melo 			      err, strerror(err));
275bfd45118SSimon Kaempflein 
276bfd45118SSimon Kaempflein #if defined(__i386__) || defined(__x86_64__)
277bfd45118SSimon Kaempflein 			if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
278d6d901c2SZhang, Yanmin 				die("No hardware sampling interrupt available."
279d6d901c2SZhang, Yanmin 				    " No APIC? If so then you can boot the kernel"
280d6d901c2SZhang, Yanmin 				    " with the \"lapic\" boot parameter to"
281d6d901c2SZhang, Yanmin 				    " force-enable it.\n");
282bfd45118SSimon Kaempflein #endif
283bfd45118SSimon Kaempflein 
284cdd6c482SIngo Molnar 			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
2857c6a1c65SPeter Zijlstra 		}
2867c6a1c65SPeter Zijlstra 	}
2877c6a1c65SPeter Zijlstra 
2880a102479SFrederic Weisbecker 	if (perf_evlist__set_filters(evlist)) {
2890a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2900a102479SFrederic Weisbecker 			strerror(errno));
2910a102479SFrederic Weisbecker 		exit(-1);
2920a102479SFrederic Weisbecker 	}
2930a102479SFrederic Weisbecker 
29418e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
29518e60939SNelson Elhage 		if (errno == EPERM)
29618e60939SNelson Elhage 			die("Permission error mapping pages.\n"
29718e60939SNelson Elhage 			    "Consider increasing "
29818e60939SNelson Elhage 			    "/proc/sys/kernel/perf_event_mlock_kb,\n"
29918e60939SNelson Elhage 			    "or try again with a smaller value of -m/--mmap_pages.\n"
30018e60939SNelson Elhage 			    "(current value: %d)\n", opts->mmap_pages);
30141d0d933SNelson Elhage 		else if (!is_power_of_2(opts->mmap_pages))
30241d0d933SNelson Elhage 			die("--mmap_pages/-m value must be a power of two.");
30341d0d933SNelson Elhage 
3040a27d7f9SArnaldo Carvalho de Melo 		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
30518e60939SNelson Elhage 	}
3060a27d7f9SArnaldo Carvalho de Melo 
307d20deb64SArnaldo Carvalho de Melo 	if (rec->file_new)
308a91e5431SArnaldo Carvalho de Melo 		session->evlist = evlist;
309a91e5431SArnaldo Carvalho de Melo 	else {
310a91e5431SArnaldo Carvalho de Melo 		if (!perf_evlist__equal(session->evlist, evlist)) {
311a91e5431SArnaldo Carvalho de Melo 			fprintf(stderr, "incompatible append\n");
312a91e5431SArnaldo Carvalho de Melo 			exit(-1);
313dd7927f4SArnaldo Carvalho de Melo 		}
31486470930SIngo Molnar  	}
31586470930SIngo Molnar 
316a91e5431SArnaldo Carvalho de Melo 	perf_session__update_sample_type(session);
317a91e5431SArnaldo Carvalho de Melo }
318a91e5431SArnaldo Carvalho de Melo 
319d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
3206122e4e4SArnaldo Carvalho de Melo {
321d20deb64SArnaldo Carvalho de Melo 	u64 size = lseek(rec->output, 0, SEEK_CUR);
3226122e4e4SArnaldo Carvalho de Melo 
3239f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
3249f591fd7SArnaldo Carvalho de Melo 		return 0;
3259f591fd7SArnaldo Carvalho de Melo 
326d20deb64SArnaldo Carvalho de Melo 	rec->session->fd = rec->output;
327d20deb64SArnaldo Carvalho de Melo 	return __perf_session__process_events(rec->session, rec->post_processing_offset,
328d20deb64SArnaldo Carvalho de Melo 					      size - rec->post_processing_offset,
3296122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
3306122e4e4SArnaldo Carvalho de Melo }
3316122e4e4SArnaldo Carvalho de Melo 
332d20deb64SArnaldo Carvalho de Melo static void perf_record__exit(int status __used, void *arg)
333f5970550SPeter Zijlstra {
334d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
335f5970550SPeter Zijlstra 
336d20deb64SArnaldo Carvalho de Melo 	if (!rec->opts.pipe_output) {
337d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
338d20deb64SArnaldo Carvalho de Melo 
339d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
340d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
341d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
342d20deb64SArnaldo Carvalho de Melo 					   rec->output, true);
343d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
344d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
345d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
346c7929e47STom Zanussi 	}
347f5970550SPeter Zijlstra }
348f5970550SPeter Zijlstra 
3498115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
350a1645ce1SZhang, Yanmin {
351a1645ce1SZhang, Yanmin 	int err;
35245694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
353a1645ce1SZhang, Yanmin 
35423346f21SArnaldo Carvalho de Melo 	if (machine__is_host(machine))
355a1645ce1SZhang, Yanmin 		return;
356a1645ce1SZhang, Yanmin 
357a1645ce1SZhang, Yanmin 	/*
358a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
359a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
360a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
361a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
362a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
363a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
364a1645ce1SZhang, Yanmin 	 */
36545694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
366743eb868SArnaldo Carvalho de Melo 					     machine);
367a1645ce1SZhang, Yanmin 	if (err < 0)
368a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
36923346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
370a1645ce1SZhang, Yanmin 
371a1645ce1SZhang, Yanmin 	/*
372a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
373a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
374a1645ce1SZhang, Yanmin 	 */
37545694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
376743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
377a1645ce1SZhang, Yanmin 	if (err < 0)
37845694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
379743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
380a1645ce1SZhang, Yanmin 	if (err < 0)
381a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
38223346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
383a1645ce1SZhang, Yanmin }
384a1645ce1SZhang, Yanmin 
38598402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
38698402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
38798402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
38898402807SFrederic Weisbecker };
38998402807SFrederic Weisbecker 
390d20deb64SArnaldo Carvalho de Melo static void perf_record__mmap_read_all(struct perf_record *rec)
39198402807SFrederic Weisbecker {
3920e2e63ddSPeter Zijlstra 	int i;
39398402807SFrederic Weisbecker 
394d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
395d20deb64SArnaldo Carvalho de Melo 		if (rec->evlist->mmap[i].base)
396d20deb64SArnaldo Carvalho de Melo 			perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
39798402807SFrederic Weisbecker 	}
39898402807SFrederic Weisbecker 
3992eeaaa09SStephane Eranian 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
400d20deb64SArnaldo Carvalho de Melo 		write_output(rec, &finished_round_event, sizeof(finished_round_event));
40198402807SFrederic Weisbecker }
40298402807SFrederic Weisbecker 
403d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
40486470930SIngo Molnar {
40586470930SIngo Molnar 	struct stat st;
40686470930SIngo Molnar 	int flags;
407781ba9d2SRobert Richter 	int err, output, feat;
4088b412664SPeter Zijlstra 	unsigned long waking = 0;
40946be604bSZhang, Yanmin 	const bool forks = argc > 0;
41023346f21SArnaldo Carvalho de Melo 	struct machine *machine;
41145694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
412d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
413d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
414d20deb64SArnaldo Carvalho de Melo 	const char *output_name = rec->output_name;
415d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
41686470930SIngo Molnar 
417d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
41833e49ea7SAndi Kleen 
419d20deb64SArnaldo Carvalho de Melo 	rec->page_size = sysconf(_SC_PAGE_SIZE);
42086470930SIngo Molnar 
421d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
422f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
423f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
42418483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
425f5970550SPeter Zijlstra 
426d7065adbSFranck Bui-Huu 	if (!output_name) {
427d7065adbSFranck Bui-Huu 		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
428d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
429d7065adbSFranck Bui-Huu 		else
430d20deb64SArnaldo Carvalho de Melo 			rec->output_name = output_name = "perf.data";
431d7065adbSFranck Bui-Huu 	}
432d7065adbSFranck Bui-Huu 	if (output_name) {
433529870e3STom Zanussi 		if (!strcmp(output_name, "-"))
434d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
435529870e3STom Zanussi 		else if (!stat(output_name, &st) && st.st_size) {
436d20deb64SArnaldo Carvalho de Melo 			if (rec->write_mode == WRITE_FORCE) {
437b38d3464SArnaldo Carvalho de Melo 				char oldname[PATH_MAX];
438b38d3464SArnaldo Carvalho de Melo 				snprintf(oldname, sizeof(oldname), "%s.old",
439b38d3464SArnaldo Carvalho de Melo 					 output_name);
440b38d3464SArnaldo Carvalho de Melo 				unlink(oldname);
441b38d3464SArnaldo Carvalho de Melo 				rename(output_name, oldname);
442b38d3464SArnaldo Carvalho de Melo 			}
443d20deb64SArnaldo Carvalho de Melo 		} else if (rec->write_mode == WRITE_APPEND) {
444d20deb64SArnaldo Carvalho de Melo 			rec->write_mode = WRITE_FORCE;
445266e0e21SPierre Habouzit 		}
446d7065adbSFranck Bui-Huu 	}
44786470930SIngo Molnar 
448f887f301SXiao Guangrong 	flags = O_CREAT|O_RDWR;
449d20deb64SArnaldo Carvalho de Melo 	if (rec->write_mode == WRITE_APPEND)
450d20deb64SArnaldo Carvalho de Melo 		rec->file_new = 0;
45186470930SIngo Molnar 	else
45286470930SIngo Molnar 		flags |= O_TRUNC;
45386470930SIngo Molnar 
454d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output)
455529870e3STom Zanussi 		output = STDOUT_FILENO;
456529870e3STom Zanussi 	else
45786470930SIngo Molnar 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
45886470930SIngo Molnar 	if (output < 0) {
45986470930SIngo Molnar 		perror("failed to create output file");
46086470930SIngo Molnar 		exit(-1);
46186470930SIngo Molnar 	}
46286470930SIngo Molnar 
463d20deb64SArnaldo Carvalho de Melo 	rec->output = output;
464d20deb64SArnaldo Carvalho de Melo 
4657865e817SFrederic Weisbecker 	session = perf_session__new(output_name, O_WRONLY,
466d20deb64SArnaldo Carvalho de Melo 				    rec->write_mode == WRITE_FORCE, false, NULL);
46794c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
468a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
469a9a70bbcSArnaldo Carvalho de Melo 		return -1;
470a9a70bbcSArnaldo Carvalho de Melo 	}
471a9a70bbcSArnaldo Carvalho de Melo 
472d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
473d20deb64SArnaldo Carvalho de Melo 
474781ba9d2SRobert Richter 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
475781ba9d2SRobert Richter 		perf_header__set_feat(&session->header, feat);
476781ba9d2SRobert Richter 
477781ba9d2SRobert Richter 	if (rec->no_buildid)
478781ba9d2SRobert Richter 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
479781ba9d2SRobert Richter 
480781ba9d2SRobert Richter 	if (!have_tracepoints(&evsel_list->entries))
4812eeaaa09SStephane Eranian 		perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
482baa2f6ceSArnaldo Carvalho de Melo 
483330aa675SStephane Eranian 	if (!rec->opts.branch_stack)
484330aa675SStephane Eranian 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
485330aa675SStephane Eranian 
486d20deb64SArnaldo Carvalho de Melo 	if (!rec->file_new) {
487a91e5431SArnaldo Carvalho de Melo 		err = perf_session__read_header(session, output);
4884dc0a04bSArnaldo Carvalho de Melo 		if (err < 0)
48939d17dacSArnaldo Carvalho de Melo 			goto out_delete_session;
4904dc0a04bSArnaldo Carvalho de Melo 	}
4914dc0a04bSArnaldo Carvalho de Melo 
492d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
493d20deb64SArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(evsel_list, opts, argv);
49435b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
49535b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
49635b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
497856e9660SPeter Zijlstra 		}
498856e9660SPeter Zijlstra 	}
499856e9660SPeter Zijlstra 
500d20deb64SArnaldo Carvalho de Melo 	perf_record__open(rec);
50186470930SIngo Molnar 
502712a4b60SArnaldo Carvalho de Melo 	/*
503d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
504712a4b60SArnaldo Carvalho de Melo 	 */
505d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
506712a4b60SArnaldo Carvalho de Melo 
507d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
508529870e3STom Zanussi 		err = perf_header__write_pipe(output);
509529870e3STom Zanussi 		if (err < 0)
510529870e3STom Zanussi 			return err;
511d20deb64SArnaldo Carvalho de Melo 	} else if (rec->file_new) {
512a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
513361c99a6SArnaldo Carvalho de Melo 						 output, false);
514d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
515d5eed904SArnaldo Carvalho de Melo 			return err;
516d5eed904SArnaldo Carvalho de Melo 	}
5177c6a1c65SPeter Zijlstra 
518d3665498SDavid Ahern 	if (!rec->no_buildid
519e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
520d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
521e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
522e20960c0SRobert Richter 		return -1;
523e20960c0SRobert Richter 	}
524e20960c0SRobert Richter 
525d20deb64SArnaldo Carvalho de Melo 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
5266122e4e4SArnaldo Carvalho de Melo 
527743eb868SArnaldo Carvalho de Melo 	machine = perf_session__find_host_machine(session);
528743eb868SArnaldo Carvalho de Melo 	if (!machine) {
529743eb868SArnaldo Carvalho de Melo 		pr_err("Couldn't find native kernel information.\n");
530743eb868SArnaldo Carvalho de Melo 		return -1;
531743eb868SArnaldo Carvalho de Melo 	}
532743eb868SArnaldo Carvalho de Melo 
533d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
53445694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
535a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
5362c46dbb5STom Zanussi 		if (err < 0) {
5372c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
5382c46dbb5STom Zanussi 			return err;
5392c46dbb5STom Zanussi 		}
540cd19a035STom Zanussi 
54145694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_event_types(tool, process_synthesized_event,
542743eb868SArnaldo Carvalho de Melo 							 machine);
543cd19a035STom Zanussi 		if (err < 0) {
544cd19a035STom Zanussi 			pr_err("Couldn't synthesize event_types.\n");
545cd19a035STom Zanussi 			return err;
546cd19a035STom Zanussi 		}
5479215545eSTom Zanussi 
548361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
54963e0c771STom Zanussi 			/*
55063e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
55163e0c771STom Zanussi 			 * there were no tracepoints so its not really
55263e0c771STom Zanussi 			 * an error, just that we don't need to
55363e0c771STom Zanussi 			 * synthesize anything.  We really have to
55463e0c771STom Zanussi 			 * return this more properly and also
55563e0c771STom Zanussi 			 * propagate errors that now are calling die()
55663e0c771STom Zanussi 			 */
55745694aa7SArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
558743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
55963e0c771STom Zanussi 			if (err <= 0) {
56063e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
56163e0c771STom Zanussi 				return err;
56263e0c771STom Zanussi 			}
563d20deb64SArnaldo Carvalho de Melo 			advance_output(rec, err);
5642c46dbb5STom Zanussi 		}
56563e0c771STom Zanussi 	}
5662c46dbb5STom Zanussi 
56745694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
568743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
56970162138SArnaldo Carvalho de Melo 	if (err < 0)
57045694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
571743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
572c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
573c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
574c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
575c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
57656b03f3cSArnaldo Carvalho de Melo 
57745694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
578743eb868SArnaldo Carvalho de Melo 					     machine);
579c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
580c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
581c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
582c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
583c1a3a4b9SArnaldo Carvalho de Melo 
584a1645ce1SZhang, Yanmin 	if (perf_guest)
58545694aa7SArnaldo Carvalho de Melo 		perf_session__process_machines(session, tool,
5868115d60cSArnaldo Carvalho de Melo 					       perf_event__synthesize_guest_os);
587b7cece76SArnaldo Carvalho de Melo 
588bea03405SNamhyung Kim 	if (!opts->target.system_wide)
58945694aa7SArnaldo Carvalho de Melo 		perf_event__synthesize_thread_map(tool, evsel_list->threads,
5908115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
591743eb868SArnaldo Carvalho de Melo 						  machine);
592234fbbf5SArnaldo Carvalho de Melo 	else
59345694aa7SArnaldo Carvalho de Melo 		perf_event__synthesize_threads(tool, process_synthesized_event,
594743eb868SArnaldo Carvalho de Melo 					       machine);
5957c6a1c65SPeter Zijlstra 
596d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
59786470930SIngo Molnar 		struct sched_param param;
59886470930SIngo Molnar 
599d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
60086470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
6016beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
60286470930SIngo Molnar 			exit(-1);
60386470930SIngo Molnar 		}
60486470930SIngo Molnar 	}
60586470930SIngo Molnar 
606764e16a3SDavid Ahern 	perf_evlist__enable(evsel_list);
607764e16a3SDavid Ahern 
608856e9660SPeter Zijlstra 	/*
609856e9660SPeter Zijlstra 	 * Let the child rip
610856e9660SPeter Zijlstra 	 */
611d4db3f16SArnaldo Carvalho de Melo 	if (forks)
61235b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
613856e9660SPeter Zijlstra 
614649c48a9SPeter Zijlstra 	for (;;) {
615d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
61686470930SIngo Molnar 
617d20deb64SArnaldo Carvalho de Melo 		perf_record__mmap_read_all(rec);
61886470930SIngo Molnar 
619d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
620649c48a9SPeter Zijlstra 			if (done)
621649c48a9SPeter Zijlstra 				break;
6225c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
6238b412664SPeter Zijlstra 			waking++;
6248b412664SPeter Zijlstra 		}
6258b412664SPeter Zijlstra 
6264152ab37SArnaldo Carvalho de Melo 		if (done)
6274152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
6288b412664SPeter Zijlstra 	}
6298b412664SPeter Zijlstra 
63018483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
631b44308f5SArnaldo Carvalho de Melo 		return 0;
632b44308f5SArnaldo Carvalho de Melo 
6338b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
63486470930SIngo Molnar 
63586470930SIngo Molnar 	/*
63686470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
63786470930SIngo Molnar 	 */
63886470930SIngo Molnar 	fprintf(stderr,
6399486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
640d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
64186470930SIngo Molnar 		output_name,
642d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
64386470930SIngo Molnar 
64486470930SIngo Molnar 	return 0;
64539d17dacSArnaldo Carvalho de Melo 
64639d17dacSArnaldo Carvalho de Melo out_delete_session:
64739d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
64839d17dacSArnaldo Carvalho de Melo 	return err;
64986470930SIngo Molnar }
65086470930SIngo Molnar 
651bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
652bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
653bdfebd84SRoberto Agostino Vitillo 
654bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
655bdfebd84SRoberto Agostino Vitillo 
656bdfebd84SRoberto Agostino Vitillo struct branch_mode {
657bdfebd84SRoberto Agostino Vitillo 	const char *name;
658bdfebd84SRoberto Agostino Vitillo 	int mode;
659bdfebd84SRoberto Agostino Vitillo };
660bdfebd84SRoberto Agostino Vitillo 
661bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
662bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
663bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
664bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
665bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
666bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
667bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
668bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
669bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
670bdfebd84SRoberto Agostino Vitillo };
671bdfebd84SRoberto Agostino Vitillo 
672bdfebd84SRoberto Agostino Vitillo static int
673a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
674bdfebd84SRoberto Agostino Vitillo {
675bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
676bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
677bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
678bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
679bdfebd84SRoberto Agostino Vitillo 
680bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
681bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
682a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
683bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
684bdfebd84SRoberto Agostino Vitillo 
685a5aabdacSStephane Eranian 	if (unset)
686a5aabdacSStephane Eranian 		return 0;
687bdfebd84SRoberto Agostino Vitillo 
688a5aabdacSStephane Eranian 	/*
689a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
690a5aabdacSStephane Eranian 	 */
691a5aabdacSStephane Eranian 	if (*mode)
692a5aabdacSStephane Eranian 		return -1;
693a5aabdacSStephane Eranian 
694a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
695a5aabdacSStephane Eranian 	if (str) {
696bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
697bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
698bdfebd84SRoberto Agostino Vitillo 		if (!s)
699bdfebd84SRoberto Agostino Vitillo 			return -1;
700bdfebd84SRoberto Agostino Vitillo 
701bdfebd84SRoberto Agostino Vitillo 		for (;;) {
702bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
703bdfebd84SRoberto Agostino Vitillo 			if (p)
704bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
705bdfebd84SRoberto Agostino Vitillo 
706bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
707bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
708bdfebd84SRoberto Agostino Vitillo 					break;
709bdfebd84SRoberto Agostino Vitillo 			}
710a5aabdacSStephane Eranian 			if (!br->name) {
711a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
712a5aabdacSStephane Eranian 					    " check man page\n", s);
713bdfebd84SRoberto Agostino Vitillo 				goto error;
714a5aabdacSStephane Eranian 			}
715bdfebd84SRoberto Agostino Vitillo 
716bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
717bdfebd84SRoberto Agostino Vitillo 
718bdfebd84SRoberto Agostino Vitillo 			if (!p)
719bdfebd84SRoberto Agostino Vitillo 				break;
720bdfebd84SRoberto Agostino Vitillo 
721bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
722bdfebd84SRoberto Agostino Vitillo 		}
723a5aabdacSStephane Eranian 	}
724bdfebd84SRoberto Agostino Vitillo 	ret = 0;
725bdfebd84SRoberto Agostino Vitillo 
726a5aabdacSStephane Eranian 	/* default to any branch */
727bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
728a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
729bdfebd84SRoberto Agostino Vitillo 	}
730bdfebd84SRoberto Agostino Vitillo error:
731bdfebd84SRoberto Agostino Vitillo 	free(os);
732bdfebd84SRoberto Agostino Vitillo 	return ret;
733bdfebd84SRoberto Agostino Vitillo }
734bdfebd84SRoberto Agostino Vitillo 
73586470930SIngo Molnar static const char * const record_usage[] = {
73686470930SIngo Molnar 	"perf record [<options>] [<command>]",
73786470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
73886470930SIngo Molnar 	NULL
73986470930SIngo Molnar };
74086470930SIngo Molnar 
741d20deb64SArnaldo Carvalho de Melo /*
742d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
743d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
744d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
745d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
746d20deb64SArnaldo Carvalho de Melo  *
747d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
748d20deb64SArnaldo Carvalho de Melo  *
749d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
750d20deb64SArnaldo Carvalho de Melo  */
751d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
752d20deb64SArnaldo Carvalho de Melo 	.opts = {
753d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
754d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
755d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
756447a6013SArnaldo Carvalho de Melo 		.freq		     = 4000,
757d1cb9fceSNamhyung Kim 		.target		     = {
758d1cb9fceSNamhyung Kim 			.uses_mmap   = true,
759d1cb9fceSNamhyung Kim 		},
760d20deb64SArnaldo Carvalho de Melo 	},
761d20deb64SArnaldo Carvalho de Melo 	.write_mode = WRITE_FORCE,
762d20deb64SArnaldo Carvalho de Melo 	.file_new   = true,
763d20deb64SArnaldo Carvalho de Melo };
7647865e817SFrederic Weisbecker 
765d20deb64SArnaldo Carvalho de Melo /*
766d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
767d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
768d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
769d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
770d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
771d20deb64SArnaldo Carvalho de Melo  */
772bca647aaSTom Zanussi const struct option record_options[] = {
773d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
77486470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
775f120f9d5SJiri Olsa 		     parse_events_option),
776d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
777c171b552SLi Zefan 		     "event filter", parse_filter),
778bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
779d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
780bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
781d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
782d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
78386470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
784d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
785acac03faSKirill Smelkov 		    "collect data without buffering"),
786d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
787daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
788bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
78986470930SIngo Molnar 			    "system-wide collection from all CPUs"),
790d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('A', "append", &record.append_file,
79186470930SIngo Molnar 			    "append to the output file to do incremental profiling"),
792bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
793c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
794d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('f', "force", &record.force,
7957865e817SFrederic Weisbecker 			"overwrite existing data file (deprecated)"),
796d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
797d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('o', "output", &record.output_name, "file",
79886470930SIngo Molnar 		    "output file name"),
799d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
8002e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
801d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
802d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
80301c2d99bSArnaldo Carvalho de Melo 		     "number of mmap data pages"),
804d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
80543bece79SLin Ming 		    "put the counters into a counter group"),
806d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
8073efa1cc9SIngo Molnar 		    "do call-graph (stack chain/backtrace) recording"),
808c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
8093da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
810b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
811d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
812649c48a9SPeter Zijlstra 		    "per thread counts"),
813d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8144bba828dSAnton Blanchard 		    "Sample addresses"),
815d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8163e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
817d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
818649c48a9SPeter Zijlstra 		    "don't sample"),
819d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
820a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
821d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
822baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
823d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
824023695d9SStephane Eranian 		     "monitor event in cgroup name only",
825023695d9SStephane Eranian 		     parse_cgroups),
826bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
827bea03405SNamhyung Kim 		   "user to profile"),
828a5aabdacSStephane Eranian 
829a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
830a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
831a5aabdacSStephane Eranian 		     parse_branch_stack),
832a5aabdacSStephane Eranian 
833a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
834a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
835bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
83686470930SIngo Molnar 	OPT_END()
83786470930SIngo Molnar };
83886470930SIngo Molnar 
839f37a291cSIngo Molnar int cmd_record(int argc, const char **argv, const char *prefix __used)
84086470930SIngo Molnar {
84169aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
84269aad6f1SArnaldo Carvalho de Melo 	struct perf_evsel *pos;
843d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
844d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
84516ad2ffbSNamhyung Kim 	char errbuf[BUFSIZ];
84686470930SIngo Molnar 
847fbe96f29SStephane Eranian 	perf_header__set_cmdline(argc, argv);
848fbe96f29SStephane Eranian 
8497e2ed097SArnaldo Carvalho de Melo 	evsel_list = perf_evlist__new(NULL, NULL);
850361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
851361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
852361c99a6SArnaldo Carvalho de Melo 
853d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
854d20deb64SArnaldo Carvalho de Melo 
855bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
856a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
857d67356e7SNamhyung Kim 	if (!argc && perf_target__none(&rec->opts.target))
858bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
85986470930SIngo Molnar 
860d20deb64SArnaldo Carvalho de Melo 	if (rec->force && rec->append_file) {
8613780f488SNamhyung Kim 		ui__error("Can't overwrite and append at the same time."
8627865e817SFrederic Weisbecker 			  " You need to choose between -f and -A");
863bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
864d20deb64SArnaldo Carvalho de Melo 	} else if (rec->append_file) {
865d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_APPEND;
8667865e817SFrederic Weisbecker 	} else {
867d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_FORCE;
8687865e817SFrederic Weisbecker 	}
8697865e817SFrederic Weisbecker 
870bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
8713780f488SNamhyung Kim 		ui__error("cgroup monitoring only available in"
872023695d9SStephane Eranian 			  " system-wide mode\n");
873023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
874023695d9SStephane Eranian 	}
875023695d9SStephane Eranian 
876655000e7SArnaldo Carvalho de Melo 	symbol__init();
877baa2f6ceSArnaldo Carvalho de Melo 
878ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
879646aaea6SArnaldo Carvalho de Melo 		pr_warning(
880646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
881ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
882646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
883646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
884646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
885646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
886646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
887ec80fde7SArnaldo Carvalho de Melo 
888d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
889a1ac1d3cSStephane Eranian 		disable_buildid_cache();
890655000e7SArnaldo Carvalho de Melo 
891361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
892361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
89369aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
89469aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
895bbd36e5eSPeter Zijlstra 	}
89686470930SIngo Molnar 
89716ad2ffbSNamhyung Kim 	err = perf_target__validate(&rec->opts.target);
89816ad2ffbSNamhyung Kim 	if (err) {
89916ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
90016ad2ffbSNamhyung Kim 		ui__warning("%s", errbuf);
90116ad2ffbSNamhyung Kim 	}
9024bd0f2d2SNamhyung Kim 
90316ad2ffbSNamhyung Kim 	err = perf_target__parse_uid(&rec->opts.target);
90416ad2ffbSNamhyung Kim 	if (err) {
90516ad2ffbSNamhyung Kim 		int saved_errno = errno;
90616ad2ffbSNamhyung Kim 
90716ad2ffbSNamhyung Kim 		perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
9083780f488SNamhyung Kim 		ui__error("%s", errbuf);
90916ad2ffbSNamhyung Kim 
91016ad2ffbSNamhyung Kim 		err = -saved_errno;
9110d37aa34SArnaldo Carvalho de Melo 		goto out_free_fd;
91216ad2ffbSNamhyung Kim 	}
9130d37aa34SArnaldo Carvalho de Melo 
91416ad2ffbSNamhyung Kim 	err = -ENOMEM;
915b809ac10SNamhyung Kim 	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
916dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
91769aad6f1SArnaldo Carvalho de Melo 
918361c99a6SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evsel_list->entries, node) {
919*7289f83cSArnaldo Carvalho de Melo 		if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
920ad7f4e3fSArnaldo Carvalho de Melo 			goto out_free_fd;
921d6d901c2SZhang, Yanmin 	}
9225c581041SArnaldo Carvalho de Melo 
923d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_interval != ULLONG_MAX)
924d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.user_interval;
925d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_freq != UINT_MAX)
926d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = rec->opts.user_freq;
927f9212819SFrederic Weisbecker 
9287e4ff9e3SMike Galbraith 	/*
9297e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
9307e4ff9e3SMike Galbraith 	 */
931d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.default_interval)
932d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = 0;
933d20deb64SArnaldo Carvalho de Melo 	else if (rec->opts.freq) {
934d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.freq;
9357e4ff9e3SMike Galbraith 	} else {
9363780f488SNamhyung Kim 		ui__error("frequency and count are zero, aborting\n");
93739d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
9385c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
9397e4ff9e3SMike Galbraith 	}
9407e4ff9e3SMike Galbraith 
941d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
94239d17dacSArnaldo Carvalho de Melo out_free_fd:
9437e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
944d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
945d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
94639d17dacSArnaldo Carvalho de Melo 	return err;
94786470930SIngo Molnar }
948