xref: /openbmc/linux/tools/perf/builtin-record.c (revision bea0340582dc47b447a014f5bf9f460925afdaf4)
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);
220*bea03405SNamhyung 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
2453da297a6SIngo Molnar 			 * is always available even if no PMU support:
2463da297a6SIngo Molnar 			 */
2475a7ed29cSRobert Richter 			if (err == ENOENT && attr->type == PERF_TYPE_HARDWARE
248f4dbfa8fSPeter Zijlstra 					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {
2493da297a6SIngo Molnar 
2503da297a6SIngo Molnar 				if (verbose)
251ca6a4258SDavid Ahern 					ui__warning("The cycles event is not supported, "
252ca6a4258SDavid Ahern 						    "trying to fall back to cpu-clock-ticks\n");
2533da297a6SIngo Molnar 				attr->type = PERF_TYPE_SOFTWARE;
254f4dbfa8fSPeter Zijlstra 				attr->config = PERF_COUNT_SW_CPU_CLOCK;
2553da297a6SIngo Molnar 				goto try_again;
2563da297a6SIngo Molnar 			}
257ca6a4258SDavid Ahern 
258ca6a4258SDavid Ahern 			if (err == ENOENT) {
259ca6a4258SDavid Ahern 				ui__warning("The %s event is not supported.\n",
260ca6a4258SDavid Ahern 					    event_name(pos));
261ca6a4258SDavid Ahern 				exit(EXIT_FAILURE);
262ca6a4258SDavid Ahern 			}
263ca6a4258SDavid Ahern 
26430c806a0SIngo Molnar 			printf("\n");
265d9cf837eSCorey Ashford 			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
266dd7927f4SArnaldo Carvalho de Melo 			      err, strerror(err));
267bfd45118SSimon Kaempflein 
268bfd45118SSimon Kaempflein #if defined(__i386__) || defined(__x86_64__)
269bfd45118SSimon Kaempflein 			if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
270d6d901c2SZhang, Yanmin 				die("No hardware sampling interrupt available."
271d6d901c2SZhang, Yanmin 				    " No APIC? If so then you can boot the kernel"
272d6d901c2SZhang, Yanmin 				    " with the \"lapic\" boot parameter to"
273d6d901c2SZhang, Yanmin 				    " force-enable it.\n");
274bfd45118SSimon Kaempflein #endif
275bfd45118SSimon Kaempflein 
276cdd6c482SIngo Molnar 			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
2777c6a1c65SPeter Zijlstra 		}
2787c6a1c65SPeter Zijlstra 	}
2797c6a1c65SPeter Zijlstra 
2800a102479SFrederic Weisbecker 	if (perf_evlist__set_filters(evlist)) {
2810a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2820a102479SFrederic Weisbecker 			strerror(errno));
2830a102479SFrederic Weisbecker 		exit(-1);
2840a102479SFrederic Weisbecker 	}
2850a102479SFrederic Weisbecker 
28618e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
28718e60939SNelson Elhage 		if (errno == EPERM)
28818e60939SNelson Elhage 			die("Permission error mapping pages.\n"
28918e60939SNelson Elhage 			    "Consider increasing "
29018e60939SNelson Elhage 			    "/proc/sys/kernel/perf_event_mlock_kb,\n"
29118e60939SNelson Elhage 			    "or try again with a smaller value of -m/--mmap_pages.\n"
29218e60939SNelson Elhage 			    "(current value: %d)\n", opts->mmap_pages);
29341d0d933SNelson Elhage 		else if (!is_power_of_2(opts->mmap_pages))
29441d0d933SNelson Elhage 			die("--mmap_pages/-m value must be a power of two.");
29541d0d933SNelson Elhage 
2960a27d7f9SArnaldo Carvalho de Melo 		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
29718e60939SNelson Elhage 	}
2980a27d7f9SArnaldo Carvalho de Melo 
299d20deb64SArnaldo Carvalho de Melo 	if (rec->file_new)
300a91e5431SArnaldo Carvalho de Melo 		session->evlist = evlist;
301a91e5431SArnaldo Carvalho de Melo 	else {
302a91e5431SArnaldo Carvalho de Melo 		if (!perf_evlist__equal(session->evlist, evlist)) {
303a91e5431SArnaldo Carvalho de Melo 			fprintf(stderr, "incompatible append\n");
304a91e5431SArnaldo Carvalho de Melo 			exit(-1);
305dd7927f4SArnaldo Carvalho de Melo 		}
30686470930SIngo Molnar  	}
30786470930SIngo Molnar 
308a91e5431SArnaldo Carvalho de Melo 	perf_session__update_sample_type(session);
309a91e5431SArnaldo Carvalho de Melo }
310a91e5431SArnaldo Carvalho de Melo 
311d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
3126122e4e4SArnaldo Carvalho de Melo {
313d20deb64SArnaldo Carvalho de Melo 	u64 size = lseek(rec->output, 0, SEEK_CUR);
3146122e4e4SArnaldo Carvalho de Melo 
3159f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
3169f591fd7SArnaldo Carvalho de Melo 		return 0;
3179f591fd7SArnaldo Carvalho de Melo 
318d20deb64SArnaldo Carvalho de Melo 	rec->session->fd = rec->output;
319d20deb64SArnaldo Carvalho de Melo 	return __perf_session__process_events(rec->session, rec->post_processing_offset,
320d20deb64SArnaldo Carvalho de Melo 					      size - rec->post_processing_offset,
3216122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
3226122e4e4SArnaldo Carvalho de Melo }
3236122e4e4SArnaldo Carvalho de Melo 
324d20deb64SArnaldo Carvalho de Melo static void perf_record__exit(int status __used, void *arg)
325f5970550SPeter Zijlstra {
326d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
327f5970550SPeter Zijlstra 
328d20deb64SArnaldo Carvalho de Melo 	if (!rec->opts.pipe_output) {
329d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
330d20deb64SArnaldo Carvalho de Melo 
331d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
332d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
333d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
334d20deb64SArnaldo Carvalho de Melo 					   rec->output, true);
335d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
336d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
337d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
338c7929e47STom Zanussi 	}
339f5970550SPeter Zijlstra }
340f5970550SPeter Zijlstra 
3418115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
342a1645ce1SZhang, Yanmin {
343a1645ce1SZhang, Yanmin 	int err;
34445694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
345a1645ce1SZhang, Yanmin 
34623346f21SArnaldo Carvalho de Melo 	if (machine__is_host(machine))
347a1645ce1SZhang, Yanmin 		return;
348a1645ce1SZhang, Yanmin 
349a1645ce1SZhang, Yanmin 	/*
350a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
351a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
352a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
353a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
354a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
355a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
356a1645ce1SZhang, Yanmin 	 */
35745694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
358743eb868SArnaldo Carvalho de Melo 					     machine);
359a1645ce1SZhang, Yanmin 	if (err < 0)
360a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
36123346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
362a1645ce1SZhang, Yanmin 
363a1645ce1SZhang, Yanmin 	/*
364a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
365a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
366a1645ce1SZhang, Yanmin 	 */
36745694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
368743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
369a1645ce1SZhang, Yanmin 	if (err < 0)
37045694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
371743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
372a1645ce1SZhang, Yanmin 	if (err < 0)
373a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
37423346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
375a1645ce1SZhang, Yanmin }
376a1645ce1SZhang, Yanmin 
37798402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
37898402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
37998402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
38098402807SFrederic Weisbecker };
38198402807SFrederic Weisbecker 
382d20deb64SArnaldo Carvalho de Melo static void perf_record__mmap_read_all(struct perf_record *rec)
38398402807SFrederic Weisbecker {
3840e2e63ddSPeter Zijlstra 	int i;
38598402807SFrederic Weisbecker 
386d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
387d20deb64SArnaldo Carvalho de Melo 		if (rec->evlist->mmap[i].base)
388d20deb64SArnaldo Carvalho de Melo 			perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
38998402807SFrederic Weisbecker 	}
39098402807SFrederic Weisbecker 
391d20deb64SArnaldo Carvalho de Melo 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
392d20deb64SArnaldo Carvalho de Melo 		write_output(rec, &finished_round_event, sizeof(finished_round_event));
39398402807SFrederic Weisbecker }
39498402807SFrederic Weisbecker 
395d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
39686470930SIngo Molnar {
39786470930SIngo Molnar 	struct stat st;
39886470930SIngo Molnar 	int flags;
399781ba9d2SRobert Richter 	int err, output, feat;
4008b412664SPeter Zijlstra 	unsigned long waking = 0;
40146be604bSZhang, Yanmin 	const bool forks = argc > 0;
40223346f21SArnaldo Carvalho de Melo 	struct machine *machine;
40345694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
404d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
405d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
406d20deb64SArnaldo Carvalho de Melo 	const char *output_name = rec->output_name;
407d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
40886470930SIngo Molnar 
409d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
41033e49ea7SAndi Kleen 
411d20deb64SArnaldo Carvalho de Melo 	rec->page_size = sysconf(_SC_PAGE_SIZE);
41286470930SIngo Molnar 
413d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
414f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
415f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
41618483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
417f5970550SPeter Zijlstra 
418d7065adbSFranck Bui-Huu 	if (!output_name) {
419d7065adbSFranck Bui-Huu 		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
420d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
421d7065adbSFranck Bui-Huu 		else
422d20deb64SArnaldo Carvalho de Melo 			rec->output_name = output_name = "perf.data";
423d7065adbSFranck Bui-Huu 	}
424d7065adbSFranck Bui-Huu 	if (output_name) {
425529870e3STom Zanussi 		if (!strcmp(output_name, "-"))
426d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
427529870e3STom Zanussi 		else if (!stat(output_name, &st) && st.st_size) {
428d20deb64SArnaldo Carvalho de Melo 			if (rec->write_mode == WRITE_FORCE) {
429b38d3464SArnaldo Carvalho de Melo 				char oldname[PATH_MAX];
430b38d3464SArnaldo Carvalho de Melo 				snprintf(oldname, sizeof(oldname), "%s.old",
431b38d3464SArnaldo Carvalho de Melo 					 output_name);
432b38d3464SArnaldo Carvalho de Melo 				unlink(oldname);
433b38d3464SArnaldo Carvalho de Melo 				rename(output_name, oldname);
434b38d3464SArnaldo Carvalho de Melo 			}
435d20deb64SArnaldo Carvalho de Melo 		} else if (rec->write_mode == WRITE_APPEND) {
436d20deb64SArnaldo Carvalho de Melo 			rec->write_mode = WRITE_FORCE;
437266e0e21SPierre Habouzit 		}
438d7065adbSFranck Bui-Huu 	}
43986470930SIngo Molnar 
440f887f301SXiao Guangrong 	flags = O_CREAT|O_RDWR;
441d20deb64SArnaldo Carvalho de Melo 	if (rec->write_mode == WRITE_APPEND)
442d20deb64SArnaldo Carvalho de Melo 		rec->file_new = 0;
44386470930SIngo Molnar 	else
44486470930SIngo Molnar 		flags |= O_TRUNC;
44586470930SIngo Molnar 
446d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output)
447529870e3STom Zanussi 		output = STDOUT_FILENO;
448529870e3STom Zanussi 	else
44986470930SIngo Molnar 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
45086470930SIngo Molnar 	if (output < 0) {
45186470930SIngo Molnar 		perror("failed to create output file");
45286470930SIngo Molnar 		exit(-1);
45386470930SIngo Molnar 	}
45486470930SIngo Molnar 
455d20deb64SArnaldo Carvalho de Melo 	rec->output = output;
456d20deb64SArnaldo Carvalho de Melo 
4577865e817SFrederic Weisbecker 	session = perf_session__new(output_name, O_WRONLY,
458d20deb64SArnaldo Carvalho de Melo 				    rec->write_mode == WRITE_FORCE, false, NULL);
45994c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
460a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
461a9a70bbcSArnaldo Carvalho de Melo 		return -1;
462a9a70bbcSArnaldo Carvalho de Melo 	}
463a9a70bbcSArnaldo Carvalho de Melo 
464d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
465d20deb64SArnaldo Carvalho de Melo 
466781ba9d2SRobert Richter 	for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
467781ba9d2SRobert Richter 		perf_header__set_feat(&session->header, feat);
468781ba9d2SRobert Richter 
469781ba9d2SRobert Richter 	if (rec->no_buildid)
470781ba9d2SRobert Richter 		perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
471781ba9d2SRobert Richter 
472781ba9d2SRobert Richter 	if (!have_tracepoints(&evsel_list->entries))
473781ba9d2SRobert Richter 		perf_header__clear_feat(&session->header, HEADER_TRACE_INFO);
474baa2f6ceSArnaldo Carvalho de Melo 
475330aa675SStephane Eranian 	if (!rec->opts.branch_stack)
476330aa675SStephane Eranian 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
477330aa675SStephane Eranian 
478d20deb64SArnaldo Carvalho de Melo 	if (!rec->file_new) {
479a91e5431SArnaldo Carvalho de Melo 		err = perf_session__read_header(session, output);
4804dc0a04bSArnaldo Carvalho de Melo 		if (err < 0)
48139d17dacSArnaldo Carvalho de Melo 			goto out_delete_session;
4824dc0a04bSArnaldo Carvalho de Melo 	}
4834dc0a04bSArnaldo Carvalho de Melo 
484d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
485d20deb64SArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(evsel_list, opts, argv);
48635b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
48735b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
48835b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
489856e9660SPeter Zijlstra 		}
490856e9660SPeter Zijlstra 	}
491856e9660SPeter Zijlstra 
492d20deb64SArnaldo Carvalho de Melo 	perf_record__open(rec);
49386470930SIngo Molnar 
494712a4b60SArnaldo Carvalho de Melo 	/*
495d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
496712a4b60SArnaldo Carvalho de Melo 	 */
497d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
498712a4b60SArnaldo Carvalho de Melo 
499d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
500529870e3STom Zanussi 		err = perf_header__write_pipe(output);
501529870e3STom Zanussi 		if (err < 0)
502529870e3STom Zanussi 			return err;
503d20deb64SArnaldo Carvalho de Melo 	} else if (rec->file_new) {
504a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
505361c99a6SArnaldo Carvalho de Melo 						 output, false);
506d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
507d5eed904SArnaldo Carvalho de Melo 			return err;
508d5eed904SArnaldo Carvalho de Melo 	}
5097c6a1c65SPeter Zijlstra 
510d3665498SDavid Ahern 	if (!rec->no_buildid
511e20960c0SRobert Richter 	    && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
512d3665498SDavid Ahern 		pr_err("Couldn't generate buildids. "
513e20960c0SRobert Richter 		       "Use --no-buildid to profile anyway.\n");
514e20960c0SRobert Richter 		return -1;
515e20960c0SRobert Richter 	}
516e20960c0SRobert Richter 
517d20deb64SArnaldo Carvalho de Melo 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
5186122e4e4SArnaldo Carvalho de Melo 
519743eb868SArnaldo Carvalho de Melo 	machine = perf_session__find_host_machine(session);
520743eb868SArnaldo Carvalho de Melo 	if (!machine) {
521743eb868SArnaldo Carvalho de Melo 		pr_err("Couldn't find native kernel information.\n");
522743eb868SArnaldo Carvalho de Melo 		return -1;
523743eb868SArnaldo Carvalho de Melo 	}
524743eb868SArnaldo Carvalho de Melo 
525d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
52645694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
527a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
5282c46dbb5STom Zanussi 		if (err < 0) {
5292c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
5302c46dbb5STom Zanussi 			return err;
5312c46dbb5STom Zanussi 		}
532cd19a035STom Zanussi 
53345694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_event_types(tool, process_synthesized_event,
534743eb868SArnaldo Carvalho de Melo 							 machine);
535cd19a035STom Zanussi 		if (err < 0) {
536cd19a035STom Zanussi 			pr_err("Couldn't synthesize event_types.\n");
537cd19a035STom Zanussi 			return err;
538cd19a035STom Zanussi 		}
5399215545eSTom Zanussi 
540361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
54163e0c771STom Zanussi 			/*
54263e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
54363e0c771STom Zanussi 			 * there were no tracepoints so its not really
54463e0c771STom Zanussi 			 * an error, just that we don't need to
54563e0c771STom Zanussi 			 * synthesize anything.  We really have to
54663e0c771STom Zanussi 			 * return this more properly and also
54763e0c771STom Zanussi 			 * propagate errors that now are calling die()
54863e0c771STom Zanussi 			 */
54945694aa7SArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
550743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
55163e0c771STom Zanussi 			if (err <= 0) {
55263e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
55363e0c771STom Zanussi 				return err;
55463e0c771STom Zanussi 			}
555d20deb64SArnaldo Carvalho de Melo 			advance_output(rec, err);
5562c46dbb5STom Zanussi 		}
55763e0c771STom Zanussi 	}
5582c46dbb5STom Zanussi 
55945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
560743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
56170162138SArnaldo Carvalho de Melo 	if (err < 0)
56245694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
563743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
564c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
565c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
566c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
567c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
56856b03f3cSArnaldo Carvalho de Melo 
56945694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
570743eb868SArnaldo Carvalho de Melo 					     machine);
571c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
572c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
573c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
574c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
575c1a3a4b9SArnaldo Carvalho de Melo 
576a1645ce1SZhang, Yanmin 	if (perf_guest)
57745694aa7SArnaldo Carvalho de Melo 		perf_session__process_machines(session, tool,
5788115d60cSArnaldo Carvalho de Melo 					       perf_event__synthesize_guest_os);
579b7cece76SArnaldo Carvalho de Melo 
580*bea03405SNamhyung Kim 	if (!opts->target.system_wide)
58145694aa7SArnaldo Carvalho de Melo 		perf_event__synthesize_thread_map(tool, evsel_list->threads,
5828115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
583743eb868SArnaldo Carvalho de Melo 						  machine);
584234fbbf5SArnaldo Carvalho de Melo 	else
58545694aa7SArnaldo Carvalho de Melo 		perf_event__synthesize_threads(tool, process_synthesized_event,
586743eb868SArnaldo Carvalho de Melo 					       machine);
5877c6a1c65SPeter Zijlstra 
588d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
58986470930SIngo Molnar 		struct sched_param param;
59086470930SIngo Molnar 
591d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
59286470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5936beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
59486470930SIngo Molnar 			exit(-1);
59586470930SIngo Molnar 		}
59686470930SIngo Molnar 	}
59786470930SIngo Molnar 
598764e16a3SDavid Ahern 	perf_evlist__enable(evsel_list);
599764e16a3SDavid Ahern 
600856e9660SPeter Zijlstra 	/*
601856e9660SPeter Zijlstra 	 * Let the child rip
602856e9660SPeter Zijlstra 	 */
603d4db3f16SArnaldo Carvalho de Melo 	if (forks)
60435b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
605856e9660SPeter Zijlstra 
606649c48a9SPeter Zijlstra 	for (;;) {
607d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
60886470930SIngo Molnar 
609d20deb64SArnaldo Carvalho de Melo 		perf_record__mmap_read_all(rec);
61086470930SIngo Molnar 
611d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
612649c48a9SPeter Zijlstra 			if (done)
613649c48a9SPeter Zijlstra 				break;
6145c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
6158b412664SPeter Zijlstra 			waking++;
6168b412664SPeter Zijlstra 		}
6178b412664SPeter Zijlstra 
6184152ab37SArnaldo Carvalho de Melo 		if (done)
6194152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
6208b412664SPeter Zijlstra 	}
6218b412664SPeter Zijlstra 
62218483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
623b44308f5SArnaldo Carvalho de Melo 		return 0;
624b44308f5SArnaldo Carvalho de Melo 
6258b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
62686470930SIngo Molnar 
62786470930SIngo Molnar 	/*
62886470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
62986470930SIngo Molnar 	 */
63086470930SIngo Molnar 	fprintf(stderr,
6319486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
632d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
63386470930SIngo Molnar 		output_name,
634d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
63586470930SIngo Molnar 
63686470930SIngo Molnar 	return 0;
63739d17dacSArnaldo Carvalho de Melo 
63839d17dacSArnaldo Carvalho de Melo out_delete_session:
63939d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
64039d17dacSArnaldo Carvalho de Melo 	return err;
64186470930SIngo Molnar }
64286470930SIngo Molnar 
643bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \
644bdfebd84SRoberto Agostino Vitillo 	{ .name = n, .mode = (m) }
645bdfebd84SRoberto Agostino Vitillo 
646bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL }
647bdfebd84SRoberto Agostino Vitillo 
648bdfebd84SRoberto Agostino Vitillo struct branch_mode {
649bdfebd84SRoberto Agostino Vitillo 	const char *name;
650bdfebd84SRoberto Agostino Vitillo 	int mode;
651bdfebd84SRoberto Agostino Vitillo };
652bdfebd84SRoberto Agostino Vitillo 
653bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = {
654bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
655bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
656bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
657bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
658bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
659bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
660bdfebd84SRoberto Agostino Vitillo 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
661bdfebd84SRoberto Agostino Vitillo 	BRANCH_END
662bdfebd84SRoberto Agostino Vitillo };
663bdfebd84SRoberto Agostino Vitillo 
664bdfebd84SRoberto Agostino Vitillo static int
665a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset)
666bdfebd84SRoberto Agostino Vitillo {
667bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \
668bdfebd84SRoberto Agostino Vitillo 	(PERF_SAMPLE_BRANCH_USER	|\
669bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_KERNEL	|\
670bdfebd84SRoberto Agostino Vitillo 	 PERF_SAMPLE_BRANCH_HV)
671bdfebd84SRoberto Agostino Vitillo 
672bdfebd84SRoberto Agostino Vitillo 	uint64_t *mode = (uint64_t *)opt->value;
673bdfebd84SRoberto Agostino Vitillo 	const struct branch_mode *br;
674a5aabdacSStephane Eranian 	char *s, *os = NULL, *p;
675bdfebd84SRoberto Agostino Vitillo 	int ret = -1;
676bdfebd84SRoberto Agostino Vitillo 
677a5aabdacSStephane Eranian 	if (unset)
678a5aabdacSStephane Eranian 		return 0;
679bdfebd84SRoberto Agostino Vitillo 
680a5aabdacSStephane Eranian 	/*
681a5aabdacSStephane Eranian 	 * cannot set it twice, -b + --branch-filter for instance
682a5aabdacSStephane Eranian 	 */
683a5aabdacSStephane Eranian 	if (*mode)
684a5aabdacSStephane Eranian 		return -1;
685a5aabdacSStephane Eranian 
686a5aabdacSStephane Eranian 	/* str may be NULL in case no arg is passed to -b */
687a5aabdacSStephane Eranian 	if (str) {
688bdfebd84SRoberto Agostino Vitillo 		/* because str is read-only */
689bdfebd84SRoberto Agostino Vitillo 		s = os = strdup(str);
690bdfebd84SRoberto Agostino Vitillo 		if (!s)
691bdfebd84SRoberto Agostino Vitillo 			return -1;
692bdfebd84SRoberto Agostino Vitillo 
693bdfebd84SRoberto Agostino Vitillo 		for (;;) {
694bdfebd84SRoberto Agostino Vitillo 			p = strchr(s, ',');
695bdfebd84SRoberto Agostino Vitillo 			if (p)
696bdfebd84SRoberto Agostino Vitillo 				*p = '\0';
697bdfebd84SRoberto Agostino Vitillo 
698bdfebd84SRoberto Agostino Vitillo 			for (br = branch_modes; br->name; br++) {
699bdfebd84SRoberto Agostino Vitillo 				if (!strcasecmp(s, br->name))
700bdfebd84SRoberto Agostino Vitillo 					break;
701bdfebd84SRoberto Agostino Vitillo 			}
702a5aabdacSStephane Eranian 			if (!br->name) {
703a5aabdacSStephane Eranian 				ui__warning("unknown branch filter %s,"
704a5aabdacSStephane Eranian 					    " check man page\n", s);
705bdfebd84SRoberto Agostino Vitillo 				goto error;
706a5aabdacSStephane Eranian 			}
707bdfebd84SRoberto Agostino Vitillo 
708bdfebd84SRoberto Agostino Vitillo 			*mode |= br->mode;
709bdfebd84SRoberto Agostino Vitillo 
710bdfebd84SRoberto Agostino Vitillo 			if (!p)
711bdfebd84SRoberto Agostino Vitillo 				break;
712bdfebd84SRoberto Agostino Vitillo 
713bdfebd84SRoberto Agostino Vitillo 			s = p + 1;
714bdfebd84SRoberto Agostino Vitillo 		}
715a5aabdacSStephane Eranian 	}
716bdfebd84SRoberto Agostino Vitillo 	ret = 0;
717bdfebd84SRoberto Agostino Vitillo 
718a5aabdacSStephane Eranian 	/* default to any branch */
719bdfebd84SRoberto Agostino Vitillo 	if ((*mode & ~ONLY_PLM) == 0) {
720a5aabdacSStephane Eranian 		*mode = PERF_SAMPLE_BRANCH_ANY;
721bdfebd84SRoberto Agostino Vitillo 	}
722bdfebd84SRoberto Agostino Vitillo error:
723bdfebd84SRoberto Agostino Vitillo 	free(os);
724bdfebd84SRoberto Agostino Vitillo 	return ret;
725bdfebd84SRoberto Agostino Vitillo }
726bdfebd84SRoberto Agostino Vitillo 
72786470930SIngo Molnar static const char * const record_usage[] = {
72886470930SIngo Molnar 	"perf record [<options>] [<command>]",
72986470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
73086470930SIngo Molnar 	NULL
73186470930SIngo Molnar };
73286470930SIngo Molnar 
733d20deb64SArnaldo Carvalho de Melo /*
734d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
735d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
736d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
737d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
738d20deb64SArnaldo Carvalho de Melo  *
739d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
740d20deb64SArnaldo Carvalho de Melo  *
741d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
742d20deb64SArnaldo Carvalho de Melo  */
743d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
744d20deb64SArnaldo Carvalho de Melo 	.opts = {
745d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
746d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
747d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
748d20deb64SArnaldo Carvalho de Melo 		.freq		     = 1000,
749d20deb64SArnaldo Carvalho de Melo 	},
750d20deb64SArnaldo Carvalho de Melo 	.write_mode = WRITE_FORCE,
751d20deb64SArnaldo Carvalho de Melo 	.file_new   = true,
752d20deb64SArnaldo Carvalho de Melo };
7537865e817SFrederic Weisbecker 
754d20deb64SArnaldo Carvalho de Melo /*
755d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
756d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
757d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
758d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
759d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
760d20deb64SArnaldo Carvalho de Melo  */
761bca647aaSTom Zanussi const struct option record_options[] = {
762d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
76386470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
764f120f9d5SJiri Olsa 		     parse_events_option),
765d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
766c171b552SLi Zefan 		     "event filter", parse_filter),
767*bea03405SNamhyung Kim 	OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
768d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
769*bea03405SNamhyung Kim 	OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
770d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
771d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
77286470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
773d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
774acac03faSKirill Smelkov 		    "collect data without buffering"),
775d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
776daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
777*bea03405SNamhyung Kim 	OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
77886470930SIngo Molnar 			    "system-wide collection from all CPUs"),
779d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('A', "append", &record.append_file,
78086470930SIngo Molnar 			    "append to the output file to do incremental profiling"),
781*bea03405SNamhyung Kim 	OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
782c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
783d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('f', "force", &record.force,
7847865e817SFrederic Weisbecker 			"overwrite existing data file (deprecated)"),
785d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
786d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('o', "output", &record.output_name, "file",
78786470930SIngo Molnar 		    "output file name"),
788d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
7892e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
790d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
791d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
79201c2d99bSArnaldo Carvalho de Melo 		     "number of mmap data pages"),
793d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
79443bece79SLin Ming 		    "put the counters into a counter group"),
795d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
7963efa1cc9SIngo Molnar 		    "do call-graph (stack chain/backtrace) recording"),
797c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
7983da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
799b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
800d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
801649c48a9SPeter Zijlstra 		    "per thread counts"),
802d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
8034bba828dSAnton Blanchard 		    "Sample addresses"),
804d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
8053e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
806d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
807649c48a9SPeter Zijlstra 		    "don't sample"),
808d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
809a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
810d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
811baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
812d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
813023695d9SStephane Eranian 		     "monitor event in cgroup name only",
814023695d9SStephane Eranian 		     parse_cgroups),
815*bea03405SNamhyung Kim 	OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
816*bea03405SNamhyung Kim 		   "user to profile"),
817a5aabdacSStephane Eranian 
818a5aabdacSStephane Eranian 	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
819a5aabdacSStephane Eranian 		     "branch any", "sample any taken branches",
820a5aabdacSStephane Eranian 		     parse_branch_stack),
821a5aabdacSStephane Eranian 
822a5aabdacSStephane Eranian 	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
823a5aabdacSStephane Eranian 		     "branch filter mask", "branch stack filter modes",
824bdfebd84SRoberto Agostino Vitillo 		     parse_branch_stack),
82586470930SIngo Molnar 	OPT_END()
82686470930SIngo Molnar };
82786470930SIngo Molnar 
828f37a291cSIngo Molnar int cmd_record(int argc, const char **argv, const char *prefix __used)
82986470930SIngo Molnar {
83069aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
83169aad6f1SArnaldo Carvalho de Melo 	struct perf_evsel *pos;
832d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
833d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
83486470930SIngo Molnar 
835fbe96f29SStephane Eranian 	perf_header__set_cmdline(argc, argv);
836fbe96f29SStephane Eranian 
8377e2ed097SArnaldo Carvalho de Melo 	evsel_list = perf_evlist__new(NULL, NULL);
838361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
839361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
840361c99a6SArnaldo Carvalho de Melo 
841d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
842d20deb64SArnaldo Carvalho de Melo 
843bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
844a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
845*bea03405SNamhyung Kim 	if (!argc && !rec->opts.target.pid && !rec->opts.target.tid &&
846*bea03405SNamhyung Kim 	    !rec->opts.target.system_wide && !rec->opts.target.cpu_list &&
847*bea03405SNamhyung Kim 	    !rec->opts.target.uid_str)
848bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
84986470930SIngo Molnar 
850d20deb64SArnaldo Carvalho de Melo 	if (rec->force && rec->append_file) {
8517865e817SFrederic Weisbecker 		fprintf(stderr, "Can't overwrite and append at the same time."
8527865e817SFrederic Weisbecker 				" You need to choose between -f and -A");
853bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
854d20deb64SArnaldo Carvalho de Melo 	} else if (rec->append_file) {
855d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_APPEND;
8567865e817SFrederic Weisbecker 	} else {
857d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_FORCE;
8587865e817SFrederic Weisbecker 	}
8597865e817SFrederic Weisbecker 
860*bea03405SNamhyung Kim 	if (nr_cgroups && !rec->opts.target.system_wide) {
861023695d9SStephane Eranian 		fprintf(stderr, "cgroup monitoring only available in"
862023695d9SStephane Eranian 			" system-wide mode\n");
863023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
864023695d9SStephane Eranian 	}
865023695d9SStephane Eranian 
866655000e7SArnaldo Carvalho de Melo 	symbol__init();
867baa2f6ceSArnaldo Carvalho de Melo 
868ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
869646aaea6SArnaldo Carvalho de Melo 		pr_warning(
870646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
871ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
872646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
873646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
874646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
875646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
876646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
877ec80fde7SArnaldo Carvalho de Melo 
878d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
879a1ac1d3cSStephane Eranian 		disable_buildid_cache();
880655000e7SArnaldo Carvalho de Melo 
881361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
882361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
88369aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
88469aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
885bbd36e5eSPeter Zijlstra 	}
88686470930SIngo Molnar 
887*bea03405SNamhyung Kim 	rec->opts.target.uid = parse_target_uid(rec->opts.target.uid_str,
888*bea03405SNamhyung Kim 						rec->opts.target.tid,
889*bea03405SNamhyung Kim 						rec->opts.target.pid);
890*bea03405SNamhyung Kim 	if (rec->opts.target.uid_str != NULL &&
891*bea03405SNamhyung Kim 	    rec->opts.target.uid == UINT_MAX - 1)
8920d37aa34SArnaldo Carvalho de Melo 		goto out_free_fd;
8930d37aa34SArnaldo Carvalho de Melo 
894*bea03405SNamhyung Kim 	if (rec->opts.target.pid)
895*bea03405SNamhyung Kim 		rec->opts.target.tid = rec->opts.target.pid;
896d6d901c2SZhang, Yanmin 
897*bea03405SNamhyung Kim 	if (perf_evlist__create_maps(evsel_list, rec->opts.target.pid,
898*bea03405SNamhyung Kim 				     rec->opts.target.tid, rec->opts.target.uid,
899*bea03405SNamhyung Kim 				     rec->opts.target.cpu_list) < 0)
900dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
90169aad6f1SArnaldo Carvalho de Melo 
902361c99a6SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evsel_list->entries, node) {
903ad7f4e3fSArnaldo Carvalho de Melo 		if (perf_header__push_event(pos->attr.config, event_name(pos)))
904ad7f4e3fSArnaldo Carvalho de Melo 			goto out_free_fd;
905d6d901c2SZhang, Yanmin 	}
9065c581041SArnaldo Carvalho de Melo 
907d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_interval != ULLONG_MAX)
908d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.user_interval;
909d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_freq != UINT_MAX)
910d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = rec->opts.user_freq;
911f9212819SFrederic Weisbecker 
9127e4ff9e3SMike Galbraith 	/*
9137e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
9147e4ff9e3SMike Galbraith 	 */
915d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.default_interval)
916d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = 0;
917d20deb64SArnaldo Carvalho de Melo 	else if (rec->opts.freq) {
918d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.freq;
9197e4ff9e3SMike Galbraith 	} else {
9207e4ff9e3SMike Galbraith 		fprintf(stderr, "frequency and count are zero, aborting\n");
92139d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
9225c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
9237e4ff9e3SMike Galbraith 	}
9247e4ff9e3SMike Galbraith 
925d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
92639d17dacSArnaldo Carvalho de Melo out_free_fd:
9277e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
928d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
929d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
93039d17dacSArnaldo Carvalho de Melo 	return err;
93186470930SIngo Molnar }
932