diff options
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r-- | tools/perf/util/session.c | 378 |
1 files changed, 231 insertions, 147 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 313dac2d94ce..caa224522fea 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -7,6 +7,8 @@ | |||
7 | #include <sys/types.h> | 7 | #include <sys/types.h> |
8 | #include <sys/mman.h> | 8 | #include <sys/mman.h> |
9 | 9 | ||
10 | #include "evlist.h" | ||
11 | #include "evsel.h" | ||
10 | #include "session.h" | 12 | #include "session.h" |
11 | #include "sort.h" | 13 | #include "sort.h" |
12 | #include "util.h" | 14 | #include "util.h" |
@@ -19,7 +21,7 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
19 | self->fd_pipe = true; | 21 | self->fd_pipe = true; |
20 | self->fd = STDIN_FILENO; | 22 | self->fd = STDIN_FILENO; |
21 | 23 | ||
22 | if (perf_header__read(self, self->fd) < 0) | 24 | if (perf_session__read_header(self, self->fd) < 0) |
23 | pr_err("incompatible file format"); | 25 | pr_err("incompatible file format"); |
24 | 26 | ||
25 | return 0; | 27 | return 0; |
@@ -51,7 +53,7 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
51 | goto out_close; | 53 | goto out_close; |
52 | } | 54 | } |
53 | 55 | ||
54 | if (perf_header__read(self, self->fd) < 0) { | 56 | if (perf_session__read_header(self, self->fd) < 0) { |
55 | pr_err("incompatible file format"); | 57 | pr_err("incompatible file format"); |
56 | goto out_close; | 58 | goto out_close; |
57 | } | 59 | } |
@@ -67,7 +69,7 @@ out_close: | |||
67 | 69 | ||
68 | static void perf_session__id_header_size(struct perf_session *session) | 70 | static void perf_session__id_header_size(struct perf_session *session) |
69 | { | 71 | { |
70 | struct sample_data *data; | 72 | struct perf_sample *data; |
71 | u64 sample_type = session->sample_type; | 73 | u64 sample_type = session->sample_type; |
72 | u16 size = 0; | 74 | u16 size = 0; |
73 | 75 | ||
@@ -92,21 +94,10 @@ out: | |||
92 | session->id_hdr_size = size; | 94 | session->id_hdr_size = size; |
93 | } | 95 | } |
94 | 96 | ||
95 | void perf_session__set_sample_id_all(struct perf_session *session, bool value) | ||
96 | { | ||
97 | session->sample_id_all = value; | ||
98 | perf_session__id_header_size(session); | ||
99 | } | ||
100 | |||
101 | void perf_session__set_sample_type(struct perf_session *session, u64 type) | ||
102 | { | ||
103 | session->sample_type = type; | ||
104 | } | ||
105 | |||
106 | void perf_session__update_sample_type(struct perf_session *self) | 97 | void perf_session__update_sample_type(struct perf_session *self) |
107 | { | 98 | { |
108 | self->sample_type = perf_header__sample_type(&self->header); | 99 | self->sample_type = perf_evlist__sample_type(self->evlist); |
109 | self->sample_id_all = perf_header__sample_id_all(&self->header); | 100 | self->sample_id_all = perf_evlist__sample_id_all(self->evlist); |
110 | perf_session__id_header_size(self); | 101 | perf_session__id_header_size(self); |
111 | } | 102 | } |
112 | 103 | ||
@@ -135,13 +126,9 @@ struct perf_session *perf_session__new(const char *filename, int mode, | |||
135 | if (self == NULL) | 126 | if (self == NULL) |
136 | goto out; | 127 | goto out; |
137 | 128 | ||
138 | if (perf_header__init(&self->header) < 0) | ||
139 | goto out_free; | ||
140 | |||
141 | memcpy(self->filename, filename, len); | 129 | memcpy(self->filename, filename, len); |
142 | self->threads = RB_ROOT; | 130 | self->threads = RB_ROOT; |
143 | INIT_LIST_HEAD(&self->dead_threads); | 131 | INIT_LIST_HEAD(&self->dead_threads); |
144 | self->hists_tree = RB_ROOT; | ||
145 | self->last_match = NULL; | 132 | self->last_match = NULL; |
146 | /* | 133 | /* |
147 | * On 64bit we can mmap the data file in one go. No need for tiny mmap | 134 | * On 64bit we can mmap the data file in one go. No need for tiny mmap |
@@ -162,17 +149,16 @@ struct perf_session *perf_session__new(const char *filename, int mode, | |||
162 | if (mode == O_RDONLY) { | 149 | if (mode == O_RDONLY) { |
163 | if (perf_session__open(self, force) < 0) | 150 | if (perf_session__open(self, force) < 0) |
164 | goto out_delete; | 151 | goto out_delete; |
152 | perf_session__update_sample_type(self); | ||
165 | } else if (mode == O_WRONLY) { | 153 | } else if (mode == O_WRONLY) { |
166 | /* | 154 | /* |
167 | * In O_RDONLY mode this will be performed when reading the | 155 | * In O_RDONLY mode this will be performed when reading the |
168 | * kernel MMAP event, in event__process_mmap(). | 156 | * kernel MMAP event, in perf_event__process_mmap(). |
169 | */ | 157 | */ |
170 | if (perf_session__create_kernel_maps(self) < 0) | 158 | if (perf_session__create_kernel_maps(self) < 0) |
171 | goto out_delete; | 159 | goto out_delete; |
172 | } | 160 | } |
173 | 161 | ||
174 | perf_session__update_sample_type(self); | ||
175 | |||
176 | if (ops && ops->ordering_requires_timestamps && | 162 | if (ops && ops->ordering_requires_timestamps && |
177 | ops->ordered_samples && !self->sample_id_all) { | 163 | ops->ordered_samples && !self->sample_id_all) { |
178 | dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); | 164 | dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); |
@@ -181,9 +167,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, | |||
181 | 167 | ||
182 | out: | 168 | out: |
183 | return self; | 169 | return self; |
184 | out_free: | ||
185 | free(self); | ||
186 | return NULL; | ||
187 | out_delete: | 170 | out_delete: |
188 | perf_session__delete(self); | 171 | perf_session__delete(self); |
189 | return NULL; | 172 | return NULL; |
@@ -214,7 +197,6 @@ static void perf_session__delete_threads(struct perf_session *self) | |||
214 | 197 | ||
215 | void perf_session__delete(struct perf_session *self) | 198 | void perf_session__delete(struct perf_session *self) |
216 | { | 199 | { |
217 | perf_header__exit(&self->header); | ||
218 | perf_session__destroy_kernel_maps(self); | 200 | perf_session__destroy_kernel_maps(self); |
219 | perf_session__delete_dead_threads(self); | 201 | perf_session__delete_dead_threads(self); |
220 | perf_session__delete_threads(self); | 202 | perf_session__delete_threads(self); |
@@ -242,17 +224,16 @@ static bool symbol__match_parent_regex(struct symbol *sym) | |||
242 | return 0; | 224 | return 0; |
243 | } | 225 | } |
244 | 226 | ||
245 | struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, | 227 | int perf_session__resolve_callchain(struct perf_session *self, |
246 | struct thread *thread, | 228 | struct thread *thread, |
247 | struct ip_callchain *chain, | 229 | struct ip_callchain *chain, |
248 | struct symbol **parent) | 230 | struct symbol **parent) |
249 | { | 231 | { |
250 | u8 cpumode = PERF_RECORD_MISC_USER; | 232 | u8 cpumode = PERF_RECORD_MISC_USER; |
251 | unsigned int i; | 233 | unsigned int i; |
252 | struct map_symbol *syms = calloc(chain->nr, sizeof(*syms)); | 234 | int err; |
253 | 235 | ||
254 | if (!syms) | 236 | callchain_cursor_reset(&self->callchain_cursor); |
255 | return NULL; | ||
256 | 237 | ||
257 | for (i = 0; i < chain->nr; i++) { | 238 | for (i = 0; i < chain->nr; i++) { |
258 | u64 ip = chain->ips[i]; | 239 | u64 ip = chain->ips[i]; |
@@ -281,30 +262,42 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, | |||
281 | *parent = al.sym; | 262 | *parent = al.sym; |
282 | if (!symbol_conf.use_callchain) | 263 | if (!symbol_conf.use_callchain) |
283 | break; | 264 | break; |
284 | syms[i].map = al.map; | ||
285 | syms[i].sym = al.sym; | ||
286 | } | 265 | } |
266 | |||
267 | err = callchain_cursor_append(&self->callchain_cursor, | ||
268 | ip, al.map, al.sym); | ||
269 | if (err) | ||
270 | return err; | ||
287 | } | 271 | } |
288 | 272 | ||
289 | return syms; | 273 | return 0; |
290 | } | 274 | } |
291 | 275 | ||
292 | static int process_event_synth_stub(event_t *event __used, | 276 | static int process_event_synth_stub(union perf_event *event __used, |
293 | struct perf_session *session __used) | 277 | struct perf_session *session __used) |
294 | { | 278 | { |
295 | dump_printf(": unhandled!\n"); | 279 | dump_printf(": unhandled!\n"); |
296 | return 0; | 280 | return 0; |
297 | } | 281 | } |
298 | 282 | ||
299 | static int process_event_stub(event_t *event __used, | 283 | static int process_event_sample_stub(union perf_event *event __used, |
300 | struct sample_data *sample __used, | 284 | struct perf_sample *sample __used, |
285 | struct perf_evsel *evsel __used, | ||
286 | struct perf_session *session __used) | ||
287 | { | ||
288 | dump_printf(": unhandled!\n"); | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int process_event_stub(union perf_event *event __used, | ||
293 | struct perf_sample *sample __used, | ||
301 | struct perf_session *session __used) | 294 | struct perf_session *session __used) |
302 | { | 295 | { |
303 | dump_printf(": unhandled!\n"); | 296 | dump_printf(": unhandled!\n"); |
304 | return 0; | 297 | return 0; |
305 | } | 298 | } |
306 | 299 | ||
307 | static int process_finished_round_stub(event_t *event __used, | 300 | static int process_finished_round_stub(union perf_event *event __used, |
308 | struct perf_session *session __used, | 301 | struct perf_session *session __used, |
309 | struct perf_event_ops *ops __used) | 302 | struct perf_event_ops *ops __used) |
310 | { | 303 | { |
@@ -312,14 +305,14 @@ static int process_finished_round_stub(event_t *event __used, | |||
312 | return 0; | 305 | return 0; |
313 | } | 306 | } |
314 | 307 | ||
315 | static int process_finished_round(event_t *event, | 308 | static int process_finished_round(union perf_event *event, |
316 | struct perf_session *session, | 309 | struct perf_session *session, |
317 | struct perf_event_ops *ops); | 310 | struct perf_event_ops *ops); |
318 | 311 | ||
319 | static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) | 312 | static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) |
320 | { | 313 | { |
321 | if (handler->sample == NULL) | 314 | if (handler->sample == NULL) |
322 | handler->sample = process_event_stub; | 315 | handler->sample = process_event_sample_stub; |
323 | if (handler->mmap == NULL) | 316 | if (handler->mmap == NULL) |
324 | handler->mmap = process_event_stub; | 317 | handler->mmap = process_event_stub; |
325 | if (handler->comm == NULL) | 318 | if (handler->comm == NULL) |
@@ -329,7 +322,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) | |||
329 | if (handler->exit == NULL) | 322 | if (handler->exit == NULL) |
330 | handler->exit = process_event_stub; | 323 | handler->exit = process_event_stub; |
331 | if (handler->lost == NULL) | 324 | if (handler->lost == NULL) |
332 | handler->lost = event__process_lost; | 325 | handler->lost = perf_event__process_lost; |
333 | if (handler->read == NULL) | 326 | if (handler->read == NULL) |
334 | handler->read = process_event_stub; | 327 | handler->read = process_event_stub; |
335 | if (handler->throttle == NULL) | 328 | if (handler->throttle == NULL) |
@@ -363,98 +356,98 @@ void mem_bswap_64(void *src, int byte_size) | |||
363 | } | 356 | } |
364 | } | 357 | } |
365 | 358 | ||
366 | static void event__all64_swap(event_t *self) | 359 | static void perf_event__all64_swap(union perf_event *event) |
367 | { | 360 | { |
368 | struct perf_event_header *hdr = &self->header; | 361 | struct perf_event_header *hdr = &event->header; |
369 | mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr)); | 362 | mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr)); |
370 | } | 363 | } |
371 | 364 | ||
372 | static void event__comm_swap(event_t *self) | 365 | static void perf_event__comm_swap(union perf_event *event) |
373 | { | 366 | { |
374 | self->comm.pid = bswap_32(self->comm.pid); | 367 | event->comm.pid = bswap_32(event->comm.pid); |
375 | self->comm.tid = bswap_32(self->comm.tid); | 368 | event->comm.tid = bswap_32(event->comm.tid); |
376 | } | 369 | } |
377 | 370 | ||
378 | static void event__mmap_swap(event_t *self) | 371 | static void perf_event__mmap_swap(union perf_event *event) |
379 | { | 372 | { |
380 | self->mmap.pid = bswap_32(self->mmap.pid); | 373 | event->mmap.pid = bswap_32(event->mmap.pid); |
381 | self->mmap.tid = bswap_32(self->mmap.tid); | 374 | event->mmap.tid = bswap_32(event->mmap.tid); |
382 | self->mmap.start = bswap_64(self->mmap.start); | 375 | event->mmap.start = bswap_64(event->mmap.start); |
383 | self->mmap.len = bswap_64(self->mmap.len); | 376 | event->mmap.len = bswap_64(event->mmap.len); |
384 | self->mmap.pgoff = bswap_64(self->mmap.pgoff); | 377 | event->mmap.pgoff = bswap_64(event->mmap.pgoff); |
385 | } | 378 | } |
386 | 379 | ||
387 | static void event__task_swap(event_t *self) | 380 | static void perf_event__task_swap(union perf_event *event) |
388 | { | 381 | { |
389 | self->fork.pid = bswap_32(self->fork.pid); | 382 | event->fork.pid = bswap_32(event->fork.pid); |
390 | self->fork.tid = bswap_32(self->fork.tid); | 383 | event->fork.tid = bswap_32(event->fork.tid); |
391 | self->fork.ppid = bswap_32(self->fork.ppid); | 384 | event->fork.ppid = bswap_32(event->fork.ppid); |
392 | self->fork.ptid = bswap_32(self->fork.ptid); | 385 | event->fork.ptid = bswap_32(event->fork.ptid); |
393 | self->fork.time = bswap_64(self->fork.time); | 386 | event->fork.time = bswap_64(event->fork.time); |
394 | } | 387 | } |
395 | 388 | ||
396 | static void event__read_swap(event_t *self) | 389 | static void perf_event__read_swap(union perf_event *event) |
397 | { | 390 | { |
398 | self->read.pid = bswap_32(self->read.pid); | 391 | event->read.pid = bswap_32(event->read.pid); |
399 | self->read.tid = bswap_32(self->read.tid); | 392 | event->read.tid = bswap_32(event->read.tid); |
400 | self->read.value = bswap_64(self->read.value); | 393 | event->read.value = bswap_64(event->read.value); |
401 | self->read.time_enabled = bswap_64(self->read.time_enabled); | 394 | event->read.time_enabled = bswap_64(event->read.time_enabled); |
402 | self->read.time_running = bswap_64(self->read.time_running); | 395 | event->read.time_running = bswap_64(event->read.time_running); |
403 | self->read.id = bswap_64(self->read.id); | 396 | event->read.id = bswap_64(event->read.id); |
404 | } | 397 | } |
405 | 398 | ||
406 | static void event__attr_swap(event_t *self) | 399 | static void perf_event__attr_swap(union perf_event *event) |
407 | { | 400 | { |
408 | size_t size; | 401 | size_t size; |
409 | 402 | ||
410 | self->attr.attr.type = bswap_32(self->attr.attr.type); | 403 | event->attr.attr.type = bswap_32(event->attr.attr.type); |
411 | self->attr.attr.size = bswap_32(self->attr.attr.size); | 404 | event->attr.attr.size = bswap_32(event->attr.attr.size); |
412 | self->attr.attr.config = bswap_64(self->attr.attr.config); | 405 | event->attr.attr.config = bswap_64(event->attr.attr.config); |
413 | self->attr.attr.sample_period = bswap_64(self->attr.attr.sample_period); | 406 | event->attr.attr.sample_period = bswap_64(event->attr.attr.sample_period); |
414 | self->attr.attr.sample_type = bswap_64(self->attr.attr.sample_type); | 407 | event->attr.attr.sample_type = bswap_64(event->attr.attr.sample_type); |
415 | self->attr.attr.read_format = bswap_64(self->attr.attr.read_format); | 408 | event->attr.attr.read_format = bswap_64(event->attr.attr.read_format); |
416 | self->attr.attr.wakeup_events = bswap_32(self->attr.attr.wakeup_events); | 409 | event->attr.attr.wakeup_events = bswap_32(event->attr.attr.wakeup_events); |
417 | self->attr.attr.bp_type = bswap_32(self->attr.attr.bp_type); | 410 | event->attr.attr.bp_type = bswap_32(event->attr.attr.bp_type); |
418 | self->attr.attr.bp_addr = bswap_64(self->attr.attr.bp_addr); | 411 | event->attr.attr.bp_addr = bswap_64(event->attr.attr.bp_addr); |
419 | self->attr.attr.bp_len = bswap_64(self->attr.attr.bp_len); | 412 | event->attr.attr.bp_len = bswap_64(event->attr.attr.bp_len); |
420 | 413 | ||
421 | size = self->header.size; | 414 | size = event->header.size; |
422 | size -= (void *)&self->attr.id - (void *)self; | 415 | size -= (void *)&event->attr.id - (void *)event; |
423 | mem_bswap_64(self->attr.id, size); | 416 | mem_bswap_64(event->attr.id, size); |
424 | } | 417 | } |
425 | 418 | ||
426 | static void event__event_type_swap(event_t *self) | 419 | static void perf_event__event_type_swap(union perf_event *event) |
427 | { | 420 | { |
428 | self->event_type.event_type.event_id = | 421 | event->event_type.event_type.event_id = |
429 | bswap_64(self->event_type.event_type.event_id); | 422 | bswap_64(event->event_type.event_type.event_id); |
430 | } | 423 | } |
431 | 424 | ||
432 | static void event__tracing_data_swap(event_t *self) | 425 | static void perf_event__tracing_data_swap(union perf_event *event) |
433 | { | 426 | { |
434 | self->tracing_data.size = bswap_32(self->tracing_data.size); | 427 | event->tracing_data.size = bswap_32(event->tracing_data.size); |
435 | } | 428 | } |
436 | 429 | ||
437 | typedef void (*event__swap_op)(event_t *self); | 430 | typedef void (*perf_event__swap_op)(union perf_event *event); |
438 | 431 | ||
439 | static event__swap_op event__swap_ops[] = { | 432 | static perf_event__swap_op perf_event__swap_ops[] = { |
440 | [PERF_RECORD_MMAP] = event__mmap_swap, | 433 | [PERF_RECORD_MMAP] = perf_event__mmap_swap, |
441 | [PERF_RECORD_COMM] = event__comm_swap, | 434 | [PERF_RECORD_COMM] = perf_event__comm_swap, |
442 | [PERF_RECORD_FORK] = event__task_swap, | 435 | [PERF_RECORD_FORK] = perf_event__task_swap, |
443 | [PERF_RECORD_EXIT] = event__task_swap, | 436 | [PERF_RECORD_EXIT] = perf_event__task_swap, |
444 | [PERF_RECORD_LOST] = event__all64_swap, | 437 | [PERF_RECORD_LOST] = perf_event__all64_swap, |
445 | [PERF_RECORD_READ] = event__read_swap, | 438 | [PERF_RECORD_READ] = perf_event__read_swap, |
446 | [PERF_RECORD_SAMPLE] = event__all64_swap, | 439 | [PERF_RECORD_SAMPLE] = perf_event__all64_swap, |
447 | [PERF_RECORD_HEADER_ATTR] = event__attr_swap, | 440 | [PERF_RECORD_HEADER_ATTR] = perf_event__attr_swap, |
448 | [PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap, | 441 | [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, |
449 | [PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap, | 442 | [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, |
450 | [PERF_RECORD_HEADER_BUILD_ID] = NULL, | 443 | [PERF_RECORD_HEADER_BUILD_ID] = NULL, |
451 | [PERF_RECORD_HEADER_MAX] = NULL, | 444 | [PERF_RECORD_HEADER_MAX] = NULL, |
452 | }; | 445 | }; |
453 | 446 | ||
454 | struct sample_queue { | 447 | struct sample_queue { |
455 | u64 timestamp; | 448 | u64 timestamp; |
456 | u64 file_offset; | 449 | u64 file_offset; |
457 | event_t *event; | 450 | union perf_event *event; |
458 | struct list_head list; | 451 | struct list_head list; |
459 | }; | 452 | }; |
460 | 453 | ||
@@ -472,8 +465,8 @@ static void perf_session_free_sample_buffers(struct perf_session *session) | |||
472 | } | 465 | } |
473 | 466 | ||
474 | static int perf_session_deliver_event(struct perf_session *session, | 467 | static int perf_session_deliver_event(struct perf_session *session, |
475 | event_t *event, | 468 | union perf_event *event, |
476 | struct sample_data *sample, | 469 | struct perf_sample *sample, |
477 | struct perf_event_ops *ops, | 470 | struct perf_event_ops *ops, |
478 | u64 file_offset); | 471 | u64 file_offset); |
479 | 472 | ||
@@ -483,7 +476,7 @@ static void flush_sample_queue(struct perf_session *s, | |||
483 | struct ordered_samples *os = &s->ordered_samples; | 476 | struct ordered_samples *os = &s->ordered_samples; |
484 | struct list_head *head = &os->samples; | 477 | struct list_head *head = &os->samples; |
485 | struct sample_queue *tmp, *iter; | 478 | struct sample_queue *tmp, *iter; |
486 | struct sample_data sample; | 479 | struct perf_sample sample; |
487 | u64 limit = os->next_flush; | 480 | u64 limit = os->next_flush; |
488 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; | 481 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; |
489 | 482 | ||
@@ -494,7 +487,7 @@ static void flush_sample_queue(struct perf_session *s, | |||
494 | if (iter->timestamp > limit) | 487 | if (iter->timestamp > limit) |
495 | break; | 488 | break; |
496 | 489 | ||
497 | event__parse_sample(iter->event, s, &sample); | 490 | perf_session__parse_sample(s, iter->event, &sample); |
498 | perf_session_deliver_event(s, iter->event, &sample, ops, | 491 | perf_session_deliver_event(s, iter->event, &sample, ops, |
499 | iter->file_offset); | 492 | iter->file_offset); |
500 | 493 | ||
@@ -550,7 +543,7 @@ static void flush_sample_queue(struct perf_session *s, | |||
550 | * Flush every events below timestamp 7 | 543 | * Flush every events below timestamp 7 |
551 | * etc... | 544 | * etc... |
552 | */ | 545 | */ |
553 | static int process_finished_round(event_t *event __used, | 546 | static int process_finished_round(union perf_event *event __used, |
554 | struct perf_session *session, | 547 | struct perf_session *session, |
555 | struct perf_event_ops *ops) | 548 | struct perf_event_ops *ops) |
556 | { | 549 | { |
@@ -607,12 +600,12 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s) | |||
607 | 600 | ||
608 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) | 601 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) |
609 | 602 | ||
610 | static int perf_session_queue_event(struct perf_session *s, event_t *event, | 603 | static int perf_session_queue_event(struct perf_session *s, union perf_event *event, |
611 | struct sample_data *data, u64 file_offset) | 604 | struct perf_sample *sample, u64 file_offset) |
612 | { | 605 | { |
613 | struct ordered_samples *os = &s->ordered_samples; | 606 | struct ordered_samples *os = &s->ordered_samples; |
614 | struct list_head *sc = &os->sample_cache; | 607 | struct list_head *sc = &os->sample_cache; |
615 | u64 timestamp = data->time; | 608 | u64 timestamp = sample->time; |
616 | struct sample_queue *new; | 609 | struct sample_queue *new; |
617 | 610 | ||
618 | if (!timestamp || timestamp == ~0ULL) | 611 | if (!timestamp || timestamp == ~0ULL) |
@@ -648,19 +641,20 @@ static int perf_session_queue_event(struct perf_session *s, event_t *event, | |||
648 | return 0; | 641 | return 0; |
649 | } | 642 | } |
650 | 643 | ||
651 | static void callchain__printf(struct sample_data *sample) | 644 | static void callchain__printf(struct perf_sample *sample) |
652 | { | 645 | { |
653 | unsigned int i; | 646 | unsigned int i; |
654 | 647 | ||
655 | printf("... chain: nr:%Lu\n", sample->callchain->nr); | 648 | printf("... chain: nr:%" PRIu64 "\n", sample->callchain->nr); |
656 | 649 | ||
657 | for (i = 0; i < sample->callchain->nr; i++) | 650 | for (i = 0; i < sample->callchain->nr; i++) |
658 | printf("..... %2d: %016Lx\n", i, sample->callchain->ips[i]); | 651 | printf("..... %2d: %016" PRIx64 "\n", |
652 | i, sample->callchain->ips[i]); | ||
659 | } | 653 | } |
660 | 654 | ||
661 | static void perf_session__print_tstamp(struct perf_session *session, | 655 | static void perf_session__print_tstamp(struct perf_session *session, |
662 | event_t *event, | 656 | union perf_event *event, |
663 | struct sample_data *sample) | 657 | struct perf_sample *sample) |
664 | { | 658 | { |
665 | if (event->header.type != PERF_RECORD_SAMPLE && | 659 | if (event->header.type != PERF_RECORD_SAMPLE && |
666 | !session->sample_id_all) { | 660 | !session->sample_id_all) { |
@@ -672,52 +666,60 @@ static void perf_session__print_tstamp(struct perf_session *session, | |||
672 | printf("%u ", sample->cpu); | 666 | printf("%u ", sample->cpu); |
673 | 667 | ||
674 | if (session->sample_type & PERF_SAMPLE_TIME) | 668 | if (session->sample_type & PERF_SAMPLE_TIME) |
675 | printf("%Lu ", sample->time); | 669 | printf("%" PRIu64 " ", sample->time); |
676 | } | 670 | } |
677 | 671 | ||
678 | static void dump_event(struct perf_session *session, event_t *event, | 672 | static void dump_event(struct perf_session *session, union perf_event *event, |
679 | u64 file_offset, struct sample_data *sample) | 673 | u64 file_offset, struct perf_sample *sample) |
680 | { | 674 | { |
681 | if (!dump_trace) | 675 | if (!dump_trace) |
682 | return; | 676 | return; |
683 | 677 | ||
684 | printf("\n%#Lx [%#x]: event: %d\n", file_offset, event->header.size, | 678 | printf("\n%#" PRIx64 " [%#x]: event: %d\n", |
685 | event->header.type); | 679 | file_offset, event->header.size, event->header.type); |
686 | 680 | ||
687 | trace_event(event); | 681 | trace_event(event); |
688 | 682 | ||
689 | if (sample) | 683 | if (sample) |
690 | perf_session__print_tstamp(session, event, sample); | 684 | perf_session__print_tstamp(session, event, sample); |
691 | 685 | ||
692 | printf("%#Lx [%#x]: PERF_RECORD_%s", file_offset, event->header.size, | 686 | printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset, |
693 | event__get_event_name(event->header.type)); | 687 | event->header.size, perf_event__name(event->header.type)); |
694 | } | 688 | } |
695 | 689 | ||
696 | static void dump_sample(struct perf_session *session, event_t *event, | 690 | static void dump_sample(struct perf_session *session, union perf_event *event, |
697 | struct sample_data *sample) | 691 | struct perf_sample *sample) |
698 | { | 692 | { |
699 | if (!dump_trace) | 693 | if (!dump_trace) |
700 | return; | 694 | return; |
701 | 695 | ||
702 | printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, | 696 | printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 "\n", |
703 | sample->pid, sample->tid, sample->ip, sample->period); | 697 | event->header.misc, sample->pid, sample->tid, sample->ip, |
698 | sample->period); | ||
704 | 699 | ||
705 | if (session->sample_type & PERF_SAMPLE_CALLCHAIN) | 700 | if (session->sample_type & PERF_SAMPLE_CALLCHAIN) |
706 | callchain__printf(sample); | 701 | callchain__printf(sample); |
707 | } | 702 | } |
708 | 703 | ||
709 | static int perf_session_deliver_event(struct perf_session *session, | 704 | static int perf_session_deliver_event(struct perf_session *session, |
710 | event_t *event, | 705 | union perf_event *event, |
711 | struct sample_data *sample, | 706 | struct perf_sample *sample, |
712 | struct perf_event_ops *ops, | 707 | struct perf_event_ops *ops, |
713 | u64 file_offset) | 708 | u64 file_offset) |
714 | { | 709 | { |
710 | struct perf_evsel *evsel; | ||
711 | |||
715 | dump_event(session, event, file_offset, sample); | 712 | dump_event(session, event, file_offset, sample); |
716 | 713 | ||
717 | switch (event->header.type) { | 714 | switch (event->header.type) { |
718 | case PERF_RECORD_SAMPLE: | 715 | case PERF_RECORD_SAMPLE: |
719 | dump_sample(session, event, sample); | 716 | dump_sample(session, event, sample); |
720 | return ops->sample(event, sample, session); | 717 | evsel = perf_evlist__id2evsel(session->evlist, sample->id); |
718 | if (evsel == NULL) { | ||
719 | ++session->hists.stats.nr_unknown_id; | ||
720 | return -1; | ||
721 | } | ||
722 | return ops->sample(event, sample, evsel, session); | ||
721 | case PERF_RECORD_MMAP: | 723 | case PERF_RECORD_MMAP: |
722 | return ops->mmap(event, sample, session); | 724 | return ops->mmap(event, sample, session); |
723 | case PERF_RECORD_COMM: | 725 | case PERF_RECORD_COMM: |
@@ -741,7 +743,7 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
741 | } | 743 | } |
742 | 744 | ||
743 | static int perf_session__preprocess_sample(struct perf_session *session, | 745 | static int perf_session__preprocess_sample(struct perf_session *session, |
744 | event_t *event, struct sample_data *sample) | 746 | union perf_event *event, struct perf_sample *sample) |
745 | { | 747 | { |
746 | if (event->header.type != PERF_RECORD_SAMPLE || | 748 | if (event->header.type != PERF_RECORD_SAMPLE || |
747 | !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) | 749 | !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) |
@@ -756,7 +758,7 @@ static int perf_session__preprocess_sample(struct perf_session *session, | |||
756 | return 0; | 758 | return 0; |
757 | } | 759 | } |
758 | 760 | ||
759 | static int perf_session__process_user_event(struct perf_session *session, event_t *event, | 761 | static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, |
760 | struct perf_event_ops *ops, u64 file_offset) | 762 | struct perf_event_ops *ops, u64 file_offset) |
761 | { | 763 | { |
762 | dump_event(session, event, file_offset, NULL); | 764 | dump_event(session, event, file_offset, NULL); |
@@ -781,15 +783,16 @@ static int perf_session__process_user_event(struct perf_session *session, event_ | |||
781 | } | 783 | } |
782 | 784 | ||
783 | static int perf_session__process_event(struct perf_session *session, | 785 | static int perf_session__process_event(struct perf_session *session, |
784 | event_t *event, | 786 | union perf_event *event, |
785 | struct perf_event_ops *ops, | 787 | struct perf_event_ops *ops, |
786 | u64 file_offset) | 788 | u64 file_offset) |
787 | { | 789 | { |
788 | struct sample_data sample; | 790 | struct perf_sample sample; |
789 | int ret; | 791 | int ret; |
790 | 792 | ||
791 | if (session->header.needs_swap && event__swap_ops[event->header.type]) | 793 | if (session->header.needs_swap && |
792 | event__swap_ops[event->header.type](event); | 794 | perf_event__swap_ops[event->header.type]) |
795 | perf_event__swap_ops[event->header.type](event); | ||
793 | 796 | ||
794 | if (event->header.type >= PERF_RECORD_HEADER_MAX) | 797 | if (event->header.type >= PERF_RECORD_HEADER_MAX) |
795 | return -EINVAL; | 798 | return -EINVAL; |
@@ -802,7 +805,7 @@ static int perf_session__process_event(struct perf_session *session, | |||
802 | /* | 805 | /* |
803 | * For all kernel events we get the sample data | 806 | * For all kernel events we get the sample data |
804 | */ | 807 | */ |
805 | event__parse_sample(event, session, &sample); | 808 | perf_session__parse_sample(session, event, &sample); |
806 | 809 | ||
807 | /* Preprocess sample records - precheck callchains */ | 810 | /* Preprocess sample records - precheck callchains */ |
808 | if (perf_session__preprocess_sample(session, event, &sample)) | 811 | if (perf_session__preprocess_sample(session, event, &sample)) |
@@ -841,10 +844,10 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se | |||
841 | static void perf_session__warn_about_errors(const struct perf_session *session, | 844 | static void perf_session__warn_about_errors(const struct perf_session *session, |
842 | const struct perf_event_ops *ops) | 845 | const struct perf_event_ops *ops) |
843 | { | 846 | { |
844 | if (ops->lost == event__process_lost && | 847 | if (ops->lost == perf_event__process_lost && |
845 | session->hists.stats.total_lost != 0) { | 848 | session->hists.stats.total_lost != 0) { |
846 | ui__warning("Processed %Lu events and LOST %Lu!\n\n" | 849 | ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64 |
847 | "Check IO/CPU overload!\n\n", | 850 | "!\n\nCheck IO/CPU overload!\n\n", |
848 | session->hists.stats.total_period, | 851 | session->hists.stats.total_period, |
849 | session->hists.stats.total_lost); | 852 | session->hists.stats.total_lost); |
850 | } | 853 | } |
@@ -858,6 +861,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session, | |||
858 | session->hists.stats.nr_unknown_events); | 861 | session->hists.stats.nr_unknown_events); |
859 | } | 862 | } |
860 | 863 | ||
864 | if (session->hists.stats.nr_unknown_id != 0) { | ||
865 | ui__warning("%u samples with id not present in the header\n", | ||
866 | session->hists.stats.nr_unknown_id); | ||
867 | } | ||
868 | |||
861 | if (session->hists.stats.nr_invalid_chains != 0) { | 869 | if (session->hists.stats.nr_invalid_chains != 0) { |
862 | ui__warning("Found invalid callchains!\n\n" | 870 | ui__warning("Found invalid callchains!\n\n" |
863 | "%u out of %u events were discarded for this reason.\n\n" | 871 | "%u out of %u events were discarded for this reason.\n\n" |
@@ -873,7 +881,7 @@ volatile int session_done; | |||
873 | static int __perf_session__process_pipe_events(struct perf_session *self, | 881 | static int __perf_session__process_pipe_events(struct perf_session *self, |
874 | struct perf_event_ops *ops) | 882 | struct perf_event_ops *ops) |
875 | { | 883 | { |
876 | event_t event; | 884 | union perf_event event; |
877 | uint32_t size; | 885 | uint32_t size; |
878 | int skip = 0; | 886 | int skip = 0; |
879 | u64 head; | 887 | u64 head; |
@@ -918,7 +926,7 @@ more: | |||
918 | 926 | ||
919 | if (size == 0 || | 927 | if (size == 0 || |
920 | (skip = perf_session__process_event(self, &event, ops, head)) < 0) { | 928 | (skip = perf_session__process_event(self, &event, ops, head)) < 0) { |
921 | dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", | 929 | dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", |
922 | head, event.header.size, event.header.type); | 930 | head, event.header.size, event.header.type); |
923 | /* | 931 | /* |
924 | * assume we lost track of the stream, check alignment, and | 932 | * assume we lost track of the stream, check alignment, and |
@@ -954,7 +962,7 @@ int __perf_session__process_events(struct perf_session *session, | |||
954 | struct ui_progress *progress; | 962 | struct ui_progress *progress; |
955 | size_t page_size, mmap_size; | 963 | size_t page_size, mmap_size; |
956 | char *buf, *mmaps[8]; | 964 | char *buf, *mmaps[8]; |
957 | event_t *event; | 965 | union perf_event *event; |
958 | uint32_t size; | 966 | uint32_t size; |
959 | 967 | ||
960 | perf_event_ops__fill_defaults(ops); | 968 | perf_event_ops__fill_defaults(ops); |
@@ -999,7 +1007,7 @@ remap: | |||
999 | file_pos = file_offset + head; | 1007 | file_pos = file_offset + head; |
1000 | 1008 | ||
1001 | more: | 1009 | more: |
1002 | event = (event_t *)(buf + head); | 1010 | event = (union perf_event *)(buf + head); |
1003 | 1011 | ||
1004 | if (session->header.needs_swap) | 1012 | if (session->header.needs_swap) |
1005 | perf_event_header__bswap(&event->header); | 1013 | perf_event_header__bswap(&event->header); |
@@ -1023,7 +1031,7 @@ more: | |||
1023 | 1031 | ||
1024 | if (size == 0 || | 1032 | if (size == 0 || |
1025 | perf_session__process_event(session, event, ops, file_pos) < 0) { | 1033 | perf_session__process_event(session, event, ops, file_pos) < 0) { |
1026 | dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", | 1034 | dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", |
1027 | file_offset + head, event->header.size, | 1035 | file_offset + head, event->header.size, |
1028 | event->header.type); | 1036 | event->header.type); |
1029 | /* | 1037 | /* |
@@ -1132,3 +1140,79 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, | |||
1132 | size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); | 1140 | size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); |
1133 | return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); | 1141 | return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); |
1134 | } | 1142 | } |
1143 | |||
1144 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | ||
1145 | { | ||
1146 | struct perf_evsel *pos; | ||
1147 | size_t ret = fprintf(fp, "Aggregated stats:\n"); | ||
1148 | |||
1149 | ret += hists__fprintf_nr_events(&session->hists, fp); | ||
1150 | |||
1151 | list_for_each_entry(pos, &session->evlist->entries, node) { | ||
1152 | ret += fprintf(fp, "%s stats:\n", event_name(pos)); | ||
1153 | ret += hists__fprintf_nr_events(&pos->hists, fp); | ||
1154 | } | ||
1155 | |||
1156 | return ret; | ||
1157 | } | ||
1158 | |||
1159 | void perf_session__print_symbols(union perf_event *event, | ||
1160 | struct perf_sample *sample, | ||
1161 | struct perf_session *session) | ||
1162 | { | ||
1163 | struct addr_location al; | ||
1164 | const char *symname, *dsoname; | ||
1165 | struct callchain_cursor *cursor = &session->callchain_cursor; | ||
1166 | struct callchain_cursor_node *node; | ||
1167 | |||
1168 | if (perf_event__preprocess_sample(event, session, &al, sample, | ||
1169 | NULL) < 0) { | ||
1170 | error("problem processing %d event, skipping it.\n", | ||
1171 | event->header.type); | ||
1172 | return; | ||
1173 | } | ||
1174 | |||
1175 | if (symbol_conf.use_callchain && sample->callchain) { | ||
1176 | |||
1177 | if (perf_session__resolve_callchain(session, al.thread, | ||
1178 | sample->callchain, NULL) != 0) { | ||
1179 | if (verbose) | ||
1180 | error("Failed to resolve callchain. Skipping\n"); | ||
1181 | return; | ||
1182 | } | ||
1183 | callchain_cursor_commit(cursor); | ||
1184 | |||
1185 | while (1) { | ||
1186 | node = callchain_cursor_current(cursor); | ||
1187 | if (!node) | ||
1188 | break; | ||
1189 | |||
1190 | if (node->sym && node->sym->name) | ||
1191 | symname = node->sym->name; | ||
1192 | else | ||
1193 | symname = ""; | ||
1194 | |||
1195 | if (node->map && node->map->dso && node->map->dso->name) | ||
1196 | dsoname = node->map->dso->name; | ||
1197 | else | ||
1198 | dsoname = ""; | ||
1199 | |||
1200 | printf("\t%16" PRIx64 " %s (%s)\n", node->ip, symname, dsoname); | ||
1201 | |||
1202 | callchain_cursor_advance(cursor); | ||
1203 | } | ||
1204 | |||
1205 | } else { | ||
1206 | if (al.sym && al.sym->name) | ||
1207 | symname = al.sym->name; | ||
1208 | else | ||
1209 | symname = ""; | ||
1210 | |||
1211 | if (al.map && al.map->dso && al.map->dso->name) | ||
1212 | dsoname = al.map->dso->name; | ||
1213 | else | ||
1214 | dsoname = ""; | ||
1215 | |||
1216 | printf("%16" PRIx64 " %s (%s)", al.addr, symname, dsoname); | ||
1217 | } | ||
1218 | } | ||