blob: 80dc5b790e4790c22b7c4f23fcbae6f45b757acb [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 Weisbecker8f288272009-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
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -020033#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
34
Frederic Weisbecker7865e812010-04-14 19:42:07 +020035enum write_mode_t {
36 WRITE_FORCE,
37 WRITE_APPEND
38};
39
Stephane Eranian3de29ca2010-05-17 12:20:43 -030040static u64 user_interval = ULLONG_MAX;
41static u64 default_interval = 0;
Ingo Molnara21ca2c2009-06-06 09:58:57 +020042
Peter Zijlstrade9ac072009-04-08 15:01:31 +020043static unsigned int page_size;
Frederic Weisbecker800cd252011-03-31 03:35:24 +020044static unsigned int mmap_pages = UINT_MAX;
Frederic Weisbeckerf9212812010-04-14 22:09:02 +020045static unsigned int user_freq = UINT_MAX;
Ingo Molnar42e59d72009-10-06 15:14:21 +020046static int freq = 1000;
Peter Zijlstrade9ac072009-04-08 15:01:31 +020047static int output;
Tom Zanussi529870e2010-04-01 23:59:16 -050048static int pipe_output = 0;
Franck Bui-Huud7065ad2011-01-16 17:14:45 +010049static const char *output_name = NULL;
Ingo Molnar42e59d72009-10-06 15:14:21 +020050static int group = 0;
Arnaldo Carvalho de Melo19679362010-05-17 15:39:16 -030051static int realtime_prio = 0;
Kirill Smelkovacac03f2011-01-12 17:59:36 +030052static bool nodelay = false;
Ian Munsiec0555642010-04-13 18:37:33 +100053static bool raw_samples = false;
Arnaldo Carvalho de Melo9c90a612010-12-02 10:25:28 -020054static bool sample_id_all_avail = true;
Ian Munsiec0555642010-04-13 18:37:33 +100055static bool system_wide = false;
Ingo Molnar42e59d72009-10-06 15:14:21 +020056static pid_t target_pid = -1;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -030057static pid_t target_tid = -1;
Ingo Molnar42e59d72009-10-06 15:14:21 +020058static pid_t child_pid = -1;
Stephane Eranian2e6cdf92010-05-12 10:40:01 +020059static bool no_inherit = false;
Frederic Weisbecker7865e812010-04-14 19:42:07 +020060static enum write_mode_t write_mode = WRITE_FORCE;
Ian Munsiec0555642010-04-13 18:37:33 +100061static bool call_graph = false;
62static bool inherit_stat = false;
63static bool no_samples = false;
64static bool sample_address = false;
Arnaldo Carvalho de Melo9c90a612010-12-02 10:25:28 -020065static bool sample_time = false;
Stephane Eraniana1ac1d32010-06-17 11:39:01 +020066static bool no_buildid = false;
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -020067static bool no_buildid_cache = false;
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -020068static struct perf_evlist *evsel_list;
Peter Zijlstrade9ac072009-04-08 15:01:31 +020069
Ingo Molnar42e59d72009-10-06 15:14:21 +020070static long samples = 0;
Ingo Molnar42e59d72009-10-06 15:14:21 +020071static u64 bytes_written = 0;
Ingo Molnara21ca2c2009-06-06 09:58:57 +020072
Ingo Molnar42e59d72009-10-06 15:14:21 +020073static int file_new = 1;
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -020074static off_t post_processing_offset;
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020075
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -020076static struct perf_session *session;
Stephane Eranianc45c6ea2010-05-28 12:00:01 +020077static const char *cpu_list;
Peter Zijlstraf5970552009-06-18 23:22:55 +020078
Tom Zanussi92155452010-04-01 23:59:21 -050079static void advance_output(size_t size)
80{
81 bytes_written += size;
82}
83
Peter Zijlstraf5970552009-06-18 23:22:55 +020084static void write_output(void *buf, size_t size)
85{
86 while (size) {
87 int ret = write(output, buf, size);
88
89 if (ret < 0)
90 die("failed to write");
91
92 size -= ret;
93 buf += ret;
94
95 bytes_written += ret;
96 }
97}
98
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -020099static int process_synthesized_event(union perf_event *event,
Arnaldo Carvalho de Melo8d50e5b2011-01-29 13:02:00 -0200100 struct perf_sample *sample __used,
Arnaldo Carvalho de Melod8f66242009-12-13 19:50:24 -0200101 struct perf_session *self __used)
Arnaldo Carvalho de Melo234fbbf2009-10-26 19:23:18 -0200102{
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200103 write_output(event, event->header.size);
Arnaldo Carvalho de Melo234fbbf2009-10-26 19:23:18 -0200104 return 0;
105}
106
Arnaldo Carvalho de Melo744bd8a2011-01-12 17:07:28 -0200107static void mmap_read(struct perf_mmap *md)
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200108{
Arnaldo Carvalho de Melo744bd8a2011-01-12 17:07:28 -0200109 unsigned int head = perf_mmap__read_head(md);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200110 unsigned int old = md->prev;
111 unsigned char *data = md->base + page_size;
112 unsigned long size;
113 void *buf;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200114
Arnaldo Carvalho de Melodc820092011-01-28 14:49:19 -0200115 if (old == head)
116 return;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200117
Arnaldo Carvalho de Melodc820092011-01-28 14:49:19 -0200118 samples++;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200119
120 size = head - old;
121
122 if ((old & md->mask) + size != (head & md->mask)) {
123 buf = &data[old & md->mask];
124 size = md->mask + 1 - (old & md->mask);
125 old += size;
Ingo Molnar021e9f42009-06-03 19:27:19 +0200126
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200127 write_output(buf, size);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200128 }
129
130 buf = &data[old & md->mask];
131 size = head - old;
132 old += size;
Ingo Molnar021e9f42009-06-03 19:27:19 +0200133
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200134 write_output(buf, size);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200135
136 md->prev = old;
Arnaldo Carvalho de Melo115d2d82011-01-12 17:11:53 -0200137 perf_mmap__write_tail(md, old);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200138}
139
140static volatile int done = 0;
Peter Zijlstraf7b7c262009-06-10 15:55:59 +0200141static volatile int signr = -1;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200142
Peter Zijlstra16c8a102009-05-05 17:50:27 +0200143static void sig_handler(int sig)
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200144{
Peter Zijlstra16c8a102009-05-05 17:50:27 +0200145 done = 1;
Peter Zijlstraf7b7c262009-06-10 15:55:59 +0200146 signr = sig;
147}
148
149static void sig_atexit(void)
150{
Ian Munsie5ffc8882010-06-09 18:38:00 +1000151 if (child_pid > 0)
Chris Wilson933da832009-10-04 01:35:01 +0100152 kill(child_pid, SIGTERM);
153
Arnaldo Carvalho de Melo18483b82010-12-06 15:13:38 -0200154 if (signr == -1 || signr == SIGUSR1)
Peter Zijlstraf7b7c262009-06-10 15:55:59 +0200155 return;
156
157 signal(signr, SIG_DFL);
158 kill(getpid(), signr);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200159}
160
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200161static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
162{
163 struct perf_event_attr *attr = &evsel->attr;
164 int track = !evsel->idx; /* only the first counter needs these */
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200165
Arnaldo Carvalho de Melo5d2cd902011-04-14 11:20:14 -0300166 attr->inherit = !no_inherit;
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200167 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
168 PERF_FORMAT_TOTAL_TIME_RUNNING |
169 PERF_FORMAT_ID;
Peter Zijlstra16c8a102009-05-05 17:50:27 +0200170
Frederic Weisbecker3a9f1312009-08-13 10:27:18 +0200171 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200172
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200173 if (evlist->nr_entries > 1)
Eric B Munson8907fd62010-03-05 12:51:05 -0300174 attr->sample_type |= PERF_SAMPLE_ID;
175
Frederic Weisbeckerf9212812010-04-14 22:09:02 +0200176 /*
177 * We default some events to a 1 default interval. But keep
178 * it a weak assumption overridable by the user.
179 */
180 if (!attr->sample_period || (user_freq != UINT_MAX &&
Stephane Eranian3de29ca2010-05-17 12:20:43 -0300181 user_interval != ULLONG_MAX)) {
Frederic Weisbeckerf9212812010-04-14 22:09:02 +0200182 if (freq) {
183 attr->sample_type |= PERF_SAMPLE_PERIOD;
184 attr->freq = 1;
185 attr->sample_freq = freq;
186 } else {
187 attr->sample_period = default_interval;
188 }
Ingo Molnar1dba15e2009-06-05 18:37:22 +0200189 }
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200190
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200191 if (no_samples)
192 attr->sample_freq = 0;
193
194 if (inherit_stat)
195 attr->inherit_stat = 1;
196
Eric B Munson3af9e852010-05-18 15:30:49 +0100197 if (sample_address) {
Anton Blanchard4bba8282009-07-16 15:44:29 +0200198 attr->sample_type |= PERF_SAMPLE_ADDR;
Eric B Munson3af9e852010-05-18 15:30:49 +0100199 attr->mmap_data = track;
200 }
Anton Blanchard4bba8282009-07-16 15:44:29 +0200201
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200202 if (call_graph)
203 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
204
Arun Sharmaf60f3592010-06-04 11:27:10 -0300205 if (system_wide)
206 attr->sample_type |= PERF_SAMPLE_CPU;
207
Arnaldo Carvalho de Meloa43d3f02010-12-25 12:12:25 -0200208 if (sample_id_all_avail &&
209 (sample_time || system_wide || !no_inherit || cpu_list))
Arnaldo Carvalho de Melo9c90a612010-12-02 10:25:28 -0200210 attr->sample_type |= PERF_SAMPLE_TIME;
211
Ingo Molnarcd6feee2009-09-02 20:20:38 +0200212 if (raw_samples) {
Ingo Molnar6ddf2592009-09-03 12:00:22 +0200213 attr->sample_type |= PERF_SAMPLE_TIME;
Frederic Weisbeckerdaac07b2009-08-13 10:27:19 +0200214 attr->sample_type |= PERF_SAMPLE_RAW;
Ingo Molnarcd6feee2009-09-02 20:20:38 +0200215 attr->sample_type |= PERF_SAMPLE_CPU;
216 }
Frederic Weisbeckerf413cdb2009-08-07 01:25:54 +0200217
Kirill Smelkovacac03f2011-01-12 17:59:36 +0300218 if (nodelay) {
219 attr->watermark = 0;
220 attr->wakeup_events = 1;
221 }
222
Ingo Molnara21ca2c2009-06-06 09:58:57 +0200223 attr->mmap = track;
224 attr->comm = track;
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200225
Stephane Eranian2e6cdf92010-05-12 10:40:01 +0200226 if (target_pid == -1 && target_tid == -1 && !system_wide) {
Zhang, Yanmin46be6042010-03-18 11:36:04 -0300227 attr->disabled = 1;
Eric B Munsonbedbfde2010-03-15 11:46:57 -0300228 attr->enable_on_exec = 1;
Zhang, Yanmin46be6042010-03-18 11:36:04 -0300229 }
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200230}
231
Arnaldo Carvalho de Meloa91e5432011-03-10 11:15:54 -0300232static bool perf_evlist__equal(struct perf_evlist *evlist,
233 struct perf_evlist *other)
234{
235 struct perf_evsel *pos, *pair;
236
237 if (evlist->nr_entries != other->nr_entries)
238 return false;
239
240 pair = list_entry(other->entries.next, struct perf_evsel, node);
241
242 list_for_each_entry(pos, &evlist->entries, node) {
243 if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
244 return false;
245 pair = list_entry(pair->node.next, struct perf_evsel, node);
246 }
247
248 return true;
249}
250
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200251static void open_counters(struct perf_evlist *evlist)
252{
253 struct perf_evsel *pos;
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200254
Arnaldo Carvalho de Melo5d2cd902011-04-14 11:20:14 -0300255 if (evlist->cpus->map[0] < 0)
256 no_inherit = true;
257
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200258 list_for_each_entry(pos, &evlist->entries, node) {
259 struct perf_event_attr *attr = &pos->attr;
260 /*
261 * Check if parse_single_tracepoint_event has already asked for
262 * PERF_SAMPLE_TIME.
263 *
264 * XXX this is kludgy but short term fix for problems introduced by
265 * eac23d1c that broke 'perf script' by having different sample_types
266 * when using multiple tracepoint events when we use a perf binary
267 * that tries to use sample_id_all on an older kernel.
268 *
269 * We need to move counter creation to perf_session, support
270 * different sample_types, etc.
271 */
272 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
273
274 config_attr(pos, evlist);
Arnaldo Carvalho de Melo9c90a612010-12-02 10:25:28 -0200275retry_sample_id:
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200276 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
Ingo Molnar3da297a2009-06-07 17:39:02 +0200277try_again:
Arnaldo Carvalho de Melo5d2cd902011-04-14 11:20:14 -0300278 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) {
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300279 int err = errno;
Ingo Molnarf250c0302009-06-05 13:18:41 +0200280
Arnaldo Carvalho de Meloc286c412011-03-28 09:50:11 -0300281 if (err == EPERM || err == EACCES) {
282 ui__warning_paranoid();
283 exit(EXIT_FAILURE);
284 } else if (err == ENODEV && cpu_list) {
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300285 die("No such device - did you specify"
286 " an out-of-range profile CPU?\n");
Arnaldo Carvalho de Melo9c90a612010-12-02 10:25:28 -0200287 } else if (err == EINVAL && sample_id_all_avail) {
288 /*
289 * Old kernel, no attr->sample_id_type_all field
290 */
291 sample_id_all_avail = false;
Arnaldo Carvalho de Meloa43d3f02010-12-25 12:12:25 -0200292 if (!sample_time && !raw_samples && !time_needed)
Ian Munsieeac23d12010-12-09 16:33:53 +1100293 attr->sample_type &= ~PERF_SAMPLE_TIME;
294
Arnaldo Carvalho de Melo9c90a612010-12-02 10:25:28 -0200295 goto retry_sample_id;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300296 }
Ingo Molnar3da297a2009-06-07 17:39:02 +0200297
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300298 /*
299 * If it's cycles then fall back to hrtimer
300 * based cpu-clock-tick sw counter, which
301 * is always available even if no PMU support:
302 */
303 if (attr->type == PERF_TYPE_HARDWARE
304 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
Ingo Molnar3da297a2009-06-07 17:39:02 +0200305
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300306 if (verbose)
David Ahernca6a4252011-03-25 13:11:11 -0600307 ui__warning("The cycles event is not supported, "
308 "trying to fall back to cpu-clock-ticks\n");
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300309 attr->type = PERF_TYPE_SOFTWARE;
310 attr->config = PERF_COUNT_SW_CPU_CLOCK;
311 goto try_again;
312 }
David Ahernca6a4252011-03-25 13:11:11 -0600313
314 if (err == ENOENT) {
315 ui__warning("The %s event is not supported.\n",
316 event_name(pos));
317 exit(EXIT_FAILURE);
318 }
319
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300320 printf("\n");
Corey Ashfordd9cf8372010-11-19 17:37:24 -0800321 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 -0200322 err, strerror(err));
Simon Kaempfleinbfd45112009-11-16 15:25:53 +1000323
324#if defined(__i386__) || defined(__x86_64__)
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300325 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
326 die("No hardware sampling interrupt available."
327 " No APIC? If so then you can boot the kernel"
328 " with the \"lapic\" boot parameter to"
329 " force-enable it.\n");
Simon Kaempfleinbfd45112009-11-16 15:25:53 +1000330#endif
331
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300332 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300333 }
Li Zefanc171b552009-10-15 11:22:07 +0800334 }
Arnaldo Carvalho de Meloa43d3f02010-12-25 12:12:25 -0200335
Frederic Weisbecker0a102472011-02-26 04:51:54 +0100336 if (perf_evlist__set_filters(evlist)) {
337 error("failed to set filter with %d (%s)\n", errno,
338 strerror(errno));
339 exit(-1);
340 }
341
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200342 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
Arnaldo Carvalho de Melo0a27d7f2011-01-14 15:50:51 -0200343 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
344
Arnaldo Carvalho de Meloa91e5432011-03-10 11:15:54 -0300345 if (file_new)
346 session->evlist = evlist;
347 else {
348 if (!perf_evlist__equal(session->evlist, evlist)) {
349 fprintf(stderr, "incompatible append\n");
350 exit(-1);
351 }
352 }
353
354 perf_session__update_sample_type(session);
Peter Zijlstra16c8a102009-05-05 17:50:27 +0200355}
356
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200357static int process_buildids(void)
358{
359 u64 size = lseek(output, 0, SEEK_CUR);
360
Arnaldo Carvalho de Melo9f591fd2010-03-11 15:53:11 -0300361 if (size == 0)
362 return 0;
363
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200364 session->fd = output;
365 return __perf_session__process_events(session, post_processing_offset,
366 size - post_processing_offset,
367 size, &build_id__mark_dso_hit_ops);
368}
369
Peter Zijlstraf5970552009-06-18 23:22:55 +0200370static void atexit_header(void)
371{
Tom Zanussic7929e42010-04-01 23:59:22 -0500372 if (!pipe_output) {
373 session->header.data_size += bytes_written;
Peter Zijlstraf5970552009-06-18 23:22:55 +0200374
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200375 if (!no_buildid)
376 process_buildids();
Arnaldo Carvalho de Meloa91e5432011-03-10 11:15:54 -0300377 perf_session__write_header(session, evsel_list, output, true);
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300378 perf_session__delete(session);
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200379 perf_evlist__delete(evsel_list);
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -0300380 symbol__exit();
Tom Zanussic7929e42010-04-01 23:59:22 -0500381 }
Peter Zijlstraf5970552009-06-18 23:22:55 +0200382}
383
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200384static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800385{
386 int err;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300387 struct perf_session *psession = data;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800388
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300389 if (machine__is_host(machine))
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800390 return;
391
392 /*
393 *As for guest kernel when processing subcommand record&report,
394 *we arrange module mmap prior to guest kernel mmap and trigger
395 *a preload dso because default guest module symbols are loaded
396 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
397 *method is used to avoid symbol missing when the first addr is
398 *in module instead of in guest kernel.
399 */
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200400 err = perf_event__synthesize_modules(process_synthesized_event,
401 psession, machine);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800402 if (err < 0)
403 pr_err("Couldn't record guest kernel [%d]'s reference"
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300404 " relocation symbol.\n", machine->pid);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800405
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800406 /*
407 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
408 * have no _text sometimes.
409 */
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200410 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
411 psession, machine, "_text");
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800412 if (err < 0)
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200413 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
414 psession, machine,
415 "_stext");
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800416 if (err < 0)
417 pr_err("Couldn't record guest kernel [%d]'s reference"
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300418 " relocation symbol.\n", machine->pid);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800419}
420
Frederic Weisbecker98402802010-05-02 22:05:29 +0200421static struct perf_event_header finished_round_event = {
422 .size = sizeof(struct perf_event_header),
423 .type = PERF_RECORD_FINISHED_ROUND,
424};
425
426static void mmap_read_all(void)
427{
Peter Zijlstra0e2e63d2010-05-20 14:45:26 +0200428 int i;
Frederic Weisbecker98402802010-05-02 22:05:29 +0200429
Arnaldo Carvalho de Meloaece9482011-05-15 09:39:00 -0300430 for (i = 0; i < evsel_list->nr_mmaps; i++) {
Arnaldo Carvalho de Melo0a27d7f2011-01-14 15:50:51 -0200431 if (evsel_list->mmap[i].base)
432 mmap_read(&evsel_list->mmap[i]);
Frederic Weisbecker98402802010-05-02 22:05:29 +0200433 }
434
435 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
436 write_output(&finished_round_event, sizeof(finished_round_event));
437}
438
Arnaldo Carvalho de Melod4db3f12009-12-27 21:36:57 -0200439static int __cmd_record(int argc, const char **argv)
Peter Zijlstra16c8a102009-05-05 17:50:27 +0200440{
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200441 int i;
Peter Zijlstra97124d52009-06-02 15:52:24 +0200442 struct stat st;
Ingo Molnarabaff322009-06-02 22:59:57 +0200443 int flags;
Arnaldo Carvalho de Melo4dc0a042009-11-19 14:55:55 -0200444 int err;
Peter Zijlstra8b412662009-09-17 19:59:05 +0200445 unsigned long waking = 0;
Peter Zijlstra856e9662009-12-16 17:55:55 +0100446 int child_ready_pipe[2], go_pipe[2];
Zhang, Yanmin46be6042010-03-18 11:36:04 -0300447 const bool forks = argc > 0;
Peter Zijlstra856e9662009-12-16 17:55:55 +0100448 char buf;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300449 struct machine *machine;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200450
451 page_size = sysconf(_SC_PAGE_SIZE);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200452
Peter Zijlstraf5970552009-06-18 23:22:55 +0200453 atexit(sig_atexit);
454 signal(SIGCHLD, sig_handler);
455 signal(SIGINT, sig_handler);
Arnaldo Carvalho de Melo18483b82010-12-06 15:13:38 -0200456 signal(SIGUSR1, sig_handler);
Peter Zijlstraf5970552009-06-18 23:22:55 +0200457
Arnaldo Carvalho de Melod4db3f12009-12-27 21:36:57 -0200458 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
Peter Zijlstra856e9662009-12-16 17:55:55 +0100459 perror("failed to create pipes");
460 exit(-1);
461 }
462
Franck Bui-Huud7065ad2011-01-16 17:14:45 +0100463 if (!output_name) {
464 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
465 pipe_output = 1;
466 else
467 output_name = "perf.data";
468 }
469 if (output_name) {
470 if (!strcmp(output_name, "-"))
471 pipe_output = 1;
472 else if (!stat(output_name, &st) && st.st_size) {
473 if (write_mode == WRITE_FORCE) {
474 char oldname[PATH_MAX];
475 snprintf(oldname, sizeof(oldname), "%s.old",
476 output_name);
477 unlink(oldname);
478 rename(output_name, oldname);
479 }
480 } else if (write_mode == WRITE_APPEND) {
481 write_mode = WRITE_FORCE;
Pierre Habouzit266e0e22009-08-07 14:16:01 +0200482 }
Peter Zijlstra97124d52009-06-02 15:52:24 +0200483 }
484
Xiao Guangrongf887f302010-02-04 16:46:42 +0800485 flags = O_CREAT|O_RDWR;
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200486 if (write_mode == WRITE_APPEND)
Peter Zijlstraf5970552009-06-18 23:22:55 +0200487 file_new = 0;
Ingo Molnarabaff322009-06-02 22:59:57 +0200488 else
489 flags |= O_TRUNC;
490
Tom Zanussi529870e2010-04-01 23:59:16 -0500491 if (pipe_output)
492 output = STDOUT_FILENO;
493 else
494 output = open(output_name, flags, S_IRUSR | S_IWUSR);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200495 if (output < 0) {
496 perror("failed to create output file");
497 exit(-1);
498 }
499
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200500 session = perf_session__new(output_name, O_WRONLY,
Ian Munsie21ef97f2010-12-10 14:09:16 +1100501 write_mode == WRITE_FORCE, false, NULL);
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200502 if (session == NULL) {
Arnaldo Carvalho de Meloa9a70bb2009-11-17 01:18:11 -0200503 pr_err("Not enough memory for reading perf file header\n");
504 return -1;
505 }
506
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200507 if (!no_buildid)
508 perf_header__set_feat(&session->header, HEADER_BUILD_ID);
509
Arnaldo Carvalho de Melo4dc0a042009-11-19 14:55:55 -0200510 if (!file_new) {
Arnaldo Carvalho de Meloa91e5432011-03-10 11:15:54 -0300511 err = perf_session__read_header(session, output);
Arnaldo Carvalho de Melo4dc0a042009-11-19 14:55:55 -0200512 if (err < 0)
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300513 goto out_delete_session;
Arnaldo Carvalho de Melo4dc0a042009-11-19 14:55:55 -0200514 }
515
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200516 if (have_tracepoints(&evsel_list->entries))
Arnaldo Carvalho de Melo94c744b2009-12-11 21:24:02 -0200517 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
Frederic Weisbecker03456a12009-10-06 23:36:47 +0200518
Frederic Weisbecker800cd252011-03-31 03:35:24 +0200519 /* 512 kiB: default amount of unprivileged mlocked memory */
520 if (mmap_pages == UINT_MAX)
521 mmap_pages = (512 * 1024) / page_size;
522
Arnaldo Carvalho de Melod4db3f12009-12-27 21:36:57 -0200523 if (forks) {
Zhang, Yanmin46be6042010-03-18 11:36:04 -0300524 child_pid = fork();
Borislav Petkov2fb750e2010-05-31 23:18:18 +0200525 if (child_pid < 0) {
Peter Zijlstra856e9662009-12-16 17:55:55 +0100526 perror("failed to fork");
527 exit(-1);
Jens Axboe0a5ac842009-08-12 11:18:01 +0200528 }
Peter Zijlstra856e9662009-12-16 17:55:55 +0100529
Zhang, Yanmin46be6042010-03-18 11:36:04 -0300530 if (!child_pid) {
Tom Zanussi529870e2010-04-01 23:59:16 -0500531 if (pipe_output)
532 dup2(2, 1);
Peter Zijlstra856e9662009-12-16 17:55:55 +0100533 close(child_ready_pipe[0]);
534 close(go_pipe[1]);
535 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
536
537 /*
538 * Do a dummy execvp to get the PLT entry resolved,
539 * so we avoid the resolver overhead on the real
540 * execvp call.
541 */
542 execvp("", (char **)argv);
543
544 /*
545 * Tell the parent we're ready to go
546 */
547 close(child_ready_pipe[1]);
548
549 /*
550 * Wait until the parent tells us to go.
551 */
552 if (read(go_pipe[0], &buf, 1) == -1)
553 perror("unable to read pipe");
554
555 execvp(argv[0], (char **)argv);
556
557 perror(argv[0]);
Arnaldo Carvalho de Melo18483b82010-12-06 15:13:38 -0200558 kill(getppid(), SIGUSR1);
Peter Zijlstra856e9662009-12-16 17:55:55 +0100559 exit(-1);
560 }
561
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300562 if (!system_wide && target_tid == -1 && target_pid == -1)
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200563 evsel_list->threads->map[0] = child_pid;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300564
Peter Zijlstra856e9662009-12-16 17:55:55 +0100565 close(child_ready_pipe[1]);
566 close(go_pipe[0]);
567 /*
568 * wait for child to settle
569 */
570 if (read(child_ready_pipe[0], &buf, 1) == -1) {
571 perror("unable to read pipe");
572 exit(-1);
573 }
574 close(child_ready_pipe[0]);
575 }
576
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200577 open_counters(evsel_list);
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200578
Arnaldo Carvalho de Melo712a4b62011-02-17 12:18:42 -0200579 /*
580 * perf_session__delete(session) will be called at atexit_header()
581 */
582 atexit(atexit_header);
583
Tom Zanussi529870e2010-04-01 23:59:16 -0500584 if (pipe_output) {
585 err = perf_header__write_pipe(output);
586 if (err < 0)
587 return err;
588 } else if (file_new) {
Arnaldo Carvalho de Meloa91e5432011-03-10 11:15:54 -0300589 err = perf_session__write_header(session, evsel_list,
590 output, false);
Arnaldo Carvalho de Melod5eed902009-11-19 14:55:56 -0200591 if (err < 0)
592 return err;
593 }
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200594
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -0200595 post_processing_offset = lseek(output, 0, SEEK_CUR);
596
Tom Zanussi2c46dbb2010-04-01 23:59:19 -0500597 if (pipe_output) {
Arnaldo Carvalho de Meloa91e5432011-03-10 11:15:54 -0300598 err = perf_session__synthesize_attrs(session,
599 process_synthesized_event);
Tom Zanussi2c46dbb2010-04-01 23:59:19 -0500600 if (err < 0) {
601 pr_err("Couldn't synthesize attrs.\n");
602 return err;
603 }
Tom Zanussicd19a032010-04-01 23:59:20 -0500604
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200605 err = perf_event__synthesize_event_types(process_synthesized_event,
606 session);
Tom Zanussicd19a032010-04-01 23:59:20 -0500607 if (err < 0) {
608 pr_err("Couldn't synthesize event_types.\n");
609 return err;
610 }
Tom Zanussi92155452010-04-01 23:59:21 -0500611
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200612 if (have_tracepoints(&evsel_list->entries)) {
Tom Zanussi63e0c772010-05-03 00:14:48 -0500613 /*
614 * FIXME err <= 0 here actually means that
615 * there were no tracepoints so its not really
616 * an error, just that we don't need to
617 * synthesize anything. We really have to
618 * return this more properly and also
619 * propagate errors that now are calling die()
620 */
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200621 err = perf_event__synthesize_tracing_data(output, evsel_list,
622 process_synthesized_event,
623 session);
Tom Zanussi63e0c772010-05-03 00:14:48 -0500624 if (err <= 0) {
625 pr_err("Couldn't record tracing data.\n");
626 return err;
627 }
Arnaldo Carvalho de Melo2c9faa02010-05-02 13:37:24 -0300628 advance_output(err);
Tom Zanussi63e0c772010-05-03 00:14:48 -0500629 }
Tom Zanussi2c46dbb2010-04-01 23:59:19 -0500630 }
631
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300632 machine = perf_session__find_host_machine(session);
633 if (!machine) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800634 pr_err("Couldn't find native kernel information.\n");
635 return -1;
636 }
637
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200638 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
639 session, machine, "_text");
Arnaldo Carvalho de Melo70162132010-03-30 18:27:39 -0300640 if (err < 0)
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200641 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
642 session, machine, "_stext");
Arnaldo Carvalho de Meloc1a3a4b2010-11-22 14:01:55 -0200643 if (err < 0)
644 pr_err("Couldn't record kernel reference relocation symbol\n"
645 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
646 "Check /proc/kallsyms permission or run as root.\n");
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200647
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200648 err = perf_event__synthesize_modules(process_synthesized_event,
649 session, machine);
Arnaldo Carvalho de Meloc1a3a4b2010-11-22 14:01:55 -0200650 if (err < 0)
651 pr_err("Couldn't record kernel module information.\n"
652 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
653 "Check /proc/modules permission or run as root.\n");
654
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800655 if (perf_guest)
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200656 perf_session__process_machines(session,
657 perf_event__synthesize_guest_os);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200658
Stephane Eraniancf103a12010-06-16 20:59:01 +0200659 if (!system_wide)
Arnaldo Carvalho de Melo7c940c12011-02-11 11:45:54 -0200660 perf_event__synthesize_thread_map(evsel_list->threads,
661 process_synthesized_event,
662 session);
Arnaldo Carvalho de Melo234fbbf2009-10-26 19:23:18 -0200663 else
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200664 perf_event__synthesize_threads(process_synthesized_event,
665 session);
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200666
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200667 if (realtime_prio) {
668 struct sched_param param;
669
670 param.sched_priority = realtime_prio;
671 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200672 pr_err("Could not set realtime priority.\n");
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200673 exit(-1);
674 }
675 }
676
Peter Zijlstra856e9662009-12-16 17:55:55 +0100677 /*
678 * Let the child rip
679 */
Arnaldo Carvalho de Melod4db3f12009-12-27 21:36:57 -0200680 if (forks)
681 close(go_pipe[1]);
Peter Zijlstra856e9662009-12-16 17:55:55 +0100682
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200683 for (;;) {
Ingo Molnar2debbc82009-06-05 14:29:10 +0200684 int hits = samples;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300685 int thread;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200686
Frederic Weisbecker98402802010-05-02 22:05:29 +0200687 mmap_read_all();
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200688
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200689 if (hits == samples) {
690 if (done)
691 break;
Arnaldo Carvalho de Melo5c581042011-01-11 22:30:02 -0200692 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
Peter Zijlstra8b412662009-09-17 19:59:05 +0200693 waking++;
694 }
695
696 if (done) {
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200697 for (i = 0; i < evsel_list->cpus->nr; i++) {
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200698 struct perf_evsel *pos;
699
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200700 list_for_each_entry(pos, &evsel_list->entries, node) {
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300701 for (thread = 0;
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200702 thread < evsel_list->threads->nr;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300703 thread++)
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200704 ioctl(FD(pos, i, thread),
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300705 PERF_EVENT_IOC_DISABLE);
706 }
Peter Zijlstra8b412662009-09-17 19:59:05 +0200707 }
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200708 }
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200709 }
710
Arnaldo Carvalho de Melo18483b82010-12-06 15:13:38 -0200711 if (quiet || signr == SIGUSR1)
Arnaldo Carvalho de Melob44308f2010-10-26 15:20:09 -0200712 return 0;
713
Peter Zijlstra8b412662009-09-17 19:59:05 +0200714 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
715
Ingo Molnar021e9f42009-06-03 19:27:19 +0200716 /*
717 * Approximate RIP event size: 24 bytes.
718 */
719 fprintf(stderr,
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -0200720 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
Ingo Molnar021e9f42009-06-03 19:27:19 +0200721 (double)bytes_written / 1024.0 / 1024.0,
722 output_name,
723 bytes_written / 24);
Ingo Molnaraddc2782009-06-02 23:43:11 +0200724
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200725 return 0;
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300726
727out_delete_session:
728 perf_session__delete(session);
729 return err;
Peter Zijlstrade9ac072009-04-08 15:01:31 +0200730}
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200731
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200732static const char * const record_usage[] = {
Mike Galbraith9e0967532009-05-28 16:25:34 +0200733 "perf record [<options>] [<command>]",
734 "perf record [<options>] -- <command> [<options>]",
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200735 NULL
736};
737
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200738static bool force, append_file;
739
Tom Zanussibca647a2010-11-10 08:11:30 -0600740const struct option record_options[] = {
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200741 OPT_CALLBACK('e', "event", &evsel_list, "event",
Thomas Gleixner86847b62009-06-06 12:24:17 +0200742 "event selector. use 'perf list' to list available events",
Jiri Olsaf120f9d2011-07-14 11:25:32 +0200743 parse_events_option),
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200744 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
Li Zefanc171b552009-10-15 11:22:07 +0800745 "event filter", parse_filter),
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200746 OPT_INTEGER('p', "pid", &target_pid,
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300747 "record events on existing process id"),
748 OPT_INTEGER('t', "tid", &target_tid,
749 "record events on existing thread id"),
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200750 OPT_INTEGER('r', "realtime", &realtime_prio,
751 "collect data with this RT SCHED_FIFO priority"),
Kirill Smelkovacac03f2011-01-12 17:59:36 +0300752 OPT_BOOLEAN('D', "no-delay", &nodelay,
753 "collect data without buffering"),
Frederic Weisbeckerdaac07b2009-08-13 10:27:19 +0200754 OPT_BOOLEAN('R', "raw-samples", &raw_samples,
755 "collect raw sample records from all opened counters"),
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200756 OPT_BOOLEAN('a', "all-cpus", &system_wide,
757 "system-wide collection from all CPUs"),
Ingo Molnarabaff322009-06-02 22:59:57 +0200758 OPT_BOOLEAN('A', "append", &append_file,
759 "append to the output file to do incremental profiling"),
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200760 OPT_STRING('C', "cpu", &cpu_list, "cpu",
761 "list of cpus to monitor"),
Peter Zijlstra97124d52009-06-02 15:52:24 +0200762 OPT_BOOLEAN('f', "force", &force,
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200763 "overwrite existing data file (deprecated)"),
Stephane Eranian3de29ca2010-05-17 12:20:43 -0300764 OPT_U64('c', "count", &user_interval, "event period to sample"),
Ingo Molnarabaff322009-06-02 22:59:57 +0200765 OPT_STRING('o', "output", &output_name, "file",
766 "output file name"),
Stephane Eranian2e6cdf92010-05-12 10:40:01 +0200767 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
768 "child tasks do not inherit counters"),
Arnaldo Carvalho de Melo19679362010-05-17 15:39:16 -0300769 OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"),
770 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200771 OPT_BOOLEAN('g', "call-graph", &call_graph,
772 "do call-graph (stack chain/backtrace) recording"),
Ian Munsiec0555642010-04-13 18:37:33 +1000773 OPT_INCR('v', "verbose", &verbose,
Ingo Molnar3da297a2009-06-07 17:39:02 +0200774 "be more verbose (show counter open errors, etc)"),
Arnaldo Carvalho de Melob44308f2010-10-26 15:20:09 -0200775 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200776 OPT_BOOLEAN('s', "stat", &inherit_stat,
777 "per thread counts"),
Anton Blanchard4bba8282009-07-16 15:44:29 +0200778 OPT_BOOLEAN('d', "data", &sample_address,
779 "Sample addresses"),
Arnaldo Carvalho de Melo9c90a612010-12-02 10:25:28 -0200780 OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"),
Peter Zijlstra649c48a2009-06-24 21:12:48 +0200781 OPT_BOOLEAN('n', "no-samples", &no_samples,
782 "don't sample"),
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200783 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache,
Stephane Eraniana1ac1d32010-06-17 11:39:01 +0200784 "do not update the buildid cache"),
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200785 OPT_BOOLEAN('B', "no-buildid", &no_buildid,
786 "do not collect buildids in perf.data"),
Stephane Eranian023695d2011-02-14 11:20:01 +0200787 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
788 "monitor event in cgroup name only",
789 parse_cgroups),
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200790 OPT_END()
791};
792
Ingo Molnarf37a2912009-07-01 12:37:06 +0200793int cmd_record(int argc, const char **argv, const char *prefix __used)
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200794{
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200795 int err = -ENOMEM;
796 struct perf_evsel *pos;
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200797
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200798 evsel_list = perf_evlist__new(NULL, NULL);
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200799 if (evsel_list == NULL)
800 return -ENOMEM;
801
Tom Zanussibca647a2010-11-10 08:11:30 -0600802 argc = parse_options(argc, argv, record_options, record_usage,
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -0200803 PARSE_OPT_STOP_AT_NON_OPTION);
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300804 if (!argc && target_pid == -1 && target_tid == -1 &&
Stephane Eranianc45c6ea2010-05-28 12:00:01 +0200805 !system_wide && !cpu_list)
Tom Zanussibca647a2010-11-10 08:11:30 -0600806 usage_with_options(record_usage, record_options);
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200807
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200808 if (force && append_file) {
809 fprintf(stderr, "Can't overwrite and append at the same time."
810 " You need to choose between -f and -A");
Tom Zanussibca647a2010-11-10 08:11:30 -0600811 usage_with_options(record_usage, record_options);
Frederic Weisbecker7865e812010-04-14 19:42:07 +0200812 } else if (append_file) {
813 write_mode = WRITE_APPEND;
814 } else {
815 write_mode = WRITE_FORCE;
816 }
817
Stephane Eranian023695d2011-02-14 11:20:01 +0200818 if (nr_cgroups && !system_wide) {
819 fprintf(stderr, "cgroup monitoring only available in"
820 " system-wide mode\n");
821 usage_with_options(record_usage, record_options);
822 }
823
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -0200824 symbol__init();
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200825
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -0300826 if (symbol_conf.kptr_restrict)
Arnaldo Carvalho de Melo646aaea62011-05-27 11:00:41 -0300827 pr_warning(
828"WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
829"check /proc/sys/kernel/kptr_restrict.\n\n"
830"Samples in kernel functions may not be resolved if a suitable vmlinux\n"
831"file is not found in the buildid cache or in the vmlinux path.\n\n"
832"Samples in kernel modules won't be resolved at all.\n\n"
833"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
834"even with a suitable vmlinux or kallsyms file.\n\n");
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -0300835
Arnaldo Carvalho de Melobaa2f6c2010-11-26 19:39:15 -0200836 if (no_buildid_cache || no_buildid)
Stephane Eraniana1ac1d32010-06-17 11:39:01 +0200837 disable_buildid_cache();
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -0200838
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200839 if (evsel_list->nr_entries == 0 &&
840 perf_evlist__add_default(evsel_list) < 0) {
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200841 pr_err("Not enough memory for event selector list\n");
842 goto out_symbol_exit;
Peter Zijlstrabbd36e52009-06-11 23:11:50 +0200843 }
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200844
Arnaldo Carvalho de Melo5c98d4662011-01-03 17:53:33 -0200845 if (target_pid != -1)
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300846 target_tid = target_pid;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300847
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200848 if (perf_evlist__create_maps(evsel_list, target_pid,
849 target_tid, cpu_list) < 0)
Arnaldo Carvalho de Melodd7927f2011-01-12 14:28:51 -0200850 usage_with_options(record_usage, record_options);
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200851
Arnaldo Carvalho de Melo361c99a2011-01-11 20:56:53 -0200852 list_for_each_entry(pos, &evsel_list->entries, node) {
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200853 if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
854 evsel_list->threads->nr) < 0)
Arnaldo Carvalho de Melo69aad6f2011-01-03 16:39:04 -0200855 goto out_free_fd;
Arnaldo Carvalho de Meload7f4e32011-01-17 18:28:13 -0200856 if (perf_header__push_event(pos->attr.config, event_name(pos)))
857 goto out_free_fd;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300858 }
Arnaldo Carvalho de Melo5c581042011-01-11 22:30:02 -0200859
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200860 if (perf_evlist__alloc_pollfd(evsel_list) < 0)
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300861 goto out_free_fd;
Zhang, Yanmind6d901c2010-03-18 11:36:05 -0300862
Stephane Eranian3de29ca2010-05-17 12:20:43 -0300863 if (user_interval != ULLONG_MAX)
Frederic Weisbeckerf9212812010-04-14 22:09:02 +0200864 default_interval = user_interval;
865 if (user_freq != UINT_MAX)
866 freq = user_freq;
867
Mike Galbraith7e4ff9e2009-10-12 07:56:03 +0200868 /*
869 * User specified count overrides default frequency.
870 */
871 if (default_interval)
872 freq = 0;
873 else if (freq) {
874 default_interval = freq;
875 } else {
876 fprintf(stderr, "frequency and count are zero, aborting\n");
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300877 err = -EINVAL;
Arnaldo Carvalho de Melo5c581042011-01-11 22:30:02 -0200878 goto out_free_fd;
Mike Galbraith7e4ff9e2009-10-12 07:56:03 +0200879 }
880
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300881 err = __cmd_record(argc, argv);
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300882out_free_fd:
Arnaldo Carvalho de Melo7e2ed092011-01-30 11:59:43 -0200883 perf_evlist__delete_maps(evsel_list);
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -0300884out_symbol_exit:
885 symbol__exit();
Arnaldo Carvalho de Melo39d17da2010-07-29 14:08:55 -0300886 return err;
Ingo Molnar0e9b20b2009-05-26 09:17:18 +0200887}