xref: /openbmc/linux/tools/perf/builtin-record.c (revision 41d0d933494ce10eb77758a1168b08e317c42e8e)
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;
2079c90a61cSArnaldo Carvalho de Melo retry_sample_id:
208d20deb64SArnaldo Carvalho de Melo 		attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
2093da297a6SIngo Molnar try_again:
210ed80f581SArnaldo Carvalho de Melo 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
211d20deb64SArnaldo Carvalho de Melo 				     opts->group, group_fd) < 0) {
21286470930SIngo Molnar 			int err = errno;
21386470930SIngo Molnar 
214c286c419SArnaldo Carvalho de Melo 			if (err == EPERM || err == EACCES) {
215b8631e6eSArnaldo Carvalho de Melo 				ui__error_paranoid();
216c286c419SArnaldo Carvalho de Melo 				exit(EXIT_FAILURE);
217d20deb64SArnaldo Carvalho de Melo 			} else if (err ==  ENODEV && opts->cpu_list) {
218d6d901c2SZhang, Yanmin 				die("No such device - did you specify"
219d6d901c2SZhang, Yanmin 					" an out-of-range profile CPU?\n");
220d20deb64SArnaldo Carvalho de Melo 			} else if (err == EINVAL && opts->sample_id_all_avail) {
2219c90a61cSArnaldo Carvalho de Melo 				/*
2229c90a61cSArnaldo Carvalho de Melo 				 * Old kernel, no attr->sample_id_type_all field
2239c90a61cSArnaldo Carvalho de Melo 				 */
224d20deb64SArnaldo Carvalho de Melo 				opts->sample_id_all_avail = false;
225d20deb64SArnaldo Carvalho de Melo 				if (!opts->sample_time && !opts->raw_samples && !time_needed)
226eac23d1cSIan Munsie 					attr->sample_type &= ~PERF_SAMPLE_TIME;
227eac23d1cSIan Munsie 
2289c90a61cSArnaldo Carvalho de Melo 				goto retry_sample_id;
229d6d901c2SZhang, Yanmin 			}
2303da297a6SIngo Molnar 
2313da297a6SIngo Molnar 			/*
2323da297a6SIngo Molnar 			 * If it's cycles then fall back to hrtimer
2333da297a6SIngo Molnar 			 * based cpu-clock-tick sw counter, which
2343da297a6SIngo Molnar 			 * is always available even if no PMU support:
2353da297a6SIngo Molnar 			 */
2363da297a6SIngo Molnar 			if (attr->type == PERF_TYPE_HARDWARE
237f4dbfa8fSPeter Zijlstra 					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {
2383da297a6SIngo Molnar 
2393da297a6SIngo Molnar 				if (verbose)
240ca6a4258SDavid Ahern 					ui__warning("The cycles event is not supported, "
241ca6a4258SDavid Ahern 						    "trying to fall back to cpu-clock-ticks\n");
2423da297a6SIngo Molnar 				attr->type = PERF_TYPE_SOFTWARE;
243f4dbfa8fSPeter Zijlstra 				attr->config = PERF_COUNT_SW_CPU_CLOCK;
2443da297a6SIngo Molnar 				goto try_again;
2453da297a6SIngo Molnar 			}
246ca6a4258SDavid Ahern 
247ca6a4258SDavid Ahern 			if (err == ENOENT) {
248ca6a4258SDavid Ahern 				ui__warning("The %s event is not supported.\n",
249ca6a4258SDavid Ahern 					    event_name(pos));
250ca6a4258SDavid Ahern 				exit(EXIT_FAILURE);
251ca6a4258SDavid Ahern 			}
252ca6a4258SDavid Ahern 
25330c806a0SIngo Molnar 			printf("\n");
254d9cf837eSCorey Ashford 			error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
255dd7927f4SArnaldo Carvalho de Melo 			      err, strerror(err));
256bfd45118SSimon Kaempflein 
257bfd45118SSimon Kaempflein #if defined(__i386__) || defined(__x86_64__)
258bfd45118SSimon Kaempflein 			if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
259d6d901c2SZhang, Yanmin 				die("No hardware sampling interrupt available."
260d6d901c2SZhang, Yanmin 				    " No APIC? If so then you can boot the kernel"
261d6d901c2SZhang, Yanmin 				    " with the \"lapic\" boot parameter to"
262d6d901c2SZhang, Yanmin 				    " force-enable it.\n");
263bfd45118SSimon Kaempflein #endif
264bfd45118SSimon Kaempflein 
265cdd6c482SIngo Molnar 			die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
2667c6a1c65SPeter Zijlstra 		}
2677c6a1c65SPeter Zijlstra 	}
2687c6a1c65SPeter Zijlstra 
2690a102479SFrederic Weisbecker 	if (perf_evlist__set_filters(evlist)) {
2700a102479SFrederic Weisbecker 		error("failed to set filter with %d (%s)\n", errno,
2710a102479SFrederic Weisbecker 			strerror(errno));
2720a102479SFrederic Weisbecker 		exit(-1);
2730a102479SFrederic Weisbecker 	}
2740a102479SFrederic Weisbecker 
27518e60939SNelson Elhage 	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
27618e60939SNelson Elhage 		if (errno == EPERM)
27718e60939SNelson Elhage 			die("Permission error mapping pages.\n"
27818e60939SNelson Elhage 			    "Consider increasing "
27918e60939SNelson Elhage 			    "/proc/sys/kernel/perf_event_mlock_kb,\n"
28018e60939SNelson Elhage 			    "or try again with a smaller value of -m/--mmap_pages.\n"
28118e60939SNelson Elhage 			    "(current value: %d)\n", opts->mmap_pages);
282*41d0d933SNelson Elhage 		else if (!is_power_of_2(opts->mmap_pages))
283*41d0d933SNelson Elhage 			die("--mmap_pages/-m value must be a power of two.");
284*41d0d933SNelson Elhage 
2850a27d7f9SArnaldo Carvalho de Melo 		die("failed to mmap with %d (%s)\n", errno, strerror(errno));
28618e60939SNelson Elhage 	}
2870a27d7f9SArnaldo Carvalho de Melo 
288d20deb64SArnaldo Carvalho de Melo 	if (rec->file_new)
289a91e5431SArnaldo Carvalho de Melo 		session->evlist = evlist;
290a91e5431SArnaldo Carvalho de Melo 	else {
291a91e5431SArnaldo Carvalho de Melo 		if (!perf_evlist__equal(session->evlist, evlist)) {
292a91e5431SArnaldo Carvalho de Melo 			fprintf(stderr, "incompatible append\n");
293a91e5431SArnaldo Carvalho de Melo 			exit(-1);
294dd7927f4SArnaldo Carvalho de Melo 		}
29586470930SIngo Molnar  	}
29686470930SIngo Molnar 
297a91e5431SArnaldo Carvalho de Melo 	perf_session__update_sample_type(session);
298a91e5431SArnaldo Carvalho de Melo }
299a91e5431SArnaldo Carvalho de Melo 
300d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec)
3016122e4e4SArnaldo Carvalho de Melo {
302d20deb64SArnaldo Carvalho de Melo 	u64 size = lseek(rec->output, 0, SEEK_CUR);
3036122e4e4SArnaldo Carvalho de Melo 
3049f591fd7SArnaldo Carvalho de Melo 	if (size == 0)
3059f591fd7SArnaldo Carvalho de Melo 		return 0;
3069f591fd7SArnaldo Carvalho de Melo 
307d20deb64SArnaldo Carvalho de Melo 	rec->session->fd = rec->output;
308d20deb64SArnaldo Carvalho de Melo 	return __perf_session__process_events(rec->session, rec->post_processing_offset,
309d20deb64SArnaldo Carvalho de Melo 					      size - rec->post_processing_offset,
3106122e4e4SArnaldo Carvalho de Melo 					      size, &build_id__mark_dso_hit_ops);
3116122e4e4SArnaldo Carvalho de Melo }
3126122e4e4SArnaldo Carvalho de Melo 
313d20deb64SArnaldo Carvalho de Melo static void perf_record__exit(int status __used, void *arg)
314f5970550SPeter Zijlstra {
315d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = arg;
316f5970550SPeter Zijlstra 
317d20deb64SArnaldo Carvalho de Melo 	if (!rec->opts.pipe_output) {
318d20deb64SArnaldo Carvalho de Melo 		rec->session->header.data_size += rec->bytes_written;
319d20deb64SArnaldo Carvalho de Melo 
320d20deb64SArnaldo Carvalho de Melo 		if (!rec->no_buildid)
321d20deb64SArnaldo Carvalho de Melo 			process_buildids(rec);
322d20deb64SArnaldo Carvalho de Melo 		perf_session__write_header(rec->session, rec->evlist,
323d20deb64SArnaldo Carvalho de Melo 					   rec->output, true);
324d20deb64SArnaldo Carvalho de Melo 		perf_session__delete(rec->session);
325d20deb64SArnaldo Carvalho de Melo 		perf_evlist__delete(rec->evlist);
326d65a458bSArnaldo Carvalho de Melo 		symbol__exit();
327c7929e47STom Zanussi 	}
328f5970550SPeter Zijlstra }
329f5970550SPeter Zijlstra 
3308115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
331a1645ce1SZhang, Yanmin {
332a1645ce1SZhang, Yanmin 	int err;
33345694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = data;
334a1645ce1SZhang, Yanmin 
33523346f21SArnaldo Carvalho de Melo 	if (machine__is_host(machine))
336a1645ce1SZhang, Yanmin 		return;
337a1645ce1SZhang, Yanmin 
338a1645ce1SZhang, Yanmin 	/*
339a1645ce1SZhang, Yanmin 	 *As for guest kernel when processing subcommand record&report,
340a1645ce1SZhang, Yanmin 	 *we arrange module mmap prior to guest kernel mmap and trigger
341a1645ce1SZhang, Yanmin 	 *a preload dso because default guest module symbols are loaded
342a1645ce1SZhang, Yanmin 	 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
343a1645ce1SZhang, Yanmin 	 *method is used to avoid symbol missing when the first addr is
344a1645ce1SZhang, Yanmin 	 *in module instead of in guest kernel.
345a1645ce1SZhang, Yanmin 	 */
34645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
347743eb868SArnaldo Carvalho de Melo 					     machine);
348a1645ce1SZhang, Yanmin 	if (err < 0)
349a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
35023346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
351a1645ce1SZhang, Yanmin 
352a1645ce1SZhang, Yanmin 	/*
353a1645ce1SZhang, Yanmin 	 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
354a1645ce1SZhang, Yanmin 	 * have no _text sometimes.
355a1645ce1SZhang, Yanmin 	 */
35645694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
357743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
358a1645ce1SZhang, Yanmin 	if (err < 0)
35945694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
360743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
361a1645ce1SZhang, Yanmin 	if (err < 0)
362a1645ce1SZhang, Yanmin 		pr_err("Couldn't record guest kernel [%d]'s reference"
36323346f21SArnaldo Carvalho de Melo 		       " relocation symbol.\n", machine->pid);
364a1645ce1SZhang, Yanmin }
365a1645ce1SZhang, Yanmin 
36698402807SFrederic Weisbecker static struct perf_event_header finished_round_event = {
36798402807SFrederic Weisbecker 	.size = sizeof(struct perf_event_header),
36898402807SFrederic Weisbecker 	.type = PERF_RECORD_FINISHED_ROUND,
36998402807SFrederic Weisbecker };
37098402807SFrederic Weisbecker 
371d20deb64SArnaldo Carvalho de Melo static void perf_record__mmap_read_all(struct perf_record *rec)
37298402807SFrederic Weisbecker {
3730e2e63ddSPeter Zijlstra 	int i;
37498402807SFrederic Weisbecker 
375d20deb64SArnaldo Carvalho de Melo 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
376d20deb64SArnaldo Carvalho de Melo 		if (rec->evlist->mmap[i].base)
377d20deb64SArnaldo Carvalho de Melo 			perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
37898402807SFrederic Weisbecker 	}
37998402807SFrederic Weisbecker 
380d20deb64SArnaldo Carvalho de Melo 	if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
381d20deb64SArnaldo Carvalho de Melo 		write_output(rec, &finished_round_event, sizeof(finished_round_event));
38298402807SFrederic Weisbecker }
38398402807SFrederic Weisbecker 
384d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
38586470930SIngo Molnar {
38686470930SIngo Molnar 	struct stat st;
38786470930SIngo Molnar 	int flags;
388d20deb64SArnaldo Carvalho de Melo 	int err, output;
3898b412664SPeter Zijlstra 	unsigned long waking = 0;
39046be604bSZhang, Yanmin 	const bool forks = argc > 0;
39123346f21SArnaldo Carvalho de Melo 	struct machine *machine;
39245694aa7SArnaldo Carvalho de Melo 	struct perf_tool *tool = &rec->tool;
393d20deb64SArnaldo Carvalho de Melo 	struct perf_record_opts *opts = &rec->opts;
394d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list = rec->evlist;
395d20deb64SArnaldo Carvalho de Melo 	const char *output_name = rec->output_name;
396d20deb64SArnaldo Carvalho de Melo 	struct perf_session *session;
39786470930SIngo Molnar 
398d20deb64SArnaldo Carvalho de Melo 	rec->progname = argv[0];
39933e49ea7SAndi Kleen 
400d20deb64SArnaldo Carvalho de Melo 	rec->page_size = sysconf(_SC_PAGE_SIZE);
40186470930SIngo Molnar 
402d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__sig_exit, rec);
403f5970550SPeter Zijlstra 	signal(SIGCHLD, sig_handler);
404f5970550SPeter Zijlstra 	signal(SIGINT, sig_handler);
40518483b81SArnaldo Carvalho de Melo 	signal(SIGUSR1, sig_handler);
406f5970550SPeter Zijlstra 
407d7065adbSFranck Bui-Huu 	if (!output_name) {
408d7065adbSFranck Bui-Huu 		if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
409d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
410d7065adbSFranck Bui-Huu 		else
411d20deb64SArnaldo Carvalho de Melo 			rec->output_name = output_name = "perf.data";
412d7065adbSFranck Bui-Huu 	}
413d7065adbSFranck Bui-Huu 	if (output_name) {
414529870e3STom Zanussi 		if (!strcmp(output_name, "-"))
415d20deb64SArnaldo Carvalho de Melo 			opts->pipe_output = true;
416529870e3STom Zanussi 		else if (!stat(output_name, &st) && st.st_size) {
417d20deb64SArnaldo Carvalho de Melo 			if (rec->write_mode == WRITE_FORCE) {
418b38d3464SArnaldo Carvalho de Melo 				char oldname[PATH_MAX];
419b38d3464SArnaldo Carvalho de Melo 				snprintf(oldname, sizeof(oldname), "%s.old",
420b38d3464SArnaldo Carvalho de Melo 					 output_name);
421b38d3464SArnaldo Carvalho de Melo 				unlink(oldname);
422b38d3464SArnaldo Carvalho de Melo 				rename(output_name, oldname);
423b38d3464SArnaldo Carvalho de Melo 			}
424d20deb64SArnaldo Carvalho de Melo 		} else if (rec->write_mode == WRITE_APPEND) {
425d20deb64SArnaldo Carvalho de Melo 			rec->write_mode = WRITE_FORCE;
426266e0e21SPierre Habouzit 		}
427d7065adbSFranck Bui-Huu 	}
42886470930SIngo Molnar 
429f887f301SXiao Guangrong 	flags = O_CREAT|O_RDWR;
430d20deb64SArnaldo Carvalho de Melo 	if (rec->write_mode == WRITE_APPEND)
431d20deb64SArnaldo Carvalho de Melo 		rec->file_new = 0;
43286470930SIngo Molnar 	else
43386470930SIngo Molnar 		flags |= O_TRUNC;
43486470930SIngo Molnar 
435d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output)
436529870e3STom Zanussi 		output = STDOUT_FILENO;
437529870e3STom Zanussi 	else
43886470930SIngo Molnar 		output = open(output_name, flags, S_IRUSR | S_IWUSR);
43986470930SIngo Molnar 	if (output < 0) {
44086470930SIngo Molnar 		perror("failed to create output file");
44186470930SIngo Molnar 		exit(-1);
44286470930SIngo Molnar 	}
44386470930SIngo Molnar 
444d20deb64SArnaldo Carvalho de Melo 	rec->output = output;
445d20deb64SArnaldo Carvalho de Melo 
4467865e817SFrederic Weisbecker 	session = perf_session__new(output_name, O_WRONLY,
447d20deb64SArnaldo Carvalho de Melo 				    rec->write_mode == WRITE_FORCE, false, NULL);
44894c744b6SArnaldo Carvalho de Melo 	if (session == NULL) {
449a9a70bbcSArnaldo Carvalho de Melo 		pr_err("Not enough memory for reading perf file header\n");
450a9a70bbcSArnaldo Carvalho de Melo 		return -1;
451a9a70bbcSArnaldo Carvalho de Melo 	}
452a9a70bbcSArnaldo Carvalho de Melo 
453d20deb64SArnaldo Carvalho de Melo 	rec->session = session;
454d20deb64SArnaldo Carvalho de Melo 
455d20deb64SArnaldo Carvalho de Melo 	if (!rec->no_buildid)
456baa2f6ceSArnaldo Carvalho de Melo 		perf_header__set_feat(&session->header, HEADER_BUILD_ID);
457baa2f6ceSArnaldo Carvalho de Melo 
458d20deb64SArnaldo Carvalho de Melo 	if (!rec->file_new) {
459a91e5431SArnaldo Carvalho de Melo 		err = perf_session__read_header(session, output);
4604dc0a04bSArnaldo Carvalho de Melo 		if (err < 0)
46139d17dacSArnaldo Carvalho de Melo 			goto out_delete_session;
4624dc0a04bSArnaldo Carvalho de Melo 	}
4634dc0a04bSArnaldo Carvalho de Melo 
464361c99a6SArnaldo Carvalho de Melo 	if (have_tracepoints(&evsel_list->entries))
46594c744b6SArnaldo Carvalho de Melo 		perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
46603456a15SFrederic Weisbecker 
467fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_HOSTNAME);
468fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_OSRELEASE);
469fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_ARCH);
470fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPUDESC);
471fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_NRCPUS);
472fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
473fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CMDLINE);
474fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_VERSION);
475fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
476fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
477fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
478fbe96f29SStephane Eranian 	perf_header__set_feat(&session->header, HEADER_CPUID);
479fbe96f29SStephane Eranian 
480d4db3f16SArnaldo Carvalho de Melo 	if (forks) {
481d20deb64SArnaldo Carvalho de Melo 		err = perf_evlist__prepare_workload(evsel_list, opts, argv);
48235b9d88eSArnaldo Carvalho de Melo 		if (err < 0) {
48335b9d88eSArnaldo Carvalho de Melo 			pr_err("Couldn't run the workload!\n");
48435b9d88eSArnaldo Carvalho de Melo 			goto out_delete_session;
485856e9660SPeter Zijlstra 		}
486856e9660SPeter Zijlstra 	}
487856e9660SPeter Zijlstra 
488d20deb64SArnaldo Carvalho de Melo 	perf_record__open(rec);
48986470930SIngo Molnar 
490712a4b60SArnaldo Carvalho de Melo 	/*
491d20deb64SArnaldo Carvalho de Melo 	 * perf_session__delete(session) will be called at perf_record__exit()
492712a4b60SArnaldo Carvalho de Melo 	 */
493d20deb64SArnaldo Carvalho de Melo 	on_exit(perf_record__exit, rec);
494712a4b60SArnaldo Carvalho de Melo 
495d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
496529870e3STom Zanussi 		err = perf_header__write_pipe(output);
497529870e3STom Zanussi 		if (err < 0)
498529870e3STom Zanussi 			return err;
499d20deb64SArnaldo Carvalho de Melo 	} else if (rec->file_new) {
500a91e5431SArnaldo Carvalho de Melo 		err = perf_session__write_header(session, evsel_list,
501361c99a6SArnaldo Carvalho de Melo 						 output, false);
502d5eed904SArnaldo Carvalho de Melo 		if (err < 0)
503d5eed904SArnaldo Carvalho de Melo 			return err;
504d5eed904SArnaldo Carvalho de Melo 	}
5057c6a1c65SPeter Zijlstra 
506d20deb64SArnaldo Carvalho de Melo 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
5076122e4e4SArnaldo Carvalho de Melo 
508743eb868SArnaldo Carvalho de Melo 	machine = perf_session__find_host_machine(session);
509743eb868SArnaldo Carvalho de Melo 	if (!machine) {
510743eb868SArnaldo Carvalho de Melo 		pr_err("Couldn't find native kernel information.\n");
511743eb868SArnaldo Carvalho de Melo 		return -1;
512743eb868SArnaldo Carvalho de Melo 	}
513743eb868SArnaldo Carvalho de Melo 
514d20deb64SArnaldo Carvalho de Melo 	if (opts->pipe_output) {
51545694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_attrs(tool, session,
516a91e5431SArnaldo Carvalho de Melo 						   process_synthesized_event);
5172c46dbb5STom Zanussi 		if (err < 0) {
5182c46dbb5STom Zanussi 			pr_err("Couldn't synthesize attrs.\n");
5192c46dbb5STom Zanussi 			return err;
5202c46dbb5STom Zanussi 		}
521cd19a035STom Zanussi 
52245694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_event_types(tool, process_synthesized_event,
523743eb868SArnaldo Carvalho de Melo 							 machine);
524cd19a035STom Zanussi 		if (err < 0) {
525cd19a035STom Zanussi 			pr_err("Couldn't synthesize event_types.\n");
526cd19a035STom Zanussi 			return err;
527cd19a035STom Zanussi 		}
5289215545eSTom Zanussi 
529361c99a6SArnaldo Carvalho de Melo 		if (have_tracepoints(&evsel_list->entries)) {
53063e0c771STom Zanussi 			/*
53163e0c771STom Zanussi 			 * FIXME err <= 0 here actually means that
53263e0c771STom Zanussi 			 * there were no tracepoints so its not really
53363e0c771STom Zanussi 			 * an error, just that we don't need to
53463e0c771STom Zanussi 			 * synthesize anything.  We really have to
53563e0c771STom Zanussi 			 * return this more properly and also
53663e0c771STom Zanussi 			 * propagate errors that now are calling die()
53763e0c771STom Zanussi 			 */
53845694aa7SArnaldo Carvalho de Melo 			err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
539743eb868SArnaldo Carvalho de Melo 								  process_synthesized_event);
54063e0c771STom Zanussi 			if (err <= 0) {
54163e0c771STom Zanussi 				pr_err("Couldn't record tracing data.\n");
54263e0c771STom Zanussi 				return err;
54363e0c771STom Zanussi 			}
544d20deb64SArnaldo Carvalho de Melo 			advance_output(rec, err);
5452c46dbb5STom Zanussi 		}
54663e0c771STom Zanussi 	}
5472c46dbb5STom Zanussi 
54845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
549743eb868SArnaldo Carvalho de Melo 						 machine, "_text");
55070162138SArnaldo Carvalho de Melo 	if (err < 0)
55145694aa7SArnaldo Carvalho de Melo 		err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
552743eb868SArnaldo Carvalho de Melo 							 machine, "_stext");
553c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
554c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel reference relocation symbol\n"
555c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
556c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/kallsyms permission or run as root.\n");
55756b03f3cSArnaldo Carvalho de Melo 
55845694aa7SArnaldo Carvalho de Melo 	err = perf_event__synthesize_modules(tool, process_synthesized_event,
559743eb868SArnaldo Carvalho de Melo 					     machine);
560c1a3a4b9SArnaldo Carvalho de Melo 	if (err < 0)
561c1a3a4b9SArnaldo Carvalho de Melo 		pr_err("Couldn't record kernel module information.\n"
562c1a3a4b9SArnaldo Carvalho de Melo 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
563c1a3a4b9SArnaldo Carvalho de Melo 		       "Check /proc/modules permission or run as root.\n");
564c1a3a4b9SArnaldo Carvalho de Melo 
565a1645ce1SZhang, Yanmin 	if (perf_guest)
56645694aa7SArnaldo Carvalho de Melo 		perf_session__process_machines(session, tool,
5678115d60cSArnaldo Carvalho de Melo 					       perf_event__synthesize_guest_os);
568b7cece76SArnaldo Carvalho de Melo 
569d20deb64SArnaldo Carvalho de Melo 	if (!opts->system_wide)
57045694aa7SArnaldo Carvalho de Melo 		perf_event__synthesize_thread_map(tool, evsel_list->threads,
5718115d60cSArnaldo Carvalho de Melo 						  process_synthesized_event,
572743eb868SArnaldo Carvalho de Melo 						  machine);
573234fbbf5SArnaldo Carvalho de Melo 	else
57445694aa7SArnaldo Carvalho de Melo 		perf_event__synthesize_threads(tool, process_synthesized_event,
575743eb868SArnaldo Carvalho de Melo 					       machine);
5767c6a1c65SPeter Zijlstra 
577d20deb64SArnaldo Carvalho de Melo 	if (rec->realtime_prio) {
57886470930SIngo Molnar 		struct sched_param param;
57986470930SIngo Molnar 
580d20deb64SArnaldo Carvalho de Melo 		param.sched_priority = rec->realtime_prio;
58186470930SIngo Molnar 		if (sched_setscheduler(0, SCHED_FIFO, &param)) {
5826beba7adSArnaldo Carvalho de Melo 			pr_err("Could not set realtime priority.\n");
58386470930SIngo Molnar 			exit(-1);
58486470930SIngo Molnar 		}
58586470930SIngo Molnar 	}
58686470930SIngo Molnar 
587764e16a3SDavid Ahern 	perf_evlist__enable(evsel_list);
588764e16a3SDavid Ahern 
589856e9660SPeter Zijlstra 	/*
590856e9660SPeter Zijlstra 	 * Let the child rip
591856e9660SPeter Zijlstra 	 */
592d4db3f16SArnaldo Carvalho de Melo 	if (forks)
59335b9d88eSArnaldo Carvalho de Melo 		perf_evlist__start_workload(evsel_list);
594856e9660SPeter Zijlstra 
595649c48a9SPeter Zijlstra 	for (;;) {
596d20deb64SArnaldo Carvalho de Melo 		int hits = rec->samples;
59786470930SIngo Molnar 
598d20deb64SArnaldo Carvalho de Melo 		perf_record__mmap_read_all(rec);
59986470930SIngo Molnar 
600d20deb64SArnaldo Carvalho de Melo 		if (hits == rec->samples) {
601649c48a9SPeter Zijlstra 			if (done)
602649c48a9SPeter Zijlstra 				break;
6035c581041SArnaldo Carvalho de Melo 			err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
6048b412664SPeter Zijlstra 			waking++;
6058b412664SPeter Zijlstra 		}
6068b412664SPeter Zijlstra 
6074152ab37SArnaldo Carvalho de Melo 		if (done)
6084152ab37SArnaldo Carvalho de Melo 			perf_evlist__disable(evsel_list);
6098b412664SPeter Zijlstra 	}
6108b412664SPeter Zijlstra 
61118483b81SArnaldo Carvalho de Melo 	if (quiet || signr == SIGUSR1)
612b44308f5SArnaldo Carvalho de Melo 		return 0;
613b44308f5SArnaldo Carvalho de Melo 
6148b412664SPeter Zijlstra 	fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
61586470930SIngo Molnar 
61686470930SIngo Molnar 	/*
61786470930SIngo Molnar 	 * Approximate RIP event size: 24 bytes.
61886470930SIngo Molnar 	 */
61986470930SIngo Molnar 	fprintf(stderr,
6209486aa38SArnaldo Carvalho de Melo 		"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
621d20deb64SArnaldo Carvalho de Melo 		(double)rec->bytes_written / 1024.0 / 1024.0,
62286470930SIngo Molnar 		output_name,
623d20deb64SArnaldo Carvalho de Melo 		rec->bytes_written / 24);
62486470930SIngo Molnar 
62586470930SIngo Molnar 	return 0;
62639d17dacSArnaldo Carvalho de Melo 
62739d17dacSArnaldo Carvalho de Melo out_delete_session:
62839d17dacSArnaldo Carvalho de Melo 	perf_session__delete(session);
62939d17dacSArnaldo Carvalho de Melo 	return err;
63086470930SIngo Molnar }
63186470930SIngo Molnar 
63286470930SIngo Molnar static const char * const record_usage[] = {
63386470930SIngo Molnar 	"perf record [<options>] [<command>]",
63486470930SIngo Molnar 	"perf record [<options>] -- <command> [<options>]",
63586470930SIngo Molnar 	NULL
63686470930SIngo Molnar };
63786470930SIngo Molnar 
638d20deb64SArnaldo Carvalho de Melo /*
639d20deb64SArnaldo Carvalho de Melo  * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
640d20deb64SArnaldo Carvalho de Melo  * because we need to have access to it in perf_record__exit, that is called
641d20deb64SArnaldo Carvalho de Melo  * after cmd_record() exits, but since record_options need to be accessible to
642d20deb64SArnaldo Carvalho de Melo  * builtin-script, leave it here.
643d20deb64SArnaldo Carvalho de Melo  *
644d20deb64SArnaldo Carvalho de Melo  * At least we don't ouch it in all the other functions here directly.
645d20deb64SArnaldo Carvalho de Melo  *
646d20deb64SArnaldo Carvalho de Melo  * Just say no to tons of global variables, sigh.
647d20deb64SArnaldo Carvalho de Melo  */
648d20deb64SArnaldo Carvalho de Melo static struct perf_record record = {
649d20deb64SArnaldo Carvalho de Melo 	.opts = {
650d20deb64SArnaldo Carvalho de Melo 		.target_pid	     = -1,
651d20deb64SArnaldo Carvalho de Melo 		.target_tid	     = -1,
652d20deb64SArnaldo Carvalho de Melo 		.mmap_pages	     = UINT_MAX,
653d20deb64SArnaldo Carvalho de Melo 		.user_freq	     = UINT_MAX,
654d20deb64SArnaldo Carvalho de Melo 		.user_interval	     = ULLONG_MAX,
655d20deb64SArnaldo Carvalho de Melo 		.freq		     = 1000,
656d20deb64SArnaldo Carvalho de Melo 		.sample_id_all_avail = true,
657d20deb64SArnaldo Carvalho de Melo 	},
658d20deb64SArnaldo Carvalho de Melo 	.write_mode = WRITE_FORCE,
659d20deb64SArnaldo Carvalho de Melo 	.file_new   = true,
660d20deb64SArnaldo Carvalho de Melo };
6617865e817SFrederic Weisbecker 
662d20deb64SArnaldo Carvalho de Melo /*
663d20deb64SArnaldo Carvalho de Melo  * XXX Will stay a global variable till we fix builtin-script.c to stop messing
664d20deb64SArnaldo Carvalho de Melo  * with it and switch to use the library functions in perf_evlist that came
665d20deb64SArnaldo Carvalho de Melo  * from builtin-record.c, i.e. use perf_record_opts,
666d20deb64SArnaldo Carvalho de Melo  * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
667d20deb64SArnaldo Carvalho de Melo  * using pipes, etc.
668d20deb64SArnaldo Carvalho de Melo  */
669bca647aaSTom Zanussi const struct option record_options[] = {
670d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('e', "event", &record.evlist, "event",
67186470930SIngo Molnar 		     "event selector. use 'perf list' to list available events",
672f120f9d5SJiri Olsa 		     parse_events_option),
673d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK(0, "filter", &record.evlist, "filter",
674c171b552SLi Zefan 		     "event filter", parse_filter),
675d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('p', "pid", &record.opts.target_pid,
676d6d901c2SZhang, Yanmin 		    "record events on existing process id"),
677d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('t', "tid", &record.opts.target_tid,
678d6d901c2SZhang, Yanmin 		    "record events on existing thread id"),
679d20deb64SArnaldo Carvalho de Melo 	OPT_INTEGER('r', "realtime", &record.realtime_prio,
68086470930SIngo Molnar 		    "collect data with this RT SCHED_FIFO priority"),
681d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
682acac03faSKirill Smelkov 		    "collect data without buffering"),
683d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
684daac07b2SFrederic Weisbecker 		    "collect raw sample records from all opened counters"),
685d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
68686470930SIngo Molnar 			    "system-wide collection from all CPUs"),
687d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('A', "append", &record.append_file,
68886470930SIngo Molnar 			    "append to the output file to do incremental profiling"),
689d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
690c45c6ea2SStephane Eranian 		    "list of cpus to monitor"),
691d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('f', "force", &record.force,
6927865e817SFrederic Weisbecker 			"overwrite existing data file (deprecated)"),
693d20deb64SArnaldo Carvalho de Melo 	OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
694d20deb64SArnaldo Carvalho de Melo 	OPT_STRING('o', "output", &record.output_name, "file",
69586470930SIngo Molnar 		    "output file name"),
696d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
6972e6cdf99SStephane Eranian 		    "child tasks do not inherit counters"),
698d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
699d20deb64SArnaldo Carvalho de Melo 	OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
70001c2d99bSArnaldo Carvalho de Melo 		     "number of mmap data pages"),
701d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN(0, "group", &record.opts.group,
70243bece79SLin Ming 		    "put the counters into a counter group"),
703d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
7043efa1cc9SIngo Molnar 		    "do call-graph (stack chain/backtrace) recording"),
705c0555642SIan Munsie 	OPT_INCR('v', "verbose", &verbose,
7063da297a6SIngo Molnar 		    "be more verbose (show counter open errors, etc)"),
707b44308f5SArnaldo Carvalho de Melo 	OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
708d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
709649c48a9SPeter Zijlstra 		    "per thread counts"),
710d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('d', "data", &record.opts.sample_address,
7114bba828dSAnton Blanchard 		    "Sample addresses"),
712d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
7133e76ac78SAndrew Vagin 	OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
714d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
715649c48a9SPeter Zijlstra 		    "don't sample"),
716d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
717a1ac1d3cSStephane Eranian 		    "do not update the buildid cache"),
718d20deb64SArnaldo Carvalho de Melo 	OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
719baa2f6ceSArnaldo Carvalho de Melo 		    "do not collect buildids in perf.data"),
720d20deb64SArnaldo Carvalho de Melo 	OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
721023695d9SStephane Eranian 		     "monitor event in cgroup name only",
722023695d9SStephane Eranian 		     parse_cgroups),
72386470930SIngo Molnar 	OPT_END()
72486470930SIngo Molnar };
72586470930SIngo Molnar 
726f37a291cSIngo Molnar int cmd_record(int argc, const char **argv, const char *prefix __used)
72786470930SIngo Molnar {
72869aad6f1SArnaldo Carvalho de Melo 	int err = -ENOMEM;
72969aad6f1SArnaldo Carvalho de Melo 	struct perf_evsel *pos;
730d20deb64SArnaldo Carvalho de Melo 	struct perf_evlist *evsel_list;
731d20deb64SArnaldo Carvalho de Melo 	struct perf_record *rec = &record;
73286470930SIngo Molnar 
733fbe96f29SStephane Eranian 	perf_header__set_cmdline(argc, argv);
734fbe96f29SStephane Eranian 
7357e2ed097SArnaldo Carvalho de Melo 	evsel_list = perf_evlist__new(NULL, NULL);
736361c99a6SArnaldo Carvalho de Melo 	if (evsel_list == NULL)
737361c99a6SArnaldo Carvalho de Melo 		return -ENOMEM;
738361c99a6SArnaldo Carvalho de Melo 
739d20deb64SArnaldo Carvalho de Melo 	rec->evlist = evsel_list;
740d20deb64SArnaldo Carvalho de Melo 
741bca647aaSTom Zanussi 	argc = parse_options(argc, argv, record_options, record_usage,
742a0541234SAnton Blanchard 			    PARSE_OPT_STOP_AT_NON_OPTION);
743d20deb64SArnaldo Carvalho de Melo 	if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
744d20deb64SArnaldo Carvalho de Melo 		!rec->opts.system_wide && !rec->opts.cpu_list)
745bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
74686470930SIngo Molnar 
747d20deb64SArnaldo Carvalho de Melo 	if (rec->force && rec->append_file) {
7487865e817SFrederic Weisbecker 		fprintf(stderr, "Can't overwrite and append at the same time."
7497865e817SFrederic Weisbecker 				" You need to choose between -f and -A");
750bca647aaSTom Zanussi 		usage_with_options(record_usage, record_options);
751d20deb64SArnaldo Carvalho de Melo 	} else if (rec->append_file) {
752d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_APPEND;
7537865e817SFrederic Weisbecker 	} else {
754d20deb64SArnaldo Carvalho de Melo 		rec->write_mode = WRITE_FORCE;
7557865e817SFrederic Weisbecker 	}
7567865e817SFrederic Weisbecker 
757d20deb64SArnaldo Carvalho de Melo 	if (nr_cgroups && !rec->opts.system_wide) {
758023695d9SStephane Eranian 		fprintf(stderr, "cgroup monitoring only available in"
759023695d9SStephane Eranian 			" system-wide mode\n");
760023695d9SStephane Eranian 		usage_with_options(record_usage, record_options);
761023695d9SStephane Eranian 	}
762023695d9SStephane Eranian 
763655000e7SArnaldo Carvalho de Melo 	symbol__init();
764baa2f6ceSArnaldo Carvalho de Melo 
765ec80fde7SArnaldo Carvalho de Melo 	if (symbol_conf.kptr_restrict)
766646aaea6SArnaldo Carvalho de Melo 		pr_warning(
767646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
768ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n"
769646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
770646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n"
771646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n"
772646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
773646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n");
774ec80fde7SArnaldo Carvalho de Melo 
775d20deb64SArnaldo Carvalho de Melo 	if (rec->no_buildid_cache || rec->no_buildid)
776a1ac1d3cSStephane Eranian 		disable_buildid_cache();
777655000e7SArnaldo Carvalho de Melo 
778361c99a6SArnaldo Carvalho de Melo 	if (evsel_list->nr_entries == 0 &&
779361c99a6SArnaldo Carvalho de Melo 	    perf_evlist__add_default(evsel_list) < 0) {
78069aad6f1SArnaldo Carvalho de Melo 		pr_err("Not enough memory for event selector list\n");
78169aad6f1SArnaldo Carvalho de Melo 		goto out_symbol_exit;
782bbd36e5eSPeter Zijlstra 	}
78386470930SIngo Molnar 
784d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.target_pid != -1)
785d20deb64SArnaldo Carvalho de Melo 		rec->opts.target_tid = rec->opts.target_pid;
786d6d901c2SZhang, Yanmin 
787d20deb64SArnaldo Carvalho de Melo 	if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
788d20deb64SArnaldo Carvalho de Melo 				     rec->opts.target_tid, rec->opts.cpu_list) < 0)
789dd7927f4SArnaldo Carvalho de Melo 		usage_with_options(record_usage, record_options);
79069aad6f1SArnaldo Carvalho de Melo 
791361c99a6SArnaldo Carvalho de Melo 	list_for_each_entry(pos, &evsel_list->entries, node) {
792ad7f4e3fSArnaldo Carvalho de Melo 		if (perf_header__push_event(pos->attr.config, event_name(pos)))
793ad7f4e3fSArnaldo Carvalho de Melo 			goto out_free_fd;
794d6d901c2SZhang, Yanmin 	}
7955c581041SArnaldo Carvalho de Melo 
796d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_interval != ULLONG_MAX)
797d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.user_interval;
798d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.user_freq != UINT_MAX)
799d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = rec->opts.user_freq;
800f9212819SFrederic Weisbecker 
8017e4ff9e3SMike Galbraith 	/*
8027e4ff9e3SMike Galbraith 	 * User specified count overrides default frequency.
8037e4ff9e3SMike Galbraith 	 */
804d20deb64SArnaldo Carvalho de Melo 	if (rec->opts.default_interval)
805d20deb64SArnaldo Carvalho de Melo 		rec->opts.freq = 0;
806d20deb64SArnaldo Carvalho de Melo 	else if (rec->opts.freq) {
807d20deb64SArnaldo Carvalho de Melo 		rec->opts.default_interval = rec->opts.freq;
8087e4ff9e3SMike Galbraith 	} else {
8097e4ff9e3SMike Galbraith 		fprintf(stderr, "frequency and count are zero, aborting\n");
81039d17dacSArnaldo Carvalho de Melo 		err = -EINVAL;
8115c581041SArnaldo Carvalho de Melo 		goto out_free_fd;
8127e4ff9e3SMike Galbraith 	}
8137e4ff9e3SMike Galbraith 
814d20deb64SArnaldo Carvalho de Melo 	err = __cmd_record(&record, argc, argv);
81539d17dacSArnaldo Carvalho de Melo out_free_fd:
8167e2ed097SArnaldo Carvalho de Melo 	perf_evlist__delete_maps(evsel_list);
817d65a458bSArnaldo Carvalho de Melo out_symbol_exit:
818d65a458bSArnaldo Carvalho de Melo 	symbol__exit();
81939d17dacSArnaldo Carvalho de Melo 	return err;
82086470930SIngo Molnar }
821