aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r--tools/perf/util/session.c226
1 files changed, 177 insertions, 49 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 52672dad1fe9..3074d38897e6 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -65,9 +65,49 @@ out_close:
65 return -1; 65 return -1;
66} 66}
67 67
68static void perf_session__id_header_size(struct perf_session *session)
69{
70 struct sample_data *data;
71 u64 sample_type = session->sample_type;
72 u16 size = 0;
73
74 if (!session->sample_id_all)
75 goto out;
76
77 if (sample_type & PERF_SAMPLE_TID)
78 size += sizeof(data->tid) * 2;
79
80 if (sample_type & PERF_SAMPLE_TIME)
81 size += sizeof(data->time);
82
83 if (sample_type & PERF_SAMPLE_ID)
84 size += sizeof(data->id);
85
86 if (sample_type & PERF_SAMPLE_STREAM_ID)
87 size += sizeof(data->stream_id);
88
89 if (sample_type & PERF_SAMPLE_CPU)
90 size += sizeof(data->cpu) * 2;
91out:
92 session->id_hdr_size = size;
93}
94
95void 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
101void perf_session__set_sample_type(struct perf_session *session, u64 type)
102{
103 session->sample_type = type;
104}
105
68void perf_session__update_sample_type(struct perf_session *self) 106void perf_session__update_sample_type(struct perf_session *self)
69{ 107{
70 self->sample_type = perf_header__sample_type(&self->header); 108 self->sample_type = perf_header__sample_type(&self->header);
109 self->sample_id_all = perf_header__sample_id_all(&self->header);
110 perf_session__id_header_size(self);
71} 111}
72 112
73int perf_session__create_kernel_maps(struct perf_session *self) 113int perf_session__create_kernel_maps(struct perf_session *self)
@@ -240,7 +280,15 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
240 return syms; 280 return syms;
241} 281}
242 282
283static int process_event_synth_stub(event_t *event __used,
284 struct perf_session *session __used)
285{
286 dump_printf(": unhandled!\n");
287 return 0;
288}
289
243static int process_event_stub(event_t *event __used, 290static int process_event_stub(event_t *event __used,
291 struct sample_data *sample __used,
244 struct perf_session *session __used) 292 struct perf_session *session __used)
245{ 293{
246 dump_printf(": unhandled!\n"); 294 dump_printf(": unhandled!\n");
@@ -280,13 +328,13 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
280 if (handler->unthrottle == NULL) 328 if (handler->unthrottle == NULL)
281 handler->unthrottle = process_event_stub; 329 handler->unthrottle = process_event_stub;
282 if (handler->attr == NULL) 330 if (handler->attr == NULL)
283 handler->attr = process_event_stub; 331 handler->attr = process_event_synth_stub;
284 if (handler->event_type == NULL) 332 if (handler->event_type == NULL)
285 handler->event_type = process_event_stub; 333 handler->event_type = process_event_synth_stub;
286 if (handler->tracing_data == NULL) 334 if (handler->tracing_data == NULL)
287 handler->tracing_data = process_event_stub; 335 handler->tracing_data = process_event_synth_stub;
288 if (handler->build_id == NULL) 336 if (handler->build_id == NULL)
289 handler->build_id = process_event_stub; 337 handler->build_id = process_event_synth_stub;
290 if (handler->finished_round == NULL) { 338 if (handler->finished_round == NULL) {
291 if (handler->ordered_samples) 339 if (handler->ordered_samples)
292 handler->finished_round = process_finished_round; 340 handler->finished_round = process_finished_round;
@@ -413,12 +461,18 @@ static void perf_session_free_sample_buffers(struct perf_session *session)
413 } 461 }
414} 462}
415 463
464static 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
416static void flush_sample_queue(struct perf_session *s, 469static void flush_sample_queue(struct perf_session *s,
417 struct perf_event_ops *ops) 470 struct perf_event_ops *ops)
418{ 471{
419 struct ordered_samples *os = &s->ordered_samples; 472 struct ordered_samples *os = &s->ordered_samples;
420 struct list_head *head = &os->samples; 473 struct list_head *head = &os->samples;
421 struct sample_queue *tmp, *iter; 474 struct sample_queue *tmp, *iter;
475 struct sample_data sample;
422 u64 limit = os->next_flush; 476 u64 limit = os->next_flush;
423 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; 477 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
424 478
@@ -429,7 +483,8 @@ static void flush_sample_queue(struct perf_session *s,
429 if (iter->timestamp > limit) 483 if (iter->timestamp > limit)
430 break; 484 break;
431 485
432 ops->sample(iter->event, s); 486 event__parse_sample(iter->event, s, &sample);
487 perf_session_deliver_event(s, iter->event, &sample, ops);
433 488
434 os->last_flush = iter->timestamp; 489 os->last_flush = iter->timestamp;
435 list_del(&iter->list); 490 list_del(&iter->list);
@@ -494,8 +549,7 @@ static int process_finished_round(event_t *event __used,
494} 549}
495 550
496/* The queue is ordered by time */ 551/* The queue is ordered by time */
497static void __queue_sample_event(struct sample_queue *new, 552static void __queue_event(struct sample_queue *new, struct perf_session *s)
498 struct perf_session *s)
499{ 553{
500 struct ordered_samples *os = &s->ordered_samples; 554 struct ordered_samples *os = &s->ordered_samples;
501 struct sample_queue *sample = os->last_sample; 555 struct sample_queue *sample = os->last_sample;
@@ -541,14 +595,17 @@ static void __queue_sample_event(struct sample_queue *new,
541 595
542#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) 596#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue))
543 597
544static int queue_sample_event(event_t *event, struct sample_data *data, 598static int perf_session_queue_event(struct perf_session *s, event_t *event,
545 struct perf_session *s) 599 struct sample_data *data)
546{ 600{
547 struct ordered_samples *os = &s->ordered_samples; 601 struct ordered_samples *os = &s->ordered_samples;
548 struct list_head *sc = &os->sample_cache; 602 struct list_head *sc = &os->sample_cache;
549 u64 timestamp = data->time; 603 u64 timestamp = data->time;
550 struct sample_queue *new; 604 struct sample_queue *new;
551 605
606 if (!timestamp)
607 return -ETIME;
608
552 if (timestamp < s->ordered_samples.last_flush) { 609 if (timestamp < s->ordered_samples.last_flush) {
553 printf("Warning: Timestamp below last timeslice flush\n"); 610 printf("Warning: Timestamp below last timeslice flush\n");
554 return -EINVAL; 611 return -EINVAL;
@@ -573,79 +630,142 @@ static int queue_sample_event(event_t *event, struct sample_data *data,
573 new->timestamp = timestamp; 630 new->timestamp = timestamp;
574 new->event = event; 631 new->event = event;
575 632
576 __queue_sample_event(new, s); 633 __queue_event(new, s);
577 634
578 return 0; 635 return 0;
579} 636}
580 637
581static int perf_session__process_sample(event_t *event, struct perf_session *s, 638static void callchain__dump(struct sample_data *sample)
582 struct perf_event_ops *ops)
583{ 639{
584 struct sample_data data; 640 unsigned int i;
585
586 if (!ops->ordered_samples)
587 return ops->sample(event, s);
588 641
589 bzero(&data, sizeof(struct sample_data)); 642 if (!dump_trace)
590 event__parse_sample(event, s->sample_type, &data); 643 return;
591 644
592 queue_sample_event(event, &data, s); 645 printf("... chain: nr:%Lu\n", sample->callchain->nr);
593 646
594 return 0; 647 for (i = 0; i < sample->callchain->nr; i++)
648 printf("..... %2d: %016Lx\n", i, sample->callchain->ips[i]);
595} 649}
596 650
597static int perf_session__process_event(struct perf_session *self, 651static void perf_session__print_tstamp(struct perf_session *session,
598 event_t *event, 652 event_t *event,
599 struct perf_event_ops *ops, 653 struct sample_data *sample)
600 u64 file_offset)
601{ 654{
602 trace_event(event); 655 if (event->header.type != PERF_RECORD_SAMPLE &&
603 656 !session->sample_id_all) {
604 if (event->header.type < PERF_RECORD_HEADER_MAX) { 657 fputs("-1 -1 ", stdout);
605 dump_printf("%#Lx [%#x]: PERF_RECORD_%s", 658 return;
606 file_offset, event->header.size,
607 event__name[event->header.type]);
608 hists__inc_nr_events(&self->hists, event->header.type);
609 } 659 }
610 660
611 if (self->header.needs_swap && event__swap_ops[event->header.type]) 661 if ((session->sample_type & PERF_SAMPLE_CPU))
612 event__swap_ops[event->header.type](event); 662 printf("%u ", sample->cpu);
613 663
664 if (session->sample_type & PERF_SAMPLE_TIME)
665 printf("%Lu ", sample->time);
666}
667
668static 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{
614 switch (event->header.type) { 673 switch (event->header.type) {
615 case PERF_RECORD_SAMPLE: 674 case PERF_RECORD_SAMPLE:
616 return perf_session__process_sample(event, self, ops); 675 return ops->sample(event, sample, session);
617 case PERF_RECORD_MMAP: 676 case PERF_RECORD_MMAP:
618 return ops->mmap(event, self); 677 return ops->mmap(event, sample, session);
619 case PERF_RECORD_COMM: 678 case PERF_RECORD_COMM:
620 return ops->comm(event, self); 679 return ops->comm(event, sample, session);
621 case PERF_RECORD_FORK: 680 case PERF_RECORD_FORK:
622 return ops->fork(event, self); 681 return ops->fork(event, sample, session);
623 case PERF_RECORD_EXIT: 682 case PERF_RECORD_EXIT:
624 return ops->exit(event, self); 683 return ops->exit(event, sample, session);
625 case PERF_RECORD_LOST: 684 case PERF_RECORD_LOST:
626 return ops->lost(event, self); 685 return ops->lost(event, sample, session);
627 case PERF_RECORD_READ: 686 case PERF_RECORD_READ:
628 return ops->read(event, self); 687 return ops->read(event, sample, session);
629 case PERF_RECORD_THROTTLE: 688 case PERF_RECORD_THROTTLE:
630 return ops->throttle(event, self); 689 return ops->throttle(event, sample, session);
631 case PERF_RECORD_UNTHROTTLE: 690 case PERF_RECORD_UNTHROTTLE:
632 return ops->unthrottle(event, self); 691 return ops->unthrottle(event, sample, session);
692 default:
693 ++session->hists.stats.nr_unknown_events;
694 return -1;
695 }
696}
697
698static int perf_session__process_event(struct perf_session *session,
699 event_t *event,
700 struct perf_event_ops *ops,
701 u64 file_offset)
702{
703 struct sample_data sample;
704 int ret;
705
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
711 if (event->header.type >= PERF_RECORD_MMAP &&
712 event->header.type <= PERF_RECORD_SAMPLE) {
713 event__parse_sample(event, session, &sample);
714 if (dump_trace)
715 perf_session__print_tstamp(session, event, &sample);
716 }
717
718 if (event->header.type < PERF_RECORD_HEADER_MAX) {
719 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
720 file_offset, event->header.size,
721 event__name[event->header.type]);
722 hists__inc_nr_events(&session->hists, event->header.type);
723 }
724
725 /* These events are processed right away */
726 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
633 case PERF_RECORD_HEADER_ATTR: 746 case PERF_RECORD_HEADER_ATTR:
634 return ops->attr(event, self); 747 return ops->attr(event, session);
635 case PERF_RECORD_HEADER_EVENT_TYPE: 748 case PERF_RECORD_HEADER_EVENT_TYPE:
636 return ops->event_type(event, self); 749 return ops->event_type(event, session);
637 case PERF_RECORD_HEADER_TRACING_DATA: 750 case PERF_RECORD_HEADER_TRACING_DATA:
638 /* setup for reading amidst mmap */ 751 /* setup for reading amidst mmap */
639 lseek(self->fd, file_offset, SEEK_SET); 752 lseek(session->fd, file_offset, SEEK_SET);
640 return ops->tracing_data(event, self); 753 return ops->tracing_data(event, session);
641 case PERF_RECORD_HEADER_BUILD_ID: 754 case PERF_RECORD_HEADER_BUILD_ID:
642 return ops->build_id(event, self); 755 return ops->build_id(event, session);
643 case PERF_RECORD_FINISHED_ROUND: 756 case PERF_RECORD_FINISHED_ROUND:
644 return ops->finished_round(event, self, ops); 757 return ops->finished_round(event, session, ops);
645 default: 758 default:
646 ++self->hists.stats.nr_unknown_events; 759 break;
647 return -1;
648 } 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);
649} 769}
650 770
651void perf_event_header__bswap(struct perf_event_header *self) 771void perf_event_header__bswap(struct perf_event_header *self)
@@ -894,6 +1014,14 @@ out_err:
894 session->hists.stats.nr_unknown_events); 1014 session->hists.stats.nr_unknown_events);
895 } 1015 }
896 1016
1017 if (session->hists.stats.nr_invalid_chains != 0) {
1018 ui__warning("Found invalid callchains!\n\n"
1019 "%u out of %u events were discarded for this reason.\n\n"
1020 "Consider reporting to linux-kernel@vger.kernel.org.\n\n",
1021 session->hists.stats.nr_invalid_chains,
1022 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]);
1023 }
1024
897 perf_session_free_sample_buffers(session); 1025 perf_session_free_sample_buffers(session);
898 return err; 1026 return err;
899} 1027}