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.
8 #define _FILE_OFFSET_BITS 64
14 #include "util/build-id.h"
15 #include "util/util.h"
16 #include "util/parse-options.h"
17 #include "util/parse-events.h"
19 #include "util/header.h"
20 #include "util/event.h"
21 #include "util/evlist.h"
22 #include "util/evsel.h"
23 #include "util/debug.h"
24 #include "util/session.h"
25 #include "util/symbol.h"
26 #include "util/cpumap.h"
27 #include "util/thread_map.h"
38 static struct perf_record_opts record_opts
= {
41 .user_freq
= UINT_MAX
,
42 .user_interval
= ULLONG_MAX
,
44 .sample_id_all_avail
= true,
47 static unsigned int page_size
;
48 static unsigned int mmap_pages
= UINT_MAX
;
50 static const char *output_name
= NULL
;
51 static bool group
= false;
52 static int realtime_prio
= 0;
53 static enum write_mode_t write_mode
= WRITE_FORCE
;
54 static bool no_buildid
= false;
55 static bool no_buildid_cache
= false;
56 static struct perf_evlist
*evsel_list
;
58 static long samples
= 0;
59 static u64 bytes_written
= 0;
61 static int file_new
= 1;
62 static off_t post_processing_offset
;
64 static struct perf_session
*session
;
65 static const char *progname
;
67 static void advance_output(size_t size
)
69 bytes_written
+= size
;
72 static void write_output(void *buf
, size_t size
)
75 int ret
= write(output
, buf
, size
);
78 die("failed to write");
87 static int process_synthesized_event(union perf_event
*event
,
88 struct perf_sample
*sample __used
,
89 struct perf_session
*self __used
)
91 write_output(event
, event
->header
.size
);
95 static void mmap_read(struct perf_mmap
*md
)
97 unsigned int head
= perf_mmap__read_head(md
);
98 unsigned int old
= md
->prev
;
99 unsigned char *data
= md
->base
+ page_size
;
110 if ((old
& md
->mask
) + size
!= (head
& md
->mask
)) {
111 buf
= &data
[old
& md
->mask
];
112 size
= md
->mask
+ 1 - (old
& md
->mask
);
115 write_output(buf
, size
);
118 buf
= &data
[old
& md
->mask
];
122 write_output(buf
, size
);
125 perf_mmap__write_tail(md
, old
);
128 static volatile int done
= 0;
129 static volatile int signr
= -1;
130 static volatile int child_finished
= 0;
132 static void sig_handler(int sig
)
141 static void sig_atexit(void)
145 if (evsel_list
->workload
.pid
> 0) {
147 kill(evsel_list
->workload
.pid
, SIGTERM
);
150 if (WIFSIGNALED(status
))
151 psignal(WTERMSIG(status
), progname
);
154 if (signr
== -1 || signr
== SIGUSR1
)
157 signal(signr
, SIG_DFL
);
158 kill(getpid(), signr
);
161 static bool perf_evlist__equal(struct perf_evlist
*evlist
,
162 struct perf_evlist
*other
)
164 struct perf_evsel
*pos
, *pair
;
166 if (evlist
->nr_entries
!= other
->nr_entries
)
169 pair
= list_entry(other
->entries
.next
, struct perf_evsel
, node
);
171 list_for_each_entry(pos
, &evlist
->entries
, node
) {
172 if (memcmp(&pos
->attr
, &pair
->attr
, sizeof(pos
->attr
) != 0))
174 pair
= list_entry(pair
->node
.next
, struct perf_evsel
, node
);
180 static void open_counters(struct perf_evlist
*evlist
)
182 struct perf_evsel
*pos
, *first
;
184 first
= list_entry(evlist
->entries
.next
, struct perf_evsel
, node
);
186 perf_evlist__config_attrs(evlist
, &record_opts
);
188 list_for_each_entry(pos
, &evlist
->entries
, node
) {
189 struct perf_event_attr
*attr
= &pos
->attr
;
190 struct xyarray
*group_fd
= NULL
;
192 * Check if parse_single_tracepoint_event has already asked for
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.
200 * We need to move counter creation to perf_session, support
201 * different sample_types, etc.
203 bool time_needed
= attr
->sample_type
& PERF_SAMPLE_TIME
;
205 if (group
&& pos
!= first
)
206 group_fd
= first
->fd
;
208 attr
->sample_id_all
= record_opts
.sample_id_all_avail
? 1 : 0;
210 if (perf_evsel__open(pos
, evlist
->cpus
, evlist
->threads
, group
,
214 if (err
== EPERM
|| err
== EACCES
) {
215 ui__error_paranoid();
217 } else if (err
== ENODEV
&& record_opts
.cpu_list
) {
218 die("No such device - did you specify"
219 " an out-of-range profile CPU?\n");
220 } else if (err
== EINVAL
&& record_opts
.sample_id_all_avail
) {
222 * Old kernel, no attr->sample_id_type_all field
224 record_opts
.sample_id_all_avail
= false;
225 if (!record_opts
.sample_time
&& !record_opts
.raw_samples
&& !time_needed
)
226 attr
->sample_type
&= ~PERF_SAMPLE_TIME
;
228 goto retry_sample_id
;
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:
236 if (attr
->type
== PERF_TYPE_HARDWARE
237 && attr
->config
== PERF_COUNT_HW_CPU_CYCLES
) {
240 ui__warning("The cycles event is not supported, "
241 "trying to fall back to cpu-clock-ticks\n");
242 attr
->type
= PERF_TYPE_SOFTWARE
;
243 attr
->config
= PERF_COUNT_SW_CPU_CLOCK
;
248 ui__warning("The %s event is not supported.\n",
254 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
257 #if defined(__i386__) || defined(__x86_64__)
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");
265 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
269 if (perf_evlist__set_filters(evlist
)) {
270 error("failed to set filter with %d (%s)\n", errno
,
275 if (perf_evlist__mmap(evlist
, mmap_pages
, false) < 0)
276 die("failed to mmap with %d (%s)\n", errno
, strerror(errno
));
279 session
->evlist
= evlist
;
281 if (!perf_evlist__equal(session
->evlist
, evlist
)) {
282 fprintf(stderr
, "incompatible append\n");
287 perf_session__update_sample_type(session
);
290 static int process_buildids(void)
292 u64 size
= lseek(output
, 0, SEEK_CUR
);
297 session
->fd
= output
;
298 return __perf_session__process_events(session
, post_processing_offset
,
299 size
- post_processing_offset
,
300 size
, &build_id__mark_dso_hit_ops
);
303 static void atexit_header(void)
305 if (!record_opts
.pipe_output
) {
306 session
->header
.data_size
+= bytes_written
;
310 perf_session__write_header(session
, evsel_list
, output
, true);
311 perf_session__delete(session
);
312 perf_evlist__delete(evsel_list
);
317 static void perf_event__synthesize_guest_os(struct machine
*machine
, void *data
)
320 struct perf_session
*psession
= data
;
322 if (machine__is_host(machine
))
326 *As for guest kernel when processing subcommand record&report,
327 *we arrange module mmap prior to guest kernel mmap and trigger
328 *a preload dso because default guest module symbols are loaded
329 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
330 *method is used to avoid symbol missing when the first addr is
331 *in module instead of in guest kernel.
333 err
= perf_event__synthesize_modules(process_synthesized_event
,
336 pr_err("Couldn't record guest kernel [%d]'s reference"
337 " relocation symbol.\n", machine
->pid
);
340 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
341 * have no _text sometimes.
343 err
= perf_event__synthesize_kernel_mmap(process_synthesized_event
,
344 psession
, machine
, "_text");
346 err
= perf_event__synthesize_kernel_mmap(process_synthesized_event
,
350 pr_err("Couldn't record guest kernel [%d]'s reference"
351 " relocation symbol.\n", machine
->pid
);
354 static struct perf_event_header finished_round_event
= {
355 .size
= sizeof(struct perf_event_header
),
356 .type
= PERF_RECORD_FINISHED_ROUND
,
359 static void mmap_read_all(void)
363 for (i
= 0; i
< evsel_list
->nr_mmaps
; i
++) {
364 if (evsel_list
->mmap
[i
].base
)
365 mmap_read(&evsel_list
->mmap
[i
]);
368 if (perf_header__has_feat(&session
->header
, HEADER_TRACE_INFO
))
369 write_output(&finished_round_event
, sizeof(finished_round_event
));
372 static int __cmd_record(int argc
, const char **argv
)
377 unsigned long waking
= 0;
378 const bool forks
= argc
> 0;
379 struct machine
*machine
;
383 page_size
= sysconf(_SC_PAGE_SIZE
);
386 signal(SIGCHLD
, sig_handler
);
387 signal(SIGINT
, sig_handler
);
388 signal(SIGUSR1
, sig_handler
);
391 if (!fstat(STDOUT_FILENO
, &st
) && S_ISFIFO(st
.st_mode
))
392 record_opts
.pipe_output
= true;
394 output_name
= "perf.data";
397 if (!strcmp(output_name
, "-"))
398 record_opts
.pipe_output
= true;
399 else if (!stat(output_name
, &st
) && st
.st_size
) {
400 if (write_mode
== WRITE_FORCE
) {
401 char oldname
[PATH_MAX
];
402 snprintf(oldname
, sizeof(oldname
), "%s.old",
405 rename(output_name
, oldname
);
407 } else if (write_mode
== WRITE_APPEND
) {
408 write_mode
= WRITE_FORCE
;
412 flags
= O_CREAT
|O_RDWR
;
413 if (write_mode
== WRITE_APPEND
)
418 if (record_opts
.pipe_output
)
419 output
= STDOUT_FILENO
;
421 output
= open(output_name
, flags
, S_IRUSR
| S_IWUSR
);
423 perror("failed to create output file");
427 session
= perf_session__new(output_name
, O_WRONLY
,
428 write_mode
== WRITE_FORCE
, false, NULL
);
429 if (session
== NULL
) {
430 pr_err("Not enough memory for reading perf file header\n");
435 perf_header__set_feat(&session
->header
, HEADER_BUILD_ID
);
438 err
= perf_session__read_header(session
, output
);
440 goto out_delete_session
;
443 if (have_tracepoints(&evsel_list
->entries
))
444 perf_header__set_feat(&session
->header
, HEADER_TRACE_INFO
);
446 perf_header__set_feat(&session
->header
, HEADER_HOSTNAME
);
447 perf_header__set_feat(&session
->header
, HEADER_OSRELEASE
);
448 perf_header__set_feat(&session
->header
, HEADER_ARCH
);
449 perf_header__set_feat(&session
->header
, HEADER_CPUDESC
);
450 perf_header__set_feat(&session
->header
, HEADER_NRCPUS
);
451 perf_header__set_feat(&session
->header
, HEADER_EVENT_DESC
);
452 perf_header__set_feat(&session
->header
, HEADER_CMDLINE
);
453 perf_header__set_feat(&session
->header
, HEADER_VERSION
);
454 perf_header__set_feat(&session
->header
, HEADER_CPU_TOPOLOGY
);
455 perf_header__set_feat(&session
->header
, HEADER_TOTAL_MEM
);
456 perf_header__set_feat(&session
->header
, HEADER_NUMA_TOPOLOGY
);
457 perf_header__set_feat(&session
->header
, HEADER_CPUID
);
459 /* 512 kiB: default amount of unprivileged mlocked memory */
460 if (mmap_pages
== UINT_MAX
)
461 mmap_pages
= (512 * 1024) / page_size
;
464 err
= perf_evlist__prepare_workload(evsel_list
, &record_opts
, argv
);
466 pr_err("Couldn't run the workload!\n");
467 goto out_delete_session
;
471 open_counters(evsel_list
);
474 * perf_session__delete(session) will be called at atexit_header()
476 atexit(atexit_header
);
478 if (record_opts
.pipe_output
) {
479 err
= perf_header__write_pipe(output
);
482 } else if (file_new
) {
483 err
= perf_session__write_header(session
, evsel_list
,
489 post_processing_offset
= lseek(output
, 0, SEEK_CUR
);
491 if (record_opts
.pipe_output
) {
492 err
= perf_session__synthesize_attrs(session
,
493 process_synthesized_event
);
495 pr_err("Couldn't synthesize attrs.\n");
499 err
= perf_event__synthesize_event_types(process_synthesized_event
,
502 pr_err("Couldn't synthesize event_types.\n");
506 if (have_tracepoints(&evsel_list
->entries
)) {
508 * FIXME err <= 0 here actually means that
509 * there were no tracepoints so its not really
510 * an error, just that we don't need to
511 * synthesize anything. We really have to
512 * return this more properly and also
513 * propagate errors that now are calling die()
515 err
= perf_event__synthesize_tracing_data(output
, evsel_list
,
516 process_synthesized_event
,
519 pr_err("Couldn't record tracing data.\n");
526 machine
= perf_session__find_host_machine(session
);
528 pr_err("Couldn't find native kernel information.\n");
532 err
= perf_event__synthesize_kernel_mmap(process_synthesized_event
,
533 session
, machine
, "_text");
535 err
= perf_event__synthesize_kernel_mmap(process_synthesized_event
,
536 session
, machine
, "_stext");
538 pr_err("Couldn't record kernel reference relocation symbol\n"
539 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
540 "Check /proc/kallsyms permission or run as root.\n");
542 err
= perf_event__synthesize_modules(process_synthesized_event
,
545 pr_err("Couldn't record kernel module information.\n"
546 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
547 "Check /proc/modules permission or run as root.\n");
550 perf_session__process_machines(session
,
551 perf_event__synthesize_guest_os
);
553 if (!record_opts
.system_wide
)
554 perf_event__synthesize_thread_map(evsel_list
->threads
,
555 process_synthesized_event
,
558 perf_event__synthesize_threads(process_synthesized_event
,
562 struct sched_param param
;
564 param
.sched_priority
= realtime_prio
;
565 if (sched_setscheduler(0, SCHED_FIFO
, ¶m
)) {
566 pr_err("Could not set realtime priority.\n");
571 perf_evlist__enable(evsel_list
);
577 perf_evlist__start_workload(evsel_list
);
584 if (hits
== samples
) {
587 err
= poll(evsel_list
->pollfd
, evsel_list
->nr_fds
, -1);
592 perf_evlist__disable(evsel_list
);
595 if (quiet
|| signr
== SIGUSR1
)
598 fprintf(stderr
, "[ perf record: Woken up %ld times to write data ]\n", waking
);
601 * Approximate RIP event size: 24 bytes.
604 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64
" samples) ]\n",
605 (double)bytes_written
/ 1024.0 / 1024.0,
612 perf_session__delete(session
);
616 static const char * const record_usage
[] = {
617 "perf record [<options>] [<command>]",
618 "perf record [<options>] -- <command> [<options>]",
622 static bool force
, append_file
;
624 const struct option record_options
[] = {
625 OPT_CALLBACK('e', "event", &evsel_list
, "event",
626 "event selector. use 'perf list' to list available events",
627 parse_events_option
),
628 OPT_CALLBACK(0, "filter", &evsel_list
, "filter",
629 "event filter", parse_filter
),
630 OPT_INTEGER('p', "pid", &record_opts
.target_pid
,
631 "record events on existing process id"),
632 OPT_INTEGER('t', "tid", &record_opts
.target_tid
,
633 "record events on existing thread id"),
634 OPT_INTEGER('r', "realtime", &realtime_prio
,
635 "collect data with this RT SCHED_FIFO priority"),
636 OPT_BOOLEAN('D', "no-delay", &record_opts
.no_delay
,
637 "collect data without buffering"),
638 OPT_BOOLEAN('R', "raw-samples", &record_opts
.raw_samples
,
639 "collect raw sample records from all opened counters"),
640 OPT_BOOLEAN('a', "all-cpus", &record_opts
.system_wide
,
641 "system-wide collection from all CPUs"),
642 OPT_BOOLEAN('A', "append", &append_file
,
643 "append to the output file to do incremental profiling"),
644 OPT_STRING('C', "cpu", &record_opts
.cpu_list
, "cpu",
645 "list of cpus to monitor"),
646 OPT_BOOLEAN('f', "force", &force
,
647 "overwrite existing data file (deprecated)"),
648 OPT_U64('c', "count", &record_opts
.user_interval
, "event period to sample"),
649 OPT_STRING('o', "output", &output_name
, "file",
651 OPT_BOOLEAN('i', "no-inherit", &record_opts
.no_inherit
,
652 "child tasks do not inherit counters"),
653 OPT_UINTEGER('F', "freq", &record_opts
.user_freq
, "profile at this frequency"),
654 OPT_UINTEGER('m', "mmap-pages", &mmap_pages
, "number of mmap data pages"),
655 OPT_BOOLEAN(0, "group", &group
,
656 "put the counters into a counter group"),
657 OPT_BOOLEAN('g', "call-graph", &record_opts
.call_graph
,
658 "do call-graph (stack chain/backtrace) recording"),
659 OPT_INCR('v', "verbose", &verbose
,
660 "be more verbose (show counter open errors, etc)"),
661 OPT_BOOLEAN('q', "quiet", &quiet
, "don't print any message"),
662 OPT_BOOLEAN('s', "stat", &record_opts
.inherit_stat
,
663 "per thread counts"),
664 OPT_BOOLEAN('d', "data", &record_opts
.sample_address
,
666 OPT_BOOLEAN('T', "timestamp", &record_opts
.sample_time
, "Sample timestamps"),
667 OPT_BOOLEAN('n', "no-samples", &record_opts
.no_samples
,
669 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache
,
670 "do not update the buildid cache"),
671 OPT_BOOLEAN('B', "no-buildid", &no_buildid
,
672 "do not collect buildids in perf.data"),
673 OPT_CALLBACK('G', "cgroup", &evsel_list
, "name",
674 "monitor event in cgroup name only",
679 int cmd_record(int argc
, const char **argv
, const char *prefix __used
)
682 struct perf_evsel
*pos
;
684 perf_header__set_cmdline(argc
, argv
);
686 evsel_list
= perf_evlist__new(NULL
, NULL
);
687 if (evsel_list
== NULL
)
690 argc
= parse_options(argc
, argv
, record_options
, record_usage
,
691 PARSE_OPT_STOP_AT_NON_OPTION
);
692 if (!argc
&& record_opts
.target_pid
== -1 && record_opts
.target_tid
== -1 &&
693 !record_opts
.system_wide
&& !record_opts
.cpu_list
)
694 usage_with_options(record_usage
, record_options
);
696 if (force
&& append_file
) {
697 fprintf(stderr
, "Can't overwrite and append at the same time."
698 " You need to choose between -f and -A");
699 usage_with_options(record_usage
, record_options
);
700 } else if (append_file
) {
701 write_mode
= WRITE_APPEND
;
703 write_mode
= WRITE_FORCE
;
706 if (nr_cgroups
&& !record_opts
.system_wide
) {
707 fprintf(stderr
, "cgroup monitoring only available in"
708 " system-wide mode\n");
709 usage_with_options(record_usage
, record_options
);
714 if (symbol_conf
.kptr_restrict
)
716 "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n"
717 "check /proc/sys/kernel/kptr_restrict.\n\n"
718 "Samples in kernel functions may not be resolved if a suitable vmlinux\n"
719 "file is not found in the buildid cache or in the vmlinux path.\n\n"
720 "Samples in kernel modules won't be resolved at all.\n\n"
721 "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
722 "even with a suitable vmlinux or kallsyms file.\n\n");
724 if (no_buildid_cache
|| no_buildid
)
725 disable_buildid_cache();
727 if (evsel_list
->nr_entries
== 0 &&
728 perf_evlist__add_default(evsel_list
) < 0) {
729 pr_err("Not enough memory for event selector list\n");
730 goto out_symbol_exit
;
733 if (record_opts
.target_pid
!= -1)
734 record_opts
.target_tid
= record_opts
.target_pid
;
736 if (perf_evlist__create_maps(evsel_list
, record_opts
.target_pid
,
737 record_opts
.target_tid
, record_opts
.cpu_list
) < 0)
738 usage_with_options(record_usage
, record_options
);
740 list_for_each_entry(pos
, &evsel_list
->entries
, node
) {
741 if (perf_evsel__alloc_fd(pos
, evsel_list
->cpus
->nr
,
742 evsel_list
->threads
->nr
) < 0)
744 if (perf_header__push_event(pos
->attr
.config
, event_name(pos
)))
748 if (perf_evlist__alloc_pollfd(evsel_list
) < 0)
751 if (record_opts
.user_interval
!= ULLONG_MAX
)
752 record_opts
.default_interval
= record_opts
.user_interval
;
753 if (record_opts
.user_freq
!= UINT_MAX
)
754 record_opts
.freq
= record_opts
.user_freq
;
757 * User specified count overrides default frequency.
759 if (record_opts
.default_interval
)
760 record_opts
.freq
= 0;
761 else if (record_opts
.freq
) {
762 record_opts
.default_interval
= record_opts
.freq
;
764 fprintf(stderr
, "frequency and count are zero, aborting\n");
769 err
= __cmd_record(argc
, argv
);
771 perf_evlist__delete_maps(evsel_list
);