diff options
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r-- | tools/perf/util/session.c | 318 |
1 files changed, 215 insertions, 103 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index cf1fe01b7e89..70ffa41518f3 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
2 | #include <traceevent/event-parse.h> | ||
2 | 3 | ||
3 | #include <byteswap.h> | 4 | #include <byteswap.h> |
4 | #include <unistd.h> | 5 | #include <unistd.h> |
@@ -12,7 +13,6 @@ | |||
12 | #include "sort.h" | 13 | #include "sort.h" |
13 | #include "util.h" | 14 | #include "util.h" |
14 | #include "cpumap.h" | 15 | #include "cpumap.h" |
15 | #include "event-parse.h" | ||
16 | #include "perf_regs.h" | 16 | #include "perf_regs.h" |
17 | #include "vdso.h" | 17 | #include "vdso.h" |
18 | 18 | ||
@@ -24,7 +24,7 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
24 | self->fd_pipe = true; | 24 | self->fd_pipe = true; |
25 | self->fd = STDIN_FILENO; | 25 | self->fd = STDIN_FILENO; |
26 | 26 | ||
27 | if (perf_session__read_header(self, self->fd) < 0) | 27 | if (perf_session__read_header(self) < 0) |
28 | pr_err("incompatible file format (rerun with -v to learn more)"); | 28 | pr_err("incompatible file format (rerun with -v to learn more)"); |
29 | 29 | ||
30 | return 0; | 30 | return 0; |
@@ -56,7 +56,7 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
56 | goto out_close; | 56 | goto out_close; |
57 | } | 57 | } |
58 | 58 | ||
59 | if (perf_session__read_header(self, self->fd) < 0) { | 59 | if (perf_session__read_header(self) < 0) { |
60 | pr_err("incompatible file format (rerun with -v to learn more)"); | 60 | pr_err("incompatible file format (rerun with -v to learn more)"); |
61 | goto out_close; | 61 | goto out_close; |
62 | } | 62 | } |
@@ -71,6 +71,11 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
71 | goto out_close; | 71 | goto out_close; |
72 | } | 72 | } |
73 | 73 | ||
74 | if (!perf_evlist__valid_read_format(self->evlist)) { | ||
75 | pr_err("non matching read_format"); | ||
76 | goto out_close; | ||
77 | } | ||
78 | |||
74 | self->size = input_stat.st_size; | 79 | self->size = input_stat.st_size; |
75 | return 0; | 80 | return 0; |
76 | 81 | ||
@@ -193,7 +198,9 @@ void perf_session__delete(struct perf_session *self) | |||
193 | vdso__exit(); | 198 | vdso__exit(); |
194 | } | 199 | } |
195 | 200 | ||
196 | static int process_event_synth_tracing_data_stub(union perf_event *event | 201 | static int process_event_synth_tracing_data_stub(struct perf_tool *tool |
202 | __maybe_unused, | ||
203 | union perf_event *event | ||
197 | __maybe_unused, | 204 | __maybe_unused, |
198 | struct perf_session *session | 205 | struct perf_session *session |
199 | __maybe_unused) | 206 | __maybe_unused) |
@@ -202,7 +209,8 @@ static int process_event_synth_tracing_data_stub(union perf_event *event | |||
202 | return 0; | 209 | return 0; |
203 | } | 210 | } |
204 | 211 | ||
205 | static int process_event_synth_attr_stub(union perf_event *event __maybe_unused, | 212 | static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused, |
213 | union perf_event *event __maybe_unused, | ||
206 | struct perf_evlist **pevlist | 214 | struct perf_evlist **pevlist |
207 | __maybe_unused) | 215 | __maybe_unused) |
208 | { | 216 | { |
@@ -238,18 +246,11 @@ static int process_finished_round_stub(struct perf_tool *tool __maybe_unused, | |||
238 | return 0; | 246 | return 0; |
239 | } | 247 | } |
240 | 248 | ||
241 | static int process_event_type_stub(struct perf_tool *tool __maybe_unused, | ||
242 | union perf_event *event __maybe_unused) | ||
243 | { | ||
244 | dump_printf(": unhandled!\n"); | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int process_finished_round(struct perf_tool *tool, | 249 | static int process_finished_round(struct perf_tool *tool, |
249 | union perf_event *event, | 250 | union perf_event *event, |
250 | struct perf_session *session); | 251 | struct perf_session *session); |
251 | 252 | ||
252 | static void perf_tool__fill_defaults(struct perf_tool *tool) | 253 | void perf_tool__fill_defaults(struct perf_tool *tool) |
253 | { | 254 | { |
254 | if (tool->sample == NULL) | 255 | if (tool->sample == NULL) |
255 | tool->sample = process_event_sample_stub; | 256 | tool->sample = process_event_sample_stub; |
@@ -271,8 +272,6 @@ static void perf_tool__fill_defaults(struct perf_tool *tool) | |||
271 | tool->unthrottle = process_event_stub; | 272 | tool->unthrottle = process_event_stub; |
272 | if (tool->attr == NULL) | 273 | if (tool->attr == NULL) |
273 | tool->attr = process_event_synth_attr_stub; | 274 | tool->attr = process_event_synth_attr_stub; |
274 | if (tool->event_type == NULL) | ||
275 | tool->event_type = process_event_type_stub; | ||
276 | if (tool->tracing_data == NULL) | 275 | if (tool->tracing_data == NULL) |
277 | tool->tracing_data = process_event_synth_tracing_data_stub; | 276 | tool->tracing_data = process_event_synth_tracing_data_stub; |
278 | if (tool->build_id == NULL) | 277 | if (tool->build_id == NULL) |
@@ -352,6 +351,25 @@ static void perf_event__mmap_swap(union perf_event *event, | |||
352 | } | 351 | } |
353 | } | 352 | } |
354 | 353 | ||
354 | static void perf_event__mmap2_swap(union perf_event *event, | ||
355 | bool sample_id_all) | ||
356 | { | ||
357 | event->mmap2.pid = bswap_32(event->mmap2.pid); | ||
358 | event->mmap2.tid = bswap_32(event->mmap2.tid); | ||
359 | event->mmap2.start = bswap_64(event->mmap2.start); | ||
360 | event->mmap2.len = bswap_64(event->mmap2.len); | ||
361 | event->mmap2.pgoff = bswap_64(event->mmap2.pgoff); | ||
362 | event->mmap2.maj = bswap_32(event->mmap2.maj); | ||
363 | event->mmap2.min = bswap_32(event->mmap2.min); | ||
364 | event->mmap2.ino = bswap_64(event->mmap2.ino); | ||
365 | |||
366 | if (sample_id_all) { | ||
367 | void *data = &event->mmap2.filename; | ||
368 | |||
369 | data += PERF_ALIGN(strlen(data) + 1, sizeof(u64)); | ||
370 | swap_sample_id_all(event, data); | ||
371 | } | ||
372 | } | ||
355 | static void perf_event__task_swap(union perf_event *event, bool sample_id_all) | 373 | static void perf_event__task_swap(union perf_event *event, bool sample_id_all) |
356 | { | 374 | { |
357 | event->fork.pid = bswap_32(event->fork.pid); | 375 | event->fork.pid = bswap_32(event->fork.pid); |
@@ -456,6 +474,7 @@ typedef void (*perf_event__swap_op)(union perf_event *event, | |||
456 | 474 | ||
457 | static perf_event__swap_op perf_event__swap_ops[] = { | 475 | static perf_event__swap_op perf_event__swap_ops[] = { |
458 | [PERF_RECORD_MMAP] = perf_event__mmap_swap, | 476 | [PERF_RECORD_MMAP] = perf_event__mmap_swap, |
477 | [PERF_RECORD_MMAP2] = perf_event__mmap2_swap, | ||
459 | [PERF_RECORD_COMM] = perf_event__comm_swap, | 478 | [PERF_RECORD_COMM] = perf_event__comm_swap, |
460 | [PERF_RECORD_FORK] = perf_event__task_swap, | 479 | [PERF_RECORD_FORK] = perf_event__task_swap, |
461 | [PERF_RECORD_EXIT] = perf_event__task_swap, | 480 | [PERF_RECORD_EXIT] = perf_event__task_swap, |
@@ -496,7 +515,7 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
496 | u64 file_offset); | 515 | u64 file_offset); |
497 | 516 | ||
498 | static int flush_sample_queue(struct perf_session *s, | 517 | static int flush_sample_queue(struct perf_session *s, |
499 | struct perf_tool *tool) | 518 | struct perf_tool *tool) |
500 | { | 519 | { |
501 | struct ordered_samples *os = &s->ordered_samples; | 520 | struct ordered_samples *os = &s->ordered_samples; |
502 | struct list_head *head = &os->samples; | 521 | struct list_head *head = &os->samples; |
@@ -505,12 +524,16 @@ static int flush_sample_queue(struct perf_session *s, | |||
505 | u64 limit = os->next_flush; | 524 | u64 limit = os->next_flush; |
506 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; | 525 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; |
507 | unsigned idx = 0, progress_next = os->nr_samples / 16; | 526 | unsigned idx = 0, progress_next = os->nr_samples / 16; |
527 | bool show_progress = limit == ULLONG_MAX; | ||
508 | int ret; | 528 | int ret; |
509 | 529 | ||
510 | if (!tool->ordered_samples || !limit) | 530 | if (!tool->ordered_samples || !limit) |
511 | return 0; | 531 | return 0; |
512 | 532 | ||
513 | list_for_each_entry_safe(iter, tmp, head, list) { | 533 | list_for_each_entry_safe(iter, tmp, head, list) { |
534 | if (session_done()) | ||
535 | return 0; | ||
536 | |||
514 | if (iter->timestamp > limit) | 537 | if (iter->timestamp > limit) |
515 | break; | 538 | break; |
516 | 539 | ||
@@ -527,7 +550,7 @@ static int flush_sample_queue(struct perf_session *s, | |||
527 | os->last_flush = iter->timestamp; | 550 | os->last_flush = iter->timestamp; |
528 | list_del(&iter->list); | 551 | list_del(&iter->list); |
529 | list_add(&iter->list, &os->sample_cache); | 552 | list_add(&iter->list, &os->sample_cache); |
530 | if (++idx >= progress_next) { | 553 | if (show_progress && (++idx >= progress_next)) { |
531 | progress_next += os->nr_samples / 16; | 554 | progress_next += os->nr_samples / 16; |
532 | ui_progress__update(idx, os->nr_samples, | 555 | ui_progress__update(idx, os->nr_samples, |
533 | "Processing time ordered events..."); | 556 | "Processing time ordered events..."); |
@@ -644,7 +667,7 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s) | |||
644 | 667 | ||
645 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) | 668 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) |
646 | 669 | ||
647 | static int perf_session_queue_event(struct perf_session *s, union perf_event *event, | 670 | int perf_session_queue_event(struct perf_session *s, union perf_event *event, |
648 | struct perf_sample *sample, u64 file_offset) | 671 | struct perf_sample *sample, u64 file_offset) |
649 | { | 672 | { |
650 | struct ordered_samples *os = &s->ordered_samples; | 673 | struct ordered_samples *os = &s->ordered_samples; |
@@ -740,7 +763,7 @@ static void perf_session__print_tstamp(struct perf_session *session, | |||
740 | union perf_event *event, | 763 | union perf_event *event, |
741 | struct perf_sample *sample) | 764 | struct perf_sample *sample) |
742 | { | 765 | { |
743 | u64 sample_type = perf_evlist__sample_type(session->evlist); | 766 | u64 sample_type = __perf_evlist__combined_sample_type(session->evlist); |
744 | 767 | ||
745 | if (event->header.type != PERF_RECORD_SAMPLE && | 768 | if (event->header.type != PERF_RECORD_SAMPLE && |
746 | !perf_evlist__sample_id_all(session->evlist)) { | 769 | !perf_evlist__sample_id_all(session->evlist)) { |
@@ -755,6 +778,36 @@ static void perf_session__print_tstamp(struct perf_session *session, | |||
755 | printf("%" PRIu64 " ", sample->time); | 778 | printf("%" PRIu64 " ", sample->time); |
756 | } | 779 | } |
757 | 780 | ||
781 | static void sample_read__printf(struct perf_sample *sample, u64 read_format) | ||
782 | { | ||
783 | printf("... sample_read:\n"); | ||
784 | |||
785 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) | ||
786 | printf("...... time enabled %016" PRIx64 "\n", | ||
787 | sample->read.time_enabled); | ||
788 | |||
789 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) | ||
790 | printf("...... time running %016" PRIx64 "\n", | ||
791 | sample->read.time_running); | ||
792 | |||
793 | if (read_format & PERF_FORMAT_GROUP) { | ||
794 | u64 i; | ||
795 | |||
796 | printf(".... group nr %" PRIu64 "\n", sample->read.group.nr); | ||
797 | |||
798 | for (i = 0; i < sample->read.group.nr; i++) { | ||
799 | struct sample_read_value *value; | ||
800 | |||
801 | value = &sample->read.group.values[i]; | ||
802 | printf("..... id %016" PRIx64 | ||
803 | ", value %016" PRIx64 "\n", | ||
804 | value->id, value->value); | ||
805 | } | ||
806 | } else | ||
807 | printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n", | ||
808 | sample->read.one.id, sample->read.one.value); | ||
809 | } | ||
810 | |||
758 | static void dump_event(struct perf_session *session, union perf_event *event, | 811 | static void dump_event(struct perf_session *session, union perf_event *event, |
759 | u64 file_offset, struct perf_sample *sample) | 812 | u64 file_offset, struct perf_sample *sample) |
760 | { | 813 | { |
@@ -804,11 +857,15 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, | |||
804 | 857 | ||
805 | if (sample_type & PERF_SAMPLE_DATA_SRC) | 858 | if (sample_type & PERF_SAMPLE_DATA_SRC) |
806 | printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); | 859 | printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); |
860 | |||
861 | if (sample_type & PERF_SAMPLE_READ) | ||
862 | sample_read__printf(sample, evsel->attr.read_format); | ||
807 | } | 863 | } |
808 | 864 | ||
809 | static struct machine * | 865 | static struct machine * |
810 | perf_session__find_machine_for_cpumode(struct perf_session *session, | 866 | perf_session__find_machine_for_cpumode(struct perf_session *session, |
811 | union perf_event *event) | 867 | union perf_event *event, |
868 | struct perf_sample *sample) | ||
812 | { | 869 | { |
813 | const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 870 | const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
814 | 871 | ||
@@ -817,10 +874,11 @@ static struct machine * | |||
817 | (cpumode == PERF_RECORD_MISC_GUEST_USER))) { | 874 | (cpumode == PERF_RECORD_MISC_GUEST_USER))) { |
818 | u32 pid; | 875 | u32 pid; |
819 | 876 | ||
820 | if (event->header.type == PERF_RECORD_MMAP) | 877 | if (event->header.type == PERF_RECORD_MMAP |
878 | || event->header.type == PERF_RECORD_MMAP2) | ||
821 | pid = event->mmap.pid; | 879 | pid = event->mmap.pid; |
822 | else | 880 | else |
823 | pid = event->ip.pid; | 881 | pid = sample->pid; |
824 | 882 | ||
825 | return perf_session__findnew_machine(session, pid); | 883 | return perf_session__findnew_machine(session, pid); |
826 | } | 884 | } |
@@ -828,6 +886,75 @@ static struct machine * | |||
828 | return &session->machines.host; | 886 | return &session->machines.host; |
829 | } | 887 | } |
830 | 888 | ||
889 | static int deliver_sample_value(struct perf_session *session, | ||
890 | struct perf_tool *tool, | ||
891 | union perf_event *event, | ||
892 | struct perf_sample *sample, | ||
893 | struct sample_read_value *v, | ||
894 | struct machine *machine) | ||
895 | { | ||
896 | struct perf_sample_id *sid; | ||
897 | |||
898 | sid = perf_evlist__id2sid(session->evlist, v->id); | ||
899 | if (sid) { | ||
900 | sample->id = v->id; | ||
901 | sample->period = v->value - sid->period; | ||
902 | sid->period = v->value; | ||
903 | } | ||
904 | |||
905 | if (!sid || sid->evsel == NULL) { | ||
906 | ++session->stats.nr_unknown_id; | ||
907 | return 0; | ||
908 | } | ||
909 | |||
910 | return tool->sample(tool, event, sample, sid->evsel, machine); | ||
911 | } | ||
912 | |||
913 | static int deliver_sample_group(struct perf_session *session, | ||
914 | struct perf_tool *tool, | ||
915 | union perf_event *event, | ||
916 | struct perf_sample *sample, | ||
917 | struct machine *machine) | ||
918 | { | ||
919 | int ret = -EINVAL; | ||
920 | u64 i; | ||
921 | |||
922 | for (i = 0; i < sample->read.group.nr; i++) { | ||
923 | ret = deliver_sample_value(session, tool, event, sample, | ||
924 | &sample->read.group.values[i], | ||
925 | machine); | ||
926 | if (ret) | ||
927 | break; | ||
928 | } | ||
929 | |||
930 | return ret; | ||
931 | } | ||
932 | |||
933 | static int | ||
934 | perf_session__deliver_sample(struct perf_session *session, | ||
935 | struct perf_tool *tool, | ||
936 | union perf_event *event, | ||
937 | struct perf_sample *sample, | ||
938 | struct perf_evsel *evsel, | ||
939 | struct machine *machine) | ||
940 | { | ||
941 | /* We know evsel != NULL. */ | ||
942 | u64 sample_type = evsel->attr.sample_type; | ||
943 | u64 read_format = evsel->attr.read_format; | ||
944 | |||
945 | /* Standard sample delievery. */ | ||
946 | if (!(sample_type & PERF_SAMPLE_READ)) | ||
947 | return tool->sample(tool, event, sample, evsel, machine); | ||
948 | |||
949 | /* For PERF_SAMPLE_READ we have either single or group mode. */ | ||
950 | if (read_format & PERF_FORMAT_GROUP) | ||
951 | return deliver_sample_group(session, tool, event, sample, | ||
952 | machine); | ||
953 | else | ||
954 | return deliver_sample_value(session, tool, event, sample, | ||
955 | &sample->read.one, machine); | ||
956 | } | ||
957 | |||
831 | static int perf_session_deliver_event(struct perf_session *session, | 958 | static int perf_session_deliver_event(struct perf_session *session, |
832 | union perf_event *event, | 959 | union perf_event *event, |
833 | struct perf_sample *sample, | 960 | struct perf_sample *sample, |
@@ -857,7 +984,8 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
857 | hists__inc_nr_events(&evsel->hists, event->header.type); | 984 | hists__inc_nr_events(&evsel->hists, event->header.type); |
858 | } | 985 | } |
859 | 986 | ||
860 | machine = perf_session__find_machine_for_cpumode(session, event); | 987 | machine = perf_session__find_machine_for_cpumode(session, event, |
988 | sample); | ||
861 | 989 | ||
862 | switch (event->header.type) { | 990 | switch (event->header.type) { |
863 | case PERF_RECORD_SAMPLE: | 991 | case PERF_RECORD_SAMPLE: |
@@ -870,9 +998,12 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
870 | ++session->stats.nr_unprocessable_samples; | 998 | ++session->stats.nr_unprocessable_samples; |
871 | return 0; | 999 | return 0; |
872 | } | 1000 | } |
873 | return tool->sample(tool, event, sample, evsel, machine); | 1001 | return perf_session__deliver_sample(session, tool, event, |
1002 | sample, evsel, machine); | ||
874 | case PERF_RECORD_MMAP: | 1003 | case PERF_RECORD_MMAP: |
875 | return tool->mmap(tool, event, sample, machine); | 1004 | return tool->mmap(tool, event, sample, machine); |
1005 | case PERF_RECORD_MMAP2: | ||
1006 | return tool->mmap2(tool, event, sample, machine); | ||
876 | case PERF_RECORD_COMM: | 1007 | case PERF_RECORD_COMM: |
877 | return tool->comm(tool, event, sample, machine); | 1008 | return tool->comm(tool, event, sample, machine); |
878 | case PERF_RECORD_FORK: | 1009 | case PERF_RECORD_FORK: |
@@ -895,22 +1026,6 @@ static int perf_session_deliver_event(struct perf_session *session, | |||
895 | } | 1026 | } |
896 | } | 1027 | } |
897 | 1028 | ||
898 | static int perf_session__preprocess_sample(struct perf_session *session, | ||
899 | union perf_event *event, struct perf_sample *sample) | ||
900 | { | ||
901 | if (event->header.type != PERF_RECORD_SAMPLE || | ||
902 | !(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_CALLCHAIN)) | ||
903 | return 0; | ||
904 | |||
905 | if (!ip_callchain__valid(sample->callchain, event)) { | ||
906 | pr_debug("call-chain problem with event, skipping it.\n"); | ||
907 | ++session->stats.nr_invalid_chains; | ||
908 | session->stats.total_invalid_chains += sample->period; | ||
909 | return -EINVAL; | ||
910 | } | ||
911 | return 0; | ||
912 | } | ||
913 | |||
914 | static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, | 1029 | static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, |
915 | struct perf_tool *tool, u64 file_offset) | 1030 | struct perf_tool *tool, u64 file_offset) |
916 | { | 1031 | { |
@@ -921,16 +1036,14 @@ static int perf_session__process_user_event(struct perf_session *session, union | |||
921 | /* These events are processed right away */ | 1036 | /* These events are processed right away */ |
922 | switch (event->header.type) { | 1037 | switch (event->header.type) { |
923 | case PERF_RECORD_HEADER_ATTR: | 1038 | case PERF_RECORD_HEADER_ATTR: |
924 | err = tool->attr(event, &session->evlist); | 1039 | err = tool->attr(tool, event, &session->evlist); |
925 | if (err == 0) | 1040 | if (err == 0) |
926 | perf_session__set_id_hdr_size(session); | 1041 | perf_session__set_id_hdr_size(session); |
927 | return err; | 1042 | return err; |
928 | case PERF_RECORD_HEADER_EVENT_TYPE: | ||
929 | return tool->event_type(tool, event); | ||
930 | case PERF_RECORD_HEADER_TRACING_DATA: | 1043 | case PERF_RECORD_HEADER_TRACING_DATA: |
931 | /* setup for reading amidst mmap */ | 1044 | /* setup for reading amidst mmap */ |
932 | lseek(session->fd, file_offset, SEEK_SET); | 1045 | lseek(session->fd, file_offset, SEEK_SET); |
933 | return tool->tracing_data(event, session); | 1046 | return tool->tracing_data(tool, event, session); |
934 | case PERF_RECORD_HEADER_BUILD_ID: | 1047 | case PERF_RECORD_HEADER_BUILD_ID: |
935 | return tool->build_id(tool, event, session); | 1048 | return tool->build_id(tool, event, session); |
936 | case PERF_RECORD_FINISHED_ROUND: | 1049 | case PERF_RECORD_FINISHED_ROUND: |
@@ -975,10 +1088,6 @@ static int perf_session__process_event(struct perf_session *session, | |||
975 | if (ret) | 1088 | if (ret) |
976 | return ret; | 1089 | return ret; |
977 | 1090 | ||
978 | /* Preprocess sample records - precheck callchains */ | ||
979 | if (perf_session__preprocess_sample(session, event, &sample)) | ||
980 | return 0; | ||
981 | |||
982 | if (tool->ordered_samples) { | 1091 | if (tool->ordered_samples) { |
983 | ret = perf_session_queue_event(session, event, &sample, | 1092 | ret = perf_session_queue_event(session, event, &sample, |
984 | file_offset); | 1093 | file_offset); |
@@ -999,7 +1108,7 @@ void perf_event_header__bswap(struct perf_event_header *self) | |||
999 | 1108 | ||
1000 | struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) | 1109 | struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) |
1001 | { | 1110 | { |
1002 | return machine__findnew_thread(&session->machines.host, pid); | 1111 | return machine__findnew_thread(&session->machines.host, 0, pid); |
1003 | } | 1112 | } |
1004 | 1113 | ||
1005 | static struct thread *perf_session__register_idle_thread(struct perf_session *self) | 1114 | static struct thread *perf_session__register_idle_thread(struct perf_session *self) |
@@ -1054,7 +1163,6 @@ static void perf_session__warn_about_errors(const struct perf_session *session, | |||
1054 | } | 1163 | } |
1055 | } | 1164 | } |
1056 | 1165 | ||
1057 | #define session_done() (*(volatile int *)(&session_done)) | ||
1058 | volatile int session_done; | 1166 | volatile int session_done; |
1059 | 1167 | ||
1060 | static int __perf_session__process_pipe_events(struct perf_session *self, | 1168 | static int __perf_session__process_pipe_events(struct perf_session *self, |
@@ -1091,8 +1199,10 @@ more: | |||
1091 | perf_event_header__bswap(&event->header); | 1199 | perf_event_header__bswap(&event->header); |
1092 | 1200 | ||
1093 | size = event->header.size; | 1201 | size = event->header.size; |
1094 | if (size == 0) | 1202 | if (size < sizeof(struct perf_event_header)) { |
1095 | size = 8; | 1203 | pr_err("bad event header size\n"); |
1204 | goto out_err; | ||
1205 | } | ||
1096 | 1206 | ||
1097 | if (size > cur_size) { | 1207 | if (size > cur_size) { |
1098 | void *new = realloc(buf, size); | 1208 | void *new = realloc(buf, size); |
@@ -1161,8 +1271,12 @@ fetch_mmaped_event(struct perf_session *session, | |||
1161 | if (session->header.needs_swap) | 1271 | if (session->header.needs_swap) |
1162 | perf_event_header__bswap(&event->header); | 1272 | perf_event_header__bswap(&event->header); |
1163 | 1273 | ||
1164 | if (head + event->header.size > mmap_size) | 1274 | if (head + event->header.size > mmap_size) { |
1275 | /* We're not fetching the event so swap back again */ | ||
1276 | if (session->header.needs_swap) | ||
1277 | perf_event_header__bswap(&event->header); | ||
1165 | return NULL; | 1278 | return NULL; |
1279 | } | ||
1166 | 1280 | ||
1167 | return event; | 1281 | return event; |
1168 | } | 1282 | } |
@@ -1242,7 +1356,7 @@ more: | |||
1242 | 1356 | ||
1243 | size = event->header.size; | 1357 | size = event->header.size; |
1244 | 1358 | ||
1245 | if (size == 0 || | 1359 | if (size < sizeof(struct perf_event_header) || |
1246 | perf_session__process_event(session, event, tool, file_pos) < 0) { | 1360 | perf_session__process_event(session, event, tool, file_pos) < 0) { |
1247 | pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", | 1361 | pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", |
1248 | file_offset + head, event->header.size, | 1362 | file_offset + head, event->header.size, |
@@ -1260,10 +1374,13 @@ more: | |||
1260 | "Processing events..."); | 1374 | "Processing events..."); |
1261 | } | 1375 | } |
1262 | 1376 | ||
1377 | err = 0; | ||
1378 | if (session_done()) | ||
1379 | goto out_err; | ||
1380 | |||
1263 | if (file_pos < file_size) | 1381 | if (file_pos < file_size) |
1264 | goto more; | 1382 | goto more; |
1265 | 1383 | ||
1266 | err = 0; | ||
1267 | /* do the final flush for ordered samples */ | 1384 | /* do the final flush for ordered samples */ |
1268 | session->ordered_samples.next_flush = ULLONG_MAX; | 1385 | session->ordered_samples.next_flush = ULLONG_MAX; |
1269 | err = flush_sample_queue(session, tool); | 1386 | err = flush_sample_queue(session, tool); |
@@ -1295,12 +1412,15 @@ int perf_session__process_events(struct perf_session *self, | |||
1295 | 1412 | ||
1296 | bool perf_session__has_traces(struct perf_session *session, const char *msg) | 1413 | bool perf_session__has_traces(struct perf_session *session, const char *msg) |
1297 | { | 1414 | { |
1298 | if (!(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_RAW)) { | 1415 | struct perf_evsel *evsel; |
1299 | pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg); | 1416 | |
1300 | return false; | 1417 | list_for_each_entry(evsel, &session->evlist->entries, node) { |
1418 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT) | ||
1419 | return true; | ||
1301 | } | 1420 | } |
1302 | 1421 | ||
1303 | return true; | 1422 | pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg); |
1423 | return false; | ||
1304 | } | 1424 | } |
1305 | 1425 | ||
1306 | int maps__set_kallsyms_ref_reloc_sym(struct map **maps, | 1426 | int maps__set_kallsyms_ref_reloc_sym(struct map **maps, |
@@ -1383,13 +1503,18 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
1383 | 1503 | ||
1384 | void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | 1504 | void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, |
1385 | struct perf_sample *sample, struct machine *machine, | 1505 | struct perf_sample *sample, struct machine *machine, |
1386 | int print_sym, int print_dso, int print_symoffset) | 1506 | unsigned int print_opts, unsigned int stack_depth) |
1387 | { | 1507 | { |
1388 | struct addr_location al; | 1508 | struct addr_location al; |
1389 | struct callchain_cursor_node *node; | 1509 | struct callchain_cursor_node *node; |
1390 | 1510 | int print_ip = print_opts & PRINT_IP_OPT_IP; | |
1391 | if (perf_event__preprocess_sample(event, machine, &al, sample, | 1511 | int print_sym = print_opts & PRINT_IP_OPT_SYM; |
1392 | NULL) < 0) { | 1512 | int print_dso = print_opts & PRINT_IP_OPT_DSO; |
1513 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; | ||
1514 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; | ||
1515 | char s = print_oneline ? ' ' : '\t'; | ||
1516 | |||
1517 | if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { | ||
1393 | error("problem processing %d event, skipping it.\n", | 1518 | error("problem processing %d event, skipping it.\n", |
1394 | event->header.type); | 1519 | event->header.type); |
1395 | return; | 1520 | return; |
@@ -1397,37 +1522,50 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | |||
1397 | 1522 | ||
1398 | if (symbol_conf.use_callchain && sample->callchain) { | 1523 | if (symbol_conf.use_callchain && sample->callchain) { |
1399 | 1524 | ||
1400 | |||
1401 | if (machine__resolve_callchain(machine, evsel, al.thread, | 1525 | if (machine__resolve_callchain(machine, evsel, al.thread, |
1402 | sample, NULL) != 0) { | 1526 | sample, NULL, NULL) != 0) { |
1403 | if (verbose) | 1527 | if (verbose) |
1404 | error("Failed to resolve callchain. Skipping\n"); | 1528 | error("Failed to resolve callchain. Skipping\n"); |
1405 | return; | 1529 | return; |
1406 | } | 1530 | } |
1407 | callchain_cursor_commit(&callchain_cursor); | 1531 | callchain_cursor_commit(&callchain_cursor); |
1408 | 1532 | ||
1409 | while (1) { | 1533 | while (stack_depth) { |
1410 | node = callchain_cursor_current(&callchain_cursor); | 1534 | node = callchain_cursor_current(&callchain_cursor); |
1411 | if (!node) | 1535 | if (!node) |
1412 | break; | 1536 | break; |
1413 | 1537 | ||
1414 | printf("\t%16" PRIx64, node->ip); | 1538 | if (print_ip) |
1539 | printf("%c%16" PRIx64, s, node->ip); | ||
1540 | |||
1415 | if (print_sym) { | 1541 | if (print_sym) { |
1416 | printf(" "); | 1542 | printf(" "); |
1417 | symbol__fprintf_symname(node->sym, stdout); | 1543 | if (print_symoffset) { |
1544 | al.addr = node->ip; | ||
1545 | al.map = node->map; | ||
1546 | symbol__fprintf_symname_offs(node->sym, &al, stdout); | ||
1547 | } else | ||
1548 | symbol__fprintf_symname(node->sym, stdout); | ||
1418 | } | 1549 | } |
1550 | |||
1419 | if (print_dso) { | 1551 | if (print_dso) { |
1420 | printf(" ("); | 1552 | printf(" ("); |
1421 | map__fprintf_dsoname(node->map, stdout); | 1553 | map__fprintf_dsoname(node->map, stdout); |
1422 | printf(")"); | 1554 | printf(")"); |
1423 | } | 1555 | } |
1424 | printf("\n"); | 1556 | |
1557 | if (!print_oneline) | ||
1558 | printf("\n"); | ||
1425 | 1559 | ||
1426 | callchain_cursor_advance(&callchain_cursor); | 1560 | callchain_cursor_advance(&callchain_cursor); |
1561 | |||
1562 | stack_depth--; | ||
1427 | } | 1563 | } |
1428 | 1564 | ||
1429 | } else { | 1565 | } else { |
1430 | printf("%16" PRIx64, sample->ip); | 1566 | if (print_ip) |
1567 | printf("%16" PRIx64, sample->ip); | ||
1568 | |||
1431 | if (print_sym) { | 1569 | if (print_sym) { |
1432 | printf(" "); | 1570 | printf(" "); |
1433 | if (print_symoffset) | 1571 | if (print_symoffset) |
@@ -1510,52 +1648,26 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session, | |||
1510 | const struct perf_evsel_str_handler *assocs, | 1648 | const struct perf_evsel_str_handler *assocs, |
1511 | size_t nr_assocs) | 1649 | size_t nr_assocs) |
1512 | { | 1650 | { |
1513 | struct perf_evlist *evlist = session->evlist; | ||
1514 | struct event_format *format; | ||
1515 | struct perf_evsel *evsel; | 1651 | struct perf_evsel *evsel; |
1516 | char *tracepoint, *name; | ||
1517 | size_t i; | 1652 | size_t i; |
1518 | int err; | 1653 | int err; |
1519 | 1654 | ||
1520 | for (i = 0; i < nr_assocs; i++) { | 1655 | for (i = 0; i < nr_assocs; i++) { |
1521 | err = -ENOMEM; | 1656 | /* |
1522 | tracepoint = strdup(assocs[i].name); | 1657 | * Adding a handler for an event not in the session, |
1523 | if (tracepoint == NULL) | 1658 | * just ignore it. |
1524 | goto out; | 1659 | */ |
1525 | 1660 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, assocs[i].name); | |
1526 | err = -ENOENT; | ||
1527 | name = strchr(tracepoint, ':'); | ||
1528 | if (name == NULL) | ||
1529 | goto out_free; | ||
1530 | |||
1531 | *name++ = '\0'; | ||
1532 | format = pevent_find_event_by_name(session->pevent, | ||
1533 | tracepoint, name); | ||
1534 | if (format == NULL) { | ||
1535 | /* | ||
1536 | * Adding a handler for an event not in the session, | ||
1537 | * just ignore it. | ||
1538 | */ | ||
1539 | goto next; | ||
1540 | } | ||
1541 | |||
1542 | evsel = perf_evlist__find_tracepoint_by_id(evlist, format->id); | ||
1543 | if (evsel == NULL) | 1661 | if (evsel == NULL) |
1544 | goto next; | 1662 | continue; |
1545 | 1663 | ||
1546 | err = -EEXIST; | 1664 | err = -EEXIST; |
1547 | if (evsel->handler.func != NULL) | 1665 | if (evsel->handler.func != NULL) |
1548 | goto out_free; | 1666 | goto out; |
1549 | evsel->handler.func = assocs[i].handler; | 1667 | evsel->handler.func = assocs[i].handler; |
1550 | next: | ||
1551 | free(tracepoint); | ||
1552 | } | 1668 | } |
1553 | 1669 | ||
1554 | err = 0; | 1670 | err = 0; |
1555 | out: | 1671 | out: |
1556 | return err; | 1672 | return err; |
1557 | |||
1558 | out_free: | ||
1559 | free(tracepoint); | ||
1560 | goto out; | ||
1561 | } | 1673 | } |