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