blob: 2990570b5c6d8923fa02422883af1e540dcd5d7f [file] [log] [blame]
Ingo Molnarabaff322009-06-02 22:59:57 +02001/*
Ingo Molnarbf9e1872009-06-02 23:37:05 +02002 * builtin-record.c
3 *
4 * Builtin record command: Record the profile of a workload
5 * (or a CPU, or a PID) into the perf.data output file - for
6 * later analysis via perf report.
Ingo Molnarabaff322009-06-02 22:59:57 +02007 */
Ingo Molnar16f762a2009-05-27 09:10:38 +02008#include "builtin.h"
Ingo Molnarbf9e1872009-06-02 23:37:05 +02009
10#include "perf.h"
11
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -020012#include "util/build-id.h"
Thomas Gleixner6eda5832009-05-01 18:29:57 +020013#include "util/util.h"
Ingo Molnar0e9b20b2009-05-26 09:17:18 +020014#include "util/parse-options.h"
Ingo Molnar8ad8db32009-05-26 11:10:09 +020015#include "util/parse-events.h"
Thomas Gleixner6eda5832009-05-01 18:29:57 +020016
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020017#include "util/header.h"
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020018#include "util/event.h"
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -020019#include "util/evlist.h"
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -020020#include "util/evsel.h"
Frederic Weisbecker8f288272009-08-16 22:05:48 +020021#include "util/debug.h"
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020022#include "util/session.h"
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020023#include "util/tool.h"
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -020024#include "util/symbol.h"
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110025#include "util/cpumap.h"
Arnaldo Carvalho de Melofd782602011-01-18 15:15:24 -020026#include "util/thread_map.h"
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020027
Peter Zijlstra97124d5e2009-06-02 15:52:24 +020028#include <unistd.h>
Peter Zijlstrade9ac072009-04-08 15:01:31 +020029#include <sched.h>
Arnaldo Carvalho de Meloa41794c2010-05-18 18:29:23 -030030#include <sys/mman.h>
Peter Zijlstrade9ac072009-04-08 15:01:31 +020031
Bernhard Rosenkraenzer78da39f2012-10-08 09:43:26 +030032#ifndef HAVE_ON_EXIT
33#ifndef ATEXIT_MAX
34#define ATEXIT_MAX 32
35#endif
36static int __on_exit_count = 0;
37typedef void (*on_exit_func_t) (int, void *);
38static on_exit_func_t __on_exit_funcs[ATEXIT_MAX];
39static void *__on_exit_args[ATEXIT_MAX];
40static int __exitcode = 0;
41static void __handle_on_exit_funcs(void);
42static int on_exit(on_exit_func_t function, void *arg);
43#define exit(x) (exit)(__exitcode = (x))
44
45static int on_exit(on_exit_func_t function, void *arg)
46{
47 if (__on_exit_count == ATEXIT_MAX)
48 return -ENOMEM;
49 else if (__on_exit_count == 0)
50 atexit(__handle_on_exit_funcs);
51 __on_exit_funcs[__on_exit_count] = function;
52 __on_exit_args[__on_exit_count++] = arg;
53 return 0;
54}
55
56static void __handle_on_exit_funcs(void)
57{
58 int i;
59 for (i = 0; i < __on_exit_count; i++)
60 __on_exit_funcs[i] (__exitcode, __on_exit_args[i]);
61}
62#endif
63
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020064struct perf_record {
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020065 struct perf_tool tool;
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020066 struct perf_record_opts opts;
67 u64 bytes_written;
68 const char *output_name;
69 struct perf_evlist *evlist;
70 struct perf_session *session;
71 const char *progname;
72 int output;
73 unsigned int page_size;
74 int realtime_prio;
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020075 bool no_buildid;
76 bool no_buildid_cache;
77 bool force;
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020078 long samples;
79 off_t post_processing_offset;
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -020080};
Ingo Molnara21ca2c2009-06-06 09:58:57 +020081
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020082static void advance_output(struct perf_record *rec, size_t size)
Tom Zanussi92155452010-04-01 23:59:21 -050083{
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020084 rec->bytes_written += size;
Tom Zanussi92155452010-04-01 23:59:21 -050085}
86
David Ahern8d3eca22012-08-26 12:24:47 -060087static int write_output(struct perf_record *rec, void *buf, size_t size)
Peter Zijlstraf5970552009-06-18 23:22:55 +020088{
89 while (size) {
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020090 int ret = write(rec->output, buf, size);
Peter Zijlstraf5970552009-06-18 23:22:55 +020091
David Ahern8d3eca22012-08-26 12:24:47 -060092 if (ret < 0) {
93 pr_err("failed to write\n");
94 return -1;
95 }
Peter Zijlstraf5970552009-06-18 23:22:55 +020096
97 size -= ret;
98 buf += ret;
99
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200100 rec->bytes_written += ret;
Peter Zijlstraf5970552009-06-18 23:22:55 +0200101 }
David Ahern8d3eca22012-08-26 12:24:47 -0600102
103 return 0;
Peter Zijlstraf5970552009-06-18 23:22:55 +0200104}
105
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200106static int process_synthesized_event(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200107 union perf_event *event,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300108 struct perf_sample *sample __maybe_unused,
109 struct machine *machine __maybe_unused)
Arnaldo Carvalho de Melo234fbbf2009-10-26 19:23:18 -0200110{
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200111 struct perf_record *rec = container_of(tool, struct perf_record, tool);
David Ahern8d3eca22012-08-26 12:24:47 -0600112 if (write_output(rec, event, event->header.size) < 0)
113 return -1;
114
Arnaldo Carvalho de Melo234fbbf2009-10-26 19:23:18 -0200115 return 0;
116}
117
David Ahern8d3eca22012-08-26 12:24:47 -0600118static int perf_record__mmap_read(struct perf_record *rec,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200119 struct perf_mmap *md)
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200120{
Arnaldo Carvalho de Melo744bd8a2011-01-12 17:07:28 -0200121 unsigned int head = perf_mmap__read_head(md);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200122 unsigned int old = md->prev;
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200123 unsigned char *data = md->base + rec->page_size;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200124 unsigned long size;
125 void *buf;
David Ahern8d3eca22012-08-26 12:24:47 -0600126 int rc = 0;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200127
Arnaldo Carvalho de Melodc820092011-01-28 14:49:19 -0200128 if (old == head)
David Ahern8d3eca22012-08-26 12:24:47 -0600129 return 0;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200130
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200131 rec->samples++;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200132
133 size = head - old;
134
135 if ((old & md->mask) + size != (head & md->mask)) {
136 buf = &data[old & md->mask];
137 size = md->mask + 1 - (old & md->mask);
138 old += size;
Ingo Molnar021e9f42009-06-03 19:27:19 +0200139
David Ahern8d3eca22012-08-26 12:24:47 -0600140 if (write_output(rec, buf, size) < 0) {
141 rc = -1;
142 goto out;
143 }
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200144 }
145
146 buf = &data[old & md->mask];
147 size = head - old;
148 old += size;
Ingo Molnar021e9f42009-06-03 19:27:19 +0200149
David Ahern8d3eca22012-08-26 12:24:47 -0600150 if (write_output(rec, buf, size) < 0) {
151 rc = -1;
152 goto out;
153 }
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200154
155 md->prev = old;
Arnaldo Carvalho de Melo115d2d82011-01-12 17:11:53 -0200156 perf_mmap__write_tail(md, old);
David Ahern8d3eca22012-08-26 12:24:47 -0600157
158out:
159 return rc;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200160}
161
162static volatile int done = 0;
Peter Zijlstraf7b7c262009-06-10 15:55:59 +0200163static volatile int signr = -1;
Andi Kleen33e49ea2011-09-15 14:31:40 -0700164static volatile int child_finished = 0;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200165
Peter Zijlstra16c8a102009-05-05 17:50:27 +0200166static void sig_handler(int sig)
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200167{
Andi Kleen33e49ea2011-09-15 14:31:40 -0700168 if (sig == SIGCHLD)
169 child_finished = 1;
170
Peter Zijlstra16c8a102009-05-05 17:50:27 +0200171 done = 1;
Peter Zijlstraf7b7c262009-06-10 15:55:59 +0200172 signr = sig;
173}
174
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300175static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
Peter Zijlstraf7b7c262009-06-10 15:55:59 +0200176{
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200177 struct perf_record *rec = arg;
Andi Kleen33e49ea2011-09-15 14:31:40 -0700178 int status;
179
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200180 if (rec->evlist->workload.pid > 0) {
Andi Kleen33e49ea2011-09-15 14:31:40 -0700181 if (!child_finished)
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200182 kill(rec->evlist->workload.pid, SIGTERM);
Andi Kleen33e49ea2011-09-15 14:31:40 -0700183
184 wait(&status);
185 if (WIFSIGNALED(status))
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200186 psignal(WTERMSIG(status), rec->progname);
Andi Kleen33e49ea2011-09-15 14:31:40 -0700187 }
Chris Wilson933da832009-10-04 01:35:01 +0100188
Arnaldo Carvalho de Melo18483b82010-12-06 15:13:38 -0200189 if (signr == -1 || signr == SIGUSR1)
Peter Zijlstraf7b7c262009-06-10 15:55:59 +0200190 return;
191
192 signal(signr, SIG_DFL);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200193}
194
David Ahern8d3eca22012-08-26 12:24:47 -0600195static int perf_record__open(struct perf_record *rec)
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200196{
Arnaldo Carvalho de Melo56e52e82012-12-13 15:10:58 -0300197 char msg[512];
Jiri Olsa6a4bb042012-08-08 12:22:36 +0200198 struct perf_evsel *pos;
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200199 struct perf_evlist *evlist = rec->evlist;
200 struct perf_session *session = rec->session;
201 struct perf_record_opts *opts = &rec->opts;
David Ahern8d3eca22012-08-26 12:24:47 -0600202 int rc = 0;
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200203
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -0300204 perf_evlist__config(evlist, opts);
Jiri Olsacac21422012-11-12 18:34:00 +0100205
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200206 list_for_each_entry(pos, &evlist->entries, node) {
Ingo Molnar3da297a2009-06-07 17:39:02 +0200207try_again:
Jiri Olsa6a4bb042012-08-08 12:22:36 +0200208 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
Arnaldo Carvalho de Melo56e52e82012-12-13 15:10:58 -0300209 if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300210 if (verbose)
Arnaldo Carvalho de Meloc0a54342012-12-13 14:16:30 -0300211 ui__warning("%s\n", msg);
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300212 goto try_again;
213 }
David Ahernca6a4252011-03-25 13:11:11 -0600214
Arnaldo Carvalho de Melo56e52e82012-12-13 15:10:58 -0300215 rc = -errno;
216 perf_evsel__open_strerror(pos, &opts->target,
217 errno, msg, sizeof(msg));
218 ui__error("%s\n", msg);
David Ahern8d3eca22012-08-26 12:24:47 -0600219 goto out;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300220 }
Li Zefanc171b552009-10-15 11:22:07 +0800221 }
Arnaldo Carvalho de Meloa43d3f02010-12-25 12:12:25 -0200222
Arnaldo Carvalho de Melo1491a632012-09-26 14:43:13 -0300223 if (perf_evlist__apply_filters(evlist)) {
Frederic Weisbecker0a102472011-02-26 04:51:54 +0100224 error("failed to set filter with %d (%s)\n", errno,
225 strerror(errno));
David Ahern8d3eca22012-08-26 12:24:47 -0600226 rc = -1;
227 goto out;
Frederic Weisbecker0a102472011-02-26 04:51:54 +0100228 }
229
Nelson Elhage18e60932011-12-19 08:39:31 -0500230 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
David Ahern8d3eca22012-08-26 12:24:47 -0600231 if (errno == EPERM) {
232 pr_err("Permission error mapping pages.\n"
233 "Consider increasing "
234 "/proc/sys/kernel/perf_event_mlock_kb,\n"
235 "or try again with a smaller value of -m/--mmap_pages.\n"
236 "(current value: %d)\n", opts->mmap_pages);
237 rc = -errno;
Jiri Olsa0089fa92012-10-20 16:33:19 +0200238 } else if (!is_power_of_2(opts->mmap_pages) &&
239 (opts->mmap_pages != UINT_MAX)) {
David Ahern8d3eca22012-08-26 12:24:47 -0600240 pr_err("--mmap_pages/-m value must be a power of two.");
241 rc = -EINVAL;
242 } else {
243 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
244 rc = -errno;
245 }
246 goto out;
Nelson Elhage18e60932011-12-19 08:39:31 -0500247 }
Arnaldo Carvalho de Melo0a27d7f2011-01-14 15:50:51 -0200248
Jiri Olsa563aecb2013-06-05 13:35:06 +0200249 session->evlist = evlist;
Arnaldo Carvalho de Melo7b56cce2012-08-01 19:31:00 -0300250 perf_session__set_id_hdr_size(session);
David Ahern8d3eca22012-08-26 12:24:47 -0600251out:
252 return rc;
Peter Zijlstra16c8a102009-05-05 17:50:27 +0200253}
254
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200255static int process_buildids(struct perf_record *rec)
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200256{
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200257 u64 size = lseek(rec->output, 0, SEEK_CUR);
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200258
Arnaldo Carvalho de Melo9f591fd2010-03-11 15:53:11 -0300259 if (size == 0)
260 return 0;
261
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200262 rec->session->fd = rec->output;
263 return __perf_session__process_events(rec->session, rec->post_processing_offset,
264 size - rec->post_processing_offset,
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200265 size, &build_id__mark_dso_hit_ops);
266}
267
David Ahern8d3eca22012-08-26 12:24:47 -0600268static void perf_record__exit(int status, void *arg)
Peter Zijlstraf5970552009-06-18 23:22:55 +0200269{
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200270 struct perf_record *rec = arg;
Peter Zijlstraf5970552009-06-18 23:22:55 +0200271
David Ahern8d3eca22012-08-26 12:24:47 -0600272 if (status != 0)
273 return;
274
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200275 if (!rec->opts.pipe_output) {
276 rec->session->header.data_size += rec->bytes_written;
277
278 if (!rec->no_buildid)
279 process_buildids(rec);
280 perf_session__write_header(rec->session, rec->evlist,
281 rec->output, true);
282 perf_session__delete(rec->session);
283 perf_evlist__delete(rec->evlist);
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -0300284 symbol__exit();
Tom Zanussic7929e42010-04-01 23:59:22 -0500285 }
Peter Zijlstraf5970552009-06-18 23:22:55 +0200286}
287
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200288static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800289{
290 int err;
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200291 struct perf_tool *tool = data;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800292 /*
293 *As for guest kernel when processing subcommand record&report,
294 *we arrange module mmap prior to guest kernel mmap and trigger
295 *a preload dso because default guest module symbols are loaded
296 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
297 *method is used to avoid symbol missing when the first addr is
298 *in module instead of in guest kernel.
299 */
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200300 err = perf_event__synthesize_modules(tool, process_synthesized_event,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200301 machine);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800302 if (err < 0)
303 pr_err("Couldn't record guest kernel [%d]'s reference"
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300304 " relocation symbol.\n", machine->pid);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800305
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800306 /*
307 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
308 * have no _text sometimes.
309 */
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200310 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200311 machine, "_text");
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800312 if (err < 0)
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200313 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200314 machine, "_stext");
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800315 if (err < 0)
316 pr_err("Couldn't record guest kernel [%d]'s reference"
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300317 " relocation symbol.\n", machine->pid);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800318}
319
Frederic Weisbecker98402802010-05-02 22:05:29 +0200320static struct perf_event_header finished_round_event = {
321 .size = sizeof(struct perf_event_header),
322 .type = PERF_RECORD_FINISHED_ROUND,
323};
324
David Ahern8d3eca22012-08-26 12:24:47 -0600325static int perf_record__mmap_read_all(struct perf_record *rec)
Frederic Weisbecker98402802010-05-02 22:05:29 +0200326{
Peter Zijlstra0e2e63d2010-05-20 14:45:26 +0200327 int i;
David Ahern8d3eca22012-08-26 12:24:47 -0600328 int rc = 0;
Frederic Weisbecker98402802010-05-02 22:05:29 +0200329
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200330 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
David Ahern8d3eca22012-08-26 12:24:47 -0600331 if (rec->evlist->mmap[i].base) {
332 if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
333 rc = -1;
334 goto out;
335 }
336 }
Frederic Weisbecker98402802010-05-02 22:05:29 +0200337 }
338
Stephane Eranian2eeaaa02012-05-15 13:28:13 +0200339 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
David Ahern8d3eca22012-08-26 12:24:47 -0600340 rc = write_output(rec, &finished_round_event,
341 sizeof(finished_round_event));
342
343out:
344 return rc;
Frederic Weisbecker98402802010-05-02 22:05:29 +0200345}
346
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200347static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
Peter Zijlstra16c8a102009-05-05 17:50:27 +0200348{
Peter Zijlstra97124d5e2009-06-02 15:52:24 +0200349 struct stat st;
Ingo Molnarabaff322009-06-02 22:59:57 +0200350 int flags;
Robert Richter781ba9d2011-12-15 17:32:40 +0100351 int err, output, feat;
Peter Zijlstra8b412662009-09-17 19:59:05 +0200352 unsigned long waking = 0;
Zhang, Yanmin46be6042010-03-18 11:36:04 -0300353 const bool forks = argc > 0;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300354 struct machine *machine;
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200355 struct perf_tool *tool = &rec->tool;
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200356 struct perf_record_opts *opts = &rec->opts;
357 struct perf_evlist *evsel_list = rec->evlist;
358 const char *output_name = rec->output_name;
359 struct perf_session *session;
Jiri Olsa27119262012-11-12 18:34:02 +0100360 bool disabled = false;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200361
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200362 rec->progname = argv[0];
Andi Kleen33e49ea2011-09-15 14:31:40 -0700363
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200364 rec->page_size = sysconf(_SC_PAGE_SIZE);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200365
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200366 on_exit(perf_record__sig_exit, rec);
Peter Zijlstraf5970552009-06-18 23:22:55 +0200367 signal(SIGCHLD, sig_handler);
368 signal(SIGINT, sig_handler);
Arnaldo Carvalho de Melo18483b82010-12-06 15:13:38 -0200369 signal(SIGUSR1, sig_handler);
David Ahern804f7ac2013-05-06 12:24:23 -0600370 signal(SIGTERM, sig_handler);
Peter Zijlstraf5970552009-06-18 23:22:55 +0200371
Franck Bui-Huud7065ad2011-01-16 17:14:45 +0100372 if (!output_name) {
373 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200374 opts->pipe_output = true;
Franck Bui-Huud7065ad2011-01-16 17:14:45 +0100375 else
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200376 rec->output_name = output_name = "perf.data";
Franck Bui-Huud7065ad2011-01-16 17:14:45 +0100377 }
378 if (output_name) {
379 if (!strcmp(output_name, "-"))
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200380 opts->pipe_output = true;
Franck Bui-Huud7065ad2011-01-16 17:14:45 +0100381 else if (!stat(output_name, &st) && st.st_size) {
Jiri Olsa563aecb2013-06-05 13:35:06 +0200382 char oldname[PATH_MAX];
383 snprintf(oldname, sizeof(oldname), "%s.old",
384 output_name);
385 unlink(oldname);
386 rename(output_name, oldname);
Pierre Habouzit266e0e22009-08-07 14:16:01 +0200387 }
Peter Zijlstra97124d5e2009-06-02 15:52:24 +0200388 }
389
Jiri Olsa563aecb2013-06-05 13:35:06 +0200390 flags = O_CREAT|O_RDWR|O_TRUNC;
Ingo Molnarabaff322009-06-02 22:59:57 +0200391
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200392 if (opts->pipe_output)
Tom Zanussi529870e2010-04-01 23:59:16 -0500393 output = STDOUT_FILENO;
394 else
395 output = open(output_name, flags, S_IRUSR | S_IWUSR);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200396 if (output < 0) {
397 perror("failed to create output file");
David Ahern8d3eca22012-08-26 12:24:47 -0600398 return -1;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200399 }
400
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200401 rec->output = output;
402
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200403 session = perf_session__new(output_name, O_WRONLY,
Jiri Olsa563aecb2013-06-05 13:35:06 +0200404 true, false, NULL);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200405 if (session == NULL) {
Arnaldo Carvalho de Meloa9a70bb2009-11-17 01:18:11 -0200406 pr_err("Not enough memory for reading perf file header\n");
407 return -1;
408 }
409
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200410 rec->session = session;
411
Robert Richter781ba9d2011-12-15 17:32:40 +0100412 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
413 perf_header__set_feat(&session->header, feat);
414
415 if (rec->no_buildid)
416 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
417
418 if (!have_tracepoints(&evsel_list->entries))
Stephane Eranian2eeaaa02012-05-15 13:28:13 +0200419 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200420
Stephane Eranian330aa672012-03-08 23:47:46 +0100421 if (!rec->opts.branch_stack)
422 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
423
Arnaldo Carvalho de Melod4db3f12009-12-27 21:36:57 -0200424 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +0900425 err = perf_evlist__prepare_workload(evsel_list, &opts->target,
Namhyung Kim55e162e2013-03-11 16:43:17 +0900426 argv, opts->pipe_output,
427 true);
Arnaldo Carvalho de Melo35b9d882011-11-09 08:47:15 -0200428 if (err < 0) {
429 pr_err("Couldn't run the workload!\n");
430 goto out_delete_session;
Jens Axboe0a5ac842009-08-12 11:18:01 +0200431 }
Peter Zijlstra856e9662009-12-16 17:55:55 +0100432 }
433
David Ahern8d3eca22012-08-26 12:24:47 -0600434 if (perf_record__open(rec) != 0) {
435 err = -1;
436 goto out_delete_session;
437 }
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200438
Namhyung Kima8bb5592013-01-22 18:09:31 +0900439 if (!evsel_list->nr_groups)
440 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
441
Arnaldo Carvalho de Melo712a4b62011-02-17 12:18:42 -0200442 /*
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200443 * perf_session__delete(session) will be called at perf_record__exit()
Arnaldo Carvalho de Melo712a4b62011-02-17 12:18:42 -0200444 */
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200445 on_exit(perf_record__exit, rec);
Arnaldo Carvalho de Melo712a4b62011-02-17 12:18:42 -0200446
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200447 if (opts->pipe_output) {
Tom Zanussi529870e2010-04-01 23:59:16 -0500448 err = perf_header__write_pipe(output);
449 if (err < 0)
David Ahern8d3eca22012-08-26 12:24:47 -0600450 goto out_delete_session;
Jiri Olsa563aecb2013-06-05 13:35:06 +0200451 } else {
Arnaldo Carvalho de Meloa91e5432011-03-10 11:15:54 -0300452 err = perf_session__write_header(session, evsel_list,
453 output, false);
Arnaldo Carvalho de Melod5eed902009-11-19 14:55:56 -0200454 if (err < 0)
David Ahern8d3eca22012-08-26 12:24:47 -0600455 goto out_delete_session;
Arnaldo Carvalho de Melod5eed902009-11-19 14:55:56 -0200456 }
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200457
David Ahernd3665492012-02-06 15:27:52 -0700458 if (!rec->no_buildid
Robert Richtere20960c2011-12-07 10:02:55 +0100459 && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
David Ahernd3665492012-02-06 15:27:52 -0700460 pr_err("Couldn't generate buildids. "
Robert Richtere20960c2011-12-07 10:02:55 +0100461 "Use --no-buildid to profile anyway.\n");
David Ahern8d3eca22012-08-26 12:24:47 -0600462 err = -1;
463 goto out_delete_session;
Robert Richtere20960c2011-12-07 10:02:55 +0100464 }
465
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200466 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200467
Arnaldo Carvalho de Melo34ba5122012-12-19 09:04:24 -0300468 machine = &session->machines.host;
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200469
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200470 if (opts->pipe_output) {
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200471 err = perf_event__synthesize_attrs(tool, session,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200472 process_synthesized_event);
Tom Zanussi2c46dbb2010-04-01 23:59:19 -0500473 if (err < 0) {
474 pr_err("Couldn't synthesize attrs.\n");
David Ahern8d3eca22012-08-26 12:24:47 -0600475 goto out_delete_session;
Tom Zanussi2c46dbb2010-04-01 23:59:19 -0500476 }
Tom Zanussicd19a032010-04-01 23:59:20 -0500477
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200478 err = perf_event__synthesize_event_types(tool, process_synthesized_event,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200479 machine);
Tom Zanussicd19a032010-04-01 23:59:20 -0500480 if (err < 0) {
481 pr_err("Couldn't synthesize event_types.\n");
David Ahern8d3eca22012-08-26 12:24:47 -0600482 goto out_delete_session;
Tom Zanussicd19a032010-04-01 23:59:20 -0500483 }
Tom Zanussi92155452010-04-01 23:59:21 -0500484
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200485 if (have_tracepoints(&evsel_list->entries)) {
Tom Zanussi63e0c772010-05-03 00:14:48 -0500486 /*
487 * FIXME err <= 0 here actually means that
488 * there were no tracepoints so its not really
489 * an error, just that we don't need to
490 * synthesize anything. We really have to
491 * return this more properly and also
492 * propagate errors that now are calling die()
493 */
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200494 err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200495 process_synthesized_event);
Tom Zanussi63e0c772010-05-03 00:14:48 -0500496 if (err <= 0) {
497 pr_err("Couldn't record tracing data.\n");
David Ahern8d3eca22012-08-26 12:24:47 -0600498 goto out_delete_session;
Tom Zanussi63e0c772010-05-03 00:14:48 -0500499 }
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200500 advance_output(rec, err);
Tom Zanussi63e0c772010-05-03 00:14:48 -0500501 }
Tom Zanussi2c46dbb2010-04-01 23:59:19 -0500502 }
503
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200504 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200505 machine, "_text");
Arnaldo Carvalho de Melo70162132010-03-30 18:27:39 -0300506 if (err < 0)
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200507 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200508 machine, "_stext");
Arnaldo Carvalho de Meloc1a3a4b2010-11-22 14:01:55 -0200509 if (err < 0)
510 pr_err("Couldn't record kernel reference relocation symbol\n"
511 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
512 "Check /proc/kallsyms permission or run as root.\n");
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200513
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200514 err = perf_event__synthesize_modules(tool, process_synthesized_event,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200515 machine);
Arnaldo Carvalho de Meloc1a3a4b2010-11-22 14:01:55 -0200516 if (err < 0)
517 pr_err("Couldn't record kernel module information.\n"
518 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
519 "Check /proc/modules permission or run as root.\n");
520
Arnaldo Carvalho de Melo7e383de2012-12-18 15:49:27 -0300521 if (perf_guest) {
Arnaldo Carvalho de Melo876650e2012-12-18 19:15:48 -0300522 machines__process_guests(&session->machines,
523 perf_event__synthesize_guest_os, tool);
Arnaldo Carvalho de Melo7e383de2012-12-18 15:49:27 -0300524 }
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -0200525
Jiri Olsae4dd45f2013-02-25 10:52:48 +0100526 if (perf_target__has_task(&opts->target))
David Ahern8d3eca22012-08-26 12:24:47 -0600527 err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
Arnaldo Carvalho de Melo7c940c12011-02-11 11:45:54 -0200528 process_synthesized_event,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200529 machine);
Jiri Olsae4dd45f2013-02-25 10:52:48 +0100530 else if (perf_target__has_cpu(&opts->target))
David Ahern8d3eca22012-08-26 12:24:47 -0600531 err = perf_event__synthesize_threads(tool, process_synthesized_event,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200532 machine);
Jiri Olsae4dd45f2013-02-25 10:52:48 +0100533 else /* command specified */
534 err = 0;
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200535
David Ahern8d3eca22012-08-26 12:24:47 -0600536 if (err != 0)
537 goto out_delete_session;
538
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200539 if (rec->realtime_prio) {
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200540 struct sched_param param;
541
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200542 param.sched_priority = rec->realtime_prio;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200543 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200544 pr_err("Could not set realtime priority.\n");
David Ahern8d3eca22012-08-26 12:24:47 -0600545 err = -1;
546 goto out_delete_session;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200547 }
548 }
549
Jiri Olsa774cb492012-11-12 18:34:01 +0100550 /*
551 * When perf is starting the traced process, all the events
552 * (apart from group members) have enable_on_exec=1 set,
553 * so don't spoil it by prematurely enabling them.
554 */
555 if (!perf_target__none(&opts->target))
556 perf_evlist__enable(evsel_list);
David Ahern764e16a32011-08-25 10:17:55 -0600557
Peter Zijlstra856e9662009-12-16 17:55:55 +0100558 /*
559 * Let the child rip
560 */
Arnaldo Carvalho de Melod4db3f12009-12-27 21:36:57 -0200561 if (forks)
Arnaldo Carvalho de Melo35b9d882011-11-09 08:47:15 -0200562 perf_evlist__start_workload(evsel_list);
Peter Zijlstra856e9662009-12-16 17:55:55 +0100563
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200564 for (;;) {
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200565 int hits = rec->samples;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200566
David Ahern8d3eca22012-08-26 12:24:47 -0600567 if (perf_record__mmap_read_all(rec) < 0) {
568 err = -1;
569 goto out_delete_session;
570 }
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200571
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200572 if (hits == rec->samples) {
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200573 if (done)
574 break;
Arnaldo Carvalho de Melo5c581042011-01-11 22:30:02 -0200575 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
Peter Zijlstra8b412662009-09-17 19:59:05 +0200576 waking++;
577 }
578
Jiri Olsa774cb492012-11-12 18:34:01 +0100579 /*
580 * When perf is starting the traced process, at the end events
581 * die with the process and we wait for that. Thus no need to
582 * disable events in this case.
583 */
Jiri Olsa27119262012-11-12 18:34:02 +0100584 if (done && !disabled && !perf_target__none(&opts->target)) {
Arnaldo Carvalho de Melo4152ab32011-07-25 11:06:19 -0300585 perf_evlist__disable(evsel_list);
Jiri Olsa27119262012-11-12 18:34:02 +0100586 disabled = true;
587 }
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200588 }
589
Arnaldo Carvalho de Melo18483b82010-12-06 15:13:38 -0200590 if (quiet || signr == SIGUSR1)
Arnaldo Carvalho de Melob44308f2010-10-26 15:20:09 -0200591 return 0;
592
Peter Zijlstra8b412662009-09-17 19:59:05 +0200593 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
594
Ingo Molnar021e9f42009-06-03 19:27:19 +0200595 /*
596 * Approximate RIP event size: 24 bytes.
597 */
598 fprintf(stderr,
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -0200599 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200600 (double)rec->bytes_written / 1024.0 / 1024.0,
Ingo Molnar021e9f42009-06-03 19:27:19 +0200601 output_name,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200602 rec->bytes_written / 24);
Ingo Molnaraddc2782009-06-02 23:43:11 +0200603
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200604 return 0;
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300605
606out_delete_session:
607 perf_session__delete(session);
608 return err;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200609}
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200610
Roberto Agostino Vitillobdfebd82012-02-09 23:21:02 +0100611#define BRANCH_OPT(n, m) \
612 { .name = n, .mode = (m) }
613
614#define BRANCH_END { .name = NULL }
615
616struct branch_mode {
617 const char *name;
618 int mode;
619};
620
621static const struct branch_mode branch_modes[] = {
622 BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
623 BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
624 BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
625 BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
626 BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
627 BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
628 BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
629 BRANCH_END
630};
631
632static int
Stephane Eraniana5aabda2012-03-08 23:47:45 +0100633parse_branch_stack(const struct option *opt, const char *str, int unset)
Roberto Agostino Vitillobdfebd82012-02-09 23:21:02 +0100634{
635#define ONLY_PLM \
636 (PERF_SAMPLE_BRANCH_USER |\
637 PERF_SAMPLE_BRANCH_KERNEL |\
638 PERF_SAMPLE_BRANCH_HV)
639
640 uint64_t *mode = (uint64_t *)opt->value;
641 const struct branch_mode *br;
Stephane Eraniana5aabda2012-03-08 23:47:45 +0100642 char *s, *os = NULL, *p;
Roberto Agostino Vitillobdfebd82012-02-09 23:21:02 +0100643 int ret = -1;
644
Stephane Eraniana5aabda2012-03-08 23:47:45 +0100645 if (unset)
646 return 0;
Roberto Agostino Vitillobdfebd82012-02-09 23:21:02 +0100647
Stephane Eraniana5aabda2012-03-08 23:47:45 +0100648 /*
649 * cannot set it twice, -b + --branch-filter for instance
650 */
651 if (*mode)
Roberto Agostino Vitillobdfebd82012-02-09 23:21:02 +0100652 return -1;
653
Stephane Eraniana5aabda2012-03-08 23:47:45 +0100654 /* str may be NULL in case no arg is passed to -b */
655 if (str) {
656 /* because str is read-only */
657 s = os = strdup(str);
658 if (!s)
659 return -1;
Roberto Agostino Vitillobdfebd82012-02-09 23:21:02 +0100660
Stephane Eraniana5aabda2012-03-08 23:47:45 +0100661 for (;;) {
662 p = strchr(s, ',');
663 if (p)
664 *p = '\0';
665
666 for (br = branch_modes; br->name; br++) {
667 if (!strcasecmp(s, br->name))
668 break;
669 }
670 if (!br->name) {
671 ui__warning("unknown branch filter %s,"
672 " check man page\n", s);
673 goto error;
674 }
675
676 *mode |= br->mode;
677
678 if (!p)
Roberto Agostino Vitillobdfebd82012-02-09 23:21:02 +0100679 break;
Stephane Eraniana5aabda2012-03-08 23:47:45 +0100680
681 s = p + 1;
Roberto Agostino Vitillobdfebd82012-02-09 23:21:02 +0100682 }
Roberto Agostino Vitillobdfebd82012-02-09 23:21:02 +0100683 }
684 ret = 0;
685
Stephane Eraniana5aabda2012-03-08 23:47:45 +0100686 /* default to any branch */
Roberto Agostino Vitillobdfebd82012-02-09 23:21:02 +0100687 if ((*mode & ~ONLY_PLM) == 0) {
Stephane Eraniana5aabda2012-03-08 23:47:45 +0100688 *mode = PERF_SAMPLE_BRANCH_ANY;
Roberto Agostino Vitillobdfebd82012-02-09 23:21:02 +0100689 }
690error:
691 free(os);
692 return ret;
693}
694
Namhyung Kim95485b12012-09-28 18:32:00 +0900695#ifdef LIBUNWIND_SUPPORT
Jiri Olsa26d33022012-08-07 15:20:47 +0200696static int get_stack_size(char *str, unsigned long *_size)
697{
698 char *endptr;
699 unsigned long size;
700 unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
701
702 size = strtoul(str, &endptr, 0);
703
704 do {
705 if (*endptr)
706 break;
707
708 size = round_up(size, sizeof(u64));
709 if (!size || size > max_size)
710 break;
711
712 *_size = size;
713 return 0;
714
715 } while (0);
716
717 pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
718 max_size, str);
719 return -1;
720}
Namhyung Kim95485b12012-09-28 18:32:00 +0900721#endif /* LIBUNWIND_SUPPORT */
Jiri Olsa26d33022012-08-07 15:20:47 +0200722
Arnaldo Carvalho de Melo75d9a1082012-12-11 16:46:05 -0300723int record_parse_callchain_opt(const struct option *opt,
724 const char *arg, int unset)
Jiri Olsa26d33022012-08-07 15:20:47 +0200725{
Arnaldo Carvalho de Meloc5ff78c2012-12-11 16:16:47 -0300726 struct perf_record_opts *opts = opt->value;
Jiri Olsa26d33022012-08-07 15:20:47 +0200727 char *tok, *name, *saveptr = NULL;
728 char *buf;
729 int ret = -1;
730
731 /* --no-call-graph */
732 if (unset)
733 return 0;
734
735 /* We specified default option if none is provided. */
736 BUG_ON(!arg);
737
738 /* We need buffer that we know we can write to. */
739 buf = malloc(strlen(arg) + 1);
740 if (!buf)
741 return -ENOMEM;
742
743 strcpy(buf, arg);
744
745 tok = strtok_r((char *)buf, ",", &saveptr);
746 name = tok ? : (char *)buf;
747
748 do {
749 /* Framepointer style */
750 if (!strncmp(name, "fp", sizeof("fp"))) {
751 if (!strtok_r(NULL, ",", &saveptr)) {
Arnaldo Carvalho de Meloc5ff78c2012-12-11 16:16:47 -0300752 opts->call_graph = CALLCHAIN_FP;
Jiri Olsa26d33022012-08-07 15:20:47 +0200753 ret = 0;
754 } else
755 pr_err("callchain: No more arguments "
756 "needed for -g fp\n");
757 break;
758
Namhyung Kim95485b12012-09-28 18:32:00 +0900759#ifdef LIBUNWIND_SUPPORT
Jiri Olsa26d33022012-08-07 15:20:47 +0200760 /* Dwarf style */
761 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
Arnaldo Carvalho de Melo61eaa3b2012-10-01 15:20:58 -0300762 const unsigned long default_stack_dump_size = 8192;
763
Jiri Olsa26d33022012-08-07 15:20:47 +0200764 ret = 0;
Arnaldo Carvalho de Meloc5ff78c2012-12-11 16:16:47 -0300765 opts->call_graph = CALLCHAIN_DWARF;
766 opts->stack_dump_size = default_stack_dump_size;
Jiri Olsa26d33022012-08-07 15:20:47 +0200767
768 tok = strtok_r(NULL, ",", &saveptr);
769 if (tok) {
770 unsigned long size = 0;
771
772 ret = get_stack_size(tok, &size);
Arnaldo Carvalho de Meloc5ff78c2012-12-11 16:16:47 -0300773 opts->stack_dump_size = size;
Jiri Olsa26d33022012-08-07 15:20:47 +0200774 }
775
776 if (!ret)
777 pr_debug("callchain: stack dump size %d\n",
Arnaldo Carvalho de Meloc5ff78c2012-12-11 16:16:47 -0300778 opts->stack_dump_size);
Namhyung Kim95485b12012-09-28 18:32:00 +0900779#endif /* LIBUNWIND_SUPPORT */
Jiri Olsa26d33022012-08-07 15:20:47 +0200780 } else {
781 pr_err("callchain: Unknown -g option "
782 "value: %s\n", arg);
783 break;
784 }
785
786 } while (0);
787
788 free(buf);
789
790 if (!ret)
Arnaldo Carvalho de Meloc5ff78c2012-12-11 16:16:47 -0300791 pr_debug("callchain: type %d\n", opts->call_graph);
Jiri Olsa26d33022012-08-07 15:20:47 +0200792
793 return ret;
794}
795
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200796static const char * const record_usage[] = {
Mike Galbraith9e0967532009-05-28 16:25:34 +0200797 "perf record [<options>] [<command>]",
798 "perf record [<options>] -- <command> [<options>]",
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200799 NULL
800};
801
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200802/*
803 * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
804 * because we need to have access to it in perf_record__exit, that is called
805 * after cmd_record() exits, but since record_options need to be accessible to
806 * builtin-script, leave it here.
807 *
808 * At least we don't ouch it in all the other functions here directly.
809 *
810 * Just say no to tons of global variables, sigh.
811 */
812static struct perf_record record = {
813 .opts = {
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200814 .mmap_pages = UINT_MAX,
815 .user_freq = UINT_MAX,
816 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo447a6012012-05-22 13:14:18 -0300817 .freq = 4000,
Namhyung Kimd1cb9fc2012-05-16 18:45:49 +0900818 .target = {
819 .uses_mmap = true,
820 },
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200821 },
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200822};
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200823
Arnaldo Carvalho de Melo61eaa3b2012-10-01 15:20:58 -0300824#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
825
826#ifdef LIBUNWIND_SUPPORT
Arnaldo Carvalho de Melo75d9a1082012-12-11 16:46:05 -0300827const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
Arnaldo Carvalho de Melo61eaa3b2012-10-01 15:20:58 -0300828#else
Arnaldo Carvalho de Melo75d9a1082012-12-11 16:46:05 -0300829const char record_callchain_help[] = CALLCHAIN_HELP "[fp]";
Arnaldo Carvalho de Melo61eaa3b2012-10-01 15:20:58 -0300830#endif
831
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200832/*
833 * XXX Will stay a global variable till we fix builtin-script.c to stop messing
834 * with it and switch to use the library functions in perf_evlist that came
835 * from builtin-record.c, i.e. use perf_record_opts,
836 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
837 * using pipes, etc.
838 */
Tom Zanussibca647a2010-11-10 08:11:30 -0600839const struct option record_options[] = {
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200840 OPT_CALLBACK('e', "event", &record.evlist, "event",
Thomas Gleixner86847b62009-06-06 12:24:17 +0200841 "event selector. use 'perf list' to list available events",
Jiri Olsaf120f9d2011-07-14 11:25:32 +0200842 parse_events_option),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200843 OPT_CALLBACK(0, "filter", &record.evlist, "filter",
Li Zefanc171b552009-10-15 11:22:07 +0800844 "event filter", parse_filter),
Namhyung Kimbea03402012-04-26 14:15:15 +0900845 OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300846 "record events on existing process id"),
Namhyung Kimbea03402012-04-26 14:15:15 +0900847 OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300848 "record events on existing thread id"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200849 OPT_INTEGER('r', "realtime", &record.realtime_prio,
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200850 "collect data with this RT SCHED_FIFO priority"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200851 OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
Kirill Smelkovacac03f2011-01-12 17:59:36 +0300852 "collect data without buffering"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200853 OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
Frederic Weisbeckerdaac07b2009-08-13 10:27:19 +0200854 "collect raw sample records from all opened counters"),
Namhyung Kimbea03402012-04-26 14:15:15 +0900855 OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200856 "system-wide collection from all CPUs"),
Namhyung Kimbea03402012-04-26 14:15:15 +0900857 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200858 "list of cpus to monitor"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200859 OPT_BOOLEAN('f', "force", &record.force,
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200860 "overwrite existing data file (deprecated)"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200861 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
862 OPT_STRING('o', "output", &record.output_name, "file",
Ingo Molnarabaff322009-06-02 22:59:57 +0200863 "output file name"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200864 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
Stephane Eranian2e6cdf92010-05-12 10:40:01 +0200865 "child tasks do not inherit counters"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200866 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
867 OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
Arnaldo Carvalho de Melo01c2d992011-11-09 09:16:26 -0200868 "number of mmap data pages"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200869 OPT_BOOLEAN(0, "group", &record.opts.group,
Lin Ming43bece72011-08-17 18:42:07 +0800870 "put the counters into a counter group"),
Arnaldo Carvalho de Meloc5ff78c2012-12-11 16:16:47 -0300871 OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts,
Arnaldo Carvalho de Melo75d9a1082012-12-11 16:46:05 -0300872 "mode[,dump_size]", record_callchain_help,
873 &record_parse_callchain_opt, "fp"),
Ian Munsiec0555642010-04-13 18:37:33 +1000874 OPT_INCR('v', "verbose", &verbose,
Ingo Molnar3da297a2009-06-07 17:39:02 +0200875 "be more verbose (show counter open errors, etc)"),
Arnaldo Carvalho de Melob44308f2010-10-26 15:20:09 -0200876 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200877 OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200878 "per thread counts"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200879 OPT_BOOLEAN('d', "data", &record.opts.sample_address,
Anton Blanchard4bba8282009-07-16 15:44:29 +0200880 "Sample addresses"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200881 OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
Andrew Vagin3e76ac72011-12-20 17:32:45 +0300882 OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200883 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200884 "don't sample"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200885 OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
Stephane Eraniana1ac1d32010-06-17 11:39:01 +0200886 "do not update the buildid cache"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200887 OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200888 "do not collect buildids in perf.data"),
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200889 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
Stephane Eranian023695d2011-02-14 11:20:01 +0200890 "monitor event in cgroup name only",
891 parse_cgroups),
Namhyung Kimbea03402012-04-26 14:15:15 +0900892 OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
893 "user to profile"),
Stephane Eraniana5aabda2012-03-08 23:47:45 +0100894
895 OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
896 "branch any", "sample any taken branches",
897 parse_branch_stack),
898
899 OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
900 "branch filter mask", "branch stack filter modes",
Roberto Agostino Vitillobdfebd82012-02-09 23:21:02 +0100901 parse_branch_stack),
Andi Kleen05484292013-01-24 16:10:29 +0100902 OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
903 "sample by weight (on special events only)"),
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200904 OPT_END()
905};
906
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300907int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200908{
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200909 int err = -ENOMEM;
910 struct perf_evsel *pos;
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200911 struct perf_evlist *evsel_list;
912 struct perf_record *rec = &record;
Namhyung Kim16ad2ff2012-05-07 14:09:02 +0900913 char errbuf[BUFSIZ];
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200914
Namhyung Kim334fe7a2013-03-11 16:43:12 +0900915 evsel_list = perf_evlist__new();
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200916 if (evsel_list == NULL)
917 return -ENOMEM;
918
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200919 rec->evlist = evsel_list;
920
Tom Zanussibca647a2010-11-10 08:11:30 -0600921 argc = parse_options(argc, argv, record_options, record_usage,
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -0200922 PARSE_OPT_STOP_AT_NON_OPTION);
Namhyung Kimd67356e2012-05-07 14:09:03 +0900923 if (!argc && perf_target__none(&rec->opts.target))
Tom Zanussibca647a2010-11-10 08:11:30 -0600924 usage_with_options(record_usage, record_options);
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200925
Namhyung Kimbea03402012-04-26 14:15:15 +0900926 if (nr_cgroups && !rec->opts.target.system_wide) {
Namhyung Kim3780f482012-05-29 13:22:57 +0900927 ui__error("cgroup monitoring only available in"
928 " system-wide mode\n");
Stephane Eranian023695d2011-02-14 11:20:01 +0200929 usage_with_options(record_usage, record_options);
930 }
931
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -0200932 symbol__init();
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200933
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -0300934 if (symbol_conf.kptr_restrict)
Arnaldo Carvalho de Melo646aaea2011-05-27 11:00:41 -0300935 pr_warning(
936"WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
937"check /proc/sys/kernel/kptr_restrict.\n\n"
938"Samples in kernel functions may not be resolved if a suitable vmlinux\n"
939"file is not found in the buildid cache or in the vmlinux path.\n\n"
940"Samples in kernel modules won't be resolved at all.\n\n"
941"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
942"even with a suitable vmlinux or kallsyms file.\n\n");
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -0300943
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200944 if (rec->no_buildid_cache || rec->no_buildid)
Stephane Eraniana1ac1d32010-06-17 11:39:01 +0200945 disable_buildid_cache();
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -0200946
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200947 if (evsel_list->nr_entries == 0 &&
948 perf_evlist__add_default(evsel_list) < 0) {
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200949 pr_err("Not enough memory for event selector list\n");
950 goto out_symbol_exit;
Peter Zijlstrabbd36e52009-06-11 23:11:50 +0200951 }
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200952
Namhyung Kim16ad2ff2012-05-07 14:09:02 +0900953 err = perf_target__validate(&rec->opts.target);
954 if (err) {
955 perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
956 ui__warning("%s", errbuf);
957 }
Namhyung Kim4bd0f2d2012-04-26 14:15:18 +0900958
Namhyung Kim16ad2ff2012-05-07 14:09:02 +0900959 err = perf_target__parse_uid(&rec->opts.target);
960 if (err) {
961 int saved_errno = errno;
962
963 perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
Namhyung Kim3780f482012-05-29 13:22:57 +0900964 ui__error("%s", errbuf);
Namhyung Kim16ad2ff2012-05-07 14:09:02 +0900965
966 err = -saved_errno;
Namhyung Kim8fa60e12013-03-15 14:48:51 +0900967 goto out_symbol_exit;
Namhyung Kim16ad2ff2012-05-07 14:09:02 +0900968 }
Arnaldo Carvalho de Melo0d37aa32012-01-19 14:08:15 -0200969
Namhyung Kim16ad2ff2012-05-07 14:09:02 +0900970 err = -ENOMEM;
Namhyung Kimb809ac12012-04-26 14:15:19 +0900971 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200972 usage_with_options(record_usage, record_options);
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200973
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200974 list_for_each_entry(pos, &evsel_list->entries, node) {
Arnaldo Carvalho de Melo7289f832012-06-12 12:34:58 -0300975 if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
Arnaldo Carvalho de Meload7f4e32011-01-17 18:28:13 -0200976 goto out_free_fd;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300977 }
Arnaldo Carvalho de Melo5c581042011-01-11 22:30:02 -0200978
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200979 if (rec->opts.user_interval != ULLONG_MAX)
980 rec->opts.default_interval = rec->opts.user_interval;
981 if (rec->opts.user_freq != UINT_MAX)
982 rec->opts.freq = rec->opts.user_freq;
Frederic Weisbeckerf9212812010-04-14 22:09:02 +0200983
Mike Galbraith7e4ff9e2009-10-12 07:56:03 +0200984 /*
985 * User specified count overrides default frequency.
986 */
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200987 if (rec->opts.default_interval)
988 rec->opts.freq = 0;
989 else if (rec->opts.freq) {
990 rec->opts.default_interval = rec->opts.freq;
Mike Galbraith7e4ff9e2009-10-12 07:56:03 +0200991 } else {
Namhyung Kim3780f482012-05-29 13:22:57 +0900992 ui__error("frequency and count are zero, aborting\n");
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300993 err = -EINVAL;
Arnaldo Carvalho de Melo5c581042011-01-11 22:30:02 -0200994 goto out_free_fd;
Mike Galbraith7e4ff9e2009-10-12 07:56:03 +0200995 }
996
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200997 err = __cmd_record(&record, argc, argv);
Namhyung Kim8fa60e12013-03-15 14:48:51 +0900998
999 perf_evlist__munmap(evsel_list);
1000 perf_evlist__close(evsel_list);
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -03001001out_free_fd:
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -02001002 perf_evlist__delete_maps(evsel_list);
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -03001003out_symbol_exit:
1004 symbol__exit();
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -03001005 return err;
Ingo Molnar0e9b20b2009-05-26 09:17:18 +02001006}