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