diff options
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r-- | tools/perf/util/session.c | 342 |
1 files changed, 198 insertions, 144 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0f4555ce9063..b5ca2558c7bb 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "evlist.h" | 10 | #include "evlist.h" |
11 | #include "evsel.h" | 11 | #include "evsel.h" |
12 | #include "session.h" | 12 | #include "session.h" |
13 | #include "tool.h" | ||
13 | #include "sort.h" | 14 | #include "sort.h" |
14 | #include "util.h" | 15 | #include "util.h" |
15 | #include "cpumap.h" | 16 | #include "cpumap.h" |
@@ -78,39 +79,13 @@ out_close: | |||
78 | return -1; | 79 | return -1; |
79 | } | 80 | } |
80 | 81 | ||
81 | static void perf_session__id_header_size(struct perf_session *session) | ||
82 | { | ||
83 | struct perf_sample *data; | ||
84 | u64 sample_type = session->sample_type; | ||
85 | u16 size = 0; | ||
86 | |||
87 | if (!session->sample_id_all) | ||
88 | goto out; | ||
89 | |||
90 | if (sample_type & PERF_SAMPLE_TID) | ||
91 | size += sizeof(data->tid) * 2; | ||
92 | |||
93 | if (sample_type & PERF_SAMPLE_TIME) | ||
94 | size += sizeof(data->time); | ||
95 | |||
96 | if (sample_type & PERF_SAMPLE_ID) | ||
97 | size += sizeof(data->id); | ||
98 | |||
99 | if (sample_type & PERF_SAMPLE_STREAM_ID) | ||
100 | size += sizeof(data->stream_id); | ||
101 | |||
102 | if (sample_type & PERF_SAMPLE_CPU) | ||
103 | size += sizeof(data->cpu) * 2; | ||
104 | out: | ||
105 | session->id_hdr_size = size; | ||
106 | } | ||
107 | |||
108 | void perf_session__update_sample_type(struct perf_session *self) | 82 | void perf_session__update_sample_type(struct perf_session *self) |
109 | { | 83 | { |
110 | self->sample_type = perf_evlist__sample_type(self->evlist); | 84 | self->sample_type = perf_evlist__sample_type(self->evlist); |
111 | self->sample_size = __perf_evsel__sample_size(self->sample_type); | 85 | self->sample_size = __perf_evsel__sample_size(self->sample_type); |
112 | self->sample_id_all = perf_evlist__sample_id_all(self->evlist); | 86 | self->sample_id_all = perf_evlist__sample_id_all(self->evlist); |
113 | perf_session__id_header_size(self); | 87 | self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist); |
88 | self->host_machine.id_hdr_size = self->id_hdr_size; | ||
114 | } | 89 | } |
115 | 90 | ||
116 | int perf_session__create_kernel_maps(struct perf_session *self) | 91 | int perf_session__create_kernel_maps(struct perf_session *self) |
@@ -130,18 +105,26 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self) | |||
130 | 105 | ||
131 | struct perf_session *perf_session__new(const char *filename, int mode, | 106 | struct perf_session *perf_session__new(const char *filename, int mode, |
132 | bool force, bool repipe, | 107 | bool force, bool repipe, |
133 | struct perf_event_ops *ops) | 108 | struct perf_tool *tool) |
134 | { | 109 | { |
135 | size_t len = filename ? strlen(filename) + 1 : 0; | 110 | struct perf_session *self; |
136 | struct perf_session *self = zalloc(sizeof(*self) + len); | 111 | struct stat st; |
112 | size_t len; | ||
113 | |||
114 | if (!filename || !strlen(filename)) { | ||
115 | if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) | ||
116 | filename = "-"; | ||
117 | else | ||
118 | filename = "perf.data"; | ||
119 | } | ||
120 | |||
121 | len = strlen(filename); | ||
122 | self = zalloc(sizeof(*self) + len); | ||
137 | 123 | ||
138 | if (self == NULL) | 124 | if (self == NULL) |
139 | goto out; | 125 | goto out; |
140 | 126 | ||
141 | memcpy(self->filename, filename, len); | 127 | memcpy(self->filename, filename, len); |
142 | self->threads = RB_ROOT; | ||
143 | INIT_LIST_HEAD(&self->dead_threads); | ||
144 | self->last_match = NULL; | ||
145 | /* | 128 | /* |
146 | * On 64bit we can mmap the data file in one go. No need for tiny mmap | 129 | * On 64bit we can mmap the data file in one go. No need for tiny mmap |
147 | * slices. On 32bit we use 32MB. | 130 | * slices. On 32bit we use 32MB. |
@@ -171,10 +154,10 @@ struct perf_session *perf_session__new(const char *filename, int mode, | |||
171 | goto out_delete; | 154 | goto out_delete; |
172 | } | 155 | } |
173 | 156 | ||
174 | if (ops && ops->ordering_requires_timestamps && | 157 | if (tool && tool->ordering_requires_timestamps && |
175 | ops->ordered_samples && !self->sample_id_all) { | 158 | tool->ordered_samples && !self->sample_id_all) { |
176 | dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); | 159 | dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); |
177 | ops->ordered_samples = false; | 160 | tool->ordered_samples = false; |
178 | } | 161 | } |
179 | 162 | ||
180 | out: | 163 | out: |
@@ -184,17 +167,22 @@ out_delete: | |||
184 | return NULL; | 167 | return NULL; |
185 | } | 168 | } |
186 | 169 | ||
187 | static void perf_session__delete_dead_threads(struct perf_session *self) | 170 | static void machine__delete_dead_threads(struct machine *machine) |
188 | { | 171 | { |
189 | struct thread *n, *t; | 172 | struct thread *n, *t; |
190 | 173 | ||
191 | list_for_each_entry_safe(t, n, &self->dead_threads, node) { | 174 | list_for_each_entry_safe(t, n, &machine->dead_threads, node) { |
192 | list_del(&t->node); | 175 | list_del(&t->node); |
193 | thread__delete(t); | 176 | thread__delete(t); |
194 | } | 177 | } |
195 | } | 178 | } |
196 | 179 | ||
197 | static void perf_session__delete_threads(struct perf_session *self) | 180 | static void perf_session__delete_dead_threads(struct perf_session *session) |
181 | { | ||
182 | machine__delete_dead_threads(&session->host_machine); | ||
183 | } | ||
184 | |||
185 | static void machine__delete_threads(struct machine *self) | ||
198 | { | 186 | { |
199 | struct rb_node *nd = rb_first(&self->threads); | 187 | struct rb_node *nd = rb_first(&self->threads); |
200 | 188 | ||
@@ -207,6 +195,11 @@ static void perf_session__delete_threads(struct perf_session *self) | |||
207 | } | 195 | } |
208 | } | 196 | } |
209 | 197 | ||
198 | static void perf_session__delete_threads(struct perf_session *session) | ||
199 | { | ||
200 | machine__delete_threads(&session->host_machine); | ||
201 | } | ||
202 | |||
210 | void perf_session__delete(struct perf_session *self) | 203 | void perf_session__delete(struct perf_session *self) |
211 | { | 204 | { |
212 | perf_session__destroy_kernel_maps(self); | 205 | perf_session__destroy_kernel_maps(self); |
@@ -217,7 +210,7 @@ void perf_session__delete(struct perf_session *self) | |||
217 | free(self); | 210 | free(self); |
218 | } | 211 | } |
219 | 212 | ||
220 | void perf_session__remove_thread(struct perf_session *self, struct thread *th) | 213 | void machine__remove_thread(struct machine *self, struct thread *th) |
221 | { | 214 | { |
222 | self->last_match = NULL; | 215 | self->last_match = NULL; |
223 | rb_erase(&th->rb_node, &self->threads); | 216 | rb_erase(&th->rb_node, &self->threads); |
@@ -236,16 +229,16 @@ static bool symbol__match_parent_regex(struct symbol *sym) | |||
236 | return 0; | 229 | return 0; |
237 | } | 230 | } |
238 | 231 | ||
239 | int perf_session__resolve_callchain(struct perf_session *self, | 232 | int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, |
240 | struct thread *thread, | 233 | struct thread *thread, |
241 | struct ip_callchain *chain, | 234 | struct ip_callchain *chain, |
242 | struct symbol **parent) | 235 | struct symbol **parent) |
243 | { | 236 | { |
244 | u8 cpumode = PERF_RECORD_MISC_USER; | 237 | u8 cpumode = PERF_RECORD_MISC_USER; |
245 | unsigned int i; | 238 | unsigned int i; |
246 | int err; | 239 | int err; |
247 | 240 | ||
248 | callchain_cursor_reset(&self->callchain_cursor); | 241 | callchain_cursor_reset(&evsel->hists.callchain_cursor); |
249 | 242 | ||
250 | for (i = 0; i < chain->nr; i++) { | 243 | for (i = 0; i < chain->nr; i++) { |
251 | u64 ip; | 244 | u64 ip; |
@@ -272,7 +265,7 @@ int perf_session__resolve_callchain(struct perf_session *self, | |||
272 | 265 | ||
273 | al.filtered = false; | 266 | al.filtered = false; |
274 | thread__find_addr_location(thread, self, cpumode, | 267 | thread__find_addr_location(thread, self, cpumode, |
275 | MAP__FUNCTION, thread->pid, ip, &al, NULL); | 268 | MAP__FUNCTION, ip, &al, NULL); |
276 | if (al.sym != NULL) { | 269 | if (al.sym != NULL) { |
277 | if (sort__has_parent && !*parent && | 270 | if (sort__has_parent && !*parent && |
278 | symbol__match_parent_regex(al.sym)) | 271 | symbol__match_parent_regex(al.sym)) |
@@ -281,7 +274,7 @@ int perf_session__resolve_callchain(struct perf_session *self, | |||
281 | break; | 274 | break; |
282 | } | 275 | } |
283 | 276 | ||
284 | err = callchain_cursor_append(&self->callchain_cursor, | 277 | err = callchain_cursor_append(&evsel->hists.callchain_cursor, |
285 | ip, al.map, al.sym); | 278 | ip, al.map, al.sym); |
286 | if (err) | 279 | if (err) |
287 | return err; | 280 | return err; |
@@ -290,75 +283,91 @@ int perf_session__resolve_callchain(struct perf_session *self, | |||
290 | return 0; | 283 | return 0; |
291 | } | 284 | } |
292 | 285 | ||
293 | static int process_event_synth_stub(union perf_event *event __used, | 286 | static int process_event_synth_tracing_data_stub(union perf_event *event __used, |
294 | struct perf_session *session __used) | 287 | struct perf_session *session __used) |
288 | { | ||
289 | dump_printf(": unhandled!\n"); | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static int process_event_synth_attr_stub(union perf_event *event __used, | ||
294 | struct perf_evlist **pevlist __used) | ||
295 | { | 295 | { |
296 | dump_printf(": unhandled!\n"); | 296 | dump_printf(": unhandled!\n"); |
297 | return 0; | 297 | return 0; |
298 | } | 298 | } |
299 | 299 | ||
300 | static int process_event_sample_stub(union perf_event *event __used, | 300 | static int process_event_sample_stub(struct perf_tool *tool __used, |
301 | union perf_event *event __used, | ||
301 | struct perf_sample *sample __used, | 302 | struct perf_sample *sample __used, |
302 | struct perf_evsel *evsel __used, | 303 | struct perf_evsel *evsel __used, |
303 | struct perf_session *session __used) | 304 | struct machine *machine __used) |
304 | { | 305 | { |
305 | dump_printf(": unhandled!\n"); | 306 | dump_printf(": unhandled!\n"); |
306 | return 0; | 307 | return 0; |
307 | } | 308 | } |
308 | 309 | ||
309 | static int process_event_stub(union perf_event *event __used, | 310 | static int process_event_stub(struct perf_tool *tool __used, |
311 | union perf_event *event __used, | ||
310 | struct perf_sample *sample __used, | 312 | struct perf_sample *sample __used, |
311 | struct perf_session *session __used) | 313 | struct machine *machine __used) |
312 | { | 314 | { |
313 | dump_printf(": unhandled!\n"); | 315 | dump_printf(": unhandled!\n"); |
314 | return 0; | 316 | return 0; |
315 | } | 317 | } |
316 | 318 | ||
317 | static int process_finished_round_stub(union perf_event *event __used, | 319 | static int process_finished_round_stub(struct perf_tool *tool __used, |
318 | struct perf_session *session __used, | 320 | union perf_event *event __used, |
319 | struct perf_event_ops *ops __used) | 321 | struct perf_session *perf_session __used) |
320 | { | 322 | { |
321 | dump_printf(": unhandled!\n"); | 323 | dump_printf(": unhandled!\n"); |
322 | return 0; | 324 | return 0; |
323 | } | 325 | } |
324 | 326 | ||
325 | static int process_finished_round(union perf_event *event, | 327 | static int process_event_type_stub(struct perf_tool *tool __used, |
326 | struct perf_session *session, | 328 | union perf_event *event __used) |
327 | struct perf_event_ops *ops); | 329 | { |
330 | dump_printf(": unhandled!\n"); | ||
331 | return 0; | ||
332 | } | ||
328 | 333 | ||
329 | static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) | 334 | static int process_finished_round(struct perf_tool *tool, |
335 | union perf_event *event, | ||
336 | struct perf_session *session); | ||
337 | |||
338 | static void perf_tool__fill_defaults(struct perf_tool *tool) | ||
330 | { | 339 | { |
331 | if (handler->sample == NULL) | 340 | if (tool->sample == NULL) |
332 | handler->sample = process_event_sample_stub; | 341 | tool->sample = process_event_sample_stub; |
333 | if (handler->mmap == NULL) | 342 | if (tool->mmap == NULL) |
334 | handler->mmap = process_event_stub; | 343 | tool->mmap = process_event_stub; |
335 | if (handler->comm == NULL) | 344 | if (tool->comm == NULL) |
336 | handler->comm = process_event_stub; | 345 | tool->comm = process_event_stub; |
337 | if (handler->fork == NULL) | 346 | if (tool->fork == NULL) |
338 | handler->fork = process_event_stub; | 347 | tool->fork = process_event_stub; |
339 | if (handler->exit == NULL) | 348 | if (tool->exit == NULL) |
340 | handler->exit = process_event_stub; | 349 | tool->exit = process_event_stub; |
341 | if (handler->lost == NULL) | 350 | if (tool->lost == NULL) |
342 | handler->lost = perf_event__process_lost; | 351 | tool->lost = perf_event__process_lost; |
343 | if (handler->read == NULL) | 352 | if (tool->read == NULL) |
344 | handler->read = process_event_stub; | 353 | tool->read = process_event_sample_stub; |
345 | if (handler->throttle == NULL) | 354 | if (tool->throttle == NULL) |
346 | handler->throttle = process_event_stub; | 355 | tool->throttle = process_event_stub; |
347 | if (handler->unthrottle == NULL) | 356 | if (tool->unthrottle == NULL) |
348 | handler->unthrottle = process_event_stub; | 357 | tool->unthrottle = process_event_stub; |
349 | if (handler->attr == NULL) | 358 | if (tool->attr == NULL) |
350 | handler->attr = process_event_synth_stub; | 359 | tool->attr = process_event_synth_attr_stub; |
351 | if (handler->event_type == NULL) | 360 | if (tool->event_type == NULL) |
352 | handler->event_type = process_event_synth_stub; | 361 | tool->event_type = process_event_type_stub; |
353 | if (handler->tracing_data == NULL) | 362 | if (tool->tracing_data == NULL) |
354 | handler->tracing_data = process_event_synth_stub; | 363 | tool->tracing_data = process_event_synth_tracing_data_stub; |
355 | if (handler->build_id == NULL) | 364 | if (tool->build_id == NULL) |
356 | handler->build_id = process_event_synth_stub; | 365 | tool->build_id = process_finished_round_stub; |
357 | if (handler->finished_round == NULL) { | 366 | if (tool->finished_round == NULL) { |
358 | if (handler->ordered_samples) | 367 | if (tool->ordered_samples) |
359 | handler->finished_round = process_finished_round; | 368 | tool->finished_round = process_finished_round; |
360 | else | 369 | else |
361 | handler->finished_round = process_finished_round_stub; | 370 | tool->finished_round = process_finished_round_stub; |
362 | } | 371 | } |
363 | } | 372 | } |
364 | 373 | ||
@@ -490,11 +499,11 @@ static void perf_session_free_sample_buffers(struct perf_session *session) | |||
490 | static int perf_session_deliver_event(struct perf_session *session, | 499 | static int perf_session_deliver_event(struct perf_session *session, |
491 | union perf_event *event, | 500 | union perf_event *event, |
492 | struct perf_sample *sample, | 501 | struct perf_sample *sample, |
493 | struct perf_event_ops *ops, | 502 | struct perf_tool *tool, |
494 | u64 file_offset); | 503 | u64 file_offset); |
495 | 504 | ||
496 | static void flush_sample_queue(struct perf_session *s, | 505 | static void flush_sample_queue(struct perf_session *s, |
497 | struct perf_event_ops *ops) | 506 | struct perf_tool *tool) |
498 | { | 507 | { |
499 | struct ordered_samples *os = &s->ordered_samples; | 508 | struct ordered_samples *os = &s->ordered_samples; |
500 | struct list_head *head = &os->samples; | 509 | struct list_head *head = &os->samples; |
@@ -505,7 +514,7 @@ static void flush_sample_queue(struct perf_session *s, | |||
505 | unsigned idx = 0, progress_next = os->nr_samples / 16; | 514 | unsigned idx = 0, progress_next = os->nr_samples / 16; |
506 | int ret; | 515 | int ret; |
507 | 516 | ||
508 | if (!ops->ordered_samples || !limit) | 517 | if (!tool->ordered_samples || !limit) |
509 | return; | 518 | return; |
510 | 519 | ||
511 | list_for_each_entry_safe(iter, tmp, head, list) { | 520 | list_for_each_entry_safe(iter, tmp, head, list) { |
@@ -516,7 +525,7 @@ static void flush_sample_queue(struct perf_session *s, | |||
516 | if (ret) | 525 | if (ret) |
517 | pr_err("Can't parse sample, err = %d\n", ret); | 526 | pr_err("Can't parse sample, err = %d\n", ret); |
518 | else | 527 | else |
519 | perf_session_deliver_event(s, iter->event, &sample, ops, | 528 | perf_session_deliver_event(s, iter->event, &sample, tool, |
520 | iter->file_offset); | 529 | iter->file_offset); |
521 | 530 | ||
522 | os->last_flush = iter->timestamp; | 531 | os->last_flush = iter->timestamp; |
@@ -578,11 +587,11 @@ static void flush_sample_queue(struct perf_session *s, | |||
578 | * Flush every events below timestamp 7 | 587 | * Flush every events below timestamp 7 |
579 | * etc... | 588 | * etc... |
580 | */ | 589 | */ |
581 | static int process_finished_round(union perf_event *event __used, | 590 | static int process_finished_round(struct perf_tool *tool, |
582 | struct perf_session *session, | 591 | union perf_event *event __used, |
583 | struct perf_event_ops *ops) | 592 | struct perf_session *session) |
584 | { | 593 | { |
585 | flush_sample_queue(session, ops); | 594 | flush_sample_queue(session, tool); |
586 | session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; | 595 | session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; |
587 | 596 | ||
588 | return 0; | 597 | return 0; |
@@ -737,13 +746,26 @@ static void dump_sample(struct perf_session *session, union perf_event *event, | |||
737 | callchain__printf(sample); | 746 | callchain__printf(sample); |
738 | } | 747 | } |
739 | 748 | ||
749 | static struct machine * | ||
750 | perf_session__find_machine_for_cpumode(struct perf_session *session, | ||
751 | union perf_event *event) | ||
752 | { | ||
753 | const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
754 | |||
755 | if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) | ||
756 | return perf_session__find_machine(session, event->ip.pid); | ||
757 | |||
758 | return perf_session__find_host_machine(session); | ||
759 | } | ||
760 | |||
740 | static int perf_session_deliver_event(struct perf_session *session, | 761 | static int perf_session_deliver_event(struct perf_session *session, |
741 | union perf_event *event, | 762 | union perf_event *event, |
742 | struct perf_sample *sample, | 763 | struct perf_sample *sample, |
743 | struct perf_event_ops *ops, | 764 | struct perf_tool *tool, |
744 | u64 file_offset) | 765 | u64 file_offset) |
745 | { | 766 | { |
746 | struct perf_evsel *evsel; | 767 | struct perf_evsel *evsel; |
768 | struct machine *machine; | ||
747 | 769 | ||
748 | dump_event(session, event, file_offset, sample); | 770 | dump_event(session, event, file_offset, sample); |
749 | 771 | ||
@@ -765,6 +787,8 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
765 | hists__inc_nr_events(&evsel->hists, event->header.type); | 787 | hists__inc_nr_events(&evsel->hists, event->header.type); |
766 | } | 788 | } |
767 | 789 | ||
790 | machine = perf_session__find_machine_for_cpumode(session, event); | ||
791 | |||
768 | switch (event->header.type) { | 792 | switch (event->header.type) { |
769 | case PERF_RECORD_SAMPLE: | 793 | case PERF_RECORD_SAMPLE: |
770 | dump_sample(session, event, sample); | 794 | dump_sample(session, event, sample); |
@@ -772,23 +796,25 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
772 | ++session->hists.stats.nr_unknown_id; | 796 | ++session->hists.stats.nr_unknown_id; |
773 | return -1; | 797 | return -1; |
774 | } | 798 | } |
775 | return ops->sample(event, sample, evsel, session); | 799 | return tool->sample(tool, event, sample, evsel, machine); |
776 | case PERF_RECORD_MMAP: | 800 | case PERF_RECORD_MMAP: |
777 | return ops->mmap(event, sample, session); | 801 | return tool->mmap(tool, event, sample, machine); |
778 | case PERF_RECORD_COMM: | 802 | case PERF_RECORD_COMM: |
779 | return ops->comm(event, sample, session); | 803 | return tool->comm(tool, event, sample, machine); |
780 | case PERF_RECORD_FORK: | 804 | case PERF_RECORD_FORK: |
781 | return ops->fork(event, sample, session); | 805 | return tool->fork(tool, event, sample, machine); |
782 | case PERF_RECORD_EXIT: | 806 | case PERF_RECORD_EXIT: |
783 | return ops->exit(event, sample, session); | 807 | return tool->exit(tool, event, sample, machine); |
784 | case PERF_RECORD_LOST: | 808 | case PERF_RECORD_LOST: |
785 | return ops->lost(event, sample, session); | 809 | if (tool->lost == perf_event__process_lost) |
810 | session->hists.stats.total_lost += event->lost.lost; | ||
811 | return tool->lost(tool, event, sample, machine); | ||
786 | case PERF_RECORD_READ: | 812 | case PERF_RECORD_READ: |
787 | return ops->read(event, sample, session); | 813 | return tool->read(tool, event, sample, evsel, machine); |
788 | case PERF_RECORD_THROTTLE: | 814 | case PERF_RECORD_THROTTLE: |
789 | return ops->throttle(event, sample, session); | 815 | return tool->throttle(tool, event, sample, machine); |
790 | case PERF_RECORD_UNTHROTTLE: | 816 | case PERF_RECORD_UNTHROTTLE: |
791 | return ops->unthrottle(event, sample, session); | 817 | return tool->unthrottle(tool, event, sample, machine); |
792 | default: | 818 | default: |
793 | ++session->hists.stats.nr_unknown_events; | 819 | ++session->hists.stats.nr_unknown_events; |
794 | return -1; | 820 | return -1; |
@@ -812,24 +838,29 @@ static int perf_session__preprocess_sample(struct perf_session *session, | |||
812 | } | 838 | } |
813 | 839 | ||
814 | static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, | 840 | static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, |
815 | struct perf_event_ops *ops, u64 file_offset) | 841 | struct perf_tool *tool, u64 file_offset) |
816 | { | 842 | { |
843 | int err; | ||
844 | |||
817 | dump_event(session, event, file_offset, NULL); | 845 | dump_event(session, event, file_offset, NULL); |
818 | 846 | ||
819 | /* These events are processed right away */ | 847 | /* These events are processed right away */ |
820 | switch (event->header.type) { | 848 | switch (event->header.type) { |
821 | case PERF_RECORD_HEADER_ATTR: | 849 | case PERF_RECORD_HEADER_ATTR: |
822 | return ops->attr(event, session); | 850 | err = tool->attr(event, &session->evlist); |
851 | if (err == 0) | ||
852 | perf_session__update_sample_type(session); | ||
853 | return err; | ||
823 | case PERF_RECORD_HEADER_EVENT_TYPE: | 854 | case PERF_RECORD_HEADER_EVENT_TYPE: |
824 | return ops->event_type(event, session); | 855 | return tool->event_type(tool, event); |
825 | case PERF_RECORD_HEADER_TRACING_DATA: | 856 | case PERF_RECORD_HEADER_TRACING_DATA: |
826 | /* setup for reading amidst mmap */ | 857 | /* setup for reading amidst mmap */ |
827 | lseek(session->fd, file_offset, SEEK_SET); | 858 | lseek(session->fd, file_offset, SEEK_SET); |
828 | return ops->tracing_data(event, session); | 859 | return tool->tracing_data(event, session); |
829 | case PERF_RECORD_HEADER_BUILD_ID: | 860 | case PERF_RECORD_HEADER_BUILD_ID: |
830 | return ops->build_id(event, session); | 861 | return tool->build_id(tool, event, session); |
831 | case PERF_RECORD_FINISHED_ROUND: | 862 | case PERF_RECORD_FINISHED_ROUND: |
832 | return ops->finished_round(event, session, ops); | 863 | return tool->finished_round(tool, event, session); |
833 | default: | 864 | default: |
834 | return -EINVAL; | 865 | return -EINVAL; |
835 | } | 866 | } |
@@ -837,7 +868,7 @@ static int perf_session__process_user_event(struct perf_session *session, union | |||
837 | 868 | ||
838 | static int perf_session__process_event(struct perf_session *session, | 869 | static int perf_session__process_event(struct perf_session *session, |
839 | union perf_event *event, | 870 | union perf_event *event, |
840 | struct perf_event_ops *ops, | 871 | struct perf_tool *tool, |
841 | u64 file_offset) | 872 | u64 file_offset) |
842 | { | 873 | { |
843 | struct perf_sample sample; | 874 | struct perf_sample sample; |
@@ -853,7 +884,7 @@ static int perf_session__process_event(struct perf_session *session, | |||
853 | hists__inc_nr_events(&session->hists, event->header.type); | 884 | hists__inc_nr_events(&session->hists, event->header.type); |
854 | 885 | ||
855 | if (event->header.type >= PERF_RECORD_USER_TYPE_START) | 886 | if (event->header.type >= PERF_RECORD_USER_TYPE_START) |
856 | return perf_session__process_user_event(session, event, ops, file_offset); | 887 | return perf_session__process_user_event(session, event, tool, file_offset); |
857 | 888 | ||
858 | /* | 889 | /* |
859 | * For all kernel events we get the sample data | 890 | * For all kernel events we get the sample data |
@@ -866,14 +897,14 @@ static int perf_session__process_event(struct perf_session *session, | |||
866 | if (perf_session__preprocess_sample(session, event, &sample)) | 897 | if (perf_session__preprocess_sample(session, event, &sample)) |
867 | return 0; | 898 | return 0; |
868 | 899 | ||
869 | if (ops->ordered_samples) { | 900 | if (tool->ordered_samples) { |
870 | ret = perf_session_queue_event(session, event, &sample, | 901 | ret = perf_session_queue_event(session, event, &sample, |
871 | file_offset); | 902 | file_offset); |
872 | if (ret != -ETIME) | 903 | if (ret != -ETIME) |
873 | return ret; | 904 | return ret; |
874 | } | 905 | } |
875 | 906 | ||
876 | return perf_session_deliver_event(session, event, &sample, ops, | 907 | return perf_session_deliver_event(session, event, &sample, tool, |
877 | file_offset); | 908 | file_offset); |
878 | } | 909 | } |
879 | 910 | ||
@@ -884,6 +915,11 @@ void perf_event_header__bswap(struct perf_event_header *self) | |||
884 | self->size = bswap_16(self->size); | 915 | self->size = bswap_16(self->size); |
885 | } | 916 | } |
886 | 917 | ||
918 | struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) | ||
919 | { | ||
920 | return machine__findnew_thread(&session->host_machine, pid); | ||
921 | } | ||
922 | |||
887 | static struct thread *perf_session__register_idle_thread(struct perf_session *self) | 923 | static struct thread *perf_session__register_idle_thread(struct perf_session *self) |
888 | { | 924 | { |
889 | struct thread *thread = perf_session__findnew(self, 0); | 925 | struct thread *thread = perf_session__findnew(self, 0); |
@@ -897,9 +933,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se | |||
897 | } | 933 | } |
898 | 934 | ||
899 | static void perf_session__warn_about_errors(const struct perf_session *session, | 935 | static void perf_session__warn_about_errors(const struct perf_session *session, |
900 | const struct perf_event_ops *ops) | 936 | const struct perf_tool *tool) |
901 | { | 937 | { |
902 | if (ops->lost == perf_event__process_lost && | 938 | if (tool->lost == perf_event__process_lost && |
903 | session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { | 939 | session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { |
904 | ui__warning("Processed %d events and lost %d chunks!\n\n" | 940 | ui__warning("Processed %d events and lost %d chunks!\n\n" |
905 | "Check IO/CPU overload!\n\n", | 941 | "Check IO/CPU overload!\n\n", |
@@ -934,7 +970,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session, | |||
934 | volatile int session_done; | 970 | volatile int session_done; |
935 | 971 | ||
936 | static int __perf_session__process_pipe_events(struct perf_session *self, | 972 | static int __perf_session__process_pipe_events(struct perf_session *self, |
937 | struct perf_event_ops *ops) | 973 | struct perf_tool *tool) |
938 | { | 974 | { |
939 | union perf_event event; | 975 | union perf_event event; |
940 | uint32_t size; | 976 | uint32_t size; |
@@ -943,7 +979,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self, | |||
943 | int err; | 979 | int err; |
944 | void *p; | 980 | void *p; |
945 | 981 | ||
946 | perf_event_ops__fill_defaults(ops); | 982 | perf_tool__fill_defaults(tool); |
947 | 983 | ||
948 | head = 0; | 984 | head = 0; |
949 | more: | 985 | more: |
@@ -979,8 +1015,7 @@ more: | |||
979 | } | 1015 | } |
980 | } | 1016 | } |
981 | 1017 | ||
982 | if (size == 0 || | 1018 | if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) { |
983 | (skip = perf_session__process_event(self, &event, ops, head)) < 0) { | ||
984 | dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", | 1019 | dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", |
985 | head, event.header.size, event.header.type); | 1020 | head, event.header.size, event.header.type); |
986 | /* | 1021 | /* |
@@ -1003,7 +1038,7 @@ more: | |||
1003 | done: | 1038 | done: |
1004 | err = 0; | 1039 | err = 0; |
1005 | out_err: | 1040 | out_err: |
1006 | perf_session__warn_about_errors(self, ops); | 1041 | perf_session__warn_about_errors(self, tool); |
1007 | perf_session_free_sample_buffers(self); | 1042 | perf_session_free_sample_buffers(self); |
1008 | return err; | 1043 | return err; |
1009 | } | 1044 | } |
@@ -1034,7 +1069,7 @@ fetch_mmaped_event(struct perf_session *session, | |||
1034 | 1069 | ||
1035 | int __perf_session__process_events(struct perf_session *session, | 1070 | int __perf_session__process_events(struct perf_session *session, |
1036 | u64 data_offset, u64 data_size, | 1071 | u64 data_offset, u64 data_size, |
1037 | u64 file_size, struct perf_event_ops *ops) | 1072 | u64 file_size, struct perf_tool *tool) |
1038 | { | 1073 | { |
1039 | u64 head, page_offset, file_offset, file_pos, progress_next; | 1074 | u64 head, page_offset, file_offset, file_pos, progress_next; |
1040 | int err, mmap_prot, mmap_flags, map_idx = 0; | 1075 | int err, mmap_prot, mmap_flags, map_idx = 0; |
@@ -1043,7 +1078,7 @@ int __perf_session__process_events(struct perf_session *session, | |||
1043 | union perf_event *event; | 1078 | union perf_event *event; |
1044 | uint32_t size; | 1079 | uint32_t size; |
1045 | 1080 | ||
1046 | perf_event_ops__fill_defaults(ops); | 1081 | perf_tool__fill_defaults(tool); |
1047 | 1082 | ||
1048 | page_size = sysconf(_SC_PAGESIZE); | 1083 | page_size = sysconf(_SC_PAGESIZE); |
1049 | 1084 | ||
@@ -1098,7 +1133,7 @@ more: | |||
1098 | size = event->header.size; | 1133 | size = event->header.size; |
1099 | 1134 | ||
1100 | if (size == 0 || | 1135 | if (size == 0 || |
1101 | perf_session__process_event(session, event, ops, file_pos) < 0) { | 1136 | perf_session__process_event(session, event, tool, file_pos) < 0) { |
1102 | dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", | 1137 | dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", |
1103 | file_offset + head, event->header.size, | 1138 | file_offset + head, event->header.size, |
1104 | event->header.type); | 1139 | event->header.type); |
@@ -1127,15 +1162,15 @@ more: | |||
1127 | err = 0; | 1162 | err = 0; |
1128 | /* do the final flush for ordered samples */ | 1163 | /* do the final flush for ordered samples */ |
1129 | session->ordered_samples.next_flush = ULLONG_MAX; | 1164 | session->ordered_samples.next_flush = ULLONG_MAX; |
1130 | flush_sample_queue(session, ops); | 1165 | flush_sample_queue(session, tool); |
1131 | out_err: | 1166 | out_err: |
1132 | perf_session__warn_about_errors(session, ops); | 1167 | perf_session__warn_about_errors(session, tool); |
1133 | perf_session_free_sample_buffers(session); | 1168 | perf_session_free_sample_buffers(session); |
1134 | return err; | 1169 | return err; |
1135 | } | 1170 | } |
1136 | 1171 | ||
1137 | int perf_session__process_events(struct perf_session *self, | 1172 | int perf_session__process_events(struct perf_session *self, |
1138 | struct perf_event_ops *ops) | 1173 | struct perf_tool *tool) |
1139 | { | 1174 | { |
1140 | int err; | 1175 | int err; |
1141 | 1176 | ||
@@ -1146,9 +1181,9 @@ int perf_session__process_events(struct perf_session *self, | |||
1146 | err = __perf_session__process_events(self, | 1181 | err = __perf_session__process_events(self, |
1147 | self->header.data_offset, | 1182 | self->header.data_offset, |
1148 | self->header.data_size, | 1183 | self->header.data_size, |
1149 | self->size, ops); | 1184 | self->size, tool); |
1150 | else | 1185 | else |
1151 | err = __perf_session__process_pipe_events(self, ops); | 1186 | err = __perf_session__process_pipe_events(self, tool); |
1152 | 1187 | ||
1153 | return err; | 1188 | return err; |
1154 | } | 1189 | } |
@@ -1163,9 +1198,8 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg) | |||
1163 | return true; | 1198 | return true; |
1164 | } | 1199 | } |
1165 | 1200 | ||
1166 | int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps, | 1201 | int maps__set_kallsyms_ref_reloc_sym(struct map **maps, |
1167 | const char *symbol_name, | 1202 | const char *symbol_name, u64 addr) |
1168 | u64 addr) | ||
1169 | { | 1203 | { |
1170 | char *bracket; | 1204 | char *bracket; |
1171 | enum map_type i; | 1205 | enum map_type i; |
@@ -1224,6 +1258,27 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | |||
1224 | return ret; | 1258 | return ret; |
1225 | } | 1259 | } |
1226 | 1260 | ||
1261 | size_t perf_session__fprintf(struct perf_session *session, FILE *fp) | ||
1262 | { | ||
1263 | /* | ||
1264 | * FIXME: Here we have to actually print all the machines in this | ||
1265 | * session, not just the host... | ||
1266 | */ | ||
1267 | return machine__fprintf(&session->host_machine, fp); | ||
1268 | } | ||
1269 | |||
1270 | void perf_session__remove_thread(struct perf_session *session, | ||
1271 | struct thread *th) | ||
1272 | { | ||
1273 | /* | ||
1274 | * FIXME: This one makes no sense, we need to remove the thread from | ||
1275 | * the machine it belongs to, perf_session can have many machines, so | ||
1276 | * doing it always on ->host_machine is wrong. Fix when auditing all | ||
1277 | * the 'perf kvm' code. | ||
1278 | */ | ||
1279 | machine__remove_thread(&session->host_machine, th); | ||
1280 | } | ||
1281 | |||
1227 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 1282 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
1228 | unsigned int type) | 1283 | unsigned int type) |
1229 | { | 1284 | { |
@@ -1236,17 +1291,16 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
1236 | return NULL; | 1291 | return NULL; |
1237 | } | 1292 | } |
1238 | 1293 | ||
1239 | void perf_session__print_ip(union perf_event *event, | 1294 | void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, |
1240 | struct perf_sample *sample, | 1295 | struct machine *machine, struct perf_evsel *evsel, |
1241 | struct perf_session *session, | 1296 | int print_sym, int print_dso) |
1242 | int print_sym, int print_dso) | ||
1243 | { | 1297 | { |
1244 | struct addr_location al; | 1298 | struct addr_location al; |
1245 | const char *symname, *dsoname; | 1299 | const char *symname, *dsoname; |
1246 | struct callchain_cursor *cursor = &session->callchain_cursor; | 1300 | struct callchain_cursor *cursor = &evsel->hists.callchain_cursor; |
1247 | struct callchain_cursor_node *node; | 1301 | struct callchain_cursor_node *node; |
1248 | 1302 | ||
1249 | if (perf_event__preprocess_sample(event, session, &al, sample, | 1303 | if (perf_event__preprocess_sample(event, machine, &al, sample, |
1250 | NULL) < 0) { | 1304 | NULL) < 0) { |
1251 | error("problem processing %d event, skipping it.\n", | 1305 | error("problem processing %d event, skipping it.\n", |
1252 | event->header.type); | 1306 | event->header.type); |
@@ -1255,7 +1309,7 @@ void perf_session__print_ip(union perf_event *event, | |||
1255 | 1309 | ||
1256 | if (symbol_conf.use_callchain && sample->callchain) { | 1310 | if (symbol_conf.use_callchain && sample->callchain) { |
1257 | 1311 | ||
1258 | if (perf_session__resolve_callchain(session, al.thread, | 1312 | if (machine__resolve_callchain(machine, evsel, al.thread, |
1259 | sample->callchain, NULL) != 0) { | 1313 | sample->callchain, NULL) != 0) { |
1260 | if (verbose) | 1314 | if (verbose) |
1261 | error("Failed to resolve callchain. Skipping\n"); | 1315 | error("Failed to resolve callchain. Skipping\n"); |