diff options
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r-- | tools/perf/util/session.c | 103 |
1 files changed, 78 insertions, 25 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 52672dad1fe9..08ec018966a8 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -70,6 +70,11 @@ void perf_session__update_sample_type(struct perf_session *self) | |||
70 | self->sample_type = perf_header__sample_type(&self->header); | 70 | self->sample_type = perf_header__sample_type(&self->header); |
71 | } | 71 | } |
72 | 72 | ||
73 | void perf_session__set_sample_type(struct perf_session *session, u64 type) | ||
74 | { | ||
75 | session->sample_type = type; | ||
76 | } | ||
77 | |||
73 | int perf_session__create_kernel_maps(struct perf_session *self) | 78 | int perf_session__create_kernel_maps(struct perf_session *self) |
74 | { | 79 | { |
75 | int ret = machine__create_kernel_maps(&self->host_machine); | 80 | int ret = machine__create_kernel_maps(&self->host_machine); |
@@ -240,7 +245,15 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, | |||
240 | return syms; | 245 | return syms; |
241 | } | 246 | } |
242 | 247 | ||
248 | static int process_event_synth_stub(event_t *event __used, | ||
249 | struct perf_session *session __used) | ||
250 | { | ||
251 | dump_printf(": unhandled!\n"); | ||
252 | return 0; | ||
253 | } | ||
254 | |||
243 | static int process_event_stub(event_t *event __used, | 255 | static int process_event_stub(event_t *event __used, |
256 | struct sample_data *sample __used, | ||
244 | struct perf_session *session __used) | 257 | struct perf_session *session __used) |
245 | { | 258 | { |
246 | dump_printf(": unhandled!\n"); | 259 | dump_printf(": unhandled!\n"); |
@@ -280,13 +293,13 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) | |||
280 | if (handler->unthrottle == NULL) | 293 | if (handler->unthrottle == NULL) |
281 | handler->unthrottle = process_event_stub; | 294 | handler->unthrottle = process_event_stub; |
282 | if (handler->attr == NULL) | 295 | if (handler->attr == NULL) |
283 | handler->attr = process_event_stub; | 296 | handler->attr = process_event_synth_stub; |
284 | if (handler->event_type == NULL) | 297 | if (handler->event_type == NULL) |
285 | handler->event_type = process_event_stub; | 298 | handler->event_type = process_event_synth_stub; |
286 | if (handler->tracing_data == NULL) | 299 | if (handler->tracing_data == NULL) |
287 | handler->tracing_data = process_event_stub; | 300 | handler->tracing_data = process_event_synth_stub; |
288 | if (handler->build_id == NULL) | 301 | if (handler->build_id == NULL) |
289 | handler->build_id = process_event_stub; | 302 | handler->build_id = process_event_synth_stub; |
290 | if (handler->finished_round == NULL) { | 303 | if (handler->finished_round == NULL) { |
291 | if (handler->ordered_samples) | 304 | if (handler->ordered_samples) |
292 | handler->finished_round = process_finished_round; | 305 | handler->finished_round = process_finished_round; |
@@ -419,6 +432,7 @@ static void flush_sample_queue(struct perf_session *s, | |||
419 | struct ordered_samples *os = &s->ordered_samples; | 432 | struct ordered_samples *os = &s->ordered_samples; |
420 | struct list_head *head = &os->samples; | 433 | struct list_head *head = &os->samples; |
421 | struct sample_queue *tmp, *iter; | 434 | struct sample_queue *tmp, *iter; |
435 | struct sample_data sample; | ||
422 | u64 limit = os->next_flush; | 436 | u64 limit = os->next_flush; |
423 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; | 437 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; |
424 | 438 | ||
@@ -429,7 +443,8 @@ static void flush_sample_queue(struct perf_session *s, | |||
429 | if (iter->timestamp > limit) | 443 | if (iter->timestamp > limit) |
430 | break; | 444 | break; |
431 | 445 | ||
432 | ops->sample(iter->event, s); | 446 | event__parse_sample(iter->event, s->sample_type, &sample); |
447 | ops->sample(iter->event, &sample, s); | ||
433 | 448 | ||
434 | os->last_flush = iter->timestamp; | 449 | os->last_flush = iter->timestamp; |
435 | list_del(&iter->list); | 450 | list_del(&iter->list); |
@@ -578,20 +593,29 @@ static int queue_sample_event(event_t *event, struct sample_data *data, | |||
578 | return 0; | 593 | return 0; |
579 | } | 594 | } |
580 | 595 | ||
581 | static int perf_session__process_sample(event_t *event, struct perf_session *s, | 596 | static int perf_session__process_sample(event_t *event, |
597 | struct sample_data *sample, | ||
598 | struct perf_session *s, | ||
582 | struct perf_event_ops *ops) | 599 | struct perf_event_ops *ops) |
583 | { | 600 | { |
584 | struct sample_data data; | ||
585 | |||
586 | if (!ops->ordered_samples) | 601 | if (!ops->ordered_samples) |
587 | return ops->sample(event, s); | 602 | return ops->sample(event, sample, s); |
603 | |||
604 | queue_sample_event(event, sample, s); | ||
605 | return 0; | ||
606 | } | ||
588 | 607 | ||
589 | bzero(&data, sizeof(struct sample_data)); | 608 | static void callchain__dump(struct sample_data *sample) |
590 | event__parse_sample(event, s->sample_type, &data); | 609 | { |
610 | unsigned int i; | ||
591 | 611 | ||
592 | queue_sample_event(event, &data, s); | 612 | if (!dump_trace) |
613 | return; | ||
593 | 614 | ||
594 | return 0; | 615 | printf("... chain: nr:%Lu\n", sample->callchain->nr); |
616 | |||
617 | for (i = 0; i < sample->callchain->nr; i++) | ||
618 | printf("..... %2d: %016Lx\n", i, sample->callchain->ips[i]); | ||
595 | } | 619 | } |
596 | 620 | ||
597 | static int perf_session__process_event(struct perf_session *self, | 621 | static int perf_session__process_event(struct perf_session *self, |
@@ -599,8 +623,16 @@ static int perf_session__process_event(struct perf_session *self, | |||
599 | struct perf_event_ops *ops, | 623 | struct perf_event_ops *ops, |
600 | u64 file_offset) | 624 | u64 file_offset) |
601 | { | 625 | { |
626 | struct sample_data sample; | ||
627 | |||
602 | trace_event(event); | 628 | trace_event(event); |
603 | 629 | ||
630 | if (self->header.needs_swap && event__swap_ops[event->header.type]) | ||
631 | event__swap_ops[event->header.type](event); | ||
632 | |||
633 | if (event->header.type == PERF_RECORD_SAMPLE) | ||
634 | event__parse_sample(event, self->sample_type, &sample); | ||
635 | |||
604 | if (event->header.type < PERF_RECORD_HEADER_MAX) { | 636 | if (event->header.type < PERF_RECORD_HEADER_MAX) { |
605 | dump_printf("%#Lx [%#x]: PERF_RECORD_%s", | 637 | dump_printf("%#Lx [%#x]: PERF_RECORD_%s", |
606 | file_offset, event->header.size, | 638 | file_offset, event->header.size, |
@@ -608,28 +640,41 @@ static int perf_session__process_event(struct perf_session *self, | |||
608 | hists__inc_nr_events(&self->hists, event->header.type); | 640 | hists__inc_nr_events(&self->hists, event->header.type); |
609 | } | 641 | } |
610 | 642 | ||
611 | if (self->header.needs_swap && event__swap_ops[event->header.type]) | ||
612 | event__swap_ops[event->header.type](event); | ||
613 | |||
614 | switch (event->header.type) { | 643 | switch (event->header.type) { |
615 | case PERF_RECORD_SAMPLE: | 644 | case PERF_RECORD_SAMPLE: |
616 | return perf_session__process_sample(event, self, ops); | 645 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, |
646 | sample.pid, sample.tid, sample.ip, sample.period); | ||
647 | |||
648 | if (self->sample_type & PERF_SAMPLE_CALLCHAIN) { | ||
649 | if (!ip_callchain__valid(sample.callchain, event)) { | ||
650 | pr_debug("call-chain problem with event, " | ||
651 | "skipping it.\n"); | ||
652 | ++self->hists.stats.nr_invalid_chains; | ||
653 | self->hists.stats.total_invalid_chains += sample.period; | ||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | callchain__dump(&sample); | ||
658 | } | ||
659 | |||
660 | return perf_session__process_sample(event, &sample, self, ops); | ||
661 | |||
617 | case PERF_RECORD_MMAP: | 662 | case PERF_RECORD_MMAP: |
618 | return ops->mmap(event, self); | 663 | return ops->mmap(event, &sample, self); |
619 | case PERF_RECORD_COMM: | 664 | case PERF_RECORD_COMM: |
620 | return ops->comm(event, self); | 665 | return ops->comm(event, &sample, self); |
621 | case PERF_RECORD_FORK: | 666 | case PERF_RECORD_FORK: |
622 | return ops->fork(event, self); | 667 | return ops->fork(event, &sample, self); |
623 | case PERF_RECORD_EXIT: | 668 | case PERF_RECORD_EXIT: |
624 | return ops->exit(event, self); | 669 | return ops->exit(event, &sample, self); |
625 | case PERF_RECORD_LOST: | 670 | case PERF_RECORD_LOST: |
626 | return ops->lost(event, self); | 671 | return ops->lost(event, &sample, self); |
627 | case PERF_RECORD_READ: | 672 | case PERF_RECORD_READ: |
628 | return ops->read(event, self); | 673 | return ops->read(event, &sample, self); |
629 | case PERF_RECORD_THROTTLE: | 674 | case PERF_RECORD_THROTTLE: |
630 | return ops->throttle(event, self); | 675 | return ops->throttle(event, &sample, self); |
631 | case PERF_RECORD_UNTHROTTLE: | 676 | case PERF_RECORD_UNTHROTTLE: |
632 | return ops->unthrottle(event, self); | 677 | return ops->unthrottle(event, &sample, self); |
633 | case PERF_RECORD_HEADER_ATTR: | 678 | case PERF_RECORD_HEADER_ATTR: |
634 | return ops->attr(event, self); | 679 | return ops->attr(event, self); |
635 | case PERF_RECORD_HEADER_EVENT_TYPE: | 680 | case PERF_RECORD_HEADER_EVENT_TYPE: |
@@ -894,6 +939,14 @@ out_err: | |||
894 | session->hists.stats.nr_unknown_events); | 939 | session->hists.stats.nr_unknown_events); |
895 | } | 940 | } |
896 | 941 | ||
942 | if (session->hists.stats.nr_invalid_chains != 0) { | ||
943 | ui__warning("Found invalid callchains!\n\n" | ||
944 | "%u out of %u events were discarded for this reason.\n\n" | ||
945 | "Consider reporting to linux-kernel@vger.kernel.org.\n\n", | ||
946 | session->hists.stats.nr_invalid_chains, | ||
947 | session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); | ||
948 | } | ||
949 | |||
897 | perf_session_free_sample_buffers(session); | 950 | perf_session_free_sample_buffers(session); |
898 | return err; | 951 | return err; |
899 | } | 952 | } |