perf tools: Pass tool context in the the perf_event_ops functions

So that we don't need to have that many globals.

Next steps will remove the 'session' pointer, that in most cases is
not needed.

Then we can rename perf_event_ops to 'perf_tool' that better describes
this class hierarchy.

Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-wp4djox7x6w1i2bab1pt4xxp@git.kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 7009cc34
...@@ -30,7 +30,8 @@ ...@@ -30,7 +30,8 @@
#include <linux/bitmap.h> #include <linux/bitmap.h>
static struct perf_annotate { struct perf_annotate {
struct perf_event_ops ops;
char const *input_name; char const *input_name;
bool force, use_tui, use_stdio; bool force, use_tui, use_stdio;
bool full_paths; bool full_paths;
...@@ -38,13 +39,12 @@ static struct perf_annotate { ...@@ -38,13 +39,12 @@ static struct perf_annotate {
const char *sym_hist_filter; const char *sym_hist_filter;
const char *cpu_list; const char *cpu_list;
DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
} annotate = { };
.input_name = "perf.data",
}, *ann = &annotate;
static int perf_evsel__add_sample(struct perf_evsel *evsel, static int perf_evsel__add_sample(struct perf_evsel *evsel,
struct perf_sample *sample, struct perf_sample *sample,
struct addr_location *al) struct addr_location *al,
struct perf_annotate *ann)
{ {
struct hist_entry *he; struct hist_entry *he;
int ret; int ret;
...@@ -79,11 +79,13 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, ...@@ -79,11 +79,13 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
return ret; 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_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct perf_session *session) struct perf_session *session)
{ {
struct perf_annotate *ann = container_of(ops, struct perf_annotate, ops);
struct addr_location al; struct addr_location al;
if (perf_event__preprocess_sample(event, session, &al, sample, if (perf_event__preprocess_sample(event, session, &al, sample,
...@@ -96,7 +98,7 @@ static int process_sample_event(union perf_event *event, ...@@ -96,7 +98,7 @@ static int process_sample_event(union perf_event *event,
if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap)) if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap))
return 0; 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, " pr_warning("problem incrementing symbol count, "
"skipping event\n"); "skipping event\n");
return -1; return -1;
...@@ -105,13 +107,15 @@ static int process_sample_event(union perf_event *event, ...@@ -105,13 +107,15 @@ static int process_sample_event(union perf_event *event,
return 0; 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, return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
ann->print_line, ann->full_paths, 0, 0); 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; struct rb_node *nd = rb_first(&self->entries), *next;
int key = K_RIGHT; int key = K_RIGHT;
...@@ -149,7 +153,7 @@ static void hists__find_annotations(struct hists *self, int evidx) ...@@ -149,7 +153,7 @@ static void hists__find_annotations(struct hists *self, int evidx)
if (next != NULL) if (next != NULL)
nd = next; nd = next;
} else { } else {
hist_entry__tty_annotate(he, evidx); hist_entry__tty_annotate(he, evidx, ann);
nd = rb_next(nd); nd = rb_next(nd);
/* /*
* Since we have a hist_entry per IP for the same * Since we have a hist_entry per IP for the same
...@@ -162,16 +166,7 @@ static void hists__find_annotations(struct hists *self, int evidx) ...@@ -162,16 +166,7 @@ static void hists__find_annotations(struct hists *self, int evidx)
} }
} }
static struct perf_event_ops event_ops = { static int __cmd_annotate(struct perf_annotate *ann)
.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)
{ {
int ret; int ret;
struct perf_session *session; struct perf_session *session;
...@@ -179,7 +174,7 @@ static int __cmd_annotate(void) ...@@ -179,7 +174,7 @@ static int __cmd_annotate(void)
u64 total_nr_samples; u64 total_nr_samples;
session = perf_session__new(ann->input_name, O_RDONLY, session = perf_session__new(ann->input_name, O_RDONLY,
ann->force, false, &event_ops); ann->force, false, &ann->ops);
if (session == NULL) if (session == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -190,7 +185,7 @@ static int __cmd_annotate(void) ...@@ -190,7 +185,7 @@ static int __cmd_annotate(void)
goto out_delete; goto out_delete;
} }
ret = perf_session__process_events(session, &event_ops); ret = perf_session__process_events(session, &ann->ops);
if (ret) if (ret)
goto out_delete; goto out_delete;
...@@ -214,7 +209,7 @@ static int __cmd_annotate(void) ...@@ -214,7 +209,7 @@ static int __cmd_annotate(void)
total_nr_samples += nr_samples; total_nr_samples += nr_samples;
hists__collapse_resort(hists); hists__collapse_resort(hists);
hists__output_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[] = { ...@@ -243,7 +238,20 @@ static const char * const annotate_usage[] = {
NULL 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", OPT_STRING('i', "input", &annotate.input_name, "file",
"input file name"), "input file name"),
OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
...@@ -275,10 +283,8 @@ static const struct option options[] = { ...@@ -275,10 +283,8 @@ static const struct option options[] = {
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
"Specify disassembler style (e.g. -M intel for intel syntax)"), "Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_END() OPT_END()
}; };
int cmd_annotate(int argc, const char **argv, const char *prefix __used)
{
argc = parse_options(argc, argv, options, annotate_usage, 0); argc = parse_options(argc, argv, options, annotate_usage, 0);
if (annotate.use_stdio) if (annotate.use_stdio)
...@@ -312,5 +318,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) ...@@ -312,5 +318,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
return -1; return -1;
} }
return __cmd_annotate(); return __cmd_annotate(&annotate);
} }
...@@ -30,7 +30,8 @@ static int hists__add_entry(struct hists *self, ...@@ -30,7 +30,8 @@ static int hists__add_entry(struct hists *self,
return -ENOMEM; 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_sample *sample,
struct perf_evsel *evsel __used, struct perf_evsel *evsel __used,
struct perf_session *session) struct perf_session *session)
......
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
static char const *input_name = "-"; static char const *input_name = "-";
static bool inject_build_ids; 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) struct perf_session *session __used)
{ {
uint32_t size; uint32_t size;
...@@ -36,47 +37,57 @@ static int perf_event__repipe_synth(union perf_event *event, ...@@ -36,47 +37,57 @@ static int perf_event__repipe_synth(union perf_event *event,
return 0; 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, static int perf_event__repipe_attr(union perf_event *event,
struct perf_evlist **pevlist __used) 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_sample *sample __used,
struct perf_session *session) 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_sample *sample __used,
struct perf_evsel *evsel __used, struct perf_evsel *evsel __used,
struct perf_session *session) 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_sample *sample,
struct perf_session *session) struct perf_session *session)
{ {
int err; int err;
err = perf_event__process_mmap(event, sample, session); err = perf_event__process_mmap(ops, event, sample, session);
perf_event__repipe(event, sample, session); perf_event__repipe(ops, event, sample, session);
return err; 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_sample *sample,
struct perf_session *session) struct perf_session *session)
{ {
int err; int err;
err = perf_event__process_task(event, sample, session); err = perf_event__process_task(ops, event, sample, session);
perf_event__repipe(event, sample, session); perf_event__repipe(ops, event, sample, session);
return err; return err;
} }
...@@ -86,7 +97,7 @@ static int perf_event__repipe_tracing_data(union perf_event *event, ...@@ -86,7 +97,7 @@ static int perf_event__repipe_tracing_data(union perf_event *event,
{ {
int err; int err;
perf_event__repipe_synth(event, session); perf_event__repipe_synth(NULL, event, session);
err = perf_event__process_tracing_data(event, session); err = perf_event__process_tracing_data(event, session);
return err; return err;
...@@ -106,7 +117,8 @@ static int dso__read_build_id(struct dso *self) ...@@ -106,7 +117,8 @@ static int dso__read_build_id(struct dso *self)
return -1; 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; u16 misc = PERF_RECORD_MISC_USER;
struct machine *machine; struct machine *machine;
...@@ -126,7 +138,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session) ...@@ -126,7 +138,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
if (self->kernel) if (self->kernel)
misc = PERF_RECORD_MISC_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); machine, session);
if (err) { if (err) {
pr_err("Can't synthesize build_id event for %s\n", self->long_name); 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) ...@@ -136,7 +148,8 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
return 0; 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_sample *sample,
struct perf_evsel *evsel __used, struct perf_evsel *evsel __used,
struct perf_session *session) struct perf_session *session)
...@@ -161,7 +174,7 @@ static int perf_event__inject_buildid(union perf_event *event, ...@@ -161,7 +174,7 @@ static int perf_event__inject_buildid(union perf_event *event,
if (!al.map->dso->hit) { if (!al.map->dso->hit) {
al.map->dso->hit = 1; al.map->dso->hit = 1;
if (map__load(al.map, NULL) >= 0) { 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 * If this fails, too bad, let the other side
* account this as unresolved. * account this as unresolved.
...@@ -174,7 +187,7 @@ static int perf_event__inject_buildid(union perf_event *event, ...@@ -174,7 +187,7 @@ static int perf_event__inject_buildid(union perf_event *event,
} }
repipe: repipe:
perf_event__repipe(event, sample, session); perf_event__repipe(ops, event, sample, session);
return 0; return 0;
} }
...@@ -190,7 +203,7 @@ struct perf_event_ops inject_ops = { ...@@ -190,7 +203,7 @@ struct perf_event_ops inject_ops = {
.unthrottle = perf_event__repipe, .unthrottle = perf_event__repipe,
.attr = perf_event__repipe_attr, .attr = perf_event__repipe_attr,
.event_type = perf_event__repipe_synth, .event_type = perf_event__repipe_synth,
.tracing_data = perf_event__repipe_synth, .tracing_data = perf_event__repipe_tracing_data_synth,
.build_id = perf_event__repipe_synth, .build_id = perf_event__repipe_synth,
}; };
......
...@@ -303,7 +303,8 @@ static void process_raw_event(union perf_event *raw_event __used, void *data, ...@@ -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_sample *sample,
struct perf_evsel *evsel __used, struct perf_evsel *evsel __used,
struct perf_session *session) struct perf_session *session)
......
...@@ -845,7 +845,8 @@ static void dump_info(void) ...@@ -845,7 +845,8 @@ static void dump_info(void)
die("Unknown type of information\n"); 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_sample *sample,
struct perf_evsel *evsel __used, struct perf_evsel *evsel __used,
struct perf_session *s) struct perf_session *s)
......
...@@ -35,43 +35,36 @@ enum write_mode_t { ...@@ -35,43 +35,36 @@ enum write_mode_t {
WRITE_APPEND WRITE_APPEND
}; };
struct perf_record_opts record_opts = { struct perf_record {
.target_pid = -1, struct perf_event_ops ops;
.target_tid = -1, struct perf_record_opts opts;
.mmap_pages = UINT_MAX, u64 bytes_written;
.user_freq = UINT_MAX, const char *output_name;
.user_interval = ULLONG_MAX, struct perf_evlist *evlist;
.freq = 1000, struct perf_session *session;
.sample_id_all_avail = true, 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 void advance_output(struct perf_record *rec, size_t 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)
{ {
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) { while (size) {
int ret = write(output, buf, size); int ret = write(rec->output, buf, size);
if (ret < 0) if (ret < 0)
die("failed to write"); die("failed to write");
...@@ -79,30 +72,33 @@ static void write_output(void *buf, size_t size) ...@@ -79,30 +72,33 @@ static void write_output(void *buf, size_t size)
size -= ret; size -= ret;
buf += 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_sample *sample __used,
struct perf_session *self __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; 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 head = perf_mmap__read_head(md);
unsigned int old = md->prev; unsigned int old = md->prev;
unsigned char *data = md->base + page_size; unsigned char *data = md->base + rec->page_size;
unsigned long size; unsigned long size;
void *buf; void *buf;
if (old == head) if (old == head)
return; return;
samples++; rec->samples++;
size = head - old; size = head - old;
...@@ -111,14 +107,14 @@ static void mmap_read(struct perf_mmap *md) ...@@ -111,14 +107,14 @@ static void mmap_read(struct perf_mmap *md)
size = md->mask + 1 - (old & md->mask); size = md->mask + 1 - (old & md->mask);
old += size; old += size;
write_output(buf, size); write_output(rec, buf, size);
} }
buf = &data[old & md->mask]; buf = &data[old & md->mask];
size = head - old; size = head - old;
old += size; old += size;
write_output(buf, size); write_output(rec, buf, size);
md->prev = old; md->prev = old;
perf_mmap__write_tail(md, old); perf_mmap__write_tail(md, old);
...@@ -137,17 +133,18 @@ static void sig_handler(int sig) ...@@ -137,17 +133,18 @@ static void sig_handler(int sig)
signr = 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; int status;
if (evsel_list->workload.pid > 0) { if (rec->evlist->workload.pid > 0) {
if (!child_finished) if (!child_finished)
kill(evsel_list->workload.pid, SIGTERM); kill(rec->evlist->workload.pid, SIGTERM);
wait(&status); wait(&status);
if (WIFSIGNALED(status)) if (WIFSIGNALED(status))
psignal(WTERMSIG(status), progname); psignal(WTERMSIG(status), rec->progname);
} }
if (signr == -1 || signr == SIGUSR1) if (signr == -1 || signr == SIGUSR1)
...@@ -176,13 +173,16 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, ...@@ -176,13 +173,16 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
return true; 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_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); 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) { list_for_each_entry(pos, &evlist->entries, node) {
struct perf_event_attr *attr = &pos->attr; struct perf_event_attr *attr = &pos->attr;
...@@ -201,27 +201,27 @@ static void open_counters(struct perf_evlist *evlist) ...@@ -201,27 +201,27 @@ static void open_counters(struct perf_evlist *evlist)
*/ */
bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
if (record_opts.group && pos != first) if (opts->group && pos != first)
group_fd = first->fd; group_fd = first->fd;
retry_sample_id: 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: try_again:
if (perf_evsel__open(pos, evlist->cpus, evlist->threads, if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
record_opts.group, group_fd) < 0) { opts->group, group_fd) < 0) {
int err = errno; int err = errno;
if (err == EPERM || err == EACCES) { if (err == EPERM || err == EACCES) {
ui__error_paranoid(); ui__error_paranoid();
exit(EXIT_FAILURE); 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" die("No such device - did you specify"
" an out-of-range profile CPU?\n"); " 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 * Old kernel, no attr->sample_id_type_all field
*/ */
record_opts.sample_id_all_avail = false; opts->sample_id_all_avail = false;
if (!record_opts.sample_time && !record_opts.raw_samples && !time_needed) if (!opts->sample_time && !opts->raw_samples && !time_needed)
attr->sample_type &= ~PERF_SAMPLE_TIME; attr->sample_type &= ~PERF_SAMPLE_TIME;
goto retry_sample_id; goto retry_sample_id;
...@@ -271,10 +271,10 @@ static void open_counters(struct perf_evlist *evlist) ...@@ -271,10 +271,10 @@ static void open_counters(struct perf_evlist *evlist)
exit(-1); 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)); die("failed to mmap with %d (%s)\n", errno, strerror(errno));
if (file_new) if (rec->file_new)
session->evlist = evlist; session->evlist = evlist;
else { else {
if (!perf_evlist__equal(session->evlist, evlist)) { if (!perf_evlist__equal(session->evlist, evlist)) {
...@@ -286,29 +286,32 @@ static void open_counters(struct perf_evlist *evlist) ...@@ -286,29 +286,32 @@ static void open_counters(struct perf_evlist *evlist)
perf_session__update_sample_type(session); 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) if (size == 0)
return 0; return 0;
session->fd = output; rec->session->fd = rec->output;
return __perf_session__process_events(session, post_processing_offset, return __perf_session__process_events(rec->session, rec->post_processing_offset,
size - post_processing_offset, size - rec->post_processing_offset,
size, &build_id__mark_dso_hit_ops); 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) { struct perf_record *rec = arg;
session->header.data_size += bytes_written;
if (!no_buildid) if (!rec->opts.pipe_output) {
process_buildids(); rec->session->header.data_size += rec->bytes_written;
perf_session__write_header(session, evsel_list, output, true);
perf_session__delete(session); if (!rec->no_buildid)
perf_evlist__delete(evsel_list); 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(); symbol__exit();
} }
} }
...@@ -316,7 +319,9 @@ static void atexit_header(void) ...@@ -316,7 +319,9 @@ static void atexit_header(void)
static void perf_event__synthesize_guest_os(struct machine *machine, void *data) static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
{ {
int err; 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)) if (machine__is_host(machine))
return; return;
...@@ -329,7 +334,7 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) ...@@ -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 *method is used to avoid symbol missing when the first addr is
*in module instead of in guest kernel. *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); psession, machine);
if (err < 0) if (err < 0)
pr_err("Couldn't record guest kernel [%d]'s reference" 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) ...@@ -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 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
* have no _text sometimes. * 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"); psession, machine, "_text");
if (err < 0) if (err < 0)
err = perf_event__synthesize_kernel_mmap(process_synthesized_event, err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
psession, machine, psession, machine,
"_stext"); "_stext");
if (err < 0) if (err < 0)
...@@ -355,66 +360,71 @@ static struct perf_event_header finished_round_event = { ...@@ -355,66 +360,71 @@ static struct perf_event_header finished_round_event = {
.type = PERF_RECORD_FINISHED_ROUND, .type = PERF_RECORD_FINISHED_ROUND,
}; };
static void mmap_read_all(void) static void perf_record__mmap_read_all(struct perf_record *rec)
{ {
int i; int i;
for (i = 0; i < evsel_list->nr_mmaps; i++) { for (i = 0; i < rec->evlist->nr_mmaps; i++) {
if (evsel_list->mmap[i].base) if (rec->evlist->mmap[i].base)
mmap_read(&evsel_list->mmap[i]); perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
} }
if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
write_output(&finished_round_event, sizeof(finished_round_event)); 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; struct stat st;
int flags; int flags;
int err; int err, output;
unsigned long waking = 0; unsigned long waking = 0;
const bool forks = argc > 0; const bool forks = argc > 0;
struct machine *machine; 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(SIGCHLD, sig_handler);
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
signal(SIGUSR1, sig_handler); signal(SIGUSR1, sig_handler);
if (!output_name) { if (!output_name) {
if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
record_opts.pipe_output = true; opts->pipe_output = true;
else else
output_name = "perf.data"; rec->output_name = output_name = "perf.data";
} }
if (output_name) { if (output_name) {
if (!strcmp(output_name, "-")) if (!strcmp(output_name, "-"))
record_opts.pipe_output = true; opts->pipe_output = true;
else if (!stat(output_name, &st) && st.st_size) { else if (!stat(output_name, &st) && st.st_size) {
if (write_mode == WRITE_FORCE) { if (rec->write_mode == WRITE_FORCE) {
char oldname[PATH_MAX]; char oldname[PATH_MAX];
snprintf(oldname, sizeof(oldname), "%s.old", snprintf(oldname, sizeof(oldname), "%s.old",
output_name); output_name);
unlink(oldname); unlink(oldname);
rename(output_name, oldname); rename(output_name, oldname);
} }
} else if (write_mode == WRITE_APPEND) { } else if (rec->write_mode == WRITE_APPEND) {
write_mode = WRITE_FORCE; rec->write_mode = WRITE_FORCE;
} }
} }
flags = O_CREAT|O_RDWR; flags = O_CREAT|O_RDWR;
if (write_mode == WRITE_APPEND) if (rec->write_mode == WRITE_APPEND)
file_new = 0; rec->file_new = 0;
else else
flags |= O_TRUNC; flags |= O_TRUNC;
if (record_opts.pipe_output) if (opts->pipe_output)
output = STDOUT_FILENO; output = STDOUT_FILENO;
else else
output = open(output_name, flags, S_IRUSR | S_IWUSR); output = open(output_name, flags, S_IRUSR | S_IWUSR);
...@@ -423,17 +433,21 @@ static int __cmd_record(int argc, const char **argv) ...@@ -423,17 +433,21 @@ static int __cmd_record(int argc, const char **argv)
exit(-1); exit(-1);
} }
rec->output = output;
session = perf_session__new(output_name, O_WRONLY, session = perf_session__new(output_name, O_WRONLY,
write_mode == WRITE_FORCE, false, NULL); rec->write_mode == WRITE_FORCE, false, NULL);
if (session == NULL) { if (session == NULL) {
pr_err("Not enough memory for reading perf file header\n"); pr_err("Not enough memory for reading perf file header\n");
return -1; return -1;
} }
if (!no_buildid) rec->session = session;
if (!rec->no_buildid)
perf_header__set_feat(&session->header, HEADER_BUILD_ID); perf_header__set_feat(&session->header, HEADER_BUILD_ID);
if (!file_new) { if (!rec->file_new) {
err = perf_session__read_header(session, output); err = perf_session__read_header(session, output);
if (err < 0) if (err < 0)
goto out_delete_session; goto out_delete_session;
...@@ -456,42 +470,42 @@ static int __cmd_record(int argc, const char **argv) ...@@ -456,42 +470,42 @@ static int __cmd_record(int argc, const char **argv)
perf_header__set_feat(&session->header, HEADER_CPUID); perf_header__set_feat(&session->header, HEADER_CPUID);
if (forks) { if (forks) {
err = perf_evlist__prepare_workload(evsel_list, &record_opts, argv); err = perf_evlist__prepare_workload(evsel_list, opts, argv);
if (err < 0) { if (err < 0) {
pr_err("Couldn't run the workload!\n"); pr_err("Couldn't run the workload!\n");
goto out_delete_session; 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); err = perf_header__write_pipe(output);
if (err < 0) if (err < 0)
return err; return err;
} else if (file_new) { } else if (rec->file_new) {
err = perf_session__write_header(session, evsel_list, err = perf_session__write_header(session, evsel_list,
output, false); output, false);
if (err < 0) if (err < 0)
return err; return err;
} }
post_processing_offset = lseek(output, 0, SEEK_CUR); rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
if (record_opts.pipe_output) { if (opts->pipe_output) {
err = perf_session__synthesize_attrs(session, err = perf_event__synthesize_attrs(ops, session,
process_synthesized_event); process_synthesized_event);
if (err < 0) { if (err < 0) {
pr_err("Couldn't synthesize attrs.\n"); pr_err("Couldn't synthesize attrs.\n");
return err; return err;
} }
err = perf_event__synthesize_event_types(process_synthesized_event, err = perf_event__synthesize_event_types(ops, process_synthesized_event,
session); session);
if (err < 0) { if (err < 0) {
pr_err("Couldn't synthesize event_types.\n"); pr_err("Couldn't synthesize event_types.\n");
...@@ -507,14 +521,14 @@ static int __cmd_record(int argc, const char **argv) ...@@ -507,14 +521,14 @@ static int __cmd_record(int argc, const char **argv)
* return this more properly and also * return this more properly and also
* propagate errors that now are calling die() * 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, process_synthesized_event,
session); session);
if (err <= 0) { if (err <= 0) {
pr_err("Couldn't record tracing data.\n"); pr_err("Couldn't record tracing data.\n");
return err; return err;
} }
advance_output(err); advance_output(rec, err);
} }
} }
...@@ -524,17 +538,17 @@ static int __cmd_record(int argc, const char **argv) ...@@ -524,17 +538,17 @@ static int __cmd_record(int argc, const char **argv)
return -1; return -1;
} }
err = perf_event__synthesize_kernel_mmap(process_synthesized_event, err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
session, machine, "_text"); session, machine, "_text");
if (err < 0) 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"); session, machine, "_stext");
if (err < 0) if (err < 0)
pr_err("Couldn't record kernel reference relocation symbol\n" pr_err("Couldn't record kernel reference relocation symbol\n"
"Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
"Check /proc/kallsyms permission or run as root.\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); session, machine);
if (err < 0) if (err < 0)
pr_err("Couldn't record kernel module information.\n" pr_err("Couldn't record kernel module information.\n"
...@@ -542,21 +556,21 @@ static int __cmd_record(int argc, const char **argv) ...@@ -542,21 +556,21 @@ static int __cmd_record(int argc, const char **argv)
"Check /proc/modules permission or run as root.\n"); "Check /proc/modules permission or run as root.\n");
if (perf_guest) if (perf_guest)
perf_session__process_machines(session, perf_session__process_machines(session, ops,
perf_event__synthesize_guest_os); perf_event__synthesize_guest_os);
if (!record_opts.system_wide) if (!opts->system_wide)
perf_event__synthesize_thread_map(evsel_list->threads, perf_event__synthesize_thread_map(ops, evsel_list->threads,
process_synthesized_event, process_synthesized_event,
session); session);
else else
perf_event__synthesize_threads(process_synthesized_event, perf_event__synthesize_threads(ops, process_synthesized_event,
session); session);
if (realtime_prio) { if (rec->realtime_prio) {
struct sched_param param; struct sched_param param;
param.sched_priority = realtime_prio; param.sched_priority = rec->realtime_prio;
if (sched_setscheduler(0, SCHED_FIFO, &param)) { if (sched_setscheduler(0, SCHED_FIFO, &param)) {
pr_err("Could not set realtime priority.\n"); pr_err("Could not set realtime priority.\n");
exit(-1); exit(-1);
...@@ -572,11 +586,11 @@ static int __cmd_record(int argc, const char **argv) ...@@ -572,11 +586,11 @@ static int __cmd_record(int argc, const char **argv)
perf_evlist__start_workload(evsel_list); perf_evlist__start_workload(evsel_list);
for (;;) { 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) if (done)
break; break;
err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
...@@ -597,9 +611,9 @@ static int __cmd_record(int argc, const char **argv) ...@@ -597,9 +611,9 @@ static int __cmd_record(int argc, const char **argv)
*/ */
fprintf(stderr, fprintf(stderr,
"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", "[ 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, output_name,
bytes_written / 24); rec->bytes_written / 24);
return 0; return 0;
...@@ -614,59 +628,88 @@ static const char * const record_usage[] = { ...@@ -614,59 +628,88 @@ static const char * const record_usage[] = {
NULL 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 option record_options[] = { const struct option record_options[] = {
OPT_CALLBACK('e', "event", &evsel_list, "event", OPT_CALLBACK('e', "event", &record.evlist, "event",
"event selector. use 'perf list' to list available events", "event selector. use 'perf list' to list available events",
parse_events_option), parse_events_option),
OPT_CALLBACK(0, "filter", &evsel_list, "filter", OPT_CALLBACK(0, "filter", &record.evlist, "filter",
"event filter", parse_filter), "event filter", parse_filter),
OPT_INTEGER('p', "pid", &record_opts.target_pid, OPT_INTEGER('p', "pid", &record.opts.target_pid,
"record events on existing process id"), "record events on existing process id"),
OPT_INTEGER('t', "tid", &record_opts.target_tid, OPT_INTEGER('t', "tid", &record.opts.target_tid,
"record events on existing thread id"), "record events on existing thread id"),
OPT_INTEGER('r', "realtime", &realtime_prio, OPT_INTEGER('r', "realtime", &record.realtime_prio,
"collect data with this RT SCHED_FIFO priority"), "collect data with this RT SCHED_FIFO priority"),
OPT_BOOLEAN('D', "no-delay", &record_opts.no_delay, OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
"collect data without buffering"), "collect data without buffering"),
OPT_BOOLEAN('R', "raw-samples", &record_opts.raw_samples, OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
"collect raw sample records from all opened counters"), "collect raw sample records from all opened counters"),
OPT_BOOLEAN('a', "all-cpus", &record_opts.system_wide, OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
"system-wide collection from all CPUs"), "system-wide collection from all CPUs"),
OPT_BOOLEAN('A', "append", &append_file, OPT_BOOLEAN('A', "append", &record.append_file,
"append to the output file to do incremental profiling"), "append to the output file to do incremental profiling"),
OPT_STRING('C', "cpu", &record_opts.cpu_list, "cpu", OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
"list of cpus to monitor"), "list of cpus to monitor"),
OPT_BOOLEAN('f', "force", &force, OPT_BOOLEAN('f', "force", &record.force,
"overwrite existing data file (deprecated)"), "overwrite existing data file (deprecated)"),
OPT_U64('c', "count", &record_opts.user_interval, "event period to sample"), OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
OPT_STRING('o', "output", &output_name, "file", OPT_STRING('o', "output", &record.output_name, "file",
"output file name"), "output file name"),
OPT_BOOLEAN('i', "no-inherit", &record_opts.no_inherit, OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
"child tasks do not inherit counters"), "child tasks do not inherit counters"),
OPT_UINTEGER('F', "freq", &record_opts.user_freq, "profile at this frequency"), OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
OPT_UINTEGER('m', "mmap-pages", &record_opts.mmap_pages, OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
"number of mmap data pages"), "number of mmap data pages"),
OPT_BOOLEAN(0, "group", &record_opts.group, OPT_BOOLEAN(0, "group", &record.opts.group,
"put the counters into a counter group"), "put the counters into a counter group"),
OPT_BOOLEAN('g', "call-graph", &record_opts.call_graph, OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
"do call-graph (stack chain/backtrace) recording"), "do call-graph (stack chain/backtrace) recording"),
OPT_INCR('v', "verbose", &verbose, OPT_INCR('v', "verbose", &verbose,
"be more verbose (show counter open errors, etc)"), "be more verbose (show counter open errors, etc)"),
OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
OPT_BOOLEAN('s', "stat", &record_opts.inherit_stat, OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
"per thread counts"), "per thread counts"),
OPT_BOOLEAN('d', "data", &record_opts.sample_address, OPT_BOOLEAN('d', "data", &record.opts.sample_address,
"Sample addresses"), "Sample addresses"),
OPT_BOOLEAN('T', "timestamp", &record_opts.sample_time, "Sample timestamps"), OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
OPT_BOOLEAN('n', "no-samples", &record_opts.no_samples, OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
"don't sample"), "don't sample"),
OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache, OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
"do not update the buildid cache"), "do not update the buildid cache"),
OPT_BOOLEAN('B', "no-buildid", &no_buildid, OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
"do not collect buildids in perf.data"), "do not collect buildids in perf.data"),
OPT_CALLBACK('G', "cgroup", &evsel_list, "name", OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
"monitor event in cgroup name only", "monitor event in cgroup name only",
parse_cgroups), parse_cgroups),
OPT_END() OPT_END()
...@@ -676,6 +719,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) ...@@ -676,6 +719,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
{ {
int err = -ENOMEM; int err = -ENOMEM;
struct perf_evsel *pos; struct perf_evsel *pos;
struct perf_evlist *evsel_list;
struct perf_record *rec = &record;
perf_header__set_cmdline(argc, argv); perf_header__set_cmdline(argc, argv);
...@@ -683,23 +728,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) ...@@ -683,23 +728,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
if (evsel_list == NULL) if (evsel_list == NULL)
return -ENOMEM; return -ENOMEM;
rec->evlist = evsel_list;
argc = parse_options(argc, argv, record_options, record_usage, argc = parse_options(argc, argv, record_options, record_usage,
PARSE_OPT_STOP_AT_NON_OPTION); PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc && record_opts.target_pid == -1 && record_opts.target_tid == -1 && if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
!record_opts.system_wide && !record_opts.cpu_list) !rec->opts.system_wide && !rec->opts.cpu_list)
usage_with_options(record_usage, record_options); usage_with_options(record_usage, record_options);
if (force && append_file) { if (rec->force && rec->append_file) {
fprintf(stderr, "Can't overwrite and append at the same time." fprintf(stderr, "Can't overwrite and append at the same time."
" You need to choose between -f and -A"); " You need to choose between -f and -A");
usage_with_options(record_usage, record_options); usage_with_options(record_usage, record_options);
} else if (append_file) { } else if (rec->append_file) {
write_mode = WRITE_APPEND; rec->write_mode = WRITE_APPEND;
} else { } else {
write_mode = WRITE_FORCE; rec->write_mode = WRITE_FORCE;
} }
if (nr_cgroups && !record_opts.system_wide) { if (nr_cgroups && !rec->opts.system_wide) {
fprintf(stderr, "cgroup monitoring only available in" fprintf(stderr, "cgroup monitoring only available in"
" system-wide mode\n"); " system-wide mode\n");
usage_with_options(record_usage, record_options); usage_with_options(record_usage, record_options);
...@@ -717,7 +764,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) ...@@ -717,7 +764,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
"If some relocation was applied (e.g. kexec) symbols may be misresolved\n" "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
"even with a suitable vmlinux or kallsyms file.\n\n"); "even with a suitable vmlinux or kallsyms file.\n\n");
if (no_buildid_cache || no_buildid) if (rec->no_buildid_cache || rec->no_buildid)
disable_buildid_cache(); disable_buildid_cache();
if (evsel_list->nr_entries == 0 && if (evsel_list->nr_entries == 0 &&
...@@ -726,11 +773,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) ...@@ -726,11 +773,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
goto out_symbol_exit; goto out_symbol_exit;
} }
if (record_opts.target_pid != -1) if (rec->opts.target_pid != -1)
record_opts.target_tid = record_opts.target_pid; rec->opts.target_tid = rec->opts.target_pid;
if (perf_evlist__create_maps(evsel_list, record_opts.target_pid, if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
record_opts.target_tid, record_opts.cpu_list) < 0) rec->opts.target_tid, rec->opts.cpu_list) < 0)
usage_with_options(record_usage, record_options); usage_with_options(record_usage, record_options);
list_for_each_entry(pos, &evsel_list->entries, node) { list_for_each_entry(pos, &evsel_list->entries, node) {
...@@ -744,25 +791,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) ...@@ -744,25 +791,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
if (perf_evlist__alloc_pollfd(evsel_list) < 0) if (perf_evlist__alloc_pollfd(evsel_list) < 0)
goto out_free_fd; goto out_free_fd;
if (record_opts.user_interval != ULLONG_MAX) if (rec->opts.user_interval != ULLONG_MAX)
record_opts.default_interval = record_opts.user_interval; rec->opts.default_interval = rec->opts.user_interval;
if (record_opts.user_freq != UINT_MAX) if (rec->opts.user_freq != UINT_MAX)
record_opts.freq = record_opts.user_freq; rec->opts.freq = rec->opts.user_freq;
/* /*
* User specified count overrides default frequency. * User specified count overrides default frequency.
*/ */
if (record_opts.default_interval) if (rec->opts.default_interval)
record_opts.freq = 0; rec->opts.freq = 0;
else if (record_opts.freq) { else if (rec->opts.freq) {
record_opts.default_interval = record_opts.freq; rec->opts.default_interval = rec->opts.freq;
} else { } else {
fprintf(stderr, "frequency and count are zero, aborting\n"); fprintf(stderr, "frequency and count are zero, aborting\n");
err = -EINVAL; err = -EINVAL;
goto out_free_fd; goto out_free_fd;
} }
err = __cmd_record(argc, argv); err = __cmd_record(&record, argc, argv);
out_free_fd: out_free_fd:
perf_evlist__delete_maps(evsel_list); perf_evlist__delete_maps(evsel_list);
out_symbol_exit: out_symbol_exit:
......
...@@ -35,7 +35,9 @@ ...@@ -35,7 +35,9 @@
#include <linux/bitmap.h> #include <linux/bitmap.h>
static struct perf_report { struct perf_report {
struct perf_event_ops ops;
struct perf_session *session;
char const *input_name; char const *input_name;
bool force, use_tui, use_stdio; bool force, use_tui, use_stdio;
bool hide_unresolved; bool hide_unresolved;
...@@ -48,12 +50,7 @@ static struct perf_report { ...@@ -48,12 +50,7 @@ static struct perf_report {
symbol_filter_t annotate_init; symbol_filter_t annotate_init;
const char *cpu_list; const char *cpu_list;
DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
} report = { };
.input_name = "perf.data",
.pretty_printing_style = "normal",
}, *rep = &report;
static char callchain_default_opt[] = "fractal,0.5,callee";
static int perf_session__add_hist_entry(struct perf_session *session, static int perf_session__add_hist_entry(struct perf_session *session,
struct addr_location *al, struct addr_location *al,
...@@ -106,11 +103,13 @@ static int perf_session__add_hist_entry(struct perf_session *session, ...@@ -106,11 +103,13 @@ static int perf_session__add_hist_entry(struct perf_session *session,
} }
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_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct perf_session *session) struct perf_session *session)
{ {
struct perf_report *rep = container_of(ops, struct perf_report, ops);
struct addr_location al; struct addr_location al;
if (perf_event__preprocess_sample(event, session, &al, sample, if (perf_event__preprocess_sample(event, session, &al, sample,
...@@ -137,10 +136,12 @@ static int process_sample_event(union perf_event *event, ...@@ -137,10 +136,12 @@ static int process_sample_event(union perf_event *event,
return 0; return 0;
} }
static int process_read_event(union perf_event *event, static int process_read_event(struct perf_event_ops *ops,
union perf_event *event,
struct perf_sample *sample __used, struct perf_sample *sample __used,
struct perf_session *session) struct perf_session *session)
{ {
struct perf_report *rep = container_of(ops, struct perf_report, ops);
struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist,
event->read.id); event->read.id);
if (rep->show_threads) { if (rep->show_threads) {
...@@ -159,8 +160,10 @@ static int process_read_event(union perf_event *event, ...@@ -159,8 +160,10 @@ static int process_read_event(union perf_event *event,
return 0; return 0;
} }
static int perf_session__setup_sample_type(struct perf_session *self) static int perf_report__setup_sample_type(struct perf_report *rep)
{ {
struct perf_session *self = rep->session;
if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
if (sort__has_parent) { if (sort__has_parent) {
ui__warning("Selected --sort parent, but no " ui__warning("Selected --sort parent, but no "
...@@ -187,22 +190,6 @@ static int perf_session__setup_sample_type(struct perf_session *self) ...@@ -187,22 +190,6 @@ static int perf_session__setup_sample_type(struct perf_session *self)
return 0; return 0;
} }
static struct perf_event_ops event_ops = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
.comm = perf_event__process_comm,
.exit = perf_event__process_task,
.fork = perf_event__process_task,
.lost = perf_event__process_lost,
.read = process_read_event,
.attr = perf_event__process_attr,
.event_type = perf_event__process_event_type,
.tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id,
.ordered_samples = true,
.ordering_requires_timestamps = true,
};
extern volatile int session_done; extern volatile int session_done;
static void sig_handler(int sig __used) static void sig_handler(int sig __used)
...@@ -225,6 +212,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self, ...@@ -225,6 +212,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
} }
static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
struct perf_report *rep,
const char *help) const char *help)
{ {
struct perf_evsel *pos; struct perf_evsel *pos;
...@@ -253,7 +241,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, ...@@ -253,7 +241,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
return 0; return 0;
} }
static int __cmd_report(void) static int __cmd_report(struct perf_report *rep)
{ {
int ret = -EINVAL; int ret = -EINVAL;
u64 nr_samples; u64 nr_samples;
...@@ -266,10 +254,12 @@ static int __cmd_report(void) ...@@ -266,10 +254,12 @@ static int __cmd_report(void)
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
session = perf_session__new(rep->input_name, O_RDONLY, session = perf_session__new(rep->input_name, O_RDONLY,
rep->force, false, &event_ops); rep->force, false, &rep->ops);
if (session == NULL) if (session == NULL)
return -ENOMEM; return -ENOMEM;
rep->session = session;
if (rep->cpu_list) { if (rep->cpu_list) {
ret = perf_session__cpu_bitmap(session, rep->cpu_list, ret = perf_session__cpu_bitmap(session, rep->cpu_list,
rep->cpu_bitmap); rep->cpu_bitmap);
...@@ -283,11 +273,11 @@ static int __cmd_report(void) ...@@ -283,11 +273,11 @@ static int __cmd_report(void)
if (rep->show_threads) if (rep->show_threads)
perf_read_values_init(&rep->show_threads_values); perf_read_values_init(&rep->show_threads_values);
ret = perf_session__setup_sample_type(session); ret = perf_report__setup_sample_type(rep);
if (ret) if (ret)
goto out_delete; goto out_delete;
ret = perf_session__process_events(session, &event_ops); ret = perf_session__process_events(session, &rep->ops);
if (ret) if (ret)
goto out_delete; goto out_delete;
...@@ -339,7 +329,7 @@ static int __cmd_report(void) ...@@ -339,7 +329,7 @@ static int __cmd_report(void)
perf_evlist__tui_browse_hists(session->evlist, help, perf_evlist__tui_browse_hists(session->evlist, help,
NULL, NULL, 0); NULL, NULL, 0);
} else } else
perf_evlist__tty_browse_hists(session->evlist, help); perf_evlist__tty_browse_hists(session->evlist, rep, help);
out_delete: out_delete:
/* /*
...@@ -358,9 +348,9 @@ static int __cmd_report(void) ...@@ -358,9 +348,9 @@ static int __cmd_report(void)
} }
static int static int
parse_callchain_opt(const struct option *opt __used, const char *arg, parse_callchain_opt(const struct option *opt, const char *arg, int unset)
int unset)
{ {
struct perf_report *rep = (struct perf_report *)opt->value;
char *tok, *tok2; char *tok, *tok2;
char *endptr; char *endptr;
...@@ -437,12 +427,33 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, ...@@ -437,12 +427,33 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
return 0; return 0;
} }
static const char * const report_usage[] = { int cmd_report(int argc, const char **argv, const char *prefix __used)
{
char callchain_default_opt[] = "fractal,0.5,callee";
const char * const report_usage[] = {
"perf report [<options>] <command>", "perf report [<options>] <command>",
NULL NULL
}; };
struct perf_report report = {
static const struct option options[] = { .ops = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
.comm = perf_event__process_comm,
.exit = perf_event__process_task,
.fork = perf_event__process_task,
.lost = perf_event__process_lost,
.read = process_read_event,
.attr = perf_event__process_attr,
.event_type = perf_event__process_event_type,
.tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id,
.ordered_samples = true,
.ordering_requires_timestamps = true,
},
.input_name = "perf.data",
.pretty_printing_style = "normal",
};
const struct option options[] = {
OPT_STRING('i', "input", &report.input_name, "file", OPT_STRING('i', "input", &report.input_name, "file",
"input file name"), "input file name"),
OPT_INCR('v', "verbose", &verbose, OPT_INCR('v', "verbose", &verbose,
...@@ -473,7 +484,7 @@ static const struct option options[] = { ...@@ -473,7 +484,7 @@ static const struct option options[] = {
"regex filter to identify parent, see: '--sort parent'"), "regex filter to identify parent, see: '--sort parent'"),
OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
"Only display entries with parent-match"), "Only display entries with parent-match"),
OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order", OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent, call_order",
"Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. " "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. "
"Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt),
OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
...@@ -507,10 +518,8 @@ static const struct option options[] = { ...@@ -507,10 +518,8 @@ static const struct option options[] = {
OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
"Show a column with the sum of periods"), "Show a column with the sum of periods"),
OPT_END() OPT_END()
}; };
int cmd_report(int argc, const char **argv, const char *prefix __used)
{
argc = parse_options(argc, argv, options, report_usage, 0); argc = parse_options(argc, argv, options, report_usage, 0);
if (report.use_stdio) if (report.use_stdio)
...@@ -579,5 +588,5 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) ...@@ -579,5 +588,5 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
return __cmd_report(); return __cmd_report(&report);
} }
...@@ -1602,7 +1602,8 @@ static void process_raw_event(union perf_event *raw_event __used, ...@@ -1602,7 +1602,8 @@ static void process_raw_event(union perf_event *raw_event __used,
process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
} }
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_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct perf_session *session) struct perf_session *session)
......
...@@ -434,7 +434,8 @@ static int cleanup_scripting(void) ...@@ -434,7 +434,8 @@ static int cleanup_scripting(void)
static char const *input_name = "perf.data"; static char const *input_name = "perf.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_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct perf_session *session) struct perf_session *session)
......
...@@ -274,7 +274,8 @@ static int cpus_cstate_state[MAX_CPUS]; ...@@ -274,7 +274,8 @@ static int cpus_cstate_state[MAX_CPUS];
static u64 cpus_pstate_start_times[MAX_CPUS]; static u64 cpus_pstate_start_times[MAX_CPUS];
static u64 cpus_pstate_state[MAX_CPUS]; static u64 cpus_pstate_state[MAX_CPUS];
static int process_comm_event(union perf_event *event, static int process_comm_event(struct perf_event_ops *ops __used,
union perf_event *event,
struct perf_sample *sample __used, struct perf_sample *sample __used,
struct perf_session *session __used) struct perf_session *session __used)
{ {
...@@ -282,7 +283,8 @@ static int process_comm_event(union perf_event *event, ...@@ -282,7 +283,8 @@ static int process_comm_event(union perf_event *event,
return 0; return 0;
} }
static int process_fork_event(union perf_event *event, static int process_fork_event(struct perf_event_ops *ops __used,
union perf_event *event,
struct perf_sample *sample __used, struct perf_sample *sample __used,
struct perf_session *session __used) struct perf_session *session __used)
{ {
...@@ -290,7 +292,8 @@ static int process_fork_event(union perf_event *event, ...@@ -290,7 +292,8 @@ static int process_fork_event(union perf_event *event,
return 0; return 0;
} }
static int process_exit_event(union perf_event *event, static int process_exit_event(struct perf_event_ops *ops __used,
union perf_event *event,
struct perf_sample *sample __used, struct perf_sample *sample __used,
struct perf_session *session __used) struct perf_session *session __used)
{ {
...@@ -487,7 +490,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) ...@@ -487,7 +490,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
} }
static int process_sample_event(union perf_event *event __used, static int process_sample_event(struct perf_event_ops *ops __used,
union perf_event *event __used,
struct perf_sample *sample, struct perf_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct perf_session *session __used) struct perf_session *session __used)
......
...@@ -824,7 +824,7 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) ...@@ -824,7 +824,7 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
perf_event__process_sample(event, evsel, &sample, self); perf_event__process_sample(event, evsel, &sample, self);
else if (event->header.type < PERF_RECORD_MAX) { else if (event->header.type < PERF_RECORD_MAX) {
hists__inc_nr_events(&evsel->hists, event->header.type); hists__inc_nr_events(&evsel->hists, event->header.type);
perf_event__process(event, &sample, self); perf_event__process(&top.ops, event, &sample, self);
} else } else
++self->hists.stats.nr_unknown_events; ++self->hists.stats.nr_unknown_events;
} }
...@@ -966,10 +966,10 @@ static int __cmd_top(void) ...@@ -966,10 +966,10 @@ static int __cmd_top(void)
goto out_delete; goto out_delete;
if (top.target_tid != -1) if (top.target_tid != -1)
perf_event__synthesize_thread_map(top.evlist->threads, perf_event__synthesize_thread_map(&top.ops, top.evlist->threads,
perf_event__process, top.session); perf_event__process, top.session);
else else
perf_event__synthesize_threads(perf_event__process, top.session); perf_event__synthesize_threads(&top.ops, perf_event__process, top.session);
start_counters(top.evlist); start_counters(top.evlist);
top.session->evlist = top.evlist; top.session->evlist = top.evlist;
......
...@@ -13,8 +13,10 @@ ...@@ -13,8 +13,10 @@
#include "symbol.h" #include "symbol.h"
#include <linux/kernel.h> #include <linux/kernel.h>
#include "debug.h" #include "debug.h"
#include "session.h"
static int build_id__mark_dso_hit(union perf_event *event, static int build_id__mark_dso_hit(struct perf_event_ops *ops __used,
union perf_event *event,
struct perf_sample *sample __used, struct perf_sample *sample __used,
struct perf_evsel *evsel __used, struct perf_evsel *evsel __used,
struct perf_session *session) struct perf_session *session)
...@@ -38,7 +40,8 @@ static int build_id__mark_dso_hit(union perf_event *event, ...@@ -38,7 +40,8 @@ static int build_id__mark_dso_hit(union perf_event *event,
return 0; return 0;
} }
static int perf_event__exit_del_thread(union perf_event *event, static int perf_event__exit_del_thread(struct perf_event_ops *ops __used,
union perf_event *event,
struct perf_sample *sample __used, struct perf_sample *sample __used,
struct perf_session *session) struct perf_session *session)
{ {
......
...@@ -101,6 +101,9 @@ int callchain_append(struct callchain_root *root, ...@@ -101,6 +101,9 @@ int callchain_append(struct callchain_root *root,
int callchain_merge(struct callchain_cursor *cursor, int callchain_merge(struct callchain_cursor *cursor,
struct callchain_root *dst, struct callchain_root *src); struct callchain_root *dst, struct callchain_root *src);
struct ip_callchain;
union perf_event;
bool ip_callchain__valid(struct ip_callchain *chain, bool ip_callchain__valid(struct ip_callchain *chain,
const union perf_event *event); const union perf_event *event);
/* /*
......
...@@ -44,7 +44,8 @@ static struct perf_sample synth_sample = { ...@@ -44,7 +44,8 @@ static struct perf_sample synth_sample = {
.period = 1, .period = 1,
}; };
static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid, static pid_t perf_event__synthesize_comm(struct perf_event_ops *ops,
union perf_event *event, pid_t pid,
int full, perf_event__handler_t process, int full, perf_event__handler_t process,
struct perf_session *session) struct perf_session *session)
{ {
...@@ -99,7 +100,7 @@ static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid, ...@@ -99,7 +100,7 @@ static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid,
if (!full) { if (!full) {
event->comm.tid = pid; event->comm.tid = pid;
process(event, &synth_sample, session); process(ops, event, &synth_sample, session);
goto out; goto out;
} }
...@@ -117,7 +118,7 @@ static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid, ...@@ -117,7 +118,7 @@ static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid,
event->comm.tid = pid; event->comm.tid = pid;
process(event, &synth_sample, session); process(ops, event, &synth_sample, session);
} }
closedir(tasks); closedir(tasks);
...@@ -127,7 +128,8 @@ static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid, ...@@ -127,7 +128,8 @@ static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid,
return tgid; return tgid;
} }
static int perf_event__synthesize_mmap_events(union perf_event *event, static int perf_event__synthesize_mmap_events(struct perf_event_ops *ops,
union perf_event *event,
pid_t pid, pid_t tgid, pid_t pid, pid_t tgid,
perf_event__handler_t process, perf_event__handler_t process,
struct perf_session *session) struct perf_session *session)
...@@ -198,7 +200,7 @@ static int perf_event__synthesize_mmap_events(union perf_event *event, ...@@ -198,7 +200,7 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
event->mmap.pid = tgid; event->mmap.pid = tgid;
event->mmap.tid = pid; event->mmap.tid = pid;
process(event, &synth_sample, session); process(ops, event, &synth_sample, session);
} }
} }
...@@ -206,7 +208,8 @@ static int perf_event__synthesize_mmap_events(union perf_event *event, ...@@ -206,7 +208,8 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
return 0; return 0;
} }
int perf_event__synthesize_modules(perf_event__handler_t process, int perf_event__synthesize_modules(struct perf_event_ops *ops,
perf_event__handler_t process,
struct perf_session *session, struct perf_session *session,
struct machine *machine) struct machine *machine)
{ {
...@@ -251,7 +254,7 @@ int perf_event__synthesize_modules(perf_event__handler_t process, ...@@ -251,7 +254,7 @@ int perf_event__synthesize_modules(perf_event__handler_t process,
memcpy(event->mmap.filename, pos->dso->long_name, memcpy(event->mmap.filename, pos->dso->long_name,
pos->dso->long_name_len + 1); pos->dso->long_name_len + 1);
process(event, &synth_sample, session); process(ops, event, &synth_sample, session);
} }
free(event); free(event);
...@@ -261,17 +264,19 @@ int perf_event__synthesize_modules(perf_event__handler_t process, ...@@ -261,17 +264,19 @@ int perf_event__synthesize_modules(perf_event__handler_t process,
static int __event__synthesize_thread(union perf_event *comm_event, static int __event__synthesize_thread(union perf_event *comm_event,
union perf_event *mmap_event, union perf_event *mmap_event,
pid_t pid, perf_event__handler_t process, pid_t pid, perf_event__handler_t process,
struct perf_event_ops *ops,
struct perf_session *session) struct perf_session *session)
{ {
pid_t tgid = perf_event__synthesize_comm(comm_event, pid, 1, process, pid_t tgid = perf_event__synthesize_comm(ops, comm_event, pid, 1, process,
session); session);
if (tgid == -1) if (tgid == -1)
return -1; return -1;
return perf_event__synthesize_mmap_events(mmap_event, pid, tgid, return perf_event__synthesize_mmap_events(ops, mmap_event, pid, tgid,
process, session); process, session);
} }
int perf_event__synthesize_thread_map(struct thread_map *threads, int perf_event__synthesize_thread_map(struct perf_event_ops *ops,
struct thread_map *threads,
perf_event__handler_t process, perf_event__handler_t process,
struct perf_session *session) struct perf_session *session)
{ {
...@@ -290,7 +295,7 @@ int perf_event__synthesize_thread_map(struct thread_map *threads, ...@@ -290,7 +295,7 @@ int perf_event__synthesize_thread_map(struct thread_map *threads,
for (thread = 0; thread < threads->nr; ++thread) { for (thread = 0; thread < threads->nr; ++thread) {
if (__event__synthesize_thread(comm_event, mmap_event, if (__event__synthesize_thread(comm_event, mmap_event,
threads->map[thread], threads->map[thread],
process, session)) { process, ops, session)) {
err = -1; err = -1;
break; break;
} }
...@@ -302,7 +307,8 @@ int perf_event__synthesize_thread_map(struct thread_map *threads, ...@@ -302,7 +307,8 @@ int perf_event__synthesize_thread_map(struct thread_map *threads,
return err; return err;
} }
int perf_event__synthesize_threads(perf_event__handler_t process, int perf_event__synthesize_threads(struct perf_event_ops *ops,
perf_event__handler_t process,
struct perf_session *session) struct perf_session *session)
{ {
DIR *proc; DIR *proc;
...@@ -330,7 +336,7 @@ int perf_event__synthesize_threads(perf_event__handler_t process, ...@@ -330,7 +336,7 @@ int perf_event__synthesize_threads(perf_event__handler_t process,
continue; continue;
__event__synthesize_thread(comm_event, mmap_event, pid, __event__synthesize_thread(comm_event, mmap_event, pid,
process, session); process, ops, session);
} }
closedir(proc); closedir(proc);
...@@ -365,7 +371,8 @@ static int find_symbol_cb(void *arg, const char *name, char type, ...@@ -365,7 +371,8 @@ static int find_symbol_cb(void *arg, const char *name, char type,
return 1; return 1;
} }
int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops,
perf_event__handler_t process,
struct perf_session *session, struct perf_session *session,
struct machine *machine, struct machine *machine,
const char *symbol_name) const char *symbol_name)
...@@ -423,13 +430,14 @@ int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, ...@@ -423,13 +430,14 @@ int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
event->mmap.len = map->end - event->mmap.start; event->mmap.len = map->end - event->mmap.start;
event->mmap.pid = machine->pid; event->mmap.pid = machine->pid;
err = process(event, &synth_sample, session); err = process(ops, event, &synth_sample, session);
free(event); free(event);
return err; return err;
} }
int perf_event__process_comm(union perf_event *event, int perf_event__process_comm(struct perf_event_ops *ops __used,
union perf_event *event,
struct perf_sample *sample __used, struct perf_sample *sample __used,
struct perf_session *session) struct perf_session *session)
{ {
...@@ -445,7 +453,8 @@ int perf_event__process_comm(union perf_event *event, ...@@ -445,7 +453,8 @@ int perf_event__process_comm(union perf_event *event,
return 0; return 0;
} }
int perf_event__process_lost(union perf_event *event, int perf_event__process_lost(struct perf_event_ops *ops __used,
union perf_event *event,
struct perf_sample *sample __used, struct perf_sample *sample __used,
struct perf_session *session) struct perf_session *session)
{ {
...@@ -468,7 +477,8 @@ static void perf_event__set_kernel_mmap_len(union perf_event *event, ...@@ -468,7 +477,8 @@ static void perf_event__set_kernel_mmap_len(union perf_event *event,
maps[MAP__FUNCTION]->end = ~0ULL; maps[MAP__FUNCTION]->end = ~0ULL;
} }
static int perf_event__process_kernel_mmap(union perf_event *event, static int perf_event__process_kernel_mmap(struct perf_event_ops *ops __used,
union perf_event *event,
struct perf_session *session) struct perf_session *session)
{ {
struct map *map; struct map *map;
...@@ -567,7 +577,8 @@ static int perf_event__process_kernel_mmap(union perf_event *event, ...@@ -567,7 +577,8 @@ static int perf_event__process_kernel_mmap(union perf_event *event,
return -1; return -1;
} }
int perf_event__process_mmap(union perf_event *event, int perf_event__process_mmap(struct perf_event_ops *ops,
union perf_event *event,
struct perf_sample *sample __used, struct perf_sample *sample __used,
struct perf_session *session) struct perf_session *session)
{ {
...@@ -583,7 +594,7 @@ int perf_event__process_mmap(union perf_event *event, ...@@ -583,7 +594,7 @@ int perf_event__process_mmap(union perf_event *event,
if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
cpumode == PERF_RECORD_MISC_KERNEL) { cpumode == PERF_RECORD_MISC_KERNEL) {
ret = perf_event__process_kernel_mmap(event, session); ret = perf_event__process_kernel_mmap(ops, event, session);
if (ret < 0) if (ret < 0)
goto out_problem; goto out_problem;
return 0; return 0;
...@@ -610,7 +621,8 @@ int perf_event__process_mmap(union perf_event *event, ...@@ -610,7 +621,8 @@ int perf_event__process_mmap(union perf_event *event,
return 0; return 0;
} }
int perf_event__process_task(union perf_event *event, int perf_event__process_task(struct perf_event_ops *ops __used,
union perf_event *event,
struct perf_sample *sample __used, struct perf_sample *sample __used,
struct perf_session *session) struct perf_session *session)
{ {
...@@ -634,22 +646,22 @@ int perf_event__process_task(union perf_event *event, ...@@ -634,22 +646,22 @@ int perf_event__process_task(union perf_event *event,
return 0; return 0;
} }
int perf_event__process(union perf_event *event, struct perf_sample *sample, int perf_event__process(struct perf_event_ops *ops, union perf_event *event,
struct perf_session *session) struct perf_sample *sample, struct perf_session *session)
{ {
switch (event->header.type) { switch (event->header.type) {
case PERF_RECORD_COMM: case PERF_RECORD_COMM:
perf_event__process_comm(event, sample, session); perf_event__process_comm(ops, event, sample, session);
break; break;
case PERF_RECORD_MMAP: case PERF_RECORD_MMAP:
perf_event__process_mmap(event, sample, session); perf_event__process_mmap(ops, event, sample, session);
break; break;
case PERF_RECORD_FORK: case PERF_RECORD_FORK:
case PERF_RECORD_EXIT: case PERF_RECORD_EXIT:
perf_event__process_task(event, sample, session); perf_event__process_task(ops, event, sample, session);
break; break;
case PERF_RECORD_LOST: case PERF_RECORD_LOST:
perf_event__process_lost(event, sample, session); perf_event__process_lost(ops, event, sample, session);
default: default:
break; break;
} }
......
...@@ -141,38 +141,52 @@ union perf_event { ...@@ -141,38 +141,52 @@ union perf_event {
void perf_event__print_totals(void); void perf_event__print_totals(void);
struct perf_event_ops;
struct perf_session; struct perf_session;
struct thread_map; struct thread_map;
typedef int (*perf_event__handler_synth_t)(union perf_event *event, typedef int (*perf_event__handler_t)(struct perf_event_ops *ops,
struct perf_session *session); union perf_event *event,
typedef int (*perf_event__handler_t)(union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
struct perf_session *session); struct perf_session *session);
int perf_event__synthesize_thread_map(struct thread_map *threads, int perf_event__synthesize_thread_map(struct perf_event_ops *ops,
struct thread_map *threads,
perf_event__handler_t process, perf_event__handler_t process,
struct perf_session *session); struct perf_session *session);
int perf_event__synthesize_threads(perf_event__handler_t process, int perf_event__synthesize_threads(struct perf_event_ops *ops,
perf_event__handler_t process,
struct perf_session *session); struct perf_session *session);
int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops,
perf_event__handler_t process,
struct perf_session *session, struct perf_session *session,
struct machine *machine, struct machine *machine,
const char *symbol_name); const char *symbol_name);
int perf_event__synthesize_modules(perf_event__handler_t process, int perf_event__synthesize_modules(struct perf_event_ops *ops,
perf_event__handler_t process,
struct perf_session *session, struct perf_session *session,
struct machine *machine); struct machine *machine);
int perf_event__process_comm(union perf_event *event, struct perf_sample *sample, int perf_event__process_comm(struct perf_event_ops *ops,
union perf_event *event,
struct perf_sample *sample,
struct perf_session *session); struct perf_session *session);
int perf_event__process_lost(union perf_event *event, struct perf_sample *sample, int perf_event__process_lost(struct perf_event_ops *ops,
union perf_event *event,
struct perf_sample *sample,
struct perf_session *session); struct perf_session *session);
int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample, int perf_event__process_mmap(struct perf_event_ops *ops,
union perf_event *event,
struct perf_sample *sample,
struct perf_session *session); struct perf_session *session);
int perf_event__process_task(union perf_event *event, struct perf_sample *sample, int perf_event__process_task(struct perf_event_ops *ops,
union perf_event *event,
struct perf_sample *sample,
struct perf_session *session); struct perf_session *session);
int perf_event__process(union perf_event *event, struct perf_sample *sample, int perf_event__process(struct perf_event_ops *ops,
union perf_event *event,
struct perf_sample *sample,
struct perf_session *session); struct perf_session *session);
struct addr_location; struct addr_location;
......
...@@ -2070,7 +2070,8 @@ int perf_session__read_header(struct perf_session *session, int fd) ...@@ -2070,7 +2070,8 @@ int perf_session__read_header(struct perf_session *session, int fd)
return -ENOMEM; return -ENOMEM;
} }
int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, int perf_event__synthesize_attr(struct perf_event_ops *ops,
struct perf_event_attr *attr, u16 ids, u64 *id,
perf_event__handler_t process, perf_event__handler_t process,
struct perf_session *session) struct perf_session *session)
{ {
...@@ -2094,21 +2095,22 @@ int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, ...@@ -2094,21 +2095,22 @@ int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
ev->attr.header.type = PERF_RECORD_HEADER_ATTR; ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
ev->attr.header.size = size; ev->attr.header.size = size;
err = process(ev, NULL, session); err = process(ops, ev, NULL, session);
free(ev); free(ev);
return err; return err;
} }
int perf_session__synthesize_attrs(struct perf_session *session, int perf_event__synthesize_attrs(struct perf_event_ops *ops,
struct perf_session *session,
perf_event__handler_t process) perf_event__handler_t process)
{ {
struct perf_evsel *attr; struct perf_evsel *attr;
int err = 0; int err = 0;
list_for_each_entry(attr, &session->evlist->entries, node) { list_for_each_entry(attr, &session->evlist->entries, node) {
err = perf_event__synthesize_attr(&attr->attr, attr->ids, err = perf_event__synthesize_attr(ops, &attr->attr, attr->ids,
attr->id, process, session); attr->id, process, session);
if (err) { if (err) {
pr_debug("failed to create perf header attribute\n"); pr_debug("failed to create perf header attribute\n");
...@@ -2156,7 +2158,8 @@ int perf_event__process_attr(union perf_event *event, ...@@ -2156,7 +2158,8 @@ int perf_event__process_attr(union perf_event *event,
return 0; return 0;
} }
int perf_event__synthesize_event_type(u64 event_id, char *name, int perf_event__synthesize_event_type(struct perf_event_ops *ops,
u64 event_id, char *name,
perf_event__handler_t process, perf_event__handler_t process,
struct perf_session *session) struct perf_session *session)
{ {
...@@ -2176,12 +2179,13 @@ int perf_event__synthesize_event_type(u64 event_id, char *name, ...@@ -2176,12 +2179,13 @@ int perf_event__synthesize_event_type(u64 event_id, char *name,
ev.event_type.header.size = sizeof(ev.event_type) - ev.event_type.header.size = sizeof(ev.event_type) -
(sizeof(ev.event_type.event_type.name) - size); (sizeof(ev.event_type.event_type.name) - size);
err = process(&ev, NULL, session); err = process(ops, &ev, NULL, session);
return err; return err;
} }
int perf_event__synthesize_event_types(perf_event__handler_t process, int perf_event__synthesize_event_types(struct perf_event_ops *ops,
perf_event__handler_t process,
struct perf_session *session) struct perf_session *session)
{ {
struct perf_trace_event_type *type; struct perf_trace_event_type *type;
...@@ -2190,7 +2194,7 @@ int perf_event__synthesize_event_types(perf_event__handler_t process, ...@@ -2190,7 +2194,7 @@ int perf_event__synthesize_event_types(perf_event__handler_t process,
for (i = 0; i < event_count; i++) { for (i = 0; i < event_count; i++) {
type = &events[i]; type = &events[i];
err = perf_event__synthesize_event_type(type->event_id, err = perf_event__synthesize_event_type(ops, type->event_id,
type->name, process, type->name, process,
session); session);
if (err) { if (err) {
...@@ -2202,7 +2206,8 @@ int perf_event__synthesize_event_types(perf_event__handler_t process, ...@@ -2202,7 +2206,8 @@ int perf_event__synthesize_event_types(perf_event__handler_t process,
return err; return err;
} }
int perf_event__process_event_type(union perf_event *event, int perf_event__process_event_type(struct perf_event_ops *ops __unused,
union perf_event *event,
struct perf_session *session __unused) struct perf_session *session __unused)
{ {
if (perf_header__push_event(event->event_type.event_type.event_id, if (perf_header__push_event(event->event_type.event_type.event_id,
...@@ -2212,7 +2217,8 @@ int perf_event__process_event_type(union perf_event *event, ...@@ -2212,7 +2217,8 @@ int perf_event__process_event_type(union perf_event *event,
return 0; return 0;
} }
int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, int perf_event__synthesize_tracing_data(struct perf_event_ops *ops, int fd,
struct perf_evlist *evlist,
perf_event__handler_t process, perf_event__handler_t process,
struct perf_session *session __unused) struct perf_session *session __unused)
{ {
...@@ -2245,7 +2251,7 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, ...@@ -2245,7 +2251,7 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
ev.tracing_data.header.size = sizeof(ev.tracing_data); ev.tracing_data.header.size = sizeof(ev.tracing_data);
ev.tracing_data.size = aligned_size; ev.tracing_data.size = aligned_size;
process(&ev, NULL, session); process(ops, &ev, NULL, session);
/* /*
* The put function will copy all the tracing data * The put function will copy all the tracing data
...@@ -2287,7 +2293,8 @@ int perf_event__process_tracing_data(union perf_event *event, ...@@ -2287,7 +2293,8 @@ int perf_event__process_tracing_data(union perf_event *event,
return size_read + padding; return size_read + padding;
} }
int perf_event__synthesize_build_id(struct dso *pos, u16 misc, int perf_event__synthesize_build_id(struct perf_event_ops *ops,
struct dso *pos, u16 misc,
perf_event__handler_t process, perf_event__handler_t process,
struct machine *machine, struct machine *machine,
struct perf_session *session) struct perf_session *session)
...@@ -2310,12 +2317,13 @@ int perf_event__synthesize_build_id(struct dso *pos, u16 misc, ...@@ -2310,12 +2317,13 @@ int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
ev.build_id.header.size = sizeof(ev.build_id) + len; ev.build_id.header.size = sizeof(ev.build_id) + len;
memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
err = process(&ev, NULL, session); err = process(ops, &ev, NULL, session);
return err; return err;
} }
int perf_event__process_build_id(union perf_event *event, int perf_event__process_build_id(struct perf_event_ops *ops __used,
union perf_event *event,
struct perf_session *session) struct perf_session *session)
{ {
__event_process_build_id(&event->build_id, __event_process_build_id(&event->build_id,
......
...@@ -68,6 +68,7 @@ struct perf_header { ...@@ -68,6 +68,7 @@ struct perf_header {
}; };
struct perf_evlist; struct perf_evlist;
struct perf_session;
int perf_session__read_header(struct perf_session *session, int fd); int perf_session__read_header(struct perf_session *session, int fd);
int perf_session__write_header(struct perf_session *session, int perf_session__write_header(struct perf_session *session,
...@@ -96,32 +97,40 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, ...@@ -96,32 +97,40 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
const char *name, bool is_kallsyms); const char *name, bool is_kallsyms);
int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, int perf_event__synthesize_attr(struct perf_event_ops *ops,
struct perf_event_attr *attr, u16 ids, u64 *id,
perf_event__handler_t process, perf_event__handler_t process,
struct perf_session *session); struct perf_session *session);
int perf_session__synthesize_attrs(struct perf_session *session, int perf_event__synthesize_attrs(struct perf_event_ops *ops,
struct perf_session *session,
perf_event__handler_t process); perf_event__handler_t process);
int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist); int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist);
int perf_event__synthesize_event_type(u64 event_id, char *name, int perf_event__synthesize_event_type(struct perf_event_ops *ops,
u64 event_id, char *name,
perf_event__handler_t process, perf_event__handler_t process,
struct perf_session *session); struct perf_session *session);
int perf_event__synthesize_event_types(perf_event__handler_t process, int perf_event__synthesize_event_types(struct perf_event_ops *ops,
perf_event__handler_t process,
struct perf_session *session); struct perf_session *session);
int perf_event__process_event_type(union perf_event *event, int perf_event__process_event_type(struct perf_event_ops *ops,
union perf_event *event,
struct perf_session *session); struct perf_session *session);
int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, int perf_event__synthesize_tracing_data(struct perf_event_ops *ops,
int fd, struct perf_evlist *evlist,
perf_event__handler_t process, perf_event__handler_t process,
struct perf_session *session); struct perf_session *session);
int perf_event__process_tracing_data(union perf_event *event, int perf_event__process_tracing_data(union perf_event *event,
struct perf_session *session); struct perf_session *session);
int perf_event__synthesize_build_id(struct dso *pos, u16 misc, int perf_event__synthesize_build_id(struct perf_event_ops *ops,
struct dso *pos, u16 misc,
perf_event__handler_t process, perf_event__handler_t process,
struct machine *machine, struct machine *machine,
struct perf_session *session); struct perf_session *session);
int perf_event__process_build_id(union perf_event *event, int perf_event__process_build_id(struct perf_event_ops *ops,
union perf_event *event,
struct perf_session *session); struct perf_session *session);
/* /*
......
...@@ -270,7 +270,15 @@ int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel ...@@ -270,7 +270,15 @@ int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel
return 0; return 0;
} }
static int process_event_synth_stub(union perf_event *event __used, static int process_event_synth_stub(struct perf_event_ops *ops __used,
union perf_event *event __used,
struct perf_session *session __used)
{
dump_printf(": unhandled!\n");
return 0;
}
static int process_event_synth_tracing_data_stub(union perf_event *event __used,
struct perf_session *session __used) struct perf_session *session __used)
{ {
dump_printf(": unhandled!\n"); dump_printf(": unhandled!\n");
...@@ -284,7 +292,8 @@ static int process_event_synth_attr_stub(union perf_event *event __used, ...@@ -284,7 +292,8 @@ static int process_event_synth_attr_stub(union perf_event *event __used,
return 0; return 0;
} }
static int process_event_sample_stub(union perf_event *event __used, static int process_event_sample_stub(struct perf_event_ops *ops __used,
union perf_event *event __used,
struct perf_sample *sample __used, struct perf_sample *sample __used,
struct perf_evsel *evsel __used, struct perf_evsel *evsel __used,
struct perf_session *session __used) struct perf_session *session __used)
...@@ -293,7 +302,8 @@ static int process_event_sample_stub(union perf_event *event __used, ...@@ -293,7 +302,8 @@ static int process_event_sample_stub(union perf_event *event __used,
return 0; return 0;
} }
static int process_event_stub(union perf_event *event __used, static int process_event_stub(struct perf_event_ops *ops __used,
union perf_event *event __used,
struct perf_sample *sample __used, struct perf_sample *sample __used,
struct perf_session *session __used) struct perf_session *session __used)
{ {
...@@ -301,17 +311,17 @@ static int process_event_stub(union perf_event *event __used, ...@@ -301,17 +311,17 @@ static int process_event_stub(union perf_event *event __used,
return 0; return 0;
} }
static int process_finished_round_stub(union perf_event *event __used, static int process_finished_round_stub(struct perf_event_ops *ops __used,
struct perf_session *session __used, union perf_event *event __used,
struct perf_event_ops *ops __used) struct perf_session *session __used)
{ {
dump_printf(": unhandled!\n"); dump_printf(": unhandled!\n");
return 0; return 0;
} }
static int process_finished_round(union perf_event *event, static int process_finished_round(struct perf_event_ops *ops,
struct perf_session *session, union perf_event *event,
struct perf_event_ops *ops); struct perf_session *session);
static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
{ {
...@@ -338,7 +348,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) ...@@ -338,7 +348,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
if (handler->event_type == NULL) if (handler->event_type == NULL)
handler->event_type = process_event_synth_stub; handler->event_type = process_event_synth_stub;
if (handler->tracing_data == NULL) if (handler->tracing_data == NULL)
handler->tracing_data = process_event_synth_stub; handler->tracing_data = process_event_synth_tracing_data_stub;
if (handler->build_id == NULL) if (handler->build_id == NULL)
handler->build_id = process_event_synth_stub; handler->build_id = process_event_synth_stub;
if (handler->finished_round == NULL) { if (handler->finished_round == NULL) {
...@@ -565,9 +575,9 @@ static void flush_sample_queue(struct perf_session *s, ...@@ -565,9 +575,9 @@ static void flush_sample_queue(struct perf_session *s,
* Flush every events below timestamp 7 * Flush every events below timestamp 7
* etc... * etc...
*/ */
static int process_finished_round(union perf_event *event __used, static int process_finished_round(struct perf_event_ops *ops,
struct perf_session *session, union perf_event *event __used,
struct perf_event_ops *ops) struct perf_session *session)
{ {
flush_sample_queue(session, ops); flush_sample_queue(session, ops);
session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
...@@ -759,23 +769,23 @@ static int perf_session_deliver_event(struct perf_session *session, ...@@ -759,23 +769,23 @@ static int perf_session_deliver_event(struct perf_session *session,
++session->hists.stats.nr_unknown_id; ++session->hists.stats.nr_unknown_id;
return -1; return -1;
} }
return ops->sample(event, sample, evsel, session); return ops->sample(ops, event, sample, evsel, session);
case PERF_RECORD_MMAP: case PERF_RECORD_MMAP:
return ops->mmap(event, sample, session); return ops->mmap(ops, event, sample, session);
case PERF_RECORD_COMM: case PERF_RECORD_COMM:
return ops->comm(event, sample, session); return ops->comm(ops, event, sample, session);
case PERF_RECORD_FORK: case PERF_RECORD_FORK:
return ops->fork(event, sample, session); return ops->fork(ops, event, sample, session);
case PERF_RECORD_EXIT: case PERF_RECORD_EXIT:
return ops->exit(event, sample, session); return ops->exit(ops, event, sample, session);
case PERF_RECORD_LOST: case PERF_RECORD_LOST:
return ops->lost(event, sample, session); return ops->lost(ops, event, sample, session);
case PERF_RECORD_READ: case PERF_RECORD_READ:
return ops->read(event, sample, session); return ops->read(ops, event, sample, session);
case PERF_RECORD_THROTTLE: case PERF_RECORD_THROTTLE:
return ops->throttle(event, sample, session); return ops->throttle(ops, event, sample, session);
case PERF_RECORD_UNTHROTTLE: case PERF_RECORD_UNTHROTTLE:
return ops->unthrottle(event, sample, session); return ops->unthrottle(ops, event, sample, session);
default: default:
++session->hists.stats.nr_unknown_events; ++session->hists.stats.nr_unknown_events;
return -1; return -1;
...@@ -813,15 +823,15 @@ static int perf_session__process_user_event(struct perf_session *session, union ...@@ -813,15 +823,15 @@ static int perf_session__process_user_event(struct perf_session *session, union
perf_session__update_sample_type(session); perf_session__update_sample_type(session);
return err; return err;
case PERF_RECORD_HEADER_EVENT_TYPE: case PERF_RECORD_HEADER_EVENT_TYPE:
return ops->event_type(event, session); return ops->event_type(ops, event, session);
case PERF_RECORD_HEADER_TRACING_DATA: case PERF_RECORD_HEADER_TRACING_DATA:
/* setup for reading amidst mmap */ /* setup for reading amidst mmap */
lseek(session->fd, file_offset, SEEK_SET); lseek(session->fd, file_offset, SEEK_SET);
return ops->tracing_data(event, session); return ops->tracing_data(event, session);
case PERF_RECORD_HEADER_BUILD_ID: case PERF_RECORD_HEADER_BUILD_ID:
return ops->build_id(event, session); return ops->build_id(ops, event, session);
case PERF_RECORD_FINISHED_ROUND: case PERF_RECORD_FINISHED_ROUND:
return ops->finished_round(event, session, ops); return ops->finished_round(ops, event, session);
default: default:
return -EINVAL; return -EINVAL;
} }
......
...@@ -56,16 +56,18 @@ struct perf_session { ...@@ -56,16 +56,18 @@ struct perf_session {
struct perf_evsel; struct perf_evsel;
struct perf_event_ops; struct perf_event_ops;
typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample, typedef int (*event_sample)(struct perf_event_ops *ops,
union perf_event *event, struct perf_sample *sample,
struct perf_evsel *evsel, struct perf_session *session); struct perf_evsel *evsel, struct perf_session *session);
typedef int (*event_op)(union perf_event *self, struct perf_sample *sample, typedef int (*event_op)(struct perf_event_ops *ops, union perf_event *event,
struct perf_sample *sample,
struct perf_session *session); struct perf_session *session);
typedef int (*event_synth_op)(union perf_event *self, typedef int (*event_synth_op)(union perf_event *self,
struct perf_session *session); struct perf_session *session);
typedef int (*event_attr_op)(union perf_event *event, typedef int (*event_attr_op)(union perf_event *event,
struct perf_evlist **pevlist); struct perf_evlist **pevlist);
typedef int (*event_op2)(union perf_event *self, struct perf_session *session, typedef int (*event_op2)(struct perf_event_ops *ops, union perf_event *event,
struct perf_event_ops *ops); struct perf_session *session);
struct perf_event_ops { struct perf_event_ops {
event_sample sample; event_sample sample;
...@@ -78,10 +80,10 @@ struct perf_event_ops { ...@@ -78,10 +80,10 @@ struct perf_event_ops {
throttle, throttle,
unthrottle; unthrottle;
event_attr_op attr; event_attr_op attr;
event_synth_op event_type, event_synth_op tracing_data;
tracing_data, event_op2 event_type,
build_id; build_id,
event_op2 finished_round; finished_round;
bool ordered_samples; bool ordered_samples;
bool ordering_requires_timestamps; bool ordering_requires_timestamps;
}; };
...@@ -142,10 +144,11 @@ struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t p ...@@ -142,10 +144,11 @@ struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t p
static inline static inline
void perf_session__process_machines(struct perf_session *self, void perf_session__process_machines(struct perf_session *self,
struct perf_event_ops *ops,
machine__process_t process) machine__process_t process)
{ {
process(&self->host_machine, self); process(&self->host_machine, ops);
return machines__process(&self->machines, process, self); return machines__process(&self->machines, process, ops);
} }
size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
......
...@@ -2,14 +2,15 @@ ...@@ -2,14 +2,15 @@
#define __PERF_TOP_H 1 #define __PERF_TOP_H 1
#include "types.h" #include "types.h"
#include "session.h"
#include "../perf.h" #include "../perf.h"
#include <stddef.h> #include <stddef.h>
struct perf_evlist; struct perf_evlist;
struct perf_evsel; struct perf_evsel;
struct perf_session;
struct perf_top { struct perf_top {
struct perf_event_ops ops;
struct perf_evlist *evlist; struct perf_evlist *evlist;
/* /*
* Symbols will be added here in perf_event__process_sample and will * Symbols will be added here in perf_event__process_sample and will
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment