186470930SIngo Molnar /* 286470930SIngo Molnar * builtin-record.c 386470930SIngo Molnar * 486470930SIngo Molnar * Builtin record command: Record the profile of a workload 586470930SIngo Molnar * (or a CPU, or a PID) into the perf.data output file - for 686470930SIngo Molnar * later analysis via perf report. 786470930SIngo Molnar */ 8b8f46c5aSXiao Guangrong #define _FILE_OFFSET_BITS 64 9b8f46c5aSXiao Guangrong 1086470930SIngo Molnar #include "builtin.h" 1186470930SIngo Molnar 1286470930SIngo Molnar #include "perf.h" 1386470930SIngo Molnar 146122e4e4SArnaldo Carvalho de Melo #include "util/build-id.h" 1586470930SIngo Molnar #include "util/util.h" 1686470930SIngo Molnar #include "util/parse-options.h" 1786470930SIngo Molnar #include "util/parse-events.h" 1886470930SIngo Molnar 197c6a1c65SPeter Zijlstra #include "util/header.h" 2066e274f3SFrederic Weisbecker #include "util/event.h" 21361c99a6SArnaldo Carvalho de Melo #include "util/evlist.h" 2269aad6f1SArnaldo Carvalho de Melo #include "util/evsel.h" 238f28827aSFrederic Weisbecker #include "util/debug.h" 2494c744b6SArnaldo Carvalho de Melo #include "util/session.h" 2545694aa7SArnaldo Carvalho de Melo #include "util/tool.h" 268d06367fSArnaldo Carvalho de Melo #include "util/symbol.h" 27a12b51c4SPaul Mackerras #include "util/cpumap.h" 28fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h" 297c6a1c65SPeter Zijlstra 3086470930SIngo Molnar #include <unistd.h> 3186470930SIngo Molnar #include <sched.h> 32a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h> 3386470930SIngo Molnar 3478da39faSBernhard Rosenkraenzer #ifndef HAVE_ON_EXIT 3578da39faSBernhard Rosenkraenzer #ifndef ATEXIT_MAX 3678da39faSBernhard Rosenkraenzer #define ATEXIT_MAX 32 3778da39faSBernhard Rosenkraenzer #endif 3878da39faSBernhard Rosenkraenzer static int __on_exit_count = 0; 3978da39faSBernhard Rosenkraenzer typedef void (*on_exit_func_t) (int, void *); 4078da39faSBernhard Rosenkraenzer static on_exit_func_t __on_exit_funcs[ATEXIT_MAX]; 4178da39faSBernhard Rosenkraenzer static void *__on_exit_args[ATEXIT_MAX]; 4278da39faSBernhard Rosenkraenzer static int __exitcode = 0; 4378da39faSBernhard Rosenkraenzer static void __handle_on_exit_funcs(void); 4478da39faSBernhard Rosenkraenzer static int on_exit(on_exit_func_t function, void *arg); 4578da39faSBernhard Rosenkraenzer #define exit(x) (exit)(__exitcode = (x)) 4678da39faSBernhard Rosenkraenzer 4778da39faSBernhard Rosenkraenzer static int on_exit(on_exit_func_t function, void *arg) 4878da39faSBernhard Rosenkraenzer { 4978da39faSBernhard Rosenkraenzer if (__on_exit_count == ATEXIT_MAX) 5078da39faSBernhard Rosenkraenzer return -ENOMEM; 5178da39faSBernhard Rosenkraenzer else if (__on_exit_count == 0) 5278da39faSBernhard Rosenkraenzer atexit(__handle_on_exit_funcs); 5378da39faSBernhard Rosenkraenzer __on_exit_funcs[__on_exit_count] = function; 5478da39faSBernhard Rosenkraenzer __on_exit_args[__on_exit_count++] = arg; 5578da39faSBernhard Rosenkraenzer return 0; 5678da39faSBernhard Rosenkraenzer } 5778da39faSBernhard Rosenkraenzer 5878da39faSBernhard Rosenkraenzer static void __handle_on_exit_funcs(void) 5978da39faSBernhard Rosenkraenzer { 6078da39faSBernhard Rosenkraenzer int i; 6178da39faSBernhard Rosenkraenzer for (i = 0; i < __on_exit_count; i++) 6278da39faSBernhard Rosenkraenzer __on_exit_funcs[i] (__exitcode, __on_exit_args[i]); 6378da39faSBernhard Rosenkraenzer } 6478da39faSBernhard Rosenkraenzer #endif 6578da39faSBernhard Rosenkraenzer 667865e817SFrederic Weisbecker enum write_mode_t { 677865e817SFrederic Weisbecker WRITE_FORCE, 687865e817SFrederic Weisbecker WRITE_APPEND 697865e817SFrederic Weisbecker }; 707865e817SFrederic Weisbecker 71d20deb64SArnaldo Carvalho de Melo struct perf_record { 7245694aa7SArnaldo Carvalho de Melo struct perf_tool tool; 73d20deb64SArnaldo Carvalho de Melo struct perf_record_opts opts; 74d20deb64SArnaldo Carvalho de Melo u64 bytes_written; 75d20deb64SArnaldo Carvalho de Melo const char *output_name; 76d20deb64SArnaldo Carvalho de Melo struct perf_evlist *evlist; 77d20deb64SArnaldo Carvalho de Melo struct perf_session *session; 78d20deb64SArnaldo Carvalho de Melo const char *progname; 79d20deb64SArnaldo Carvalho de Melo int output; 80d20deb64SArnaldo Carvalho de Melo unsigned int page_size; 81d20deb64SArnaldo Carvalho de Melo int realtime_prio; 82d20deb64SArnaldo Carvalho de Melo enum write_mode_t write_mode; 83d20deb64SArnaldo Carvalho de Melo bool no_buildid; 84d20deb64SArnaldo Carvalho de Melo bool no_buildid_cache; 85d20deb64SArnaldo Carvalho de Melo bool force; 86d20deb64SArnaldo Carvalho de Melo bool file_new; 87d20deb64SArnaldo Carvalho de Melo bool append_file; 88d20deb64SArnaldo Carvalho de Melo long samples; 89d20deb64SArnaldo Carvalho de Melo off_t post_processing_offset; 900f82ebc4SArnaldo Carvalho de Melo }; 9186470930SIngo Molnar 92d20deb64SArnaldo Carvalho de Melo static void advance_output(struct perf_record *rec, size_t size) 939215545eSTom Zanussi { 94d20deb64SArnaldo Carvalho de Melo rec->bytes_written += size; 959215545eSTom Zanussi } 969215545eSTom Zanussi 978d3eca20SDavid Ahern static int write_output(struct perf_record *rec, void *buf, size_t size) 98f5970550SPeter Zijlstra { 99f5970550SPeter Zijlstra while (size) { 100d20deb64SArnaldo Carvalho de Melo int ret = write(rec->output, buf, size); 101f5970550SPeter Zijlstra 1028d3eca20SDavid Ahern if (ret < 0) { 1038d3eca20SDavid Ahern pr_err("failed to write\n"); 1048d3eca20SDavid Ahern return -1; 1058d3eca20SDavid Ahern } 106f5970550SPeter Zijlstra 107f5970550SPeter Zijlstra size -= ret; 108f5970550SPeter Zijlstra buf += ret; 109f5970550SPeter Zijlstra 110d20deb64SArnaldo Carvalho de Melo rec->bytes_written += ret; 111f5970550SPeter Zijlstra } 1128d3eca20SDavid Ahern 1138d3eca20SDavid Ahern return 0; 114f5970550SPeter Zijlstra } 115f5970550SPeter Zijlstra 11645694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool, 117d20deb64SArnaldo Carvalho de Melo union perf_event *event, 1181d037ca1SIrina Tirdea struct perf_sample *sample __maybe_unused, 1191d037ca1SIrina Tirdea struct machine *machine __maybe_unused) 120234fbbf5SArnaldo Carvalho de Melo { 12145694aa7SArnaldo Carvalho de Melo struct perf_record *rec = container_of(tool, struct perf_record, tool); 1228d3eca20SDavid Ahern if (write_output(rec, event, event->header.size) < 0) 1238d3eca20SDavid Ahern return -1; 1248d3eca20SDavid Ahern 125234fbbf5SArnaldo Carvalho de Melo return 0; 126234fbbf5SArnaldo Carvalho de Melo } 127234fbbf5SArnaldo Carvalho de Melo 1288d3eca20SDavid Ahern static int perf_record__mmap_read(struct perf_record *rec, 129d20deb64SArnaldo Carvalho de Melo struct perf_mmap *md) 13086470930SIngo Molnar { 131744bd8aaSArnaldo Carvalho de Melo unsigned int head = perf_mmap__read_head(md); 13286470930SIngo Molnar unsigned int old = md->prev; 133d20deb64SArnaldo Carvalho de Melo unsigned char *data = md->base + rec->page_size; 13486470930SIngo Molnar unsigned long size; 13586470930SIngo Molnar void *buf; 1368d3eca20SDavid Ahern int rc = 0; 13786470930SIngo Molnar 138dc82009aSArnaldo Carvalho de Melo if (old == head) 1398d3eca20SDavid Ahern return 0; 14086470930SIngo Molnar 141d20deb64SArnaldo Carvalho de Melo rec->samples++; 14286470930SIngo Molnar 14386470930SIngo Molnar size = head - old; 14486470930SIngo Molnar 14586470930SIngo Molnar if ((old & md->mask) + size != (head & md->mask)) { 14686470930SIngo Molnar buf = &data[old & md->mask]; 14786470930SIngo Molnar size = md->mask + 1 - (old & md->mask); 14886470930SIngo Molnar old += size; 14986470930SIngo Molnar 1508d3eca20SDavid Ahern if (write_output(rec, buf, size) < 0) { 1518d3eca20SDavid Ahern rc = -1; 1528d3eca20SDavid Ahern goto out; 1538d3eca20SDavid Ahern } 15486470930SIngo Molnar } 15586470930SIngo Molnar 15686470930SIngo Molnar buf = &data[old & md->mask]; 15786470930SIngo Molnar size = head - old; 15886470930SIngo Molnar old += size; 15986470930SIngo Molnar 1608d3eca20SDavid Ahern if (write_output(rec, buf, size) < 0) { 1618d3eca20SDavid Ahern rc = -1; 1628d3eca20SDavid Ahern goto out; 1638d3eca20SDavid Ahern } 16486470930SIngo Molnar 16586470930SIngo Molnar md->prev = old; 166115d2d89SArnaldo Carvalho de Melo perf_mmap__write_tail(md, old); 1678d3eca20SDavid Ahern 1688d3eca20SDavid Ahern out: 1698d3eca20SDavid Ahern return rc; 17086470930SIngo Molnar } 17186470930SIngo Molnar 17286470930SIngo Molnar static volatile int done = 0; 173f7b7c26eSPeter Zijlstra static volatile int signr = -1; 17433e49ea7SAndi Kleen static volatile int child_finished = 0; 17586470930SIngo Molnar 17686470930SIngo Molnar static void sig_handler(int sig) 17786470930SIngo Molnar { 17833e49ea7SAndi Kleen if (sig == SIGCHLD) 17933e49ea7SAndi Kleen child_finished = 1; 18033e49ea7SAndi Kleen 18186470930SIngo Molnar done = 1; 182f7b7c26eSPeter Zijlstra signr = sig; 183f7b7c26eSPeter Zijlstra } 184f7b7c26eSPeter Zijlstra 1851d037ca1SIrina Tirdea static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg) 186f7b7c26eSPeter Zijlstra { 187d20deb64SArnaldo Carvalho de Melo struct perf_record *rec = arg; 18833e49ea7SAndi Kleen int status; 18933e49ea7SAndi Kleen 190d20deb64SArnaldo Carvalho de Melo if (rec->evlist->workload.pid > 0) { 19133e49ea7SAndi Kleen if (!child_finished) 192d20deb64SArnaldo Carvalho de Melo kill(rec->evlist->workload.pid, SIGTERM); 193933da83aSChris Wilson 19433e49ea7SAndi Kleen wait(&status); 19533e49ea7SAndi Kleen if (WIFSIGNALED(status)) 196d20deb64SArnaldo Carvalho de Melo psignal(WTERMSIG(status), rec->progname); 19733e49ea7SAndi Kleen } 19833e49ea7SAndi Kleen 19918483b81SArnaldo Carvalho de Melo if (signr == -1 || signr == SIGUSR1) 200f7b7c26eSPeter Zijlstra return; 201f7b7c26eSPeter Zijlstra 202f7b7c26eSPeter Zijlstra signal(signr, SIG_DFL); 203f7b7c26eSPeter Zijlstra kill(getpid(), signr); 20486470930SIngo Molnar } 20586470930SIngo Molnar 206a91e5431SArnaldo Carvalho de Melo static bool perf_evlist__equal(struct perf_evlist *evlist, 207a91e5431SArnaldo Carvalho de Melo struct perf_evlist *other) 208a91e5431SArnaldo Carvalho de Melo { 209a91e5431SArnaldo Carvalho de Melo struct perf_evsel *pos, *pair; 210a91e5431SArnaldo Carvalho de Melo 211a91e5431SArnaldo Carvalho de Melo if (evlist->nr_entries != other->nr_entries) 212a91e5431SArnaldo Carvalho de Melo return false; 213a91e5431SArnaldo Carvalho de Melo 2140c21f736SArnaldo Carvalho de Melo pair = perf_evlist__first(other); 215a91e5431SArnaldo Carvalho de Melo 216a91e5431SArnaldo Carvalho de Melo list_for_each_entry(pos, &evlist->entries, node) { 217a91e5431SArnaldo Carvalho de Melo if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0)) 218a91e5431SArnaldo Carvalho de Melo return false; 2190c21f736SArnaldo Carvalho de Melo pair = perf_evsel__next(pair); 220a91e5431SArnaldo Carvalho de Melo } 221a91e5431SArnaldo Carvalho de Melo 222a91e5431SArnaldo Carvalho de Melo return true; 223a91e5431SArnaldo Carvalho de Melo } 224a91e5431SArnaldo Carvalho de Melo 2258d3eca20SDavid Ahern static int perf_record__open(struct perf_record *rec) 226dd7927f4SArnaldo Carvalho de Melo { 227*56e52e85SArnaldo Carvalho de Melo char msg[512]; 2286a4bb04cSJiri Olsa struct perf_evsel *pos; 229d20deb64SArnaldo Carvalho de Melo struct perf_evlist *evlist = rec->evlist; 230d20deb64SArnaldo Carvalho de Melo struct perf_session *session = rec->session; 231d20deb64SArnaldo Carvalho de Melo struct perf_record_opts *opts = &rec->opts; 2328d3eca20SDavid Ahern int rc = 0; 233dd7927f4SArnaldo Carvalho de Melo 234f77a9518SArnaldo Carvalho de Melo perf_evlist__config(evlist, opts); 235cac21425SJiri Olsa 236dd7927f4SArnaldo Carvalho de Melo list_for_each_entry(pos, &evlist->entries, node) { 2373da297a6SIngo Molnar try_again: 2386a4bb04cSJiri Olsa if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { 239*56e52e85SArnaldo Carvalho de Melo if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { 2403da297a6SIngo Molnar if (verbose) 241c0a54341SArnaldo Carvalho de Melo ui__warning("%s\n", msg); 2423da297a6SIngo Molnar goto try_again; 2433da297a6SIngo Molnar } 244ca6a4258SDavid Ahern 245*56e52e85SArnaldo Carvalho de Melo rc = -errno; 246*56e52e85SArnaldo Carvalho de Melo perf_evsel__open_strerror(pos, &opts->target, 247*56e52e85SArnaldo Carvalho de Melo errno, msg, sizeof(msg)); 248*56e52e85SArnaldo Carvalho de Melo ui__error("%s\n", msg); 2498d3eca20SDavid Ahern goto out; 2507c6a1c65SPeter Zijlstra } 2517c6a1c65SPeter Zijlstra } 2527c6a1c65SPeter Zijlstra 2531491a632SArnaldo Carvalho de Melo if (perf_evlist__apply_filters(evlist)) { 2540a102479SFrederic Weisbecker error("failed to set filter with %d (%s)\n", errno, 2550a102479SFrederic Weisbecker strerror(errno)); 2568d3eca20SDavid Ahern rc = -1; 2578d3eca20SDavid Ahern goto out; 2580a102479SFrederic Weisbecker } 2590a102479SFrederic Weisbecker 26018e60939SNelson Elhage if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { 2618d3eca20SDavid Ahern if (errno == EPERM) { 2628d3eca20SDavid Ahern pr_err("Permission error mapping pages.\n" 26318e60939SNelson Elhage "Consider increasing " 26418e60939SNelson Elhage "/proc/sys/kernel/perf_event_mlock_kb,\n" 26518e60939SNelson Elhage "or try again with a smaller value of -m/--mmap_pages.\n" 26618e60939SNelson Elhage "(current value: %d)\n", opts->mmap_pages); 2678d3eca20SDavid Ahern rc = -errno; 2680089fa98SJiri Olsa } else if (!is_power_of_2(opts->mmap_pages) && 2690089fa98SJiri Olsa (opts->mmap_pages != UINT_MAX)) { 2708d3eca20SDavid Ahern pr_err("--mmap_pages/-m value must be a power of two."); 2718d3eca20SDavid Ahern rc = -EINVAL; 2728d3eca20SDavid Ahern } else { 2738d3eca20SDavid Ahern pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); 2748d3eca20SDavid Ahern rc = -errno; 2758d3eca20SDavid Ahern } 2768d3eca20SDavid Ahern goto out; 27718e60939SNelson Elhage } 2780a27d7f9SArnaldo Carvalho de Melo 279d20deb64SArnaldo Carvalho de Melo if (rec->file_new) 280a91e5431SArnaldo Carvalho de Melo session->evlist = evlist; 281a91e5431SArnaldo Carvalho de Melo else { 282a91e5431SArnaldo Carvalho de Melo if (!perf_evlist__equal(session->evlist, evlist)) { 283a91e5431SArnaldo Carvalho de Melo fprintf(stderr, "incompatible append\n"); 2848d3eca20SDavid Ahern rc = -1; 2858d3eca20SDavid Ahern goto out; 286dd7927f4SArnaldo Carvalho de Melo } 28786470930SIngo Molnar } 28886470930SIngo Molnar 2897b56cce2SArnaldo Carvalho de Melo perf_session__set_id_hdr_size(session); 2908d3eca20SDavid Ahern out: 2918d3eca20SDavid Ahern return rc; 292a91e5431SArnaldo Carvalho de Melo } 293a91e5431SArnaldo Carvalho de Melo 294d20deb64SArnaldo Carvalho de Melo static int process_buildids(struct perf_record *rec) 2956122e4e4SArnaldo Carvalho de Melo { 296d20deb64SArnaldo Carvalho de Melo u64 size = lseek(rec->output, 0, SEEK_CUR); 2976122e4e4SArnaldo Carvalho de Melo 2989f591fd7SArnaldo Carvalho de Melo if (size == 0) 2999f591fd7SArnaldo Carvalho de Melo return 0; 3009f591fd7SArnaldo Carvalho de Melo 301d20deb64SArnaldo Carvalho de Melo rec->session->fd = rec->output; 302d20deb64SArnaldo Carvalho de Melo return __perf_session__process_events(rec->session, rec->post_processing_offset, 303d20deb64SArnaldo Carvalho de Melo size - rec->post_processing_offset, 3046122e4e4SArnaldo Carvalho de Melo size, &build_id__mark_dso_hit_ops); 3056122e4e4SArnaldo Carvalho de Melo } 3066122e4e4SArnaldo Carvalho de Melo 3078d3eca20SDavid Ahern static void perf_record__exit(int status, void *arg) 308f5970550SPeter Zijlstra { 309d20deb64SArnaldo Carvalho de Melo struct perf_record *rec = arg; 310f5970550SPeter Zijlstra 3118d3eca20SDavid Ahern if (status != 0) 3128d3eca20SDavid Ahern return; 3138d3eca20SDavid Ahern 314d20deb64SArnaldo Carvalho de Melo if (!rec->opts.pipe_output) { 315d20deb64SArnaldo Carvalho de Melo rec->session->header.data_size += rec->bytes_written; 316d20deb64SArnaldo Carvalho de Melo 317d20deb64SArnaldo Carvalho de Melo if (!rec->no_buildid) 318d20deb64SArnaldo Carvalho de Melo process_buildids(rec); 319d20deb64SArnaldo Carvalho de Melo perf_session__write_header(rec->session, rec->evlist, 320d20deb64SArnaldo Carvalho de Melo rec->output, true); 321d20deb64SArnaldo Carvalho de Melo perf_session__delete(rec->session); 322d20deb64SArnaldo Carvalho de Melo perf_evlist__delete(rec->evlist); 323d65a458bSArnaldo Carvalho de Melo symbol__exit(); 324c7929e47STom Zanussi } 325f5970550SPeter Zijlstra } 326f5970550SPeter Zijlstra 3278115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data) 328a1645ce1SZhang, Yanmin { 329a1645ce1SZhang, Yanmin int err; 33045694aa7SArnaldo Carvalho de Melo struct perf_tool *tool = data; 331a1645ce1SZhang, Yanmin 33223346f21SArnaldo Carvalho de Melo if (machine__is_host(machine)) 333a1645ce1SZhang, Yanmin return; 334a1645ce1SZhang, Yanmin 335a1645ce1SZhang, Yanmin /* 336a1645ce1SZhang, Yanmin *As for guest kernel when processing subcommand record&report, 337a1645ce1SZhang, Yanmin *we arrange module mmap prior to guest kernel mmap and trigger 338a1645ce1SZhang, Yanmin *a preload dso because default guest module symbols are loaded 339a1645ce1SZhang, Yanmin *from guest kallsyms instead of /lib/modules/XXX/XXX. This 340a1645ce1SZhang, Yanmin *method is used to avoid symbol missing when the first addr is 341a1645ce1SZhang, Yanmin *in module instead of in guest kernel. 342a1645ce1SZhang, Yanmin */ 34345694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_modules(tool, process_synthesized_event, 344743eb868SArnaldo Carvalho de Melo machine); 345a1645ce1SZhang, Yanmin if (err < 0) 346a1645ce1SZhang, Yanmin pr_err("Couldn't record guest kernel [%d]'s reference" 34723346f21SArnaldo Carvalho de Melo " relocation symbol.\n", machine->pid); 348a1645ce1SZhang, Yanmin 349a1645ce1SZhang, Yanmin /* 350a1645ce1SZhang, Yanmin * We use _stext for guest kernel because guest kernel's /proc/kallsyms 351a1645ce1SZhang, Yanmin * have no _text sometimes. 352a1645ce1SZhang, Yanmin */ 35345694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 354743eb868SArnaldo Carvalho de Melo machine, "_text"); 355a1645ce1SZhang, Yanmin if (err < 0) 35645694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 357743eb868SArnaldo Carvalho de Melo machine, "_stext"); 358a1645ce1SZhang, Yanmin if (err < 0) 359a1645ce1SZhang, Yanmin pr_err("Couldn't record guest kernel [%d]'s reference" 36023346f21SArnaldo Carvalho de Melo " relocation symbol.\n", machine->pid); 361a1645ce1SZhang, Yanmin } 362a1645ce1SZhang, Yanmin 36398402807SFrederic Weisbecker static struct perf_event_header finished_round_event = { 36498402807SFrederic Weisbecker .size = sizeof(struct perf_event_header), 36598402807SFrederic Weisbecker .type = PERF_RECORD_FINISHED_ROUND, 36698402807SFrederic Weisbecker }; 36798402807SFrederic Weisbecker 3688d3eca20SDavid Ahern static int perf_record__mmap_read_all(struct perf_record *rec) 36998402807SFrederic Weisbecker { 3700e2e63ddSPeter Zijlstra int i; 3718d3eca20SDavid Ahern int rc = 0; 37298402807SFrederic Weisbecker 373d20deb64SArnaldo Carvalho de Melo for (i = 0; i < rec->evlist->nr_mmaps; i++) { 3748d3eca20SDavid Ahern if (rec->evlist->mmap[i].base) { 3758d3eca20SDavid Ahern if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { 3768d3eca20SDavid Ahern rc = -1; 3778d3eca20SDavid Ahern goto out; 3788d3eca20SDavid Ahern } 3798d3eca20SDavid Ahern } 38098402807SFrederic Weisbecker } 38198402807SFrederic Weisbecker 3822eeaaa09SStephane Eranian if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) 3838d3eca20SDavid Ahern rc = write_output(rec, &finished_round_event, 3848d3eca20SDavid Ahern sizeof(finished_round_event)); 3858d3eca20SDavid Ahern 3868d3eca20SDavid Ahern out: 3878d3eca20SDavid Ahern return rc; 38898402807SFrederic Weisbecker } 38998402807SFrederic Weisbecker 390d20deb64SArnaldo Carvalho de Melo static int __cmd_record(struct perf_record *rec, int argc, const char **argv) 39186470930SIngo Molnar { 39286470930SIngo Molnar struct stat st; 39386470930SIngo Molnar int flags; 394781ba9d2SRobert Richter int err, output, feat; 3958b412664SPeter Zijlstra unsigned long waking = 0; 39646be604bSZhang, Yanmin const bool forks = argc > 0; 39723346f21SArnaldo Carvalho de Melo struct machine *machine; 39845694aa7SArnaldo Carvalho de Melo struct perf_tool *tool = &rec->tool; 399d20deb64SArnaldo Carvalho de Melo struct perf_record_opts *opts = &rec->opts; 400d20deb64SArnaldo Carvalho de Melo struct perf_evlist *evsel_list = rec->evlist; 401d20deb64SArnaldo Carvalho de Melo const char *output_name = rec->output_name; 402d20deb64SArnaldo Carvalho de Melo struct perf_session *session; 4032711926aSJiri Olsa bool disabled = false; 40486470930SIngo Molnar 405d20deb64SArnaldo Carvalho de Melo rec->progname = argv[0]; 40633e49ea7SAndi Kleen 407d20deb64SArnaldo Carvalho de Melo rec->page_size = sysconf(_SC_PAGE_SIZE); 40886470930SIngo Molnar 409d20deb64SArnaldo Carvalho de Melo on_exit(perf_record__sig_exit, rec); 410f5970550SPeter Zijlstra signal(SIGCHLD, sig_handler); 411f5970550SPeter Zijlstra signal(SIGINT, sig_handler); 41218483b81SArnaldo Carvalho de Melo signal(SIGUSR1, sig_handler); 413f5970550SPeter Zijlstra 414d7065adbSFranck Bui-Huu if (!output_name) { 415d7065adbSFranck Bui-Huu if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) 416d20deb64SArnaldo Carvalho de Melo opts->pipe_output = true; 417d7065adbSFranck Bui-Huu else 418d20deb64SArnaldo Carvalho de Melo rec->output_name = output_name = "perf.data"; 419d7065adbSFranck Bui-Huu } 420d7065adbSFranck Bui-Huu if (output_name) { 421529870e3STom Zanussi if (!strcmp(output_name, "-")) 422d20deb64SArnaldo Carvalho de Melo opts->pipe_output = true; 423529870e3STom Zanussi else if (!stat(output_name, &st) && st.st_size) { 424d20deb64SArnaldo Carvalho de Melo if (rec->write_mode == WRITE_FORCE) { 425b38d3464SArnaldo Carvalho de Melo char oldname[PATH_MAX]; 426b38d3464SArnaldo Carvalho de Melo snprintf(oldname, sizeof(oldname), "%s.old", 427b38d3464SArnaldo Carvalho de Melo output_name); 428b38d3464SArnaldo Carvalho de Melo unlink(oldname); 429b38d3464SArnaldo Carvalho de Melo rename(output_name, oldname); 430b38d3464SArnaldo Carvalho de Melo } 431d20deb64SArnaldo Carvalho de Melo } else if (rec->write_mode == WRITE_APPEND) { 432d20deb64SArnaldo Carvalho de Melo rec->write_mode = WRITE_FORCE; 433266e0e21SPierre Habouzit } 434d7065adbSFranck Bui-Huu } 43586470930SIngo Molnar 436f887f301SXiao Guangrong flags = O_CREAT|O_RDWR; 437d20deb64SArnaldo Carvalho de Melo if (rec->write_mode == WRITE_APPEND) 438d20deb64SArnaldo Carvalho de Melo rec->file_new = 0; 43986470930SIngo Molnar else 44086470930SIngo Molnar flags |= O_TRUNC; 44186470930SIngo Molnar 442d20deb64SArnaldo Carvalho de Melo if (opts->pipe_output) 443529870e3STom Zanussi output = STDOUT_FILENO; 444529870e3STom Zanussi else 44586470930SIngo Molnar output = open(output_name, flags, S_IRUSR | S_IWUSR); 44686470930SIngo Molnar if (output < 0) { 44786470930SIngo Molnar perror("failed to create output file"); 4488d3eca20SDavid Ahern return -1; 44986470930SIngo Molnar } 45086470930SIngo Molnar 451d20deb64SArnaldo Carvalho de Melo rec->output = output; 452d20deb64SArnaldo Carvalho de Melo 4537865e817SFrederic Weisbecker session = perf_session__new(output_name, O_WRONLY, 454d20deb64SArnaldo Carvalho de Melo rec->write_mode == WRITE_FORCE, false, NULL); 45594c744b6SArnaldo Carvalho de Melo if (session == NULL) { 456a9a70bbcSArnaldo Carvalho de Melo pr_err("Not enough memory for reading perf file header\n"); 457a9a70bbcSArnaldo Carvalho de Melo return -1; 458a9a70bbcSArnaldo Carvalho de Melo } 459a9a70bbcSArnaldo Carvalho de Melo 460d20deb64SArnaldo Carvalho de Melo rec->session = session; 461d20deb64SArnaldo Carvalho de Melo 462781ba9d2SRobert Richter for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++) 463781ba9d2SRobert Richter perf_header__set_feat(&session->header, feat); 464781ba9d2SRobert Richter 465781ba9d2SRobert Richter if (rec->no_buildid) 466781ba9d2SRobert Richter perf_header__clear_feat(&session->header, HEADER_BUILD_ID); 467781ba9d2SRobert Richter 468781ba9d2SRobert Richter if (!have_tracepoints(&evsel_list->entries)) 4692eeaaa09SStephane Eranian perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); 470baa2f6ceSArnaldo Carvalho de Melo 471330aa675SStephane Eranian if (!rec->opts.branch_stack) 472330aa675SStephane Eranian perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); 473330aa675SStephane Eranian 474d20deb64SArnaldo Carvalho de Melo if (!rec->file_new) { 475a91e5431SArnaldo Carvalho de Melo err = perf_session__read_header(session, output); 4764dc0a04bSArnaldo Carvalho de Melo if (err < 0) 47739d17dacSArnaldo Carvalho de Melo goto out_delete_session; 4784dc0a04bSArnaldo Carvalho de Melo } 4794dc0a04bSArnaldo Carvalho de Melo 480d4db3f16SArnaldo Carvalho de Melo if (forks) { 481d20deb64SArnaldo Carvalho de Melo err = perf_evlist__prepare_workload(evsel_list, opts, argv); 48235b9d88eSArnaldo Carvalho de Melo if (err < 0) { 48335b9d88eSArnaldo Carvalho de Melo pr_err("Couldn't run the workload!\n"); 48435b9d88eSArnaldo Carvalho de Melo goto out_delete_session; 485856e9660SPeter Zijlstra } 486856e9660SPeter Zijlstra } 487856e9660SPeter Zijlstra 4888d3eca20SDavid Ahern if (perf_record__open(rec) != 0) { 4898d3eca20SDavid Ahern err = -1; 4908d3eca20SDavid Ahern goto out_delete_session; 4918d3eca20SDavid Ahern } 49286470930SIngo Molnar 493712a4b60SArnaldo Carvalho de Melo /* 494d20deb64SArnaldo Carvalho de Melo * perf_session__delete(session) will be called at perf_record__exit() 495712a4b60SArnaldo Carvalho de Melo */ 496d20deb64SArnaldo Carvalho de Melo on_exit(perf_record__exit, rec); 497712a4b60SArnaldo Carvalho de Melo 498d20deb64SArnaldo Carvalho de Melo if (opts->pipe_output) { 499529870e3STom Zanussi err = perf_header__write_pipe(output); 500529870e3STom Zanussi if (err < 0) 5018d3eca20SDavid Ahern goto out_delete_session; 502d20deb64SArnaldo Carvalho de Melo } else if (rec->file_new) { 503a91e5431SArnaldo Carvalho de Melo err = perf_session__write_header(session, evsel_list, 504361c99a6SArnaldo Carvalho de Melo output, false); 505d5eed904SArnaldo Carvalho de Melo if (err < 0) 5068d3eca20SDavid Ahern goto out_delete_session; 507d5eed904SArnaldo Carvalho de Melo } 5087c6a1c65SPeter Zijlstra 509d3665498SDavid Ahern if (!rec->no_buildid 510e20960c0SRobert Richter && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { 511d3665498SDavid Ahern pr_err("Couldn't generate buildids. " 512e20960c0SRobert Richter "Use --no-buildid to profile anyway.\n"); 5138d3eca20SDavid Ahern err = -1; 5148d3eca20SDavid Ahern goto out_delete_session; 515e20960c0SRobert Richter } 516e20960c0SRobert Richter 517d20deb64SArnaldo Carvalho de Melo rec->post_processing_offset = lseek(output, 0, SEEK_CUR); 5186122e4e4SArnaldo Carvalho de Melo 519743eb868SArnaldo Carvalho de Melo machine = perf_session__find_host_machine(session); 520743eb868SArnaldo Carvalho de Melo if (!machine) { 521743eb868SArnaldo Carvalho de Melo pr_err("Couldn't find native kernel information.\n"); 5228d3eca20SDavid Ahern err = -1; 5238d3eca20SDavid Ahern goto out_delete_session; 524743eb868SArnaldo Carvalho de Melo } 525743eb868SArnaldo Carvalho de Melo 526d20deb64SArnaldo Carvalho de Melo if (opts->pipe_output) { 52745694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_attrs(tool, session, 528a91e5431SArnaldo Carvalho de Melo process_synthesized_event); 5292c46dbb5STom Zanussi if (err < 0) { 5302c46dbb5STom Zanussi pr_err("Couldn't synthesize attrs.\n"); 5318d3eca20SDavid Ahern goto out_delete_session; 5322c46dbb5STom Zanussi } 533cd19a035STom Zanussi 53445694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_event_types(tool, process_synthesized_event, 535743eb868SArnaldo Carvalho de Melo machine); 536cd19a035STom Zanussi if (err < 0) { 537cd19a035STom Zanussi pr_err("Couldn't synthesize event_types.\n"); 5388d3eca20SDavid Ahern goto out_delete_session; 539cd19a035STom Zanussi } 5409215545eSTom Zanussi 541361c99a6SArnaldo Carvalho de Melo if (have_tracepoints(&evsel_list->entries)) { 54263e0c771STom Zanussi /* 54363e0c771STom Zanussi * FIXME err <= 0 here actually means that 54463e0c771STom Zanussi * there were no tracepoints so its not really 54563e0c771STom Zanussi * an error, just that we don't need to 54663e0c771STom Zanussi * synthesize anything. We really have to 54763e0c771STom Zanussi * return this more properly and also 54863e0c771STom Zanussi * propagate errors that now are calling die() 54963e0c771STom Zanussi */ 55045694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_tracing_data(tool, output, evsel_list, 551743eb868SArnaldo Carvalho de Melo process_synthesized_event); 55263e0c771STom Zanussi if (err <= 0) { 55363e0c771STom Zanussi pr_err("Couldn't record tracing data.\n"); 5548d3eca20SDavid Ahern goto out_delete_session; 55563e0c771STom Zanussi } 556d20deb64SArnaldo Carvalho de Melo advance_output(rec, err); 5572c46dbb5STom Zanussi } 55863e0c771STom Zanussi } 5592c46dbb5STom Zanussi 56045694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 561743eb868SArnaldo Carvalho de Melo machine, "_text"); 56270162138SArnaldo Carvalho de Melo if (err < 0) 56345694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 564743eb868SArnaldo Carvalho de Melo machine, "_stext"); 565c1a3a4b9SArnaldo Carvalho de Melo if (err < 0) 566c1a3a4b9SArnaldo Carvalho de Melo pr_err("Couldn't record kernel reference relocation symbol\n" 567c1a3a4b9SArnaldo Carvalho de Melo "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 568c1a3a4b9SArnaldo Carvalho de Melo "Check /proc/kallsyms permission or run as root.\n"); 56956b03f3cSArnaldo Carvalho de Melo 57045694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_modules(tool, process_synthesized_event, 571743eb868SArnaldo Carvalho de Melo machine); 572c1a3a4b9SArnaldo Carvalho de Melo if (err < 0) 573c1a3a4b9SArnaldo Carvalho de Melo pr_err("Couldn't record kernel module information.\n" 574c1a3a4b9SArnaldo Carvalho de Melo "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 575c1a3a4b9SArnaldo Carvalho de Melo "Check /proc/modules permission or run as root.\n"); 576c1a3a4b9SArnaldo Carvalho de Melo 577a1645ce1SZhang, Yanmin if (perf_guest) 57845694aa7SArnaldo Carvalho de Melo perf_session__process_machines(session, tool, 5798115d60cSArnaldo Carvalho de Melo perf_event__synthesize_guest_os); 580b7cece76SArnaldo Carvalho de Melo 581bea03405SNamhyung Kim if (!opts->target.system_wide) 5828d3eca20SDavid Ahern err = perf_event__synthesize_thread_map(tool, evsel_list->threads, 5838115d60cSArnaldo Carvalho de Melo process_synthesized_event, 584743eb868SArnaldo Carvalho de Melo machine); 585234fbbf5SArnaldo Carvalho de Melo else 5868d3eca20SDavid Ahern err = perf_event__synthesize_threads(tool, process_synthesized_event, 587743eb868SArnaldo Carvalho de Melo machine); 5887c6a1c65SPeter Zijlstra 5898d3eca20SDavid Ahern if (err != 0) 5908d3eca20SDavid Ahern goto out_delete_session; 5918d3eca20SDavid Ahern 592d20deb64SArnaldo Carvalho de Melo if (rec->realtime_prio) { 59386470930SIngo Molnar struct sched_param param; 59486470930SIngo Molnar 595d20deb64SArnaldo Carvalho de Melo param.sched_priority = rec->realtime_prio; 59686470930SIngo Molnar if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { 5976beba7adSArnaldo Carvalho de Melo pr_err("Could not set realtime priority.\n"); 5988d3eca20SDavid Ahern err = -1; 5998d3eca20SDavid Ahern goto out_delete_session; 60086470930SIngo Molnar } 60186470930SIngo Molnar } 60286470930SIngo Molnar 603774cb499SJiri Olsa /* 604774cb499SJiri Olsa * When perf is starting the traced process, all the events 605774cb499SJiri Olsa * (apart from group members) have enable_on_exec=1 set, 606774cb499SJiri Olsa * so don't spoil it by prematurely enabling them. 607774cb499SJiri Olsa */ 608774cb499SJiri Olsa if (!perf_target__none(&opts->target)) 609764e16a3SDavid Ahern perf_evlist__enable(evsel_list); 610764e16a3SDavid Ahern 611856e9660SPeter Zijlstra /* 612856e9660SPeter Zijlstra * Let the child rip 613856e9660SPeter Zijlstra */ 614d4db3f16SArnaldo Carvalho de Melo if (forks) 61535b9d88eSArnaldo Carvalho de Melo perf_evlist__start_workload(evsel_list); 616856e9660SPeter Zijlstra 617649c48a9SPeter Zijlstra for (;;) { 618d20deb64SArnaldo Carvalho de Melo int hits = rec->samples; 61986470930SIngo Molnar 6208d3eca20SDavid Ahern if (perf_record__mmap_read_all(rec) < 0) { 6218d3eca20SDavid Ahern err = -1; 6228d3eca20SDavid Ahern goto out_delete_session; 6238d3eca20SDavid Ahern } 62486470930SIngo Molnar 625d20deb64SArnaldo Carvalho de Melo if (hits == rec->samples) { 626649c48a9SPeter Zijlstra if (done) 627649c48a9SPeter Zijlstra break; 6285c581041SArnaldo Carvalho de Melo err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); 6298b412664SPeter Zijlstra waking++; 6308b412664SPeter Zijlstra } 6318b412664SPeter Zijlstra 632774cb499SJiri Olsa /* 633774cb499SJiri Olsa * When perf is starting the traced process, at the end events 634774cb499SJiri Olsa * die with the process and we wait for that. Thus no need to 635774cb499SJiri Olsa * disable events in this case. 636774cb499SJiri Olsa */ 6372711926aSJiri Olsa if (done && !disabled && !perf_target__none(&opts->target)) { 6384152ab37SArnaldo Carvalho de Melo perf_evlist__disable(evsel_list); 6392711926aSJiri Olsa disabled = true; 6402711926aSJiri Olsa } 6418b412664SPeter Zijlstra } 6428b412664SPeter Zijlstra 64318483b81SArnaldo Carvalho de Melo if (quiet || signr == SIGUSR1) 644b44308f5SArnaldo Carvalho de Melo return 0; 645b44308f5SArnaldo Carvalho de Melo 6468b412664SPeter Zijlstra fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); 64786470930SIngo Molnar 64886470930SIngo Molnar /* 64986470930SIngo Molnar * Approximate RIP event size: 24 bytes. 65086470930SIngo Molnar */ 65186470930SIngo Molnar fprintf(stderr, 6529486aa38SArnaldo Carvalho de Melo "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", 653d20deb64SArnaldo Carvalho de Melo (double)rec->bytes_written / 1024.0 / 1024.0, 65486470930SIngo Molnar output_name, 655d20deb64SArnaldo Carvalho de Melo rec->bytes_written / 24); 65686470930SIngo Molnar 65786470930SIngo Molnar return 0; 65839d17dacSArnaldo Carvalho de Melo 65939d17dacSArnaldo Carvalho de Melo out_delete_session: 66039d17dacSArnaldo Carvalho de Melo perf_session__delete(session); 66139d17dacSArnaldo Carvalho de Melo return err; 66286470930SIngo Molnar } 66386470930SIngo Molnar 664bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \ 665bdfebd84SRoberto Agostino Vitillo { .name = n, .mode = (m) } 666bdfebd84SRoberto Agostino Vitillo 667bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL } 668bdfebd84SRoberto Agostino Vitillo 669bdfebd84SRoberto Agostino Vitillo struct branch_mode { 670bdfebd84SRoberto Agostino Vitillo const char *name; 671bdfebd84SRoberto Agostino Vitillo int mode; 672bdfebd84SRoberto Agostino Vitillo }; 673bdfebd84SRoberto Agostino Vitillo 674bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = { 675bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER), 676bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL), 677bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV), 678bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY), 679bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL), 680bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN), 681bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL), 682bdfebd84SRoberto Agostino Vitillo BRANCH_END 683bdfebd84SRoberto Agostino Vitillo }; 684bdfebd84SRoberto Agostino Vitillo 685bdfebd84SRoberto Agostino Vitillo static int 686a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset) 687bdfebd84SRoberto Agostino Vitillo { 688bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \ 689bdfebd84SRoberto Agostino Vitillo (PERF_SAMPLE_BRANCH_USER |\ 690bdfebd84SRoberto Agostino Vitillo PERF_SAMPLE_BRANCH_KERNEL |\ 691bdfebd84SRoberto Agostino Vitillo PERF_SAMPLE_BRANCH_HV) 692bdfebd84SRoberto Agostino Vitillo 693bdfebd84SRoberto Agostino Vitillo uint64_t *mode = (uint64_t *)opt->value; 694bdfebd84SRoberto Agostino Vitillo const struct branch_mode *br; 695a5aabdacSStephane Eranian char *s, *os = NULL, *p; 696bdfebd84SRoberto Agostino Vitillo int ret = -1; 697bdfebd84SRoberto Agostino Vitillo 698a5aabdacSStephane Eranian if (unset) 699a5aabdacSStephane Eranian return 0; 700bdfebd84SRoberto Agostino Vitillo 701a5aabdacSStephane Eranian /* 702a5aabdacSStephane Eranian * cannot set it twice, -b + --branch-filter for instance 703a5aabdacSStephane Eranian */ 704a5aabdacSStephane Eranian if (*mode) 705a5aabdacSStephane Eranian return -1; 706a5aabdacSStephane Eranian 707a5aabdacSStephane Eranian /* str may be NULL in case no arg is passed to -b */ 708a5aabdacSStephane Eranian if (str) { 709bdfebd84SRoberto Agostino Vitillo /* because str is read-only */ 710bdfebd84SRoberto Agostino Vitillo s = os = strdup(str); 711bdfebd84SRoberto Agostino Vitillo if (!s) 712bdfebd84SRoberto Agostino Vitillo return -1; 713bdfebd84SRoberto Agostino Vitillo 714bdfebd84SRoberto Agostino Vitillo for (;;) { 715bdfebd84SRoberto Agostino Vitillo p = strchr(s, ','); 716bdfebd84SRoberto Agostino Vitillo if (p) 717bdfebd84SRoberto Agostino Vitillo *p = '\0'; 718bdfebd84SRoberto Agostino Vitillo 719bdfebd84SRoberto Agostino Vitillo for (br = branch_modes; br->name; br++) { 720bdfebd84SRoberto Agostino Vitillo if (!strcasecmp(s, br->name)) 721bdfebd84SRoberto Agostino Vitillo break; 722bdfebd84SRoberto Agostino Vitillo } 723a5aabdacSStephane Eranian if (!br->name) { 724a5aabdacSStephane Eranian ui__warning("unknown branch filter %s," 725a5aabdacSStephane Eranian " check man page\n", s); 726bdfebd84SRoberto Agostino Vitillo goto error; 727a5aabdacSStephane Eranian } 728bdfebd84SRoberto Agostino Vitillo 729bdfebd84SRoberto Agostino Vitillo *mode |= br->mode; 730bdfebd84SRoberto Agostino Vitillo 731bdfebd84SRoberto Agostino Vitillo if (!p) 732bdfebd84SRoberto Agostino Vitillo break; 733bdfebd84SRoberto Agostino Vitillo 734bdfebd84SRoberto Agostino Vitillo s = p + 1; 735bdfebd84SRoberto Agostino Vitillo } 736a5aabdacSStephane Eranian } 737bdfebd84SRoberto Agostino Vitillo ret = 0; 738bdfebd84SRoberto Agostino Vitillo 739a5aabdacSStephane Eranian /* default to any branch */ 740bdfebd84SRoberto Agostino Vitillo if ((*mode & ~ONLY_PLM) == 0) { 741a5aabdacSStephane Eranian *mode = PERF_SAMPLE_BRANCH_ANY; 742bdfebd84SRoberto Agostino Vitillo } 743bdfebd84SRoberto Agostino Vitillo error: 744bdfebd84SRoberto Agostino Vitillo free(os); 745bdfebd84SRoberto Agostino Vitillo return ret; 746bdfebd84SRoberto Agostino Vitillo } 747bdfebd84SRoberto Agostino Vitillo 74895485b1cSNamhyung Kim #ifdef LIBUNWIND_SUPPORT 74926d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size) 75026d33022SJiri Olsa { 75126d33022SJiri Olsa char *endptr; 75226d33022SJiri Olsa unsigned long size; 75326d33022SJiri Olsa unsigned long max_size = round_down(USHRT_MAX, sizeof(u64)); 75426d33022SJiri Olsa 75526d33022SJiri Olsa size = strtoul(str, &endptr, 0); 75626d33022SJiri Olsa 75726d33022SJiri Olsa do { 75826d33022SJiri Olsa if (*endptr) 75926d33022SJiri Olsa break; 76026d33022SJiri Olsa 76126d33022SJiri Olsa size = round_up(size, sizeof(u64)); 76226d33022SJiri Olsa if (!size || size > max_size) 76326d33022SJiri Olsa break; 76426d33022SJiri Olsa 76526d33022SJiri Olsa *_size = size; 76626d33022SJiri Olsa return 0; 76726d33022SJiri Olsa 76826d33022SJiri Olsa } while (0); 76926d33022SJiri Olsa 77026d33022SJiri Olsa pr_err("callchain: Incorrect stack dump size (max %ld): %s\n", 77126d33022SJiri Olsa max_size, str); 77226d33022SJiri Olsa return -1; 77326d33022SJiri Olsa } 77495485b1cSNamhyung Kim #endif /* LIBUNWIND_SUPPORT */ 77526d33022SJiri Olsa 77675d9a108SArnaldo Carvalho de Melo int record_parse_callchain_opt(const struct option *opt, 77775d9a108SArnaldo Carvalho de Melo const char *arg, int unset) 77826d33022SJiri Olsa { 779c5ff78c3SArnaldo Carvalho de Melo struct perf_record_opts *opts = opt->value; 78026d33022SJiri Olsa char *tok, *name, *saveptr = NULL; 78126d33022SJiri Olsa char *buf; 78226d33022SJiri Olsa int ret = -1; 78326d33022SJiri Olsa 78426d33022SJiri Olsa /* --no-call-graph */ 78526d33022SJiri Olsa if (unset) 78626d33022SJiri Olsa return 0; 78726d33022SJiri Olsa 78826d33022SJiri Olsa /* We specified default option if none is provided. */ 78926d33022SJiri Olsa BUG_ON(!arg); 79026d33022SJiri Olsa 79126d33022SJiri Olsa /* We need buffer that we know we can write to. */ 79226d33022SJiri Olsa buf = malloc(strlen(arg) + 1); 79326d33022SJiri Olsa if (!buf) 79426d33022SJiri Olsa return -ENOMEM; 79526d33022SJiri Olsa 79626d33022SJiri Olsa strcpy(buf, arg); 79726d33022SJiri Olsa 79826d33022SJiri Olsa tok = strtok_r((char *)buf, ",", &saveptr); 79926d33022SJiri Olsa name = tok ? : (char *)buf; 80026d33022SJiri Olsa 80126d33022SJiri Olsa do { 80226d33022SJiri Olsa /* Framepointer style */ 80326d33022SJiri Olsa if (!strncmp(name, "fp", sizeof("fp"))) { 80426d33022SJiri Olsa if (!strtok_r(NULL, ",", &saveptr)) { 805c5ff78c3SArnaldo Carvalho de Melo opts->call_graph = CALLCHAIN_FP; 80626d33022SJiri Olsa ret = 0; 80726d33022SJiri Olsa } else 80826d33022SJiri Olsa pr_err("callchain: No more arguments " 80926d33022SJiri Olsa "needed for -g fp\n"); 81026d33022SJiri Olsa break; 81126d33022SJiri Olsa 81295485b1cSNamhyung Kim #ifdef LIBUNWIND_SUPPORT 81326d33022SJiri Olsa /* Dwarf style */ 81426d33022SJiri Olsa } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { 81561eaa3beSArnaldo Carvalho de Melo const unsigned long default_stack_dump_size = 8192; 81661eaa3beSArnaldo Carvalho de Melo 81726d33022SJiri Olsa ret = 0; 818c5ff78c3SArnaldo Carvalho de Melo opts->call_graph = CALLCHAIN_DWARF; 819c5ff78c3SArnaldo Carvalho de Melo opts->stack_dump_size = default_stack_dump_size; 82026d33022SJiri Olsa 82126d33022SJiri Olsa tok = strtok_r(NULL, ",", &saveptr); 82226d33022SJiri Olsa if (tok) { 82326d33022SJiri Olsa unsigned long size = 0; 82426d33022SJiri Olsa 82526d33022SJiri Olsa ret = get_stack_size(tok, &size); 826c5ff78c3SArnaldo Carvalho de Melo opts->stack_dump_size = size; 82726d33022SJiri Olsa } 82826d33022SJiri Olsa 82926d33022SJiri Olsa if (!ret) 83026d33022SJiri Olsa pr_debug("callchain: stack dump size %d\n", 831c5ff78c3SArnaldo Carvalho de Melo opts->stack_dump_size); 83295485b1cSNamhyung Kim #endif /* LIBUNWIND_SUPPORT */ 83326d33022SJiri Olsa } else { 83426d33022SJiri Olsa pr_err("callchain: Unknown -g option " 83526d33022SJiri Olsa "value: %s\n", arg); 83626d33022SJiri Olsa break; 83726d33022SJiri Olsa } 83826d33022SJiri Olsa 83926d33022SJiri Olsa } while (0); 84026d33022SJiri Olsa 84126d33022SJiri Olsa free(buf); 84226d33022SJiri Olsa 84326d33022SJiri Olsa if (!ret) 844c5ff78c3SArnaldo Carvalho de Melo pr_debug("callchain: type %d\n", opts->call_graph); 84526d33022SJiri Olsa 84626d33022SJiri Olsa return ret; 84726d33022SJiri Olsa } 84826d33022SJiri Olsa 84986470930SIngo Molnar static const char * const record_usage[] = { 85086470930SIngo Molnar "perf record [<options>] [<command>]", 85186470930SIngo Molnar "perf record [<options>] -- <command> [<options>]", 85286470930SIngo Molnar NULL 85386470930SIngo Molnar }; 85486470930SIngo Molnar 855d20deb64SArnaldo Carvalho de Melo /* 856d20deb64SArnaldo Carvalho de Melo * XXX Ideally would be local to cmd_record() and passed to a perf_record__new 857d20deb64SArnaldo Carvalho de Melo * because we need to have access to it in perf_record__exit, that is called 858d20deb64SArnaldo Carvalho de Melo * after cmd_record() exits, but since record_options need to be accessible to 859d20deb64SArnaldo Carvalho de Melo * builtin-script, leave it here. 860d20deb64SArnaldo Carvalho de Melo * 861d20deb64SArnaldo Carvalho de Melo * At least we don't ouch it in all the other functions here directly. 862d20deb64SArnaldo Carvalho de Melo * 863d20deb64SArnaldo Carvalho de Melo * Just say no to tons of global variables, sigh. 864d20deb64SArnaldo Carvalho de Melo */ 865d20deb64SArnaldo Carvalho de Melo static struct perf_record record = { 866d20deb64SArnaldo Carvalho de Melo .opts = { 867d20deb64SArnaldo Carvalho de Melo .mmap_pages = UINT_MAX, 868d20deb64SArnaldo Carvalho de Melo .user_freq = UINT_MAX, 869d20deb64SArnaldo Carvalho de Melo .user_interval = ULLONG_MAX, 870447a6013SArnaldo Carvalho de Melo .freq = 4000, 871d1cb9fceSNamhyung Kim .target = { 872d1cb9fceSNamhyung Kim .uses_mmap = true, 873d1cb9fceSNamhyung Kim }, 874d20deb64SArnaldo Carvalho de Melo }, 875d20deb64SArnaldo Carvalho de Melo .write_mode = WRITE_FORCE, 876d20deb64SArnaldo Carvalho de Melo .file_new = true, 877d20deb64SArnaldo Carvalho de Melo }; 8787865e817SFrederic Weisbecker 87961eaa3beSArnaldo Carvalho de Melo #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " 88061eaa3beSArnaldo Carvalho de Melo 88161eaa3beSArnaldo Carvalho de Melo #ifdef LIBUNWIND_SUPPORT 88275d9a108SArnaldo Carvalho de Melo const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; 88361eaa3beSArnaldo Carvalho de Melo #else 88475d9a108SArnaldo Carvalho de Melo const char record_callchain_help[] = CALLCHAIN_HELP "[fp]"; 88561eaa3beSArnaldo Carvalho de Melo #endif 88661eaa3beSArnaldo Carvalho de Melo 887d20deb64SArnaldo Carvalho de Melo /* 888d20deb64SArnaldo Carvalho de Melo * XXX Will stay a global variable till we fix builtin-script.c to stop messing 889d20deb64SArnaldo Carvalho de Melo * with it and switch to use the library functions in perf_evlist that came 890d20deb64SArnaldo Carvalho de Melo * from builtin-record.c, i.e. use perf_record_opts, 891d20deb64SArnaldo Carvalho de Melo * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', 892d20deb64SArnaldo Carvalho de Melo * using pipes, etc. 893d20deb64SArnaldo Carvalho de Melo */ 894bca647aaSTom Zanussi const struct option record_options[] = { 895d20deb64SArnaldo Carvalho de Melo OPT_CALLBACK('e', "event", &record.evlist, "event", 89686470930SIngo Molnar "event selector. use 'perf list' to list available events", 897f120f9d5SJiri Olsa parse_events_option), 898d20deb64SArnaldo Carvalho de Melo OPT_CALLBACK(0, "filter", &record.evlist, "filter", 899c171b552SLi Zefan "event filter", parse_filter), 900bea03405SNamhyung Kim OPT_STRING('p', "pid", &record.opts.target.pid, "pid", 901d6d901c2SZhang, Yanmin "record events on existing process id"), 902bea03405SNamhyung Kim OPT_STRING('t', "tid", &record.opts.target.tid, "tid", 903d6d901c2SZhang, Yanmin "record events on existing thread id"), 904d20deb64SArnaldo Carvalho de Melo OPT_INTEGER('r', "realtime", &record.realtime_prio, 90586470930SIngo Molnar "collect data with this RT SCHED_FIFO priority"), 906d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay, 907acac03faSKirill Smelkov "collect data without buffering"), 908d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, 909daac07b2SFrederic Weisbecker "collect raw sample records from all opened counters"), 910bea03405SNamhyung Kim OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide, 91186470930SIngo Molnar "system-wide collection from all CPUs"), 912d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('A', "append", &record.append_file, 91386470930SIngo Molnar "append to the output file to do incremental profiling"), 914bea03405SNamhyung Kim OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu", 915c45c6ea2SStephane Eranian "list of cpus to monitor"), 916d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('f', "force", &record.force, 9177865e817SFrederic Weisbecker "overwrite existing data file (deprecated)"), 918d20deb64SArnaldo Carvalho de Melo OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), 919d20deb64SArnaldo Carvalho de Melo OPT_STRING('o', "output", &record.output_name, "file", 92086470930SIngo Molnar "output file name"), 921d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit, 9222e6cdf99SStephane Eranian "child tasks do not inherit counters"), 923d20deb64SArnaldo Carvalho de Melo OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), 924d20deb64SArnaldo Carvalho de Melo OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages, 92501c2d99bSArnaldo Carvalho de Melo "number of mmap data pages"), 926d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN(0, "group", &record.opts.group, 92743bece79SLin Ming "put the counters into a counter group"), 928c5ff78c3SArnaldo Carvalho de Melo OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts, 92975d9a108SArnaldo Carvalho de Melo "mode[,dump_size]", record_callchain_help, 93075d9a108SArnaldo Carvalho de Melo &record_parse_callchain_opt, "fp"), 931c0555642SIan Munsie OPT_INCR('v', "verbose", &verbose, 9323da297a6SIngo Molnar "be more verbose (show counter open errors, etc)"), 933b44308f5SArnaldo Carvalho de Melo OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 934d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat, 935649c48a9SPeter Zijlstra "per thread counts"), 936d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('d', "data", &record.opts.sample_address, 9374bba828dSAnton Blanchard "Sample addresses"), 938d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"), 9393e76ac78SAndrew Vagin OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"), 940d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, 941649c48a9SPeter Zijlstra "don't sample"), 942d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache, 943a1ac1d3cSStephane Eranian "do not update the buildid cache"), 944d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('B', "no-buildid", &record.no_buildid, 945baa2f6ceSArnaldo Carvalho de Melo "do not collect buildids in perf.data"), 946d20deb64SArnaldo Carvalho de Melo OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 947023695d9SStephane Eranian "monitor event in cgroup name only", 948023695d9SStephane Eranian parse_cgroups), 949bea03405SNamhyung Kim OPT_STRING('u', "uid", &record.opts.target.uid_str, "user", 950bea03405SNamhyung Kim "user to profile"), 951a5aabdacSStephane Eranian 952a5aabdacSStephane Eranian OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack, 953a5aabdacSStephane Eranian "branch any", "sample any taken branches", 954a5aabdacSStephane Eranian parse_branch_stack), 955a5aabdacSStephane Eranian 956a5aabdacSStephane Eranian OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack, 957a5aabdacSStephane Eranian "branch filter mask", "branch stack filter modes", 958bdfebd84SRoberto Agostino Vitillo parse_branch_stack), 95986470930SIngo Molnar OPT_END() 96086470930SIngo Molnar }; 96186470930SIngo Molnar 9621d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) 96386470930SIngo Molnar { 96469aad6f1SArnaldo Carvalho de Melo int err = -ENOMEM; 96569aad6f1SArnaldo Carvalho de Melo struct perf_evsel *pos; 966d20deb64SArnaldo Carvalho de Melo struct perf_evlist *evsel_list; 967d20deb64SArnaldo Carvalho de Melo struct perf_record *rec = &record; 96816ad2ffbSNamhyung Kim char errbuf[BUFSIZ]; 96986470930SIngo Molnar 9707e2ed097SArnaldo Carvalho de Melo evsel_list = perf_evlist__new(NULL, NULL); 971361c99a6SArnaldo Carvalho de Melo if (evsel_list == NULL) 972361c99a6SArnaldo Carvalho de Melo return -ENOMEM; 973361c99a6SArnaldo Carvalho de Melo 974d20deb64SArnaldo Carvalho de Melo rec->evlist = evsel_list; 975d20deb64SArnaldo Carvalho de Melo 976bca647aaSTom Zanussi argc = parse_options(argc, argv, record_options, record_usage, 977a0541234SAnton Blanchard PARSE_OPT_STOP_AT_NON_OPTION); 978d67356e7SNamhyung Kim if (!argc && perf_target__none(&rec->opts.target)) 979bca647aaSTom Zanussi usage_with_options(record_usage, record_options); 98086470930SIngo Molnar 981d20deb64SArnaldo Carvalho de Melo if (rec->force && rec->append_file) { 9823780f488SNamhyung Kim ui__error("Can't overwrite and append at the same time." 9837865e817SFrederic Weisbecker " You need to choose between -f and -A"); 984bca647aaSTom Zanussi usage_with_options(record_usage, record_options); 985d20deb64SArnaldo Carvalho de Melo } else if (rec->append_file) { 986d20deb64SArnaldo Carvalho de Melo rec->write_mode = WRITE_APPEND; 9877865e817SFrederic Weisbecker } else { 988d20deb64SArnaldo Carvalho de Melo rec->write_mode = WRITE_FORCE; 9897865e817SFrederic Weisbecker } 9907865e817SFrederic Weisbecker 991bea03405SNamhyung Kim if (nr_cgroups && !rec->opts.target.system_wide) { 9923780f488SNamhyung Kim ui__error("cgroup monitoring only available in" 993023695d9SStephane Eranian " system-wide mode\n"); 994023695d9SStephane Eranian usage_with_options(record_usage, record_options); 995023695d9SStephane Eranian } 996023695d9SStephane Eranian 997655000e7SArnaldo Carvalho de Melo symbol__init(); 998baa2f6ceSArnaldo Carvalho de Melo 999ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) 1000646aaea6SArnaldo Carvalho de Melo pr_warning( 1001646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n" 1002ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n" 1003646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n" 1004646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n" 1005646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n" 1006646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n" 1007646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n"); 1008ec80fde7SArnaldo Carvalho de Melo 1009d20deb64SArnaldo Carvalho de Melo if (rec->no_buildid_cache || rec->no_buildid) 1010a1ac1d3cSStephane Eranian disable_buildid_cache(); 1011655000e7SArnaldo Carvalho de Melo 1012361c99a6SArnaldo Carvalho de Melo if (evsel_list->nr_entries == 0 && 1013361c99a6SArnaldo Carvalho de Melo perf_evlist__add_default(evsel_list) < 0) { 101469aad6f1SArnaldo Carvalho de Melo pr_err("Not enough memory for event selector list\n"); 101569aad6f1SArnaldo Carvalho de Melo goto out_symbol_exit; 1016bbd36e5eSPeter Zijlstra } 101786470930SIngo Molnar 101816ad2ffbSNamhyung Kim err = perf_target__validate(&rec->opts.target); 101916ad2ffbSNamhyung Kim if (err) { 102016ad2ffbSNamhyung Kim perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 102116ad2ffbSNamhyung Kim ui__warning("%s", errbuf); 102216ad2ffbSNamhyung Kim } 10234bd0f2d2SNamhyung Kim 102416ad2ffbSNamhyung Kim err = perf_target__parse_uid(&rec->opts.target); 102516ad2ffbSNamhyung Kim if (err) { 102616ad2ffbSNamhyung Kim int saved_errno = errno; 102716ad2ffbSNamhyung Kim 102816ad2ffbSNamhyung Kim perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 10293780f488SNamhyung Kim ui__error("%s", errbuf); 103016ad2ffbSNamhyung Kim 103116ad2ffbSNamhyung Kim err = -saved_errno; 10320d37aa34SArnaldo Carvalho de Melo goto out_free_fd; 103316ad2ffbSNamhyung Kim } 10340d37aa34SArnaldo Carvalho de Melo 103516ad2ffbSNamhyung Kim err = -ENOMEM; 1036b809ac10SNamhyung Kim if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) 1037dd7927f4SArnaldo Carvalho de Melo usage_with_options(record_usage, record_options); 103869aad6f1SArnaldo Carvalho de Melo 1039361c99a6SArnaldo Carvalho de Melo list_for_each_entry(pos, &evsel_list->entries, node) { 10407289f83cSArnaldo Carvalho de Melo if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos))) 1041ad7f4e3fSArnaldo Carvalho de Melo goto out_free_fd; 1042d6d901c2SZhang, Yanmin } 10435c581041SArnaldo Carvalho de Melo 1044d20deb64SArnaldo Carvalho de Melo if (rec->opts.user_interval != ULLONG_MAX) 1045d20deb64SArnaldo Carvalho de Melo rec->opts.default_interval = rec->opts.user_interval; 1046d20deb64SArnaldo Carvalho de Melo if (rec->opts.user_freq != UINT_MAX) 1047d20deb64SArnaldo Carvalho de Melo rec->opts.freq = rec->opts.user_freq; 1048f9212819SFrederic Weisbecker 10497e4ff9e3SMike Galbraith /* 10507e4ff9e3SMike Galbraith * User specified count overrides default frequency. 10517e4ff9e3SMike Galbraith */ 1052d20deb64SArnaldo Carvalho de Melo if (rec->opts.default_interval) 1053d20deb64SArnaldo Carvalho de Melo rec->opts.freq = 0; 1054d20deb64SArnaldo Carvalho de Melo else if (rec->opts.freq) { 1055d20deb64SArnaldo Carvalho de Melo rec->opts.default_interval = rec->opts.freq; 10567e4ff9e3SMike Galbraith } else { 10573780f488SNamhyung Kim ui__error("frequency and count are zero, aborting\n"); 105839d17dacSArnaldo Carvalho de Melo err = -EINVAL; 10595c581041SArnaldo Carvalho de Melo goto out_free_fd; 10607e4ff9e3SMike Galbraith } 10617e4ff9e3SMike Galbraith 1062d20deb64SArnaldo Carvalho de Melo err = __cmd_record(&record, argc, argv); 106339d17dacSArnaldo Carvalho de Melo out_free_fd: 10647e2ed097SArnaldo Carvalho de Melo perf_evlist__delete_maps(evsel_list); 1065d65a458bSArnaldo Carvalho de Melo out_symbol_exit: 1066d65a458bSArnaldo Carvalho de Melo symbol__exit(); 106739d17dacSArnaldo Carvalho de Melo return err; 106886470930SIngo Molnar } 1069