diff options
author | Ingo Molnar <mingo@elte.hu> | 2010-04-15 03:13:26 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-04-15 03:13:26 -0400 |
commit | 84b13fd596522db47f9545d5124c30cc00dfdf5a (patch) | |
tree | c1f51b8fe43a59fb56ea43a18da88c0d0812dd7d /tools/perf/util/header.c | |
parent | f92128193094c288bc315db1694fafeaeb7ee1d0 (diff) | |
parent | a0cccc2e8e9fb16cbed3a117b30e3fbac3092ee3 (diff) |
Merge branch 'perf/live' into perf/core
Conflicts:
tools/perf/builtin-record.c
Merge reason: add the live tracing feature, resolve conflict.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 361 |
1 files changed, 336 insertions, 25 deletions
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 | |||
104 | struct perf_trace_event_type { | ||
105 | u64 event_id; | ||
106 | char name[MAX_EVENT_NAME]; | ||
107 | }; | ||
108 | |||
109 | static int event_count; | 102 | static int event_count; |
110 | static struct perf_trace_event_type *events; | 103 | static struct perf_trace_event_type *events; |
111 | 104 | ||
@@ -427,6 +420,25 @@ out_free: | |||
427 | return err; | 420 | return err; |
428 | } | 421 | } |
429 | 422 | ||
423 | int 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 | |||
430 | int perf_header__write(struct perf_header *self, int fd, bool at_exit) | 442 | int 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 | ||
521 | static 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 | |||
536 | static int perf_header__getbuffer64(struct perf_header *self, | 533 | static 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 | ||
665 | int perf_header__read(struct perf_header *self, int fd) | 662 | static 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 | |||
681 | static 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 | |||
696 | int 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 | |||
804 | int 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 | |||
832 | int 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 | |||
853 | int 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 | |||
883 | int 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 | |||
908 | int 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 | |||
928 | int 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 | |||
938 | int 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 | |||
966 | int 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 | |||
990 | int 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 | |||
1016 | static 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 | |||
1035 | int 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 | |||
1061 | int 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 | } | ||