diff options
-rw-r--r-- | tools/perf/util/session.c | 125 |
1 files changed, 72 insertions, 53 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 5c756609104e..3074d38897e6 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -461,6 +461,11 @@ static void perf_session_free_sample_buffers(struct perf_session *session) | |||
461 | } | 461 | } |
462 | } | 462 | } |
463 | 463 | ||
464 | static int perf_session_deliver_event(struct perf_session *session, | ||
465 | event_t *event, | ||
466 | struct sample_data *sample, | ||
467 | struct perf_event_ops *ops); | ||
468 | |||
464 | static void flush_sample_queue(struct perf_session *s, | 469 | static void flush_sample_queue(struct perf_session *s, |
465 | struct perf_event_ops *ops) | 470 | struct perf_event_ops *ops) |
466 | { | 471 | { |
@@ -479,7 +484,7 @@ static void flush_sample_queue(struct perf_session *s, | |||
479 | break; | 484 | break; |
480 | 485 | ||
481 | event__parse_sample(iter->event, s, &sample); | 486 | event__parse_sample(iter->event, s, &sample); |
482 | ops->sample(iter->event, &sample, s); | 487 | perf_session_deliver_event(s, iter->event, &sample, ops); |
483 | 488 | ||
484 | os->last_flush = iter->timestamp; | 489 | os->last_flush = iter->timestamp; |
485 | list_del(&iter->list); | 490 | list_del(&iter->list); |
@@ -544,8 +549,7 @@ static int process_finished_round(event_t *event __used, | |||
544 | } | 549 | } |
545 | 550 | ||
546 | /* The queue is ordered by time */ | 551 | /* The queue is ordered by time */ |
547 | static void __queue_sample_event(struct sample_queue *new, | 552 | static void __queue_event(struct sample_queue *new, struct perf_session *s) |
548 | struct perf_session *s) | ||
549 | { | 553 | { |
550 | struct ordered_samples *os = &s->ordered_samples; | 554 | struct ordered_samples *os = &s->ordered_samples; |
551 | struct sample_queue *sample = os->last_sample; | 555 | struct sample_queue *sample = os->last_sample; |
@@ -591,14 +595,17 @@ static void __queue_sample_event(struct sample_queue *new, | |||
591 | 595 | ||
592 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) | 596 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) |
593 | 597 | ||
594 | static int queue_sample_event(event_t *event, struct sample_data *data, | 598 | static int perf_session_queue_event(struct perf_session *s, event_t *event, |
595 | struct perf_session *s) | 599 | struct sample_data *data) |
596 | { | 600 | { |
597 | struct ordered_samples *os = &s->ordered_samples; | 601 | struct ordered_samples *os = &s->ordered_samples; |
598 | struct list_head *sc = &os->sample_cache; | 602 | struct list_head *sc = &os->sample_cache; |
599 | u64 timestamp = data->time; | 603 | u64 timestamp = data->time; |
600 | struct sample_queue *new; | 604 | struct sample_queue *new; |
601 | 605 | ||
606 | if (!timestamp) | ||
607 | return -ETIME; | ||
608 | |||
602 | if (timestamp < s->ordered_samples.last_flush) { | 609 | if (timestamp < s->ordered_samples.last_flush) { |
603 | printf("Warning: Timestamp below last timeslice flush\n"); | 610 | printf("Warning: Timestamp below last timeslice flush\n"); |
604 | return -EINVAL; | 611 | return -EINVAL; |
@@ -623,20 +630,8 @@ static int queue_sample_event(event_t *event, struct sample_data *data, | |||
623 | new->timestamp = timestamp; | 630 | new->timestamp = timestamp; |
624 | new->event = event; | 631 | new->event = event; |
625 | 632 | ||
626 | __queue_sample_event(new, s); | 633 | __queue_event(new, s); |
627 | |||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static int perf_session__process_sample(event_t *event, | ||
632 | struct sample_data *sample, | ||
633 | struct perf_session *s, | ||
634 | struct perf_event_ops *ops) | ||
635 | { | ||
636 | if (!ops->ordered_samples) | ||
637 | return ops->sample(event, sample, s); | ||
638 | 634 | ||
639 | queue_sample_event(event, sample, s); | ||
640 | return 0; | 635 | return 0; |
641 | } | 636 | } |
642 | 637 | ||
@@ -670,83 +665,107 @@ static void perf_session__print_tstamp(struct perf_session *session, | |||
670 | printf("%Lu ", sample->time); | 665 | printf("%Lu ", sample->time); |
671 | } | 666 | } |
672 | 667 | ||
673 | static int perf_session__process_event(struct perf_session *self, | 668 | static int perf_session_deliver_event(struct perf_session *session, |
669 | event_t *event, | ||
670 | struct sample_data *sample, | ||
671 | struct perf_event_ops *ops) | ||
672 | { | ||
673 | switch (event->header.type) { | ||
674 | case PERF_RECORD_SAMPLE: | ||
675 | return ops->sample(event, sample, session); | ||
676 | case PERF_RECORD_MMAP: | ||
677 | return ops->mmap(event, sample, session); | ||
678 | case PERF_RECORD_COMM: | ||
679 | return ops->comm(event, sample, session); | ||
680 | case PERF_RECORD_FORK: | ||
681 | return ops->fork(event, sample, session); | ||
682 | case PERF_RECORD_EXIT: | ||
683 | return ops->exit(event, sample, session); | ||
684 | case PERF_RECORD_LOST: | ||
685 | return ops->lost(event, sample, session); | ||
686 | case PERF_RECORD_READ: | ||
687 | return ops->read(event, sample, session); | ||
688 | case PERF_RECORD_THROTTLE: | ||
689 | return ops->throttle(event, sample, session); | ||
690 | case PERF_RECORD_UNTHROTTLE: | ||
691 | return ops->unthrottle(event, sample, session); | ||
692 | default: | ||
693 | ++session->hists.stats.nr_unknown_events; | ||
694 | return -1; | ||
695 | } | ||
696 | } | ||
697 | |||
698 | static int perf_session__process_event(struct perf_session *session, | ||
674 | event_t *event, | 699 | event_t *event, |
675 | struct perf_event_ops *ops, | 700 | struct perf_event_ops *ops, |
676 | u64 file_offset) | 701 | u64 file_offset) |
677 | { | 702 | { |
678 | struct sample_data sample; | 703 | struct sample_data sample; |
704 | int ret; | ||
679 | 705 | ||
680 | trace_event(event); | 706 | trace_event(event); |
681 | 707 | ||
682 | if (self->header.needs_swap && event__swap_ops[event->header.type]) | 708 | if (session->header.needs_swap && event__swap_ops[event->header.type]) |
683 | event__swap_ops[event->header.type](event); | 709 | event__swap_ops[event->header.type](event); |
684 | 710 | ||
685 | if (event->header.type >= PERF_RECORD_MMAP && | 711 | if (event->header.type >= PERF_RECORD_MMAP && |
686 | event->header.type <= PERF_RECORD_SAMPLE) { | 712 | event->header.type <= PERF_RECORD_SAMPLE) { |
687 | event__parse_sample(event, self, &sample); | 713 | event__parse_sample(event, session, &sample); |
688 | if (dump_trace) | 714 | if (dump_trace) |
689 | perf_session__print_tstamp(self, event, &sample); | 715 | perf_session__print_tstamp(session, event, &sample); |
690 | } | 716 | } |
691 | 717 | ||
692 | if (event->header.type < PERF_RECORD_HEADER_MAX) { | 718 | if (event->header.type < PERF_RECORD_HEADER_MAX) { |
693 | dump_printf("%#Lx [%#x]: PERF_RECORD_%s", | 719 | dump_printf("%#Lx [%#x]: PERF_RECORD_%s", |
694 | file_offset, event->header.size, | 720 | file_offset, event->header.size, |
695 | event__name[event->header.type]); | 721 | event__name[event->header.type]); |
696 | hists__inc_nr_events(&self->hists, event->header.type); | 722 | hists__inc_nr_events(&session->hists, event->header.type); |
697 | } | 723 | } |
698 | 724 | ||
725 | /* These events are processed right away */ | ||
699 | switch (event->header.type) { | 726 | switch (event->header.type) { |
700 | case PERF_RECORD_SAMPLE: | 727 | case PERF_RECORD_SAMPLE: |
701 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, | 728 | dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", |
729 | event->header.misc, | ||
702 | sample.pid, sample.tid, sample.ip, sample.period); | 730 | sample.pid, sample.tid, sample.ip, sample.period); |
703 | 731 | ||
704 | if (self->sample_type & PERF_SAMPLE_CALLCHAIN) { | 732 | if (session->sample_type & PERF_SAMPLE_CALLCHAIN) { |
705 | if (!ip_callchain__valid(sample.callchain, event)) { | 733 | if (!ip_callchain__valid(sample.callchain, event)) { |
706 | pr_debug("call-chain problem with event, " | 734 | pr_debug("call-chain problem with event, " |
707 | "skipping it.\n"); | 735 | "skipping it.\n"); |
708 | ++self->hists.stats.nr_invalid_chains; | 736 | ++session->hists.stats.nr_invalid_chains; |
709 | self->hists.stats.total_invalid_chains += sample.period; | 737 | session->hists.stats.total_invalid_chains += |
738 | sample.period; | ||
710 | return 0; | 739 | return 0; |
711 | } | 740 | } |
712 | 741 | ||
713 | callchain__dump(&sample); | 742 | callchain__dump(&sample); |
714 | } | 743 | } |
744 | break; | ||
715 | 745 | ||
716 | return perf_session__process_sample(event, &sample, self, ops); | ||
717 | |||
718 | case PERF_RECORD_MMAP: | ||
719 | return ops->mmap(event, &sample, self); | ||
720 | case PERF_RECORD_COMM: | ||
721 | return ops->comm(event, &sample, self); | ||
722 | case PERF_RECORD_FORK: | ||
723 | return ops->fork(event, &sample, self); | ||
724 | case PERF_RECORD_EXIT: | ||
725 | return ops->exit(event, &sample, self); | ||
726 | case PERF_RECORD_LOST: | ||
727 | return ops->lost(event, &sample, self); | ||
728 | case PERF_RECORD_READ: | ||
729 | return ops->read(event, &sample, self); | ||
730 | case PERF_RECORD_THROTTLE: | ||
731 | return ops->throttle(event, &sample, self); | ||
732 | case PERF_RECORD_UNTHROTTLE: | ||
733 | return ops->unthrottle(event, &sample, self); | ||
734 | case PERF_RECORD_HEADER_ATTR: | 746 | case PERF_RECORD_HEADER_ATTR: |
735 | return ops->attr(event, self); | 747 | return ops->attr(event, session); |
736 | case PERF_RECORD_HEADER_EVENT_TYPE: | 748 | case PERF_RECORD_HEADER_EVENT_TYPE: |
737 | return ops->event_type(event, self); | 749 | return ops->event_type(event, session); |
738 | case PERF_RECORD_HEADER_TRACING_DATA: | 750 | case PERF_RECORD_HEADER_TRACING_DATA: |
739 | /* setup for reading amidst mmap */ | 751 | /* setup for reading amidst mmap */ |
740 | lseek(self->fd, file_offset, SEEK_SET); | 752 | lseek(session->fd, file_offset, SEEK_SET); |
741 | return ops->tracing_data(event, self); | 753 | return ops->tracing_data(event, session); |
742 | case PERF_RECORD_HEADER_BUILD_ID: | 754 | case PERF_RECORD_HEADER_BUILD_ID: |
743 | return ops->build_id(event, self); | 755 | return ops->build_id(event, session); |
744 | case PERF_RECORD_FINISHED_ROUND: | 756 | case PERF_RECORD_FINISHED_ROUND: |
745 | return ops->finished_round(event, self, ops); | 757 | return ops->finished_round(event, session, ops); |
746 | default: | 758 | default: |
747 | ++self->hists.stats.nr_unknown_events; | 759 | break; |
748 | return -1; | ||
749 | } | 760 | } |
761 | |||
762 | if (ops->ordered_samples) { | ||
763 | ret = perf_session_queue_event(session, event, &sample); | ||
764 | if (ret != -ETIME) | ||
765 | return ret; | ||
766 | } | ||
767 | |||
768 | return perf_session_deliver_event(session, event, &sample, ops); | ||
750 | } | 769 | } |
751 | 770 | ||
752 | void perf_event_header__bswap(struct perf_event_header *self) | 771 | void perf_event_header__bswap(struct perf_event_header *self) |