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 3378da39faSBernhard Rosenkraenzer 348c6f45a7SArnaldo Carvalho de Melo struct record { 3545694aa7SArnaldo Carvalho de Melo struct perf_tool tool; 36b4006796SArnaldo Carvalho de Melo struct record_opts opts; 37d20deb64SArnaldo Carvalho de Melo u64 bytes_written; 38f5fc1412SJiri Olsa struct perf_data_file file; 39d20deb64SArnaldo Carvalho de Melo struct perf_evlist *evlist; 40d20deb64SArnaldo Carvalho de Melo struct perf_session *session; 41d20deb64SArnaldo Carvalho de Melo const char *progname; 42d20deb64SArnaldo Carvalho de Melo int realtime_prio; 43d20deb64SArnaldo Carvalho de Melo bool no_buildid; 44d20deb64SArnaldo Carvalho de Melo bool no_buildid_cache; 45d20deb64SArnaldo Carvalho de Melo long samples; 460f82ebc4SArnaldo Carvalho de Melo }; 4786470930SIngo Molnar 488c6f45a7SArnaldo Carvalho de Melo static int record__write(struct record *rec, void *bf, size_t size) 49f5970550SPeter Zijlstra { 50cf8b2e69SArnaldo Carvalho de Melo if (perf_data_file__write(rec->session->file, bf, size) < 0) { 514f624685SAdrian Hunter pr_err("failed to write perf data, error: %m\n"); 528d3eca20SDavid Ahern return -1; 538d3eca20SDavid Ahern } 54f5970550SPeter Zijlstra 55cf8b2e69SArnaldo Carvalho de Melo rec->bytes_written += size; 568d3eca20SDavid Ahern return 0; 57f5970550SPeter Zijlstra } 58f5970550SPeter Zijlstra 5945694aa7SArnaldo Carvalho de Melo static int process_synthesized_event(struct perf_tool *tool, 60d20deb64SArnaldo Carvalho de Melo union perf_event *event, 611d037ca1SIrina Tirdea struct perf_sample *sample __maybe_unused, 621d037ca1SIrina Tirdea struct machine *machine __maybe_unused) 63234fbbf5SArnaldo Carvalho de Melo { 648c6f45a7SArnaldo Carvalho de Melo struct record *rec = container_of(tool, struct record, tool); 658c6f45a7SArnaldo Carvalho de Melo return record__write(rec, event, event->header.size); 66234fbbf5SArnaldo Carvalho de Melo } 67234fbbf5SArnaldo Carvalho de Melo 68*e5685730SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, int idx) 6986470930SIngo Molnar { 70*e5685730SArnaldo Carvalho de Melo struct perf_mmap *md = &rec->evlist->mmap[idx]; 71744bd8aaSArnaldo Carvalho de Melo unsigned int head = perf_mmap__read_head(md); 7286470930SIngo Molnar unsigned int old = md->prev; 73918512b4SJiri Olsa unsigned char *data = md->base + page_size; 7486470930SIngo Molnar unsigned long size; 7586470930SIngo Molnar void *buf; 768d3eca20SDavid Ahern int rc = 0; 7786470930SIngo Molnar 78dc82009aSArnaldo Carvalho de Melo if (old == head) 798d3eca20SDavid Ahern return 0; 8086470930SIngo Molnar 81d20deb64SArnaldo Carvalho de Melo rec->samples++; 8286470930SIngo Molnar 8386470930SIngo Molnar size = head - old; 8486470930SIngo Molnar 8586470930SIngo Molnar if ((old & md->mask) + size != (head & md->mask)) { 8686470930SIngo Molnar buf = &data[old & md->mask]; 8786470930SIngo Molnar size = md->mask + 1 - (old & md->mask); 8886470930SIngo Molnar old += size; 8986470930SIngo Molnar 908c6f45a7SArnaldo Carvalho de Melo if (record__write(rec, buf, size) < 0) { 918d3eca20SDavid Ahern rc = -1; 928d3eca20SDavid Ahern goto out; 938d3eca20SDavid Ahern } 9486470930SIngo Molnar } 9586470930SIngo Molnar 9686470930SIngo Molnar buf = &data[old & md->mask]; 9786470930SIngo Molnar size = head - old; 9886470930SIngo Molnar old += size; 9986470930SIngo Molnar 1008c6f45a7SArnaldo Carvalho de Melo if (record__write(rec, buf, size) < 0) { 1018d3eca20SDavid Ahern rc = -1; 1028d3eca20SDavid Ahern goto out; 1038d3eca20SDavid Ahern } 10486470930SIngo Molnar 10586470930SIngo Molnar md->prev = old; 106*e5685730SArnaldo Carvalho de Melo perf_evlist__mmap_consume(rec->evlist, idx); 1078d3eca20SDavid Ahern out: 1088d3eca20SDavid Ahern return rc; 10986470930SIngo Molnar } 11086470930SIngo Molnar 11186470930SIngo Molnar static volatile int done = 0; 112f7b7c26eSPeter Zijlstra static volatile int signr = -1; 11333e49ea7SAndi Kleen static volatile int child_finished = 0; 11486470930SIngo Molnar 11586470930SIngo Molnar static void sig_handler(int sig) 11686470930SIngo Molnar { 11733e49ea7SAndi Kleen if (sig == SIGCHLD) 11833e49ea7SAndi Kleen child_finished = 1; 11945604710SNamhyung Kim else 12045604710SNamhyung Kim signr = sig; 12133e49ea7SAndi Kleen 12286470930SIngo Molnar done = 1; 123f7b7c26eSPeter Zijlstra } 124f7b7c26eSPeter Zijlstra 12545604710SNamhyung Kim static void record__sig_exit(void) 126f7b7c26eSPeter Zijlstra { 12745604710SNamhyung Kim if (signr == -1) 128f7b7c26eSPeter Zijlstra return; 129f7b7c26eSPeter Zijlstra 130f7b7c26eSPeter Zijlstra signal(signr, SIG_DFL); 13145604710SNamhyung Kim raise(signr); 13286470930SIngo Molnar } 13386470930SIngo Molnar 1348c6f45a7SArnaldo Carvalho de Melo static int record__open(struct record *rec) 135dd7927f4SArnaldo Carvalho de Melo { 13656e52e85SArnaldo Carvalho de Melo char msg[512]; 1376a4bb04cSJiri Olsa struct perf_evsel *pos; 138d20deb64SArnaldo Carvalho de Melo struct perf_evlist *evlist = rec->evlist; 139d20deb64SArnaldo Carvalho de Melo struct perf_session *session = rec->session; 140b4006796SArnaldo Carvalho de Melo struct record_opts *opts = &rec->opts; 1418d3eca20SDavid Ahern int rc = 0; 142dd7927f4SArnaldo Carvalho de Melo 143f77a9518SArnaldo Carvalho de Melo perf_evlist__config(evlist, opts); 144cac21425SJiri Olsa 1450050f7aaSArnaldo Carvalho de Melo evlist__for_each(evlist, pos) { 1463da297a6SIngo Molnar try_again: 1476a4bb04cSJiri Olsa if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { 14856e52e85SArnaldo Carvalho de Melo if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { 1493da297a6SIngo Molnar if (verbose) 150c0a54341SArnaldo Carvalho de Melo ui__warning("%s\n", msg); 1513da297a6SIngo Molnar goto try_again; 1523da297a6SIngo Molnar } 153ca6a4258SDavid Ahern 15456e52e85SArnaldo Carvalho de Melo rc = -errno; 15556e52e85SArnaldo Carvalho de Melo perf_evsel__open_strerror(pos, &opts->target, 15656e52e85SArnaldo Carvalho de Melo errno, msg, sizeof(msg)); 15756e52e85SArnaldo Carvalho de Melo ui__error("%s\n", msg); 1588d3eca20SDavid Ahern goto out; 1597c6a1c65SPeter Zijlstra } 1607c6a1c65SPeter Zijlstra } 1617c6a1c65SPeter Zijlstra 1621491a632SArnaldo Carvalho de Melo if (perf_evlist__apply_filters(evlist)) { 1630a102479SFrederic Weisbecker error("failed to set filter with %d (%s)\n", errno, 16435550da3SMasami Hiramatsu strerror_r(errno, msg, sizeof(msg))); 1658d3eca20SDavid Ahern rc = -1; 1668d3eca20SDavid Ahern goto out; 1670a102479SFrederic Weisbecker } 1680a102479SFrederic Weisbecker 16918e60939SNelson Elhage if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { 1708d3eca20SDavid Ahern if (errno == EPERM) { 1718d3eca20SDavid Ahern pr_err("Permission error mapping pages.\n" 17218e60939SNelson Elhage "Consider increasing " 17318e60939SNelson Elhage "/proc/sys/kernel/perf_event_mlock_kb,\n" 17418e60939SNelson Elhage "or try again with a smaller value of -m/--mmap_pages.\n" 17553653d70SAdrian Hunter "(current value: %u)\n", opts->mmap_pages); 1768d3eca20SDavid Ahern rc = -errno; 1778d3eca20SDavid Ahern } else { 17835550da3SMasami Hiramatsu pr_err("failed to mmap with %d (%s)\n", errno, 17935550da3SMasami Hiramatsu strerror_r(errno, msg, sizeof(msg))); 1808d3eca20SDavid Ahern rc = -errno; 1818d3eca20SDavid Ahern } 1828d3eca20SDavid Ahern goto out; 18318e60939SNelson Elhage } 1840a27d7f9SArnaldo Carvalho de Melo 185a91e5431SArnaldo Carvalho de Melo session->evlist = evlist; 1867b56cce2SArnaldo Carvalho de Melo perf_session__set_id_hdr_size(session); 1878d3eca20SDavid Ahern out: 1888d3eca20SDavid Ahern return rc; 189a91e5431SArnaldo Carvalho de Melo } 190a91e5431SArnaldo Carvalho de Melo 1918c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec) 1926122e4e4SArnaldo Carvalho de Melo { 193f5fc1412SJiri Olsa struct perf_data_file *file = &rec->file; 194f5fc1412SJiri Olsa struct perf_session *session = rec->session; 1957ab75cffSDavid Ahern u64 start = session->header.data_offset; 1966122e4e4SArnaldo Carvalho de Melo 197f5fc1412SJiri Olsa u64 size = lseek(file->fd, 0, SEEK_CUR); 1989f591fd7SArnaldo Carvalho de Melo if (size == 0) 1999f591fd7SArnaldo Carvalho de Melo return 0; 2009f591fd7SArnaldo Carvalho de Melo 2017ab75cffSDavid Ahern return __perf_session__process_events(session, start, 2027ab75cffSDavid Ahern size - start, 2036122e4e4SArnaldo Carvalho de Melo size, &build_id__mark_dso_hit_ops); 2046122e4e4SArnaldo Carvalho de Melo } 2056122e4e4SArnaldo Carvalho de Melo 2068115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data) 207a1645ce1SZhang, Yanmin { 208a1645ce1SZhang, Yanmin int err; 20945694aa7SArnaldo Carvalho de Melo struct perf_tool *tool = data; 210a1645ce1SZhang, Yanmin /* 211a1645ce1SZhang, Yanmin *As for guest kernel when processing subcommand record&report, 212a1645ce1SZhang, Yanmin *we arrange module mmap prior to guest kernel mmap and trigger 213a1645ce1SZhang, Yanmin *a preload dso because default guest module symbols are loaded 214a1645ce1SZhang, Yanmin *from guest kallsyms instead of /lib/modules/XXX/XXX. This 215a1645ce1SZhang, Yanmin *method is used to avoid symbol missing when the first addr is 216a1645ce1SZhang, Yanmin *in module instead of in guest kernel. 217a1645ce1SZhang, Yanmin */ 21845694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_modules(tool, process_synthesized_event, 219743eb868SArnaldo Carvalho de Melo machine); 220a1645ce1SZhang, Yanmin if (err < 0) 221a1645ce1SZhang, Yanmin pr_err("Couldn't record guest kernel [%d]'s reference" 22223346f21SArnaldo Carvalho de Melo " relocation symbol.\n", machine->pid); 223a1645ce1SZhang, Yanmin 224a1645ce1SZhang, Yanmin /* 225a1645ce1SZhang, Yanmin * We use _stext for guest kernel because guest kernel's /proc/kallsyms 226a1645ce1SZhang, Yanmin * have no _text sometimes. 227a1645ce1SZhang, Yanmin */ 22845694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 2290ae617beSAdrian Hunter machine); 230a1645ce1SZhang, Yanmin if (err < 0) 231a1645ce1SZhang, Yanmin pr_err("Couldn't record guest kernel [%d]'s reference" 23223346f21SArnaldo Carvalho de Melo " relocation symbol.\n", machine->pid); 233a1645ce1SZhang, Yanmin } 234a1645ce1SZhang, Yanmin 23598402807SFrederic Weisbecker static struct perf_event_header finished_round_event = { 23698402807SFrederic Weisbecker .size = sizeof(struct perf_event_header), 23798402807SFrederic Weisbecker .type = PERF_RECORD_FINISHED_ROUND, 23898402807SFrederic Weisbecker }; 23998402807SFrederic Weisbecker 2408c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec) 24198402807SFrederic Weisbecker { 242dcabb507SJiri Olsa u64 bytes_written = rec->bytes_written; 2430e2e63ddSPeter Zijlstra int i; 2448d3eca20SDavid Ahern int rc = 0; 24598402807SFrederic Weisbecker 246d20deb64SArnaldo Carvalho de Melo for (i = 0; i < rec->evlist->nr_mmaps; i++) { 2478d3eca20SDavid Ahern if (rec->evlist->mmap[i].base) { 248*e5685730SArnaldo Carvalho de Melo if (record__mmap_read(rec, i) != 0) { 2498d3eca20SDavid Ahern rc = -1; 2508d3eca20SDavid Ahern goto out; 2518d3eca20SDavid Ahern } 2528d3eca20SDavid Ahern } 25398402807SFrederic Weisbecker } 25498402807SFrederic Weisbecker 255dcabb507SJiri Olsa /* 256dcabb507SJiri Olsa * Mark the round finished in case we wrote 257dcabb507SJiri Olsa * at least one event. 258dcabb507SJiri Olsa */ 259dcabb507SJiri Olsa if (bytes_written != rec->bytes_written) 2608c6f45a7SArnaldo Carvalho de Melo rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); 2618d3eca20SDavid Ahern 2628d3eca20SDavid Ahern out: 2638d3eca20SDavid Ahern return rc; 26498402807SFrederic Weisbecker } 26598402807SFrederic Weisbecker 2668c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec) 26757706abcSDavid Ahern { 26857706abcSDavid Ahern struct perf_session *session = rec->session; 26957706abcSDavid Ahern int feat; 27057706abcSDavid Ahern 27157706abcSDavid Ahern for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++) 27257706abcSDavid Ahern perf_header__set_feat(&session->header, feat); 27357706abcSDavid Ahern 27457706abcSDavid Ahern if (rec->no_buildid) 27557706abcSDavid Ahern perf_header__clear_feat(&session->header, HEADER_BUILD_ID); 27657706abcSDavid Ahern 2773e2be2daSArnaldo Carvalho de Melo if (!have_tracepoints(&rec->evlist->entries)) 27857706abcSDavid Ahern perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); 27957706abcSDavid Ahern 28057706abcSDavid Ahern if (!rec->opts.branch_stack) 28157706abcSDavid Ahern perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); 28257706abcSDavid Ahern } 28357706abcSDavid Ahern 284f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno; 285f33cbe72SArnaldo Carvalho de Melo 286f33cbe72SArnaldo Carvalho de Melo /* 287f33cbe72SArnaldo Carvalho de Melo * perf_evlist__prepare_workload will send a SIGUSR1 288f33cbe72SArnaldo Carvalho de Melo * if the fork fails, since we asked by setting its 289f33cbe72SArnaldo Carvalho de Melo * want_signal to true. 290f33cbe72SArnaldo Carvalho de Melo */ 29145604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused, 29245604710SNamhyung Kim siginfo_t *info, 293f33cbe72SArnaldo Carvalho de Melo void *ucontext __maybe_unused) 294f33cbe72SArnaldo Carvalho de Melo { 295f33cbe72SArnaldo Carvalho de Melo workload_exec_errno = info->si_value.sival_int; 296f33cbe72SArnaldo Carvalho de Melo done = 1; 297f33cbe72SArnaldo Carvalho de Melo child_finished = 1; 298f33cbe72SArnaldo Carvalho de Melo } 299f33cbe72SArnaldo Carvalho de Melo 3008c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv) 30186470930SIngo Molnar { 30257706abcSDavid Ahern int err; 30345604710SNamhyung Kim int status = 0; 3048b412664SPeter Zijlstra unsigned long waking = 0; 30546be604bSZhang, Yanmin const bool forks = argc > 0; 30623346f21SArnaldo Carvalho de Melo struct machine *machine; 30745694aa7SArnaldo Carvalho de Melo struct perf_tool *tool = &rec->tool; 308b4006796SArnaldo Carvalho de Melo struct record_opts *opts = &rec->opts; 309f5fc1412SJiri Olsa struct perf_data_file *file = &rec->file; 310d20deb64SArnaldo Carvalho de Melo struct perf_session *session; 3112711926aSJiri Olsa bool disabled = false; 31286470930SIngo Molnar 313d20deb64SArnaldo Carvalho de Melo rec->progname = argv[0]; 31433e49ea7SAndi Kleen 31545604710SNamhyung Kim atexit(record__sig_exit); 316f5970550SPeter Zijlstra signal(SIGCHLD, sig_handler); 317f5970550SPeter Zijlstra signal(SIGINT, sig_handler); 318804f7ac7SDavid Ahern signal(SIGTERM, sig_handler); 319f5970550SPeter Zijlstra 320f5fc1412SJiri Olsa session = perf_session__new(file, false, NULL); 32194c744b6SArnaldo Carvalho de Melo if (session == NULL) { 322ffa91880SAdrien BAK pr_err("Perf session creation failed.\n"); 323a9a70bbcSArnaldo Carvalho de Melo return -1; 324a9a70bbcSArnaldo Carvalho de Melo } 325a9a70bbcSArnaldo Carvalho de Melo 326d20deb64SArnaldo Carvalho de Melo rec->session = session; 327d20deb64SArnaldo Carvalho de Melo 3288c6f45a7SArnaldo Carvalho de Melo record__init_features(rec); 329330aa675SStephane Eranian 330d4db3f16SArnaldo Carvalho de Melo if (forks) { 3313e2be2daSArnaldo Carvalho de Melo err = perf_evlist__prepare_workload(rec->evlist, &opts->target, 332f5fc1412SJiri Olsa argv, file->is_pipe, 333735f7e0bSArnaldo Carvalho de Melo workload_exec_failed_signal); 33435b9d88eSArnaldo Carvalho de Melo if (err < 0) { 33535b9d88eSArnaldo Carvalho de Melo pr_err("Couldn't run the workload!\n"); 33645604710SNamhyung Kim status = err; 33735b9d88eSArnaldo Carvalho de Melo goto out_delete_session; 338856e9660SPeter Zijlstra } 339856e9660SPeter Zijlstra } 340856e9660SPeter Zijlstra 3418c6f45a7SArnaldo Carvalho de Melo if (record__open(rec) != 0) { 3428d3eca20SDavid Ahern err = -1; 34345604710SNamhyung Kim goto out_child; 3448d3eca20SDavid Ahern } 34586470930SIngo Molnar 3463e2be2daSArnaldo Carvalho de Melo if (!rec->evlist->nr_groups) 347a8bb559bSNamhyung Kim perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); 348a8bb559bSNamhyung Kim 349f5fc1412SJiri Olsa if (file->is_pipe) { 350f5fc1412SJiri Olsa err = perf_header__write_pipe(file->fd); 351529870e3STom Zanussi if (err < 0) 35245604710SNamhyung Kim goto out_child; 353563aecb2SJiri Olsa } else { 3543e2be2daSArnaldo Carvalho de Melo err = perf_session__write_header(session, rec->evlist, 355f5fc1412SJiri Olsa file->fd, false); 356d5eed904SArnaldo Carvalho de Melo if (err < 0) 35745604710SNamhyung Kim goto out_child; 358d5eed904SArnaldo Carvalho de Melo } 3597c6a1c65SPeter Zijlstra 360d3665498SDavid Ahern if (!rec->no_buildid 361e20960c0SRobert Richter && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { 362d3665498SDavid Ahern pr_err("Couldn't generate buildids. " 363e20960c0SRobert Richter "Use --no-buildid to profile anyway.\n"); 3648d3eca20SDavid Ahern err = -1; 36545604710SNamhyung Kim goto out_child; 366e20960c0SRobert Richter } 367e20960c0SRobert Richter 36834ba5122SArnaldo Carvalho de Melo machine = &session->machines.host; 369743eb868SArnaldo Carvalho de Melo 370f5fc1412SJiri Olsa if (file->is_pipe) { 37145694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_attrs(tool, session, 372a91e5431SArnaldo Carvalho de Melo process_synthesized_event); 3732c46dbb5STom Zanussi if (err < 0) { 3742c46dbb5STom Zanussi pr_err("Couldn't synthesize attrs.\n"); 37545604710SNamhyung Kim goto out_child; 3762c46dbb5STom Zanussi } 377cd19a035STom Zanussi 3783e2be2daSArnaldo Carvalho de Melo if (have_tracepoints(&rec->evlist->entries)) { 37963e0c771STom Zanussi /* 38063e0c771STom Zanussi * FIXME err <= 0 here actually means that 38163e0c771STom Zanussi * there were no tracepoints so its not really 38263e0c771STom Zanussi * an error, just that we don't need to 38363e0c771STom Zanussi * synthesize anything. We really have to 38463e0c771STom Zanussi * return this more properly and also 38563e0c771STom Zanussi * propagate errors that now are calling die() 38663e0c771STom Zanussi */ 3873e2be2daSArnaldo Carvalho de Melo err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist, 388743eb868SArnaldo Carvalho de Melo process_synthesized_event); 38963e0c771STom Zanussi if (err <= 0) { 39063e0c771STom Zanussi pr_err("Couldn't record tracing data.\n"); 39145604710SNamhyung Kim goto out_child; 39263e0c771STom Zanussi } 393f34b9001SDavid Ahern rec->bytes_written += err; 3942c46dbb5STom Zanussi } 39563e0c771STom Zanussi } 3962c46dbb5STom Zanussi 39745694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 3980ae617beSAdrian Hunter machine); 399c1a3a4b9SArnaldo Carvalho de Melo if (err < 0) 400c1a3a4b9SArnaldo Carvalho de Melo pr_err("Couldn't record kernel reference relocation symbol\n" 401c1a3a4b9SArnaldo Carvalho de Melo "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 402c1a3a4b9SArnaldo Carvalho de Melo "Check /proc/kallsyms permission or run as root.\n"); 40356b03f3cSArnaldo Carvalho de Melo 40445694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_modules(tool, process_synthesized_event, 405743eb868SArnaldo Carvalho de Melo machine); 406c1a3a4b9SArnaldo Carvalho de Melo if (err < 0) 407c1a3a4b9SArnaldo Carvalho de Melo pr_err("Couldn't record kernel module information.\n" 408c1a3a4b9SArnaldo Carvalho de Melo "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 409c1a3a4b9SArnaldo Carvalho de Melo "Check /proc/modules permission or run as root.\n"); 410c1a3a4b9SArnaldo Carvalho de Melo 4117e383de4SArnaldo Carvalho de Melo if (perf_guest) { 412876650e6SArnaldo Carvalho de Melo machines__process_guests(&session->machines, 4137e383de4SArnaldo Carvalho de Melo perf_event__synthesize_guest_os, tool); 4147e383de4SArnaldo Carvalho de Melo } 415b7cece76SArnaldo Carvalho de Melo 4163e2be2daSArnaldo Carvalho de Melo err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads, 41758d925dcSArnaldo Carvalho de Melo process_synthesized_event, opts->sample_address); 4188d3eca20SDavid Ahern if (err != 0) 41945604710SNamhyung Kim goto out_child; 4208d3eca20SDavid Ahern 421d20deb64SArnaldo Carvalho de Melo if (rec->realtime_prio) { 42286470930SIngo Molnar struct sched_param param; 42386470930SIngo Molnar 424d20deb64SArnaldo Carvalho de Melo param.sched_priority = rec->realtime_prio; 42586470930SIngo Molnar if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { 4266beba7adSArnaldo Carvalho de Melo pr_err("Could not set realtime priority.\n"); 4278d3eca20SDavid Ahern err = -1; 42845604710SNamhyung Kim goto out_child; 42986470930SIngo Molnar } 43086470930SIngo Molnar } 43186470930SIngo Molnar 432774cb499SJiri Olsa /* 433774cb499SJiri Olsa * When perf is starting the traced process, all the events 434774cb499SJiri Olsa * (apart from group members) have enable_on_exec=1 set, 435774cb499SJiri Olsa * so don't spoil it by prematurely enabling them. 436774cb499SJiri Olsa */ 4376619a53eSAndi Kleen if (!target__none(&opts->target) && !opts->initial_delay) 4383e2be2daSArnaldo Carvalho de Melo perf_evlist__enable(rec->evlist); 439764e16a3SDavid Ahern 440856e9660SPeter Zijlstra /* 441856e9660SPeter Zijlstra * Let the child rip 442856e9660SPeter Zijlstra */ 443735f7e0bSArnaldo Carvalho de Melo if (forks) 4443e2be2daSArnaldo Carvalho de Melo perf_evlist__start_workload(rec->evlist); 445856e9660SPeter Zijlstra 4466619a53eSAndi Kleen if (opts->initial_delay) { 4476619a53eSAndi Kleen usleep(opts->initial_delay * 1000); 4486619a53eSAndi Kleen perf_evlist__enable(rec->evlist); 4496619a53eSAndi Kleen } 4506619a53eSAndi Kleen 451649c48a9SPeter Zijlstra for (;;) { 452d20deb64SArnaldo Carvalho de Melo int hits = rec->samples; 45386470930SIngo Molnar 4548c6f45a7SArnaldo Carvalho de Melo if (record__mmap_read_all(rec) < 0) { 4558d3eca20SDavid Ahern err = -1; 45645604710SNamhyung Kim goto out_child; 4578d3eca20SDavid Ahern } 45886470930SIngo Molnar 459d20deb64SArnaldo Carvalho de Melo if (hits == rec->samples) { 460649c48a9SPeter Zijlstra if (done) 461649c48a9SPeter Zijlstra break; 4623e2be2daSArnaldo Carvalho de Melo err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1); 463a515114fSJiri Olsa /* 464a515114fSJiri Olsa * Propagate error, only if there's any. Ignore positive 465a515114fSJiri Olsa * number of returned events and interrupt error. 466a515114fSJiri Olsa */ 467a515114fSJiri Olsa if (err > 0 || (err < 0 && errno == EINTR)) 46845604710SNamhyung Kim err = 0; 4698b412664SPeter Zijlstra waking++; 4708b412664SPeter Zijlstra } 4718b412664SPeter Zijlstra 472774cb499SJiri Olsa /* 473774cb499SJiri Olsa * When perf is starting the traced process, at the end events 474774cb499SJiri Olsa * die with the process and we wait for that. Thus no need to 475774cb499SJiri Olsa * disable events in this case. 476774cb499SJiri Olsa */ 477602ad878SArnaldo Carvalho de Melo if (done && !disabled && !target__none(&opts->target)) { 4783e2be2daSArnaldo Carvalho de Melo perf_evlist__disable(rec->evlist); 4792711926aSJiri Olsa disabled = true; 4802711926aSJiri Olsa } 4818b412664SPeter Zijlstra } 4828b412664SPeter Zijlstra 483f33cbe72SArnaldo Carvalho de Melo if (forks && workload_exec_errno) { 48435550da3SMasami Hiramatsu char msg[STRERR_BUFSIZE]; 485f33cbe72SArnaldo Carvalho de Melo const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); 486f33cbe72SArnaldo Carvalho de Melo pr_err("Workload failed: %s\n", emsg); 487f33cbe72SArnaldo Carvalho de Melo err = -1; 48845604710SNamhyung Kim goto out_child; 489f33cbe72SArnaldo Carvalho de Melo } 490f33cbe72SArnaldo Carvalho de Melo 49145604710SNamhyung Kim if (!quiet) { 4928b412664SPeter Zijlstra fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); 49386470930SIngo Molnar 49486470930SIngo Molnar /* 49586470930SIngo Molnar * Approximate RIP event size: 24 bytes. 49686470930SIngo Molnar */ 49786470930SIngo Molnar fprintf(stderr, 4989486aa38SArnaldo Carvalho de Melo "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", 499d20deb64SArnaldo Carvalho de Melo (double)rec->bytes_written / 1024.0 / 1024.0, 5006a4d98d7SJiri Olsa file->path, 501d20deb64SArnaldo Carvalho de Melo rec->bytes_written / 24); 50245604710SNamhyung Kim } 50386470930SIngo Molnar 50445604710SNamhyung Kim out_child: 50545604710SNamhyung Kim if (forks) { 50645604710SNamhyung Kim int exit_status; 50745604710SNamhyung Kim 50845604710SNamhyung Kim if (!child_finished) 50945604710SNamhyung Kim kill(rec->evlist->workload.pid, SIGTERM); 51045604710SNamhyung Kim 51145604710SNamhyung Kim wait(&exit_status); 51245604710SNamhyung Kim 51345604710SNamhyung Kim if (err < 0) 51445604710SNamhyung Kim status = err; 51545604710SNamhyung Kim else if (WIFEXITED(exit_status)) 51645604710SNamhyung Kim status = WEXITSTATUS(exit_status); 51745604710SNamhyung Kim else if (WIFSIGNALED(exit_status)) 51845604710SNamhyung Kim signr = WTERMSIG(exit_status); 51945604710SNamhyung Kim } else 52045604710SNamhyung Kim status = err; 52145604710SNamhyung Kim 52245604710SNamhyung Kim if (!err && !file->is_pipe) { 52345604710SNamhyung Kim rec->session->header.data_size += rec->bytes_written; 52445604710SNamhyung Kim 52545604710SNamhyung Kim if (!rec->no_buildid) 52645604710SNamhyung Kim process_buildids(rec); 52745604710SNamhyung Kim perf_session__write_header(rec->session, rec->evlist, 52845604710SNamhyung Kim file->fd, true); 52945604710SNamhyung Kim } 53039d17dacSArnaldo Carvalho de Melo 53139d17dacSArnaldo Carvalho de Melo out_delete_session: 53239d17dacSArnaldo Carvalho de Melo perf_session__delete(session); 53345604710SNamhyung Kim return status; 53486470930SIngo Molnar } 53586470930SIngo Molnar 536bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \ 537bdfebd84SRoberto Agostino Vitillo { .name = n, .mode = (m) } 538bdfebd84SRoberto Agostino Vitillo 539bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL } 540bdfebd84SRoberto Agostino Vitillo 541bdfebd84SRoberto Agostino Vitillo struct branch_mode { 542bdfebd84SRoberto Agostino Vitillo const char *name; 543bdfebd84SRoberto Agostino Vitillo int mode; 544bdfebd84SRoberto Agostino Vitillo }; 545bdfebd84SRoberto Agostino Vitillo 546bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = { 547bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER), 548bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL), 549bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV), 550bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY), 551bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL), 552bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN), 553bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL), 5540126d493SAndi Kleen BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX), 5550126d493SAndi Kleen BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX), 5560126d493SAndi Kleen BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX), 5570fffa5dfSAnshuman Khandual BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND), 558bdfebd84SRoberto Agostino Vitillo BRANCH_END 559bdfebd84SRoberto Agostino Vitillo }; 560bdfebd84SRoberto Agostino Vitillo 561bdfebd84SRoberto Agostino Vitillo static int 562a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset) 563bdfebd84SRoberto Agostino Vitillo { 564bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \ 565bdfebd84SRoberto Agostino Vitillo (PERF_SAMPLE_BRANCH_USER |\ 566bdfebd84SRoberto Agostino Vitillo PERF_SAMPLE_BRANCH_KERNEL |\ 567bdfebd84SRoberto Agostino Vitillo PERF_SAMPLE_BRANCH_HV) 568bdfebd84SRoberto Agostino Vitillo 569bdfebd84SRoberto Agostino Vitillo uint64_t *mode = (uint64_t *)opt->value; 570bdfebd84SRoberto Agostino Vitillo const struct branch_mode *br; 571a5aabdacSStephane Eranian char *s, *os = NULL, *p; 572bdfebd84SRoberto Agostino Vitillo int ret = -1; 573bdfebd84SRoberto Agostino Vitillo 574a5aabdacSStephane Eranian if (unset) 575a5aabdacSStephane Eranian return 0; 576bdfebd84SRoberto Agostino Vitillo 577a5aabdacSStephane Eranian /* 578a5aabdacSStephane Eranian * cannot set it twice, -b + --branch-filter for instance 579a5aabdacSStephane Eranian */ 580a5aabdacSStephane Eranian if (*mode) 581a5aabdacSStephane Eranian return -1; 582a5aabdacSStephane Eranian 583a5aabdacSStephane Eranian /* str may be NULL in case no arg is passed to -b */ 584a5aabdacSStephane Eranian if (str) { 585bdfebd84SRoberto Agostino Vitillo /* because str is read-only */ 586bdfebd84SRoberto Agostino Vitillo s = os = strdup(str); 587bdfebd84SRoberto Agostino Vitillo if (!s) 588bdfebd84SRoberto Agostino Vitillo return -1; 589bdfebd84SRoberto Agostino Vitillo 590bdfebd84SRoberto Agostino Vitillo for (;;) { 591bdfebd84SRoberto Agostino Vitillo p = strchr(s, ','); 592bdfebd84SRoberto Agostino Vitillo if (p) 593bdfebd84SRoberto Agostino Vitillo *p = '\0'; 594bdfebd84SRoberto Agostino Vitillo 595bdfebd84SRoberto Agostino Vitillo for (br = branch_modes; br->name; br++) { 596bdfebd84SRoberto Agostino Vitillo if (!strcasecmp(s, br->name)) 597bdfebd84SRoberto Agostino Vitillo break; 598bdfebd84SRoberto Agostino Vitillo } 599a5aabdacSStephane Eranian if (!br->name) { 600a5aabdacSStephane Eranian ui__warning("unknown branch filter %s," 601a5aabdacSStephane Eranian " check man page\n", s); 602bdfebd84SRoberto Agostino Vitillo goto error; 603a5aabdacSStephane Eranian } 604bdfebd84SRoberto Agostino Vitillo 605bdfebd84SRoberto Agostino Vitillo *mode |= br->mode; 606bdfebd84SRoberto Agostino Vitillo 607bdfebd84SRoberto Agostino Vitillo if (!p) 608bdfebd84SRoberto Agostino Vitillo break; 609bdfebd84SRoberto Agostino Vitillo 610bdfebd84SRoberto Agostino Vitillo s = p + 1; 611bdfebd84SRoberto Agostino Vitillo } 612a5aabdacSStephane Eranian } 613bdfebd84SRoberto Agostino Vitillo ret = 0; 614bdfebd84SRoberto Agostino Vitillo 615a5aabdacSStephane Eranian /* default to any branch */ 616bdfebd84SRoberto Agostino Vitillo if ((*mode & ~ONLY_PLM) == 0) { 617a5aabdacSStephane Eranian *mode = PERF_SAMPLE_BRANCH_ANY; 618bdfebd84SRoberto Agostino Vitillo } 619bdfebd84SRoberto Agostino Vitillo error: 620bdfebd84SRoberto Agostino Vitillo free(os); 621bdfebd84SRoberto Agostino Vitillo return ret; 622bdfebd84SRoberto Agostino Vitillo } 623bdfebd84SRoberto Agostino Vitillo 6249ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT 62526d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size) 62626d33022SJiri Olsa { 62726d33022SJiri Olsa char *endptr; 62826d33022SJiri Olsa unsigned long size; 62926d33022SJiri Olsa unsigned long max_size = round_down(USHRT_MAX, sizeof(u64)); 63026d33022SJiri Olsa 63126d33022SJiri Olsa size = strtoul(str, &endptr, 0); 63226d33022SJiri Olsa 63326d33022SJiri Olsa do { 63426d33022SJiri Olsa if (*endptr) 63526d33022SJiri Olsa break; 63626d33022SJiri Olsa 63726d33022SJiri Olsa size = round_up(size, sizeof(u64)); 63826d33022SJiri Olsa if (!size || size > max_size) 63926d33022SJiri Olsa break; 64026d33022SJiri Olsa 64126d33022SJiri Olsa *_size = size; 64226d33022SJiri Olsa return 0; 64326d33022SJiri Olsa 64426d33022SJiri Olsa } while (0); 64526d33022SJiri Olsa 64626d33022SJiri Olsa pr_err("callchain: Incorrect stack dump size (max %ld): %s\n", 64726d33022SJiri Olsa max_size, str); 64826d33022SJiri Olsa return -1; 64926d33022SJiri Olsa } 6509ff125d1SJiri Olsa #endif /* HAVE_DWARF_UNWIND_SUPPORT */ 65126d33022SJiri Olsa 652b4006796SArnaldo Carvalho de Melo int record_parse_callchain(const char *arg, struct record_opts *opts) 65326d33022SJiri Olsa { 65426d33022SJiri Olsa char *tok, *name, *saveptr = NULL; 65526d33022SJiri Olsa char *buf; 65626d33022SJiri Olsa int ret = -1; 65726d33022SJiri Olsa 65826d33022SJiri Olsa /* We need buffer that we know we can write to. */ 65926d33022SJiri Olsa buf = malloc(strlen(arg) + 1); 66026d33022SJiri Olsa if (!buf) 66126d33022SJiri Olsa return -ENOMEM; 66226d33022SJiri Olsa 66326d33022SJiri Olsa strcpy(buf, arg); 66426d33022SJiri Olsa 66526d33022SJiri Olsa tok = strtok_r((char *)buf, ",", &saveptr); 66626d33022SJiri Olsa name = tok ? : (char *)buf; 66726d33022SJiri Olsa 66826d33022SJiri Olsa do { 66926d33022SJiri Olsa /* Framepointer style */ 67026d33022SJiri Olsa if (!strncmp(name, "fp", sizeof("fp"))) { 67126d33022SJiri Olsa if (!strtok_r(NULL, ",", &saveptr)) { 672c5ff78c3SArnaldo Carvalho de Melo opts->call_graph = CALLCHAIN_FP; 67326d33022SJiri Olsa ret = 0; 67426d33022SJiri Olsa } else 67526d33022SJiri Olsa pr_err("callchain: No more arguments " 67626d33022SJiri Olsa "needed for -g fp\n"); 67726d33022SJiri Olsa break; 67826d33022SJiri Olsa 6799ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT 68026d33022SJiri Olsa /* Dwarf style */ 68126d33022SJiri Olsa } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { 68261eaa3beSArnaldo Carvalho de Melo const unsigned long default_stack_dump_size = 8192; 68361eaa3beSArnaldo Carvalho de Melo 68426d33022SJiri Olsa ret = 0; 685c5ff78c3SArnaldo Carvalho de Melo opts->call_graph = CALLCHAIN_DWARF; 686c5ff78c3SArnaldo Carvalho de Melo opts->stack_dump_size = default_stack_dump_size; 68726d33022SJiri Olsa 68826d33022SJiri Olsa tok = strtok_r(NULL, ",", &saveptr); 68926d33022SJiri Olsa if (tok) { 69026d33022SJiri Olsa unsigned long size = 0; 69126d33022SJiri Olsa 69226d33022SJiri Olsa ret = get_stack_size(tok, &size); 693c5ff78c3SArnaldo Carvalho de Melo opts->stack_dump_size = size; 69426d33022SJiri Olsa } 6959ff125d1SJiri Olsa #endif /* HAVE_DWARF_UNWIND_SUPPORT */ 69626d33022SJiri Olsa } else { 69709b0fd45SJiri Olsa pr_err("callchain: Unknown --call-graph option " 69826d33022SJiri Olsa "value: %s\n", arg); 69926d33022SJiri Olsa break; 70026d33022SJiri Olsa } 70126d33022SJiri Olsa 70226d33022SJiri Olsa } while (0); 70326d33022SJiri Olsa 70426d33022SJiri Olsa free(buf); 70509b0fd45SJiri Olsa return ret; 70609b0fd45SJiri Olsa } 70726d33022SJiri Olsa 708b4006796SArnaldo Carvalho de Melo static void callchain_debug(struct record_opts *opts) 70909b0fd45SJiri Olsa { 710a601fdffSJiri Olsa static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" }; 711a601fdffSJiri Olsa 712a601fdffSJiri Olsa pr_debug("callchain: type %s\n", str[opts->call_graph]); 71326d33022SJiri Olsa 71409b0fd45SJiri Olsa if (opts->call_graph == CALLCHAIN_DWARF) 71509b0fd45SJiri Olsa pr_debug("callchain: stack dump size %d\n", 71609b0fd45SJiri Olsa opts->stack_dump_size); 71709b0fd45SJiri Olsa } 71809b0fd45SJiri Olsa 71909b0fd45SJiri Olsa int record_parse_callchain_opt(const struct option *opt, 72009b0fd45SJiri Olsa const char *arg, 72109b0fd45SJiri Olsa int unset) 72209b0fd45SJiri Olsa { 723b4006796SArnaldo Carvalho de Melo struct record_opts *opts = opt->value; 72409b0fd45SJiri Olsa int ret; 72509b0fd45SJiri Olsa 726eb853e80SJiri Olsa opts->call_graph_enabled = !unset; 727eb853e80SJiri Olsa 72809b0fd45SJiri Olsa /* --no-call-graph */ 72909b0fd45SJiri Olsa if (unset) { 73009b0fd45SJiri Olsa opts->call_graph = CALLCHAIN_NONE; 73109b0fd45SJiri Olsa pr_debug("callchain: disabled\n"); 73209b0fd45SJiri Olsa return 0; 73309b0fd45SJiri Olsa } 73409b0fd45SJiri Olsa 73509b0fd45SJiri Olsa ret = record_parse_callchain(arg, opts); 73609b0fd45SJiri Olsa if (!ret) 73709b0fd45SJiri Olsa callchain_debug(opts); 73809b0fd45SJiri Olsa 73926d33022SJiri Olsa return ret; 74026d33022SJiri Olsa } 74126d33022SJiri Olsa 74209b0fd45SJiri Olsa int record_callchain_opt(const struct option *opt, 74309b0fd45SJiri Olsa const char *arg __maybe_unused, 74409b0fd45SJiri Olsa int unset __maybe_unused) 74509b0fd45SJiri Olsa { 746b4006796SArnaldo Carvalho de Melo struct record_opts *opts = opt->value; 74709b0fd45SJiri Olsa 748eb853e80SJiri Olsa opts->call_graph_enabled = !unset; 749eb853e80SJiri Olsa 75009b0fd45SJiri Olsa if (opts->call_graph == CALLCHAIN_NONE) 75109b0fd45SJiri Olsa opts->call_graph = CALLCHAIN_FP; 75209b0fd45SJiri Olsa 75309b0fd45SJiri Olsa callchain_debug(opts); 75409b0fd45SJiri Olsa return 0; 75509b0fd45SJiri Olsa } 75609b0fd45SJiri Olsa 757eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb) 758eb853e80SJiri Olsa { 759eb853e80SJiri Olsa struct record *rec = cb; 760eb853e80SJiri Olsa 761eb853e80SJiri Olsa if (!strcmp(var, "record.call-graph")) 762eb853e80SJiri Olsa return record_parse_callchain(value, &rec->opts); 763eb853e80SJiri Olsa 764eb853e80SJiri Olsa return perf_default_config(var, value, cb); 765eb853e80SJiri Olsa } 766eb853e80SJiri Olsa 76786470930SIngo Molnar static const char * const record_usage[] = { 76886470930SIngo Molnar "perf record [<options>] [<command>]", 76986470930SIngo Molnar "perf record [<options>] -- <command> [<options>]", 77086470930SIngo Molnar NULL 77186470930SIngo Molnar }; 77286470930SIngo Molnar 773d20deb64SArnaldo Carvalho de Melo /* 7748c6f45a7SArnaldo Carvalho de Melo * XXX Ideally would be local to cmd_record() and passed to a record__new 7758c6f45a7SArnaldo Carvalho de Melo * because we need to have access to it in record__exit, that is called 776d20deb64SArnaldo Carvalho de Melo * after cmd_record() exits, but since record_options need to be accessible to 777d20deb64SArnaldo Carvalho de Melo * builtin-script, leave it here. 778d20deb64SArnaldo Carvalho de Melo * 779d20deb64SArnaldo Carvalho de Melo * At least we don't ouch it in all the other functions here directly. 780d20deb64SArnaldo Carvalho de Melo * 781d20deb64SArnaldo Carvalho de Melo * Just say no to tons of global variables, sigh. 782d20deb64SArnaldo Carvalho de Melo */ 7838c6f45a7SArnaldo Carvalho de Melo static struct record record = { 784d20deb64SArnaldo Carvalho de Melo .opts = { 7858affc2b8SAndi Kleen .sample_time = true, 786d20deb64SArnaldo Carvalho de Melo .mmap_pages = UINT_MAX, 787d20deb64SArnaldo Carvalho de Melo .user_freq = UINT_MAX, 788d20deb64SArnaldo Carvalho de Melo .user_interval = ULLONG_MAX, 789447a6013SArnaldo Carvalho de Melo .freq = 4000, 790d1cb9fceSNamhyung Kim .target = { 791d1cb9fceSNamhyung Kim .uses_mmap = true, 7923aa5939dSAdrian Hunter .default_per_cpu = true, 793d1cb9fceSNamhyung Kim }, 794d20deb64SArnaldo Carvalho de Melo }, 795d20deb64SArnaldo Carvalho de Melo }; 7967865e817SFrederic Weisbecker 79709b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " 79861eaa3beSArnaldo Carvalho de Melo 7999ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT 80009b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf"; 80161eaa3beSArnaldo Carvalho de Melo #else 80209b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp"; 80361eaa3beSArnaldo Carvalho de Melo #endif 80461eaa3beSArnaldo Carvalho de Melo 805d20deb64SArnaldo Carvalho de Melo /* 806d20deb64SArnaldo Carvalho de Melo * XXX Will stay a global variable till we fix builtin-script.c to stop messing 807d20deb64SArnaldo Carvalho de Melo * with it and switch to use the library functions in perf_evlist that came 808b4006796SArnaldo Carvalho de Melo * from builtin-record.c, i.e. use record_opts, 809d20deb64SArnaldo Carvalho de Melo * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', 810d20deb64SArnaldo Carvalho de Melo * using pipes, etc. 811d20deb64SArnaldo Carvalho de Melo */ 812bca647aaSTom Zanussi const struct option record_options[] = { 813d20deb64SArnaldo Carvalho de Melo OPT_CALLBACK('e', "event", &record.evlist, "event", 81486470930SIngo Molnar "event selector. use 'perf list' to list available events", 815f120f9d5SJiri Olsa parse_events_option), 816d20deb64SArnaldo Carvalho de Melo OPT_CALLBACK(0, "filter", &record.evlist, "filter", 817c171b552SLi Zefan "event filter", parse_filter), 818bea03405SNamhyung Kim OPT_STRING('p', "pid", &record.opts.target.pid, "pid", 819d6d901c2SZhang, Yanmin "record events on existing process id"), 820bea03405SNamhyung Kim OPT_STRING('t', "tid", &record.opts.target.tid, "tid", 821d6d901c2SZhang, Yanmin "record events on existing thread id"), 822d20deb64SArnaldo Carvalho de Melo OPT_INTEGER('r', "realtime", &record.realtime_prio, 82386470930SIngo Molnar "collect data with this RT SCHED_FIFO priority"), 824509051eaSArnaldo Carvalho de Melo OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering, 825acac03faSKirill Smelkov "collect data without buffering"), 826d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, 827daac07b2SFrederic Weisbecker "collect raw sample records from all opened counters"), 828bea03405SNamhyung Kim OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide, 82986470930SIngo Molnar "system-wide collection from all CPUs"), 830bea03405SNamhyung Kim OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu", 831c45c6ea2SStephane Eranian "list of cpus to monitor"), 832d20deb64SArnaldo Carvalho de Melo OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), 833f5fc1412SJiri Olsa OPT_STRING('o', "output", &record.file.path, "file", 83486470930SIngo Molnar "output file name"), 83569e7e5b0SAdrian Hunter OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit, 83669e7e5b0SAdrian Hunter &record.opts.no_inherit_set, 8372e6cdf99SStephane Eranian "child tasks do not inherit counters"), 838d20deb64SArnaldo Carvalho de Melo OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), 839994a1f78SJiri Olsa OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages", 840994a1f78SJiri Olsa "number of mmap data pages", 841994a1f78SJiri Olsa perf_evlist__parse_mmap_pages), 842d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN(0, "group", &record.opts.group, 84343bece79SLin Ming "put the counters into a counter group"), 84409b0fd45SJiri Olsa OPT_CALLBACK_NOOPT('g', NULL, &record.opts, 84509b0fd45SJiri Olsa NULL, "enables call-graph recording" , 84609b0fd45SJiri Olsa &record_callchain_opt), 84709b0fd45SJiri Olsa OPT_CALLBACK(0, "call-graph", &record.opts, 84875d9a108SArnaldo Carvalho de Melo "mode[,dump_size]", record_callchain_help, 84909b0fd45SJiri Olsa &record_parse_callchain_opt), 850c0555642SIan Munsie OPT_INCR('v', "verbose", &verbose, 8513da297a6SIngo Molnar "be more verbose (show counter open errors, etc)"), 852b44308f5SArnaldo Carvalho de Melo OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 853d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat, 854649c48a9SPeter Zijlstra "per thread counts"), 855d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('d', "data", &record.opts.sample_address, 8564bba828dSAnton Blanchard "Sample addresses"), 857d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"), 8583e76ac78SAndrew Vagin OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"), 859d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, 860649c48a9SPeter Zijlstra "don't sample"), 861d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache, 862a1ac1d3cSStephane Eranian "do not update the buildid cache"), 863d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('B', "no-buildid", &record.no_buildid, 864baa2f6ceSArnaldo Carvalho de Melo "do not collect buildids in perf.data"), 865d20deb64SArnaldo Carvalho de Melo OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 866023695d9SStephane Eranian "monitor event in cgroup name only", 867023695d9SStephane Eranian parse_cgroups), 868a6205a35SArnaldo Carvalho de Melo OPT_UINTEGER('D', "delay", &record.opts.initial_delay, 8696619a53eSAndi Kleen "ms to wait before starting measurement after program start"), 870bea03405SNamhyung Kim OPT_STRING('u', "uid", &record.opts.target.uid_str, "user", 871bea03405SNamhyung Kim "user to profile"), 872a5aabdacSStephane Eranian 873a5aabdacSStephane Eranian OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack, 874a5aabdacSStephane Eranian "branch any", "sample any taken branches", 875a5aabdacSStephane Eranian parse_branch_stack), 876a5aabdacSStephane Eranian 877a5aabdacSStephane Eranian OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack, 878a5aabdacSStephane Eranian "branch filter mask", "branch stack filter modes", 879bdfebd84SRoberto Agostino Vitillo parse_branch_stack), 88005484298SAndi Kleen OPT_BOOLEAN('W', "weight", &record.opts.sample_weight, 88105484298SAndi Kleen "sample by weight (on special events only)"), 882475eeab9SAndi Kleen OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction, 883475eeab9SAndi Kleen "sample transaction flags (special events only)"), 8843aa5939dSAdrian Hunter OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread, 8853aa5939dSAdrian Hunter "use per-thread mmaps"), 88686470930SIngo Molnar OPT_END() 88786470930SIngo Molnar }; 88886470930SIngo Molnar 8891d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) 89086470930SIngo Molnar { 89169aad6f1SArnaldo Carvalho de Melo int err = -ENOMEM; 8928c6f45a7SArnaldo Carvalho de Melo struct record *rec = &record; 89316ad2ffbSNamhyung Kim char errbuf[BUFSIZ]; 89486470930SIngo Molnar 8953e2be2daSArnaldo Carvalho de Melo rec->evlist = perf_evlist__new(); 8963e2be2daSArnaldo Carvalho de Melo if (rec->evlist == NULL) 897361c99a6SArnaldo Carvalho de Melo return -ENOMEM; 898361c99a6SArnaldo Carvalho de Melo 899eb853e80SJiri Olsa perf_config(perf_record_config, rec); 900eb853e80SJiri Olsa 901bca647aaSTom Zanussi argc = parse_options(argc, argv, record_options, record_usage, 902a0541234SAnton Blanchard PARSE_OPT_STOP_AT_NON_OPTION); 903602ad878SArnaldo Carvalho de Melo if (!argc && target__none(&rec->opts.target)) 904bca647aaSTom Zanussi usage_with_options(record_usage, record_options); 90586470930SIngo Molnar 906bea03405SNamhyung Kim if (nr_cgroups && !rec->opts.target.system_wide) { 9073780f488SNamhyung Kim ui__error("cgroup monitoring only available in" 908023695d9SStephane Eranian " system-wide mode\n"); 909023695d9SStephane Eranian usage_with_options(record_usage, record_options); 910023695d9SStephane Eranian } 911023695d9SStephane Eranian 9120a7e6d1bSNamhyung Kim symbol__init(NULL); 913baa2f6ceSArnaldo Carvalho de Melo 914ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) 915646aaea6SArnaldo Carvalho de Melo pr_warning( 916646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n" 917ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n" 918646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n" 919646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n" 920646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n" 921646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n" 922646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n"); 923ec80fde7SArnaldo Carvalho de Melo 924d20deb64SArnaldo Carvalho de Melo if (rec->no_buildid_cache || rec->no_buildid) 925a1ac1d3cSStephane Eranian disable_buildid_cache(); 926655000e7SArnaldo Carvalho de Melo 9273e2be2daSArnaldo Carvalho de Melo if (rec->evlist->nr_entries == 0 && 9283e2be2daSArnaldo Carvalho de Melo perf_evlist__add_default(rec->evlist) < 0) { 92969aad6f1SArnaldo Carvalho de Melo pr_err("Not enough memory for event selector list\n"); 93069aad6f1SArnaldo Carvalho de Melo goto out_symbol_exit; 931bbd36e5eSPeter Zijlstra } 93286470930SIngo Molnar 93369e7e5b0SAdrian Hunter if (rec->opts.target.tid && !rec->opts.no_inherit_set) 93469e7e5b0SAdrian Hunter rec->opts.no_inherit = true; 93569e7e5b0SAdrian Hunter 936602ad878SArnaldo Carvalho de Melo err = target__validate(&rec->opts.target); 93716ad2ffbSNamhyung Kim if (err) { 938602ad878SArnaldo Carvalho de Melo target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 93916ad2ffbSNamhyung Kim ui__warning("%s", errbuf); 94016ad2ffbSNamhyung Kim } 9414bd0f2d2SNamhyung Kim 942602ad878SArnaldo Carvalho de Melo err = target__parse_uid(&rec->opts.target); 94316ad2ffbSNamhyung Kim if (err) { 94416ad2ffbSNamhyung Kim int saved_errno = errno; 94516ad2ffbSNamhyung Kim 946602ad878SArnaldo Carvalho de Melo target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 9473780f488SNamhyung Kim ui__error("%s", errbuf); 94816ad2ffbSNamhyung Kim 94916ad2ffbSNamhyung Kim err = -saved_errno; 9508fa60e1fSNamhyung Kim goto out_symbol_exit; 95116ad2ffbSNamhyung Kim } 9520d37aa34SArnaldo Carvalho de Melo 95316ad2ffbSNamhyung Kim err = -ENOMEM; 9543e2be2daSArnaldo Carvalho de Melo if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0) 955dd7927f4SArnaldo Carvalho de Melo usage_with_options(record_usage, record_options); 95669aad6f1SArnaldo Carvalho de Melo 957b4006796SArnaldo Carvalho de Melo if (record_opts__config(&rec->opts)) { 95839d17dacSArnaldo Carvalho de Melo err = -EINVAL; 95903ad9747SArnaldo Carvalho de Melo goto out_symbol_exit; 9607e4ff9e3SMike Galbraith } 9617e4ff9e3SMike Galbraith 962d20deb64SArnaldo Carvalho de Melo err = __cmd_record(&record, argc, argv); 963d65a458bSArnaldo Carvalho de Melo out_symbol_exit: 96445604710SNamhyung Kim perf_evlist__delete(rec->evlist); 965d65a458bSArnaldo Carvalho de Melo symbol__exit(); 96639d17dacSArnaldo Carvalho de Melo return err; 96786470930SIngo Molnar } 968