aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/event.h35
-rw-r--r--tools/perf/util/header.c361
-rw-r--r--tools/perf/util/header.h38
-rw-r--r--tools/perf/util/session.c192
-rw-r--r--tools/perf/util/session.h10
-rw-r--r--tools/perf/util/trace-event-info.c24
-rw-r--r--tools/perf/util/trace-event-read.c89
-rw-r--r--tools/perf/util/trace-event.h4
8 files changed, 672 insertions, 81 deletions
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 7f7cf8539cfe..e5740ea140ab 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -83,6 +83,37 @@ struct build_id_event {
83 char filename[]; 83 char filename[];
84}; 84};
85 85
86enum perf_header_event_type { /* above any possible kernel type */
87 PERF_RECORD_HEADER_ATTR = 64,
88 PERF_RECORD_HEADER_EVENT_TYPE = 65,
89 PERF_RECORD_HEADER_TRACING_DATA = 66,
90 PERF_RECORD_HEADER_BUILD_ID = 67,
91 PERF_RECORD_HEADER_MAX
92};
93
94struct attr_event {
95 struct perf_event_header header;
96 struct perf_event_attr attr;
97 u64 id[];
98};
99
100#define MAX_EVENT_NAME 64
101
102struct perf_trace_event_type {
103 u64 event_id;
104 char name[MAX_EVENT_NAME];
105};
106
107struct event_type_event {
108 struct perf_event_header header;
109 struct perf_trace_event_type event_type;
110};
111
112struct tracing_data_event {
113 struct perf_event_header header;
114 u32 size;
115};
116
86typedef union event_union { 117typedef union event_union {
87 struct perf_event_header header; 118 struct perf_event_header header;
88 struct ip_event ip; 119 struct ip_event ip;
@@ -92,6 +123,10 @@ typedef union event_union {
92 struct lost_event lost; 123 struct lost_event lost;
93 struct read_event read; 124 struct read_event read;
94 struct sample_event sample; 125 struct sample_event sample;
126 struct attr_event attr;
127 struct event_type_event event_type;
128 struct tracing_data_event tracing_data;
129 struct build_id_event build_id;
95} event_t; 130} event_t;
96 131
97struct events_stats { 132struct events_stats {
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 6c9aa16ee51f..628173ba689e 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -99,13 +99,6 @@ int perf_header__add_attr(struct perf_header *self,
99 return 0; 99 return 0;
100} 100}
101 101
102#define MAX_EVENT_NAME 64
103
104struct perf_trace_event_type {
105 u64 event_id;
106 char name[MAX_EVENT_NAME];
107};
108
109static int event_count; 102static int event_count;
110static struct perf_trace_event_type *events; 103static struct perf_trace_event_type *events;
111 104
@@ -427,6 +420,25 @@ out_free:
427 return err; 420 return err;
428} 421}
429 422
423int perf_header__write_pipe(int fd)
424{
425 struct perf_pipe_file_header f_header;
426 int err;
427
428 f_header = (struct perf_pipe_file_header){
429 .magic = PERF_MAGIC,
430 .size = sizeof(f_header),
431 };
432
433 err = do_write(fd, &f_header, sizeof(f_header));
434 if (err < 0) {
435 pr_debug("failed to write perf pipe header\n");
436 return err;
437 }
438
439 return 0;
440}
441
430int perf_header__write(struct perf_header *self, int fd, bool at_exit) 442int perf_header__write(struct perf_header *self, int fd, bool at_exit)
431{ 443{
432 struct perf_file_header f_header; 444 struct perf_file_header f_header;
@@ -518,25 +530,10 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
518 return 0; 530 return 0;
519} 531}
520 532
521static int do_read(int fd, void *buf, size_t size)
522{
523 while (size) {
524 int ret = read(fd, buf, size);
525
526 if (ret <= 0)
527 return -1;
528
529 size -= ret;
530 buf += ret;
531 }
532
533 return 0;
534}
535
536static int perf_header__getbuffer64(struct perf_header *self, 533static int perf_header__getbuffer64(struct perf_header *self,
537 int fd, void *buf, size_t size) 534 int fd, void *buf, size_t size)
538{ 535{
539 if (do_read(fd, buf, size)) 536 if (do_read(fd, buf, size) <= 0)
540 return -1; 537 return -1;
541 538
542 if (self->needs_swap) 539 if (self->needs_swap)
@@ -592,7 +589,7 @@ int perf_file_header__read(struct perf_file_header *self,
592{ 589{
593 lseek(fd, 0, SEEK_SET); 590 lseek(fd, 0, SEEK_SET);
594 591
595 if (do_read(fd, self, sizeof(*self)) || 592 if (do_read(fd, self, sizeof(*self)) <= 0 ||
596 memcmp(&self->magic, __perf_magic, sizeof(self->magic))) 593 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
597 return -1; 594 return -1;
598 595
@@ -662,13 +659,51 @@ static int perf_file_section__process(struct perf_file_section *self,
662 return 0; 659 return 0;
663} 660}
664 661
665int perf_header__read(struct perf_header *self, int fd) 662static int perf_file_header__read_pipe(struct perf_pipe_file_header *self,
663 struct perf_header *ph, int fd)
664{
665 if (do_read(fd, self, sizeof(*self)) <= 0 ||
666 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
667 return -1;
668
669 if (self->size != sizeof(*self)) {
670 u64 size = bswap_64(self->size);
671
672 if (size != sizeof(*self))
673 return -1;
674
675 ph->needs_swap = true;
676 }
677
678 return 0;
679}
680
681static int perf_header__read_pipe(struct perf_session *session, int fd)
682{
683 struct perf_header *self = &session->header;
684 struct perf_pipe_file_header f_header;
685
686 if (perf_file_header__read_pipe(&f_header, self, fd) < 0) {
687 pr_debug("incompatible file format\n");
688 return -EINVAL;
689 }
690
691 session->fd = fd;
692
693 return 0;
694}
695
696int perf_header__read(struct perf_session *session, int fd)
666{ 697{
698 struct perf_header *self = &session->header;
667 struct perf_file_header f_header; 699 struct perf_file_header f_header;
668 struct perf_file_attr f_attr; 700 struct perf_file_attr f_attr;
669 u64 f_id; 701 u64 f_id;
670 int nr_attrs, nr_ids, i, j; 702 int nr_attrs, nr_ids, i, j;
671 703
704 if (session->fd_pipe)
705 return perf_header__read_pipe(session, fd);
706
672 if (perf_file_header__read(&f_header, self, fd) < 0) { 707 if (perf_file_header__read(&f_header, self, fd) < 0) {
673 pr_debug("incompatible file format\n"); 708 pr_debug("incompatible file format\n");
674 return -EINVAL; 709 return -EINVAL;
@@ -765,3 +800,279 @@ perf_header__find_attr(u64 id, struct perf_header *header)
765 800
766 return NULL; 801 return NULL;
767} 802}
803
804int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
805 event__handler_t process,
806 struct perf_session *session)
807{
808 event_t *ev;
809 size_t size;
810 int err;
811
812 size = sizeof(struct perf_event_attr);
813 size = ALIGN(size, sizeof(u64));
814 size += sizeof(struct perf_event_header);
815 size += ids * sizeof(u64);
816
817 ev = malloc(size);
818
819 ev->attr.attr = *attr;
820 memcpy(ev->attr.id, id, ids * sizeof(u64));
821
822 ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
823 ev->attr.header.size = size;
824
825 err = process(ev, session);
826
827 free(ev);
828
829 return err;
830}
831
832int event__synthesize_attrs(struct perf_header *self,
833 event__handler_t process,
834 struct perf_session *session)
835{
836 struct perf_header_attr *attr;
837 int i, err = 0;
838
839 for (i = 0; i < self->attrs; i++) {
840 attr = self->attr[i];
841
842 err = event__synthesize_attr(&attr->attr, attr->ids, attr->id,
843 process, session);
844 if (err) {
845 pr_debug("failed to create perf header attribute\n");
846 return err;
847 }
848 }
849
850 return err;
851}
852
853int event__process_attr(event_t *self, struct perf_session *session)
854{
855 struct perf_header_attr *attr;
856 unsigned int i, ids, n_ids;
857
858 attr = perf_header_attr__new(&self->attr.attr);
859 if (attr == NULL)
860 return -ENOMEM;
861
862 ids = self->header.size;
863 ids -= (void *)&self->attr.id - (void *)self;
864 n_ids = ids / sizeof(u64);
865
866 for (i = 0; i < n_ids; i++) {
867 if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) {
868 perf_header_attr__delete(attr);
869 return -ENOMEM;
870 }
871 }
872
873 if (perf_header__add_attr(&session->header, attr) < 0) {
874 perf_header_attr__delete(attr);
875 return -ENOMEM;
876 }
877
878 perf_session__update_sample_type(session);
879
880 return 0;
881}
882
883int event__synthesize_event_type(u64 event_id, char *name,
884 event__handler_t process,
885 struct perf_session *session)
886{
887 event_t ev;
888 size_t size = 0;
889 int err = 0;
890
891 memset(&ev, 0, sizeof(ev));
892
893 ev.event_type.event_type.event_id = event_id;
894 memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME);
895 strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1);
896
897 ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
898 size = strlen(name);
899 size = ALIGN(size, sizeof(u64));
900 ev.event_type.header.size = sizeof(ev.event_type) -
901 (sizeof(ev.event_type.event_type.name) - size);
902
903 err = process(&ev, session);
904
905 return err;
906}
907
908int event__synthesize_event_types(event__handler_t process,
909 struct perf_session *session)
910{
911 struct perf_trace_event_type *type;
912 int i, err = 0;
913
914 for (i = 0; i < event_count; i++) {
915 type = &events[i];
916
917 err = event__synthesize_event_type(type->event_id, type->name,
918 process, session);
919 if (err) {
920 pr_debug("failed to create perf header event type\n");
921 return err;
922 }
923 }
924
925 return err;
926}
927
928int event__process_event_type(event_t *self,
929 struct perf_session *session __unused)
930{
931 if (perf_header__push_event(self->event_type.event_type.event_id,
932 self->event_type.event_type.name) < 0)
933 return -ENOMEM;
934
935 return 0;
936}
937
938int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
939 int nb_events,
940 event__handler_t process,
941 struct perf_session *session __unused)
942{
943 event_t ev;
944 ssize_t size = 0, aligned_size = 0, padding;
945 int err = 0;
946
947 memset(&ev, 0, sizeof(ev));
948
949 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
950 size = read_tracing_data_size(fd, pattrs, nb_events);
951 if (size <= 0)
952 return size;
953 aligned_size = ALIGN(size, sizeof(u64));
954 padding = aligned_size - size;
955 ev.tracing_data.header.size = sizeof(ev.tracing_data);
956 ev.tracing_data.size = aligned_size;
957
958 process(&ev, session);
959
960 err = read_tracing_data(fd, pattrs, nb_events);
961 write_padded(fd, NULL, 0, padding);
962
963 return aligned_size;
964}
965
966int event__process_tracing_data(event_t *self,
967 struct perf_session *session)
968{
969 ssize_t size_read, padding, size = self->tracing_data.size;
970 off_t offset = lseek(session->fd, 0, SEEK_CUR);
971 char buf[BUFSIZ];
972
973 /* setup for reading amidst mmap */
974 lseek(session->fd, offset + sizeof(struct tracing_data_event),
975 SEEK_SET);
976
977 size_read = trace_report(session->fd);
978
979 padding = ALIGN(size_read, sizeof(u64)) - size_read;
980
981 if (read(session->fd, buf, padding) < 0)
982 die("reading input file");
983
984 if (size_read + padding != size)
985 die("tracing data size mismatch");
986
987 return size_read + padding;
988}
989
990int event__synthesize_build_id(struct dso *pos, u16 misc,
991 event__handler_t process,
992 struct perf_session *session)
993{
994 event_t ev;
995 size_t len;
996 int err = 0;
997
998 if (!pos->hit)
999 return err;
1000
1001 memset(&ev, 0, sizeof(ev));
1002
1003 len = pos->long_name_len + 1;
1004 len = ALIGN(len, NAME_ALIGN);
1005 memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id));
1006 ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID;
1007 ev.build_id.header.misc = misc;
1008 ev.build_id.header.size = sizeof(ev.build_id) + len;
1009 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
1010
1011 err = process(&ev, session);
1012
1013 return err;
1014}
1015
1016static int __event_synthesize_build_ids(struct list_head *head, u16 misc,
1017 event__handler_t process,
1018 struct perf_session *session)
1019{
1020 struct dso *pos;
1021
1022 dsos__for_each_with_build_id(pos, head) {
1023 int err;
1024 if (!pos->hit)
1025 continue;
1026
1027 err = event__synthesize_build_id(pos, misc, process, session);
1028 if (err < 0)
1029 return err;
1030 }
1031
1032 return 0;
1033}
1034
1035int event__synthesize_build_ids(event__handler_t process,
1036 struct perf_session *session)
1037{
1038 int err;
1039
1040 if (!dsos__read_build_ids(true))
1041 return 0;
1042
1043 err = __event_synthesize_build_ids(&dsos__kernel,
1044 PERF_RECORD_MISC_KERNEL,
1045 process, session);
1046 if (err == 0)
1047 err = __event_synthesize_build_ids(&dsos__user,
1048 PERF_RECORD_MISC_USER,
1049 process, session);
1050
1051 if (err < 0) {
1052 pr_debug("failed to synthesize build ids\n");
1053 return err;
1054 }
1055
1056 dsos__cache_build_ids();
1057
1058 return 0;
1059}
1060
1061int event__process_build_id(event_t *self,
1062 struct perf_session *session __unused)
1063{
1064 struct list_head *head = &dsos__user;
1065 struct dso *dso;
1066
1067 if (self->build_id.header.misc & PERF_RECORD_MISC_KERNEL)
1068 head = &dsos__kernel;
1069
1070 dso = __dsos__findnew(head, self->build_id.filename);
1071 if (dso != NULL) {
1072 dso__set_build_id(dso, &self->build_id.build_id);
1073 if (head == &dsos__kernel && self->build_id.filename[0] == '[')
1074 dso->kernel = 1;
1075 }
1076
1077 return 0;
1078}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index c059f08cf877..4214e2375650 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -39,6 +39,11 @@ struct perf_file_header {
39 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 39 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
40}; 40};
41 41
42struct perf_pipe_file_header {
43 u64 magic;
44 u64 size;
45};
46
42struct perf_header; 47struct perf_header;
43 48
44int perf_file_header__read(struct perf_file_header *self, 49int perf_file_header__read(struct perf_file_header *self,
@@ -60,8 +65,9 @@ struct perf_header {
60int perf_header__init(struct perf_header *self); 65int perf_header__init(struct perf_header *self);
61void perf_header__exit(struct perf_header *self); 66void perf_header__exit(struct perf_header *self);
62 67
63int perf_header__read(struct perf_header *self, int fd); 68int perf_header__read(struct perf_session *session, int fd);
64int perf_header__write(struct perf_header *self, int fd, bool at_exit); 69int perf_header__write(struct perf_header *self, int fd, bool at_exit);
70int perf_header__write_pipe(int fd);
65 71
66int perf_header__add_attr(struct perf_header *self, 72int perf_header__add_attr(struct perf_header *self,
67 struct perf_header_attr *attr); 73 struct perf_header_attr *attr);
@@ -89,4 +95,34 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
89 const char *name, bool is_kallsyms); 95 const char *name, bool is_kallsyms);
90int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); 96int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
91 97
98int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
99 event__handler_t process,
100 struct perf_session *session);
101int event__synthesize_attrs(struct perf_header *self,
102 event__handler_t process,
103 struct perf_session *session);
104int event__process_attr(event_t *self, struct perf_session *session);
105
106int event__synthesize_event_type(u64 event_id, char *name,
107 event__handler_t process,
108 struct perf_session *session);
109int event__synthesize_event_types(event__handler_t process,
110 struct perf_session *session);
111int event__process_event_type(event_t *self,
112 struct perf_session *session);
113
114int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
115 int nb_events,
116 event__handler_t process,
117 struct perf_session *session);
118int event__process_tracing_data(event_t *self,
119 struct perf_session *session);
120
121int event__synthesize_build_id(struct dso *pos, u16 misc,
122 event__handler_t process,
123 struct perf_session *session);
124int event__synthesize_build_ids(event__handler_t process,
125 struct perf_session *session);
126int event__process_build_id(event_t *self, struct perf_session *session);
127
92#endif /* __PERF_HEADER_H */ 128#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ddf288fca3eb..0fdf3ebef1e9 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -14,6 +14,16 @@ static int perf_session__open(struct perf_session *self, bool force)
14{ 14{
15 struct stat input_stat; 15 struct stat input_stat;
16 16
17 if (!strcmp(self->filename, "-")) {
18 self->fd_pipe = true;
19 self->fd = STDIN_FILENO;
20
21 if (perf_header__read(self, self->fd) < 0)
22 pr_err("incompatible file format");
23
24 return 0;
25 }
26
17 self->fd = open(self->filename, O_RDONLY); 27 self->fd = open(self->filename, O_RDONLY);
18 if (self->fd < 0) { 28 if (self->fd < 0) {
19 pr_err("failed to open file: %s", self->filename); 29 pr_err("failed to open file: %s", self->filename);
@@ -38,7 +48,7 @@ static int perf_session__open(struct perf_session *self, bool force)
38 goto out_close; 48 goto out_close;
39 } 49 }
40 50
41 if (perf_header__read(&self->header, self->fd) < 0) { 51 if (perf_header__read(self, self->fd) < 0) {
42 pr_err("incompatible file format"); 52 pr_err("incompatible file format");
43 goto out_close; 53 goto out_close;
44 } 54 }
@@ -52,6 +62,11 @@ out_close:
52 return -1; 62 return -1;
53} 63}
54 64
65void perf_session__update_sample_type(struct perf_session *self)
66{
67 self->sample_type = perf_header__sample_type(&self->header);
68}
69
55struct perf_session *perf_session__new(const char *filename, int mode, bool force) 70struct perf_session *perf_session__new(const char *filename, int mode, bool force)
56{ 71{
57 size_t len = filename ? strlen(filename) + 1 : 0; 72 size_t len = filename ? strlen(filename) + 1 : 0;
@@ -85,7 +100,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
85 goto out_delete; 100 goto out_delete;
86 } 101 }
87 102
88 self->sample_type = perf_header__sample_type(&self->header); 103 perf_session__update_sample_type(self);
89out: 104out:
90 return self; 105 return self;
91out_free: 106out_free:
@@ -185,6 +200,14 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
185 handler->throttle = process_event_stub; 200 handler->throttle = process_event_stub;
186 if (handler->unthrottle == NULL) 201 if (handler->unthrottle == NULL)
187 handler->unthrottle = process_event_stub; 202 handler->unthrottle = process_event_stub;
203 if (handler->attr == NULL)
204 handler->attr = process_event_stub;
205 if (handler->event_type == NULL)
206 handler->event_type = process_event_stub;
207 if (handler->tracing_data == NULL)
208 handler->tracing_data = process_event_stub;
209 if (handler->build_id == NULL)
210 handler->build_id = process_event_stub;
188} 211}
189 212
190static const char *event__name[] = { 213static const char *event__name[] = {
@@ -198,16 +221,23 @@ static const char *event__name[] = {
198 [PERF_RECORD_FORK] = "FORK", 221 [PERF_RECORD_FORK] = "FORK",
199 [PERF_RECORD_READ] = "READ", 222 [PERF_RECORD_READ] = "READ",
200 [PERF_RECORD_SAMPLE] = "SAMPLE", 223 [PERF_RECORD_SAMPLE] = "SAMPLE",
224 [PERF_RECORD_HEADER_ATTR] = "ATTR",
225 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
226 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
227 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
201}; 228};
202 229
203unsigned long event__total[PERF_RECORD_MAX]; 230unsigned long event__total[PERF_RECORD_HEADER_MAX];
204 231
205void event__print_totals(void) 232void event__print_totals(void)
206{ 233{
207 int i; 234 int i;
208 for (i = 0; i < PERF_RECORD_MAX; ++i) 235 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
236 if (!event__name[i])
237 continue;
209 pr_info("%10s events: %10ld\n", 238 pr_info("%10s events: %10ld\n",
210 event__name[i], event__total[i]); 239 event__name[i], event__total[i]);
240 }
211} 241}
212 242
213void mem_bswap_64(void *src, int byte_size) 243void mem_bswap_64(void *src, int byte_size)
@@ -261,6 +291,37 @@ static void event__read_swap(event_t *self)
261 self->read.id = bswap_64(self->read.id); 291 self->read.id = bswap_64(self->read.id);
262} 292}
263 293
294static void event__attr_swap(event_t *self)
295{
296 size_t size;
297
298 self->attr.attr.type = bswap_32(self->attr.attr.type);
299 self->attr.attr.size = bswap_32(self->attr.attr.size);
300 self->attr.attr.config = bswap_64(self->attr.attr.config);
301 self->attr.attr.sample_period = bswap_64(self->attr.attr.sample_period);
302 self->attr.attr.sample_type = bswap_64(self->attr.attr.sample_type);
303 self->attr.attr.read_format = bswap_64(self->attr.attr.read_format);
304 self->attr.attr.wakeup_events = bswap_32(self->attr.attr.wakeup_events);
305 self->attr.attr.bp_type = bswap_32(self->attr.attr.bp_type);
306 self->attr.attr.bp_addr = bswap_64(self->attr.attr.bp_addr);
307 self->attr.attr.bp_len = bswap_64(self->attr.attr.bp_len);
308
309 size = self->header.size;
310 size -= (void *)&self->attr.id - (void *)self;
311 mem_bswap_64(self->attr.id, size);
312}
313
314static void event__event_type_swap(event_t *self)
315{
316 self->event_type.event_type.event_id =
317 bswap_64(self->event_type.event_type.event_id);
318}
319
320static void event__tracing_data_swap(event_t *self)
321{
322 self->tracing_data.size = bswap_32(self->tracing_data.size);
323}
324
264typedef void (*event__swap_op)(event_t *self); 325typedef void (*event__swap_op)(event_t *self);
265 326
266static event__swap_op event__swap_ops[] = { 327static event__swap_op event__swap_ops[] = {
@@ -271,7 +332,11 @@ static event__swap_op event__swap_ops[] = {
271 [PERF_RECORD_LOST] = event__all64_swap, 332 [PERF_RECORD_LOST] = event__all64_swap,
272 [PERF_RECORD_READ] = event__read_swap, 333 [PERF_RECORD_READ] = event__read_swap,
273 [PERF_RECORD_SAMPLE] = event__all64_swap, 334 [PERF_RECORD_SAMPLE] = event__all64_swap,
274 [PERF_RECORD_MAX] = NULL, 335 [PERF_RECORD_HEADER_ATTR] = event__attr_swap,
336 [PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap,
337 [PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap,
338 [PERF_RECORD_HEADER_BUILD_ID] = NULL,
339 [PERF_RECORD_HEADER_MAX] = NULL,
275}; 340};
276 341
277static int perf_session__process_event(struct perf_session *self, 342static int perf_session__process_event(struct perf_session *self,
@@ -281,7 +346,7 @@ static int perf_session__process_event(struct perf_session *self,
281{ 346{
282 trace_event(event); 347 trace_event(event);
283 348
284 if (event->header.type < PERF_RECORD_MAX) { 349 if (event->header.type < PERF_RECORD_HEADER_MAX) {
285 dump_printf("%#Lx [%#x]: PERF_RECORD_%s", 350 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
286 offset + head, event->header.size, 351 offset + head, event->header.size,
287 event__name[event->header.type]); 352 event__name[event->header.type]);
@@ -311,6 +376,16 @@ static int perf_session__process_event(struct perf_session *self,
311 return ops->throttle(event, self); 376 return ops->throttle(event, self);
312 case PERF_RECORD_UNTHROTTLE: 377 case PERF_RECORD_UNTHROTTLE:
313 return ops->unthrottle(event, self); 378 return ops->unthrottle(event, self);
379 case PERF_RECORD_HEADER_ATTR:
380 return ops->attr(event, self);
381 case PERF_RECORD_HEADER_EVENT_TYPE:
382 return ops->event_type(event, self);
383 case PERF_RECORD_HEADER_TRACING_DATA:
384 /* setup for reading amidst mmap */
385 lseek(self->fd, offset + head, SEEK_SET);
386 return ops->tracing_data(event, self);
387 case PERF_RECORD_HEADER_BUILD_ID:
388 return ops->build_id(event, self);
314 default: 389 default:
315 self->unknown_events++; 390 self->unknown_events++;
316 return -1; 391 return -1;
@@ -376,6 +451,101 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
376 return thread; 451 return thread;
377} 452}
378 453
454int do_read(int fd, void *buf, size_t size)
455{
456 void *buf_start = buf;
457
458 while (size) {
459 int ret = read(fd, buf, size);
460
461 if (ret <= 0)
462 return ret;
463
464 size -= ret;
465 buf += ret;
466 }
467
468 return buf - buf_start;
469}
470
471#define session_done() (*(volatile int *)(&session_done))
472volatile int session_done;
473
474static int __perf_session__process_pipe_events(struct perf_session *self,
475 struct perf_event_ops *ops)
476{
477 event_t event;
478 uint32_t size;
479 int skip = 0;
480 u64 head;
481 int err;
482 void *p;
483
484 perf_event_ops__fill_defaults(ops);
485
486 head = 0;
487more:
488 err = do_read(self->fd, &event, sizeof(struct perf_event_header));
489 if (err <= 0) {
490 if (err == 0)
491 goto done;
492
493 pr_err("failed to read event header\n");
494 goto out_err;
495 }
496
497 if (self->header.needs_swap)
498 perf_event_header__bswap(&event.header);
499
500 size = event.header.size;
501 if (size == 0)
502 size = 8;
503
504 p = &event;
505 p += sizeof(struct perf_event_header);
506
507 err = do_read(self->fd, p, size - sizeof(struct perf_event_header));
508 if (err <= 0) {
509 if (err == 0) {
510 pr_err("unexpected end of event stream\n");
511 goto done;
512 }
513
514 pr_err("failed to read event data\n");
515 goto out_err;
516 }
517
518 if (size == 0 ||
519 (skip = perf_session__process_event(self, &event, ops,
520 0, head)) < 0) {
521 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
522 head, event.header.size, event.header.type);
523 /*
524 * assume we lost track of the stream, check alignment, and
525 * increment a single u64 in the hope to catch on again 'soon'.
526 */
527 if (unlikely(head & 7))
528 head &= ~7ULL;
529
530 size = 8;
531 }
532
533 head += size;
534
535 dump_printf("\n%#Lx [%#x]: event: %d\n",
536 head, event.header.size, event.header.type);
537
538 if (skip > 0)
539 head += skip;
540
541 if (!session_done())
542 goto more;
543done:
544 err = 0;
545out_err:
546 return err;
547}
548
379int __perf_session__process_events(struct perf_session *self, 549int __perf_session__process_events(struct perf_session *self,
380 u64 data_offset, u64 data_size, 550 u64 data_offset, u64 data_size,
381 u64 file_size, struct perf_event_ops *ops) 551 u64 file_size, struct perf_event_ops *ops)
@@ -499,9 +669,13 @@ out_getcwd_err:
499 self->cwdlen = strlen(self->cwd); 669 self->cwdlen = strlen(self->cwd);
500 } 670 }
501 671
502 err = __perf_session__process_events(self, self->header.data_offset, 672 if (!self->fd_pipe)
503 self->header.data_size, 673 err = __perf_session__process_events(self,
504 self->size, ops); 674 self->header.data_offset,
675 self->header.data_size,
676 self->size, ops);
677 else
678 err = __perf_session__process_pipe_events(self, ops);
505out_err: 679out_err:
506 return err; 680 return err;
507} 681}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 27f4c2dc715b..0ac14d42dc28 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -27,6 +27,7 @@ struct perf_session {
27 u64 sample_type; 27 u64 sample_type;
28 struct ref_reloc_sym ref_reloc_sym; 28 struct ref_reloc_sym ref_reloc_sym;
29 int fd; 29 int fd;
30 bool fd_pipe;
30 int cwdlen; 31 int cwdlen;
31 char *cwd; 32 char *cwd;
32 char filename[0]; 33 char filename[0];
@@ -43,7 +44,11 @@ struct perf_event_ops {
43 lost, 44 lost,
44 read, 45 read,
45 throttle, 46 throttle,
46 unthrottle; 47 unthrottle,
48 attr,
49 event_type,
50 tracing_data,
51 build_id;
47}; 52};
48 53
49struct perf_session *perf_session__new(const char *filename, int mode, bool force); 54struct perf_session *perf_session__new(const char *filename, int mode, bool force);
@@ -92,6 +97,9 @@ static inline struct map *
92 return map_groups__new_module(&self->kmaps, start, filename); 97 return map_groups__new_module(&self->kmaps, start, filename);
93} 98}
94 99
100int do_read(int fd, void *buf, size_t size);
101void perf_session__update_sample_type(struct perf_session *self);
102
95#ifdef NO_NEWT_SUPPORT 103#ifdef NO_NEWT_SUPPORT
96static inline int perf_session__browse_hists(struct rb_root *hists __used, 104static inline int perf_session__browse_hists(struct rb_root *hists __used,
97 u64 nr_hists __used, 105 u64 nr_hists __used,
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 5ea8973ad331..30cd9b575953 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -154,10 +154,17 @@ static void put_tracing_file(char *file)
154 free(file); 154 free(file);
155} 155}
156 156
157static ssize_t calc_data_size;
158
157static ssize_t write_or_die(const void *buf, size_t len) 159static ssize_t write_or_die(const void *buf, size_t len)
158{ 160{
159 int ret; 161 int ret;
160 162
163 if (calc_data_size) {
164 calc_data_size += len;
165 return len;
166 }
167
161 ret = write(output_fd, buf, len); 168 ret = write(output_fd, buf, len);
162 if (ret < 0) 169 if (ret < 0)
163 die("writing to '%s'", output_file); 170 die("writing to '%s'", output_file);
@@ -526,3 +533,20 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
526 533
527 return 0; 534 return 0;
528} 535}
536
537ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs,
538 int nb_events)
539{
540 ssize_t size;
541 int err = 0;
542
543 calc_data_size = 1;
544 err = read_tracing_data(fd, pattrs, nb_events);
545 size = calc_data_size - 1;
546 calc_data_size = 0;
547
548 if (err < 0)
549 return err;
550
551 return size;
552}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 7cd1193918c7..44889c9b5630 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -50,14 +50,37 @@ static int long_size;
50 50
51static unsigned long page_size; 51static unsigned long page_size;
52 52
53static ssize_t calc_data_size;
54
55static int do_read(int fd, void *buf, int size)
56{
57 int rsize = size;
58
59 while (size) {
60 int ret = read(fd, buf, size);
61
62 if (ret <= 0)
63 return -1;
64
65 size -= ret;
66 buf += ret;
67 }
68
69 return rsize;
70}
71
53static int read_or_die(void *data, int size) 72static int read_or_die(void *data, int size)
54{ 73{
55 int r; 74 int r;
56 75
57 r = read(input_fd, data, size); 76 r = do_read(input_fd, data, size);
58 if (r != size) 77 if (r <= 0)
59 die("reading input file (size expected=%d received=%d)", 78 die("reading input file (size expected=%d received=%d)",
60 size, r); 79 size, r);
80
81 if (calc_data_size)
82 calc_data_size += r;
83
61 return r; 84 return r;
62} 85}
63 86
@@ -82,56 +105,28 @@ static char *read_string(void)
82 char buf[BUFSIZ]; 105 char buf[BUFSIZ];
83 char *str = NULL; 106 char *str = NULL;
84 int size = 0; 107 int size = 0;
85 int i;
86 off_t r; 108 off_t r;
109 char c;
87 110
88 for (;;) { 111 for (;;) {
89 r = read(input_fd, buf, BUFSIZ); 112 r = read(input_fd, &c, 1);
90 if (r < 0) 113 if (r < 0)
91 die("reading input file"); 114 die("reading input file");
92 115
93 if (!r) 116 if (!r)
94 die("no data"); 117 die("no data");
95 118
96 for (i = 0; i < r; i++) { 119 buf[size++] = c;
97 if (!buf[i])
98 break;
99 }
100 if (i < r)
101 break;
102 120
103 if (str) { 121 if (!c)
104 size += BUFSIZ; 122 break;
105 str = realloc(str, size);
106 if (!str)
107 die("malloc of size %d", size);
108 memcpy(str + (size - BUFSIZ), buf, BUFSIZ);
109 } else {
110 size = BUFSIZ;
111 str = malloc_or_die(size);
112 memcpy(str, buf, size);
113 }
114 } 123 }
115 124
116 /* trailing \0: */ 125 if (calc_data_size)
117 i++; 126 calc_data_size += size;
118 127
119 /* move the file descriptor to the end of the string */ 128 str = malloc_or_die(size);
120 r = lseek(input_fd, -(r - i), SEEK_CUR); 129 memcpy(str, buf, size);
121 if (r == (off_t)-1)
122 die("lseek");
123
124 if (str) {
125 size += i;
126 str = realloc(str, size);
127 if (!str)
128 die("malloc of size %d", size);
129 memcpy(str + (size - i), buf, i);
130 } else {
131 size = i;
132 str = malloc_or_die(i);
133 memcpy(str, buf, i);
134 }
135 130
136 return str; 131 return str;
137} 132}
@@ -459,7 +454,7 @@ struct record *trace_read_data(int cpu)
459 return data; 454 return data;
460} 455}
461 456
462void trace_report(int fd) 457ssize_t trace_report(int fd)
463{ 458{
464 char buf[BUFSIZ]; 459 char buf[BUFSIZ];
465 char test[] = { 23, 8, 68 }; 460 char test[] = { 23, 8, 68 };
@@ -467,6 +462,9 @@ void trace_report(int fd)
467 int show_version = 0; 462 int show_version = 0;
468 int show_funcs = 0; 463 int show_funcs = 0;
469 int show_printk = 0; 464 int show_printk = 0;
465 ssize_t size;
466
467 calc_data_size = 1;
470 468
471 input_fd = fd; 469 input_fd = fd;
472 470
@@ -499,14 +497,17 @@ void trace_report(int fd)
499 read_proc_kallsyms(); 497 read_proc_kallsyms();
500 read_ftrace_printk(); 498 read_ftrace_printk();
501 499
500 size = calc_data_size - 1;
501 calc_data_size = 0;
502
502 if (show_funcs) { 503 if (show_funcs) {
503 print_funcs(); 504 print_funcs();
504 return; 505 return size;
505 } 506 }
506 if (show_printk) { 507 if (show_printk) {
507 print_printk(); 508 print_printk();
508 return; 509 return size;
509 } 510 }
510 511
511 return; 512 return size;
512} 513}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 81f2fd20a0ea..1f45d468fd9a 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -163,7 +163,7 @@ struct record *trace_read_data(int cpu);
163 163
164void parse_set_info(int nr_cpus, int long_sz); 164void parse_set_info(int nr_cpus, int long_sz);
165 165
166void trace_report(int fd); 166ssize_t trace_report(int fd);
167 167
168void *malloc_or_die(unsigned int size); 168void *malloc_or_die(unsigned int size);
169 169
@@ -259,6 +259,8 @@ void *raw_field_ptr(struct event *event, const char *name, void *data);
259unsigned long long eval_flag(const char *flag); 259unsigned long long eval_flag(const char *flag);
260 260
261int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events); 261int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
262ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs,
263 int nb_events);
262 264
263/* taken from kernel/trace/trace.h */ 265/* taken from kernel/trace/trace.h */
264enum trace_flag_type { 266enum trace_flag_type {