perf tools: Pass tool context in the the perf_event_ops functions
[linux-2.6-block.git] / tools / perf / builtin-record.c
CommitLineData
abaff32a 1/*
bf9e1876
IM
2 * 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.
abaff32a 7 */
b8f46c5a
XG
8#define _FILE_OFFSET_BITS 64
9
16f762a2 10#include "builtin.h"
bf9e1876
IM
11
12#include "perf.h"
13
6122e4e4 14#include "util/build-id.h"
6eda5838 15#include "util/util.h"
0e9b20b8 16#include "util/parse-options.h"
8ad8db37 17#include "util/parse-events.h"
6eda5838 18
7c6a1c65 19#include "util/header.h"
66e274f3 20#include "util/event.h"
361c99a6 21#include "util/evlist.h"
69aad6f1 22#include "util/evsel.h"
8f28827a 23#include "util/debug.h"
94c744b6 24#include "util/session.h"
8d06367f 25#include "util/symbol.h"
a12b51c4 26#include "util/cpumap.h"
fd78260b 27#include "util/thread_map.h"
7c6a1c65 28
97124d5e 29#include <unistd.h>
de9ac07b 30#include <sched.h>
a41794cd 31#include <sys/mman.h>
de9ac07b 32
7865e817
FW
33enum write_mode_t {
34 WRITE_FORCE,
35 WRITE_APPEND
36};
37
d20deb64
ACM
38struct perf_record {
39 struct perf_event_ops ops;
40 struct perf_record_opts opts;
41 u64 bytes_written;
42 const char *output_name;
43 struct perf_evlist *evlist;
44 struct perf_session *session;
45 const char *progname;
46 int output;
47 unsigned int page_size;
48 int realtime_prio;
49 enum write_mode_t write_mode;
50 bool no_buildid;
51 bool no_buildid_cache;
52 bool force;
53 bool file_new;
54 bool append_file;
55 long samples;
56 off_t post_processing_offset;
0f82ebc4 57};
a21ca2ca 58
d20deb64 59static void advance_output(struct perf_record *rec, size_t size)
9215545e 60{
d20deb64 61 rec->bytes_written += size;
9215545e
TZ
62}
63
d20deb64 64static void write_output(struct perf_record *rec, void *buf, size_t size)
f5970550
PZ
65{
66 while (size) {
d20deb64 67 int ret = write(rec->output, buf, size);
f5970550
PZ
68
69 if (ret < 0)
70 die("failed to write");
71
72 size -= ret;
73 buf += ret;
74
d20deb64 75 rec->bytes_written += ret;
f5970550
PZ
76 }
77}
78
d20deb64
ACM
79static int process_synthesized_event(struct perf_event_ops *ops,
80 union perf_event *event,
8d50e5b4 81 struct perf_sample *sample __used,
d8f66248 82 struct perf_session *self __used)
234fbbf5 83{
d20deb64
ACM
84 struct perf_record *rec = container_of(ops, struct perf_record, ops);
85 write_output(rec, event, event->header.size);
234fbbf5
ACM
86 return 0;
87}
88
d20deb64
ACM
89static void perf_record__mmap_read(struct perf_record *rec,
90 struct perf_mmap *md)
de9ac07b 91{
744bd8aa 92 unsigned int head = perf_mmap__read_head(md);
de9ac07b 93 unsigned int old = md->prev;
d20deb64 94 unsigned char *data = md->base + rec->page_size;
de9ac07b
PZ
95 unsigned long size;
96 void *buf;
de9ac07b 97
dc82009a
ACM
98 if (old == head)
99 return;
100
d20deb64 101 rec->samples++;
de9ac07b
PZ
102
103 size = head - old;
104
105 if ((old & md->mask) + size != (head & md->mask)) {
106 buf = &data[old & md->mask];
107 size = md->mask + 1 - (old & md->mask);
108 old += size;
021e9f47 109
d20deb64 110 write_output(rec, buf, size);
de9ac07b
PZ
111 }
112
113 buf = &data[old & md->mask];
114 size = head - old;
115 old += size;
021e9f47 116
d20deb64 117 write_output(rec, buf, size);
de9ac07b
PZ
118
119 md->prev = old;
115d2d89 120 perf_mmap__write_tail(md, old);
de9ac07b
PZ
121}
122
123static volatile int done = 0;
f7b7c26e 124static volatile int signr = -1;
33e49ea7 125static volatile int child_finished = 0;
de9ac07b 126
16c8a109 127static void sig_handler(int sig)
de9ac07b 128{
33e49ea7
AK
129 if (sig == SIGCHLD)
130 child_finished = 1;
131
16c8a109 132 done = 1;
f7b7c26e
PZ
133 signr = sig;
134}
135
d20deb64 136static void perf_record__sig_exit(int exit_status __used, void *arg)
f7b7c26e 137{
d20deb64 138 struct perf_record *rec = arg;
33e49ea7
AK
139 int status;
140
d20deb64 141 if (rec->evlist->workload.pid > 0) {
33e49ea7 142 if (!child_finished)
d20deb64 143 kill(rec->evlist->workload.pid, SIGTERM);
33e49ea7
AK
144
145 wait(&status);
146 if (WIFSIGNALED(status))
d20deb64 147 psignal(WTERMSIG(status), rec->progname);
33e49ea7 148 }
933da83a 149
18483b81 150 if (signr == -1 || signr == SIGUSR1)
f7b7c26e
PZ
151 return;
152
153 signal(signr, SIG_DFL);
154 kill(getpid(), signr);
de9ac07b
PZ
155}
156
a91e5431
ACM
157static bool perf_evlist__equal(struct perf_evlist *evlist,
158 struct perf_evlist *other)
159{
160 struct perf_evsel *pos, *pair;
161
162 if (evlist->nr_entries != other->nr_entries)
163 return false;
164
165 pair = list_entry(other->entries.next, struct perf_evsel, node);
166
167 list_for_each_entry(pos, &evlist->entries, node) {
168 if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
169 return false;
170 pair = list_entry(pair->node.next, struct perf_evsel, node);
171 }
172
173 return true;
174}
175
d20deb64 176static void perf_record__open(struct perf_record *rec)
dd7927f4 177{
727ab04e 178 struct perf_evsel *pos, *first;
d20deb64
ACM
179 struct perf_evlist *evlist = rec->evlist;
180 struct perf_session *session = rec->session;
181 struct perf_record_opts *opts = &rec->opts;
dd7927f4 182
727ab04e
ACM
183 first = list_entry(evlist->entries.next, struct perf_evsel, node);
184
d20deb64 185 perf_evlist__config_attrs(evlist, opts);
0f82ebc4 186
dd7927f4
ACM
187 list_for_each_entry(pos, &evlist->entries, node) {
188 struct perf_event_attr *attr = &pos->attr;
727ab04e 189 struct xyarray *group_fd = NULL;
dd7927f4
ACM
190 /*
191 * Check if parse_single_tracepoint_event has already asked for
192 * PERF_SAMPLE_TIME.
193 *
194 * XXX this is kludgy but short term fix for problems introduced by
195 * eac23d1c that broke 'perf script' by having different sample_types
196 * when using multiple tracepoint events when we use a perf binary
197 * that tries to use sample_id_all on an older kernel.
198 *
199 * We need to move counter creation to perf_session, support
200 * different sample_types, etc.
201 */
202 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
d6d901c2 203
d20deb64 204 if (opts->group && pos != first)
727ab04e 205 group_fd = first->fd;
dd7927f4 206retry_sample_id:
d20deb64 207 attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
dd7927f4 208try_again:
ed80f581 209 if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
d20deb64 210 opts->group, group_fd) < 0) {
d6d901c2
ZY
211 int err = errno;
212
c286c419 213 if (err == EPERM || err == EACCES) {
b8631e6e 214 ui__error_paranoid();
c286c419 215 exit(EXIT_FAILURE);
d20deb64 216 } else if (err == ENODEV && opts->cpu_list) {
d6d901c2
ZY
217 die("No such device - did you specify"
218 " an out-of-range profile CPU?\n");
d20deb64 219 } else if (err == EINVAL && opts->sample_id_all_avail) {
9c90a61c
ACM
220 /*
221 * Old kernel, no attr->sample_id_type_all field
222 */
d20deb64
ACM
223 opts->sample_id_all_avail = false;
224 if (!opts->sample_time && !opts->raw_samples && !time_needed)
eac23d1c
IM
225 attr->sample_type &= ~PERF_SAMPLE_TIME;
226
9c90a61c 227 goto retry_sample_id;
d6d901c2 228 }
3da297a6 229
d6d901c2
ZY
230 /*
231 * If it's cycles then fall back to hrtimer
232 * based cpu-clock-tick sw counter, which
233 * is always available even if no PMU support:
234 */
235 if (attr->type == PERF_TYPE_HARDWARE
236 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
237
238 if (verbose)
ca6a4258
DA
239 ui__warning("The cycles event is not supported, "
240 "trying to fall back to cpu-clock-ticks\n");
d6d901c2
ZY
241 attr->type = PERF_TYPE_SOFTWARE;
242 attr->config = PERF_COUNT_SW_CPU_CLOCK;
243 goto try_again;
244 }
ca6a4258
DA
245
246 if (err == ENOENT) {
247 ui__warning("The %s event is not supported.\n",
248 event_name(pos));
249 exit(EXIT_FAILURE);
250 }
251
d6d901c2 252 printf("\n");
d9cf837e 253 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
dd7927f4 254 err, strerror(err));
bfd45118
SK
255
256#if defined(__i386__) || defined(__x86_64__)
d6d901c2
ZY
257 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
258 die("No hardware sampling interrupt available."
259 " No APIC? If so then you can boot the kernel"
260 " with the \"lapic\" boot parameter to"
261 " force-enable it.\n");
bfd45118
SK
262#endif
263
d6d901c2 264 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
c171b552
LZ
265 }
266 }
a43d3f08 267
0a102479
FW
268 if (perf_evlist__set_filters(evlist)) {
269 error("failed to set filter with %d (%s)\n", errno,
270 strerror(errno));
271 exit(-1);
272 }
273
d20deb64 274 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0)
0a27d7f9
ACM
275 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
276
d20deb64 277 if (rec->file_new)
a91e5431
ACM
278 session->evlist = evlist;
279 else {
280 if (!perf_evlist__equal(session->evlist, evlist)) {
281 fprintf(stderr, "incompatible append\n");
282 exit(-1);
283 }
284 }
285
286 perf_session__update_sample_type(session);
16c8a109
PZ
287}
288
d20deb64 289static int process_buildids(struct perf_record *rec)
6122e4e4 290{
d20deb64 291 u64 size = lseek(rec->output, 0, SEEK_CUR);
6122e4e4 292
9f591fd7
ACM
293 if (size == 0)
294 return 0;
295
d20deb64
ACM
296 rec->session->fd = rec->output;
297 return __perf_session__process_events(rec->session, rec->post_processing_offset,
298 size - rec->post_processing_offset,
6122e4e4
ACM
299 size, &build_id__mark_dso_hit_ops);
300}
301
d20deb64 302static void perf_record__exit(int status __used, void *arg)
f5970550 303{
d20deb64
ACM
304 struct perf_record *rec = arg;
305
306 if (!rec->opts.pipe_output) {
307 rec->session->header.data_size += rec->bytes_written;
308
309 if (!rec->no_buildid)
310 process_buildids(rec);
311 perf_session__write_header(rec->session, rec->evlist,
312 rec->output, true);
313 perf_session__delete(rec->session);
314 perf_evlist__delete(rec->evlist);
d65a458b 315 symbol__exit();
c7929e47 316 }
f5970550
PZ
317}
318
8115d60c 319static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
a1645ce1
ZY
320{
321 int err;
d20deb64
ACM
322 struct perf_event_ops *ops = data;
323 struct perf_record *rec = container_of(ops, struct perf_record, ops);
324 struct perf_session *psession = rec->session;
a1645ce1 325
23346f21 326 if (machine__is_host(machine))
a1645ce1
ZY
327 return;
328
329 /*
330 *As for guest kernel when processing subcommand record&report,
331 *we arrange module mmap prior to guest kernel mmap and trigger
332 *a preload dso because default guest module symbols are loaded
333 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
334 *method is used to avoid symbol missing when the first addr is
335 *in module instead of in guest kernel.
336 */
d20deb64 337 err = perf_event__synthesize_modules(ops, process_synthesized_event,
8115d60c 338 psession, machine);
a1645ce1
ZY
339 if (err < 0)
340 pr_err("Couldn't record guest kernel [%d]'s reference"
23346f21 341 " relocation symbol.\n", machine->pid);
a1645ce1 342
a1645ce1
ZY
343 /*
344 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
345 * have no _text sometimes.
346 */
d20deb64 347 err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
8115d60c 348 psession, machine, "_text");
a1645ce1 349 if (err < 0)
d20deb64 350 err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
8115d60c
ACM
351 psession, machine,
352 "_stext");
a1645ce1
ZY
353 if (err < 0)
354 pr_err("Couldn't record guest kernel [%d]'s reference"
23346f21 355 " relocation symbol.\n", machine->pid);
a1645ce1
ZY
356}
357
98402807
FW
358static struct perf_event_header finished_round_event = {
359 .size = sizeof(struct perf_event_header),
360 .type = PERF_RECORD_FINISHED_ROUND,
361};
362
d20deb64 363static void perf_record__mmap_read_all(struct perf_record *rec)
98402807 364{
0e2e63dd 365 int i;
98402807 366
d20deb64
ACM
367 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
368 if (rec->evlist->mmap[i].base)
369 perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
98402807
FW
370 }
371
d20deb64
ACM
372 if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
373 write_output(rec, &finished_round_event, sizeof(finished_round_event));
98402807
FW
374}
375
d20deb64 376static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
16c8a109 377{
abaff32a 378 struct stat st;
abaff32a 379 int flags;
d20deb64 380 int err, output;
8b412664 381 unsigned long waking = 0;
46be604b 382 const bool forks = argc > 0;
23346f21 383 struct machine *machine;
d20deb64
ACM
384 struct perf_event_ops *ops = &rec->ops;
385 struct perf_record_opts *opts = &rec->opts;
386 struct perf_evlist *evsel_list = rec->evlist;
387 const char *output_name = rec->output_name;
388 struct perf_session *session;
de9ac07b 389
d20deb64 390 rec->progname = argv[0];
33e49ea7 391
d20deb64 392 rec->page_size = sysconf(_SC_PAGE_SIZE);
de9ac07b 393
d20deb64 394 on_exit(perf_record__sig_exit, rec);
f5970550
PZ
395 signal(SIGCHLD, sig_handler);
396 signal(SIGINT, sig_handler);
18483b81 397 signal(SIGUSR1, sig_handler);
f5970550 398
d7065adb
FBH
399 if (!output_name) {
400 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
d20deb64 401 opts->pipe_output = true;
d7065adb 402 else
d20deb64 403 rec->output_name = output_name = "perf.data";
d7065adb
FBH
404 }
405 if (output_name) {
406 if (!strcmp(output_name, "-"))
d20deb64 407 opts->pipe_output = true;
d7065adb 408 else if (!stat(output_name, &st) && st.st_size) {
d20deb64 409 if (rec->write_mode == WRITE_FORCE) {
d7065adb
FBH
410 char oldname[PATH_MAX];
411 snprintf(oldname, sizeof(oldname), "%s.old",
412 output_name);
413 unlink(oldname);
414 rename(output_name, oldname);
415 }
d20deb64
ACM
416 } else if (rec->write_mode == WRITE_APPEND) {
417 rec->write_mode = WRITE_FORCE;
266e0e21 418 }
97124d5e
PZ
419 }
420
f887f301 421 flags = O_CREAT|O_RDWR;
d20deb64
ACM
422 if (rec->write_mode == WRITE_APPEND)
423 rec->file_new = 0;
abaff32a
IM
424 else
425 flags |= O_TRUNC;
426
d20deb64 427 if (opts->pipe_output)
529870e3
TZ
428 output = STDOUT_FILENO;
429 else
430 output = open(output_name, flags, S_IRUSR | S_IWUSR);
de9ac07b
PZ
431 if (output < 0) {
432 perror("failed to create output file");
433 exit(-1);
434 }
435
d20deb64
ACM
436 rec->output = output;
437
7865e817 438 session = perf_session__new(output_name, O_WRONLY,
d20deb64 439 rec->write_mode == WRITE_FORCE, false, NULL);
94c744b6 440 if (session == NULL) {
a9a70bbc
ACM
441 pr_err("Not enough memory for reading perf file header\n");
442 return -1;
443 }
444
d20deb64
ACM
445 rec->session = session;
446
447 if (!rec->no_buildid)
baa2f6ce
ACM
448 perf_header__set_feat(&session->header, HEADER_BUILD_ID);
449
d20deb64 450 if (!rec->file_new) {
a91e5431 451 err = perf_session__read_header(session, output);
4dc0a04b 452 if (err < 0)
39d17dac 453 goto out_delete_session;
4dc0a04b
ACM
454 }
455
361c99a6 456 if (have_tracepoints(&evsel_list->entries))
94c744b6 457 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
03456a15 458
fbe96f29
SE
459 perf_header__set_feat(&session->header, HEADER_HOSTNAME);
460 perf_header__set_feat(&session->header, HEADER_OSRELEASE);
461 perf_header__set_feat(&session->header, HEADER_ARCH);
462 perf_header__set_feat(&session->header, HEADER_CPUDESC);
463 perf_header__set_feat(&session->header, HEADER_NRCPUS);
464 perf_header__set_feat(&session->header, HEADER_EVENT_DESC);
465 perf_header__set_feat(&session->header, HEADER_CMDLINE);
466 perf_header__set_feat(&session->header, HEADER_VERSION);
467 perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
468 perf_header__set_feat(&session->header, HEADER_TOTAL_MEM);
469 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
470 perf_header__set_feat(&session->header, HEADER_CPUID);
471
d4db3f16 472 if (forks) {
d20deb64 473 err = perf_evlist__prepare_workload(evsel_list, opts, argv);
35b9d88e
ACM
474 if (err < 0) {
475 pr_err("Couldn't run the workload!\n");
476 goto out_delete_session;
856e9660 477 }
856e9660
PZ
478 }
479
d20deb64 480 perf_record__open(rec);
de9ac07b 481
712a4b60 482 /*
d20deb64 483 * perf_session__delete(session) will be called at perf_record__exit()
712a4b60 484 */
d20deb64 485 on_exit(perf_record__exit, rec);
712a4b60 486
d20deb64 487 if (opts->pipe_output) {
529870e3
TZ
488 err = perf_header__write_pipe(output);
489 if (err < 0)
490 return err;
d20deb64 491 } else if (rec->file_new) {
a91e5431
ACM
492 err = perf_session__write_header(session, evsel_list,
493 output, false);
d5eed904
ACM
494 if (err < 0)
495 return err;
56b03f3c
ACM
496 }
497
d20deb64 498 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
6122e4e4 499
d20deb64
ACM
500 if (opts->pipe_output) {
501 err = perf_event__synthesize_attrs(ops, session,
502 process_synthesized_event);
2c46dbb5
TZ
503 if (err < 0) {
504 pr_err("Couldn't synthesize attrs.\n");
505 return err;
506 }
cd19a035 507
d20deb64 508 err = perf_event__synthesize_event_types(ops, process_synthesized_event,
8115d60c 509 session);
cd19a035
TZ
510 if (err < 0) {
511 pr_err("Couldn't synthesize event_types.\n");
512 return err;
513 }
9215545e 514
361c99a6 515 if (have_tracepoints(&evsel_list->entries)) {
63e0c771
TZ
516 /*
517 * FIXME err <= 0 here actually means that
518 * there were no tracepoints so its not really
519 * an error, just that we don't need to
520 * synthesize anything. We really have to
521 * return this more properly and also
522 * propagate errors that now are calling die()
523 */
d20deb64 524 err = perf_event__synthesize_tracing_data(ops, output, evsel_list,
8115d60c
ACM
525 process_synthesized_event,
526 session);
63e0c771
TZ
527 if (err <= 0) {
528 pr_err("Couldn't record tracing data.\n");
529 return err;
530 }
d20deb64 531 advance_output(rec, err);
63e0c771 532 }
2c46dbb5
TZ
533 }
534
23346f21
ACM
535 machine = perf_session__find_host_machine(session);
536 if (!machine) {
a1645ce1
ZY
537 pr_err("Couldn't find native kernel information.\n");
538 return -1;
539 }
540
d20deb64 541 err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
8115d60c 542 session, machine, "_text");
70162138 543 if (err < 0)
d20deb64 544 err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
8115d60c 545 session, machine, "_stext");
c1a3a4b9
ACM
546 if (err < 0)
547 pr_err("Couldn't record kernel reference relocation symbol\n"
548 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
549 "Check /proc/kallsyms permission or run as root.\n");
b7cece76 550
d20deb64 551 err = perf_event__synthesize_modules(ops, process_synthesized_event,
8115d60c 552 session, machine);
c1a3a4b9
ACM
553 if (err < 0)
554 pr_err("Couldn't record kernel module information.\n"
555 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
556 "Check /proc/modules permission or run as root.\n");
557
a1645ce1 558 if (perf_guest)
d20deb64 559 perf_session__process_machines(session, ops,
8115d60c 560 perf_event__synthesize_guest_os);
7c6a1c65 561
d20deb64
ACM
562 if (!opts->system_wide)
563 perf_event__synthesize_thread_map(ops, evsel_list->threads,
7c940c18
ACM
564 process_synthesized_event,
565 session);
234fbbf5 566 else
d20deb64 567 perf_event__synthesize_threads(ops, process_synthesized_event,
8115d60c 568 session);
7c6a1c65 569
d20deb64 570 if (rec->realtime_prio) {
de9ac07b
PZ
571 struct sched_param param;
572
d20deb64 573 param.sched_priority = rec->realtime_prio;
de9ac07b 574 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
6beba7ad 575 pr_err("Could not set realtime priority.\n");
de9ac07b
PZ
576 exit(-1);
577 }
578 }
579
764e16a3
DA
580 perf_evlist__enable(evsel_list);
581
856e9660
PZ
582 /*
583 * Let the child rip
584 */
d4db3f16 585 if (forks)
35b9d88e 586 perf_evlist__start_workload(evsel_list);
856e9660 587
649c48a9 588 for (;;) {
d20deb64 589 int hits = rec->samples;
de9ac07b 590
d20deb64 591 perf_record__mmap_read_all(rec);
de9ac07b 592
d20deb64 593 if (hits == rec->samples) {
649c48a9
PZ
594 if (done)
595 break;
5c581041 596 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
8b412664
PZ
597 waking++;
598 }
599
4152ab37
ACM
600 if (done)
601 perf_evlist__disable(evsel_list);
de9ac07b
PZ
602 }
603
18483b81 604 if (quiet || signr == SIGUSR1)
b44308f5
ACM
605 return 0;
606
8b412664
PZ
607 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
608
021e9f47
IM
609 /*
610 * Approximate RIP event size: 24 bytes.
611 */
612 fprintf(stderr,
9486aa38 613 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
d20deb64 614 (double)rec->bytes_written / 1024.0 / 1024.0,
021e9f47 615 output_name,
d20deb64 616 rec->bytes_written / 24);
addc2785 617
de9ac07b 618 return 0;
39d17dac
ACM
619
620out_delete_session:
621 perf_session__delete(session);
622 return err;
de9ac07b 623}
0e9b20b8 624
0e9b20b8 625static const char * const record_usage[] = {
9e096753
MG
626 "perf record [<options>] [<command>]",
627 "perf record [<options>] -- <command> [<options>]",
0e9b20b8
IM
628 NULL
629};
630
d20deb64
ACM
631/*
632 * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
633 * because we need to have access to it in perf_record__exit, that is called
634 * after cmd_record() exits, but since record_options need to be accessible to
635 * builtin-script, leave it here.
636 *
637 * At least we don't ouch it in all the other functions here directly.
638 *
639 * Just say no to tons of global variables, sigh.
640 */
641static struct perf_record record = {
642 .opts = {
643 .target_pid = -1,
644 .target_tid = -1,
645 .mmap_pages = UINT_MAX,
646 .user_freq = UINT_MAX,
647 .user_interval = ULLONG_MAX,
648 .freq = 1000,
649 .sample_id_all_avail = true,
650 },
651 .write_mode = WRITE_FORCE,
652 .file_new = true,
653};
7865e817 654
d20deb64
ACM
655/*
656 * XXX Will stay a global variable till we fix builtin-script.c to stop messing
657 * with it and switch to use the library functions in perf_evlist that came
658 * from builtin-record.c, i.e. use perf_record_opts,
659 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
660 * using pipes, etc.
661 */
bca647aa 662const struct option record_options[] = {
d20deb64 663 OPT_CALLBACK('e', "event", &record.evlist, "event",
86847b62 664 "event selector. use 'perf list' to list available events",
f120f9d5 665 parse_events_option),
d20deb64 666 OPT_CALLBACK(0, "filter", &record.evlist, "filter",
c171b552 667 "event filter", parse_filter),
d20deb64 668 OPT_INTEGER('p', "pid", &record.opts.target_pid,
d6d901c2 669 "record events on existing process id"),
d20deb64 670 OPT_INTEGER('t', "tid", &record.opts.target_tid,
d6d901c2 671 "record events on existing thread id"),
d20deb64 672 OPT_INTEGER('r', "realtime", &record.realtime_prio,
0e9b20b8 673 "collect data with this RT SCHED_FIFO priority"),
d20deb64 674 OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
acac03fa 675 "collect data without buffering"),
d20deb64 676 OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
daac07b2 677 "collect raw sample records from all opened counters"),
d20deb64 678 OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
0e9b20b8 679 "system-wide collection from all CPUs"),
d20deb64 680 OPT_BOOLEAN('A', "append", &record.append_file,
abaff32a 681 "append to the output file to do incremental profiling"),
d20deb64 682 OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
c45c6ea2 683 "list of cpus to monitor"),
d20deb64 684 OPT_BOOLEAN('f', "force", &record.force,
7865e817 685 "overwrite existing data file (deprecated)"),
d20deb64
ACM
686 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
687 OPT_STRING('o', "output", &record.output_name, "file",
abaff32a 688 "output file name"),
d20deb64 689 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
2e6cdf99 690 "child tasks do not inherit counters"),
d20deb64
ACM
691 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
692 OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
01c2d99b 693 "number of mmap data pages"),
d20deb64 694 OPT_BOOLEAN(0, "group", &record.opts.group,
43bece79 695 "put the counters into a counter group"),
d20deb64 696 OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
3efa1cc9 697 "do call-graph (stack chain/backtrace) recording"),
c0555642 698 OPT_INCR('v', "verbose", &verbose,
3da297a6 699 "be more verbose (show counter open errors, etc)"),
b44308f5 700 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
d20deb64 701 OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
649c48a9 702 "per thread counts"),
d20deb64 703 OPT_BOOLEAN('d', "data", &record.opts.sample_address,
4bba828d 704 "Sample addresses"),
d20deb64
ACM
705 OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
706 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
649c48a9 707 "don't sample"),
d20deb64 708 OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
a1ac1d3c 709 "do not update the buildid cache"),
d20deb64 710 OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
baa2f6ce 711 "do not collect buildids in perf.data"),
d20deb64 712 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
023695d9
SE
713 "monitor event in cgroup name only",
714 parse_cgroups),
0e9b20b8
IM
715 OPT_END()
716};
717
f37a291c 718int cmd_record(int argc, const char **argv, const char *prefix __used)
0e9b20b8 719{
69aad6f1
ACM
720 int err = -ENOMEM;
721 struct perf_evsel *pos;
d20deb64
ACM
722 struct perf_evlist *evsel_list;
723 struct perf_record *rec = &record;
0e9b20b8 724
fbe96f29
SE
725 perf_header__set_cmdline(argc, argv);
726
7e2ed097 727 evsel_list = perf_evlist__new(NULL, NULL);
361c99a6
ACM
728 if (evsel_list == NULL)
729 return -ENOMEM;
730
d20deb64
ACM
731 rec->evlist = evsel_list;
732
bca647aa 733 argc = parse_options(argc, argv, record_options, record_usage,
655000e7 734 PARSE_OPT_STOP_AT_NON_OPTION);
d20deb64
ACM
735 if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
736 !rec->opts.system_wide && !rec->opts.cpu_list)
bca647aa 737 usage_with_options(record_usage, record_options);
0e9b20b8 738
d20deb64 739 if (rec->force && rec->append_file) {
7865e817
FW
740 fprintf(stderr, "Can't overwrite and append at the same time."
741 " You need to choose between -f and -A");
bca647aa 742 usage_with_options(record_usage, record_options);
d20deb64
ACM
743 } else if (rec->append_file) {
744 rec->write_mode = WRITE_APPEND;
7865e817 745 } else {
d20deb64 746 rec->write_mode = WRITE_FORCE;
7865e817
FW
747 }
748
d20deb64 749 if (nr_cgroups && !rec->opts.system_wide) {
023695d9
SE
750 fprintf(stderr, "cgroup monitoring only available in"
751 " system-wide mode\n");
752 usage_with_options(record_usage, record_options);
753 }
754
655000e7 755 symbol__init();
baa2f6ce 756
ec80fde7 757 if (symbol_conf.kptr_restrict)
646aaea6
ACM
758 pr_warning(
759"WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
760"check /proc/sys/kernel/kptr_restrict.\n\n"
761"Samples in kernel functions may not be resolved if a suitable vmlinux\n"
762"file is not found in the buildid cache or in the vmlinux path.\n\n"
763"Samples in kernel modules won't be resolved at all.\n\n"
764"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
765"even with a suitable vmlinux or kallsyms file.\n\n");
ec80fde7 766
d20deb64 767 if (rec->no_buildid_cache || rec->no_buildid)
a1ac1d3c 768 disable_buildid_cache();
655000e7 769
361c99a6
ACM
770 if (evsel_list->nr_entries == 0 &&
771 perf_evlist__add_default(evsel_list) < 0) {
69aad6f1
ACM
772 pr_err("Not enough memory for event selector list\n");
773 goto out_symbol_exit;
bbd36e5e 774 }
0e9b20b8 775
d20deb64
ACM
776 if (rec->opts.target_pid != -1)
777 rec->opts.target_tid = rec->opts.target_pid;
d6d901c2 778
d20deb64
ACM
779 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
780 rec->opts.target_tid, rec->opts.cpu_list) < 0)
dd7927f4 781 usage_with_options(record_usage, record_options);
69aad6f1 782
361c99a6 783 list_for_each_entry(pos, &evsel_list->entries, node) {
7e2ed097
ACM
784 if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
785 evsel_list->threads->nr) < 0)
69aad6f1 786 goto out_free_fd;
ad7f4e3f
ACM
787 if (perf_header__push_event(pos->attr.config, event_name(pos)))
788 goto out_free_fd;
d6d901c2 789 }
5c581041 790
7e2ed097 791 if (perf_evlist__alloc_pollfd(evsel_list) < 0)
39d17dac 792 goto out_free_fd;
d6d901c2 793
d20deb64
ACM
794 if (rec->opts.user_interval != ULLONG_MAX)
795 rec->opts.default_interval = rec->opts.user_interval;
796 if (rec->opts.user_freq != UINT_MAX)
797 rec->opts.freq = rec->opts.user_freq;
f9212819 798
7e4ff9e3
MG
799 /*
800 * User specified count overrides default frequency.
801 */
d20deb64
ACM
802 if (rec->opts.default_interval)
803 rec->opts.freq = 0;
804 else if (rec->opts.freq) {
805 rec->opts.default_interval = rec->opts.freq;
7e4ff9e3
MG
806 } else {
807 fprintf(stderr, "frequency and count are zero, aborting\n");
39d17dac 808 err = -EINVAL;
5c581041 809 goto out_free_fd;
7e4ff9e3
MG
810 }
811
d20deb64 812 err = __cmd_record(&record, argc, argv);
39d17dac 813out_free_fd:
7e2ed097 814 perf_evlist__delete_maps(evsel_list);
d65a458b
ACM
815out_symbol_exit:
816 symbol__exit();
39d17dac 817 return err;
0e9b20b8 818}