diff options
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c new file mode 100644 index 000000000000..450384b3bbe5 --- /dev/null +++ b/tools/perf/util/header.c | |||
@@ -0,0 +1,242 @@ | |||
1 | #include <sys/types.h> | ||
2 | #include <unistd.h> | ||
3 | #include <stdio.h> | ||
4 | #include <stdlib.h> | ||
5 | |||
6 | #include "util.h" | ||
7 | #include "header.h" | ||
8 | |||
9 | /* | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | struct perf_header_attr *perf_header_attr__new(struct perf_counter_attr *attr) | ||
14 | { | ||
15 | struct perf_header_attr *self = malloc(sizeof(*self)); | ||
16 | |||
17 | if (!self) | ||
18 | die("nomem"); | ||
19 | |||
20 | self->attr = *attr; | ||
21 | self->ids = 0; | ||
22 | self->size = 1; | ||
23 | self->id = malloc(sizeof(u64)); | ||
24 | |||
25 | if (!self->id) | ||
26 | die("nomem"); | ||
27 | |||
28 | return self; | ||
29 | } | ||
30 | |||
31 | void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) | ||
32 | { | ||
33 | int pos = self->ids; | ||
34 | |||
35 | self->ids++; | ||
36 | if (self->ids > self->size) { | ||
37 | self->size *= 2; | ||
38 | self->id = realloc(self->id, self->size * sizeof(u64)); | ||
39 | if (!self->id) | ||
40 | die("nomem"); | ||
41 | } | ||
42 | self->id[pos] = id; | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * | ||
47 | */ | ||
48 | |||
49 | struct perf_header *perf_header__new(void) | ||
50 | { | ||
51 | struct perf_header *self = malloc(sizeof(*self)); | ||
52 | |||
53 | if (!self) | ||
54 | die("nomem"); | ||
55 | |||
56 | self->frozen = 0; | ||
57 | |||
58 | self->attrs = 0; | ||
59 | self->size = 1; | ||
60 | self->attr = malloc(sizeof(void *)); | ||
61 | |||
62 | if (!self->attr) | ||
63 | die("nomem"); | ||
64 | |||
65 | self->data_offset = 0; | ||
66 | self->data_size = 0; | ||
67 | |||
68 | return self; | ||
69 | } | ||
70 | |||
71 | void perf_header__add_attr(struct perf_header *self, | ||
72 | struct perf_header_attr *attr) | ||
73 | { | ||
74 | int pos = self->attrs; | ||
75 | |||
76 | if (self->frozen) | ||
77 | die("frozen"); | ||
78 | |||
79 | self->attrs++; | ||
80 | if (self->attrs > self->size) { | ||
81 | self->size *= 2; | ||
82 | self->attr = realloc(self->attr, self->size * sizeof(void *)); | ||
83 | if (!self->attr) | ||
84 | die("nomem"); | ||
85 | } | ||
86 | self->attr[pos] = attr; | ||
87 | } | ||
88 | |||
89 | static const char *__perf_magic = "PERFFILE"; | ||
90 | |||
91 | #define PERF_MAGIC (*(u64 *)__perf_magic) | ||
92 | |||
93 | struct perf_file_section { | ||
94 | u64 offset; | ||
95 | u64 size; | ||
96 | }; | ||
97 | |||
98 | struct perf_file_attr { | ||
99 | struct perf_counter_attr attr; | ||
100 | struct perf_file_section ids; | ||
101 | }; | ||
102 | |||
103 | struct perf_file_header { | ||
104 | u64 magic; | ||
105 | u64 size; | ||
106 | u64 attr_size; | ||
107 | struct perf_file_section attrs; | ||
108 | struct perf_file_section data; | ||
109 | }; | ||
110 | |||
111 | static void do_write(int fd, void *buf, size_t size) | ||
112 | { | ||
113 | while (size) { | ||
114 | int ret = write(fd, buf, size); | ||
115 | |||
116 | if (ret < 0) | ||
117 | die("failed to write"); | ||
118 | |||
119 | size -= ret; | ||
120 | buf += ret; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | void perf_header__write(struct perf_header *self, int fd) | ||
125 | { | ||
126 | struct perf_file_header f_header; | ||
127 | struct perf_file_attr f_attr; | ||
128 | struct perf_header_attr *attr; | ||
129 | int i; | ||
130 | |||
131 | lseek(fd, sizeof(f_header), SEEK_SET); | ||
132 | |||
133 | |||
134 | for (i = 0; i < self->attrs; i++) { | ||
135 | attr = self->attr[i]; | ||
136 | |||
137 | attr->id_offset = lseek(fd, 0, SEEK_CUR); | ||
138 | do_write(fd, attr->id, attr->ids * sizeof(u64)); | ||
139 | } | ||
140 | |||
141 | |||
142 | self->attr_offset = lseek(fd, 0, SEEK_CUR); | ||
143 | |||
144 | for (i = 0; i < self->attrs; i++) { | ||
145 | attr = self->attr[i]; | ||
146 | |||
147 | f_attr = (struct perf_file_attr){ | ||
148 | .attr = attr->attr, | ||
149 | .ids = { | ||
150 | .offset = attr->id_offset, | ||
151 | .size = attr->ids * sizeof(u64), | ||
152 | } | ||
153 | }; | ||
154 | do_write(fd, &f_attr, sizeof(f_attr)); | ||
155 | } | ||
156 | |||
157 | |||
158 | self->data_offset = lseek(fd, 0, SEEK_CUR); | ||
159 | |||
160 | f_header = (struct perf_file_header){ | ||
161 | .magic = PERF_MAGIC, | ||
162 | .size = sizeof(f_header), | ||
163 | .attr_size = sizeof(f_attr), | ||
164 | .attrs = { | ||
165 | .offset = self->attr_offset, | ||
166 | .size = self->attrs * sizeof(f_attr), | ||
167 | }, | ||
168 | .data = { | ||
169 | .offset = self->data_offset, | ||
170 | .size = self->data_size, | ||
171 | }, | ||
172 | }; | ||
173 | |||
174 | lseek(fd, 0, SEEK_SET); | ||
175 | do_write(fd, &f_header, sizeof(f_header)); | ||
176 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | ||
177 | |||
178 | self->frozen = 1; | ||
179 | } | ||
180 | |||
181 | static void do_read(int fd, void *buf, size_t size) | ||
182 | { | ||
183 | while (size) { | ||
184 | int ret = read(fd, buf, size); | ||
185 | |||
186 | if (ret < 0) | ||
187 | die("failed to read"); | ||
188 | |||
189 | size -= ret; | ||
190 | buf += ret; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | struct perf_header *perf_header__read(int fd) | ||
195 | { | ||
196 | struct perf_header *self = perf_header__new(); | ||
197 | struct perf_file_header f_header; | ||
198 | struct perf_file_attr f_attr; | ||
199 | u64 f_id; | ||
200 | |||
201 | int nr_attrs, nr_ids, i, j; | ||
202 | |||
203 | lseek(fd, 0, SEEK_SET); | ||
204 | do_read(fd, &f_header, sizeof(f_header)); | ||
205 | |||
206 | if (f_header.magic != PERF_MAGIC || | ||
207 | f_header.size != sizeof(f_header) || | ||
208 | f_header.attr_size != sizeof(f_attr)) | ||
209 | die("incompatible file format"); | ||
210 | |||
211 | nr_attrs = f_header.attrs.size / sizeof(f_attr); | ||
212 | lseek(fd, f_header.attrs.offset, SEEK_SET); | ||
213 | |||
214 | for (i = 0; i < nr_attrs; i++) { | ||
215 | struct perf_header_attr *attr; | ||
216 | off_t tmp = lseek(fd, 0, SEEK_CUR); | ||
217 | |||
218 | do_read(fd, &f_attr, sizeof(f_attr)); | ||
219 | |||
220 | attr = perf_header_attr__new(&f_attr.attr); | ||
221 | |||
222 | nr_ids = f_attr.ids.size / sizeof(u64); | ||
223 | lseek(fd, f_attr.ids.offset, SEEK_SET); | ||
224 | |||
225 | for (j = 0; j < nr_ids; j++) { | ||
226 | do_read(fd, &f_id, sizeof(f_id)); | ||
227 | |||
228 | perf_header_attr__add_id(attr, f_id); | ||
229 | } | ||
230 | perf_header__add_attr(self, attr); | ||
231 | lseek(fd, tmp, SEEK_SET); | ||
232 | } | ||
233 | |||
234 | self->data_offset = f_header.data.offset; | ||
235 | self->data_size = f_header.data.size; | ||
236 | |||
237 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | ||
238 | |||
239 | self->frozen = 1; | ||
240 | |||
241 | return self; | ||
242 | } | ||