diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-03-10 09:15:54 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-03-10 09:15:54 -0500 |
commit | a91e5431d54f5359fccb5ec2512f252eb217707e (patch) | |
tree | 8f8ba4940d9f4e910b339baee13a710baa920378 /tools/perf/util/header.c | |
parent | 6547250381eb315acff3d52b4872ad775359407c (diff) |
perf session: Use evlist/evsel for managing perf.data attributes
So that we can reuse things like the id to attr lookup routine
(perf_evlist__id2evsel) that uses a hash table instead of the linear
lookup done in the older perf_header_attr routines, etc.
Also to make evsels/evlist more pervasive an API, simplyfing using the
emerging perf lib.
cc: Arun Sharma <arun@sharma-home.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 225 |
1 files changed, 84 insertions, 141 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 108b0db7bbef..40b10e4d3927 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
10 | 10 | ||
11 | #include "evlist.h" | 11 | #include "evlist.h" |
12 | #include "evsel.h" | ||
12 | #include "util.h" | 13 | #include "util.h" |
13 | #include "header.h" | 14 | #include "header.h" |
14 | #include "../perf.h" | 15 | #include "../perf.h" |
@@ -19,89 +20,6 @@ | |||
19 | 20 | ||
20 | static bool no_buildid_cache = false; | 21 | static bool no_buildid_cache = false; |
21 | 22 | ||
22 | /* | ||
23 | * Create new perf.data header attribute: | ||
24 | */ | ||
25 | struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr) | ||
26 | { | ||
27 | struct perf_header_attr *self = malloc(sizeof(*self)); | ||
28 | |||
29 | if (self != NULL) { | ||
30 | self->attr = *attr; | ||
31 | self->ids = 0; | ||
32 | self->size = 1; | ||
33 | self->id = malloc(sizeof(u64)); | ||
34 | if (self->id == NULL) { | ||
35 | free(self); | ||
36 | self = NULL; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | return self; | ||
41 | } | ||
42 | |||
43 | void perf_header_attr__delete(struct perf_header_attr *self) | ||
44 | { | ||
45 | free(self->id); | ||
46 | free(self); | ||
47 | } | ||
48 | |||
49 | int perf_header_attr__add_id(struct perf_header_attr *self, u64 id) | ||
50 | { | ||
51 | int pos = self->ids; | ||
52 | |||
53 | self->ids++; | ||
54 | if (self->ids > self->size) { | ||
55 | int nsize = self->size * 2; | ||
56 | u64 *nid = realloc(self->id, nsize * sizeof(u64)); | ||
57 | |||
58 | if (nid == NULL) | ||
59 | return -1; | ||
60 | |||
61 | self->size = nsize; | ||
62 | self->id = nid; | ||
63 | } | ||
64 | self->id[pos] = id; | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | int perf_header__init(struct perf_header *self) | ||
69 | { | ||
70 | self->size = 1; | ||
71 | self->attr = malloc(sizeof(void *)); | ||
72 | return self->attr == NULL ? -ENOMEM : 0; | ||
73 | } | ||
74 | |||
75 | void perf_header__exit(struct perf_header *self) | ||
76 | { | ||
77 | int i; | ||
78 | for (i = 0; i < self->attrs; ++i) | ||
79 | perf_header_attr__delete(self->attr[i]); | ||
80 | free(self->attr); | ||
81 | } | ||
82 | |||
83 | int perf_header__add_attr(struct perf_header *self, | ||
84 | struct perf_header_attr *attr) | ||
85 | { | ||
86 | if (self->frozen) | ||
87 | return -1; | ||
88 | |||
89 | if (self->attrs == self->size) { | ||
90 | int nsize = self->size * 2; | ||
91 | struct perf_header_attr **nattr; | ||
92 | |||
93 | nattr = realloc(self->attr, nsize * sizeof(void *)); | ||
94 | if (nattr == NULL) | ||
95 | return -1; | ||
96 | |||
97 | self->size = nsize; | ||
98 | self->attr = nattr; | ||
99 | } | ||
100 | |||
101 | self->attr[self->attrs++] = attr; | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int event_count; | 23 | static int event_count; |
106 | static struct perf_trace_event_type *events; | 24 | static struct perf_trace_event_type *events; |
107 | 25 | ||
@@ -515,33 +433,41 @@ int perf_header__write_pipe(int fd) | |||
515 | return 0; | 433 | return 0; |
516 | } | 434 | } |
517 | 435 | ||
518 | int perf_header__write(struct perf_header *self, struct perf_evlist *evlist, | 436 | int perf_session__write_header(struct perf_session *session, |
519 | int fd, bool at_exit) | 437 | struct perf_evlist *evlist, |
438 | int fd, bool at_exit) | ||
520 | { | 439 | { |
521 | struct perf_file_header f_header; | 440 | struct perf_file_header f_header; |
522 | struct perf_file_attr f_attr; | 441 | struct perf_file_attr f_attr; |
523 | struct perf_header_attr *attr; | 442 | struct perf_header *self = &session->header; |
524 | int i, err; | 443 | struct perf_evsel *attr, *pair = NULL; |
444 | int err; | ||
525 | 445 | ||
526 | lseek(fd, sizeof(f_header), SEEK_SET); | 446 | lseek(fd, sizeof(f_header), SEEK_SET); |
527 | 447 | ||
528 | for (i = 0; i < self->attrs; i++) { | 448 | if (session->evlist != evlist) |
529 | attr = self->attr[i]; | 449 | pair = list_entry(session->evlist->entries.next, struct perf_evsel, node); |
530 | 450 | ||
451 | list_for_each_entry(attr, &evlist->entries, node) { | ||
531 | attr->id_offset = lseek(fd, 0, SEEK_CUR); | 452 | attr->id_offset = lseek(fd, 0, SEEK_CUR); |
532 | err = do_write(fd, attr->id, attr->ids * sizeof(u64)); | 453 | err = do_write(fd, attr->id, attr->ids * sizeof(u64)); |
533 | if (err < 0) { | 454 | if (err < 0) { |
455 | out_err_write: | ||
534 | pr_debug("failed to write perf header\n"); | 456 | pr_debug("failed to write perf header\n"); |
535 | return err; | 457 | return err; |
536 | } | 458 | } |
459 | if (session->evlist != evlist) { | ||
460 | err = do_write(fd, pair->id, pair->ids * sizeof(u64)); | ||
461 | if (err < 0) | ||
462 | goto out_err_write; | ||
463 | attr->ids += pair->ids; | ||
464 | pair = list_entry(pair->node.next, struct perf_evsel, node); | ||
465 | } | ||
537 | } | 466 | } |
538 | 467 | ||
539 | |||
540 | self->attr_offset = lseek(fd, 0, SEEK_CUR); | 468 | self->attr_offset = lseek(fd, 0, SEEK_CUR); |
541 | 469 | ||
542 | for (i = 0; i < self->attrs; i++) { | 470 | list_for_each_entry(attr, &evlist->entries, node) { |
543 | attr = self->attr[i]; | ||
544 | |||
545 | f_attr = (struct perf_file_attr){ | 471 | f_attr = (struct perf_file_attr){ |
546 | .attr = attr->attr, | 472 | .attr = attr->attr, |
547 | .ids = { | 473 | .ids = { |
@@ -580,7 +506,7 @@ int perf_header__write(struct perf_header *self, struct perf_evlist *evlist, | |||
580 | .attr_size = sizeof(f_attr), | 506 | .attr_size = sizeof(f_attr), |
581 | .attrs = { | 507 | .attrs = { |
582 | .offset = self->attr_offset, | 508 | .offset = self->attr_offset, |
583 | .size = self->attrs * sizeof(f_attr), | 509 | .size = evlist->nr_entries * sizeof(f_attr), |
584 | }, | 510 | }, |
585 | .data = { | 511 | .data = { |
586 | .offset = self->data_offset, | 512 | .offset = self->data_offset, |
@@ -861,7 +787,7 @@ static int perf_header__read_pipe(struct perf_session *session, int fd) | |||
861 | return 0; | 787 | return 0; |
862 | } | 788 | } |
863 | 789 | ||
864 | int perf_header__read(struct perf_session *session, int fd) | 790 | int perf_session__read_header(struct perf_session *session, int fd) |
865 | { | 791 | { |
866 | struct perf_header *self = &session->header; | 792 | struct perf_header *self = &session->header; |
867 | struct perf_file_header f_header; | 793 | struct perf_file_header f_header; |
@@ -869,6 +795,10 @@ int perf_header__read(struct perf_session *session, int fd) | |||
869 | u64 f_id; | 795 | u64 f_id; |
870 | int nr_attrs, nr_ids, i, j; | 796 | int nr_attrs, nr_ids, i, j; |
871 | 797 | ||
798 | session->evlist = perf_evlist__new(NULL, NULL); | ||
799 | if (session->evlist == NULL) | ||
800 | return -ENOMEM; | ||
801 | |||
872 | if (session->fd_pipe) | 802 | if (session->fd_pipe) |
873 | return perf_header__read_pipe(session, fd); | 803 | return perf_header__read_pipe(session, fd); |
874 | 804 | ||
@@ -881,33 +811,39 @@ int perf_header__read(struct perf_session *session, int fd) | |||
881 | lseek(fd, f_header.attrs.offset, SEEK_SET); | 811 | lseek(fd, f_header.attrs.offset, SEEK_SET); |
882 | 812 | ||
883 | for (i = 0; i < nr_attrs; i++) { | 813 | for (i = 0; i < nr_attrs; i++) { |
884 | struct perf_header_attr *attr; | 814 | struct perf_evsel *evsel; |
885 | off_t tmp; | 815 | off_t tmp; |
886 | 816 | ||
887 | if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr))) | 817 | if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr))) |
888 | goto out_errno; | 818 | goto out_errno; |
889 | 819 | ||
890 | tmp = lseek(fd, 0, SEEK_CUR); | 820 | tmp = lseek(fd, 0, SEEK_CUR); |
821 | evsel = perf_evsel__new(&f_attr.attr, i); | ||
891 | 822 | ||
892 | attr = perf_header_attr__new(&f_attr.attr); | 823 | if (evsel == NULL) |
893 | if (attr == NULL) | 824 | goto out_delete_evlist; |
894 | return -ENOMEM; | 825 | /* |
826 | * Do it before so that if perf_evsel__alloc_id fails, this | ||
827 | * entry gets purged too at perf_evlist__delete(). | ||
828 | */ | ||
829 | perf_evlist__add(session->evlist, evsel); | ||
895 | 830 | ||
896 | nr_ids = f_attr.ids.size / sizeof(u64); | 831 | nr_ids = f_attr.ids.size / sizeof(u64); |
832 | /* | ||
833 | * We don't have the cpu and thread maps on the header, so | ||
834 | * for allocating the perf_sample_id table we fake 1 cpu and | ||
835 | * hattr->ids threads. | ||
836 | */ | ||
837 | if (perf_evsel__alloc_id(evsel, 1, nr_ids)) | ||
838 | goto out_delete_evlist; | ||
839 | |||
897 | lseek(fd, f_attr.ids.offset, SEEK_SET); | 840 | lseek(fd, f_attr.ids.offset, SEEK_SET); |
898 | 841 | ||
899 | for (j = 0; j < nr_ids; j++) { | 842 | for (j = 0; j < nr_ids; j++) { |
900 | if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id))) | 843 | if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id))) |
901 | goto out_errno; | 844 | goto out_errno; |
902 | 845 | ||
903 | if (perf_header_attr__add_id(attr, f_id) < 0) { | 846 | perf_evlist__id_add(session->evlist, evsel, 0, j, f_id); |
904 | perf_header_attr__delete(attr); | ||
905 | return -ENOMEM; | ||
906 | } | ||
907 | } | ||
908 | if (perf_header__add_attr(self, attr) < 0) { | ||
909 | perf_header_attr__delete(attr); | ||
910 | return -ENOMEM; | ||
911 | } | 847 | } |
912 | 848 | ||
913 | lseek(fd, tmp, SEEK_SET); | 849 | lseek(fd, tmp, SEEK_SET); |
@@ -932,37 +868,38 @@ int perf_header__read(struct perf_session *session, int fd) | |||
932 | return 0; | 868 | return 0; |
933 | out_errno: | 869 | out_errno: |
934 | return -errno; | 870 | return -errno; |
871 | |||
872 | out_delete_evlist: | ||
873 | perf_evlist__delete(session->evlist); | ||
874 | session->evlist = NULL; | ||
875 | return -ENOMEM; | ||
935 | } | 876 | } |
936 | 877 | ||
937 | u64 perf_header__sample_type(struct perf_header *header) | 878 | u64 perf_evlist__sample_type(struct perf_evlist *evlist) |
938 | { | 879 | { |
880 | struct perf_evsel *pos; | ||
939 | u64 type = 0; | 881 | u64 type = 0; |
940 | int i; | ||
941 | |||
942 | for (i = 0; i < header->attrs; i++) { | ||
943 | struct perf_header_attr *attr = header->attr[i]; | ||
944 | 882 | ||
883 | list_for_each_entry(pos, &evlist->entries, node) { | ||
945 | if (!type) | 884 | if (!type) |
946 | type = attr->attr.sample_type; | 885 | type = pos->attr.sample_type; |
947 | else if (type != attr->attr.sample_type) | 886 | else if (type != pos->attr.sample_type) |
948 | die("non matching sample_type"); | 887 | die("non matching sample_type"); |
949 | } | 888 | } |
950 | 889 | ||
951 | return type; | 890 | return type; |
952 | } | 891 | } |
953 | 892 | ||
954 | bool perf_header__sample_id_all(const struct perf_header *header) | 893 | bool perf_evlist__sample_id_all(const struct perf_evlist *evlist) |
955 | { | 894 | { |
956 | bool value = false, first = true; | 895 | bool value = false, first = true; |
957 | int i; | 896 | struct perf_evsel *pos; |
958 | |||
959 | for (i = 0; i < header->attrs; i++) { | ||
960 | struct perf_header_attr *attr = header->attr[i]; | ||
961 | 897 | ||
898 | list_for_each_entry(pos, &evlist->entries, node) { | ||
962 | if (first) { | 899 | if (first) { |
963 | value = attr->attr.sample_id_all; | 900 | value = pos->attr.sample_id_all; |
964 | first = false; | 901 | first = false; |
965 | } else if (value != attr->attr.sample_id_all) | 902 | } else if (value != pos->attr.sample_id_all) |
966 | die("non matching sample_id_all"); | 903 | die("non matching sample_id_all"); |
967 | } | 904 | } |
968 | 905 | ||
@@ -1000,16 +937,13 @@ int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | |||
1000 | return err; | 937 | return err; |
1001 | } | 938 | } |
1002 | 939 | ||
1003 | int perf_event__synthesize_attrs(struct perf_header *self, | 940 | int perf_session__synthesize_attrs(struct perf_session *session, |
1004 | perf_event__handler_t process, | 941 | perf_event__handler_t process) |
1005 | struct perf_session *session) | ||
1006 | { | 942 | { |
1007 | struct perf_header_attr *attr; | 943 | struct perf_evsel *attr; |
1008 | int i, err = 0; | 944 | int err = 0; |
1009 | |||
1010 | for (i = 0; i < self->attrs; i++) { | ||
1011 | attr = self->attr[i]; | ||
1012 | 945 | ||
946 | list_for_each_entry(attr, &session->evlist->entries, node) { | ||
1013 | err = perf_event__synthesize_attr(&attr->attr, attr->ids, | 947 | err = perf_event__synthesize_attr(&attr->attr, attr->ids, |
1014 | attr->id, process, session); | 948 | attr->id, process, session); |
1015 | if (err) { | 949 | if (err) { |
@@ -1024,27 +958,36 @@ int perf_event__synthesize_attrs(struct perf_header *self, | |||
1024 | int perf_event__process_attr(union perf_event *event, | 958 | int perf_event__process_attr(union perf_event *event, |
1025 | struct perf_session *session) | 959 | struct perf_session *session) |
1026 | { | 960 | { |
1027 | struct perf_header_attr *attr; | ||
1028 | unsigned int i, ids, n_ids; | 961 | unsigned int i, ids, n_ids; |
962 | struct perf_evsel *evsel; | ||
1029 | 963 | ||
1030 | attr = perf_header_attr__new(&event->attr.attr); | 964 | if (session->evlist == NULL) { |
1031 | if (attr == NULL) | 965 | session->evlist = perf_evlist__new(NULL, NULL); |
966 | if (session->evlist == NULL) | ||
967 | return -ENOMEM; | ||
968 | } | ||
969 | |||
970 | evsel = perf_evsel__new(&event->attr.attr, | ||
971 | session->evlist->nr_entries); | ||
972 | if (evsel == NULL) | ||
1032 | return -ENOMEM; | 973 | return -ENOMEM; |
1033 | 974 | ||
975 | perf_evlist__add(session->evlist, evsel); | ||
976 | |||
1034 | ids = event->header.size; | 977 | ids = event->header.size; |
1035 | ids -= (void *)&event->attr.id - (void *)event; | 978 | ids -= (void *)&event->attr.id - (void *)event; |
1036 | n_ids = ids / sizeof(u64); | 979 | n_ids = ids / sizeof(u64); |
980 | /* | ||
981 | * We don't have the cpu and thread maps on the header, so | ||
982 | * for allocating the perf_sample_id table we fake 1 cpu and | ||
983 | * hattr->ids threads. | ||
984 | */ | ||
985 | if (perf_evsel__alloc_id(evsel, 1, n_ids)) | ||
986 | return -ENOMEM; | ||
1037 | 987 | ||
1038 | for (i = 0; i < n_ids; i++) { | 988 | for (i = 0; i < n_ids; i++) { |
1039 | if (perf_header_attr__add_id(attr, event->attr.id[i]) < 0) { | 989 | perf_evlist__id_add(session->evlist, evsel, 0, i, |
1040 | perf_header_attr__delete(attr); | 990 | event->attr.id[i]); |
1041 | return -ENOMEM; | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | if (perf_header__add_attr(&session->header, attr) < 0) { | ||
1046 | perf_header_attr__delete(attr); | ||
1047 | return -ENOMEM; | ||
1048 | } | 991 | } |
1049 | 992 | ||
1050 | perf_session__update_sample_type(session); | 993 | perf_session__update_sample_type(session); |