diff options
Diffstat (limited to 'tools')
| -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) |
