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 688c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read(struct record *rec, struct perf_mmap *md) 6986470930SIngo Molnar { 70744bd8aaSArnaldo Carvalho de Melo unsigned int head = perf_mmap__read_head(md); 7186470930SIngo Molnar unsigned int old = md->prev; 72918512b4SJiri Olsa unsigned char *data = md->base + page_size; 7386470930SIngo Molnar unsigned long size; 7486470930SIngo Molnar void *buf; 758d3eca20SDavid Ahern int rc = 0; 7686470930SIngo Molnar 77dc82009aSArnaldo Carvalho de Melo if (old == head) 788d3eca20SDavid Ahern return 0; 7986470930SIngo Molnar 80d20deb64SArnaldo Carvalho de Melo rec->samples++; 8186470930SIngo Molnar 8286470930SIngo Molnar size = head - old; 8386470930SIngo Molnar 8486470930SIngo Molnar if ((old & md->mask) + size != (head & md->mask)) { 8586470930SIngo Molnar buf = &data[old & md->mask]; 8686470930SIngo Molnar size = md->mask + 1 - (old & md->mask); 8786470930SIngo Molnar old += size; 8886470930SIngo Molnar 898c6f45a7SArnaldo Carvalho de Melo if (record__write(rec, buf, size) < 0) { 908d3eca20SDavid Ahern rc = -1; 918d3eca20SDavid Ahern goto out; 928d3eca20SDavid Ahern } 9386470930SIngo Molnar } 9486470930SIngo Molnar 9586470930SIngo Molnar buf = &data[old & md->mask]; 9686470930SIngo Molnar size = head - old; 9786470930SIngo Molnar old += size; 9886470930SIngo Molnar 998c6f45a7SArnaldo Carvalho de Melo if (record__write(rec, buf, size) < 0) { 1008d3eca20SDavid Ahern rc = -1; 1018d3eca20SDavid Ahern goto out; 1028d3eca20SDavid Ahern } 10386470930SIngo Molnar 10486470930SIngo Molnar md->prev = old; 105115d2d89SArnaldo Carvalho de Melo perf_mmap__write_tail(md, old); 1068d3eca20SDavid Ahern 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, 1640a102479SFrederic Weisbecker strerror(errno)); 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 { 1788d3eca20SDavid Ahern pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); 1798d3eca20SDavid Ahern rc = -errno; 1808d3eca20SDavid Ahern } 1818d3eca20SDavid Ahern goto out; 18218e60939SNelson Elhage } 1830a27d7f9SArnaldo Carvalho de Melo 184a91e5431SArnaldo Carvalho de Melo session->evlist = evlist; 1857b56cce2SArnaldo Carvalho de Melo perf_session__set_id_hdr_size(session); 1868d3eca20SDavid Ahern out: 1878d3eca20SDavid Ahern return rc; 188a91e5431SArnaldo Carvalho de Melo } 189a91e5431SArnaldo Carvalho de Melo 1908c6f45a7SArnaldo Carvalho de Melo static int process_buildids(struct record *rec) 1916122e4e4SArnaldo Carvalho de Melo { 192f5fc1412SJiri Olsa struct perf_data_file *file = &rec->file; 193f5fc1412SJiri Olsa struct perf_session *session = rec->session; 1947ab75cffSDavid Ahern u64 start = session->header.data_offset; 1956122e4e4SArnaldo Carvalho de Melo 196f5fc1412SJiri Olsa u64 size = lseek(file->fd, 0, SEEK_CUR); 1979f591fd7SArnaldo Carvalho de Melo if (size == 0) 1989f591fd7SArnaldo Carvalho de Melo return 0; 1999f591fd7SArnaldo Carvalho de Melo 2007ab75cffSDavid Ahern return __perf_session__process_events(session, start, 2017ab75cffSDavid Ahern size - start, 2026122e4e4SArnaldo Carvalho de Melo size, &build_id__mark_dso_hit_ops); 2036122e4e4SArnaldo Carvalho de Melo } 2046122e4e4SArnaldo Carvalho de Melo 2058115d60cSArnaldo Carvalho de Melo static void perf_event__synthesize_guest_os(struct machine *machine, void *data) 206a1645ce1SZhang, Yanmin { 207a1645ce1SZhang, Yanmin int err; 20845694aa7SArnaldo Carvalho de Melo struct perf_tool *tool = data; 209a1645ce1SZhang, Yanmin /* 210a1645ce1SZhang, Yanmin *As for guest kernel when processing subcommand record&report, 211a1645ce1SZhang, Yanmin *we arrange module mmap prior to guest kernel mmap and trigger 212a1645ce1SZhang, Yanmin *a preload dso because default guest module symbols are loaded 213a1645ce1SZhang, Yanmin *from guest kallsyms instead of /lib/modules/XXX/XXX. This 214a1645ce1SZhang, Yanmin *method is used to avoid symbol missing when the first addr is 215a1645ce1SZhang, Yanmin *in module instead of in guest kernel. 216a1645ce1SZhang, Yanmin */ 21745694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_modules(tool, process_synthesized_event, 218743eb868SArnaldo Carvalho de Melo machine); 219a1645ce1SZhang, Yanmin if (err < 0) 220a1645ce1SZhang, Yanmin pr_err("Couldn't record guest kernel [%d]'s reference" 22123346f21SArnaldo Carvalho de Melo " relocation symbol.\n", machine->pid); 222a1645ce1SZhang, Yanmin 223a1645ce1SZhang, Yanmin /* 224a1645ce1SZhang, Yanmin * We use _stext for guest kernel because guest kernel's /proc/kallsyms 225a1645ce1SZhang, Yanmin * have no _text sometimes. 226a1645ce1SZhang, Yanmin */ 22745694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 2280ae617beSAdrian Hunter machine); 229a1645ce1SZhang, Yanmin if (err < 0) 230a1645ce1SZhang, Yanmin pr_err("Couldn't record guest kernel [%d]'s reference" 23123346f21SArnaldo Carvalho de Melo " relocation symbol.\n", machine->pid); 232a1645ce1SZhang, Yanmin } 233a1645ce1SZhang, Yanmin 23498402807SFrederic Weisbecker static struct perf_event_header finished_round_event = { 23598402807SFrederic Weisbecker .size = sizeof(struct perf_event_header), 23698402807SFrederic Weisbecker .type = PERF_RECORD_FINISHED_ROUND, 23798402807SFrederic Weisbecker }; 23898402807SFrederic Weisbecker 2398c6f45a7SArnaldo Carvalho de Melo static int record__mmap_read_all(struct record *rec) 24098402807SFrederic Weisbecker { 241dcabb507SJiri Olsa u64 bytes_written = rec->bytes_written; 2420e2e63ddSPeter Zijlstra int i; 2438d3eca20SDavid Ahern int rc = 0; 24498402807SFrederic Weisbecker 245d20deb64SArnaldo Carvalho de Melo for (i = 0; i < rec->evlist->nr_mmaps; i++) { 2468d3eca20SDavid Ahern if (rec->evlist->mmap[i].base) { 2478c6f45a7SArnaldo Carvalho de Melo if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { 2488d3eca20SDavid Ahern rc = -1; 2498d3eca20SDavid Ahern goto out; 2508d3eca20SDavid Ahern } 2518d3eca20SDavid Ahern } 25298402807SFrederic Weisbecker } 25398402807SFrederic Weisbecker 254dcabb507SJiri Olsa /* 255dcabb507SJiri Olsa * Mark the round finished in case we wrote 256dcabb507SJiri Olsa * at least one event. 257dcabb507SJiri Olsa */ 258dcabb507SJiri Olsa if (bytes_written != rec->bytes_written) 2598c6f45a7SArnaldo Carvalho de Melo rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); 2608d3eca20SDavid Ahern 2618d3eca20SDavid Ahern out: 2628d3eca20SDavid Ahern return rc; 26398402807SFrederic Weisbecker } 26498402807SFrederic Weisbecker 2658c6f45a7SArnaldo Carvalho de Melo static void record__init_features(struct record *rec) 26657706abcSDavid Ahern { 26757706abcSDavid Ahern struct perf_session *session = rec->session; 26857706abcSDavid Ahern int feat; 26957706abcSDavid Ahern 27057706abcSDavid Ahern for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++) 27157706abcSDavid Ahern perf_header__set_feat(&session->header, feat); 27257706abcSDavid Ahern 27357706abcSDavid Ahern if (rec->no_buildid) 27457706abcSDavid Ahern perf_header__clear_feat(&session->header, HEADER_BUILD_ID); 27557706abcSDavid Ahern 2763e2be2daSArnaldo Carvalho de Melo if (!have_tracepoints(&rec->evlist->entries)) 27757706abcSDavid Ahern perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); 27857706abcSDavid Ahern 27957706abcSDavid Ahern if (!rec->opts.branch_stack) 28057706abcSDavid Ahern perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); 28157706abcSDavid Ahern } 28257706abcSDavid Ahern 283f33cbe72SArnaldo Carvalho de Melo static volatile int workload_exec_errno; 284f33cbe72SArnaldo Carvalho de Melo 285f33cbe72SArnaldo Carvalho de Melo /* 286f33cbe72SArnaldo Carvalho de Melo * perf_evlist__prepare_workload will send a SIGUSR1 287f33cbe72SArnaldo Carvalho de Melo * if the fork fails, since we asked by setting its 288f33cbe72SArnaldo Carvalho de Melo * want_signal to true. 289f33cbe72SArnaldo Carvalho de Melo */ 29045604710SNamhyung Kim static void workload_exec_failed_signal(int signo __maybe_unused, 29145604710SNamhyung Kim siginfo_t *info, 292f33cbe72SArnaldo Carvalho de Melo void *ucontext __maybe_unused) 293f33cbe72SArnaldo Carvalho de Melo { 294f33cbe72SArnaldo Carvalho de Melo workload_exec_errno = info->si_value.sival_int; 295f33cbe72SArnaldo Carvalho de Melo done = 1; 296f33cbe72SArnaldo Carvalho de Melo child_finished = 1; 297f33cbe72SArnaldo Carvalho de Melo } 298f33cbe72SArnaldo Carvalho de Melo 2998c6f45a7SArnaldo Carvalho de Melo static int __cmd_record(struct record *rec, int argc, const char **argv) 30086470930SIngo Molnar { 30157706abcSDavid Ahern int err; 30245604710SNamhyung Kim int status = 0; 3038b412664SPeter Zijlstra unsigned long waking = 0; 30446be604bSZhang, Yanmin const bool forks = argc > 0; 30523346f21SArnaldo Carvalho de Melo struct machine *machine; 30645694aa7SArnaldo Carvalho de Melo struct perf_tool *tool = &rec->tool; 307b4006796SArnaldo Carvalho de Melo struct record_opts *opts = &rec->opts; 308f5fc1412SJiri Olsa struct perf_data_file *file = &rec->file; 309d20deb64SArnaldo Carvalho de Melo struct perf_session *session; 3102711926aSJiri Olsa bool disabled = false; 31186470930SIngo Molnar 312d20deb64SArnaldo Carvalho de Melo rec->progname = argv[0]; 31333e49ea7SAndi Kleen 31445604710SNamhyung Kim atexit(record__sig_exit); 315f5970550SPeter Zijlstra signal(SIGCHLD, sig_handler); 316f5970550SPeter Zijlstra signal(SIGINT, sig_handler); 317804f7ac7SDavid Ahern signal(SIGTERM, sig_handler); 318f5970550SPeter Zijlstra 319f5fc1412SJiri Olsa session = perf_session__new(file, false, NULL); 32094c744b6SArnaldo Carvalho de Melo if (session == NULL) { 321ffa91880SAdrien BAK pr_err("Perf session creation failed.\n"); 322a9a70bbcSArnaldo Carvalho de Melo return -1; 323a9a70bbcSArnaldo Carvalho de Melo } 324a9a70bbcSArnaldo Carvalho de Melo 325d20deb64SArnaldo Carvalho de Melo rec->session = session; 326d20deb64SArnaldo Carvalho de Melo 3278c6f45a7SArnaldo Carvalho de Melo record__init_features(rec); 328330aa675SStephane Eranian 329d4db3f16SArnaldo Carvalho de Melo if (forks) { 3303e2be2daSArnaldo Carvalho de Melo err = perf_evlist__prepare_workload(rec->evlist, &opts->target, 331f5fc1412SJiri Olsa argv, file->is_pipe, 332735f7e0bSArnaldo Carvalho de Melo workload_exec_failed_signal); 33335b9d88eSArnaldo Carvalho de Melo if (err < 0) { 33435b9d88eSArnaldo Carvalho de Melo pr_err("Couldn't run the workload!\n"); 33545604710SNamhyung Kim status = err; 33635b9d88eSArnaldo Carvalho de Melo goto out_delete_session; 337856e9660SPeter Zijlstra } 338856e9660SPeter Zijlstra } 339856e9660SPeter Zijlstra 3408c6f45a7SArnaldo Carvalho de Melo if (record__open(rec) != 0) { 3418d3eca20SDavid Ahern err = -1; 34245604710SNamhyung Kim goto out_child; 3438d3eca20SDavid Ahern } 34486470930SIngo Molnar 3453e2be2daSArnaldo Carvalho de Melo if (!rec->evlist->nr_groups) 346a8bb559bSNamhyung Kim perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); 347a8bb559bSNamhyung Kim 348f5fc1412SJiri Olsa if (file->is_pipe) { 349f5fc1412SJiri Olsa err = perf_header__write_pipe(file->fd); 350529870e3STom Zanussi if (err < 0) 35145604710SNamhyung Kim goto out_child; 352563aecb2SJiri Olsa } else { 3533e2be2daSArnaldo Carvalho de Melo err = perf_session__write_header(session, rec->evlist, 354f5fc1412SJiri Olsa file->fd, false); 355d5eed904SArnaldo Carvalho de Melo if (err < 0) 35645604710SNamhyung Kim goto out_child; 357d5eed904SArnaldo Carvalho de Melo } 3587c6a1c65SPeter Zijlstra 359d3665498SDavid Ahern if (!rec->no_buildid 360e20960c0SRobert Richter && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { 361d3665498SDavid Ahern pr_err("Couldn't generate buildids. " 362e20960c0SRobert Richter "Use --no-buildid to profile anyway.\n"); 3638d3eca20SDavid Ahern err = -1; 36445604710SNamhyung Kim goto out_child; 365e20960c0SRobert Richter } 366e20960c0SRobert Richter 36734ba5122SArnaldo Carvalho de Melo machine = &session->machines.host; 368743eb868SArnaldo Carvalho de Melo 369f5fc1412SJiri Olsa if (file->is_pipe) { 37045694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_attrs(tool, session, 371a91e5431SArnaldo Carvalho de Melo process_synthesized_event); 3722c46dbb5STom Zanussi if (err < 0) { 3732c46dbb5STom Zanussi pr_err("Couldn't synthesize attrs.\n"); 37445604710SNamhyung Kim goto out_child; 3752c46dbb5STom Zanussi } 376cd19a035STom Zanussi 3773e2be2daSArnaldo Carvalho de Melo if (have_tracepoints(&rec->evlist->entries)) { 37863e0c771STom Zanussi /* 37963e0c771STom Zanussi * FIXME err <= 0 here actually means that 38063e0c771STom Zanussi * there were no tracepoints so its not really 38163e0c771STom Zanussi * an error, just that we don't need to 38263e0c771STom Zanussi * synthesize anything. We really have to 38363e0c771STom Zanussi * return this more properly and also 38463e0c771STom Zanussi * propagate errors that now are calling die() 38563e0c771STom Zanussi */ 3863e2be2daSArnaldo Carvalho de Melo err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist, 387743eb868SArnaldo Carvalho de Melo process_synthesized_event); 38863e0c771STom Zanussi if (err <= 0) { 38963e0c771STom Zanussi pr_err("Couldn't record tracing data.\n"); 39045604710SNamhyung Kim goto out_child; 39163e0c771STom Zanussi } 392f34b9001SDavid Ahern rec->bytes_written += err; 3932c46dbb5STom Zanussi } 39463e0c771STom Zanussi } 3952c46dbb5STom Zanussi 39645694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 3970ae617beSAdrian Hunter machine); 398c1a3a4b9SArnaldo Carvalho de Melo if (err < 0) 399c1a3a4b9SArnaldo Carvalho de Melo pr_err("Couldn't record kernel reference relocation symbol\n" 400c1a3a4b9SArnaldo Carvalho de Melo "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 401c1a3a4b9SArnaldo Carvalho de Melo "Check /proc/kallsyms permission or run as root.\n"); 40256b03f3cSArnaldo Carvalho de Melo 40345694aa7SArnaldo Carvalho de Melo err = perf_event__synthesize_modules(tool, process_synthesized_event, 404743eb868SArnaldo Carvalho de Melo machine); 405c1a3a4b9SArnaldo Carvalho de Melo if (err < 0) 406c1a3a4b9SArnaldo Carvalho de Melo pr_err("Couldn't record kernel module information.\n" 407c1a3a4b9SArnaldo Carvalho de Melo "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 408c1a3a4b9SArnaldo Carvalho de Melo "Check /proc/modules permission or run as root.\n"); 409c1a3a4b9SArnaldo Carvalho de Melo 4107e383de4SArnaldo Carvalho de Melo if (perf_guest) { 411876650e6SArnaldo Carvalho de Melo machines__process_guests(&session->machines, 4127e383de4SArnaldo Carvalho de Melo perf_event__synthesize_guest_os, tool); 4137e383de4SArnaldo Carvalho de Melo } 414b7cece76SArnaldo Carvalho de Melo 4153e2be2daSArnaldo Carvalho de Melo err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads, 41658d925dcSArnaldo Carvalho de Melo process_synthesized_event, opts->sample_address); 4178d3eca20SDavid Ahern if (err != 0) 41845604710SNamhyung Kim goto out_child; 4198d3eca20SDavid Ahern 420d20deb64SArnaldo Carvalho de Melo if (rec->realtime_prio) { 42186470930SIngo Molnar struct sched_param param; 42286470930SIngo Molnar 423d20deb64SArnaldo Carvalho de Melo param.sched_priority = rec->realtime_prio; 42486470930SIngo Molnar if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { 4256beba7adSArnaldo Carvalho de Melo pr_err("Could not set realtime priority.\n"); 4268d3eca20SDavid Ahern err = -1; 42745604710SNamhyung Kim goto out_child; 42886470930SIngo Molnar } 42986470930SIngo Molnar } 43086470930SIngo Molnar 431774cb499SJiri Olsa /* 432774cb499SJiri Olsa * When perf is starting the traced process, all the events 433774cb499SJiri Olsa * (apart from group members) have enable_on_exec=1 set, 434774cb499SJiri Olsa * so don't spoil it by prematurely enabling them. 435774cb499SJiri Olsa */ 4366619a53eSAndi Kleen if (!target__none(&opts->target) && !opts->initial_delay) 4373e2be2daSArnaldo Carvalho de Melo perf_evlist__enable(rec->evlist); 438764e16a3SDavid Ahern 439856e9660SPeter Zijlstra /* 440856e9660SPeter Zijlstra * Let the child rip 441856e9660SPeter Zijlstra */ 442735f7e0bSArnaldo Carvalho de Melo if (forks) 4433e2be2daSArnaldo Carvalho de Melo perf_evlist__start_workload(rec->evlist); 444856e9660SPeter Zijlstra 4456619a53eSAndi Kleen if (opts->initial_delay) { 4466619a53eSAndi Kleen usleep(opts->initial_delay * 1000); 4476619a53eSAndi Kleen perf_evlist__enable(rec->evlist); 4486619a53eSAndi Kleen } 4496619a53eSAndi Kleen 450649c48a9SPeter Zijlstra for (;;) { 451d20deb64SArnaldo Carvalho de Melo int hits = rec->samples; 45286470930SIngo Molnar 4538c6f45a7SArnaldo Carvalho de Melo if (record__mmap_read_all(rec) < 0) { 4548d3eca20SDavid Ahern err = -1; 45545604710SNamhyung Kim goto out_child; 4568d3eca20SDavid Ahern } 45786470930SIngo Molnar 458d20deb64SArnaldo Carvalho de Melo if (hits == rec->samples) { 459649c48a9SPeter Zijlstra if (done) 460649c48a9SPeter Zijlstra break; 4613e2be2daSArnaldo Carvalho de Melo err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1); 462a515114fSJiri Olsa /* 463a515114fSJiri Olsa * Propagate error, only if there's any. Ignore positive 464a515114fSJiri Olsa * number of returned events and interrupt error. 465a515114fSJiri Olsa */ 466a515114fSJiri Olsa if (err > 0 || (err < 0 && errno == EINTR)) 46745604710SNamhyung Kim err = 0; 4688b412664SPeter Zijlstra waking++; 4698b412664SPeter Zijlstra } 4708b412664SPeter Zijlstra 471774cb499SJiri Olsa /* 472774cb499SJiri Olsa * When perf is starting the traced process, at the end events 473774cb499SJiri Olsa * die with the process and we wait for that. Thus no need to 474774cb499SJiri Olsa * disable events in this case. 475774cb499SJiri Olsa */ 476602ad878SArnaldo Carvalho de Melo if (done && !disabled && !target__none(&opts->target)) { 4773e2be2daSArnaldo Carvalho de Melo perf_evlist__disable(rec->evlist); 4782711926aSJiri Olsa disabled = true; 4792711926aSJiri Olsa } 4808b412664SPeter Zijlstra } 4818b412664SPeter Zijlstra 482f33cbe72SArnaldo Carvalho de Melo if (forks && workload_exec_errno) { 483f33cbe72SArnaldo Carvalho de Melo char msg[512]; 484f33cbe72SArnaldo Carvalho de Melo const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); 485f33cbe72SArnaldo Carvalho de Melo pr_err("Workload failed: %s\n", emsg); 486f33cbe72SArnaldo Carvalho de Melo err = -1; 48745604710SNamhyung Kim goto out_child; 488f33cbe72SArnaldo Carvalho de Melo } 489f33cbe72SArnaldo Carvalho de Melo 49045604710SNamhyung Kim if (!quiet) { 4918b412664SPeter Zijlstra fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); 49286470930SIngo Molnar 49386470930SIngo Molnar /* 49486470930SIngo Molnar * Approximate RIP event size: 24 bytes. 49586470930SIngo Molnar */ 49686470930SIngo Molnar fprintf(stderr, 4979486aa38SArnaldo Carvalho de Melo "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", 498d20deb64SArnaldo Carvalho de Melo (double)rec->bytes_written / 1024.0 / 1024.0, 4996a4d98d7SJiri Olsa file->path, 500d20deb64SArnaldo Carvalho de Melo rec->bytes_written / 24); 50145604710SNamhyung Kim } 50286470930SIngo Molnar 50345604710SNamhyung Kim out_child: 50445604710SNamhyung Kim if (forks) { 50545604710SNamhyung Kim int exit_status; 50645604710SNamhyung Kim 50745604710SNamhyung Kim if (!child_finished) 50845604710SNamhyung Kim kill(rec->evlist->workload.pid, SIGTERM); 50945604710SNamhyung Kim 51045604710SNamhyung Kim wait(&exit_status); 51145604710SNamhyung Kim 51245604710SNamhyung Kim if (err < 0) 51345604710SNamhyung Kim status = err; 51445604710SNamhyung Kim else if (WIFEXITED(exit_status)) 51545604710SNamhyung Kim status = WEXITSTATUS(exit_status); 51645604710SNamhyung Kim else if (WIFSIGNALED(exit_status)) 51745604710SNamhyung Kim signr = WTERMSIG(exit_status); 51845604710SNamhyung Kim } else 51945604710SNamhyung Kim status = err; 52045604710SNamhyung Kim 52145604710SNamhyung Kim if (!err && !file->is_pipe) { 52245604710SNamhyung Kim rec->session->header.data_size += rec->bytes_written; 52345604710SNamhyung Kim 52445604710SNamhyung Kim if (!rec->no_buildid) 52545604710SNamhyung Kim process_buildids(rec); 52645604710SNamhyung Kim perf_session__write_header(rec->session, rec->evlist, 52745604710SNamhyung Kim file->fd, true); 52845604710SNamhyung Kim } 52939d17dacSArnaldo Carvalho de Melo 53039d17dacSArnaldo Carvalho de Melo out_delete_session: 53139d17dacSArnaldo Carvalho de Melo perf_session__delete(session); 53245604710SNamhyung Kim return status; 53386470930SIngo Molnar } 53486470930SIngo Molnar 535bdfebd84SRoberto Agostino Vitillo #define BRANCH_OPT(n, m) \ 536bdfebd84SRoberto Agostino Vitillo { .name = n, .mode = (m) } 537bdfebd84SRoberto Agostino Vitillo 538bdfebd84SRoberto Agostino Vitillo #define BRANCH_END { .name = NULL } 539bdfebd84SRoberto Agostino Vitillo 540bdfebd84SRoberto Agostino Vitillo struct branch_mode { 541bdfebd84SRoberto Agostino Vitillo const char *name; 542bdfebd84SRoberto Agostino Vitillo int mode; 543bdfebd84SRoberto Agostino Vitillo }; 544bdfebd84SRoberto Agostino Vitillo 545bdfebd84SRoberto Agostino Vitillo static const struct branch_mode branch_modes[] = { 546bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER), 547bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL), 548bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV), 549bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY), 550bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL), 551bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN), 552bdfebd84SRoberto Agostino Vitillo BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL), 5530126d493SAndi Kleen BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX), 5540126d493SAndi Kleen BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX), 5550126d493SAndi Kleen BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX), 5560fffa5dfSAnshuman Khandual BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND), 557bdfebd84SRoberto Agostino Vitillo BRANCH_END 558bdfebd84SRoberto Agostino Vitillo }; 559bdfebd84SRoberto Agostino Vitillo 560bdfebd84SRoberto Agostino Vitillo static int 561a5aabdacSStephane Eranian parse_branch_stack(const struct option *opt, const char *str, int unset) 562bdfebd84SRoberto Agostino Vitillo { 563bdfebd84SRoberto Agostino Vitillo #define ONLY_PLM \ 564bdfebd84SRoberto Agostino Vitillo (PERF_SAMPLE_BRANCH_USER |\ 565bdfebd84SRoberto Agostino Vitillo PERF_SAMPLE_BRANCH_KERNEL |\ 566bdfebd84SRoberto Agostino Vitillo PERF_SAMPLE_BRANCH_HV) 567bdfebd84SRoberto Agostino Vitillo 568bdfebd84SRoberto Agostino Vitillo uint64_t *mode = (uint64_t *)opt->value; 569bdfebd84SRoberto Agostino Vitillo const struct branch_mode *br; 570a5aabdacSStephane Eranian char *s, *os = NULL, *p; 571bdfebd84SRoberto Agostino Vitillo int ret = -1; 572bdfebd84SRoberto Agostino Vitillo 573a5aabdacSStephane Eranian if (unset) 574a5aabdacSStephane Eranian return 0; 575bdfebd84SRoberto Agostino Vitillo 576a5aabdacSStephane Eranian /* 577a5aabdacSStephane Eranian * cannot set it twice, -b + --branch-filter for instance 578a5aabdacSStephane Eranian */ 579a5aabdacSStephane Eranian if (*mode) 580a5aabdacSStephane Eranian return -1; 581a5aabdacSStephane Eranian 582a5aabdacSStephane Eranian /* str may be NULL in case no arg is passed to -b */ 583a5aabdacSStephane Eranian if (str) { 584bdfebd84SRoberto Agostino Vitillo /* because str is read-only */ 585bdfebd84SRoberto Agostino Vitillo s = os = strdup(str); 586bdfebd84SRoberto Agostino Vitillo if (!s) 587bdfebd84SRoberto Agostino Vitillo return -1; 588bdfebd84SRoberto Agostino Vitillo 589bdfebd84SRoberto Agostino Vitillo for (;;) { 590bdfebd84SRoberto Agostino Vitillo p = strchr(s, ','); 591bdfebd84SRoberto Agostino Vitillo if (p) 592bdfebd84SRoberto Agostino Vitillo *p = '\0'; 593bdfebd84SRoberto Agostino Vitillo 594bdfebd84SRoberto Agostino Vitillo for (br = branch_modes; br->name; br++) { 595bdfebd84SRoberto Agostino Vitillo if (!strcasecmp(s, br->name)) 596bdfebd84SRoberto Agostino Vitillo break; 597bdfebd84SRoberto Agostino Vitillo } 598a5aabdacSStephane Eranian if (!br->name) { 599a5aabdacSStephane Eranian ui__warning("unknown branch filter %s," 600a5aabdacSStephane Eranian " check man page\n", s); 601bdfebd84SRoberto Agostino Vitillo goto error; 602a5aabdacSStephane Eranian } 603bdfebd84SRoberto Agostino Vitillo 604bdfebd84SRoberto Agostino Vitillo *mode |= br->mode; 605bdfebd84SRoberto Agostino Vitillo 606bdfebd84SRoberto Agostino Vitillo if (!p) 607bdfebd84SRoberto Agostino Vitillo break; 608bdfebd84SRoberto Agostino Vitillo 609bdfebd84SRoberto Agostino Vitillo s = p + 1; 610bdfebd84SRoberto Agostino Vitillo } 611a5aabdacSStephane Eranian } 612bdfebd84SRoberto Agostino Vitillo ret = 0; 613bdfebd84SRoberto Agostino Vitillo 614a5aabdacSStephane Eranian /* default to any branch */ 615bdfebd84SRoberto Agostino Vitillo if ((*mode & ~ONLY_PLM) == 0) { 616a5aabdacSStephane Eranian *mode = PERF_SAMPLE_BRANCH_ANY; 617bdfebd84SRoberto Agostino Vitillo } 618bdfebd84SRoberto Agostino Vitillo error: 619bdfebd84SRoberto Agostino Vitillo free(os); 620bdfebd84SRoberto Agostino Vitillo return ret; 621bdfebd84SRoberto Agostino Vitillo } 622bdfebd84SRoberto Agostino Vitillo 6239ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT 62426d33022SJiri Olsa static int get_stack_size(char *str, unsigned long *_size) 62526d33022SJiri Olsa { 62626d33022SJiri Olsa char *endptr; 62726d33022SJiri Olsa unsigned long size; 62826d33022SJiri Olsa unsigned long max_size = round_down(USHRT_MAX, sizeof(u64)); 62926d33022SJiri Olsa 63026d33022SJiri Olsa size = strtoul(str, &endptr, 0); 63126d33022SJiri Olsa 63226d33022SJiri Olsa do { 63326d33022SJiri Olsa if (*endptr) 63426d33022SJiri Olsa break; 63526d33022SJiri Olsa 63626d33022SJiri Olsa size = round_up(size, sizeof(u64)); 63726d33022SJiri Olsa if (!size || size > max_size) 63826d33022SJiri Olsa break; 63926d33022SJiri Olsa 64026d33022SJiri Olsa *_size = size; 64126d33022SJiri Olsa return 0; 64226d33022SJiri Olsa 64326d33022SJiri Olsa } while (0); 64426d33022SJiri Olsa 64526d33022SJiri Olsa pr_err("callchain: Incorrect stack dump size (max %ld): %s\n", 64626d33022SJiri Olsa max_size, str); 64726d33022SJiri Olsa return -1; 64826d33022SJiri Olsa } 6499ff125d1SJiri Olsa #endif /* HAVE_DWARF_UNWIND_SUPPORT */ 65026d33022SJiri Olsa 651b4006796SArnaldo Carvalho de Melo int record_parse_callchain(const char *arg, struct record_opts *opts) 65226d33022SJiri Olsa { 65326d33022SJiri Olsa char *tok, *name, *saveptr = NULL; 65426d33022SJiri Olsa char *buf; 65526d33022SJiri Olsa int ret = -1; 65626d33022SJiri Olsa 65726d33022SJiri Olsa /* We need buffer that we know we can write to. */ 65826d33022SJiri Olsa buf = malloc(strlen(arg) + 1); 65926d33022SJiri Olsa if (!buf) 66026d33022SJiri Olsa return -ENOMEM; 66126d33022SJiri Olsa 66226d33022SJiri Olsa strcpy(buf, arg); 66326d33022SJiri Olsa 66426d33022SJiri Olsa tok = strtok_r((char *)buf, ",", &saveptr); 66526d33022SJiri Olsa name = tok ? : (char *)buf; 66626d33022SJiri Olsa 66726d33022SJiri Olsa do { 66826d33022SJiri Olsa /* Framepointer style */ 66926d33022SJiri Olsa if (!strncmp(name, "fp", sizeof("fp"))) { 67026d33022SJiri Olsa if (!strtok_r(NULL, ",", &saveptr)) { 671c5ff78c3SArnaldo Carvalho de Melo opts->call_graph = CALLCHAIN_FP; 67226d33022SJiri Olsa ret = 0; 67326d33022SJiri Olsa } else 67426d33022SJiri Olsa pr_err("callchain: No more arguments " 67526d33022SJiri Olsa "needed for -g fp\n"); 67626d33022SJiri Olsa break; 67726d33022SJiri Olsa 6789ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT 67926d33022SJiri Olsa /* Dwarf style */ 68026d33022SJiri Olsa } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { 68161eaa3beSArnaldo Carvalho de Melo const unsigned long default_stack_dump_size = 8192; 68261eaa3beSArnaldo Carvalho de Melo 68326d33022SJiri Olsa ret = 0; 684c5ff78c3SArnaldo Carvalho de Melo opts->call_graph = CALLCHAIN_DWARF; 685c5ff78c3SArnaldo Carvalho de Melo opts->stack_dump_size = default_stack_dump_size; 68626d33022SJiri Olsa 68726d33022SJiri Olsa tok = strtok_r(NULL, ",", &saveptr); 68826d33022SJiri Olsa if (tok) { 68926d33022SJiri Olsa unsigned long size = 0; 69026d33022SJiri Olsa 69126d33022SJiri Olsa ret = get_stack_size(tok, &size); 692c5ff78c3SArnaldo Carvalho de Melo opts->stack_dump_size = size; 69326d33022SJiri Olsa } 6949ff125d1SJiri Olsa #endif /* HAVE_DWARF_UNWIND_SUPPORT */ 69526d33022SJiri Olsa } else { 69609b0fd45SJiri Olsa pr_err("callchain: Unknown --call-graph option " 69726d33022SJiri Olsa "value: %s\n", arg); 69826d33022SJiri Olsa break; 69926d33022SJiri Olsa } 70026d33022SJiri Olsa 70126d33022SJiri Olsa } while (0); 70226d33022SJiri Olsa 70326d33022SJiri Olsa free(buf); 70409b0fd45SJiri Olsa return ret; 70509b0fd45SJiri Olsa } 70626d33022SJiri Olsa 707b4006796SArnaldo Carvalho de Melo static void callchain_debug(struct record_opts *opts) 70809b0fd45SJiri Olsa { 709a601fdffSJiri Olsa static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" }; 710a601fdffSJiri Olsa 711a601fdffSJiri Olsa pr_debug("callchain: type %s\n", str[opts->call_graph]); 71226d33022SJiri Olsa 71309b0fd45SJiri Olsa if (opts->call_graph == CALLCHAIN_DWARF) 71409b0fd45SJiri Olsa pr_debug("callchain: stack dump size %d\n", 71509b0fd45SJiri Olsa opts->stack_dump_size); 71609b0fd45SJiri Olsa } 71709b0fd45SJiri Olsa 71809b0fd45SJiri Olsa int record_parse_callchain_opt(const struct option *opt, 71909b0fd45SJiri Olsa const char *arg, 72009b0fd45SJiri Olsa int unset) 72109b0fd45SJiri Olsa { 722b4006796SArnaldo Carvalho de Melo struct record_opts *opts = opt->value; 72309b0fd45SJiri Olsa int ret; 72409b0fd45SJiri Olsa 725eb853e80SJiri Olsa opts->call_graph_enabled = !unset; 726eb853e80SJiri Olsa 72709b0fd45SJiri Olsa /* --no-call-graph */ 72809b0fd45SJiri Olsa if (unset) { 72909b0fd45SJiri Olsa opts->call_graph = CALLCHAIN_NONE; 73009b0fd45SJiri Olsa pr_debug("callchain: disabled\n"); 73109b0fd45SJiri Olsa return 0; 73209b0fd45SJiri Olsa } 73309b0fd45SJiri Olsa 73409b0fd45SJiri Olsa ret = record_parse_callchain(arg, opts); 73509b0fd45SJiri Olsa if (!ret) 73609b0fd45SJiri Olsa callchain_debug(opts); 73709b0fd45SJiri Olsa 73826d33022SJiri Olsa return ret; 73926d33022SJiri Olsa } 74026d33022SJiri Olsa 74109b0fd45SJiri Olsa int record_callchain_opt(const struct option *opt, 74209b0fd45SJiri Olsa const char *arg __maybe_unused, 74309b0fd45SJiri Olsa int unset __maybe_unused) 74409b0fd45SJiri Olsa { 745b4006796SArnaldo Carvalho de Melo struct record_opts *opts = opt->value; 74609b0fd45SJiri Olsa 747eb853e80SJiri Olsa opts->call_graph_enabled = !unset; 748eb853e80SJiri Olsa 74909b0fd45SJiri Olsa if (opts->call_graph == CALLCHAIN_NONE) 75009b0fd45SJiri Olsa opts->call_graph = CALLCHAIN_FP; 75109b0fd45SJiri Olsa 75209b0fd45SJiri Olsa callchain_debug(opts); 75309b0fd45SJiri Olsa return 0; 75409b0fd45SJiri Olsa } 75509b0fd45SJiri Olsa 756eb853e80SJiri Olsa static int perf_record_config(const char *var, const char *value, void *cb) 757eb853e80SJiri Olsa { 758eb853e80SJiri Olsa struct record *rec = cb; 759eb853e80SJiri Olsa 760eb853e80SJiri Olsa if (!strcmp(var, "record.call-graph")) 761eb853e80SJiri Olsa return record_parse_callchain(value, &rec->opts); 762eb853e80SJiri Olsa 763eb853e80SJiri Olsa return perf_default_config(var, value, cb); 764eb853e80SJiri Olsa } 765eb853e80SJiri Olsa 76686470930SIngo Molnar static const char * const record_usage[] = { 76786470930SIngo Molnar "perf record [<options>] [<command>]", 76886470930SIngo Molnar "perf record [<options>] -- <command> [<options>]", 76986470930SIngo Molnar NULL 77086470930SIngo Molnar }; 77186470930SIngo Molnar 772d20deb64SArnaldo Carvalho de Melo /* 7738c6f45a7SArnaldo Carvalho de Melo * XXX Ideally would be local to cmd_record() and passed to a record__new 7748c6f45a7SArnaldo Carvalho de Melo * because we need to have access to it in record__exit, that is called 775d20deb64SArnaldo Carvalho de Melo * after cmd_record() exits, but since record_options need to be accessible to 776d20deb64SArnaldo Carvalho de Melo * builtin-script, leave it here. 777d20deb64SArnaldo Carvalho de Melo * 778d20deb64SArnaldo Carvalho de Melo * At least we don't ouch it in all the other functions here directly. 779d20deb64SArnaldo Carvalho de Melo * 780d20deb64SArnaldo Carvalho de Melo * Just say no to tons of global variables, sigh. 781d20deb64SArnaldo Carvalho de Melo */ 7828c6f45a7SArnaldo Carvalho de Melo static struct record record = { 783d20deb64SArnaldo Carvalho de Melo .opts = { 7848affc2b8SAndi Kleen .sample_time = true, 785d20deb64SArnaldo Carvalho de Melo .mmap_pages = UINT_MAX, 786d20deb64SArnaldo Carvalho de Melo .user_freq = UINT_MAX, 787d20deb64SArnaldo Carvalho de Melo .user_interval = ULLONG_MAX, 788447a6013SArnaldo Carvalho de Melo .freq = 4000, 789d1cb9fceSNamhyung Kim .target = { 790d1cb9fceSNamhyung Kim .uses_mmap = true, 7913aa5939dSAdrian Hunter .default_per_cpu = true, 792d1cb9fceSNamhyung Kim }, 793d20deb64SArnaldo Carvalho de Melo }, 794d20deb64SArnaldo Carvalho de Melo }; 7957865e817SFrederic Weisbecker 79609b0fd45SJiri Olsa #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " 79761eaa3beSArnaldo Carvalho de Melo 7989ff125d1SJiri Olsa #ifdef HAVE_DWARF_UNWIND_SUPPORT 79909b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf"; 80061eaa3beSArnaldo Carvalho de Melo #else 80109b0fd45SJiri Olsa const char record_callchain_help[] = CALLCHAIN_HELP "fp"; 80261eaa3beSArnaldo Carvalho de Melo #endif 80361eaa3beSArnaldo Carvalho de Melo 804d20deb64SArnaldo Carvalho de Melo /* 805d20deb64SArnaldo Carvalho de Melo * XXX Will stay a global variable till we fix builtin-script.c to stop messing 806d20deb64SArnaldo Carvalho de Melo * with it and switch to use the library functions in perf_evlist that came 807b4006796SArnaldo Carvalho de Melo * from builtin-record.c, i.e. use record_opts, 808d20deb64SArnaldo Carvalho de Melo * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', 809d20deb64SArnaldo Carvalho de Melo * using pipes, etc. 810d20deb64SArnaldo Carvalho de Melo */ 811bca647aaSTom Zanussi const struct option record_options[] = { 812d20deb64SArnaldo Carvalho de Melo OPT_CALLBACK('e', "event", &record.evlist, "event", 81386470930SIngo Molnar "event selector. use 'perf list' to list available events", 814f120f9d5SJiri Olsa parse_events_option), 815d20deb64SArnaldo Carvalho de Melo OPT_CALLBACK(0, "filter", &record.evlist, "filter", 816c171b552SLi Zefan "event filter", parse_filter), 817bea03405SNamhyung Kim OPT_STRING('p', "pid", &record.opts.target.pid, "pid", 818d6d901c2SZhang, Yanmin "record events on existing process id"), 819bea03405SNamhyung Kim OPT_STRING('t', "tid", &record.opts.target.tid, "tid", 820d6d901c2SZhang, Yanmin "record events on existing thread id"), 821d20deb64SArnaldo Carvalho de Melo OPT_INTEGER('r', "realtime", &record.realtime_prio, 82286470930SIngo Molnar "collect data with this RT SCHED_FIFO priority"), 823509051eaSArnaldo Carvalho de Melo OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering, 824acac03faSKirill Smelkov "collect data without buffering"), 825d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, 826daac07b2SFrederic Weisbecker "collect raw sample records from all opened counters"), 827bea03405SNamhyung Kim OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide, 82886470930SIngo Molnar "system-wide collection from all CPUs"), 829bea03405SNamhyung Kim OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu", 830c45c6ea2SStephane Eranian "list of cpus to monitor"), 831d20deb64SArnaldo Carvalho de Melo OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), 832f5fc1412SJiri Olsa OPT_STRING('o', "output", &record.file.path, "file", 83386470930SIngo Molnar "output file name"), 83469e7e5b0SAdrian Hunter OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit, 83569e7e5b0SAdrian Hunter &record.opts.no_inherit_set, 8362e6cdf99SStephane Eranian "child tasks do not inherit counters"), 837d20deb64SArnaldo Carvalho de Melo OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), 838994a1f78SJiri Olsa OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages", 839994a1f78SJiri Olsa "number of mmap data pages", 840994a1f78SJiri Olsa perf_evlist__parse_mmap_pages), 841d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN(0, "group", &record.opts.group, 84243bece79SLin Ming "put the counters into a counter group"), 84309b0fd45SJiri Olsa OPT_CALLBACK_NOOPT('g', NULL, &record.opts, 84409b0fd45SJiri Olsa NULL, "enables call-graph recording" , 84509b0fd45SJiri Olsa &record_callchain_opt), 84609b0fd45SJiri Olsa OPT_CALLBACK(0, "call-graph", &record.opts, 84775d9a108SArnaldo Carvalho de Melo "mode[,dump_size]", record_callchain_help, 84809b0fd45SJiri Olsa &record_parse_callchain_opt), 849c0555642SIan Munsie OPT_INCR('v', "verbose", &verbose, 8503da297a6SIngo Molnar "be more verbose (show counter open errors, etc)"), 851b44308f5SArnaldo Carvalho de Melo OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 852d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat, 853649c48a9SPeter Zijlstra "per thread counts"), 854d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('d', "data", &record.opts.sample_address, 8554bba828dSAnton Blanchard "Sample addresses"), 856d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"), 8573e76ac78SAndrew Vagin OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"), 858d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, 859649c48a9SPeter Zijlstra "don't sample"), 860d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache, 861a1ac1d3cSStephane Eranian "do not update the buildid cache"), 862d20deb64SArnaldo Carvalho de Melo OPT_BOOLEAN('B', "no-buildid", &record.no_buildid, 863baa2f6ceSArnaldo Carvalho de Melo "do not collect buildids in perf.data"), 864d20deb64SArnaldo Carvalho de Melo OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 865023695d9SStephane Eranian "monitor event in cgroup name only", 866023695d9SStephane Eranian parse_cgroups), 867a6205a35SArnaldo Carvalho de Melo OPT_UINTEGER('D', "delay", &record.opts.initial_delay, 8686619a53eSAndi Kleen "ms to wait before starting measurement after program start"), 869bea03405SNamhyung Kim OPT_STRING('u', "uid", &record.opts.target.uid_str, "user", 870bea03405SNamhyung Kim "user to profile"), 871a5aabdacSStephane Eranian 872a5aabdacSStephane Eranian OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack, 873a5aabdacSStephane Eranian "branch any", "sample any taken branches", 874a5aabdacSStephane Eranian parse_branch_stack), 875a5aabdacSStephane Eranian 876a5aabdacSStephane Eranian OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack, 877a5aabdacSStephane Eranian "branch filter mask", "branch stack filter modes", 878bdfebd84SRoberto Agostino Vitillo parse_branch_stack), 87905484298SAndi Kleen OPT_BOOLEAN('W', "weight", &record.opts.sample_weight, 88005484298SAndi Kleen "sample by weight (on special events only)"), 881475eeab9SAndi Kleen OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction, 882475eeab9SAndi Kleen "sample transaction flags (special events only)"), 8833aa5939dSAdrian Hunter OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread, 8843aa5939dSAdrian Hunter "use per-thread mmaps"), 88586470930SIngo Molnar OPT_END() 88686470930SIngo Molnar }; 88786470930SIngo Molnar 8881d037ca1SIrina Tirdea int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) 88986470930SIngo Molnar { 89069aad6f1SArnaldo Carvalho de Melo int err = -ENOMEM; 8918c6f45a7SArnaldo Carvalho de Melo struct record *rec = &record; 89216ad2ffbSNamhyung Kim char errbuf[BUFSIZ]; 89386470930SIngo Molnar 8943e2be2daSArnaldo Carvalho de Melo rec->evlist = perf_evlist__new(); 8953e2be2daSArnaldo Carvalho de Melo if (rec->evlist == NULL) 896361c99a6SArnaldo Carvalho de Melo return -ENOMEM; 897361c99a6SArnaldo Carvalho de Melo 898eb853e80SJiri Olsa perf_config(perf_record_config, rec); 899eb853e80SJiri Olsa 900bca647aaSTom Zanussi argc = parse_options(argc, argv, record_options, record_usage, 901a0541234SAnton Blanchard PARSE_OPT_STOP_AT_NON_OPTION); 902602ad878SArnaldo Carvalho de Melo if (!argc && target__none(&rec->opts.target)) 903bca647aaSTom Zanussi usage_with_options(record_usage, record_options); 90486470930SIngo Molnar 905bea03405SNamhyung Kim if (nr_cgroups && !rec->opts.target.system_wide) { 9063780f488SNamhyung Kim ui__error("cgroup monitoring only available in" 907023695d9SStephane Eranian " system-wide mode\n"); 908023695d9SStephane Eranian usage_with_options(record_usage, record_options); 909023695d9SStephane Eranian } 910023695d9SStephane Eranian 911*0a7e6d1bSNamhyung Kim symbol__init(NULL); 912baa2f6ceSArnaldo Carvalho de Melo 913ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) 914646aaea6SArnaldo Carvalho de Melo pr_warning( 915646aaea6SArnaldo Carvalho de Melo "WARNING: Kernel address maps (/proc/{kallsyms,modules}) are restricted,\n" 916ec80fde7SArnaldo Carvalho de Melo "check /proc/sys/kernel/kptr_restrict.\n\n" 917646aaea6SArnaldo Carvalho de Melo "Samples in kernel functions may not be resolved if a suitable vmlinux\n" 918646aaea6SArnaldo Carvalho de Melo "file is not found in the buildid cache or in the vmlinux path.\n\n" 919646aaea6SArnaldo Carvalho de Melo "Samples in kernel modules won't be resolved at all.\n\n" 920646aaea6SArnaldo Carvalho de Melo "If some relocation was applied (e.g. kexec) symbols may be misresolved\n" 921646aaea6SArnaldo Carvalho de Melo "even with a suitable vmlinux or kallsyms file.\n\n"); 922ec80fde7SArnaldo Carvalho de Melo 923d20deb64SArnaldo Carvalho de Melo if (rec->no_buildid_cache || rec->no_buildid) 924a1ac1d3cSStephane Eranian disable_buildid_cache(); 925655000e7SArnaldo Carvalho de Melo 9263e2be2daSArnaldo Carvalho de Melo if (rec->evlist->nr_entries == 0 && 9273e2be2daSArnaldo Carvalho de Melo perf_evlist__add_default(rec->evlist) < 0) { 92869aad6f1SArnaldo Carvalho de Melo pr_err("Not enough memory for event selector list\n"); 92969aad6f1SArnaldo Carvalho de Melo goto out_symbol_exit; 930bbd36e5eSPeter Zijlstra } 93186470930SIngo Molnar 93269e7e5b0SAdrian Hunter if (rec->opts.target.tid && !rec->opts.no_inherit_set) 93369e7e5b0SAdrian Hunter rec->opts.no_inherit = true; 93469e7e5b0SAdrian Hunter 935602ad878SArnaldo Carvalho de Melo err = target__validate(&rec->opts.target); 93616ad2ffbSNamhyung Kim if (err) { 937602ad878SArnaldo Carvalho de Melo target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 93816ad2ffbSNamhyung Kim ui__warning("%s", errbuf); 93916ad2ffbSNamhyung Kim } 9404bd0f2d2SNamhyung Kim 941602ad878SArnaldo Carvalho de Melo err = target__parse_uid(&rec->opts.target); 94216ad2ffbSNamhyung Kim if (err) { 94316ad2ffbSNamhyung Kim int saved_errno = errno; 94416ad2ffbSNamhyung Kim 945602ad878SArnaldo Carvalho de Melo target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 9463780f488SNamhyung Kim ui__error("%s", errbuf); 94716ad2ffbSNamhyung Kim 94816ad2ffbSNamhyung Kim err = -saved_errno; 9498fa60e1fSNamhyung Kim goto out_symbol_exit; 95016ad2ffbSNamhyung Kim } 9510d37aa34SArnaldo Carvalho de Melo 95216ad2ffbSNamhyung Kim err = -ENOMEM; 9533e2be2daSArnaldo Carvalho de Melo if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0) 954dd7927f4SArnaldo Carvalho de Melo usage_with_options(record_usage, record_options); 95569aad6f1SArnaldo Carvalho de Melo 956b4006796SArnaldo Carvalho de Melo if (record_opts__config(&rec->opts)) { 95739d17dacSArnaldo Carvalho de Melo err = -EINVAL; 95803ad9747SArnaldo Carvalho de Melo goto out_symbol_exit; 9597e4ff9e3SMike Galbraith } 9607e4ff9e3SMike Galbraith 961d20deb64SArnaldo Carvalho de Melo err = __cmd_record(&record, argc, argv); 962d65a458bSArnaldo Carvalho de Melo out_symbol_exit: 96345604710SNamhyung Kim perf_evlist__delete(rec->evlist); 964d65a458bSArnaldo Carvalho de Melo symbol__exit(); 96539d17dacSArnaldo Carvalho de Melo return err; 96686470930SIngo Molnar } 967