blob: c3ac5415c097ca3009af0393ea355dc7f36aa6d9 [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 */
Xiao Guangrongb8f46c52010-02-03 11:53:14 +08008#define _FILE_OFFSET_BITS 64
9
Ingo Molnar16f762a2009-05-27 09:10:38 +020010#include "builtin.h"
Ingo Molnarbf9e1872009-06-02 23:37:05 +020011
12#include "perf.h"
13
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -020014#include "util/build-id.h"
Thomas Gleixner6eda5832009-05-01 18:29:57 +020015#include "util/util.h"
Ingo Molnar0e9b20b2009-05-26 09:17:18 +020016#include "util/parse-options.h"
Ingo Molnar8ad8db32009-05-26 11:10:09 +020017#include "util/parse-events.h"
Thomas Gleixner6eda5832009-05-01 18:29:57 +020018
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020019#include "util/header.h"
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020020#include "util/event.h"
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -020021#include "util/evlist.h"
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -020022#include "util/evsel.h"
Frederic Weisbecker8f28827a2009-08-16 22:05:48 +020023#include "util/debug.h"
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020024#include "util/session.h"
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -020025#include "util/symbol.h"
Paul Mackerrasa12b51c2010-03-10 20:36:09 +110026#include "util/cpumap.h"
Arnaldo Carvalho de Melofd782602011-01-18 15:15:24 -020027#include "util/thread_map.h"
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020028
Peter Zijlstra97124d52009-06-02 15:52:24 +020029#include <unistd.h>
Peter Zijlstrade9ac072009-04-08 15:01:31 +020030#include <sched.h>
Arnaldo Carvalho de Meloa41794c2010-05-18 18:29:23 -030031#include <sys/mman.h>
Peter Zijlstrade9ac072009-04-08 15:01:31 +020032
Frederic Weisbecker7865e812010-04-14 19:42:07 +020033enum write_mode_t {
34 WRITE_FORCE,
35 WRITE_APPEND
36};
37
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -020038static struct perf_record_opts record_opts = {
39 .target_pid = -1,
40 .target_tid = -1,
41 .user_freq = UINT_MAX,
42 .user_interval = ULLONG_MAX,
43 .freq = 1000,
44 .sample_id_all_avail = true,
45};
Ingo Molnara21ca2c2009-06-06 09:58:57 +020046
Peter Zijlstrade9ac072009-04-08 15:01:31 +020047static unsigned int page_size;
Frederic Weisbecker800cd252011-03-31 03:35:24 +020048static unsigned int mmap_pages = UINT_MAX;
Peter Zijlstrade9ac072009-04-08 15:01:31 +020049static int output;
Tom Zanussi529870e2010-04-01 23:59:16 -050050static int pipe_output = 0;
Franck Bui-Huud7065ad2011-01-16 17:14:45 +010051static const char *output_name = NULL;
Lin Ming43bece72011-08-17 18:42:07 +080052static bool group = false;
Arnaldo Carvalho de Melo19679362010-05-17 15:39:16 -030053static int realtime_prio = 0;
Ingo Molnar42e59d72009-10-06 15:14:21 +020054static pid_t child_pid = -1;
Frederic Weisbecker7865e812010-04-14 19:42:07 +020055static enum write_mode_t write_mode = WRITE_FORCE;
Stephane Eraniana1ac1d32010-06-17 11:39:01 +020056static bool no_buildid = false;
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -020057static bool no_buildid_cache = false;
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -020058static struct perf_evlist *evsel_list;
Peter Zijlstrade9ac072009-04-08 15:01:31 +020059
Ingo Molnar42e59d72009-10-06 15:14:21 +020060static long samples = 0;
Ingo Molnar42e59d72009-10-06 15:14:21 +020061static u64 bytes_written = 0;
Ingo Molnara21ca2c2009-06-06 09:58:57 +020062
Ingo Molnar42e59d72009-10-06 15:14:21 +020063static int file_new = 1;
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -020064static off_t post_processing_offset;
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020065
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020066static struct perf_session *session;
Andi Kleen33e49ea2011-09-15 14:31:40 -070067static const char *progname;
Peter Zijlstraf5970552009-06-18 23:22:55 +020068
Tom Zanussi92155452010-04-01 23:59:21 -050069static void advance_output(size_t size)
70{
71 bytes_written += size;
72}
73
Peter Zijlstraf5970552009-06-18 23:22:55 +020074static void write_output(void *buf, size_t size)
75{
76 while (size) {
77 int ret = write(output, buf, size);
78
79 if (ret < 0)
80 die("failed to write");
81
82 size -= ret;
83 buf += ret;
84
85 bytes_written += ret;
86 }
87}
88
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -020089static int process_synthesized_event(union perf_event *event,
Arnaldo Carvalho de Melo8d50e5b2011-01-29 13:02:00 -020090 struct perf_sample *sample __used,
Arnaldo Carvalho de Melod8f66242009-12-13 19:50:24 -020091 struct perf_session *self __used)
Arnaldo Carvalho de Melo234fbbf2009-10-26 19:23:18 -020092{
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -020093 write_output(event, event->header.size);
Arnaldo Carvalho de Melo234fbbf2009-10-26 19:23:18 -020094 return 0;
95}
96
Arnaldo Carvalho de Melo744bd8a2011-01-12 17:07:28 -020097static void mmap_read(struct perf_mmap *md)
Peter Zijlstrade9ac072009-04-08 15:01:31 +020098{
Arnaldo Carvalho de Melo744bd8a2011-01-12 17:07:28 -020099 unsigned int head = perf_mmap__read_head(md);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200100 unsigned int old = md->prev;
101 unsigned char *data = md->base + page_size;
102 unsigned long size;
103 void *buf;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200104
Arnaldo Carvalho de Melodc820092011-01-28 14:49:19 -0200105 if (old == head)
106 return;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200107
Arnaldo Carvalho de Melodc820092011-01-28 14:49:19 -0200108 samples++;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200109
110 size = head - old;
111
112 if ((old & md->mask) + size != (head & md->mask)) {
113 buf = &data[old & md->mask];
114 size = md->mask + 1 - (old & md->mask);
115 old += size;
Ingo Molnar021e9f42009-06-03 19:27:19 +0200116
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200117 write_output(buf, size);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200118 }
119
120 buf = &data[old & md->mask];
121 size = head - old;
122 old += size;
Ingo Molnar021e9f42009-06-03 19:27:19 +0200123
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200124 write_output(buf, size);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200125
126 md->prev = old;
Arnaldo Carvalho de Melo115d2d82011-01-12 17:11:53 -0200127 perf_mmap__write_tail(md, old);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200128}
129
130static volatile int done = 0;
Peter Zijlstraf7b7c262009-06-10 15:55:59 +0200131static volatile int signr = -1;
Andi Kleen33e49ea2011-09-15 14:31:40 -0700132static volatile int child_finished = 0;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200133
Peter Zijlstra16c8a102009-05-05 17:50:27 +0200134static void sig_handler(int sig)
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200135{
Andi Kleen33e49ea2011-09-15 14:31:40 -0700136 if (sig == SIGCHLD)
137 child_finished = 1;
138
Peter Zijlstra16c8a102009-05-05 17:50:27 +0200139 done = 1;
Peter Zijlstraf7b7c262009-06-10 15:55:59 +0200140 signr = sig;
141}
142
143static void sig_atexit(void)
144{
Andi Kleen33e49ea2011-09-15 14:31:40 -0700145 int status;
146
147 if (child_pid > 0) {
148 if (!child_finished)
149 kill(child_pid, SIGTERM);
150
151 wait(&status);
152 if (WIFSIGNALED(status))
153 psignal(WTERMSIG(status), progname);
154 }
Chris Wilson933da832009-10-04 01:35:01 +0100155
Arnaldo Carvalho de Melo18483b82010-12-06 15:13:38 -0200156 if (signr == -1 || signr == SIGUSR1)
Peter Zijlstraf7b7c262009-06-10 15:55:59 +0200157 return;
158
159 signal(signr, SIG_DFL);
160 kill(getpid(), signr);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200161}
162
Arnaldo Carvalho de Meloa91e5432011-03-10 11:15:54 -0300163static bool perf_evlist__equal(struct perf_evlist *evlist,
164 struct perf_evlist *other)
165{
166 struct perf_evsel *pos, *pair;
167
168 if (evlist->nr_entries != other->nr_entries)
169 return false;
170
171 pair = list_entry(other->entries.next, struct perf_evsel, node);
172
173 list_for_each_entry(pos, &evlist->entries, node) {
174 if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
175 return false;
176 pair = list_entry(pair->node.next, struct perf_evsel, node);
177 }
178
179 return true;
180}
181
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200182static void open_counters(struct perf_evlist *evlist)
183{
Arnaldo Carvalho de Melo727ab042011-10-25 10:42:19 -0200184 struct perf_evsel *pos, *first;
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200185
Arnaldo Carvalho de Melo727ab042011-10-25 10:42:19 -0200186 first = list_entry(evlist->entries.next, struct perf_evsel, node);
187
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200188 perf_evlist__config_attrs(evlist, &record_opts);
189
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200190 list_for_each_entry(pos, &evlist->entries, node) {
191 struct perf_event_attr *attr = &pos->attr;
Arnaldo Carvalho de Melo727ab042011-10-25 10:42:19 -0200192 struct xyarray *group_fd = NULL;
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200193 /*
194 * Check if parse_single_tracepoint_event has already asked for
195 * PERF_SAMPLE_TIME.
196 *
197 * XXX this is kludgy but short term fix for problems introduced by
198 * eac23d1c that broke 'perf script' by having different sample_types
199 * when using multiple tracepoint events when we use a perf binary
200 * that tries to use sample_id_all on an older kernel.
201 *
202 * We need to move counter creation to perf_session, support
203 * different sample_types, etc.
204 */
205 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
206
Arnaldo Carvalho de Melo727ab042011-10-25 10:42:19 -0200207 if (group && pos != first)
208 group_fd = first->fd;
Arnaldo Carvalho de Melo9c90a612010-12-02 10:25:28 -0200209retry_sample_id:
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200210 attr->sample_id_all = record_opts.sample_id_all_avail ? 1 : 0;
Ingo Molnar3da297a2009-06-07 17:39:02 +0200211try_again:
Arnaldo Carvalho de Melo727ab042011-10-25 10:42:19 -0200212 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group,
213 group_fd) < 0) {
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300214 int err = errno;
Ingo Molnarf250c0302009-06-05 13:18:41 +0200215
Arnaldo Carvalho de Meloc286c412011-03-28 09:50:11 -0300216 if (err == EPERM || err == EACCES) {
Arnaldo Carvalho de Melob8631e62011-10-26 08:02:55 -0200217 ui__error_paranoid();
Arnaldo Carvalho de Meloc286c412011-03-28 09:50:11 -0300218 exit(EXIT_FAILURE);
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200219 } else if (err == ENODEV && record_opts.cpu_list) {
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300220 die("No such device - did you specify"
221 " an out-of-range profile CPU?\n");
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200222 } else if (err == EINVAL && record_opts.sample_id_all_avail) {
Arnaldo Carvalho de Melo9c90a612010-12-02 10:25:28 -0200223 /*
224 * Old kernel, no attr->sample_id_type_all field
225 */
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200226 record_opts.sample_id_all_avail = false;
227 if (!record_opts.sample_time && !record_opts.raw_samples && !time_needed)
Ian Munsieeac23d12010-12-09 16:33:53 +1100228 attr->sample_type &= ~PERF_SAMPLE_TIME;
229
Arnaldo Carvalho de Melo9c90a612010-12-02 10:25:28 -0200230 goto retry_sample_id;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300231 }
Ingo Molnar3da297a2009-06-07 17:39:02 +0200232
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300233 /*
234 * If it's cycles then fall back to hrtimer
235 * based cpu-clock-tick sw counter, which
236 * is always available even if no PMU support:
237 */
238 if (attr->type == PERF_TYPE_HARDWARE
239 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
Ingo Molnar3da297a2009-06-07 17:39:02 +0200240
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300241 if (verbose)
David Ahernca6a4252011-03-25 13:11:11 -0600242 ui__warning("The cycles event is not supported, "
243 "trying to fall back to cpu-clock-ticks\n");
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300244 attr->type = PERF_TYPE_SOFTWARE;
245 attr->config = PERF_COUNT_SW_CPU_CLOCK;
246 goto try_again;
247 }
David Ahernca6a4252011-03-25 13:11:11 -0600248
249 if (err == ENOENT) {
250 ui__warning("The %s event is not supported.\n",
251 event_name(pos));
252 exit(EXIT_FAILURE);
253 }
254
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300255 printf("\n");
Corey Ashfordd9cf8372010-11-19 17:37:24 -0800256 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200257 err, strerror(err));
Simon Kaempfleinbfd45112009-11-16 15:25:53 +1000258
259#if defined(__i386__) || defined(__x86_64__)
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300260 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
261 die("No hardware sampling interrupt available."
262 " No APIC? If so then you can boot the kernel"
263 " with the \"lapic\" boot parameter to"
264 " force-enable it.\n");
Simon Kaempfleinbfd45112009-11-16 15:25:53 +1000265#endif
266
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300267 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300268 }
Li Zefanc171b552009-10-15 11:22:07 +0800269 }
Arnaldo Carvalho de Meloa43d3f02010-12-25 12:12:25 -0200270
Frederic Weisbecker0a102472011-02-26 04:51:54 +0100271 if (perf_evlist__set_filters(evlist)) {
272 error("failed to set filter with %d (%s)\n", errno,
273 strerror(errno));
274 exit(-1);
275 }
276
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200277 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
Arnaldo Carvalho de Melo0a27d7f2011-01-14 15:50:51 -0200278 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
279
Arnaldo Carvalho de Meloa91e5432011-03-10 11:15:54 -0300280 if (file_new)
281 session->evlist = evlist;
282 else {
283 if (!perf_evlist__equal(session->evlist, evlist)) {
284 fprintf(stderr, "incompatible append\n");
285 exit(-1);
286 }
287 }
288
289 perf_session__update_sample_type(session);
Peter Zijlstra16c8a102009-05-05 17:50:27 +0200290}
291
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200292static int process_buildids(void)
293{
294 u64 size = lseek(output, 0, SEEK_CUR);
295
Arnaldo Carvalho de Melo9f591fd2010-03-11 15:53:11 -0300296 if (size == 0)
297 return 0;
298
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200299 session->fd = output;
300 return __perf_session__process_events(session, post_processing_offset,
301 size - post_processing_offset,
302 size, &build_id__mark_dso_hit_ops);
303}
304
Peter Zijlstraf5970552009-06-18 23:22:55 +0200305static void atexit_header(void)
306{
Tom Zanussic7929e42010-04-01 23:59:22 -0500307 if (!pipe_output) {
308 session->header.data_size += bytes_written;
Peter Zijlstraf5970552009-06-18 23:22:55 +0200309
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200310 if (!no_buildid)
311 process_buildids();
Arnaldo Carvalho de Meloa91e5432011-03-10 11:15:54 -0300312 perf_session__write_header(session, evsel_list, output, true);
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300313 perf_session__delete(session);
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200314 perf_evlist__delete(evsel_list);
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -0300315 symbol__exit();
Tom Zanussic7929e42010-04-01 23:59:22 -0500316 }
Peter Zijlstraf5970552009-06-18 23:22:55 +0200317}
318
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200319static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800320{
321 int err;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300322 struct perf_session *psession = data;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800323
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300324 if (machine__is_host(machine))
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800325 return;
326
327 /*
328 *As for guest kernel when processing subcommand record&report,
329 *we arrange module mmap prior to guest kernel mmap and trigger
330 *a preload dso because default guest module symbols are loaded
331 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
332 *method is used to avoid symbol missing when the first addr is
333 *in module instead of in guest kernel.
334 */
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200335 err = perf_event__synthesize_modules(process_synthesized_event,
336 psession, machine);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800337 if (err < 0)
338 pr_err("Couldn't record guest kernel [%d]'s reference"
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300339 " relocation symbol.\n", machine->pid);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800340
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800341 /*
342 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
343 * have no _text sometimes.
344 */
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200345 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
346 psession, machine, "_text");
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800347 if (err < 0)
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200348 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
349 psession, machine,
350 "_stext");
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800351 if (err < 0)
352 pr_err("Couldn't record guest kernel [%d]'s reference"
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300353 " relocation symbol.\n", machine->pid);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800354}
355
Frederic Weisbecker98402802010-05-02 22:05:29 +0200356static struct perf_event_header finished_round_event = {
357 .size = sizeof(struct perf_event_header),
358 .type = PERF_RECORD_FINISHED_ROUND,
359};
360
361static void mmap_read_all(void)
362{
Peter Zijlstra0e2e63d2010-05-20 14:45:26 +0200363 int i;
Frederic Weisbecker98402802010-05-02 22:05:29 +0200364
Arnaldo Carvalho de Meloaece9482011-05-15 09:39:00 -0300365 for (i = 0; i < evsel_list->nr_mmaps; i++) {
Arnaldo Carvalho de Melo0a27d7f2011-01-14 15:50:51 -0200366 if (evsel_list->mmap[i].base)
367 mmap_read(&evsel_list->mmap[i]);
Frederic Weisbecker98402802010-05-02 22:05:29 +0200368 }
369
370 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
371 write_output(&finished_round_event, sizeof(finished_round_event));
372}
373
Arnaldo Carvalho de Melod4db3f12009-12-27 21:36:57 -0200374static int __cmd_record(int argc, const char **argv)
Peter Zijlstra16c8a102009-05-05 17:50:27 +0200375{
Peter Zijlstra97124d52009-06-02 15:52:24 +0200376 struct stat st;
Ingo Molnarabaff322009-06-02 22:59:57 +0200377 int flags;
Arnaldo Carvalho de Melo4dc0a042009-11-19 14:55:55 -0200378 int err;
Peter Zijlstra8b412662009-09-17 19:59:05 +0200379 unsigned long waking = 0;
Peter Zijlstra856e9662009-12-16 17:55:55 +0100380 int child_ready_pipe[2], go_pipe[2];
Zhang, Yanmin46be6042010-03-18 11:36:04 -0300381 const bool forks = argc > 0;
Peter Zijlstra856e9662009-12-16 17:55:55 +0100382 char buf;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300383 struct machine *machine;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200384
Andi Kleen33e49ea2011-09-15 14:31:40 -0700385 progname = argv[0];
386
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200387 page_size = sysconf(_SC_PAGE_SIZE);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200388
Peter Zijlstraf5970552009-06-18 23:22:55 +0200389 atexit(sig_atexit);
390 signal(SIGCHLD, sig_handler);
391 signal(SIGINT, sig_handler);
Arnaldo Carvalho de Melo18483b82010-12-06 15:13:38 -0200392 signal(SIGUSR1, sig_handler);
Peter Zijlstraf5970552009-06-18 23:22:55 +0200393
Arnaldo Carvalho de Melod4db3f12009-12-27 21:36:57 -0200394 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
Peter Zijlstra856e9662009-12-16 17:55:55 +0100395 perror("failed to create pipes");
396 exit(-1);
397 }
398
Franck Bui-Huud7065ad2011-01-16 17:14:45 +0100399 if (!output_name) {
400 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200401 pipe_output = true;
Franck Bui-Huud7065ad2011-01-16 17:14:45 +0100402 else
403 output_name = "perf.data";
404 }
405 if (output_name) {
406 if (!strcmp(output_name, "-"))
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200407 pipe_output = true;
Franck Bui-Huud7065ad2011-01-16 17:14:45 +0100408 else if (!stat(output_name, &st) && st.st_size) {
409 if (write_mode == WRITE_FORCE) {
410 char oldname[PATH_MAX];
411 snprintf(oldname, sizeof(oldname), "%s.old",
412 output_name);
413 unlink(oldname);
414 rename(output_name, oldname);
415 }
416 } else if (write_mode == WRITE_APPEND) {
417 write_mode = WRITE_FORCE;
Pierre Habouzit266e0e22009-08-07 14:16:01 +0200418 }
Peter Zijlstra97124d52009-06-02 15:52:24 +0200419 }
420
Xiao Guangrongf887f302010-02-04 16:46:42 +0800421 flags = O_CREAT|O_RDWR;
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200422 if (write_mode == WRITE_APPEND)
Peter Zijlstraf5970552009-06-18 23:22:55 +0200423 file_new = 0;
Ingo Molnarabaff322009-06-02 22:59:57 +0200424 else
425 flags |= O_TRUNC;
426
Tom Zanussi529870e2010-04-01 23:59:16 -0500427 if (pipe_output)
428 output = STDOUT_FILENO;
429 else
430 output = open(output_name, flags, S_IRUSR | S_IWUSR);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200431 if (output < 0) {
432 perror("failed to create output file");
433 exit(-1);
434 }
435
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200436 session = perf_session__new(output_name, O_WRONLY,
Ian Munsie21ef97f2010-12-10 14:09:16 +1100437 write_mode == WRITE_FORCE, false, NULL);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200438 if (session == NULL) {
Arnaldo Carvalho de Meloa9a70bb2009-11-17 01:18:11 -0200439 pr_err("Not enough memory for reading perf file header\n");
440 return -1;
441 }
442
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200443 if (!no_buildid)
444 perf_header__set_feat(&session->header, HEADER_BUILD_ID);
445
Arnaldo Carvalho de Melo4dc0a042009-11-19 14:55:55 -0200446 if (!file_new) {
Arnaldo Carvalho de Meloa91e5432011-03-10 11:15:54 -0300447 err = perf_session__read_header(session, output);
Arnaldo Carvalho de Melo4dc0a042009-11-19 14:55:55 -0200448 if (err < 0)
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300449 goto out_delete_session;
Arnaldo Carvalho de Melo4dc0a042009-11-19 14:55:55 -0200450 }
451
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200452 if (have_tracepoints(&evsel_list->entries))
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200453 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
Frederic Weisbecker03456a12009-10-06 23:36:47 +0200454
Stephane Eranianfbe96f22011-09-30 15:40:40 +0200455 perf_header__set_feat(&session->header, HEADER_HOSTNAME);
456 perf_header__set_feat(&session->header, HEADER_OSRELEASE);
457 perf_header__set_feat(&session->header, HEADER_ARCH);
458 perf_header__set_feat(&session->header, HEADER_CPUDESC);
459 perf_header__set_feat(&session->header, HEADER_NRCPUS);
460 perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
461 perf_header__set_feat(&session->header, HEADER_CMDLINE);
462 perf_header__set_feat(&session->header, HEADER_VERSION);
463 perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
464 perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
465 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
466 perf_header__set_feat(&session->header, HEADER_CPUID);
467
Frederic Weisbecker800cd252011-03-31 03:35:24 +0200468 /* 512 kiB: default amount of unprivileged mlocked memory */
469 if (mmap_pages == UINT_MAX)
470 mmap_pages = (512 * 1024) / page_size;
471
Arnaldo Carvalho de Melod4db3f12009-12-27 21:36:57 -0200472 if (forks) {
Zhang, Yanmin46be6042010-03-18 11:36:04 -0300473 child_pid = fork();
Borislav Petkov2fb750e2010-05-31 23:18:18 +0200474 if (child_pid < 0) {
Peter Zijlstra856e9662009-12-16 17:55:55 +0100475 perror("failed to fork");
476 exit(-1);
Jens Axboe0a5ac842009-08-12 11:18:01 +0200477 }
Peter Zijlstra856e9662009-12-16 17:55:55 +0100478
Zhang, Yanmin46be6042010-03-18 11:36:04 -0300479 if (!child_pid) {
Tom Zanussi529870e2010-04-01 23:59:16 -0500480 if (pipe_output)
481 dup2(2, 1);
Peter Zijlstra856e9662009-12-16 17:55:55 +0100482 close(child_ready_pipe[0]);
483 close(go_pipe[1]);
484 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
485
486 /*
487 * Do a dummy execvp to get the PLT entry resolved,
488 * so we avoid the resolver overhead on the real
489 * execvp call.
490 */
491 execvp("", (char **)argv);
492
493 /*
494 * Tell the parent we're ready to go
495 */
496 close(child_ready_pipe[1]);
497
498 /*
499 * Wait until the parent tells us to go.
500 */
501 if (read(go_pipe[0], &buf, 1) == -1)
502 perror("unable to read pipe");
503
504 execvp(argv[0], (char **)argv);
505
506 perror(argv[0]);
Arnaldo Carvalho de Melo18483b82010-12-06 15:13:38 -0200507 kill(getppid(), SIGUSR1);
Peter Zijlstra856e9662009-12-16 17:55:55 +0100508 exit(-1);
509 }
510
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200511 if (!record_opts.system_wide && record_opts.target_tid == -1 && record_opts.target_pid == -1)
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200512 evsel_list->threads->map[0] = child_pid;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300513
Peter Zijlstra856e9662009-12-16 17:55:55 +0100514 close(child_ready_pipe[1]);
515 close(go_pipe[0]);
516 /*
517 * wait for child to settle
518 */
519 if (read(child_ready_pipe[0], &buf, 1) == -1) {
520 perror("unable to read pipe");
521 exit(-1);
522 }
523 close(child_ready_pipe[0]);
524 }
525
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200526 open_counters(evsel_list);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200527
Arnaldo Carvalho de Melo712a4b62011-02-17 12:18:42 -0200528 /*
529 * perf_session__delete(session) will be called at atexit_header()
530 */
531 atexit(atexit_header);
532
Tom Zanussi529870e2010-04-01 23:59:16 -0500533 if (pipe_output) {
534 err = perf_header__write_pipe(output);
535 if (err < 0)
536 return err;
537 } else if (file_new) {
Arnaldo Carvalho de Meloa91e5432011-03-10 11:15:54 -0300538 err = perf_session__write_header(session, evsel_list,
539 output, false);
Arnaldo Carvalho de Melod5eed902009-11-19 14:55:56 -0200540 if (err < 0)
541 return err;
542 }
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200543
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200544 post_processing_offset = lseek(output, 0, SEEK_CUR);
545
Tom Zanussi2c46dbb2010-04-01 23:59:19 -0500546 if (pipe_output) {
Arnaldo Carvalho de Meloa91e5432011-03-10 11:15:54 -0300547 err = perf_session__synthesize_attrs(session,
548 process_synthesized_event);
Tom Zanussi2c46dbb2010-04-01 23:59:19 -0500549 if (err < 0) {
550 pr_err("Couldn't synthesize attrs.\n");
551 return err;
552 }
Tom Zanussicd19a032010-04-01 23:59:20 -0500553
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200554 err = perf_event__synthesize_event_types(process_synthesized_event,
555 session);
Tom Zanussicd19a032010-04-01 23:59:20 -0500556 if (err < 0) {
557 pr_err("Couldn't synthesize event_types.\n");
558 return err;
559 }
Tom Zanussi92155452010-04-01 23:59:21 -0500560
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200561 if (have_tracepoints(&evsel_list->entries)) {
Tom Zanussi63e0c772010-05-03 00:14:48 -0500562 /*
563 * FIXME err <= 0 here actually means that
564 * there were no tracepoints so its not really
565 * an error, just that we don't need to
566 * synthesize anything. We really have to
567 * return this more properly and also
568 * propagate errors that now are calling die()
569 */
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200570 err = perf_event__synthesize_tracing_data(output, evsel_list,
571 process_synthesized_event,
572 session);
Tom Zanussi63e0c772010-05-03 00:14:48 -0500573 if (err <= 0) {
574 pr_err("Couldn't record tracing data.\n");
575 return err;
576 }
Arnaldo Carvalho de Melo2c9faa02010-05-02 13:37:24 -0300577 advance_output(err);
Tom Zanussi63e0c772010-05-03 00:14:48 -0500578 }
Tom Zanussi2c46dbb2010-04-01 23:59:19 -0500579 }
580
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300581 machine = perf_session__find_host_machine(session);
582 if (!machine) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800583 pr_err("Couldn't find native kernel information.\n");
584 return -1;
585 }
586
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200587 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
588 session, machine, "_text");
Arnaldo Carvalho de Melo70162132010-03-30 18:27:39 -0300589 if (err < 0)
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200590 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
591 session, machine, "_stext");
Arnaldo Carvalho de Meloc1a3a4b2010-11-22 14:01:55 -0200592 if (err < 0)
593 pr_err("Couldn't record kernel reference relocation symbol\n"
594 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
595 "Check /proc/kallsyms permission or run as root.\n");
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200596
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200597 err = perf_event__synthesize_modules(process_synthesized_event,
598 session, machine);
Arnaldo Carvalho de Meloc1a3a4b2010-11-22 14:01:55 -0200599 if (err < 0)
600 pr_err("Couldn't record kernel module information.\n"
601 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
602 "Check /proc/modules permission or run as root.\n");
603
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800604 if (perf_guest)
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200605 perf_session__process_machines(session,
606 perf_event__synthesize_guest_os);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200607
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200608 if (!record_opts.system_wide)
Arnaldo Carvalho de Melo7c940c12011-02-11 11:45:54 -0200609 perf_event__synthesize_thread_map(evsel_list->threads,
610 process_synthesized_event,
611 session);
Arnaldo Carvalho de Melo234fbbf2009-10-26 19:23:18 -0200612 else
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200613 perf_event__synthesize_threads(process_synthesized_event,
614 session);
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200615
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200616 if (realtime_prio) {
617 struct sched_param param;
618
619 param.sched_priority = realtime_prio;
620 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200621 pr_err("Could not set realtime priority.\n");
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200622 exit(-1);
623 }
624 }
625
David Ahern764e16a32011-08-25 10:17:55 -0600626 perf_evlist__enable(evsel_list);
627
Peter Zijlstra856e9662009-12-16 17:55:55 +0100628 /*
629 * Let the child rip
630 */
Arnaldo Carvalho de Melod4db3f12009-12-27 21:36:57 -0200631 if (forks)
632 close(go_pipe[1]);
Peter Zijlstra856e9662009-12-16 17:55:55 +0100633
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200634 for (;;) {
Ingo Molnar2debbc82009-06-05 14:29:10 +0200635 int hits = samples;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200636
Frederic Weisbecker98402802010-05-02 22:05:29 +0200637 mmap_read_all();
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200638
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200639 if (hits == samples) {
640 if (done)
641 break;
Arnaldo Carvalho de Melo5c581042011-01-11 22:30:02 -0200642 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
Peter Zijlstra8b412662009-09-17 19:59:05 +0200643 waking++;
644 }
645
Arnaldo Carvalho de Melo4152ab32011-07-25 11:06:19 -0300646 if (done)
647 perf_evlist__disable(evsel_list);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200648 }
649
Arnaldo Carvalho de Melo18483b82010-12-06 15:13:38 -0200650 if (quiet || signr == SIGUSR1)
Arnaldo Carvalho de Melob44308f2010-10-26 15:20:09 -0200651 return 0;
652
Peter Zijlstra8b412662009-09-17 19:59:05 +0200653 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
654
Ingo Molnar021e9f42009-06-03 19:27:19 +0200655 /*
656 * Approximate RIP event size: 24 bytes.
657 */
658 fprintf(stderr,
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -0200659 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
Ingo Molnar021e9f42009-06-03 19:27:19 +0200660 (double)bytes_written / 1024.0 / 1024.0,
661 output_name,
662 bytes_written / 24);
Ingo Molnaraddc2782009-06-02 23:43:11 +0200663
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200664 return 0;
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300665
666out_delete_session:
667 perf_session__delete(session);
668 return err;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200669}
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200670
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200671static const char * const record_usage[] = {
Mike Galbraith9e0967532009-05-28 16:25:34 +0200672 "perf record [<options>] [<command>]",
673 "perf record [<options>] -- <command> [<options>]",
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200674 NULL
675};
676
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200677static bool force, append_file;
678
Tom Zanussibca647a2010-11-10 08:11:30 -0600679const struct option record_options[] = {
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200680 OPT_CALLBACK('e', "event", &evsel_list, "event",
Thomas Gleixner86847b62009-06-06 12:24:17 +0200681 "event selector. use 'perf list' to list available events",
Jiri Olsaf120f9d2011-07-14 11:25:32 +0200682 parse_events_option),
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200683 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
Li Zefanc171b552009-10-15 11:22:07 +0800684 "event filter", parse_filter),
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200685 OPT_INTEGER('p', "pid", &record_opts.target_pid,
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300686 "record events on existing process id"),
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200687 OPT_INTEGER('t', "tid", &record_opts.target_tid,
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300688 "record events on existing thread id"),
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200689 OPT_INTEGER('r', "realtime", &realtime_prio,
690 "collect data with this RT SCHED_FIFO priority"),
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200691 OPT_BOOLEAN('D', "no-delay", &record_opts.no_delay,
Kirill Smelkovacac03f2011-01-12 17:59:36 +0300692 "collect data without buffering"),
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200693 OPT_BOOLEAN('R', "raw-samples", &record_opts.raw_samples,
Frederic Weisbeckerdaac07b2009-08-13 10:27:19 +0200694 "collect raw sample records from all opened counters"),
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200695 OPT_BOOLEAN('a', "all-cpus", &record_opts.system_wide,
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200696 "system-wide collection from all CPUs"),
Ingo Molnarabaff322009-06-02 22:59:57 +0200697 OPT_BOOLEAN('A', "append", &append_file,
698 "append to the output file to do incremental profiling"),
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200699 OPT_STRING('C', "cpu", &record_opts.cpu_list, "cpu",
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200700 "list of cpus to monitor"),
Peter Zijlstra97124d52009-06-02 15:52:24 +0200701 OPT_BOOLEAN('f', "force", &force,
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200702 "overwrite existing data file (deprecated)"),
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200703 OPT_U64('c', "count", &record_opts.user_interval, "event period to sample"),
Ingo Molnarabaff322009-06-02 22:59:57 +0200704 OPT_STRING('o', "output", &output_name, "file",
705 "output file name"),
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200706 OPT_BOOLEAN('i', "no-inherit", &record_opts.no_inherit,
Stephane Eranian2e6cdf92010-05-12 10:40:01 +0200707 "child tasks do not inherit counters"),
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200708 OPT_UINTEGER('F', "freq", &record_opts.user_freq, "profile at this frequency"),
Arnaldo Carvalho de Melo19679362010-05-17 15:39:16 -0300709 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
Lin Ming43bece72011-08-17 18:42:07 +0800710 OPT_BOOLEAN(0, "group", &group,
711 "put the counters into a counter group"),
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200712 OPT_BOOLEAN('g', "call-graph", &record_opts.call_graph,
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200713 "do call-graph (stack chain/backtrace) recording"),
Ian Munsiec0555642010-04-13 18:37:33 +1000714 OPT_INCR('v', "verbose", &verbose,
Ingo Molnar3da297a2009-06-07 17:39:02 +0200715 "be more verbose (show counter open errors, etc)"),
Arnaldo Carvalho de Melob44308f2010-10-26 15:20:09 -0200716 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200717 OPT_BOOLEAN('s', "stat", &record_opts.inherit_stat,
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200718 "per thread counts"),
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200719 OPT_BOOLEAN('d', "data", &record_opts.sample_address,
Anton Blanchard4bba8282009-07-16 15:44:29 +0200720 "Sample addresses"),
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200721 OPT_BOOLEAN('T', "timestamp", &record_opts.sample_time, "Sample timestamps"),
722 OPT_BOOLEAN('n', "no-samples", &record_opts.no_samples,
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200723 "don't sample"),
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200724 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache,
Stephane Eraniana1ac1d32010-06-17 11:39:01 +0200725 "do not update the buildid cache"),
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200726 OPT_BOOLEAN('B', "no-buildid", &no_buildid,
727 "do not collect buildids in perf.data"),
Stephane Eranian023695d2011-02-14 11:20:01 +0200728 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
729 "monitor event in cgroup name only",
730 parse_cgroups),
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200731 OPT_END()
732};
733
Ingo Molnarf37a2912009-07-01 12:37:06 +0200734int cmd_record(int argc, const char **argv, const char *prefix __used)
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200735{
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200736 int err = -ENOMEM;
737 struct perf_evsel *pos;
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200738
Stephane Eranianfbe96f22011-09-30 15:40:40 +0200739 perf_header__set_cmdline(argc, argv);
740
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200741 evsel_list = perf_evlist__new(NULL, NULL);
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200742 if (evsel_list == NULL)
743 return -ENOMEM;
744
Tom Zanussibca647a2010-11-10 08:11:30 -0600745 argc = parse_options(argc, argv, record_options, record_usage,
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -0200746 PARSE_OPT_STOP_AT_NON_OPTION);
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200747 if (!argc && record_opts.target_pid == -1 && record_opts.target_tid == -1 &&
748 !record_opts.system_wide && !record_opts.cpu_list)
Tom Zanussibca647a2010-11-10 08:11:30 -0600749 usage_with_options(record_usage, record_options);
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200750
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200751 if (force && append_file) {
752 fprintf(stderr, "Can't overwrite and append at the same time."
753 " You need to choose between -f and -A");
Tom Zanussibca647a2010-11-10 08:11:30 -0600754 usage_with_options(record_usage, record_options);
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200755 } else if (append_file) {
756 write_mode = WRITE_APPEND;
757 } else {
758 write_mode = WRITE_FORCE;
759 }
760
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200761 if (nr_cgroups && !record_opts.system_wide) {
Stephane Eranian023695d2011-02-14 11:20:01 +0200762 fprintf(stderr, "cgroup monitoring only available in"
763 " system-wide mode\n");
764 usage_with_options(record_usage, record_options);
765 }
766
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -0200767 symbol__init();
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200768
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -0300769 if (symbol_conf.kptr_restrict)
Arnaldo Carvalho de Melo646aaea2011-05-27 11:00:41 -0300770 pr_warning(
771"WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
772"check /proc/sys/kernel/kptr_restrict.\n\n"
773"Samples in kernel functions may not be resolved if a suitable vmlinux\n"
774"file is not found in the buildid cache or in the vmlinux path.\n\n"
775"Samples in kernel modules won't be resolved at all.\n\n"
776"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
777"even with a suitable vmlinux or kallsyms file.\n\n");
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -0300778
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200779 if (no_buildid_cache || no_buildid)
Stephane Eraniana1ac1d32010-06-17 11:39:01 +0200780 disable_buildid_cache();
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -0200781
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200782 if (evsel_list->nr_entries == 0 &&
783 perf_evlist__add_default(evsel_list) < 0) {
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200784 pr_err("Not enough memory for event selector list\n");
785 goto out_symbol_exit;
Peter Zijlstrabbd36e52009-06-11 23:11:50 +0200786 }
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200787
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200788 if (record_opts.target_pid != -1)
789 record_opts.target_tid = record_opts.target_pid;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300790
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200791 if (perf_evlist__create_maps(evsel_list, record_opts.target_pid,
792 record_opts.target_tid, record_opts.cpu_list) < 0)
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200793 usage_with_options(record_usage, record_options);
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200794
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200795 list_for_each_entry(pos, &evsel_list->entries, node) {
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200796 if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
797 evsel_list->threads->nr) < 0)
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200798 goto out_free_fd;
Arnaldo Carvalho de Meload7f4e32011-01-17 18:28:13 -0200799 if (perf_header__push_event(pos->attr.config, event_name(pos)))
800 goto out_free_fd;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300801 }
Arnaldo Carvalho de Melo5c581042011-01-11 22:30:02 -0200802
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200803 if (perf_evlist__alloc_pollfd(evsel_list) < 0)
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300804 goto out_free_fd;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300805
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200806 if (record_opts.user_interval != ULLONG_MAX)
807 record_opts.default_interval = record_opts.user_interval;
808 if (record_opts.user_freq != UINT_MAX)
809 record_opts.freq = record_opts.user_freq;
Frederic Weisbeckerf9212812010-04-14 22:09:02 +0200810
Mike Galbraith7e4ff9e2009-10-12 07:56:03 +0200811 /*
812 * User specified count overrides default frequency.
813 */
Arnaldo Carvalho de Melo0f82ebc2011-11-08 14:41:57 -0200814 if (record_opts.default_interval)
815 record_opts.freq = 0;
816 else if (record_opts.freq) {
817 record_opts.default_interval = record_opts.freq;
Mike Galbraith7e4ff9e2009-10-12 07:56:03 +0200818 } else {
819 fprintf(stderr, "frequency and count are zero, aborting\n");
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300820 err = -EINVAL;
Arnaldo Carvalho de Melo5c581042011-01-11 22:30:02 -0200821 goto out_free_fd;
Mike Galbraith7e4ff9e2009-10-12 07:56:03 +0200822 }
823
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300824 err = __cmd_record(argc, argv);
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300825out_free_fd:
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200826 perf_evlist__delete_maps(evsel_list);
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -0300827out_symbol_exit:
828 symbol__exit();
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300829 return err;
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200830}