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 */ 886470930SIngo Molnar #include "builtin.h" 986470930SIngo Molnar 1086470930SIngo Molnar #include "perf.h" 1186470930SIngo Molnar 126122e4e4SArnaldo Carvalho de Melo #include "util/build-id.h" 1386470930SIngo Molnar #include "util/util.h" 1486470930SIngo Molnar #include "util/parse-options.h" 1586470930SIngo Molnar #include "util/parse-events.h" 1686470930SIngo Molnar 177c6a1c65SPeter Zijlstra #include "util/header.h" 1866e274f3SFrederic Weisbecker #include "util/event.h" 19361c99a6SArnaldo Carvalho de Melo #include "util/evlist.h" 2069aad6f1SArnaldo Carvalho de Melo #include "util/evsel.h" 218f28827aSFrederic Weisbecker #include "util/debug.h" 2294c744b6SArnaldo Carvalho de Melo #include "util/session.h" 2345694aa7SArnaldo Carvalho de Melo #include "util/tool.h" 248d06367fSArnaldo Carvalho de Melo #include "util/symbol.h" 25a12b51c4SPaul Mackerras #include "util/cpumap.h" 26fd78260bSArnaldo Carvalho de Melo #include "util/thread_map.h" 27f5fc1412SJiri Olsa #include "util/data.h" 287c6a1c65SPeter Zijlstra 2986470930SIngo Molnar #include <unistd.h> 3086470930SIngo Molnar #include <sched.h> 31a41794cdSArnaldo Carvalho de Melo #include <sys/mman.h> 3286470930SIngo Molnar 3389fe808aSIngo Molnar #ifndef HAVE_ON_EXIT_SUPPORT 3478da39faSBernhard Rosenkraenzer #ifndef ATEXIT_MAX 3578da39faSBernhard Rosenkraenzer #define ATEXIT_MAX 32 3678da39faSBernhard Rosenkraenzer #endif 3778da39faSBernhard Rosenkraenzer static int __on_exit_count = 0; 3878da39faSBernhard Rosenkraenzer typedef void (*on_exit_func_t) (int, void *); 3978da39faSBernhard Rosenkraenzer static on_exit_func_t __on_exit_funcs[ATEXIT_MAX]; 4078da39faSBernhard Rosenkraenzer static void *__on_exit_args[ATEXIT_MAX]; 4178da39faSBernhard Rosenkraenzer static int __exitcode = 0; 4278da39faSBernhard Rosenkraenzer static void __handle_on_exit_funcs(void); 4378da39faSBernhard Rosenkraenzer static int on_exit(on_exit_func_t function, void *arg); 4478da39faSBernhard Rosenkraenzer #define exit(x) (exit)(__exitcode = (x)) 4578da39faSBernhard Rosenkraenzer 4678da39faSBernhard Rosenkraenzer static int on_exit(on_exit_func_t function, void *arg) 4778da39faSBernhard Rosenkraenzer { 4878da39faSBernhard Rosenkraenzer if (__on_exit_count == ATEXIT_MAX) 4978da39faSBernhard Rosenkraenzer return -ENOMEM; 5078da39faSBernhard Rosenkraenzer else if (__on_exit_count == 0) 5178da39faSBernhard Rosenkraenzer atexit(__handle_on_exit_funcs); 5278da39faSBernhard Rosenkraenzer __on_exit_funcs[__on_exit_count] = function; 5378da39faSBernhard Rosenkraenzer __on_exit_args[__on_exit_count++] = arg; 5478da39faSBernhard Rosenkraenzer return 0; 5578da39faSBernhard Rosenkraenzer } 5678da39faSBernhard Rosenkraenzer 5778da39faSBernhard Rosenkraenzer static void __handle_on_exit_funcs(void) 5878da39faSBernhard Rosenkraenzer { 5978da39faSBernhard Rosenkraenzer int i; 6078da39faSBernhard Rosenkraenzer for (i = 0; i < __on_exit_count; i++) 6178da39faSBernhard Rosenkraenzer __on_exit_funcs[i] (__exitcode, __on_exit_args[i]); 6278da39faSBernhard Rosenkraenzer } 6378da39faSBernhard Rosenkraenzer #endif 6478da39faSBernhard Rosenkraenzer 658c6f45a7SArnaldo Carvalho de Melo struct record { 6645694aa7SArnaldo Carvalho de Melo struct perf_tool tool; 67b4006796SArnaldo Carvalho de Melo struct record_opts opts; 68d20deb64SArnaldo Carvalho de Melo u64 bytes_written; 69f5fc1412SJiri Olsa struct perf_data_file file; 70d20deb64SArnaldo Carvalho de Melo struct perf_evlist *evlist; 71d20deb64SArnaldo Carvalho de Melo struct perf_session *session; 72d20deb64SArnaldo Carvalho de Melo const char *progname; 73d20deb64SArnaldo Carvalho de Melo int realtime_prio; 74d20deb64SArnaldo Carvalho de Melo bool no_buildid; 75d20deb64SArnaldo Carvalho de Melo bool no_buildid_cache; 76d20deb64SArnaldo Carvalho de Melo long samples; 770f82ebc4SArnaldo Carvalho de Melo }; 7886470930SIngo Molnar 798c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size) 80f5970550SPeter Zijlstra { 81cf8b2e69SArnaldo Carvalho de Melo if (perf_data_file__write(rec->session->file, bf, size) < 0) { 824f624685SAdrian Hunter pr_err("failed to write perf data, error: %m\n"); 838d3eca20SDavid Ahern return -1; 848d3eca20SDavid Ahern } 85f5970550SPeter Zijlstra 86cf8b2e69SArnaldo Carvalho de Melo rec->bytes_written += size; 878d3eca20SDavid Ahern return 0; 88f5970550SPeter Zijlstra } 89f5970550SPeter Zijlstra 9045694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool, 91d20deb64SArnaldo Carvalho de Melo union perf_event *event, 921d037ca1SIrina Tirdea struct perf_sample *sample __maybe_unused, 931d037ca1SIrina Tirdea struct machine *machine __maybe_unused) 94234fbbf5SArnaldo Carvalho de Melo { 958c6f45a7SArnaldo Carvalho de Melo struct record *rec = container_of(tool, struct record, tool); 968c6f45a7SArnaldo Carvalho de Melo return record__write(rec, event, event->header.size); 97234fbbf5SArnaldo Carvalho de Melo } 98234fbbf5SArnaldo Carvalho de Melo 998c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, struct perf_mmap *md) 10086470930SIngo Molnar { 101744bd8aaSArnaldo Carvalho de Melo unsigned int head = perf_mmap__read_head(md); 10286470930SIngo Molnar unsigned int old = md->prev; 103918512b4SJiri Olsa unsigned char *data = md->base + page_size; 10486470930SIngo Molnar unsigned long size; 10586470930SIngo Molnar void *buf; 1068d3eca20SDavid Ahern int rc = 0; 10786470930SIngo Molnar 108dc82009aSArnaldo Carvalho de Melo if (old == head) 1098d3eca20SDavid Ahern return 0; 11086470930SIngo Molnar 111d20deb64SArnaldo Carvalho de Melo rec->samples++; 11286470930SIngo Molnar 11386470930SIngo Molnar size = head - old; 11486470930SIngo Molnar 11586470930SIngo Molnar if ((old & md->mask) + size != (head & md->mask)) { 11686470930SIngo Molnar buf = &data[old & md->mask]; 11786470930SIngo Molnar size = md->mask + 1 - (old & md->mask); 11886470930SIngo Molnar old += size; 11986470930SIngo Molnar 1208c6f45a7SArnaldo Carvalho de Melo if (record__write(rec, buf, size) < 0) { 1218d3eca20SDavid Ahern rc = -1; 1228d3eca20SDavid Ahern goto out; 1238d3eca20SDavid Ahern } 12486470930SIngo Molnar } 12586470930SIngo Molnar 12686470930SIngo Molnar buf = &data[old & md->mask]; 12786470930SIngo Molnar size = head - old; 12886470930SIngo Molnar old += size; 12986470930SIngo Molnar 1308c6f45a7SArnaldo Carvalho de Melo if (record__write(rec, buf, size) < 0) { 1318d3eca20SDavid Ahern rc = -1; 1328d3eca20SDavid Ahern goto out; 1338d3eca20SDavid Ahern } 13486470930SIngo Molnar 13586470930SIngo Molnar md->prev = old; 136115d2d89SArnaldo Carvalho de Melo perf_mmap__write_tail(md, old); 1378d3eca20SDavid Ahern 1388d3eca20SDavid Ahern out: 1398d3eca20SDavid Ahern return rc; 14086470930SIngo Molnar } 14186470930SIngo Molnar 14286470930SIngo Molnar static volatile int done = 0; 143f7b7c26eSPeter Zijlstra static volatile int signr = -1; 14433e49ea7SAndi Kleen static volatile int child_finished = 0; 14586470930SIngo Molnar 14686470930SIngo Molnar static void sig_handler(int sig) 14786470930SIngo Molnar { 14833e49ea7SAndi Kleen if (sig == SIGCHLD) 14933e49ea7SAndi Kleen child_finished = 1; 15033e49ea7SAndi Kleen 15186470930SIngo Molnar done = 1; 152f7b7c26eSPeter Zijlstra signr = sig; 153f7b7c26eSPeter Zijlstra } 154f7b7c26eSPeter Zijlstra 1558c6f45a7SArnaldo Carvalho de Melo static void record__sig_exit(int exit_status __maybe_unused, void *arg) 156f7b7c26eSPeter Zijlstra { 1578c6f45a7SArnaldo Carvalho de Melo struct record *rec = arg; 15833e49ea7SAndi Kleen int status; 15933e49ea7SAndi Kleen 160d20deb64SArnaldo Carvalho de Melo if (rec->evlist->workload.pid > 0) { 16133e49ea7SAndi Kleen if (!child_finished) 162d20deb64SArnaldo Carvalho de Melo kill(rec->evlist->workload.pid, SIGTERM); 163933da83aSChris Wilson 16433e49ea7SAndi Kleen wait(&status); 16533e49ea7SAndi Kleen if (WIFSIGNALED(status)) 166d20deb64SArnaldo Carvalho de Melo psignal(WTERMSIG(status), rec->progname); 16733e49ea7SAndi Kleen } 16833e49ea7SAndi Kleen 16918483b81SArnaldo Carvalho de Melo if (signr == -1 || signr == SIGUSR1) 170f7b7c26eSPeter Zijlstra return; 171f7b7c26eSPeter Zijlstra 172f7b7c26eSPeter Zijlstra signal(signr, SIG_DFL); 17386470930SIngo Molnar } 17486470930SIngo Molnar 1758c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec) 176dd7927f4SArnaldo Carvalho de Melo { 17756e52e85SArnaldo Carvalho de Melo char msg[512]; 1786a4bb04cSJiri Olsa struct perf_evsel *pos; 179d20deb64SArnaldo Carvalho de Melo struct perf_evlist *evlist = rec->evlist; 180d20deb64SArnaldo Carvalho de Melo struct perf_session *session = rec->session; 181b4006796SArnaldo Carvalho de Melo struct record_opts *opts = &rec->opts; 1828d3eca20SDavid Ahern int rc = 0; 183dd7927f4SArnaldo Carvalho de Melo 184f77a9518SArnaldo Carvalho de Melo perf_evlist__config(evlist, opts); 185cac21425SJiri Olsa 186dd7927f4SArnaldo Carvalho de Melo list_for_each_entry(pos, &evlist->entries, node) { 1873da297a6SIngo Molnar try_again: 1886a4bb04cSJiri Olsa if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { 18956e52e85SArnaldo Carvalho de Melo if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { 1903da297a6SIngo Molnar if (verbose) 191c0a54341SArnaldo Carvalho de Melo ui__warning("%s\n", msg); 1923da297a6SIngo Molnar goto try_again; 1933da297a6SIngo Molnar } 194ca6a4258SDavid Ahern 19556e52e85SArnaldo Carvalho de Melo rc = -errno; 19656e52e85SArnaldo Carvalho de Melo perf_evsel__open_strerror(pos, &opts->target, 19756e52e85SArnaldo Carvalho de Melo errno, msg, sizeof(msg)); 19856e52e85SArnaldo Carvalho de Melo ui__error("%s\n", msg); 1998d3eca20SDavid Ahern goto out; 2007c6a1c65SPeter Zijlstra } 2017c6a1c65SPeter Zijlstra } 2027c6a1c65SPeter Zijlstra 2031491a632SArnaldo Carvalho de Melo if (perf_evlist__apply_filters(evlist)) { 2040a102479SFrederic Weisbecker error("failed to set filter with %d (%s)\n", errno, 2050a102479SFrederic Weisbecker strerror(errno)); 2068d3eca20SDavid Ahern rc = -1; 2078d3eca20SDavid Ahern goto out; 2080a102479SFrederic Weisbecker } 2090a102479SFrederic Weisbecker 21018e60939SNelson Elhage if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { 2118d3eca20SDavid Ahern if (errno == EPERM) { 2128d3eca20SDavid Ahern pr_err("Permission error mapping pages.\n" 21318e60939SNelson Elhage "Consider increasing " 21418e60939SNelson Elhage "/proc/sys/kernel/perf_event_mlock_kb,\n" 21518e60939SNelson Elhage "or try again with a smaller value of -m/--mmap_pages.\n" 21653653d70SAdrian Hunter "(current value: %u)\n", opts->mmap_pages); 2178d3eca20SDavid Ahern rc = -errno; 2188d3eca20SDavid Ahern } else { 2198d3eca20SDavid Ahern pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); 2208d3eca20SDavid Ahern rc = -errno; 2218d3eca20SDavid Ahern } 2228d3eca20SDavid Ahern goto out; 22318e60939SNelson Elhage } 2240a27d7f9SArnaldo Carvalho de Melo 225a91e5431SArnaldo Carvalho de Melo session->evlist = evlist; 2267b56cce2SArnaldo Carvalho de Melo perf_session__set_id_hdr_size(session); 2278d3eca20SDavid Ahern out: 2288d3eca20SDavid Ahern return rc; 229a91e5431SArnaldo Carvalho de Melo } 230a91e5431SArnaldo Carvalho de Melo 2318c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec) 2326122e4e4SArnaldo Carvalho de Melo { 233f5fc1412SJiri Olsa struct perf_data_file *file = &rec->file; 234f5fc1412SJiri Olsa struct perf_session *session = rec->session; 2357ab75cffSDavid Ahern u64 start = session->header.data_offset; 2366122e4e4SArnaldo Carvalho de Melo 237f5fc1412SJiri Olsa u64 size = lseek(file->fd, 0, SEEK_CUR); 2389f591fd7SArnaldo Carvalho de Melo if (size == 0) 2399f591fd7SArnaldo Carvalho de Melo return 0; 2409f591fd7SArnaldo Carvalho de Melo 2417ab75cffSDavid Ahern return __perf_session__process_events(session, start, 2427ab75cffSDavid Ahern size - start, 2436122e4e4SArnaldo Carvalho de Melo size, &build_id__mark_dso_hit_ops); 2446122e4e4SArnaldo Carvalho de Melo } 2456122e4e4SArnaldo Carvalho de Melo 2468c6f45a7SArnaldo Carvalho de Melo static void record__exit(int status, void *arg) 247f5970550SPeter Zijlstra { 2488c6f45a7SArnaldo Carvalho de Melo struct record *rec = arg; 249f5fc1412SJiri Olsa struct perf_data_file *file = &rec->file; 250f5970550SPeter Zijlstra 2518d3eca20SDavid Ahern if (status != 0) 2528d3eca20SDavid Ahern return; 2538d3eca20SDavid Ahern 254f5fc1412SJiri Olsa if (!file->is_pipe) { 255d20deb64SArnaldo Carvalho de Melo rec->session->header.data_size += rec->bytes_written; 256d20deb64SArnaldo Carvalho de Melo 257d20deb64SArnaldo Carvalho de Melo if (!rec->no_buildid) 258d20deb64SArnaldo Carvalho de Melo process_buildids(rec); 259d20deb64SArnaldo Carvalho de Melo perf_session__write_header(rec->session, rec->evlist, 260f5fc1412SJiri Olsa file->fd, true); 261d20deb64SArnaldo Carvalho de Melo perf_session__delete(rec->session); 262d20deb64SArnaldo Carvalho de Melo perf_evlist__delete(rec->evlist); 263d65a458bSArnaldo Carvalho de Melo symbol__exit(); 264c7929e47STom Zanussi } 265f5970550SPeter Zijlstra } 266f5970550SPeter Zijlstra 2678115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data) 268a1645ce1SZhang, Yanmin { 269a1645ce1SZhang, Yanmin int err; 27045694aa7SArnaldo Carvalho de Melo struct perf_tool *tool = data; 271a1645ce1SZhang, Yanmin /* 272a1645ce1SZhang, Yanmin *As for guest kernel when processing subcommand record&report, 273a1645ce1SZhang, Yanmin *we arrange module mmap prior to guest kernel mmap and trigger 274a1645ce1SZhang, Yanmin *a preload dso because default guest module symbols are loaded 275a1645ce1SZhang, Yanmin *from guest kallsyms instead of /lib/modules/XXX/XXX. This 276a1645ce1SZhang, Yanmin *method is used to avoid symbol missing when the first addr is 277a1645ce1SZhang, Yanmin *in module instead of in guest kernel. 278a1645ce1SZhang, Yanmin */ 27945694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_modules(tool, process_synthesized_event, 280743eb868SArnaldo Carvalho de Melo machine); 281a1645ce1SZhang, Yanmin if (err < 0) 282a1645ce1SZhang, Yanmin pr_err("Couldn't record guest kernel [%d]'s reference" 28323346f21SArnaldo Carvalho de Melo " relocation symbol.\n", machine->pid); 284a1645ce1SZhang, Yanmin 285a1645ce1SZhang, Yanmin /* 286a1645ce1SZhang, Yanmin * We use _stext for guest kernel because guest kernel's /proc/kallsyms 287a1645ce1SZhang, Yanmin * have no _text sometimes. 288a1645ce1SZhang, Yanmin */ 28945694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 290743eb868SArnaldo Carvalho de Melo machine, "_text"); 291a1645ce1SZhang, Yanmin if (err < 0) 29245694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 293743eb868SArnaldo Carvalho de Melo machine, "_stext"); 294a1645ce1SZhang, Yanmin if (err < 0) 295a1645ce1SZhang, Yanmin pr_err("Couldn't record guest kernel [%d]'s reference" 29623346f21SArnaldo Carvalho de Melo " relocation symbol.\n", machine->pid); 297a1645ce1SZhang, Yanmin } 298a1645ce1SZhang, Yanmin 29998402807SFrederic Weisbecker static struct perf_event_header finished_round_event = { 30098402807SFrederic Weisbecker .size = sizeof(struct perf_event_header), 30198402807SFrederic Weisbecker .type = PERF_RECORD_FINISHED_ROUND, 30298402807SFrederic Weisbecker }; 30398402807SFrederic Weisbecker 3048c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec) 30598402807SFrederic Weisbecker { 3060e2e63ddSPeter Zijlstra int i; 3078d3eca20SDavid Ahern int rc = 0; 30898402807SFrederic Weisbecker 309d20deb64SArnaldo Carvalho de Melo for (i = 0; i < rec->evlist->nr_mmaps; i++) { 3108d3eca20SDavid Ahern if (rec->evlist->mmap[i].base) { 3118c6f45a7SArnaldo Carvalho de Melo if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { 3128d3eca20SDavid Ahern rc = -1; 3138d3eca20SDavid Ahern goto out; 3148d3eca20SDavid Ahern } 3158d3eca20SDavid Ahern } 31698402807SFrederic Weisbecker } 31798402807SFrederic Weisbecker 3182eeaaa09SStephane Eranian if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) 3198c6f45a7SArnaldo Carvalho de Melo rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); 3208d3eca20SDavid Ahern 3218d3eca20SDavid Ahern out: 3228d3eca20SDavid Ahern return rc; 32398402807SFrederic Weisbecker } 32498402807SFrederic Weisbecker 3258c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec) 32657706abcSDavid Ahern { 32757706abcSDavid Ahern struct perf_evlist *evsel_list = rec->evlist; 32857706abcSDavid Ahern struct perf_session *session = rec->session; 32957706abcSDavid Ahern int feat; 33057706abcSDavid Ahern 33157706abcSDavid Ahern for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++) 33257706abcSDavid Ahern perf_header__set_feat(&session->header, feat); 33357706abcSDavid Ahern 33457706abcSDavid Ahern if (rec->no_buildid) 33557706abcSDavid Ahern perf_header__clear_feat(&session->header, HEADER_BUILD_ID); 33657706abcSDavid Ahern 33757706abcSDavid Ahern if (!have_tracepoints(&evsel_list->entries)) 33857706abcSDavid Ahern perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); 33957706abcSDavid Ahern 34057706abcSDavid Ahern if (!rec->opts.branch_stack) 34157706abcSDavid Ahern perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); 34257706abcSDavid Ahern } 34357706abcSDavid Ahern 344*f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno; 345*f33cbe72SArnaldo Carvalho de Melo 346*f33cbe72SArnaldo Carvalho de Melo /* 347*f33cbe72SArnaldo Carvalho de Melo * perf_evlist__prepare_workload will send a SIGUSR1 348*f33cbe72SArnaldo Carvalho de Melo * if the fork fails, since we asked by setting its 349*f33cbe72SArnaldo Carvalho de Melo * want_signal to true. 350*f33cbe72SArnaldo Carvalho de Melo */ 351*f33cbe72SArnaldo Carvalho de Melo static void workload_exec_failed_signal(int signo, siginfo_t *info, 352*f33cbe72SArnaldo Carvalho de Melo void *ucontext __maybe_unused) 353*f33cbe72SArnaldo Carvalho de Melo { 354*f33cbe72SArnaldo Carvalho de Melo workload_exec_errno = info->si_value.sival_int; 355*f33cbe72SArnaldo Carvalho de Melo done = 1; 356*f33cbe72SArnaldo Carvalho de Melo signr = signo; 357*f33cbe72SArnaldo Carvalho de Melo child_finished = 1; 358*f33cbe72SArnaldo Carvalho de Melo } 359*f33cbe72SArnaldo Carvalho de Melo 3608c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv) 36186470930SIngo Molnar { 36257706abcSDavid Ahern int err; 3638b412664SPeter Zijlstra unsigned long waking = 0; 36446be604bSZhang, Yanmin const bool forks = argc > 0; 36523346f21SArnaldo Carvalho de Melo struct machine *machine; 36645694aa7SArnaldo Carvalho de Melo struct perf_tool *tool = &rec->tool; 367b4006796SArnaldo Carvalho de Melo struct record_opts *opts = &rec->opts; 368d20deb64SArnaldo Carvalho de Melo struct perf_evlist *evsel_list = rec->evlist; 369f5fc1412SJiri Olsa struct perf_data_file *file = &rec->file; 370d20deb64SArnaldo Carvalho de Melo struct perf_session *session; 3712711926aSJiri Olsa bool disabled = false; 37286470930SIngo Molnar 373d20deb64SArnaldo Carvalho de Melo rec->progname = argv[0]; 37433e49ea7SAndi Kleen 3758c6f45a7SArnaldo Carvalho de Melo on_exit(record__sig_exit, rec); 376f5970550SPeter Zijlstra signal(SIGCHLD, sig_handler); 377f5970550SPeter Zijlstra signal(SIGINT, sig_handler); 378804f7ac7SDavid Ahern signal(SIGTERM, sig_handler); 379f5970550SPeter Zijlstra 380f5fc1412SJiri Olsa session = perf_session__new(file, false, NULL); 38194c744b6SArnaldo Carvalho de Melo if (session == NULL) { 382a9a70bbcSArnaldo Carvalho de Melo pr_err("Not enough memory for reading perf file header\n"); 383a9a70bbcSArnaldo Carvalho de Melo return -1; 384a9a70bbcSArnaldo Carvalho de Melo } 385a9a70bbcSArnaldo Carvalho de Melo 386d20deb64SArnaldo Carvalho de Melo rec->session = session; 387d20deb64SArnaldo Carvalho de Melo 3888c6f45a7SArnaldo Carvalho de Melo record__init_features(rec); 389330aa675SStephane Eranian 390d4db3f16SArnaldo Carvalho de Melo if (forks) { 3916ef73ec4SNamhyung Kim err = perf_evlist__prepare_workload(evsel_list, &opts->target, 392f5fc1412SJiri Olsa argv, file->is_pipe, 39355e162eaSNamhyung Kim true); 39435b9d88eSArnaldo Carvalho de Melo if (err < 0) { 39535b9d88eSArnaldo Carvalho de Melo pr_err("Couldn't run the workload!\n"); 39635b9d88eSArnaldo Carvalho de Melo goto out_delete_session; 397856e9660SPeter Zijlstra } 398856e9660SPeter Zijlstra } 399856e9660SPeter Zijlstra 4008c6f45a7SArnaldo Carvalho de Melo if (record__open(rec) != 0) { 4018d3eca20SDavid Ahern err = -1; 4028d3eca20SDavid Ahern goto out_delete_session; 4038d3eca20SDavid Ahern } 40486470930SIngo Molnar 405a8bb559bSNamhyung Kim if (!evsel_list->nr_groups) 406a8bb559bSNamhyung Kim perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); 407a8bb559bSNamhyung Kim 408712a4b60SArnaldo Carvalho de Melo /* 4098c6f45a7SArnaldo Carvalho de Melo * perf_session__delete(session) will be called at record__exit() 410712a4b60SArnaldo Carvalho de Melo */ 4118c6f45a7SArnaldo Carvalho de Melo on_exit(record__exit, rec); 412712a4b60SArnaldo Carvalho de Melo 413f5fc1412SJiri Olsa if (file->is_pipe) { 414f5fc1412SJiri Olsa err = perf_header__write_pipe(file->fd); 415529870e3STom Zanussi if (err < 0) 4168d3eca20SDavid Ahern goto out_delete_session; 417563aecb2SJiri Olsa } else { 418a91e5431SArnaldo Carvalho de Melo err = perf_session__write_header(session, evsel_list, 419f5fc1412SJiri Olsa file->fd, false); 420d5eed904SArnaldo Carvalho de Melo if (err < 0) 4218d3eca20SDavid Ahern goto out_delete_session; 422d5eed904SArnaldo Carvalho de Melo } 4237c6a1c65SPeter Zijlstra 424d3665498SDavid Ahern if (!rec->no_buildid 425e20960c0SRobert Richter && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { 426d3665498SDavid Ahern pr_err("Couldn't generate buildids. " 427e20960c0SRobert Richter "Use --no-buildid to profile anyway.\n"); 4288d3eca20SDavid Ahern err = -1; 4298d3eca20SDavid Ahern goto out_delete_session; 430e20960c0SRobert Richter } 431e20960c0SRobert Richter 43234ba5122SArnaldo Carvalho de Melo machine = &session->machines.host; 433743eb868SArnaldo Carvalho de Melo 434f5fc1412SJiri Olsa if (file->is_pipe) { 43545694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_attrs(tool, session, 436a91e5431SArnaldo Carvalho de Melo process_synthesized_event); 4372c46dbb5STom Zanussi if (err < 0) { 4382c46dbb5STom Zanussi pr_err("Couldn't synthesize attrs.\n"); 4398d3eca20SDavid Ahern goto out_delete_session; 4402c46dbb5STom Zanussi } 441cd19a035STom Zanussi 442361c99a6SArnaldo Carvalho de Melo if (have_tracepoints(&evsel_list->entries)) { 44363e0c771STom Zanussi /* 44463e0c771STom Zanussi * FIXME err <= 0 here actually means that 44563e0c771STom Zanussi * there were no tracepoints so its not really 44663e0c771STom Zanussi * an error, just that we don't need to 44763e0c771STom Zanussi * synthesize anything. We really have to 44863e0c771STom Zanussi * return this more properly and also 44963e0c771STom Zanussi * propagate errors that now are calling die() 45063e0c771STom Zanussi */ 451f5fc1412SJiri Olsa err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list, 452743eb868SArnaldo Carvalho de Melo process_synthesized_event); 45363e0c771STom Zanussi if (err <= 0) { 45463e0c771STom Zanussi pr_err("Couldn't record tracing data.\n"); 4558d3eca20SDavid Ahern goto out_delete_session; 45663e0c771STom Zanussi } 457f34b9001SDavid Ahern rec->bytes_written += err; 4582c46dbb5STom Zanussi } 45963e0c771STom Zanussi } 4602c46dbb5STom Zanussi 46145694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 462743eb868SArnaldo Carvalho de Melo machine, "_text"); 46370162138SArnaldo Carvalho de Melo if (err < 0) 46445694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 465743eb868SArnaldo Carvalho de Melo machine, "_stext"); 466c1a3a4b9SArnaldo Carvalho de Melo if (err < 0) 467c1a3a4b9SArnaldo Carvalho de Melo pr_err("Couldn't record kernel reference relocation symbol\n" 468c1a3a4b9SArnaldo Carvalho de Melo "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 469c1a3a4b9SArnaldo Carvalho de Melo "Check /proc/kallsyms permission or run as root.\n"); 47056b03f3cSArnaldo Carvalho de Melo 47145694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_modules(tool, process_synthesized_event, 472743eb868SArnaldo Carvalho de Melo machine); 473c1a3a4b9SArnaldo Carvalho de Melo if (err < 0) 474c1a3a4b9SArnaldo Carvalho de Melo pr_err("Couldn't record kernel module information.\n" 475c1a3a4b9SArnaldo Carvalho de Melo "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 476c1a3a4b9SArnaldo Carvalho de Melo "Check /proc/modules permission or run as root.\n"); 477c1a3a4b9SArnaldo Carvalho de Melo 4787e383de4SArnaldo Carvalho de Melo if (perf_guest) { 479876650e6SArnaldo Carvalho de Melo machines__process_guests(&session->machines, 4807e383de4SArnaldo Carvalho de Melo perf_event__synthesize_guest_os, tool); 4817e383de4SArnaldo Carvalho de Melo } 482b7cece76SArnaldo Carvalho de Melo 483a33fbd56SArnaldo Carvalho de Melo err = __machine__synthesize_threads(machine, tool, &opts->target, evsel_list->threads, 48458d925dcSArnaldo Carvalho de Melo process_synthesized_event, opts->sample_address); 4858d3eca20SDavid Ahern if (err != 0) 4868d3eca20SDavid Ahern goto out_delete_session; 4878d3eca20SDavid Ahern 488d20deb64SArnaldo Carvalho de Melo if (rec->realtime_prio) { 48986470930SIngo Molnar struct sched_param param; 49086470930SIngo Molnar 491d20deb64SArnaldo Carvalho de Melo param.sched_priority = rec->realtime_prio; 49286470930SIngo Molnar if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { 4936beba7adSArnaldo Carvalho de Melo pr_err("Could not set realtime priority.\n"); 4948d3eca20SDavid Ahern err = -1; 4958d3eca20SDavid Ahern goto out_delete_session; 49686470930SIngo Molnar } 49786470930SIngo Molnar } 49886470930SIngo Molnar 499774cb499SJiri Olsa /* 500774cb499SJiri Olsa * When perf is starting the traced process, all the events 501774cb499SJiri Olsa * (apart from group members) have enable_on_exec=1 set, 502774cb499SJiri Olsa * so don't spoil it by prematurely enabling them. 503774cb499SJiri Olsa */ 504602ad878SArnaldo Carvalho de Melo if (!target__none(&opts->target)) 505764e16a3SDavid Ahern perf_evlist__enable(evsel_list); 506764e16a3SDavid Ahern 507856e9660SPeter Zijlstra /* 508856e9660SPeter Zijlstra * Let the child rip 509856e9660SPeter Zijlstra */ 510*f33cbe72SArnaldo Carvalho de Melo if (forks) { 511*f33cbe72SArnaldo Carvalho de Melo struct sigaction act = { 512*f33cbe72SArnaldo Carvalho de Melo .sa_flags = SA_SIGINFO, 513*f33cbe72SArnaldo Carvalho de Melo .sa_sigaction = workload_exec_failed_signal, 514*f33cbe72SArnaldo Carvalho de Melo }; 515*f33cbe72SArnaldo Carvalho de Melo /* 516*f33cbe72SArnaldo Carvalho de Melo * perf_evlist__prepare_workload will, after we call 517*f33cbe72SArnaldo Carvalho de Melo * perf_evlist__start_Workload, send a SIGUSR1 if the exec call 518*f33cbe72SArnaldo Carvalho de Melo * fails, that we will catch in workload_signal to flip 519*f33cbe72SArnaldo Carvalho de Melo * workload_exec_errno. 520*f33cbe72SArnaldo Carvalho de Melo */ 521*f33cbe72SArnaldo Carvalho de Melo sigaction(SIGUSR1, &act, NULL); 52235b9d88eSArnaldo Carvalho de Melo perf_evlist__start_workload(evsel_list); 523*f33cbe72SArnaldo Carvalho de Melo } 524856e9660SPeter Zijlstra 525649c48a9SPeter Zijlstra for (;;) { 526d20deb64SArnaldo Carvalho de Melo int hits = rec->samples; 52786470930SIngo Molnar 5288c6f45a7SArnaldo Carvalho de Melo if (record__mmap_read_all(rec) < 0) { 5298d3eca20SDavid Ahern err = -1; 5308d3eca20SDavid Ahern goto out_delete_session; 5318d3eca20SDavid Ahern } 53286470930SIngo Molnar 533d20deb64SArnaldo Carvalho de Melo if (hits == rec->samples) { 534649c48a9SPeter Zijlstra if (done) 535649c48a9SPeter Zijlstra break; 5365c581041SArnaldo Carvalho de Melo err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); 5378b412664SPeter Zijlstra waking++; 5388b412664SPeter Zijlstra } 5398b412664SPeter Zijlstra 540774cb499SJiri Olsa /* 541774cb499SJiri Olsa * When perf is starting the traced process, at the end events 542774cb499SJiri Olsa * die with the process and we wait for that. Thus no need to 543774cb499SJiri Olsa * disable events in this case. 544774cb499SJiri Olsa */ 545602ad878SArnaldo Carvalho de Melo if (done && !disabled && !target__none(&opts->target)) { 5464152ab37SArnaldo Carvalho de Melo perf_evlist__disable(evsel_list); 5472711926aSJiri Olsa disabled = true; 5482711926aSJiri Olsa } 5498b412664SPeter Zijlstra } 5508b412664SPeter Zijlstra 551*f33cbe72SArnaldo Carvalho de Melo if (forks && workload_exec_errno) { 552*f33cbe72SArnaldo Carvalho de Melo char msg[512]; 553*f33cbe72SArnaldo Carvalho de Melo const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); 554*f33cbe72SArnaldo Carvalho de Melo pr_err("Workload failed: %s\n", emsg); 555*f33cbe72SArnaldo Carvalho de Melo err = -1; 556*f33cbe72SArnaldo Carvalho de Melo goto out_delete_session; 557*f33cbe72SArnaldo Carvalho de Melo } 558*f33cbe72SArnaldo Carvalho de Melo 55918483b81SArnaldo Carvalho de Melo if (quiet || signr == SIGUSR1) 560b44308f5SArnaldo Carvalho de Melo return 0; 561b44308f5SArnaldo Carvalho de Melo 5628b412664SPeter Zijlstra fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); 56386470930SIngo Molnar 56486470930SIngo Molnar /* 56586470930SIngo Molnar * Approximate RIP event size: 24 bytes. 56686470930SIngo Molnar */ 56786470930SIngo Molnar fprintf(stderr, 5689486aa38SArnaldo Carvalho de Melo "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", 569d20deb64SArnaldo Carvalho de Melo (double)rec->bytes_written / 1024.0 / 1024.0, 5706a4d98d7SJiri Olsa file->path, 571d20deb64SArnaldo Carvalho de Melo rec->bytes_written / 24); 57286470930SIngo Molnar 57386470930SIngo Molnar return 0; 57439d17dacSArnaldo Carvalho de Melo 57539d17dacSArnaldo Carvalho de Melo out_delete_session: 57639d17dacSArnaldo Carvalho de Melo perf_session__delete(session); 57739d17dacSArnaldo Carvalho de Melo return err; 57886470930SIngo Molnar } 57986470930SIngo Molnar 580bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \ 581bdfebd84SRoberto Agostino Vitillo { .name = n, .mode = (m) } 582bdfebd84SRoberto Agostino Vitillo 583bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL } 584bdfebd84SRoberto Agostino Vitillo 585bdfebd84SRoberto Agostino Vitillo struct branch_mode { 586bdfebd84SRoberto Agostino Vitillo const char *name; 587bdfebd84SRoberto Agostino Vitillo int mode; 588bdfebd84SRoberto Agostino Vitillo }; 589bdfebd84SRoberto Agostino Vitillo 590bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = { 591bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER), 592bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL), 593bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV), 594bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY), 595bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL), 596bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN), 597bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL), 5980126d493SAndi Kleen BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX), 5990126d493SAndi Kleen BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX), 6000126d493SAndi Kleen BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX), 601bdfebd84SRoberto Agostino Vitillo BRANCH_END 602bdfebd84SRoberto Agostino Vitillo }; 603bdfebd84SRoberto Agostino Vitillo 604bdfebd84SRoberto Agostino Vitillo static int 605a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset) 606bdfebd84SRoberto Agostino Vitillo { 607bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \ 608bdfebd84SRoberto Agostino Vitillo (PERF_SAMPLE_BRANCH_USER |\ 609bdfebd84SRoberto Agostino Vitillo PERF_SAMPLE_BRANCH_KERNEL |\ 610bdfebd84SRoberto Agostino Vitillo PERF_SAMPLE_BRANCH_HV) 611bdfebd84SRoberto Agostino Vitillo 612bdfebd84SRoberto Agostino Vitillo uint64_t *mode = (uint64_t *)opt->value; 613bdfebd84SRoberto Agostino Vitillo const struct branch_mode *br; 614a5aabdacSStephane Eranian char *s, *os = NULL, *p; 615bdfebd84SRoberto Agostino Vitillo int ret = -1; 616bdfebd84SRoberto Agostino Vitillo 617a5aabdacSStephane Eranian if (unset) 618a5aabdacSStephane Eranian return 0; 619bdfebd84SRoberto Agostino Vitillo 620a5aabdacSStephane Eranian /* 621a5aabdacSStephane Eranian * cannot set it twice, -b + --branch-filter for instance 622a5aabdacSStephane Eranian */ 623a5aabdacSStephane Eranian if (*mode) 624a5aabdacSStephane Eranian return -1; 625a5aabdacSStephane Eranian 626a5aabdacSStephane Eranian /* str may be NULL in case no arg is passed to -b */ 627a5aabdacSStephane Eranian if (str) { 628bdfebd84SRoberto Agostino Vitillo /* because str is read-only */ 629bdfebd84SRoberto Agostino Vitillo s = os = strdup(str); 630bdfebd84SRoberto Agostino Vitillo if (!s) 631bdfebd84SRoberto Agostino Vitillo return -1; 632bdfebd84SRoberto Agostino Vitillo 633bdfebd84SRoberto Agostino Vitillo for (;;) { 634bdfebd84SRoberto Agostino Vitillo p = strchr(s, ','); 635bdfebd84SRoberto Agostino Vitillo if (p) 636bdfebd84SRoberto Agostino Vitillo *p = '\0'; 637bdfebd84SRoberto Agostino Vitillo 638bdfebd84SRoberto Agostino Vitillo for (br = branch_modes; br->name; br++) { 639bdfebd84SRoberto Agostino Vitillo if (!strcasecmp(s, br->name)) 640bdfebd84SRoberto Agostino Vitillo break; 641bdfebd84SRoberto Agostino Vitillo } 642a5aabdacSStephane Eranian if (!br->name) { 643a5aabdacSStephane Eranian ui__warning("unknown branch filter %s," 644a5aabdacSStephane Eranian " check man page\n", s); 645bdfebd84SRoberto Agostino Vitillo goto error; 646a5aabdacSStephane Eranian } 647bdfebd84SRoberto Agostino Vitillo 648bdfebd84SRoberto Agostino Vitillo *mode |= br->mode; 649bdfebd84SRoberto Agostino Vitillo 650bdfebd84SRoberto Agostino Vitillo if (!p) 651bdfebd84SRoberto Agostino Vitillo break; 652bdfebd84SRoberto Agostino Vitillo 653bdfebd84SRoberto Agostino Vitillo s = p + 1; 654bdfebd84SRoberto Agostino Vitillo } 655a5aabdacSStephane Eranian } 656bdfebd84SRoberto Agostino Vitillo ret = 0; 657bdfebd84SRoberto Agostino Vitillo 658a5aabdacSStephane Eranian /* default to any branch */ 659bdfebd84SRoberto Agostino Vitillo if ((*mode & ~ONLY_PLM) == 0) { 660a5aabdacSStephane Eranian *mode = PERF_SAMPLE_BRANCH_ANY; 661bdfebd84SRoberto Agostino Vitillo } 662bdfebd84SRoberto Agostino Vitillo error: 663bdfebd84SRoberto Agostino Vitillo free(os); 664bdfebd84SRoberto Agostino Vitillo return ret; 665bdfebd84SRoberto Agostino Vitillo } 666bdfebd84SRoberto Agostino Vitillo 66789fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT 66826d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size) 66926d33022SJiri Olsa { 67026d33022SJiri Olsa char *endptr; 67126d33022SJiri Olsa unsigned long size; 67226d33022SJiri Olsa unsigned long max_size = round_down(USHRT_MAX, sizeof(u64)); 67326d33022SJiri Olsa 67426d33022SJiri Olsa size = strtoul(str, &endptr, 0); 67526d33022SJiri Olsa 67626d33022SJiri Olsa do { 67726d33022SJiri Olsa if (*endptr) 67826d33022SJiri Olsa break; 67926d33022SJiri Olsa 68026d33022SJiri Olsa size = round_up(size, sizeof(u64)); 68126d33022SJiri Olsa if (!size || size > max_size) 68226d33022SJiri Olsa break; 68326d33022SJiri Olsa 68426d33022SJiri Olsa *_size = size; 68526d33022SJiri Olsa return 0; 68626d33022SJiri Olsa 68726d33022SJiri Olsa } while (0); 68826d33022SJiri Olsa 68926d33022SJiri Olsa pr_err("callchain: Incorrect stack dump size (max %ld): %s\n", 69026d33022SJiri Olsa max_size, str); 69126d33022SJiri Olsa return -1; 69226d33022SJiri Olsa } 69389fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */ 69426d33022SJiri Olsa 695b4006796SArnaldo Carvalho de Melo int record_parse_callchain(const char *arg, struct record_opts *opts) 69626d33022SJiri Olsa { 69726d33022SJiri Olsa char *tok, *name, *saveptr = NULL; 69826d33022SJiri Olsa char *buf; 69926d33022SJiri Olsa int ret = -1; 70026d33022SJiri Olsa 70126d33022SJiri Olsa /* We need buffer that we know we can write to. */ 70226d33022SJiri Olsa buf = malloc(strlen(arg) + 1); 70326d33022SJiri Olsa if (!buf) 70426d33022SJiri Olsa return -ENOMEM; 70526d33022SJiri Olsa 70626d33022SJiri Olsa strcpy(buf, arg); 70726d33022SJiri Olsa 70826d33022SJiri Olsa tok = strtok_r((char *)buf, ",", &saveptr); 70926d33022SJiri Olsa name = tok ? : (char *)buf; 71026d33022SJiri Olsa 71126d33022SJiri Olsa do { 71226d33022SJiri Olsa /* Framepointer style */ 71326d33022SJiri Olsa if (!strncmp(name, "fp", sizeof("fp"))) { 71426d33022SJiri Olsa if (!strtok_r(NULL, ",", &saveptr)) { 715c5ff78c3SArnaldo Carvalho de Melo opts->call_graph = CALLCHAIN_FP; 71626d33022SJiri Olsa ret = 0; 71726d33022SJiri Olsa } else 71826d33022SJiri Olsa pr_err("callchain: No more arguments " 71926d33022SJiri Olsa "needed for -g fp\n"); 72026d33022SJiri Olsa break; 72126d33022SJiri Olsa 72289fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT 72326d33022SJiri Olsa /* Dwarf style */ 72426d33022SJiri Olsa } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { 72561eaa3beSArnaldo Carvalho de Melo const unsigned long default_stack_dump_size = 8192; 72661eaa3beSArnaldo Carvalho de Melo 72726d33022SJiri Olsa ret = 0; 728c5ff78c3SArnaldo Carvalho de Melo opts->call_graph = CALLCHAIN_DWARF; 729c5ff78c3SArnaldo Carvalho de Melo opts->stack_dump_size = default_stack_dump_size; 73026d33022SJiri Olsa 73126d33022SJiri Olsa tok = strtok_r(NULL, ",", &saveptr); 73226d33022SJiri Olsa if (tok) { 73326d33022SJiri Olsa unsigned long size = 0; 73426d33022SJiri Olsa 73526d33022SJiri Olsa ret = get_stack_size(tok, &size); 736c5ff78c3SArnaldo Carvalho de Melo opts->stack_dump_size = size; 73726d33022SJiri Olsa } 73889fe808aSIngo Molnar #endif /* HAVE_LIBUNWIND_SUPPORT */ 73926d33022SJiri Olsa } else { 74009b0fd45SJiri Olsa pr_err("callchain: Unknown --call-graph option " 74126d33022SJiri Olsa "value: %s\n", arg); 74226d33022SJiri Olsa break; 74326d33022SJiri Olsa } 74426d33022SJiri Olsa 74526d33022SJiri Olsa } while (0); 74626d33022SJiri Olsa 74726d33022SJiri Olsa free(buf); 74809b0fd45SJiri Olsa return ret; 74909b0fd45SJiri Olsa } 75026d33022SJiri Olsa 751b4006796SArnaldo Carvalho de Melo static void callchain_debug(struct record_opts *opts) 75209b0fd45SJiri Olsa { 753c5ff78c3SArnaldo Carvalho de Melo pr_debug("callchain: type %d\n", opts->call_graph); 75426d33022SJiri Olsa 75509b0fd45SJiri Olsa if (opts->call_graph == CALLCHAIN_DWARF) 75609b0fd45SJiri Olsa pr_debug("callchain: stack dump size %d\n", 75709b0fd45SJiri Olsa opts->stack_dump_size); 75809b0fd45SJiri Olsa } 75909b0fd45SJiri Olsa 76009b0fd45SJiri Olsa int record_parse_callchain_opt(const struct option *opt, 76109b0fd45SJiri Olsa const char *arg, 76209b0fd45SJiri Olsa int unset) 76309b0fd45SJiri Olsa { 764b4006796SArnaldo Carvalho de Melo struct record_opts *opts = opt->value; 76509b0fd45SJiri Olsa int ret; 76609b0fd45SJiri Olsa 76709b0fd45SJiri Olsa /* --no-call-graph */ 76809b0fd45SJiri Olsa if (unset) { 76909b0fd45SJiri Olsa opts->call_graph = CALLCHAIN_NONE; 77009b0fd45SJiri Olsa pr_debug("callchain: disabled\n"); 77109b0fd45SJiri Olsa return 0; 77209b0fd45SJiri Olsa } 77309b0fd45SJiri Olsa 77409b0fd45SJiri Olsa ret = record_parse_callchain(arg, opts); 77509b0fd45SJiri Olsa if (!ret) 77609b0fd45SJiri Olsa callchain_debug(opts); 77709b0fd45SJiri Olsa 77826d33022SJiri Olsa return ret; 77926d33022SJiri Olsa } 78026d33022SJiri Olsa 78109b0fd45SJiri Olsa int record_callchain_opt(const struct option *opt, 78209b0fd45SJiri Olsa const char *arg __maybe_unused, 78309b0fd45SJiri Olsa int unset __maybe_unused) 78409b0fd45SJiri Olsa { 785b4006796SArnaldo Carvalho de Melo struct record_opts *opts = opt->value; 78609b0fd45SJiri Olsa 78709b0fd45SJiri Olsa if (opts->call_graph == CALLCHAIN_NONE) 78809b0fd45SJiri Olsa opts->call_graph = CALLCHAIN_FP; 78909b0fd45SJiri Olsa 79009b0fd45SJiri Olsa callchain_debug(opts); 79109b0fd45SJiri Olsa return 0; 79209b0fd45SJiri Olsa } 79309b0fd45SJiri Olsa 79486470930SIngo Molnar static const char * const record_usage[] = { 79586470930SIngo Molnar "perf record [<options>] [<command>]", 79686470930SIngo Molnar "perf record [<options>] -- <command> [<options>]", 79786470930SIngo Molnar NULL 79886470930SIngo Molnar }; 79986470930SIngo Molnar 800d20deb64SArnaldo Carvalho de Melo /* 8018c6f45a7SArnaldo Carvalho de Melo * XXX Ideally would be local to cmd_record() and passed to a record__new 8028c6f45a7SArnaldo Carvalho de Melo * because we need to have access to it in record__exit, that is called 803d20deb64SArnaldo Carvalho de Melo * after cmd_record() exits, but since record_options need to be accessible to 804d20deb64SArnaldo Carvalho de Melo * builtin-script, leave it here. 805d20deb64SArnaldo Carvalho de Melo * 806d20deb64SArnaldo Carvalho de Melo * At least we don't ouch it in all the other functions here directly. 807d20deb64SArnaldo Carvalho de Melo * 808d20deb64SArnaldo Carvalho de Melo * Just say no to tons of global variables, sigh. 809d20deb64SArnaldo Carvalho de Melo */ 8108c6f45a7SArnaldo Carvalho de Melo static struct record record = { 811d20deb64SArnaldo Carvalho de Melo .opts = { 812d20deb64SArnaldo Carvalho de Melo .mmap_pages = UINT_MAX, 813d20deb64SArnaldo Carvalho de Melo .user_freq = UINT_MAX, 814d20deb64SArnaldo Carvalho de Melo .user_interval = ULLONG_MAX, 815447a6013SArnaldo Carvalho de Melo .freq = 4000, 816d1cb9fceSNamhyung Kim .target = { 817d1cb9fceSNamhyung Kim .uses_mmap = true, 8183aa5939dSAdrian Hunter .default_per_cpu = true, 819d1cb9fceSNamhyung Kim }, 820d20deb64SArnaldo Carvalho de Melo }, 821d20deb64SArnaldo Carvalho de Melo }; 8227865e817SFrederic Weisbecker 82309b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " 82461eaa3beSArnaldo Carvalho de Melo 82589fe808aSIngo Molnar #ifdef HAVE_LIBUNWIND_SUPPORT 82609b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf"; 82761eaa3beSArnaldo Carvalho de Melo #else 82809b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp"; 82961eaa3beSArnaldo Carvalho de Melo #endif 83061eaa3beSArnaldo Carvalho de Melo 831d20deb64SArnaldo Carvalho de Melo /* 832d20deb64SArnaldo Carvalho de Melo * XXX Will stay a global variable till we fix builtin-script.c to stop messing 833d20deb64SArnaldo Carvalho de Melo * with it and switch to use the library functions in perf_evlist that came 834b4006796SArnaldo Carvalho de Melo * from builtin-record.c, i.e. use record_opts, 835d20deb64SArnaldo Carvalho de Melo * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', 836d20deb64SArnaldo Carvalho de Melo * using pipes, etc. 837d20deb64SArnaldo Carvalho de Melo */ 838bca647aaSTom Zanussi const struct option record_options[] = { 839d20deb64SArnaldo Carvalho de Melo OPT_CALLBACK('e', "event", &record.evlist, "event", 84086470930SIngo Molnar "event selector. use 'perf list' to list available events", 841f120f9d5SJiri Olsa parse_events_option), 842d20deb64SArnaldo Carvalho de Melo OPT_CALLBACK(0, "filter", &record.evlist, "filter", 843c171b552SLi Zefan "event filter", parse_filter), 844bea03405SNamhyung Kim OPT_STRING('p', "pid", &record.opts.target.pid, "pid", 845d6d901c2SZhang, Yanmin "record events on existing process id"), 846bea03405SNamhyung Kim OPT_STRING('t', "tid", &record.opts.target.tid, "tid", 847d6d901c2SZhang, Yanmin "record events on existing thread id"), 848d20deb64SArnaldo Carvalho de Melo OPT_INTEGER('r', "realtime", &record.realtime_prio, 84986470930SIngo Molnar "collect data with this RT SCHED_FIFO priority"), 850d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay, 851acac03faSKirill Smelkov "collect data without buffering"), 852d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, 853daac07b2SFrederic Weisbecker "collect raw sample records from all opened counters"), 854bea03405SNamhyung Kim OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide, 85586470930SIngo Molnar "system-wide collection from all CPUs"), 856bea03405SNamhyung Kim OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu", 857c45c6ea2SStephane Eranian "list of cpus to monitor"), 858d20deb64SArnaldo Carvalho de Melo OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), 859f5fc1412SJiri Olsa OPT_STRING('o', "output", &record.file.path, "file", 86086470930SIngo Molnar "output file name"), 86169e7e5b0SAdrian Hunter OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit, 86269e7e5b0SAdrian Hunter &record.opts.no_inherit_set, 8632e6cdf99SStephane Eranian "child tasks do not inherit counters"), 864d20deb64SArnaldo Carvalho de Melo OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), 865994a1f78SJiri Olsa OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages", 866994a1f78SJiri Olsa "number of mmap data pages", 867994a1f78SJiri Olsa perf_evlist__parse_mmap_pages), 868d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN(0, "group", &record.opts.group, 86943bece79SLin Ming "put the counters into a counter group"), 87009b0fd45SJiri Olsa OPT_CALLBACK_NOOPT('g', NULL, &record.opts, 87109b0fd45SJiri Olsa NULL, "enables call-graph recording" , 87209b0fd45SJiri Olsa &record_callchain_opt), 87309b0fd45SJiri Olsa OPT_CALLBACK(0, "call-graph", &record.opts, 87475d9a108SArnaldo Carvalho de Melo "mode[,dump_size]", record_callchain_help, 87509b0fd45SJiri Olsa &record_parse_callchain_opt), 876c0555642SIan Munsie OPT_INCR('v', "verbose", &verbose, 8773da297a6SIngo Molnar "be more verbose (show counter open errors, etc)"), 878b44308f5SArnaldo Carvalho de Melo OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 879d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat, 880649c48a9SPeter Zijlstra "per thread counts"), 881d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('d', "data", &record.opts.sample_address, 8824bba828dSAnton Blanchard "Sample addresses"), 883d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"), 8843e76ac78SAndrew Vagin OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"), 885d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, 886649c48a9SPeter Zijlstra "don't sample"), 887d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache, 888a1ac1d3cSStephane Eranian "do not update the buildid cache"), 889d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('B', "no-buildid", &record.no_buildid, 890baa2f6ceSArnaldo Carvalho de Melo "do not collect buildids in perf.data"), 891d20deb64SArnaldo Carvalho de Melo OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 892023695d9SStephane Eranian "monitor event in cgroup name only", 893023695d9SStephane Eranian parse_cgroups), 894bea03405SNamhyung Kim OPT_STRING('u', "uid", &record.opts.target.uid_str, "user", 895bea03405SNamhyung Kim "user to profile"), 896a5aabdacSStephane Eranian 897a5aabdacSStephane Eranian OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack, 898a5aabdacSStephane Eranian "branch any", "sample any taken branches", 899a5aabdacSStephane Eranian parse_branch_stack), 900a5aabdacSStephane Eranian 901a5aabdacSStephane Eranian OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack, 902a5aabdacSStephane Eranian "branch filter mask", "branch stack filter modes", 903bdfebd84SRoberto Agostino Vitillo parse_branch_stack), 90405484298SAndi Kleen OPT_BOOLEAN('W', "weight", &record.opts.sample_weight, 90505484298SAndi Kleen "sample by weight (on special events only)"), 906475eeab9SAndi Kleen OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction, 907475eeab9SAndi Kleen "sample transaction flags (special events only)"), 9083aa5939dSAdrian Hunter OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread, 9093aa5939dSAdrian Hunter "use per-thread mmaps"), 91086470930SIngo Molnar OPT_END() 91186470930SIngo Molnar }; 91286470930SIngo Molnar 9131d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) 91486470930SIngo Molnar { 91569aad6f1SArnaldo Carvalho de Melo int err = -ENOMEM; 916d20deb64SArnaldo Carvalho de Melo struct perf_evlist *evsel_list; 9178c6f45a7SArnaldo Carvalho de Melo struct record *rec = &record; 91816ad2ffbSNamhyung Kim char errbuf[BUFSIZ]; 91986470930SIngo Molnar 920334fe7a3SNamhyung Kim evsel_list = perf_evlist__new(); 921361c99a6SArnaldo Carvalho de Melo if (evsel_list == NULL) 922361c99a6SArnaldo Carvalho de Melo return -ENOMEM; 923361c99a6SArnaldo Carvalho de Melo 924d20deb64SArnaldo Carvalho de Melo rec->evlist = evsel_list; 925d20deb64SArnaldo Carvalho de Melo 926bca647aaSTom Zanussi argc = parse_options(argc, argv, record_options, record_usage, 927a0541234SAnton Blanchard PARSE_OPT_STOP_AT_NON_OPTION); 928602ad878SArnaldo Carvalho de Melo if (!argc && target__none(&rec->opts.target)) 929bca647aaSTom Zanussi usage_with_options(record_usage, record_options); 93086470930SIngo Molnar 931bea03405SNamhyung Kim if (nr_cgroups && !rec->opts.target.system_wide) { 9323780f488SNamhyung Kim ui__error("cgroup monitoring only available in" 933023695d9SStephane Eranian " system-wide mode\n"); 934023695d9SStephane Eranian usage_with_options(record_usage, record_options); 935023695d9SStephane Eranian } 936023695d9SStephane Eranian 937655000e7SArnaldo Carvalho de Melo symbol__init(); 938baa2f6ceSArnaldo Carvalho de Melo 939ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) 940646aaea6SArnaldo Carvalho de Melo pr_warning( 941646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n" 942ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n" 943646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n" 944646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n" 945646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n" 946646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n" 947646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n"); 948ec80fde7SArnaldo Carvalho de Melo 949d20deb64SArnaldo Carvalho de Melo if (rec->no_buildid_cache || rec->no_buildid) 950a1ac1d3cSStephane Eranian disable_buildid_cache(); 951655000e7SArnaldo Carvalho de Melo 952361c99a6SArnaldo Carvalho de Melo if (evsel_list->nr_entries == 0 && 953361c99a6SArnaldo Carvalho de Melo perf_evlist__add_default(evsel_list) < 0) { 95469aad6f1SArnaldo Carvalho de Melo pr_err("Not enough memory for event selector list\n"); 95569aad6f1SArnaldo Carvalho de Melo goto out_symbol_exit; 956bbd36e5eSPeter Zijlstra } 95786470930SIngo Molnar 95869e7e5b0SAdrian Hunter if (rec->opts.target.tid && !rec->opts.no_inherit_set) 95969e7e5b0SAdrian Hunter rec->opts.no_inherit = true; 96069e7e5b0SAdrian Hunter 961602ad878SArnaldo Carvalho de Melo err = target__validate(&rec->opts.target); 96216ad2ffbSNamhyung Kim if (err) { 963602ad878SArnaldo Carvalho de Melo target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 96416ad2ffbSNamhyung Kim ui__warning("%s", errbuf); 96516ad2ffbSNamhyung Kim } 9664bd0f2d2SNamhyung Kim 967602ad878SArnaldo Carvalho de Melo err = target__parse_uid(&rec->opts.target); 96816ad2ffbSNamhyung Kim if (err) { 96916ad2ffbSNamhyung Kim int saved_errno = errno; 97016ad2ffbSNamhyung Kim 971602ad878SArnaldo Carvalho de Melo target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 9723780f488SNamhyung Kim ui__error("%s", errbuf); 97316ad2ffbSNamhyung Kim 97416ad2ffbSNamhyung Kim err = -saved_errno; 9758fa60e1fSNamhyung Kim goto out_symbol_exit; 97616ad2ffbSNamhyung Kim } 9770d37aa34SArnaldo Carvalho de Melo 97816ad2ffbSNamhyung Kim err = -ENOMEM; 979b809ac10SNamhyung Kim if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) 980dd7927f4SArnaldo Carvalho de Melo usage_with_options(record_usage, record_options); 98169aad6f1SArnaldo Carvalho de Melo 982b4006796SArnaldo Carvalho de Melo if (record_opts__config(&rec->opts)) { 98339d17dacSArnaldo Carvalho de Melo err = -EINVAL; 9845c581041SArnaldo Carvalho de Melo goto out_free_fd; 9857e4ff9e3SMike Galbraith } 9867e4ff9e3SMike Galbraith 987d20deb64SArnaldo Carvalho de Melo err = __cmd_record(&record, argc, argv); 9888fa60e1fSNamhyung Kim 9898fa60e1fSNamhyung Kim perf_evlist__munmap(evsel_list); 9908fa60e1fSNamhyung Kim perf_evlist__close(evsel_list); 99139d17dacSArnaldo Carvalho de Melo out_free_fd: 9927e2ed097SArnaldo Carvalho de Melo perf_evlist__delete_maps(evsel_list); 993d65a458bSArnaldo Carvalho de Melo out_symbol_exit: 994d65a458bSArnaldo Carvalho de Melo symbol__exit(); 99539d17dacSArnaldo Carvalho de Melo return err; 99686470930SIngo Molnar } 997