diff options
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r-- | tools/perf/util/session.c | 154 |
1 files changed, 95 insertions, 59 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 3074d38897e6..b59abf5aba36 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -444,6 +444,7 @@ static event__swap_op event__swap_ops[] = { | |||
444 | 444 | ||
445 | struct sample_queue { | 445 | struct sample_queue { |
446 | u64 timestamp; | 446 | u64 timestamp; |
447 | u64 file_offset; | ||
447 | event_t *event; | 448 | event_t *event; |
448 | struct list_head list; | 449 | struct list_head list; |
449 | }; | 450 | }; |
@@ -464,7 +465,8 @@ static void perf_session_free_sample_buffers(struct perf_session *session) | |||
464 | static int perf_session_deliver_event(struct perf_session *session, | 465 | static int perf_session_deliver_event(struct perf_session *session, |
465 | event_t *event, | 466 | event_t *event, |
466 | struct sample_data *sample, | 467 | struct sample_data *sample, |
467 | struct perf_event_ops *ops); | 468 | struct perf_event_ops *ops, |
469 | u64 file_offset); | ||
468 | 470 | ||
469 | static void flush_sample_queue(struct perf_session *s, | 471 | static void flush_sample_queue(struct perf_session *s, |
470 | struct perf_event_ops *ops) | 472 | struct perf_event_ops *ops) |
@@ -484,7 +486,8 @@ static void flush_sample_queue(struct perf_session *s, | |||
484 | break; | 486 | break; |
485 | 487 | ||
486 | event__parse_sample(iter->event, s, &sample); | 488 | event__parse_sample(iter->event, s, &sample); |
487 | perf_session_deliver_event(s, iter->event, &sample, ops); | 489 | perf_session_deliver_event(s, iter->event, &sample, ops, |
490 | iter->file_offset); | ||
488 | 491 | ||
489 | os->last_flush = iter->timestamp; | 492 | os->last_flush = iter->timestamp; |
490 | list_del(&iter->list); | 493 | list_del(&iter->list); |
@@ -596,14 +599,14 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s) | |||
596 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) | 599 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) |
597 | 600 | ||
598 | static int perf_session_queue_event(struct perf_session *s, event_t *event, | 601 | static int perf_session_queue_event(struct perf_session *s, event_t *event, |
599 | struct sample_data *data) | 602 | struct sample_data *data, u64 file_offset) |
600 | { | 603 | { |
601 | struct ordered_samples *os = &s->ordered_samples; | 604 | struct ordered_samples *os = &s->ordered_samples; |
602 | struct list_head *sc = &os->sample_cache; | 605 | struct list_head *sc = &os->sample_cache; |
603 | u64 timestamp = data->time; | 606 | u64 timestamp = data->time; |
604 | struct sample_queue *new; | 607 | struct sample_queue *new; |
605 | 608 | ||
606 | if (!timestamp) | 609 | if (!timestamp || timestamp == ~0ULL) |
607 | return -ETIME; | 610 | return -ETIME; |
608 | 611 | ||
609 | if (timestamp < s->ordered_samples.last_flush) { | 612 | if (timestamp < s->ordered_samples.last_flush) { |
@@ -628,6 +631,7 @@ static int perf_session_queue_event(struct perf_session *s, event_t *event, | |||
628 | } | 631 | } |
629 | 632 | ||
630 | new->timestamp = timestamp; | 633 | new->timestamp = timestamp; |
634 | new->file_offset = file_offset; | ||
631 | new->event = event; | 635 | new->event = event; |
632 | 636 | ||
633 | __queue_event(new, s); | 637 | __queue_event(new, s); |
@@ -635,13 +639,10 @@ static int perf_session_queue_event(struct perf_session *s, event_t *event, | |||
635 | return 0; | 639 | return 0; |
636 | } | 640 | } |
637 | 641 | ||
638 | static void callchain__dump(struct sample_data *sample) | 642 | static void callchain__printf(struct sample_data *sample) |
639 | { | 643 | { |
640 | unsigned int i; | 644 | unsigned int i; |
641 | 645 | ||
642 | if (!dump_trace) | ||
643 | return; | ||
644 | |||
645 | printf("... chain: nr:%Lu\n", sample->callchain->nr); | 646 | printf("... chain: nr:%Lu\n", sample->callchain->nr); |
646 | 647 | ||
647 | for (i = 0; i < sample->callchain->nr; i++) | 648 | for (i = 0; i < sample->callchain->nr; i++) |
@@ -665,13 +666,48 @@ static void perf_session__print_tstamp(struct perf_session *session, | |||
665 | printf("%Lu ", sample->time); | 666 | printf("%Lu ", sample->time); |
666 | } | 667 | } |
667 | 668 | ||
669 | static void dump_event(struct perf_session *session, event_t *event, | ||
670 | u64 file_offset, struct sample_data *sample) | ||
671 | { | ||
672 | if (!dump_trace) | ||
673 | return; | ||
674 | |||
675 | printf("\n%#Lx [%#x]: event: %d\n", file_offset, event->header.size, | ||
676 | event->header.type); | ||
677 | |||
678 | trace_event(event); | ||
679 | |||
680 | if (sample) | ||
681 | perf_session__print_tstamp(session, event, sample); | ||
682 | |||
683 | printf("%#Lx [%#x]: PERF_RECORD_%s", file_offset, event->header.size, | ||
684 | event__get_event_name(event->header.type)); | ||
685 | } | ||
686 | |||
687 | static void dump_sample(struct perf_session *session, event_t *event, | ||
688 | struct sample_data *sample) | ||
689 | { | ||
690 | if (!dump_trace) | ||
691 | return; | ||
692 | |||
693 | printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, | ||
694 | sample->pid, sample->tid, sample->ip, sample->period); | ||
695 | |||
696 | if (session->sample_type & PERF_SAMPLE_CALLCHAIN) | ||
697 | callchain__printf(sample); | ||
698 | } | ||
699 | |||
668 | static int perf_session_deliver_event(struct perf_session *session, | 700 | static int perf_session_deliver_event(struct perf_session *session, |
669 | event_t *event, | 701 | event_t *event, |
670 | struct sample_data *sample, | 702 | struct sample_data *sample, |
671 | struct perf_event_ops *ops) | 703 | struct perf_event_ops *ops, |
704 | u64 file_offset) | ||
672 | { | 705 | { |
706 | dump_event(session, event, file_offset, sample); | ||
707 | |||
673 | switch (event->header.type) { | 708 | switch (event->header.type) { |
674 | case PERF_RECORD_SAMPLE: | 709 | case PERF_RECORD_SAMPLE: |
710 | dump_sample(session, event, sample); | ||
675 | return ops->sample(event, sample, session); | 711 | return ops->sample(event, sample, session); |
676 | case PERF_RECORD_MMAP: | 712 | case PERF_RECORD_MMAP: |
677 | return ops->mmap(event, sample, session); | 713 | return ops->mmap(event, sample, session); |
@@ -695,54 +731,29 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
695 | } | 731 | } |
696 | } | 732 | } |
697 | 733 | ||
698 | static int perf_session__process_event(struct perf_session *session, | 734 | static int perf_session__preprocess_sample(struct perf_session *session, |
699 | event_t *event, | 735 | event_t *event, struct sample_data *sample) |
700 | struct perf_event_ops *ops, | ||
701 | u64 file_offset) | ||
702 | { | 736 | { |
703 | struct sample_data sample; | 737 | if (event->header.type != PERF_RECORD_SAMPLE || |
704 | int ret; | 738 | !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) |
705 | 739 | return 0; | |
706 | trace_event(event); | ||
707 | |||
708 | if (session->header.needs_swap && event__swap_ops[event->header.type]) | ||
709 | event__swap_ops[event->header.type](event); | ||
710 | 740 | ||
711 | if (event->header.type >= PERF_RECORD_MMAP && | 741 | if (!ip_callchain__valid(sample->callchain, event)) { |
712 | event->header.type <= PERF_RECORD_SAMPLE) { | 742 | pr_debug("call-chain problem with event, skipping it.\n"); |
713 | event__parse_sample(event, session, &sample); | 743 | ++session->hists.stats.nr_invalid_chains; |
714 | if (dump_trace) | 744 | session->hists.stats.total_invalid_chains += sample->period; |
715 | perf_session__print_tstamp(session, event, &sample); | 745 | return -EINVAL; |
716 | } | 746 | } |
747 | return 0; | ||
748 | } | ||
717 | 749 | ||
718 | if (event->header.type < PERF_RECORD_HEADER_MAX) { | 750 | static int perf_session__process_user_event(struct perf_session *session, event_t *event, |
719 | dump_printf("%#Lx [%#x]: PERF_RECORD_%s", | 751 | struct perf_event_ops *ops, u64 file_offset) |
720 | file_offset, event->header.size, | 752 | { |
721 | event__name[event->header.type]); | 753 | dump_event(session, event, file_offset, NULL); |
722 | hists__inc_nr_events(&session->hists, event->header.type); | ||
723 | } | ||
724 | 754 | ||
725 | /* These events are processed right away */ | 755 | /* These events are processed right away */ |
726 | switch (event->header.type) { | 756 | switch (event->header.type) { |
727 | case PERF_RECORD_SAMPLE: | ||
728 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", | ||
729 | event->header.misc, | ||
730 | sample.pid, sample.tid, sample.ip, sample.period); | ||
731 | |||
732 | if (session->sample_type & PERF_SAMPLE_CALLCHAIN) { | ||
733 | if (!ip_callchain__valid(sample.callchain, event)) { | ||
734 | pr_debug("call-chain problem with event, " | ||
735 | "skipping it.\n"); | ||
736 | ++session->hists.stats.nr_invalid_chains; | ||
737 | session->hists.stats.total_invalid_chains += | ||
738 | sample.period; | ||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | callchain__dump(&sample); | ||
743 | } | ||
744 | break; | ||
745 | |||
746 | case PERF_RECORD_HEADER_ATTR: | 757 | case PERF_RECORD_HEADER_ATTR: |
747 | return ops->attr(event, session); | 758 | return ops->attr(event, session); |
748 | case PERF_RECORD_HEADER_EVENT_TYPE: | 759 | case PERF_RECORD_HEADER_EVENT_TYPE: |
@@ -756,16 +767,47 @@ static int perf_session__process_event(struct perf_session *session, | |||
756 | case PERF_RECORD_FINISHED_ROUND: | 767 | case PERF_RECORD_FINISHED_ROUND: |
757 | return ops->finished_round(event, session, ops); | 768 | return ops->finished_round(event, session, ops); |
758 | default: | 769 | default: |
759 | break; | 770 | return -EINVAL; |
760 | } | 771 | } |
772 | } | ||
773 | |||
774 | static int perf_session__process_event(struct perf_session *session, | ||
775 | event_t *event, | ||
776 | struct perf_event_ops *ops, | ||
777 | u64 file_offset) | ||
778 | { | ||
779 | struct sample_data sample; | ||
780 | int ret; | ||
781 | |||
782 | if (session->header.needs_swap && event__swap_ops[event->header.type]) | ||
783 | event__swap_ops[event->header.type](event); | ||
784 | |||
785 | if (event->header.type >= PERF_RECORD_HEADER_MAX) | ||
786 | return -EINVAL; | ||
787 | |||
788 | hists__inc_nr_events(&session->hists, event->header.type); | ||
789 | |||
790 | if (event->header.type >= PERF_RECORD_USER_TYPE_START) | ||
791 | return perf_session__process_user_event(session, event, ops, file_offset); | ||
792 | |||
793 | /* | ||
794 | * For all kernel events we get the sample data | ||
795 | */ | ||
796 | event__parse_sample(event, session, &sample); | ||
797 | |||
798 | /* Preprocess sample records - precheck callchains */ | ||
799 | if (perf_session__preprocess_sample(session, event, &sample)) | ||
800 | return 0; | ||
761 | 801 | ||
762 | if (ops->ordered_samples) { | 802 | if (ops->ordered_samples) { |
763 | ret = perf_session_queue_event(session, event, &sample); | 803 | ret = perf_session_queue_event(session, event, &sample, |
804 | file_offset); | ||
764 | if (ret != -ETIME) | 805 | if (ret != -ETIME) |
765 | return ret; | 806 | return ret; |
766 | } | 807 | } |
767 | 808 | ||
768 | return perf_session_deliver_event(session, event, &sample, ops); | 809 | return perf_session_deliver_event(session, event, &sample, ops, |
810 | file_offset); | ||
769 | } | 811 | } |
770 | 812 | ||
771 | void perf_event_header__bswap(struct perf_event_header *self) | 813 | void perf_event_header__bswap(struct perf_event_header *self) |
@@ -870,9 +912,6 @@ more: | |||
870 | 912 | ||
871 | head += size; | 913 | head += size; |
872 | 914 | ||
873 | dump_printf("\n%#Lx [%#x]: event: %d\n", | ||
874 | head, event.header.size, event.header.type); | ||
875 | |||
876 | if (skip > 0) | 915 | if (skip > 0) |
877 | head += skip; | 916 | head += skip; |
878 | 917 | ||
@@ -961,9 +1000,6 @@ more: | |||
961 | 1000 | ||
962 | size = event->header.size; | 1001 | size = event->header.size; |
963 | 1002 | ||
964 | dump_printf("\n%#Lx [%#x]: event: %d\n", | ||
965 | file_pos, event->header.size, event->header.type); | ||
966 | |||
967 | if (size == 0 || | 1003 | if (size == 0 || |
968 | perf_session__process_event(session, event, ops, file_pos) < 0) { | 1004 | perf_session__process_event(session, event, ops, file_pos) < 0) { |
969 | dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", | 1005 | dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", |