aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/builtin-annotate.c62
-rw-r--r--tools/perf/builtin-diff.c3
-rw-r--r--tools/perf/builtin-inject.c55
-rw-r--r--tools/perf/builtin-kmem.c3
-rw-r--r--tools/perf/builtin-lock.c3
-rw-r--r--tools/perf/builtin-record.c383
-rw-r--r--tools/perf/builtin-report.c97
-rw-r--r--tools/perf/builtin-sched.c3
-rw-r--r--tools/perf/builtin-script.c3
-rw-r--r--tools/perf/builtin-timechart.c12
-rw-r--r--tools/perf/builtin-top.c6
-rw-r--r--tools/perf/util/build-id.c7
-rw-r--r--tools/perf/util/callchain.h3
-rw-r--r--tools/perf/util/event.c66
-rw-r--r--tools/perf/util/event.h38
-rw-r--r--tools/perf/util/header.c36
-rw-r--r--tools/perf/util/header.h27
-rw-r--r--tools/perf/util/session.c60
-rw-r--r--tools/perf/util/session.h23
-rw-r--r--tools/perf/util/top.h3
20 files changed, 520 insertions, 373 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 4f0c3d98352d..483cb9466444 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -30,7 +30,8 @@
30 30
31#include <linux/bitmap.h> 31#include <linux/bitmap.h>
32 32
33static struct perf_annotate { 33struct perf_annotate {
34 struct perf_event_ops ops;
34 char const *input_name; 35 char const *input_name;
35 bool force, use_tui, use_stdio; 36 bool force, use_tui, use_stdio;
36 bool full_paths; 37 bool full_paths;
@@ -38,13 +39,12 @@ static struct perf_annotate {
38 const char *sym_hist_filter; 39 const char *sym_hist_filter;
39 const char *cpu_list; 40 const char *cpu_list;
40 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 41 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
41} annotate = { 42};
42 .input_name = "perf.data",
43}, *ann = &annotate;
44 43
45static int perf_evsel__add_sample(struct perf_evsel *evsel, 44static int perf_evsel__add_sample(struct perf_evsel *evsel,
46 struct perf_sample *sample, 45 struct perf_sample *sample,
47 struct addr_location *al) 46 struct addr_location *al,
47 struct perf_annotate *ann)
48{ 48{
49 struct hist_entry *he; 49 struct hist_entry *he;
50 int ret; 50 int ret;
@@ -79,11 +79,13 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
79 return ret; 79 return ret;
80} 80}
81 81
82static int process_sample_event(union perf_event *event, 82static int process_sample_event(struct perf_event_ops *ops,
83 union perf_event *event,
83 struct perf_sample *sample, 84 struct perf_sample *sample,
84 struct perf_evsel *evsel, 85 struct perf_evsel *evsel,
85 struct perf_session *session) 86 struct perf_session *session)
86{ 87{
88 struct perf_annotate *ann = container_of(ops, struct perf_annotate, ops);
87 struct addr_location al; 89 struct addr_location al;
88 90
89 if (perf_event__preprocess_sample(event, session, &al, sample, 91 if (perf_event__preprocess_sample(event, session, &al, sample,
@@ -96,7 +98,7 @@ static int process_sample_event(union perf_event *event,
96 if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap)) 98 if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap))
97 return 0; 99 return 0;
98 100
99 if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al)) { 101 if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al, ann)) {
100 pr_warning("problem incrementing symbol count, " 102 pr_warning("problem incrementing symbol count, "
101 "skipping event\n"); 103 "skipping event\n");
102 return -1; 104 return -1;
@@ -105,13 +107,15 @@ static int process_sample_event(union perf_event *event,
105 return 0; 107 return 0;
106} 108}
107 109
108static int hist_entry__tty_annotate(struct hist_entry *he, int evidx) 110static int hist_entry__tty_annotate(struct hist_entry *he, int evidx,
111 struct perf_annotate *ann)
109{ 112{
110 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, 113 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
111 ann->print_line, ann->full_paths, 0, 0); 114 ann->print_line, ann->full_paths, 0, 0);
112} 115}
113 116
114static void hists__find_annotations(struct hists *self, int evidx) 117static void hists__find_annotations(struct hists *self, int evidx,
118 struct perf_annotate *ann)
115{ 119{
116 struct rb_node *nd = rb_first(&self->entries), *next; 120 struct rb_node *nd = rb_first(&self->entries), *next;
117 int key = K_RIGHT; 121 int key = K_RIGHT;
@@ -149,7 +153,7 @@ find_next:
149 if (next != NULL) 153 if (next != NULL)
150 nd = next; 154 nd = next;
151 } else { 155 } else {
152 hist_entry__tty_annotate(he, evidx); 156 hist_entry__tty_annotate(he, evidx, ann);
153 nd = rb_next(nd); 157 nd = rb_next(nd);
154 /* 158 /*
155 * Since we have a hist_entry per IP for the same 159 * Since we have a hist_entry per IP for the same
@@ -162,16 +166,7 @@ find_next:
162 } 166 }
163} 167}
164 168
165static struct perf_event_ops event_ops = { 169static int __cmd_annotate(struct perf_annotate *ann)
166 .sample = process_sample_event,
167 .mmap = perf_event__process_mmap,
168 .comm = perf_event__process_comm,
169 .fork = perf_event__process_task,
170 .ordered_samples = true,
171 .ordering_requires_timestamps = true,
172};
173
174static int __cmd_annotate(void)
175{ 170{
176 int ret; 171 int ret;
177 struct perf_session *session; 172 struct perf_session *session;
@@ -179,7 +174,7 @@ static int __cmd_annotate(void)
179 u64 total_nr_samples; 174 u64 total_nr_samples;
180 175
181 session = perf_session__new(ann->input_name, O_RDONLY, 176 session = perf_session__new(ann->input_name, O_RDONLY,
182 ann->force, false, &event_ops); 177 ann->force, false, &ann->ops);
183 if (session == NULL) 178 if (session == NULL)
184 return -ENOMEM; 179 return -ENOMEM;
185 180
@@ -190,7 +185,7 @@ static int __cmd_annotate(void)
190 goto out_delete; 185 goto out_delete;
191 } 186 }
192 187
193 ret = perf_session__process_events(session, &event_ops); 188 ret = perf_session__process_events(session, &ann->ops);
194 if (ret) 189 if (ret)
195 goto out_delete; 190 goto out_delete;
196 191
@@ -214,7 +209,7 @@ static int __cmd_annotate(void)
214 total_nr_samples += nr_samples; 209 total_nr_samples += nr_samples;
215 hists__collapse_resort(hists); 210 hists__collapse_resort(hists);
216 hists__output_resort(hists); 211 hists__output_resort(hists);
217 hists__find_annotations(hists, pos->idx); 212 hists__find_annotations(hists, pos->idx, ann);
218 } 213 }
219 } 214 }
220 215
@@ -243,7 +238,20 @@ static const char * const annotate_usage[] = {
243 NULL 238 NULL
244}; 239};
245 240
246static const struct option options[] = { 241int cmd_annotate(int argc, const char **argv, const char *prefix __used)
242{
243 struct perf_annotate annotate = {
244 .ops = {
245 .sample = process_sample_event,
246 .mmap = perf_event__process_mmap,
247 .comm = perf_event__process_comm,
248 .fork = perf_event__process_task,
249 .ordered_samples = true,
250 .ordering_requires_timestamps = true,
251 },
252 .input_name = "perf.data",
253 };
254 const struct option options[] = {
247 OPT_STRING('i', "input", &annotate.input_name, "file", 255 OPT_STRING('i', "input", &annotate.input_name, "file",
248 "input file name"), 256 "input file name"),
249 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 257 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
@@ -275,10 +283,8 @@ static const struct option options[] = {
275 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 283 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
276 "Specify disassembler style (e.g. -M intel for intel syntax)"), 284 "Specify disassembler style (e.g. -M intel for intel syntax)"),
277 OPT_END() 285 OPT_END()
278}; 286 };
279 287
280int cmd_annotate(int argc, const char **argv, const char *prefix __used)
281{
282 argc = parse_options(argc, argv, options, annotate_usage, 0); 288 argc = parse_options(argc, argv, options, annotate_usage, 0);
283 289
284 if (annotate.use_stdio) 290 if (annotate.use_stdio)
@@ -312,5 +318,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
312 return -1; 318 return -1;
313 } 319 }
314 320
315 return __cmd_annotate(); 321 return __cmd_annotate(&annotate);
316} 322}
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index b39f3a1ee7dc..9a0872f9e837 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -30,7 +30,8 @@ static int hists__add_entry(struct hists *self,
30 return -ENOMEM; 30 return -ENOMEM;
31} 31}
32 32
33static int diff__process_sample_event(union perf_event *event, 33static int diff__process_sample_event(struct perf_event_ops *ops __used,
34 union perf_event *event,
34 struct perf_sample *sample, 35 struct perf_sample *sample,
35 struct perf_evsel *evsel __used, 36 struct perf_evsel *evsel __used,
36 struct perf_session *session) 37 struct perf_session *session)
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 978751ec64ce..6ce6d80b59db 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -16,7 +16,8 @@
16static char const *input_name = "-"; 16static char const *input_name = "-";
17static bool inject_build_ids; 17static bool inject_build_ids;
18 18
19static int perf_event__repipe_synth(union perf_event *event, 19static int perf_event__repipe_synth(struct perf_event_ops *ops __used,
20 union perf_event *event,
20 struct perf_session *session __used) 21 struct perf_session *session __used)
21{ 22{
22 uint32_t size; 23 uint32_t size;
@@ -36,47 +37,57 @@ static int perf_event__repipe_synth(union perf_event *event,
36 return 0; 37 return 0;
37} 38}
38 39
40static int perf_event__repipe_tracing_data_synth(union perf_event *event,
41 struct perf_session *session)
42{
43 return perf_event__repipe_synth(NULL, event, session);
44}
45
39static int perf_event__repipe_attr(union perf_event *event, 46static int perf_event__repipe_attr(union perf_event *event,
40 struct perf_evlist **pevlist __used) 47 struct perf_evlist **pevlist __used)
41{ 48{
42 return perf_event__repipe_synth(event, NULL); 49 return perf_event__repipe_synth(NULL, event, NULL);
43} 50}
44 51
45static int perf_event__repipe(union perf_event *event, 52static int perf_event__repipe(struct perf_event_ops *ops,
53 union perf_event *event,
46 struct perf_sample *sample __used, 54 struct perf_sample *sample __used,
47 struct perf_session *session) 55 struct perf_session *session)
48{ 56{
49 return perf_event__repipe_synth(event, session); 57 return perf_event__repipe_synth(ops, event, session);
50} 58}
51 59
52static int perf_event__repipe_sample(union perf_event *event, 60static int perf_event__repipe_sample(struct perf_event_ops *ops,
61 union perf_event *event,
53 struct perf_sample *sample __used, 62 struct perf_sample *sample __used,
54 struct perf_evsel *evsel __used, 63 struct perf_evsel *evsel __used,
55 struct perf_session *session) 64 struct perf_session *session)
56{ 65{
57 return perf_event__repipe_synth(event, session); 66 return perf_event__repipe_synth(ops, event, session);
58} 67}
59 68
60static int perf_event__repipe_mmap(union perf_event *event, 69static int perf_event__repipe_mmap(struct perf_event_ops *ops,
70 union perf_event *event,
61 struct perf_sample *sample, 71 struct perf_sample *sample,
62 struct perf_session *session) 72 struct perf_session *session)
63{ 73{
64 int err; 74 int err;
65 75
66 err = perf_event__process_mmap(event, sample, session); 76 err = perf_event__process_mmap(ops, event, sample, session);
67 perf_event__repipe(event, sample, session); 77 perf_event__repipe(ops, event, sample, session);
68 78
69 return err; 79 return err;
70} 80}
71 81
72static int perf_event__repipe_task(union perf_event *event, 82static int perf_event__repipe_task(struct perf_event_ops *ops,
83 union perf_event *event,
73 struct perf_sample *sample, 84 struct perf_sample *sample,
74 struct perf_session *session) 85 struct perf_session *session)
75{ 86{
76 int err; 87 int err;
77 88
78 err = perf_event__process_task(event, sample, session); 89 err = perf_event__process_task(ops, event, sample, session);
79 perf_event__repipe(event, sample, session); 90 perf_event__repipe(ops, event, sample, session);
80 91
81 return err; 92 return err;
82} 93}
@@ -86,7 +97,7 @@ static int perf_event__repipe_tracing_data(union perf_event *event,
86{ 97{
87 int err; 98 int err;
88 99
89 perf_event__repipe_synth(event, session); 100 perf_event__repipe_synth(NULL, event, session);
90 err = perf_event__process_tracing_data(event, session); 101 err = perf_event__process_tracing_data(event, session);
91 102
92 return err; 103 return err;
@@ -106,7 +117,8 @@ static int dso__read_build_id(struct dso *self)
106 return -1; 117 return -1;
107} 118}
108 119
109static int dso__inject_build_id(struct dso *self, struct perf_session *session) 120static int dso__inject_build_id(struct dso *self, struct perf_event_ops *ops,
121 struct perf_session *session)
110{ 122{
111 u16 misc = PERF_RECORD_MISC_USER; 123 u16 misc = PERF_RECORD_MISC_USER;
112 struct machine *machine; 124 struct machine *machine;
@@ -126,7 +138,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
126 if (self->kernel) 138 if (self->kernel)
127 misc = PERF_RECORD_MISC_KERNEL; 139 misc = PERF_RECORD_MISC_KERNEL;
128 140
129 err = perf_event__synthesize_build_id(self, misc, perf_event__repipe, 141 err = perf_event__synthesize_build_id(ops, self, misc, perf_event__repipe,
130 machine, session); 142 machine, session);
131 if (err) { 143 if (err) {
132 pr_err("Can't synthesize build_id event for %s\n", self->long_name); 144 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 return 0; 148 return 0;
137} 149}
138 150
139static int perf_event__inject_buildid(union perf_event *event, 151static int perf_event__inject_buildid(struct perf_event_ops *ops,
152 union perf_event *event,
140 struct perf_sample *sample, 153 struct perf_sample *sample,
141 struct perf_evsel *evsel __used, 154 struct perf_evsel *evsel __used,
142 struct perf_session *session) 155 struct perf_session *session)
@@ -161,7 +174,7 @@ static int perf_event__inject_buildid(union perf_event *event,
161 if (!al.map->dso->hit) { 174 if (!al.map->dso->hit) {
162 al.map->dso->hit = 1; 175 al.map->dso->hit = 1;
163 if (map__load(al.map, NULL) >= 0) { 176 if (map__load(al.map, NULL) >= 0) {
164 dso__inject_build_id(al.map->dso, session); 177 dso__inject_build_id(al.map->dso, ops, session);
165 /* 178 /*
166 * If this fails, too bad, let the other side 179 * If this fails, too bad, let the other side
167 * account this as unresolved. 180 * account this as unresolved.
@@ -174,7 +187,7 @@ static int perf_event__inject_buildid(union perf_event *event,
174 } 187 }
175 188
176repipe: 189repipe:
177 perf_event__repipe(event, sample, session); 190 perf_event__repipe(ops, event, sample, session);
178 return 0; 191 return 0;
179} 192}
180 193
@@ -189,9 +202,9 @@ struct perf_event_ops inject_ops = {
189 .throttle = perf_event__repipe, 202 .throttle = perf_event__repipe,
190 .unthrottle = perf_event__repipe, 203 .unthrottle = perf_event__repipe,
191 .attr = perf_event__repipe_attr, 204 .attr = perf_event__repipe_attr,
192 .event_type = perf_event__repipe_synth, 205 .event_type = perf_event__repipe_synth,
193 .tracing_data = perf_event__repipe_synth, 206 .tracing_data = perf_event__repipe_tracing_data_synth,
194 .build_id = perf_event__repipe_synth, 207 .build_id = perf_event__repipe_synth,
195}; 208};
196 209
197extern volatile int session_done; 210extern volatile int session_done;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 225e963df105..5d01218e50e0 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -303,7 +303,8 @@ static void process_raw_event(union perf_event *raw_event __used, void *data,
303 } 303 }
304} 304}
305 305
306static int process_sample_event(union perf_event *event, 306static int process_sample_event(struct perf_event_ops *ops __used,
307 union perf_event *event,
307 struct perf_sample *sample, 308 struct perf_sample *sample,
308 struct perf_evsel *evsel __used, 309 struct perf_evsel *evsel __used,
309 struct perf_session *session) 310 struct perf_session *session)
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 899080ace267..f06b0a44c7cb 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -845,7 +845,8 @@ static void dump_info(void)
845 die("Unknown type of information\n"); 845 die("Unknown type of information\n");
846} 846}
847 847
848static int process_sample_event(union perf_event *event, 848static int process_sample_event(struct perf_event_ops *ops __used,
849 union perf_event *event,
849 struct perf_sample *sample, 850 struct perf_sample *sample,
850 struct perf_evsel *evsel __used, 851 struct perf_evsel *evsel __used,
851 struct perf_session *s) 852 struct perf_session *s)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ba6777a147ca..4642d38b8d19 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -35,43 +35,36 @@ enum write_mode_t {
35 WRITE_APPEND 35 WRITE_APPEND
36}; 36};
37 37
38struct perf_record_opts record_opts = { 38struct perf_record {
39 .target_pid = -1, 39 struct perf_event_ops ops;
40 .target_tid = -1, 40 struct perf_record_opts opts;
41 .mmap_pages = UINT_MAX, 41 u64 bytes_written;
42 .user_freq = UINT_MAX, 42 const char *output_name;
43 .user_interval = ULLONG_MAX, 43 struct perf_evlist *evlist;
44 .freq = 1000, 44 struct perf_session *session;
45 .sample_id_all_avail = true, 45 const char *progname;
46 int output;
47 unsigned int page_size;
48 int realtime_prio;
49 enum write_mode_t write_mode;
50 bool no_buildid;
51 bool no_buildid_cache;
52 bool force;
53 bool file_new;
54 bool append_file;
55 long samples;
56 off_t post_processing_offset;
46}; 57};
47 58
48static unsigned int page_size; 59static void advance_output(struct perf_record *rec, size_t size)
49static int output;
50static const char *output_name = NULL;
51static int realtime_prio = 0;
52static enum write_mode_t write_mode = WRITE_FORCE;
53static bool no_buildid = false;
54static bool no_buildid_cache = false;
55static struct perf_evlist *evsel_list;
56
57static long samples = 0;
58static u64 bytes_written = 0;
59
60static int file_new = 1;
61static off_t post_processing_offset;
62
63static struct perf_session *session;
64static const char *progname;
65
66static void advance_output(size_t size)
67{ 60{
68 bytes_written += size; 61 rec->bytes_written += size;
69} 62}
70 63
71static void write_output(void *buf, size_t size) 64static void write_output(struct perf_record *rec, void *buf, size_t size)
72{ 65{
73 while (size) { 66 while (size) {
74 int ret = write(output, buf, size); 67 int ret = write(rec->output, buf, size);
75 68
76 if (ret < 0) 69 if (ret < 0)
77 die("failed to write"); 70 die("failed to write");
@@ -79,30 +72,33 @@ static void write_output(void *buf, size_t size)
79 size -= ret; 72 size -= ret;
80 buf += ret; 73 buf += ret;
81 74
82 bytes_written += ret; 75 rec->bytes_written += ret;
83 } 76 }
84} 77}
85 78
86static int process_synthesized_event(union perf_event *event, 79static int process_synthesized_event(struct perf_event_ops *ops,
80 union perf_event *event,
87 struct perf_sample *sample __used, 81 struct perf_sample *sample __used,
88 struct perf_session *self __used) 82 struct perf_session *self __used)
89{ 83{
90 write_output(event, event->header.size); 84 struct perf_record *rec = container_of(ops, struct perf_record, ops);
85 write_output(rec, event, event->header.size);
91 return 0; 86 return 0;
92} 87}
93 88
94static void mmap_read(struct perf_mmap *md) 89static void perf_record__mmap_read(struct perf_record *rec,
90 struct perf_mmap *md)
95{ 91{
96 unsigned int head = perf_mmap__read_head(md); 92 unsigned int head = perf_mmap__read_head(md);
97 unsigned int old = md->prev; 93 unsigned int old = md->prev;
98 unsigned char *data = md->base + page_size; 94 unsigned char *data = md->base + rec->page_size;
99 unsigned long size; 95 unsigned long size;
100 void *buf; 96 void *buf;
101 97
102 if (old == head) 98 if (old == head)
103 return; 99 return;
104 100
105 samples++; 101 rec->samples++;
106 102
107 size = head - old; 103 size = head - old;
108 104
@@ -111,14 +107,14 @@ static void mmap_read(struct perf_mmap *md)
111 size = md->mask + 1 - (old & md->mask); 107 size = md->mask + 1 - (old & md->mask);
112 old += size; 108 old += size;
113 109
114 write_output(buf, size); 110 write_output(rec, buf, size);
115 } 111 }
116 112
117 buf = &data[old & md->mask]; 113 buf = &data[old & md->mask];
118 size = head - old; 114 size = head - old;
119 old += size; 115 old += size;
120 116
121 write_output(buf, size); 117 write_output(rec, buf, size);
122 118
123 md->prev = old; 119 md->prev = old;
124 perf_mmap__write_tail(md, old); 120 perf_mmap__write_tail(md, old);
@@ -137,17 +133,18 @@ static void sig_handler(int sig)
137 signr = sig; 133 signr = sig;
138} 134}
139 135
140static void sig_atexit(void) 136static void perf_record__sig_exit(int exit_status __used, void *arg)
141{ 137{
138 struct perf_record *rec = arg;
142 int status; 139 int status;
143 140
144 if (evsel_list->workload.pid > 0) { 141 if (rec->evlist->workload.pid > 0) {
145 if (!child_finished) 142 if (!child_finished)
146 kill(evsel_list->workload.pid, SIGTERM); 143 kill(rec->evlist->workload.pid, SIGTERM);
147 144
148 wait(&status); 145 wait(&status);
149 if (WIFSIGNALED(status)) 146 if (WIFSIGNALED(status))
150 psignal(WTERMSIG(status), progname); 147 psignal(WTERMSIG(status), rec->progname);
151 } 148 }
152 149
153 if (signr == -1 || signr == SIGUSR1) 150 if (signr == -1 || signr == SIGUSR1)
@@ -176,13 +173,16 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
176 return true; 173 return true;
177} 174}
178 175
179static void open_counters(struct perf_evlist *evlist) 176static void perf_record__open(struct perf_record *rec)
180{ 177{
181 struct perf_evsel *pos, *first; 178 struct perf_evsel *pos, *first;
179 struct perf_evlist *evlist = rec->evlist;
180 struct perf_session *session = rec->session;
181 struct perf_record_opts *opts = &rec->opts;
182 182
183 first = list_entry(evlist->entries.next, struct perf_evsel, node); 183 first = list_entry(evlist->entries.next, struct perf_evsel, node);
184 184
185 perf_evlist__config_attrs(evlist, &record_opts); 185 perf_evlist__config_attrs(evlist, opts);
186 186
187 list_for_each_entry(pos, &evlist->entries, node) { 187 list_for_each_entry(pos, &evlist->entries, node) {
188 struct perf_event_attr *attr = &pos->attr; 188 struct perf_event_attr *attr = &pos->attr;
@@ -201,27 +201,27 @@ static void open_counters(struct perf_evlist *evlist)
201 */ 201 */
202 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; 202 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
203 203
204 if (record_opts.group && pos != first) 204 if (opts->group && pos != first)
205 group_fd = first->fd; 205 group_fd = first->fd;
206retry_sample_id: 206retry_sample_id:
207 attr->sample_id_all = record_opts.sample_id_all_avail ? 1 : 0; 207 attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
208try_again: 208try_again:
209 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, 209 if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
210 record_opts.group, group_fd) < 0) { 210 opts->group, group_fd) < 0) {
211 int err = errno; 211 int err = errno;
212 212
213 if (err == EPERM || err == EACCES) { 213 if (err == EPERM || err == EACCES) {
214 ui__error_paranoid(); 214 ui__error_paranoid();
215 exit(EXIT_FAILURE); 215 exit(EXIT_FAILURE);
216 } else if (err == ENODEV && record_opts.cpu_list) { 216 } else if (err == ENODEV && opts->cpu_list) {
217 die("No such device - did you specify" 217 die("No such device - did you specify"
218 " an out-of-range profile CPU?\n"); 218 " an out-of-range profile CPU?\n");
219 } else if (err == EINVAL && record_opts.sample_id_all_avail) { 219 } else if (err == EINVAL && opts->sample_id_all_avail) {
220 /* 220 /*
221 * Old kernel, no attr->sample_id_type_all field 221 * Old kernel, no attr->sample_id_type_all field
222 */ 222 */
223 record_opts.sample_id_all_avail = false; 223 opts->sample_id_all_avail = false;
224 if (!record_opts.sample_time && !record_opts.raw_samples && !time_needed) 224 if (!opts->sample_time && !opts->raw_samples && !time_needed)
225 attr->sample_type &= ~PERF_SAMPLE_TIME; 225 attr->sample_type &= ~PERF_SAMPLE_TIME;
226 226
227 goto retry_sample_id; 227 goto retry_sample_id;
@@ -271,10 +271,10 @@ try_again:
271 exit(-1); 271 exit(-1);
272 } 272 }
273 273
274 if (perf_evlist__mmap(evlist, record_opts.mmap_pages, false) < 0) 274 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0)
275 die("failed to mmap with %d (%s)\n", errno, strerror(errno)); 275 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
276 276
277 if (file_new) 277 if (rec->file_new)
278 session->evlist = evlist; 278 session->evlist = evlist;
279 else { 279 else {
280 if (!perf_evlist__equal(session->evlist, evlist)) { 280 if (!perf_evlist__equal(session->evlist, evlist)) {
@@ -286,29 +286,32 @@ try_again:
286 perf_session__update_sample_type(session); 286 perf_session__update_sample_type(session);
287} 287}
288 288
289static int process_buildids(void) 289static int process_buildids(struct perf_record *rec)
290{ 290{
291 u64 size = lseek(output, 0, SEEK_CUR); 291 u64 size = lseek(rec->output, 0, SEEK_CUR);
292 292
293 if (size == 0) 293 if (size == 0)
294 return 0; 294 return 0;
295 295
296 session->fd = output; 296 rec->session->fd = rec->output;
297 return __perf_session__process_events(session, post_processing_offset, 297 return __perf_session__process_events(rec->session, rec->post_processing_offset,
298 size - post_processing_offset, 298 size - rec->post_processing_offset,
299 size, &build_id__mark_dso_hit_ops); 299 size, &build_id__mark_dso_hit_ops);
300} 300}
301 301
302static void atexit_header(void) 302static void perf_record__exit(int status __used, void *arg)
303{ 303{
304 if (!record_opts.pipe_output) { 304 struct perf_record *rec = arg;
305 session->header.data_size += bytes_written; 305
306 306 if (!rec->opts.pipe_output) {
307 if (!no_buildid) 307 rec->session->header.data_size += rec->bytes_written;
308 process_buildids(); 308
309 perf_session__write_header(session, evsel_list, output, true); 309 if (!rec->no_buildid)
310 perf_session__delete(session); 310 process_buildids(rec);
311 perf_evlist__delete(evsel_list); 311 perf_session__write_header(rec->session, rec->evlist,
312 rec->output, true);
313 perf_session__delete(rec->session);
314 perf_evlist__delete(rec->evlist);
312 symbol__exit(); 315 symbol__exit();
313 } 316 }
314} 317}
@@ -316,7 +319,9 @@ static void atexit_header(void)
316static void perf_event__synthesize_guest_os(struct machine *machine, void *data) 319static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
317{ 320{
318 int err; 321 int err;
319 struct perf_session *psession = data; 322 struct perf_event_ops *ops = data;
323 struct perf_record *rec = container_of(ops, struct perf_record, ops);
324 struct perf_session *psession = rec->session;
320 325
321 if (machine__is_host(machine)) 326 if (machine__is_host(machine))
322 return; 327 return;
@@ -329,7 +334,7 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
329 *method is used to avoid symbol missing when the first addr is 334 *method is used to avoid symbol missing when the first addr is
330 *in module instead of in guest kernel. 335 *in module instead of in guest kernel.
331 */ 336 */
332 err = perf_event__synthesize_modules(process_synthesized_event, 337 err = perf_event__synthesize_modules(ops, process_synthesized_event,
333 psession, machine); 338 psession, machine);
334 if (err < 0) 339 if (err < 0)
335 pr_err("Couldn't record guest kernel [%d]'s reference" 340 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 * We use _stext for guest kernel because guest kernel's /proc/kallsyms 344 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
340 * have no _text sometimes. 345 * have no _text sometimes.
341 */ 346 */
342 err = perf_event__synthesize_kernel_mmap(process_synthesized_event, 347 err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
343 psession, machine, "_text"); 348 psession, machine, "_text");
344 if (err < 0) 349 if (err < 0)
345 err = perf_event__synthesize_kernel_mmap(process_synthesized_event, 350 err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
346 psession, machine, 351 psession, machine,
347 "_stext"); 352 "_stext");
348 if (err < 0) 353 if (err < 0)
@@ -355,66 +360,71 @@ static struct perf_event_header finished_round_event = {
355 .type = PERF_RECORD_FINISHED_ROUND, 360 .type = PERF_RECORD_FINISHED_ROUND,
356}; 361};
357 362
358static void mmap_read_all(void) 363static void perf_record__mmap_read_all(struct perf_record *rec)
359{ 364{
360 int i; 365 int i;
361 366
362 for (i = 0; i < evsel_list->nr_mmaps; i++) { 367 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
363 if (evsel_list->mmap[i].base) 368 if (rec->evlist->mmap[i].base)
364 mmap_read(&evsel_list->mmap[i]); 369 perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
365 } 370 }
366 371
367 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) 372 if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
368 write_output(&finished_round_event, sizeof(finished_round_event)); 373 write_output(rec, &finished_round_event, sizeof(finished_round_event));
369} 374}
370 375
371static int __cmd_record(int argc, const char **argv) 376static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
372{ 377{
373 struct stat st; 378 struct stat st;
374 int flags; 379 int flags;
375 int err; 380 int err, output;
376 unsigned long waking = 0; 381 unsigned long waking = 0;
377 const bool forks = argc > 0; 382 const bool forks = argc > 0;
378 struct machine *machine; 383 struct machine *machine;
384 struct perf_event_ops *ops = &rec->ops;
385 struct perf_record_opts *opts = &rec->opts;
386 struct perf_evlist *evsel_list = rec->evlist;
387 const char *output_name = rec->output_name;
388 struct perf_session *session;
379 389
380 progname = argv[0]; 390 rec->progname = argv[0];
381 391
382 page_size = sysconf(_SC_PAGE_SIZE); 392 rec->page_size = sysconf(_SC_PAGE_SIZE);
383 393
384 atexit(sig_atexit); 394 on_exit(perf_record__sig_exit, rec);
385 signal(SIGCHLD, sig_handler); 395 signal(SIGCHLD, sig_handler);
386 signal(SIGINT, sig_handler); 396 signal(SIGINT, sig_handler);
387 signal(SIGUSR1, sig_handler); 397 signal(SIGUSR1, sig_handler);
388 398
389 if (!output_name) { 399 if (!output_name) {
390 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) 400 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
391 record_opts.pipe_output = true; 401 opts->pipe_output = true;
392 else 402 else
393 output_name = "perf.data"; 403 rec->output_name = output_name = "perf.data";
394 } 404 }
395 if (output_name) { 405 if (output_name) {
396 if (!strcmp(output_name, "-")) 406 if (!strcmp(output_name, "-"))
397 record_opts.pipe_output = true; 407 opts->pipe_output = true;
398 else if (!stat(output_name, &st) && st.st_size) { 408 else if (!stat(output_name, &st) && st.st_size) {
399 if (write_mode == WRITE_FORCE) { 409 if (rec->write_mode == WRITE_FORCE) {
400 char oldname[PATH_MAX]; 410 char oldname[PATH_MAX];
401 snprintf(oldname, sizeof(oldname), "%s.old", 411 snprintf(oldname, sizeof(oldname), "%s.old",
402 output_name); 412 output_name);
403 unlink(oldname); 413 unlink(oldname);
404 rename(output_name, oldname); 414 rename(output_name, oldname);
405 } 415 }
406 } else if (write_mode == WRITE_APPEND) { 416 } else if (rec->write_mode == WRITE_APPEND) {
407 write_mode = WRITE_FORCE; 417 rec->write_mode = WRITE_FORCE;
408 } 418 }
409 } 419 }
410 420
411 flags = O_CREAT|O_RDWR; 421 flags = O_CREAT|O_RDWR;
412 if (write_mode == WRITE_APPEND) 422 if (rec->write_mode == WRITE_APPEND)
413 file_new = 0; 423 rec->file_new = 0;
414 else 424 else
415 flags |= O_TRUNC; 425 flags |= O_TRUNC;
416 426
417 if (record_opts.pipe_output) 427 if (opts->pipe_output)
418 output = STDOUT_FILENO; 428 output = STDOUT_FILENO;
419 else 429 else
420 output = open(output_name, flags, S_IRUSR | S_IWUSR); 430 output = open(output_name, flags, S_IRUSR | S_IWUSR);
@@ -423,17 +433,21 @@ static int __cmd_record(int argc, const char **argv)
423 exit(-1); 433 exit(-1);
424 } 434 }
425 435
436 rec->output = output;
437
426 session = perf_session__new(output_name, O_WRONLY, 438 session = perf_session__new(output_name, O_WRONLY,
427 write_mode == WRITE_FORCE, false, NULL); 439 rec->write_mode == WRITE_FORCE, false, NULL);
428 if (session == NULL) { 440 if (session == NULL) {
429 pr_err("Not enough memory for reading perf file header\n"); 441 pr_err("Not enough memory for reading perf file header\n");
430 return -1; 442 return -1;
431 } 443 }
432 444
433 if (!no_buildid) 445 rec->session = session;
446
447 if (!rec->no_buildid)
434 perf_header__set_feat(&session->header, HEADER_BUILD_ID); 448 perf_header__set_feat(&session->header, HEADER_BUILD_ID);
435 449
436 if (!file_new) { 450 if (!rec->file_new) {
437 err = perf_session__read_header(session, output); 451 err = perf_session__read_header(session, output);
438 if (err < 0) 452 if (err < 0)
439 goto out_delete_session; 453 goto out_delete_session;
@@ -456,42 +470,42 @@ static int __cmd_record(int argc, const char **argv)
456 perf_header__set_feat(&session->header, HEADER_CPUID); 470 perf_header__set_feat(&session->header, HEADER_CPUID);
457 471
458 if (forks) { 472 if (forks) {
459 err = perf_evlist__prepare_workload(evsel_list, &record_opts, argv); 473 err = perf_evlist__prepare_workload(evsel_list, opts, argv);
460 if (err < 0) { 474 if (err < 0) {
461 pr_err("Couldn't run the workload!\n"); 475 pr_err("Couldn't run the workload!\n");
462 goto out_delete_session; 476 goto out_delete_session;
463 } 477 }
464 } 478 }
465 479
466 open_counters(evsel_list); 480 perf_record__open(rec);
467 481
468 /* 482 /*
469 * perf_session__delete(session) will be called at atexit_header() 483 * perf_session__delete(session) will be called at perf_record__exit()
470 */ 484 */
471 atexit(atexit_header); 485 on_exit(perf_record__exit, rec);
472 486
473 if (record_opts.pipe_output) { 487 if (opts->pipe_output) {
474 err = perf_header__write_pipe(output); 488 err = perf_header__write_pipe(output);
475 if (err < 0) 489 if (err < 0)
476 return err; 490 return err;
477 } else if (file_new) { 491 } else if (rec->file_new) {
478 err = perf_session__write_header(session, evsel_list, 492 err = perf_session__write_header(session, evsel_list,
479 output, false); 493 output, false);
480 if (err < 0) 494 if (err < 0)
481 return err; 495 return err;
482 } 496 }
483 497
484 post_processing_offset = lseek(output, 0, SEEK_CUR); 498 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
485 499
486 if (record_opts.pipe_output) { 500 if (opts->pipe_output) {
487 err = perf_session__synthesize_attrs(session, 501 err = perf_event__synthesize_attrs(ops, session,
488 process_synthesized_event); 502 process_synthesized_event);
489 if (err < 0) { 503 if (err < 0) {
490 pr_err("Couldn't synthesize attrs.\n"); 504 pr_err("Couldn't synthesize attrs.\n");
491 return err; 505 return err;
492 } 506 }
493 507
494 err = perf_event__synthesize_event_types(process_synthesized_event, 508 err = perf_event__synthesize_event_types(ops, process_synthesized_event,
495 session); 509 session);
496 if (err < 0) { 510 if (err < 0) {
497 pr_err("Couldn't synthesize event_types.\n"); 511 pr_err("Couldn't synthesize event_types.\n");
@@ -507,14 +521,14 @@ static int __cmd_record(int argc, const char **argv)
507 * return this more properly and also 521 * return this more properly and also
508 * propagate errors that now are calling die() 522 * propagate errors that now are calling die()
509 */ 523 */
510 err = perf_event__synthesize_tracing_data(output, evsel_list, 524 err = perf_event__synthesize_tracing_data(ops, output, evsel_list,
511 process_synthesized_event, 525 process_synthesized_event,
512 session); 526 session);
513 if (err <= 0) { 527 if (err <= 0) {
514 pr_err("Couldn't record tracing data.\n"); 528 pr_err("Couldn't record tracing data.\n");
515 return err; 529 return err;
516 } 530 }
517 advance_output(err); 531 advance_output(rec, err);
518 } 532 }
519 } 533 }
520 534
@@ -524,17 +538,17 @@ static int __cmd_record(int argc, const char **argv)
524 return -1; 538 return -1;
525 } 539 }
526 540
527 err = perf_event__synthesize_kernel_mmap(process_synthesized_event, 541 err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
528 session, machine, "_text"); 542 session, machine, "_text");
529 if (err < 0) 543 if (err < 0)
530 err = perf_event__synthesize_kernel_mmap(process_synthesized_event, 544 err = perf_event__synthesize_kernel_mmap(ops, process_synthesized_event,
531 session, machine, "_stext"); 545 session, machine, "_stext");
532 if (err < 0) 546 if (err < 0)
533 pr_err("Couldn't record kernel reference relocation symbol\n" 547 pr_err("Couldn't record kernel reference relocation symbol\n"
534 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 548 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
535 "Check /proc/kallsyms permission or run as root.\n"); 549 "Check /proc/kallsyms permission or run as root.\n");
536 550
537 err = perf_event__synthesize_modules(process_synthesized_event, 551 err = perf_event__synthesize_modules(ops, process_synthesized_event,
538 session, machine); 552 session, machine);
539 if (err < 0) 553 if (err < 0)
540 pr_err("Couldn't record kernel module information.\n" 554 pr_err("Couldn't record kernel module information.\n"
@@ -542,21 +556,21 @@ static int __cmd_record(int argc, const char **argv)
542 "Check /proc/modules permission or run as root.\n"); 556 "Check /proc/modules permission or run as root.\n");
543 557
544 if (perf_guest) 558 if (perf_guest)
545 perf_session__process_machines(session, 559 perf_session__process_machines(session, ops,
546 perf_event__synthesize_guest_os); 560 perf_event__synthesize_guest_os);
547 561
548 if (!record_opts.system_wide) 562 if (!opts->system_wide)
549 perf_event__synthesize_thread_map(evsel_list->threads, 563 perf_event__synthesize_thread_map(ops, evsel_list->threads,
550 process_synthesized_event, 564 process_synthesized_event,
551 session); 565 session);
552 else 566 else
553 perf_event__synthesize_threads(process_synthesized_event, 567 perf_event__synthesize_threads(ops, process_synthesized_event,
554 session); 568 session);
555 569
556 if (realtime_prio) { 570 if (rec->realtime_prio) {
557 struct sched_param param; 571 struct sched_param param;
558 572
559 param.sched_priority = realtime_prio; 573 param.sched_priority = rec->realtime_prio;
560 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 574 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
561 pr_err("Could not set realtime priority.\n"); 575 pr_err("Could not set realtime priority.\n");
562 exit(-1); 576 exit(-1);
@@ -572,11 +586,11 @@ static int __cmd_record(int argc, const char **argv)
572 perf_evlist__start_workload(evsel_list); 586 perf_evlist__start_workload(evsel_list);
573 587
574 for (;;) { 588 for (;;) {
575 int hits = samples; 589 int hits = rec->samples;
576 590
577 mmap_read_all(); 591 perf_record__mmap_read_all(rec);
578 592
579 if (hits == samples) { 593 if (hits == rec->samples) {
580 if (done) 594 if (done)
581 break; 595 break;
582 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); 596 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
@@ -597,9 +611,9 @@ static int __cmd_record(int argc, const char **argv)
597 */ 611 */
598 fprintf(stderr, 612 fprintf(stderr,
599 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", 613 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
600 (double)bytes_written / 1024.0 / 1024.0, 614 (double)rec->bytes_written / 1024.0 / 1024.0,
601 output_name, 615 output_name,
602 bytes_written / 24); 616 rec->bytes_written / 24);
603 617
604 return 0; 618 return 0;
605 619
@@ -614,59 +628,88 @@ static const char * const record_usage[] = {
614 NULL 628 NULL
615}; 629};
616 630
617static bool force, append_file; 631/*
632 * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
633 * because we need to have access to it in perf_record__exit, that is called
634 * after cmd_record() exits, but since record_options need to be accessible to
635 * builtin-script, leave it here.
636 *
637 * At least we don't ouch it in all the other functions here directly.
638 *
639 * Just say no to tons of global variables, sigh.
640 */
641static struct perf_record record = {
642 .opts = {
643 .target_pid = -1,
644 .target_tid = -1,
645 .mmap_pages = UINT_MAX,
646 .user_freq = UINT_MAX,
647 .user_interval = ULLONG_MAX,
648 .freq = 1000,
649 .sample_id_all_avail = true,
650 },
651 .write_mode = WRITE_FORCE,
652 .file_new = true,
653};
618 654
655/*
656 * XXX Will stay a global variable till we fix builtin-script.c to stop messing
657 * with it and switch to use the library functions in perf_evlist that came
658 * from builtin-record.c, i.e. use perf_record_opts,
659 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
660 * using pipes, etc.
661 */
619const struct option record_options[] = { 662const struct option record_options[] = {
620 OPT_CALLBACK('e', "event", &evsel_list, "event", 663 OPT_CALLBACK('e', "event", &record.evlist, "event",
621 "event selector. use 'perf list' to list available events", 664 "event selector. use 'perf list' to list available events",
622 parse_events_option), 665 parse_events_option),
623 OPT_CALLBACK(0, "filter", &evsel_list, "filter", 666 OPT_CALLBACK(0, "filter", &record.evlist, "filter",
624 "event filter", parse_filter), 667 "event filter", parse_filter),
625 OPT_INTEGER('p', "pid", &record_opts.target_pid, 668 OPT_INTEGER('p', "pid", &record.opts.target_pid,
626 "record events on existing process id"), 669 "record events on existing process id"),
627 OPT_INTEGER('t', "tid", &record_opts.target_tid, 670 OPT_INTEGER('t', "tid", &record.opts.target_tid,
628 "record events on existing thread id"), 671 "record events on existing thread id"),
629 OPT_INTEGER('r', "realtime", &realtime_prio, 672 OPT_INTEGER('r', "realtime", &record.realtime_prio,
630 "collect data with this RT SCHED_FIFO priority"), 673 "collect data with this RT SCHED_FIFO priority"),
631 OPT_BOOLEAN('D', "no-delay", &record_opts.no_delay, 674 OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
632 "collect data without buffering"), 675 "collect data without buffering"),
633 OPT_BOOLEAN('R', "raw-samples", &record_opts.raw_samples, 676 OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
634 "collect raw sample records from all opened counters"), 677 "collect raw sample records from all opened counters"),
635 OPT_BOOLEAN('a', "all-cpus", &record_opts.system_wide, 678 OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
636 "system-wide collection from all CPUs"), 679 "system-wide collection from all CPUs"),
637 OPT_BOOLEAN('A', "append", &append_file, 680 OPT_BOOLEAN('A', "append", &record.append_file,
638 "append to the output file to do incremental profiling"), 681 "append to the output file to do incremental profiling"),
639 OPT_STRING('C', "cpu", &record_opts.cpu_list, "cpu", 682 OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
640 "list of cpus to monitor"), 683 "list of cpus to monitor"),
641 OPT_BOOLEAN('f', "force", &force, 684 OPT_BOOLEAN('f', "force", &record.force,
642 "overwrite existing data file (deprecated)"), 685 "overwrite existing data file (deprecated)"),
643 OPT_U64('c', "count", &record_opts.user_interval, "event period to sample"), 686 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
644 OPT_STRING('o', "output", &output_name, "file", 687 OPT_STRING('o', "output", &record.output_name, "file",
645 "output file name"), 688 "output file name"),
646 OPT_BOOLEAN('i', "no-inherit", &record_opts.no_inherit, 689 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
647 "child tasks do not inherit counters"), 690 "child tasks do not inherit counters"),
648 OPT_UINTEGER('F', "freq", &record_opts.user_freq, "profile at this frequency"), 691 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
649 OPT_UINTEGER('m', "mmap-pages", &record_opts.mmap_pages, 692 OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
650 "number of mmap data pages"), 693 "number of mmap data pages"),
651 OPT_BOOLEAN(0, "group", &record_opts.group, 694 OPT_BOOLEAN(0, "group", &record.opts.group,
652 "put the counters into a counter group"), 695 "put the counters into a counter group"),
653 OPT_BOOLEAN('g', "call-graph", &record_opts.call_graph, 696 OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
654 "do call-graph (stack chain/backtrace) recording"), 697 "do call-graph (stack chain/backtrace) recording"),
655 OPT_INCR('v', "verbose", &verbose, 698 OPT_INCR('v', "verbose", &verbose,
656 "be more verbose (show counter open errors, etc)"), 699 "be more verbose (show counter open errors, etc)"),
657 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 700 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
658 OPT_BOOLEAN('s', "stat", &record_opts.inherit_stat, 701 OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
659 "per thread counts"), 702 "per thread counts"),
660 OPT_BOOLEAN('d', "data", &record_opts.sample_address, 703 OPT_BOOLEAN('d', "data", &record.opts.sample_address,
661 "Sample addresses"), 704 "Sample addresses"),
662 OPT_BOOLEAN('T', "timestamp", &record_opts.sample_time, "Sample timestamps"), 705 OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
663 OPT_BOOLEAN('n', "no-samples", &record_opts.no_samples, 706 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
664 "don't sample"), 707 "don't sample"),
665 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache, 708 OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
666 "do not update the buildid cache"), 709 "do not update the buildid cache"),
667 OPT_BOOLEAN('B', "no-buildid", &no_buildid, 710 OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
668 "do not collect buildids in perf.data"), 711 "do not collect buildids in perf.data"),
669 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 712 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
670 "monitor event in cgroup name only", 713 "monitor event in cgroup name only",
671 parse_cgroups), 714 parse_cgroups),
672 OPT_END() 715 OPT_END()
@@ -676,6 +719,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
676{ 719{
677 int err = -ENOMEM; 720 int err = -ENOMEM;
678 struct perf_evsel *pos; 721 struct perf_evsel *pos;
722 struct perf_evlist *evsel_list;
723 struct perf_record *rec = &record;
679 724
680 perf_header__set_cmdline(argc, argv); 725 perf_header__set_cmdline(argc, argv);
681 726
@@ -683,23 +728,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
683 if (evsel_list == NULL) 728 if (evsel_list == NULL)
684 return -ENOMEM; 729 return -ENOMEM;
685 730
731 rec->evlist = evsel_list;
732
686 argc = parse_options(argc, argv, record_options, record_usage, 733 argc = parse_options(argc, argv, record_options, record_usage,
687 PARSE_OPT_STOP_AT_NON_OPTION); 734 PARSE_OPT_STOP_AT_NON_OPTION);
688 if (!argc && record_opts.target_pid == -1 && record_opts.target_tid == -1 && 735 if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
689 !record_opts.system_wide && !record_opts.cpu_list) 736 !rec->opts.system_wide && !rec->opts.cpu_list)
690 usage_with_options(record_usage, record_options); 737 usage_with_options(record_usage, record_options);
691 738
692 if (force && append_file) { 739 if (rec->force && rec->append_file) {
693 fprintf(stderr, "Can't overwrite and append at the same time." 740 fprintf(stderr, "Can't overwrite and append at the same time."
694 " You need to choose between -f and -A"); 741 " You need to choose between -f and -A");
695 usage_with_options(record_usage, record_options); 742 usage_with_options(record_usage, record_options);
696 } else if (append_file) { 743 } else if (rec->append_file) {
697 write_mode = WRITE_APPEND; 744 rec->write_mode = WRITE_APPEND;
698 } else { 745 } else {
699 write_mode = WRITE_FORCE; 746 rec->write_mode = WRITE_FORCE;
700 } 747 }
701 748
702 if (nr_cgroups && !record_opts.system_wide) { 749 if (nr_cgroups && !rec->opts.system_wide) {
703 fprintf(stderr, "cgroup monitoring only available in" 750 fprintf(stderr, "cgroup monitoring only available in"
704 " system-wide mode\n"); 751 " system-wide mode\n");
705 usage_with_options(record_usage, record_options); 752 usage_with_options(record_usage, record_options);
@@ -717,7 +764,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
717"If some relocation was applied (e.g. kexec) symbols may be misresolved\n" 764"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
718"even with a suitable vmlinux or kallsyms file.\n\n"); 765"even with a suitable vmlinux or kallsyms file.\n\n");
719 766
720 if (no_buildid_cache || no_buildid) 767 if (rec->no_buildid_cache || rec->no_buildid)
721 disable_buildid_cache(); 768 disable_buildid_cache();
722 769
723 if (evsel_list->nr_entries == 0 && 770 if (evsel_list->nr_entries == 0 &&
@@ -726,11 +773,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
726 goto out_symbol_exit; 773 goto out_symbol_exit;
727 } 774 }
728 775
729 if (record_opts.target_pid != -1) 776 if (rec->opts.target_pid != -1)
730 record_opts.target_tid = record_opts.target_pid; 777 rec->opts.target_tid = rec->opts.target_pid;
731 778
732 if (perf_evlist__create_maps(evsel_list, record_opts.target_pid, 779 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
733 record_opts.target_tid, record_opts.cpu_list) < 0) 780 rec->opts.target_tid, rec->opts.cpu_list) < 0)
734 usage_with_options(record_usage, record_options); 781 usage_with_options(record_usage, record_options);
735 782
736 list_for_each_entry(pos, &evsel_list->entries, node) { 783 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 if (perf_evlist__alloc_pollfd(evsel_list) < 0) 791 if (perf_evlist__alloc_pollfd(evsel_list) < 0)
745 goto out_free_fd; 792 goto out_free_fd;
746 793
747 if (record_opts.user_interval != ULLONG_MAX) 794 if (rec->opts.user_interval != ULLONG_MAX)
748 record_opts.default_interval = record_opts.user_interval; 795 rec->opts.default_interval = rec->opts.user_interval;
749 if (record_opts.user_freq != UINT_MAX) 796 if (rec->opts.user_freq != UINT_MAX)
750 record_opts.freq = record_opts.user_freq; 797 rec->opts.freq = rec->opts.user_freq;
751 798
752 /* 799 /*
753 * User specified count overrides default frequency. 800 * User specified count overrides default frequency.
754 */ 801 */
755 if (record_opts.default_interval) 802 if (rec->opts.default_interval)
756 record_opts.freq = 0; 803 rec->opts.freq = 0;
757 else if (record_opts.freq) { 804 else if (rec->opts.freq) {
758 record_opts.default_interval = record_opts.freq; 805 rec->opts.default_interval = rec->opts.freq;
759 } else { 806 } else {
760 fprintf(stderr, "frequency and count are zero, aborting\n"); 807 fprintf(stderr, "frequency and count are zero, aborting\n");
761 err = -EINVAL; 808 err = -EINVAL;
762 goto out_free_fd; 809 goto out_free_fd;
763 } 810 }
764 811
765 err = __cmd_record(argc, argv); 812 err = __cmd_record(&record, argc, argv);
766out_free_fd: 813out_free_fd:
767 perf_evlist__delete_maps(evsel_list); 814 perf_evlist__delete_maps(evsel_list);
768out_symbol_exit: 815out_symbol_exit:
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 5d2e819dfc40..8795520f6e1d 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -35,7 +35,9 @@
35 35
36#include <linux/bitmap.h> 36#include <linux/bitmap.h>
37 37
38static struct perf_report { 38struct perf_report {
39 struct perf_event_ops ops;
40 struct perf_session *session;
39 char const *input_name; 41 char const *input_name;
40 bool force, use_tui, use_stdio; 42 bool force, use_tui, use_stdio;
41 bool hide_unresolved; 43 bool hide_unresolved;
@@ -48,12 +50,7 @@ static struct perf_report {
48 symbol_filter_t annotate_init; 50 symbol_filter_t annotate_init;
49 const char *cpu_list; 51 const char *cpu_list;
50 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 52 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
51} report = { 53};
52 .input_name = "perf.data",
53 .pretty_printing_style = "normal",
54}, *rep = &report;
55
56static char callchain_default_opt[] = "fractal,0.5,callee";
57 54
58static int perf_session__add_hist_entry(struct perf_session *session, 55static int perf_session__add_hist_entry(struct perf_session *session,
59 struct addr_location *al, 56 struct addr_location *al,
@@ -106,11 +103,13 @@ out:
106} 103}
107 104
108 105
109static int process_sample_event(union perf_event *event, 106static int process_sample_event(struct perf_event_ops *ops,
107 union perf_event *event,
110 struct perf_sample *sample, 108 struct perf_sample *sample,
111 struct perf_evsel *evsel, 109 struct perf_evsel *evsel,
112 struct perf_session *session) 110 struct perf_session *session)
113{ 111{
112 struct perf_report *rep = container_of(ops, struct perf_report, ops);
114 struct addr_location al; 113 struct addr_location al;
115 114
116 if (perf_event__preprocess_sample(event, session, &al, sample, 115 if (perf_event__preprocess_sample(event, session, &al, sample,
@@ -137,10 +136,12 @@ static int process_sample_event(union perf_event *event,
137 return 0; 136 return 0;
138} 137}
139 138
140static int process_read_event(union perf_event *event, 139static int process_read_event(struct perf_event_ops *ops,
140 union perf_event *event,
141 struct perf_sample *sample __used, 141 struct perf_sample *sample __used,
142 struct perf_session *session) 142 struct perf_session *session)
143{ 143{
144 struct perf_report *rep = container_of(ops, struct perf_report, ops);
144 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, 145 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist,
145 event->read.id); 146 event->read.id);
146 if (rep->show_threads) { 147 if (rep->show_threads) {
@@ -159,8 +160,10 @@ static int process_read_event(union perf_event *event,
159 return 0; 160 return 0;
160} 161}
161 162
162static int perf_session__setup_sample_type(struct perf_session *self) 163static int perf_report__setup_sample_type(struct perf_report *rep)
163{ 164{
165 struct perf_session *self = rep->session;
166
164 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { 167 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
165 if (sort__has_parent) { 168 if (sort__has_parent) {
166 ui__warning("Selected --sort parent, but no " 169 ui__warning("Selected --sort parent, but no "
@@ -187,22 +190,6 @@ static int perf_session__setup_sample_type(struct perf_session *self)
187 return 0; 190 return 0;
188} 191}
189 192
190static struct perf_event_ops event_ops = {
191 .sample = process_sample_event,
192 .mmap = perf_event__process_mmap,
193 .comm = perf_event__process_comm,
194 .exit = perf_event__process_task,
195 .fork = perf_event__process_task,
196 .lost = perf_event__process_lost,
197 .read = process_read_event,
198 .attr = perf_event__process_attr,
199 .event_type = perf_event__process_event_type,
200 .tracing_data = perf_event__process_tracing_data,
201 .build_id = perf_event__process_build_id,
202 .ordered_samples = true,
203 .ordering_requires_timestamps = true,
204};
205
206extern volatile int session_done; 193extern volatile int session_done;
207 194
208static void sig_handler(int sig __used) 195static void sig_handler(int sig __used)
@@ -225,6 +212,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
225} 212}
226 213
227static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, 214static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
215 struct perf_report *rep,
228 const char *help) 216 const char *help)
229{ 217{
230 struct perf_evsel *pos; 218 struct perf_evsel *pos;
@@ -253,7 +241,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
253 return 0; 241 return 0;
254} 242}
255 243
256static int __cmd_report(void) 244static int __cmd_report(struct perf_report *rep)
257{ 245{
258 int ret = -EINVAL; 246 int ret = -EINVAL;
259 u64 nr_samples; 247 u64 nr_samples;
@@ -266,10 +254,12 @@ static int __cmd_report(void)
266 signal(SIGINT, sig_handler); 254 signal(SIGINT, sig_handler);
267 255
268 session = perf_session__new(rep->input_name, O_RDONLY, 256 session = perf_session__new(rep->input_name, O_RDONLY,
269 rep->force, false, &event_ops); 257 rep->force, false, &rep->ops);
270 if (session == NULL) 258 if (session == NULL)
271 return -ENOMEM; 259 return -ENOMEM;
272 260
261 rep->session = session;
262
273 if (rep->cpu_list) { 263 if (rep->cpu_list) {
274 ret = perf_session__cpu_bitmap(session, rep->cpu_list, 264 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
275 rep->cpu_bitmap); 265 rep->cpu_bitmap);
@@ -283,11 +273,11 @@ static int __cmd_report(void)
283 if (rep->show_threads) 273 if (rep->show_threads)
284 perf_read_values_init(&rep->show_threads_values); 274 perf_read_values_init(&rep->show_threads_values);
285 275
286 ret = perf_session__setup_sample_type(session); 276 ret = perf_report__setup_sample_type(rep);
287 if (ret) 277 if (ret)
288 goto out_delete; 278 goto out_delete;
289 279
290 ret = perf_session__process_events(session, &event_ops); 280 ret = perf_session__process_events(session, &rep->ops);
291 if (ret) 281 if (ret)
292 goto out_delete; 282 goto out_delete;
293 283
@@ -339,7 +329,7 @@ static int __cmd_report(void)
339 perf_evlist__tui_browse_hists(session->evlist, help, 329 perf_evlist__tui_browse_hists(session->evlist, help,
340 NULL, NULL, 0); 330 NULL, NULL, 0);
341 } else 331 } else
342 perf_evlist__tty_browse_hists(session->evlist, help); 332 perf_evlist__tty_browse_hists(session->evlist, rep, help);
343 333
344out_delete: 334out_delete:
345 /* 335 /*
@@ -358,9 +348,9 @@ out_delete:
358} 348}
359 349
360static int 350static int
361parse_callchain_opt(const struct option *opt __used, const char *arg, 351parse_callchain_opt(const struct option *opt, const char *arg, int unset)
362 int unset)
363{ 352{
353 struct perf_report *rep = (struct perf_report *)opt->value;
364 char *tok, *tok2; 354 char *tok, *tok2;
365 char *endptr; 355 char *endptr;
366 356
@@ -437,12 +427,33 @@ setup:
437 return 0; 427 return 0;
438} 428}
439 429
440static const char * const report_usage[] = { 430int cmd_report(int argc, const char **argv, const char *prefix __used)
441 "perf report [<options>] <command>", 431{
442 NULL 432 char callchain_default_opt[] = "fractal,0.5,callee";
443}; 433 const char * const report_usage[] = {
444 434 "perf report [<options>] <command>",
445static const struct option options[] = { 435 NULL
436 };
437 struct perf_report report = {
438 .ops = {
439 .sample = process_sample_event,
440 .mmap = perf_event__process_mmap,
441 .comm = perf_event__process_comm,
442 .exit = perf_event__process_task,
443 .fork = perf_event__process_task,
444 .lost = perf_event__process_lost,
445 .read = process_read_event,
446 .attr = perf_event__process_attr,
447 .event_type = perf_event__process_event_type,
448 .tracing_data = perf_event__process_tracing_data,
449 .build_id = perf_event__process_build_id,
450 .ordered_samples = true,
451 .ordering_requires_timestamps = true,
452 },
453 .input_name = "perf.data",
454 .pretty_printing_style = "normal",
455 };
456 const struct option options[] = {
446 OPT_STRING('i', "input", &report.input_name, "file", 457 OPT_STRING('i', "input", &report.input_name, "file",
447 "input file name"), 458 "input file name"),
448 OPT_INCR('v', "verbose", &verbose, 459 OPT_INCR('v', "verbose", &verbose,
@@ -473,7 +484,7 @@ static const struct option options[] = {
473 "regex filter to identify parent, see: '--sort parent'"), 484 "regex filter to identify parent, see: '--sort parent'"),
474 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 485 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
475 "Only display entries with parent-match"), 486 "Only display entries with parent-match"),
476 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order", 487 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent, call_order",
477 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. " 488 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. "
478 "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), 489 "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt),
479 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, 490 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
@@ -507,10 +518,8 @@ static const struct option options[] = {
507 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 518 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
508 "Show a column with the sum of periods"), 519 "Show a column with the sum of periods"),
509 OPT_END() 520 OPT_END()
510}; 521 };
511 522
512int cmd_report(int argc, const char **argv, const char *prefix __used)
513{
514 argc = parse_options(argc, argv, options, report_usage, 0); 523 argc = parse_options(argc, argv, options, report_usage, 0);
515 524
516 if (report.use_stdio) 525 if (report.use_stdio)
@@ -579,5 +588,5 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
579 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); 588 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
580 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); 589 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
581 590
582 return __cmd_report(); 591 return __cmd_report(&report);
583} 592}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index d51af0beab13..b11d6283fedf 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1602,7 +1602,8 @@ static void process_raw_event(union perf_event *raw_event __used,
1602 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); 1602 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1603} 1603}
1604 1604
1605static int process_sample_event(union perf_event *event, 1605static int process_sample_event(struct perf_event_ops *ops __used,
1606 union perf_event *event,
1606 struct perf_sample *sample, 1607 struct perf_sample *sample,
1607 struct perf_evsel *evsel, 1608 struct perf_evsel *evsel,
1608 struct perf_session *session) 1609 struct perf_session *session)
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 47545e9c9b27..3b7820612ebf 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -434,7 +434,8 @@ static int cleanup_scripting(void)
434 434
435static char const *input_name = "perf.data"; 435static char const *input_name = "perf.data";
436 436
437static int process_sample_event(union perf_event *event, 437static int process_sample_event(struct perf_event_ops *ops __used,
438 union perf_event *event,
438 struct perf_sample *sample, 439 struct perf_sample *sample,
439 struct perf_evsel *evsel, 440 struct perf_evsel *evsel,
440 struct perf_session *session) 441 struct perf_session *session)
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 3fc52b1aa430..62298a0d7dc9 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -274,7 +274,8 @@ static int cpus_cstate_state[MAX_CPUS];
274static u64 cpus_pstate_start_times[MAX_CPUS]; 274static u64 cpus_pstate_start_times[MAX_CPUS];
275static u64 cpus_pstate_state[MAX_CPUS]; 275static u64 cpus_pstate_state[MAX_CPUS];
276 276
277static int process_comm_event(union perf_event *event, 277static int process_comm_event(struct perf_event_ops *ops __used,
278 union perf_event *event,
278 struct perf_sample *sample __used, 279 struct perf_sample *sample __used,
279 struct perf_session *session __used) 280 struct perf_session *session __used)
280{ 281{
@@ -282,7 +283,8 @@ static int process_comm_event(union perf_event *event,
282 return 0; 283 return 0;
283} 284}
284 285
285static int process_fork_event(union perf_event *event, 286static int process_fork_event(struct perf_event_ops *ops __used,
287 union perf_event *event,
286 struct perf_sample *sample __used, 288 struct perf_sample *sample __used,
287 struct perf_session *session __used) 289 struct perf_session *session __used)
288{ 290{
@@ -290,7 +292,8 @@ static int process_fork_event(union perf_event *event,
290 return 0; 292 return 0;
291} 293}
292 294
293static int process_exit_event(union perf_event *event, 295static int process_exit_event(struct perf_event_ops *ops __used,
296 union perf_event *event,
294 struct perf_sample *sample __used, 297 struct perf_sample *sample __used,
295 struct perf_session *session __used) 298 struct perf_session *session __used)
296{ 299{
@@ -487,7 +490,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
487} 490}
488 491
489 492
490static int process_sample_event(union perf_event *event __used, 493static int process_sample_event(struct perf_event_ops *ops __used,
494 union perf_event *event __used,
491 struct perf_sample *sample, 495 struct perf_sample *sample,
492 struct perf_evsel *evsel, 496 struct perf_evsel *evsel,
493 struct perf_session *session __used) 497 struct perf_session *session __used)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 9b3bbb40d46f..e8e3320602bd 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -824,7 +824,7 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
824 perf_event__process_sample(event, evsel, &sample, self); 824 perf_event__process_sample(event, evsel, &sample, self);
825 else if (event->header.type < PERF_RECORD_MAX) { 825 else if (event->header.type < PERF_RECORD_MAX) {
826 hists__inc_nr_events(&evsel->hists, event->header.type); 826 hists__inc_nr_events(&evsel->hists, event->header.type);
827 perf_event__process(event, &sample, self); 827 perf_event__process(&top.ops, event, &sample, self);
828 } else 828 } else
829 ++self->hists.stats.nr_unknown_events; 829 ++self->hists.stats.nr_unknown_events;
830 } 830 }
@@ -966,10 +966,10 @@ static int __cmd_top(void)
966 goto out_delete; 966 goto out_delete;
967 967
968 if (top.target_tid != -1) 968 if (top.target_tid != -1)
969 perf_event__synthesize_thread_map(top.evlist->threads, 969 perf_event__synthesize_thread_map(&top.ops, top.evlist->threads,
970 perf_event__process, top.session); 970 perf_event__process, top.session);
971 else 971 else
972 perf_event__synthesize_threads(perf_event__process, top.session); 972 perf_event__synthesize_threads(&top.ops, perf_event__process, top.session);
973 973
974 start_counters(top.evlist); 974 start_counters(top.evlist);
975 top.session->evlist = top.evlist; 975 top.session->evlist = top.evlist;
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index f2fe6ec08945..0e4de1865013 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -13,8 +13,10 @@
13#include "symbol.h" 13#include "symbol.h"
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include "debug.h" 15#include "debug.h"
16#include "session.h"
16 17
17static int build_id__mark_dso_hit(union perf_event *event, 18static int build_id__mark_dso_hit(struct perf_event_ops *ops __used,
19 union perf_event *event,
18 struct perf_sample *sample __used, 20 struct perf_sample *sample __used,
19 struct perf_evsel *evsel __used, 21 struct perf_evsel *evsel __used,
20 struct perf_session *session) 22 struct perf_session *session)
@@ -38,7 +40,8 @@ static int build_id__mark_dso_hit(union perf_event *event,
38 return 0; 40 return 0;
39} 41}
40 42
41static int perf_event__exit_del_thread(union perf_event *event, 43static int perf_event__exit_del_thread(struct perf_event_ops *ops __used,
44 union perf_event *event,
42 struct perf_sample *sample __used, 45 struct perf_sample *sample __used,
43 struct perf_session *session) 46 struct perf_session *session)
44{ 47{
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 9b4ff16cac96..7f9c0f1ae3a9 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -101,6 +101,9 @@ int callchain_append(struct callchain_root *root,
101int callchain_merge(struct callchain_cursor *cursor, 101int callchain_merge(struct callchain_cursor *cursor,
102 struct callchain_root *dst, struct callchain_root *src); 102 struct callchain_root *dst, struct callchain_root *src);
103 103
104struct ip_callchain;
105union perf_event;
106
104bool ip_callchain__valid(struct ip_callchain *chain, 107bool ip_callchain__valid(struct ip_callchain *chain,
105 const union perf_event *event); 108 const union perf_event *event);
106/* 109/*
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 437f8ca679a0..4800f38c7277 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -44,7 +44,8 @@ static struct perf_sample synth_sample = {
44 .period = 1, 44 .period = 1,
45}; 45};
46 46
47static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid, 47static pid_t perf_event__synthesize_comm(struct perf_event_ops *ops,
48 union perf_event *event, pid_t pid,
48 int full, perf_event__handler_t process, 49 int full, perf_event__handler_t process,
49 struct perf_session *session) 50 struct perf_session *session)
50{ 51{
@@ -99,7 +100,7 @@ out_race:
99 if (!full) { 100 if (!full) {
100 event->comm.tid = pid; 101 event->comm.tid = pid;
101 102
102 process(event, &synth_sample, session); 103 process(ops, event, &synth_sample, session);
103 goto out; 104 goto out;
104 } 105 }
105 106
@@ -117,7 +118,7 @@ out_race:
117 118
118 event->comm.tid = pid; 119 event->comm.tid = pid;
119 120
120 process(event, &synth_sample, session); 121 process(ops, event, &synth_sample, session);
121 } 122 }
122 123
123 closedir(tasks); 124 closedir(tasks);
@@ -127,7 +128,8 @@ out:
127 return tgid; 128 return tgid;
128} 129}
129 130
130static int perf_event__synthesize_mmap_events(union perf_event *event, 131static int perf_event__synthesize_mmap_events(struct perf_event_ops *ops,
132 union perf_event *event,
131 pid_t pid, pid_t tgid, 133 pid_t pid, pid_t tgid,
132 perf_event__handler_t process, 134 perf_event__handler_t process,
133 struct perf_session *session) 135 struct perf_session *session)
@@ -198,7 +200,7 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
198 event->mmap.pid = tgid; 200 event->mmap.pid = tgid;
199 event->mmap.tid = pid; 201 event->mmap.tid = pid;
200 202
201 process(event, &synth_sample, session); 203 process(ops, event, &synth_sample, session);
202 } 204 }
203 } 205 }
204 206
@@ -206,7 +208,8 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
206 return 0; 208 return 0;
207} 209}
208 210
209int perf_event__synthesize_modules(perf_event__handler_t process, 211int perf_event__synthesize_modules(struct perf_event_ops *ops,
212 perf_event__handler_t process,
210 struct perf_session *session, 213 struct perf_session *session,
211 struct machine *machine) 214 struct machine *machine)
212{ 215{
@@ -251,7 +254,7 @@ int perf_event__synthesize_modules(perf_event__handler_t process,
251 254
252 memcpy(event->mmap.filename, pos->dso->long_name, 255 memcpy(event->mmap.filename, pos->dso->long_name,
253 pos->dso->long_name_len + 1); 256 pos->dso->long_name_len + 1);
254 process(event, &synth_sample, session); 257 process(ops, event, &synth_sample, session);
255 } 258 }
256 259
257 free(event); 260 free(event);
@@ -261,17 +264,19 @@ int perf_event__synthesize_modules(perf_event__handler_t process,
261static int __event__synthesize_thread(union perf_event *comm_event, 264static int __event__synthesize_thread(union perf_event *comm_event,
262 union perf_event *mmap_event, 265 union perf_event *mmap_event,
263 pid_t pid, perf_event__handler_t process, 266 pid_t pid, perf_event__handler_t process,
267 struct perf_event_ops *ops,
264 struct perf_session *session) 268 struct perf_session *session)
265{ 269{
266 pid_t tgid = perf_event__synthesize_comm(comm_event, pid, 1, process, 270 pid_t tgid = perf_event__synthesize_comm(ops, comm_event, pid, 1, process,
267 session); 271 session);
268 if (tgid == -1) 272 if (tgid == -1)
269 return -1; 273 return -1;
270 return perf_event__synthesize_mmap_events(mmap_event, pid, tgid, 274 return perf_event__synthesize_mmap_events(ops, mmap_event, pid, tgid,
271 process, session); 275 process, session);
272} 276}
273 277
274int perf_event__synthesize_thread_map(struct thread_map *threads, 278int perf_event__synthesize_thread_map(struct perf_event_ops *ops,
279 struct thread_map *threads,
275 perf_event__handler_t process, 280 perf_event__handler_t process,
276 struct perf_session *session) 281 struct perf_session *session)
277{ 282{
@@ -290,7 +295,7 @@ int perf_event__synthesize_thread_map(struct thread_map *threads,
290 for (thread = 0; thread < threads->nr; ++thread) { 295 for (thread = 0; thread < threads->nr; ++thread) {
291 if (__event__synthesize_thread(comm_event, mmap_event, 296 if (__event__synthesize_thread(comm_event, mmap_event,
292 threads->map[thread], 297 threads->map[thread],
293 process, session)) { 298 process, ops, session)) {
294 err = -1; 299 err = -1;
295 break; 300 break;
296 } 301 }
@@ -302,7 +307,8 @@ out:
302 return err; 307 return err;
303} 308}
304 309
305int perf_event__synthesize_threads(perf_event__handler_t process, 310int perf_event__synthesize_threads(struct perf_event_ops *ops,
311 perf_event__handler_t process,
306 struct perf_session *session) 312 struct perf_session *session)
307{ 313{
308 DIR *proc; 314 DIR *proc;
@@ -330,7 +336,7 @@ int perf_event__synthesize_threads(perf_event__handler_t process,
330 continue; 336 continue;
331 337
332 __event__synthesize_thread(comm_event, mmap_event, pid, 338 __event__synthesize_thread(comm_event, mmap_event, pid,
333 process, session); 339 process, ops, session);
334 } 340 }
335 341
336 closedir(proc); 342 closedir(proc);
@@ -365,7 +371,8 @@ static int find_symbol_cb(void *arg, const char *name, char type,
365 return 1; 371 return 1;
366} 372}
367 373
368int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, 374int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops,
375 perf_event__handler_t process,
369 struct perf_session *session, 376 struct perf_session *session,
370 struct machine *machine, 377 struct machine *machine,
371 const char *symbol_name) 378 const char *symbol_name)
@@ -423,13 +430,14 @@ int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
423 event->mmap.len = map->end - event->mmap.start; 430 event->mmap.len = map->end - event->mmap.start;
424 event->mmap.pid = machine->pid; 431 event->mmap.pid = machine->pid;
425 432
426 err = process(event, &synth_sample, session); 433 err = process(ops, event, &synth_sample, session);
427 free(event); 434 free(event);
428 435
429 return err; 436 return err;
430} 437}
431 438
432int perf_event__process_comm(union perf_event *event, 439int perf_event__process_comm(struct perf_event_ops *ops __used,
440 union perf_event *event,
433 struct perf_sample *sample __used, 441 struct perf_sample *sample __used,
434 struct perf_session *session) 442 struct perf_session *session)
435{ 443{
@@ -445,7 +453,8 @@ int perf_event__process_comm(union perf_event *event,
445 return 0; 453 return 0;
446} 454}
447 455
448int perf_event__process_lost(union perf_event *event, 456int perf_event__process_lost(struct perf_event_ops *ops __used,
457 union perf_event *event,
449 struct perf_sample *sample __used, 458 struct perf_sample *sample __used,
450 struct perf_session *session) 459 struct perf_session *session)
451{ 460{
@@ -468,7 +477,8 @@ static void perf_event__set_kernel_mmap_len(union perf_event *event,
468 maps[MAP__FUNCTION]->end = ~0ULL; 477 maps[MAP__FUNCTION]->end = ~0ULL;
469} 478}
470 479
471static int perf_event__process_kernel_mmap(union perf_event *event, 480static int perf_event__process_kernel_mmap(struct perf_event_ops *ops __used,
481 union perf_event *event,
472 struct perf_session *session) 482 struct perf_session *session)
473{ 483{
474 struct map *map; 484 struct map *map;
@@ -567,7 +577,8 @@ out_problem:
567 return -1; 577 return -1;
568} 578}
569 579
570int perf_event__process_mmap(union perf_event *event, 580int perf_event__process_mmap(struct perf_event_ops *ops,
581 union perf_event *event,
571 struct perf_sample *sample __used, 582 struct perf_sample *sample __used,
572 struct perf_session *session) 583 struct perf_session *session)
573{ 584{
@@ -583,7 +594,7 @@ int perf_event__process_mmap(union perf_event *event,
583 594
584 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 595 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
585 cpumode == PERF_RECORD_MISC_KERNEL) { 596 cpumode == PERF_RECORD_MISC_KERNEL) {
586 ret = perf_event__process_kernel_mmap(event, session); 597 ret = perf_event__process_kernel_mmap(ops, event, session);
587 if (ret < 0) 598 if (ret < 0)
588 goto out_problem; 599 goto out_problem;
589 return 0; 600 return 0;
@@ -610,7 +621,8 @@ out_problem:
610 return 0; 621 return 0;
611} 622}
612 623
613int perf_event__process_task(union perf_event *event, 624int perf_event__process_task(struct perf_event_ops *ops __used,
625 union perf_event *event,
614 struct perf_sample *sample __used, 626 struct perf_sample *sample __used,
615 struct perf_session *session) 627 struct perf_session *session)
616{ 628{
@@ -634,22 +646,22 @@ int perf_event__process_task(union perf_event *event,
634 return 0; 646 return 0;
635} 647}
636 648
637int perf_event__process(union perf_event *event, struct perf_sample *sample, 649int perf_event__process(struct perf_event_ops *ops, union perf_event *event,
638 struct perf_session *session) 650 struct perf_sample *sample, struct perf_session *session)
639{ 651{
640 switch (event->header.type) { 652 switch (event->header.type) {
641 case PERF_RECORD_COMM: 653 case PERF_RECORD_COMM:
642 perf_event__process_comm(event, sample, session); 654 perf_event__process_comm(ops, event, sample, session);
643 break; 655 break;
644 case PERF_RECORD_MMAP: 656 case PERF_RECORD_MMAP:
645 perf_event__process_mmap(event, sample, session); 657 perf_event__process_mmap(ops, event, sample, session);
646 break; 658 break;
647 case PERF_RECORD_FORK: 659 case PERF_RECORD_FORK:
648 case PERF_RECORD_EXIT: 660 case PERF_RECORD_EXIT:
649 perf_event__process_task(event, sample, session); 661 perf_event__process_task(ops, event, sample, session);
650 break; 662 break;
651 case PERF_RECORD_LOST: 663 case PERF_RECORD_LOST:
652 perf_event__process_lost(event, sample, session); 664 perf_event__process_lost(ops, event, sample, session);
653 default: 665 default:
654 break; 666 break;
655 } 667 }
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 357a85b85248..669409d35710 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -141,38 +141,52 @@ union perf_event {
141 141
142void perf_event__print_totals(void); 142void perf_event__print_totals(void);
143 143
144struct perf_event_ops;
144struct perf_session; 145struct perf_session;
145struct thread_map; 146struct thread_map;
146 147
147typedef int (*perf_event__handler_synth_t)(union perf_event *event, 148typedef int (*perf_event__handler_t)(struct perf_event_ops *ops,
148 struct perf_session *session); 149 union perf_event *event,
149typedef int (*perf_event__handler_t)(union perf_event *event,
150 struct perf_sample *sample, 150 struct perf_sample *sample,
151 struct perf_session *session); 151 struct perf_session *session);
152 152
153int perf_event__synthesize_thread_map(struct thread_map *threads, 153int perf_event__synthesize_thread_map(struct perf_event_ops *ops,
154 struct thread_map *threads,
154 perf_event__handler_t process, 155 perf_event__handler_t process,
155 struct perf_session *session); 156 struct perf_session *session);
156int perf_event__synthesize_threads(perf_event__handler_t process, 157int perf_event__synthesize_threads(struct perf_event_ops *ops,
158 perf_event__handler_t process,
157 struct perf_session *session); 159 struct perf_session *session);
158int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, 160int perf_event__synthesize_kernel_mmap(struct perf_event_ops *ops,
161 perf_event__handler_t process,
159 struct perf_session *session, 162 struct perf_session *session,
160 struct machine *machine, 163 struct machine *machine,
161 const char *symbol_name); 164 const char *symbol_name);
162 165
163int perf_event__synthesize_modules(perf_event__handler_t process, 166int perf_event__synthesize_modules(struct perf_event_ops *ops,
167 perf_event__handler_t process,
164 struct perf_session *session, 168 struct perf_session *session,
165 struct machine *machine); 169 struct machine *machine);
166 170
167int perf_event__process_comm(union perf_event *event, struct perf_sample *sample, 171int perf_event__process_comm(struct perf_event_ops *ops,
172 union perf_event *event,
173 struct perf_sample *sample,
168 struct perf_session *session); 174 struct perf_session *session);
169int perf_event__process_lost(union perf_event *event, struct perf_sample *sample, 175int perf_event__process_lost(struct perf_event_ops *ops,
176 union perf_event *event,
177 struct perf_sample *sample,
170 struct perf_session *session); 178 struct perf_session *session);
171int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample, 179int perf_event__process_mmap(struct perf_event_ops *ops,
180 union perf_event *event,
181 struct perf_sample *sample,
172 struct perf_session *session); 182 struct perf_session *session);
173int perf_event__process_task(union perf_event *event, struct perf_sample *sample, 183int perf_event__process_task(struct perf_event_ops *ops,
184 union perf_event *event,
185 struct perf_sample *sample,
174 struct perf_session *session); 186 struct perf_session *session);
175int perf_event__process(union perf_event *event, struct perf_sample *sample, 187int perf_event__process(struct perf_event_ops *ops,
188 union perf_event *event,
189 struct perf_sample *sample,
176 struct perf_session *session); 190 struct perf_session *session);
177 191
178struct addr_location; 192struct addr_location;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 1fa97dd21200..ab3a2b0e8f06 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2070,7 +2070,8 @@ out_delete_evlist:
2070 return -ENOMEM; 2070 return -ENOMEM;
2071} 2071}
2072 2072
2073int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 2073int perf_event__synthesize_attr(struct perf_event_ops *ops,
2074 struct perf_event_attr *attr, u16 ids, u64 *id,
2074 perf_event__handler_t process, 2075 perf_event__handler_t process,
2075 struct perf_session *session) 2076 struct perf_session *session)
2076{ 2077{
@@ -2094,21 +2095,22 @@ int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
2094 ev->attr.header.type = PERF_RECORD_HEADER_ATTR; 2095 ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
2095 ev->attr.header.size = size; 2096 ev->attr.header.size = size;
2096 2097
2097 err = process(ev, NULL, session); 2098 err = process(ops, ev, NULL, session);
2098 2099
2099 free(ev); 2100 free(ev);
2100 2101
2101 return err; 2102 return err;
2102} 2103}
2103 2104
2104int perf_session__synthesize_attrs(struct perf_session *session, 2105int perf_event__synthesize_attrs(struct perf_event_ops *ops,
2106 struct perf_session *session,
2105 perf_event__handler_t process) 2107 perf_event__handler_t process)
2106{ 2108{
2107 struct perf_evsel *attr; 2109 struct perf_evsel *attr;
2108 int err = 0; 2110 int err = 0;
2109 2111
2110 list_for_each_entry(attr, &session->evlist->entries, node) { 2112 list_for_each_entry(attr, &session->evlist->entries, node) {
2111 err = perf_event__synthesize_attr(&attr->attr, attr->ids, 2113 err = perf_event__synthesize_attr(ops, &attr->attr, attr->ids,
2112 attr->id, process, session); 2114 attr->id, process, session);
2113 if (err) { 2115 if (err) {
2114 pr_debug("failed to create perf header attribute\n"); 2116 pr_debug("failed to create perf header attribute\n");
@@ -2156,7 +2158,8 @@ int perf_event__process_attr(union perf_event *event,
2156 return 0; 2158 return 0;
2157} 2159}
2158 2160
2159int perf_event__synthesize_event_type(u64 event_id, char *name, 2161int perf_event__synthesize_event_type(struct perf_event_ops *ops,
2162 u64 event_id, char *name,
2160 perf_event__handler_t process, 2163 perf_event__handler_t process,
2161 struct perf_session *session) 2164 struct perf_session *session)
2162{ 2165{
@@ -2176,12 +2179,13 @@ int perf_event__synthesize_event_type(u64 event_id, char *name,
2176 ev.event_type.header.size = sizeof(ev.event_type) - 2179 ev.event_type.header.size = sizeof(ev.event_type) -
2177 (sizeof(ev.event_type.event_type.name) - size); 2180 (sizeof(ev.event_type.event_type.name) - size);
2178 2181
2179 err = process(&ev, NULL, session); 2182 err = process(ops, &ev, NULL, session);
2180 2183
2181 return err; 2184 return err;
2182} 2185}
2183 2186
2184int perf_event__synthesize_event_types(perf_event__handler_t process, 2187int perf_event__synthesize_event_types(struct perf_event_ops *ops,
2188 perf_event__handler_t process,
2185 struct perf_session *session) 2189 struct perf_session *session)
2186{ 2190{
2187 struct perf_trace_event_type *type; 2191 struct perf_trace_event_type *type;
@@ -2190,7 +2194,7 @@ int perf_event__synthesize_event_types(perf_event__handler_t process,
2190 for (i = 0; i < event_count; i++) { 2194 for (i = 0; i < event_count; i++) {
2191 type = &events[i]; 2195 type = &events[i];
2192 2196
2193 err = perf_event__synthesize_event_type(type->event_id, 2197 err = perf_event__synthesize_event_type(ops, type->event_id,
2194 type->name, process, 2198 type->name, process,
2195 session); 2199 session);
2196 if (err) { 2200 if (err) {
@@ -2202,7 +2206,8 @@ int perf_event__synthesize_event_types(perf_event__handler_t process,
2202 return err; 2206 return err;
2203} 2207}
2204 2208
2205int perf_event__process_event_type(union perf_event *event, 2209int perf_event__process_event_type(struct perf_event_ops *ops __unused,
2210 union perf_event *event,
2206 struct perf_session *session __unused) 2211 struct perf_session *session __unused)
2207{ 2212{
2208 if (perf_header__push_event(event->event_type.event_type.event_id, 2213 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 return 0; 2217 return 0;
2213} 2218}
2214 2219
2215int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, 2220int perf_event__synthesize_tracing_data(struct perf_event_ops *ops, int fd,
2221 struct perf_evlist *evlist,
2216 perf_event__handler_t process, 2222 perf_event__handler_t process,
2217 struct perf_session *session __unused) 2223 struct perf_session *session __unused)
2218{ 2224{
@@ -2245,7 +2251,7 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
2245 ev.tracing_data.header.size = sizeof(ev.tracing_data); 2251 ev.tracing_data.header.size = sizeof(ev.tracing_data);
2246 ev.tracing_data.size = aligned_size; 2252 ev.tracing_data.size = aligned_size;
2247 2253
2248 process(&ev, NULL, session); 2254 process(ops, &ev, NULL, session);
2249 2255
2250 /* 2256 /*
2251 * The put function will copy all the tracing data 2257 * The put function will copy all the tracing data
@@ -2287,7 +2293,8 @@ int perf_event__process_tracing_data(union perf_event *event,
2287 return size_read + padding; 2293 return size_read + padding;
2288} 2294}
2289 2295
2290int perf_event__synthesize_build_id(struct dso *pos, u16 misc, 2296int perf_event__synthesize_build_id(struct perf_event_ops *ops,
2297 struct dso *pos, u16 misc,
2291 perf_event__handler_t process, 2298 perf_event__handler_t process,
2292 struct machine *machine, 2299 struct machine *machine,
2293 struct perf_session *session) 2300 struct perf_session *session)
@@ -2310,12 +2317,13 @@ int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
2310 ev.build_id.header.size = sizeof(ev.build_id) + len; 2317 ev.build_id.header.size = sizeof(ev.build_id) + len;
2311 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); 2318 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
2312 2319
2313 err = process(&ev, NULL, session); 2320 err = process(ops, &ev, NULL, session);
2314 2321
2315 return err; 2322 return err;
2316} 2323}
2317 2324
2318int perf_event__process_build_id(union perf_event *event, 2325int perf_event__process_build_id(struct perf_event_ops *ops __used,
2326 union perf_event *event,
2319 struct perf_session *session) 2327 struct perf_session *session)
2320{ 2328{
2321 __event_process_build_id(&event->build_id, 2329 __event_process_build_id(&event->build_id,
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 0a88982bc392..54dae5f09556 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -68,6 +68,7 @@ struct perf_header {
68}; 68};
69 69
70struct perf_evlist; 70struct perf_evlist;
71struct perf_session;
71 72
72int perf_session__read_header(struct perf_session *session, int fd); 73int perf_session__read_header(struct perf_session *session, int fd);
73int perf_session__write_header(struct perf_session *session, 74int 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 const char *name, bool is_kallsyms); 97 const char *name, bool is_kallsyms);
97int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); 98int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
98 99
99int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 100int perf_event__synthesize_attr(struct perf_event_ops *ops,
101 struct perf_event_attr *attr, u16 ids, u64 *id,
100 perf_event__handler_t process, 102 perf_event__handler_t process,
101 struct perf_session *session); 103 struct perf_session *session);
102int perf_session__synthesize_attrs(struct perf_session *session, 104int perf_event__synthesize_attrs(struct perf_event_ops *ops,
103 perf_event__handler_t process); 105 struct perf_session *session,
106 perf_event__handler_t process);
104int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist); 107int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist);
105 108
106int perf_event__synthesize_event_type(u64 event_id, char *name, 109int perf_event__synthesize_event_type(struct perf_event_ops *ops,
110 u64 event_id, char *name,
107 perf_event__handler_t process, 111 perf_event__handler_t process,
108 struct perf_session *session); 112 struct perf_session *session);
109int perf_event__synthesize_event_types(perf_event__handler_t process, 113int perf_event__synthesize_event_types(struct perf_event_ops *ops,
114 perf_event__handler_t process,
110 struct perf_session *session); 115 struct perf_session *session);
111int perf_event__process_event_type(union perf_event *event, 116int perf_event__process_event_type(struct perf_event_ops *ops,
117 union perf_event *event,
112 struct perf_session *session); 118 struct perf_session *session);
113 119
114int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, 120int perf_event__synthesize_tracing_data(struct perf_event_ops *ops,
121 int fd, struct perf_evlist *evlist,
115 perf_event__handler_t process, 122 perf_event__handler_t process,
116 struct perf_session *session); 123 struct perf_session *session);
117int perf_event__process_tracing_data(union perf_event *event, 124int perf_event__process_tracing_data(union perf_event *event,
118 struct perf_session *session); 125 struct perf_session *session);
119 126
120int perf_event__synthesize_build_id(struct dso *pos, u16 misc, 127int perf_event__synthesize_build_id(struct perf_event_ops *ops,
128 struct dso *pos, u16 misc,
121 perf_event__handler_t process, 129 perf_event__handler_t process,
122 struct machine *machine, 130 struct machine *machine,
123 struct perf_session *session); 131 struct perf_session *session);
124int perf_event__process_build_id(union perf_event *event, 132int perf_event__process_build_id(struct perf_event_ops *ops,
133 union perf_event *event,
125 struct perf_session *session); 134 struct perf_session *session);
126 135
127/* 136/*
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 734358b51ed1..a36023a66779 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -270,13 +270,21 @@ int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel
270 return 0; 270 return 0;
271} 271}
272 272
273static int process_event_synth_stub(union perf_event *event __used, 273static int process_event_synth_stub(struct perf_event_ops *ops __used,
274 union perf_event *event __used,
274 struct perf_session *session __used) 275 struct perf_session *session __used)
275{ 276{
276 dump_printf(": unhandled!\n"); 277 dump_printf(": unhandled!\n");
277 return 0; 278 return 0;
278} 279}
279 280
281static int process_event_synth_tracing_data_stub(union perf_event *event __used,
282 struct perf_session *session __used)
283{
284 dump_printf(": unhandled!\n");
285 return 0;
286}
287
280static int process_event_synth_attr_stub(union perf_event *event __used, 288static int process_event_synth_attr_stub(union perf_event *event __used,
281 struct perf_evlist **pevlist __used) 289 struct perf_evlist **pevlist __used)
282{ 290{
@@ -284,7 +292,8 @@ static int process_event_synth_attr_stub(union perf_event *event __used,
284 return 0; 292 return 0;
285} 293}
286 294
287static int process_event_sample_stub(union perf_event *event __used, 295static int process_event_sample_stub(struct perf_event_ops *ops __used,
296 union perf_event *event __used,
288 struct perf_sample *sample __used, 297 struct perf_sample *sample __used,
289 struct perf_evsel *evsel __used, 298 struct perf_evsel *evsel __used,
290 struct perf_session *session __used) 299 struct perf_session *session __used)
@@ -293,7 +302,8 @@ static int process_event_sample_stub(union perf_event *event __used,
293 return 0; 302 return 0;
294} 303}
295 304
296static int process_event_stub(union perf_event *event __used, 305static int process_event_stub(struct perf_event_ops *ops __used,
306 union perf_event *event __used,
297 struct perf_sample *sample __used, 307 struct perf_sample *sample __used,
298 struct perf_session *session __used) 308 struct perf_session *session __used)
299{ 309{
@@ -301,17 +311,17 @@ static int process_event_stub(union perf_event *event __used,
301 return 0; 311 return 0;
302} 312}
303 313
304static int process_finished_round_stub(union perf_event *event __used, 314static int process_finished_round_stub(struct perf_event_ops *ops __used,
305 struct perf_session *session __used, 315 union perf_event *event __used,
306 struct perf_event_ops *ops __used) 316 struct perf_session *session __used)
307{ 317{
308 dump_printf(": unhandled!\n"); 318 dump_printf(": unhandled!\n");
309 return 0; 319 return 0;
310} 320}
311 321
312static int process_finished_round(union perf_event *event, 322static int process_finished_round(struct perf_event_ops *ops,
313 struct perf_session *session, 323 union perf_event *event,
314 struct perf_event_ops *ops); 324 struct perf_session *session);
315 325
316static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) 326static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
317{ 327{
@@ -338,7 +348,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
338 if (handler->event_type == NULL) 348 if (handler->event_type == NULL)
339 handler->event_type = process_event_synth_stub; 349 handler->event_type = process_event_synth_stub;
340 if (handler->tracing_data == NULL) 350 if (handler->tracing_data == NULL)
341 handler->tracing_data = process_event_synth_stub; 351 handler->tracing_data = process_event_synth_tracing_data_stub;
342 if (handler->build_id == NULL) 352 if (handler->build_id == NULL)
343 handler->build_id = process_event_synth_stub; 353 handler->build_id = process_event_synth_stub;
344 if (handler->finished_round == NULL) { 354 if (handler->finished_round == NULL) {
@@ -565,9 +575,9 @@ static void flush_sample_queue(struct perf_session *s,
565 * Flush every events below timestamp 7 575 * Flush every events below timestamp 7
566 * etc... 576 * etc...
567 */ 577 */
568static int process_finished_round(union perf_event *event __used, 578static int process_finished_round(struct perf_event_ops *ops,
569 struct perf_session *session, 579 union perf_event *event __used,
570 struct perf_event_ops *ops) 580 struct perf_session *session)
571{ 581{
572 flush_sample_queue(session, ops); 582 flush_sample_queue(session, ops);
573 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; 583 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 ++session->hists.stats.nr_unknown_id; 769 ++session->hists.stats.nr_unknown_id;
760 return -1; 770 return -1;
761 } 771 }
762 return ops->sample(event, sample, evsel, session); 772 return ops->sample(ops, event, sample, evsel, session);
763 case PERF_RECORD_MMAP: 773 case PERF_RECORD_MMAP:
764 return ops->mmap(event, sample, session); 774 return ops->mmap(ops, event, sample, session);
765 case PERF_RECORD_COMM: 775 case PERF_RECORD_COMM:
766 return ops->comm(event, sample, session); 776 return ops->comm(ops, event, sample, session);
767 case PERF_RECORD_FORK: 777 case PERF_RECORD_FORK:
768 return ops->fork(event, sample, session); 778 return ops->fork(ops, event, sample, session);
769 case PERF_RECORD_EXIT: 779 case PERF_RECORD_EXIT:
770 return ops->exit(event, sample, session); 780 return ops->exit(ops, event, sample, session);
771 case PERF_RECORD_LOST: 781 case PERF_RECORD_LOST:
772 return ops->lost(event, sample, session); 782 return ops->lost(ops, event, sample, session);
773 case PERF_RECORD_READ: 783 case PERF_RECORD_READ:
774 return ops->read(event, sample, session); 784 return ops->read(ops, event, sample, session);
775 case PERF_RECORD_THROTTLE: 785 case PERF_RECORD_THROTTLE:
776 return ops->throttle(event, sample, session); 786 return ops->throttle(ops, event, sample, session);
777 case PERF_RECORD_UNTHROTTLE: 787 case PERF_RECORD_UNTHROTTLE:
778 return ops->unthrottle(event, sample, session); 788 return ops->unthrottle(ops, event, sample, session);
779 default: 789 default:
780 ++session->hists.stats.nr_unknown_events; 790 ++session->hists.stats.nr_unknown_events;
781 return -1; 791 return -1;
@@ -813,15 +823,15 @@ static int perf_session__process_user_event(struct perf_session *session, union
813 perf_session__update_sample_type(session); 823 perf_session__update_sample_type(session);
814 return err; 824 return err;
815 case PERF_RECORD_HEADER_EVENT_TYPE: 825 case PERF_RECORD_HEADER_EVENT_TYPE:
816 return ops->event_type(event, session); 826 return ops->event_type(ops, event, session);
817 case PERF_RECORD_HEADER_TRACING_DATA: 827 case PERF_RECORD_HEADER_TRACING_DATA:
818 /* setup for reading amidst mmap */ 828 /* setup for reading amidst mmap */
819 lseek(session->fd, file_offset, SEEK_SET); 829 lseek(session->fd, file_offset, SEEK_SET);
820 return ops->tracing_data(event, session); 830 return ops->tracing_data(event, session);
821 case PERF_RECORD_HEADER_BUILD_ID: 831 case PERF_RECORD_HEADER_BUILD_ID:
822 return ops->build_id(event, session); 832 return ops->build_id(ops, event, session);
823 case PERF_RECORD_FINISHED_ROUND: 833 case PERF_RECORD_FINISHED_ROUND:
824 return ops->finished_round(event, session, ops); 834 return ops->finished_round(ops, event, session);
825 default: 835 default:
826 return -EINVAL; 836 return -EINVAL;
827 } 837 }
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index d2f430367713..6de3d1368900 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -56,16 +56,18 @@ struct perf_session {
56struct perf_evsel; 56struct perf_evsel;
57struct perf_event_ops; 57struct perf_event_ops;
58 58
59typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample, 59typedef int (*event_sample)(struct perf_event_ops *ops,
60 union perf_event *event, struct perf_sample *sample,
60 struct perf_evsel *evsel, struct perf_session *session); 61 struct perf_evsel *evsel, struct perf_session *session);
61typedef int (*event_op)(union perf_event *self, struct perf_sample *sample, 62typedef int (*event_op)(struct perf_event_ops *ops, union perf_event *event,
63 struct perf_sample *sample,
62 struct perf_session *session); 64 struct perf_session *session);
63typedef int (*event_synth_op)(union perf_event *self, 65typedef int (*event_synth_op)(union perf_event *self,
64 struct perf_session *session); 66 struct perf_session *session);
65typedef int (*event_attr_op)(union perf_event *event, 67typedef int (*event_attr_op)(union perf_event *event,
66 struct perf_evlist **pevlist); 68 struct perf_evlist **pevlist);
67typedef int (*event_op2)(union perf_event *self, struct perf_session *session, 69typedef int (*event_op2)(struct perf_event_ops *ops, union perf_event *event,
68 struct perf_event_ops *ops); 70 struct perf_session *session);
69 71
70struct perf_event_ops { 72struct perf_event_ops {
71 event_sample sample; 73 event_sample sample;
@@ -78,10 +80,10 @@ struct perf_event_ops {
78 throttle, 80 throttle,
79 unthrottle; 81 unthrottle;
80 event_attr_op attr; 82 event_attr_op attr;
81 event_synth_op event_type, 83 event_synth_op tracing_data;
82 tracing_data, 84 event_op2 event_type,
83 build_id; 85 build_id,
84 event_op2 finished_round; 86 finished_round;
85 bool ordered_samples; 87 bool ordered_samples;
86 bool ordering_requires_timestamps; 88 bool ordering_requires_timestamps;
87}; 89};
@@ -142,10 +144,11 @@ struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t p
142 144
143static inline 145static inline
144void perf_session__process_machines(struct perf_session *self, 146void perf_session__process_machines(struct perf_session *self,
147 struct perf_event_ops *ops,
145 machine__process_t process) 148 machine__process_t process)
146{ 149{
147 process(&self->host_machine, self); 150 process(&self->host_machine, ops);
148 return machines__process(&self->machines, process, self); 151 return machines__process(&self->machines, process, ops);
149} 152}
150 153
151size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); 154size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 399650967958..44eda6fc6b33 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -2,14 +2,15 @@
2#define __PERF_TOP_H 1 2#define __PERF_TOP_H 1
3 3
4#include "types.h" 4#include "types.h"
5#include "session.h"
5#include "../perf.h" 6#include "../perf.h"
6#include <stddef.h> 7#include <stddef.h>
7 8
8struct perf_evlist; 9struct perf_evlist;
9struct perf_evsel; 10struct perf_evsel;
10struct perf_session;
11 11
12struct perf_top { 12struct perf_top {
13 struct perf_event_ops ops;
13 struct perf_evlist *evlist; 14 struct perf_evlist *evlist;
14 /* 15 /*
15 * Symbols will be added here in perf_event__process_sample and will 16 * Symbols will be added here in perf_event__process_sample and will