diff options
-rw-r--r-- | tools/perf/builtin-annotate.c | 62 | ||||
-rw-r--r-- | tools/perf/builtin-diff.c | 3 | ||||
-rw-r--r-- | tools/perf/builtin-inject.c | 55 | ||||
-rw-r--r-- | tools/perf/builtin-kmem.c | 3 | ||||
-rw-r--r-- | tools/perf/builtin-lock.c | 3 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 383 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 97 | ||||
-rw-r--r-- | tools/perf/builtin-sched.c | 3 | ||||
-rw-r--r-- | tools/perf/builtin-script.c | 3 | ||||
-rw-r--r-- | tools/perf/builtin-timechart.c | 12 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 6 | ||||
-rw-r--r-- | tools/perf/util/build-id.c | 7 | ||||
-rw-r--r-- | tools/perf/util/callchain.h | 3 | ||||
-rw-r--r-- | tools/perf/util/event.c | 66 | ||||
-rw-r--r-- | tools/perf/util/event.h | 38 | ||||
-rw-r--r-- | tools/perf/util/header.c | 36 | ||||
-rw-r--r-- | tools/perf/util/header.h | 27 | ||||
-rw-r--r-- | tools/perf/util/session.c | 60 | ||||
-rw-r--r-- | tools/perf/util/session.h | 23 | ||||
-rw-r--r-- | tools/perf/util/top.h | 3 |
20 files changed, 520 insertions, 373 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 4f0c3d98352..483cb946644 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -30,7 +30,8 @@ #include <linux/bitmap.h> -static struct perf_annotate { +struct perf_annotate { + struct perf_event_ops ops; char const *input_name; bool force, use_tui, use_stdio; bool full_paths; @@ -38,13 +39,12 @@ static struct perf_annotate { const char *sym_hist_filter; const char *cpu_list; DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); -} annotate = { - .input_name = "perf.data", -}, *ann = &annotate; +}; static int perf_evsel__add_sample(struct perf_evsel *evsel, struct perf_sample *sample, - struct addr_location *al) + struct addr_location *al, + struct perf_annotate *ann) { struct hist_entry *he; int ret; @@ -79,11 +79,13 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, return ret; } -static int process_sample_event(union perf_event *event, +static int process_sample_event(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, struct perf_session *session) { + struct perf_annotate *ann = container_of(ops, struct perf_annotate, ops); struct addr_location al; if (perf_event__preprocess_sample(event, session, &al, sample, @@ -96,7 +98,7 @@ static int process_sample_event(union perf_event *event, if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap)) return 0; - if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al)) { + if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al, ann)) { pr_warning("problem incrementing symbol count, " "skipping event\n"); return -1; @@ -105,13 +107,15 @@ static int process_sample_event(union perf_event *event, return 0; } -static int hist_entry__tty_annotate(struct hist_entry *he, int evidx) +static int hist_entry__tty_annotate(struct hist_entry *he, int evidx, + struct perf_annotate *ann) { return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, ann->print_line, ann->full_paths, 0, 0); } -static void hists__find_annotations(struct hists *self, int evidx) +static void hists__find_annotations(struct hists *self, int evidx, + struct perf_annotate *ann) { struct rb_node *nd = rb_first(&self->entries), *next; int key = K_RIGHT; @@ -149,7 +153,7 @@ find_next: if (next != NULL) nd = next; } else { - hist_entry__tty_annotate(he, evidx); + hist_entry__tty_annotate(he, evidx, ann); nd = rb_next(nd); /* * Since we have a hist_entry per IP for the same @@ -162,16 +166,7 @@ find_next: } } -static struct perf_event_ops event_ops = { - .sample = process_sample_event, - .mmap = perf_event__process_mmap, - .comm = perf_event__process_comm, - .fork = perf_event__process_task, - .ordered_samples = true, - .ordering_requires_timestamps = true, -}; - -static int __cmd_annotate(void) +static int __cmd_annotate(struct perf_annotate *ann) { int ret; struct perf_session *session; @@ -179,7 +174,7 @@ static int __cmd_annotate(void) u64 total_nr_samples; session = perf_session__new(ann->input_name, O_RDONLY, - ann->force, false, &event_ops); + ann->force, false, &ann->ops); if (session == NULL) return -ENOMEM; @@ -190,7 +185,7 @@ static int __cmd_annotate(void) goto out_delete; } - ret = perf_session__process_events(session, &event_ops); + ret = perf_session__process_events(session, &ann->ops); if (ret) goto out_delete; @@ -214,7 +209,7 @@ static int __cmd_annotate(void) total_nr_samples += nr_samples; hists__collapse_resort(hists); hists__output_resort(hists); - hists__find_annotations(hists, pos->idx); + hists__find_annotations(hists, pos->idx, ann); } } @@ -243,7 +238,20 @@ static const char * const annotate_usage[] = { NULL }; -static const struct option options[] = { +int cmd_annotate(int argc, const char **argv, const char *prefix __used) +{ + struct perf_annotate annotate = { + .ops = { + .sample = process_sample_event, + .mmap = perf_event__process_mmap, + .comm = perf_event__process_comm, + .fork = perf_event__process_task, + .ordered_samples = true, + .ordering_requires_timestamps = true, + }, + .input_name = "perf.data", + }; + const struct option options[] = { OPT_STRING('i', "input", &annotate.input_name, "file", "input file name"), OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", @@ -275,10 +283,8 @@ static const struct option options[] = { OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), OPT_END() -}; + }; -int cmd_annotate(int argc, const char **argv, const char *prefix __used) -{ argc = parse_options(argc, argv, options, annotate_usage, 0); if (annotate.use_stdio) @@ -312,5 +318,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) return -1; } - return __cmd_annotate(); + return __cmd_annotate(&annotate); } diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index b39f3a1ee7d..9a0872f9e83 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -30,7 +30,8 @@ static int hists__add_entry(struct hists *self, return -ENOMEM; } -static int diff__process_sample_event(union perf_event *event, +static int diff__process_sample_event(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, struct perf_session *session) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 978751ec64c..6ce6d80b59d 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -16,7 +16,8 @@ static char const *input_name = "-"; static bool inject_build_ids; -static int perf_event__repipe_synth(union perf_event *event, +static int perf_event__repipe_synth(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_session *session __used) { uint32_t size; @@ -36,47 +37,57 @@ static int perf_event__repipe_synth(union perf_event *event, return 0; } +static int perf_event__repipe_tracing_data_synth(union perf_event *event, + struct perf_session *session) +{ + return perf_event__repipe_synth(NULL, event, session); +} + static int perf_event__repipe_attr(union perf_event *event, struct perf_evlist **pevlist __used) { - return perf_event__repipe_synth(event, NULL); + return perf_event__repipe_synth(NULL, event, NULL); } -static int perf_event__repipe(union perf_event *event, +static int perf_event__repipe(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample __used, struct perf_session *session) { - return perf_event__repipe_synth(event, session); + return perf_event__repipe_synth(ops, event, session); } -static int perf_event__repipe_sample(union perf_event *event, +static int perf_event__repipe_sample(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample __used, struct perf_evsel *evsel __used, struct perf_session *session) { - return perf_event__repipe_synth(event, session); + return perf_event__repipe_synth(ops, event, session); } -static int perf_event__repipe_mmap(union perf_event *event, +static int perf_event__repipe_mmap(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample, struct perf_session *session) { int err; - err = perf_event__process_mmap(event, sample, session); - perf_event__repipe(event, sample, session); + err = perf_event__process_mmap(ops, event, sample, session); + perf_event__repipe(ops, event, sample, session); return err; } -static int perf_event__repipe_task(union perf_event *event, +static int perf_event__repipe_task(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample, struct perf_session *session) { int err; - err = perf_event__process_task(event, sample, session); - perf_event__repipe(event, sample, session); + err = perf_event__process_task(ops, event, sample, session); + perf_event__repipe(ops, event, sample, session); return err; } @@ -86,7 +97,7 @@ static int perf_event__repipe_tracing_data(union perf_event *event, { int err; - perf_event__repipe_synth(event, session); + perf_event__repipe_synth(NULL, event, session); err = perf_event__process_tracing_data(event, session); return err; @@ -106,7 +117,8 @@ static int dso__read_build_id(struct dso *self) return -1; } -static int dso__inject_build_id(struct dso *self, struct perf_session *session) +static int dso__inject_build_id(struct dso *self, struct perf_event_ops *ops, + struct perf_session *session) { u16 misc = PERF_RECORD_MISC_USER; struct machine *machine; @@ -126,7 +138,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session) if (self->kernel) misc = PERF_RECORD_MISC_KERNEL; - err = perf_event__synthesize_build_id(self, misc, perf_event__repipe, + err = perf_event__synthesize_build_id(ops, self, misc, perf_event__repipe, machine, session); if (err) { pr_err("Can't synthesize build_id event for %s\n", self->long_name); @@ -136,7 +148,8 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session) return 0; } -static int perf_event__inject_buildid(union perf_event *event, +static int perf_event__inject_buildid(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, struct perf_session *session) @@ -161,7 +174,7 @@ static int perf_event__inject_buildid(union perf_event *event, if (!al.map->dso->hit) { al.map->dso->hit = 1; if (map__load(al.map, NULL) >= 0) { - dso__inject_build_id(al.map->dso, session); + dso__inject_build_id(al.map->dso, ops, session); /* * If this fails, too bad, let the other side * account this as unresolved. @@ -174,7 +187,7 @@ static int perf_event__inject_buildid(union perf_event *event, } repipe: - perf_event__repipe(event, sample, session); + perf_event__repipe(ops, event, sample, session); return 0; } @@ -189,9 +202,9 @@ struct perf_event_ops inject_ops = { .throttle = perf_event__repipe, .unthrottle = perf_event__repipe, .attr = perf_event__repipe_attr, - .event_type = perf_event__repipe_synth, - .tracing_data = perf_event__repipe_synth, - .build_id = perf_event__repipe_synth, + .event_type = perf_event__repipe_synth, + .tracing_data = perf_event__repipe_tracing_data_synth, + .build_id = perf_event__repipe_synth, }; extern volatile int session_done; diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 225e963df10..5d01218e50e 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -303,7 +303,8 @@ static void process_raw_event(union perf_event *raw_event __used, void *data, } } -static int process_sample_event(union perf_event *event, +static int process_sample_event(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, struct perf_session *session) diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 899080ace26..f06b0a44c7c 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -845,7 +845,8 @@ static void dump_info(void) die("Unknown type of information\n"); } -static int process_sample_event(union perf_event *event, +static int process_sample_event(struct perf_event_ops *ops __used, + union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, struct perf_session *s) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ba6777a147c..4642d38b8d1 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -35,43 +35,36 @@ enum write_mode_t { WRITE_APPEND }; -struct perf_record_opts record_opts = { - .target_pid = -1, - .target_tid = -1, - .mmap_pages = UINT_MAX, - .user_freq = UINT_MAX, - .user_interval = ULLONG_MAX, - .freq = 1000, - .sample_id_all_avail = true, +struct perf_record { + struct perf_event_ops ops; + struct perf_record_opts opts; + u64 bytes_written; + const char *output_name; + struct perf_evlist *evlist; + struct perf_session *session; + const char *progname; + int output; + unsigned int page_size; + int realtime_prio; + enum write_mode_t write_mode; + bool no_buildid; + bool no_buildid_cache; + bool force; + bool file_new; + bool append_file; + long samples; + off_t post_processing_offset; }; -static unsigned int page_size; -static int output; -static const char *output_name = NULL; -static int realtime_prio = 0; -static enum write_mode_t write_mode = WRITE_FORCE; -static bool no_buildid = false; -static bool no_buildid_cache = false; -static struct perf_evlist *evsel_list; - -static long samples = 0; -static u64 bytes_written = 0; - -static int file_new = 1; -static off_t post_processing_offset; - -static struct perf_session *session; -static const char *progname; - -static void advance_output(size_t size) +static void advance_output(struct perf_record *rec, size_t size) { - bytes_written += size; + rec->bytes_written += size; } -static void write_output(void *buf, size_t size) +static void write_output(struct perf_record *rec, void *buf, size_t size) { while (size) { - int ret = write(output, buf, size); + int ret = write(rec->output, buf, size); if (ret < 0) die("failed to write"); @@ -79,30 +72,33 @@ static void write_output(void *buf, size_t size) size -= ret; buf += ret; - bytes_written += ret; + rec->bytes_written += ret; } } -static int process_synthesized_event(union perf_event *event, +static int process_synthesized_event(struct perf_event_ops *ops, + union perf_event *event, struct perf_sample *sample __used, struct perf_session *self __used) { - write_output(event, event->header.size); + struct perf_record *rec = container_of(ops, struct perf_record, ops); + write_output(rec, event, event->header.size); return 0; } -static void mmap_read(struct perf_mmap *md) +static void perf_record__mmap_read(struct perf_record *rec, + struct perf_mmap *md) { unsigned int head = perf_mmap__read_head(md); unsigned int old = md->prev; - unsigned char *data = md->base + page_size; + unsigned char *data = md->base + rec->page_size; unsigned long size; void *buf; if (old == head) return; - samples++; + rec->samples++; size = head - old; @@ -111,14 +107,14 @@ static void mmap_read(struct perf_mmap *md) size = md->mask + 1 - (old & md->mask); old += size; - write_output(buf, size); + write_output(rec, buf, size); } buf = &data[old & md->mask]; size = head - old; old += size; - write_output(buf, size); + write_output(rec, buf, size); md->prev = old; perf_mmap__write_tail(md, old); @@ -137,17 +133,18 @@ static void sig_handler(int sig) signr = sig; } -static void sig_atexit(void) +static void perf_record__sig_exit(int exit_status __used, void *arg) { + struct perf_record *rec = arg; int status; - if (evsel_list->workload.pid > 0) { + if (rec->evlist->workload.pid > 0) { if (!child_finished) - kill(evsel_list->workload.pid, SIGTERM); + kill(rec->evlist->workload.pid, SIGTERM); wait(&status); if (WIFSIGNALED(status)) - psignal(WTERMSIG(status), progname); + psignal(WTERMSIG(status), rec->progname); } if (signr == -1 || signr == SIGUSR1) @@ -176,13 +173,16 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, return true; } -static void open_counters(struct perf_evlist *evlist) +static void perf_record__open(struct perf_record *rec) { struct perf_evsel *pos, *first; + struct perf_evlist *evlist = rec->evlist; + struct perf_session *session = rec->session; + struct perf_record_opts *opts = &rec->opts; first = list_entry(evlist->entries.next, struct perf_evsel, node); - perf_evlist__config_attrs(evlist, &record_opts); + perf_evlist__config_attrs(evlist, opts); list_for_each_entry(pos, &evlist->entries, node) { struct perf_event_attr *attr = &pos->attr; @@ -201,27 +201,27 @@ static void open_counters(struct perf_evlist *evlist) */ bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; - if (record_opts.group && pos != first) + if (opts->group && pos != first) group_fd = first->fd; retry_sample_id: - attr->sample_id_all = record_opts.sample_id_all_avail ? 1 : 0; + attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; try_again: if (perf_evsel__open(pos, evlist->cpus, evlist->threads, - record_opts.group, group_fd) < 0) { + opts->group, group_fd) < 0) { int err = errno; if (err == EPERM || err == EACCES) { ui__error_paranoid(); exit(EXIT_FAILURE); - } else if (err == ENODEV && record_opts.cpu_list) { + } else if (err == ENODEV && opts->cpu_list) { die("No such device - did you specify" " an out-of-range profile CPU?\n"); - } else if (err == EINVAL && record_opts.sample_id_all_avail) { + } else if (err == EINVAL && opts->sample_id_all_avail) { /* * Old kernel, no attr->sample_id_type_all field */ - record_opts.sample_id_all_avail = false; - if (!record_opts.sample_time && !record_opts.raw_samples && !time_needed) + opts->sample_id_all_avail = false; + if (!opts->sample_time && !opts->raw_samples && !time_needed) attr->sample_type &= ~PERF_SAMPLE_TIME; goto retry_sample_id; @@ -271,10 +271,10 @@ try_again: exit(-1); } - if (perf_evlist__mmap(evlist, record_opts.mmap_pages, false) < 0) + if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) die("failed to mmap with %d (%s)\n", errno, strerror(errno)); - if (file_new) + if (rec->file_new) session->evlist = evlist; else { if (!perf_evlist__equal(session->evlist, evlist)) { @@ -286,29 +286,32 @@ try_again: perf_session__update_sample_type(session); } -static int process_buildids(void) +static int process_buildids(struct perf_record *rec) { - u64 size = lseek(output, 0, SEEK_CUR); + u64 size = lseek(rec->output, 0, SEEK_CUR); if (size == 0) return 0; - session->fd = output; - return __perf_session__process_events(session, post_processing_offset, - size - post_processing_offset, + rec->session->fd = rec->output; + return __perf_session__process_events(rec->session, rec->post_processing_offset, + size - rec->post_processing_offset, size, &build_id__mark_dso_hit_ops); } -static void atexit_header(void) +static void perf_record__exit(int status __used, void *arg) { - if (!record_opts.pipe_output) { - session->header.data_size += bytes_written; - - if (!no_buildid) - process_buildids(); - perf_session__write_header(session, evsel_list, output, true); - perf_session__delete(session); - perf_evlist__delete(evsel_list); + struct perf_record *rec = arg; + + if (!rec->opts.pipe_output) { + rec->session->header.data_size += rec->bytes_written; + + if (!rec->no_buildid) + process_buildids(rec); + perf_session__write_header(rec->session, rec->evlist, + rec->output, true); + perf_session__delete(rec->session); + perf_evlist__delete(rec->evlist); symbol__exit(); } } @@ -316,7 +319,9 @@ static void atexit_header(void) static void perf_event__synthesize_guest_os(struct machine *machine, void *data) { int err; - struct perf_session *psession = data; + struct perf_event_ops *ops = data; + struct perf_record *rec = container_of(ops, struct perf_record, ops); + struct perf_session *psession = rec->session; if (machine__is_host(machine)) return; @@ -329,7 +334,7 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) *method is used to avoid symbol missing when the first addr is *in module instead of in guest kernel. */ - err = perf_event__synthesize_modules(process_synthesized_event, + err = perf_event__synthesize_modules(ops, process_synthesized_event, psession, machine); if (err < 0) pr_err("Couldn't record guest kernel [%d]'s reference" @@ -339,10 +344,10 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) * We use _stext for guest kernel because guest kernel's /proc/kallsyms * have no _text sometimes. */ - err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, psession, machine, "_text"); if (err < 0) - err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, psession, machine, "_stext"); if (err < 0) @@ -355,66 +360,71 @@ static struct perf_event_header finished_round_event = { .type = PERF_RECORD_FINISHED_ROUND, }; -static void mmap_read_all(void) +static void perf_record__mmap_read_all(struct perf_record *rec) { int i; - for (i = 0; i < evsel_list->nr_mmaps; i++) { - if (evsel_list->mmap[i].base) - mmap_read(&evsel_list->mmap[i]); + for (i = 0; i < rec->evlist->nr_mmaps; i++) { + if (rec->evlist->mmap[i].base) + perf_record__mmap_read(rec, &rec->evlist->mmap[i]); } - if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) - write_output(&finished_round_event, sizeof(finished_round_event)); + if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO)) + write_output(rec, &finished_round_event, sizeof(finished_round_event)); } -static int __cmd_record(int argc, const char **argv) +static int __cmd_record(struct perf_record *rec, int argc, const char **argv) { struct stat st; int flags; - int err; + int err, output; unsigned long waking = 0; const bool forks = argc > 0; struct machine *machine; + struct perf_event_ops *ops = &rec->ops; + struct perf_record_opts *opts = &rec->opts; + struct perf_evlist *evsel_list = rec->evlist; + const char *output_name = rec->output_name; + struct perf_session *session; - progname = argv[0]; + rec->progname = argv[0]; - page_size = sysconf(_SC_PAGE_SIZE); + rec->page_size = sysconf(_SC_PAGE_SIZE); - atexit(sig_atexit); + on_exit(perf_record__sig_exit, rec); signal(SIGCHLD, sig_handler); signal(SIGINT, sig_handler); signal(SIGUSR1, sig_handler); if (!output_name) { if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) - record_opts.pipe_output = true; + opts->pipe_output = true; else - output_name = "perf.data"; + rec->output_name = output_name = "perf.data"; } if (output_name) { if (!strcmp(output_name, "-")) - record_opts.pipe_output = true; + opts->pipe_output = true; else if (!stat(output_name, &st) && st.st_size) { - if (write_mode == WRITE_FORCE) { + if (rec->write_mode == WRITE_FORCE) { char oldname[PATH_MAX]; snprintf(oldname, sizeof(oldname), "%s.old", output_name); unlink(oldname); rename(output_name, oldname); } - } else if (write_mode == WRITE_APPEND) { - write_mode = WRITE_FORCE; + } else if (rec->write_mode == WRITE_APPEND) { + rec->write_mode = WRITE_FORCE; } } flags = O_CREAT|O_RDWR; - if (write_mode == WRITE_APPEND) - file_new = 0; + if (rec->write_mode == WRITE_APPEND) + rec->file_new = 0; else flags |= O_TRUNC; - if (record_opts.pipe_output) + if (opts->pipe_output) output = STDOUT_FILENO; else output = open(output_name, flags, S_IRUSR | S_IWUSR); @@ -423,17 +433,21 @@ static int __cmd_record(int argc, const char **argv) exit(-1); } + rec->output = output; + session = perf_session__new(output_name, O_WRONLY, - write_mode == WRITE_FORCE, false, NULL); + rec->write_mode == WRITE_FORCE, false, NULL); if (session == NULL) { pr_err("Not enough memory for reading perf file header\n"); return -1; } - if (!no_buildid) + rec->session = session; + + if (!rec->no_buildid) perf_header__set_feat(&session->header, HEADER_BUILD_ID); - if (!file_new) { + if (!rec->file_new) { err = perf_session__read_header(session, output); if (err < 0) goto out_delete_session; @@ -456,42 +470,42 @@ static int __cmd_record(int argc, const char **argv) perf_header__set_feat(&session->header, HEADER_CPUID); if (forks) { - err = perf_evlist__prepare_workload(evsel_list, &record_opts, argv); + err = perf_evlist__prepare_workload(evsel_list, opts, argv); if (err < 0) { pr_err("Couldn't run the workload!\n"); goto out_delete_session; } } - open_counters(evsel_list); + perf_record__open(rec); /* - * perf_session__delete(session) will be called at atexit_header() + * perf_session__delete(session) will be called at perf_record__exit() */ - atexit(atexit_header); + on_exit(perf_record__exit, rec); - if (record_opts.pipe_output) { + if (opts->pipe_output) { err = perf_header__write_pipe(output); if (err < 0) return err; - } else if (file_new) { + } else if (rec->file_new) { err = perf_session__write_header(session, evsel_list, output, false); if (err < 0) return err; } - post_processing_offset = lseek(output, 0, SEEK_CUR); + rec->post_processing_offset = lseek(output, 0, SEEK_CUR); - if (record_opts.pipe_output) { - err = perf_session__synthesize_attrs(session, - process_synthesized_event); + if (opts->pipe_output) { + err = perf_event__synthesize_attrs(ops, session, + process_synthesized_event); if (err < 0) { pr_err("Couldn't synthesize attrs.\n"); return err; } - err = perf_event__synthesize_event_types(process_synthesized_event, + err = perf_event__synthesize_event_types(ops, process_synthesized_event, session); if (err < 0) { pr_err("Couldn't synthesize event_types.\n"); @@ -507,14 +521,14 @@ static int __cmd_record(int argc, const char **argv) * return this more properly and also * propagate errors that now are calling die() */ - err = perf_event__synthesize_tracing_data(output, evsel_list, + err = perf_event__synthesize_tracing_data(ops, output, evsel_list, process_synthesized_event, session); if (err <= 0) { pr_err("Couldn't record tracing data.\n"); return err; } - advance_output(err); + advance_output(rec, err); } } @@ -524,17 +538,17 @@ static int __cmd_record(int argc, const char **argv) return -1; } - err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, session, machine, "_text"); if (err < 0) - err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event, session, machine, "_stext"); if (err < 0) pr_err("Couldn't record kernel reference relocation symbol\n" "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" "Check /proc/kallsyms permission or run as root.\n"); - err = perf_event__synthesize_modules(process_synthesized_event, + err = perf_event__synthesize_modules(ops, process_synthesized_event, session, machine); if (err < 0) pr_err("Couldn't record kernel module information.\n" @@ -542,21 +556,21 @@ static int __cmd_record(int argc, const char **argv) "Check /proc/modules permission or run as root.\n"); if (perf_guest) - perf_session__process_machines(session, + perf_session__process_machines(session, ops, perf_event__synthesize_guest_os); - if (!record_opts.system_wide) - perf_event__synthesize_thread_map(evsel_list->threads, + if (!opts->system_wide) + perf_event__synthesize_thread_map(ops, evsel_list->threads, process_synthesized_event, session); else - perf_event__synthesize_threads(process_synthesized_event, + perf_event__synthesize_threads(ops, process_synthesized_event, session); - if (realtime_prio) { + if (rec->realtime_prio) { struct sched_param param; - param.sched_priority = realtime_prio; + param.sched_priority = rec->realtime_prio; if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { pr_err("Could not set realtime priority.\n"); exit(-1); @@ -572,11 +586,11 @@ static int __cmd_record(int argc, const char **argv) perf_evlist__start_workload(evsel_list); for (;;) { - int hits = samples; + int hits = rec->samples; - mmap_read_all(); + perf_record__mmap_read_all(rec); - if (hits == samples) { + if (hits == rec->samples) { if (done) break; err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); @@ -597,9 +611,9 @@ static int __cmd_record(int argc, const char **argv) */ fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", - (double)bytes_written / 1024.0 / 1024.0, + (double)rec->bytes_written / 1024.0 / 1024.0, output_name, - bytes_written / 24); + rec->bytes_written / 24); return 0; @@ -614,59 +628,88 @@ static const char * const record_usage[] = { NULL }; -static bool force, append_file; +/* + * XXX Ideally would be local to cmd_record() and passed to a perf_record__new + * because we need to have access to it in perf_record__exit, that is called + * after cmd_record() exits, but since record_options need to be accessible to + * builtin-script, leave it here. + * + * At least we don't ouch it in all the other functions here directly. + * + * Just say no to tons of global variables, sigh. + */ +static struct perf_record record = { + .opts = { + .target_pid = -1, + .target_tid = -1, + .mmap_pages = UINT_MAX, + .user_freq = UINT_MAX, + .user_interval = ULLONG_MAX, + .freq = 1000, + .sample_id_all_avail = true, + }, + .write_mode = WRITE_FORCE, + .file_new = true, +}; +/* + * XXX Will stay a global variable till we fix builtin-script.c to stop messing + * with it and switch to use the library functions in perf_evlist that came + * from builtin-record.c, i.e. use perf_record_opts, + * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', + * using pipes, etc. + */ const struct optio |