diff options
-rw-r--r-- | tools/perf/builtin-record.c | 4 | ||||
-rw-r--r-- | tools/perf/util/header.c | 100 | ||||
-rw-r--r-- | tools/perf/util/header.h | 30 |
3 files changed, 78 insertions, 56 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index fc3709cba136..f0467ff0d8ad 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -574,11 +574,11 @@ static int __cmd_record(int argc, const char **argv) | |||
574 | header = perf_header__new(); | 574 | header = perf_header__new(); |
575 | 575 | ||
576 | if (raw_samples) { | 576 | if (raw_samples) { |
577 | perf_header__set_trace_info(); | 577 | perf_header__feat_trace_info(header); |
578 | } else { | 578 | } else { |
579 | for (i = 0; i < nr_counters; i++) { | 579 | for (i = 0; i < nr_counters; i++) { |
580 | if (attrs[i].sample_type & PERF_SAMPLE_RAW) { | 580 | if (attrs[i].sample_type & PERF_SAMPLE_RAW) { |
581 | perf_header__set_trace_info(); | 581 | perf_header__feat_trace_info(header); |
582 | break; | 582 | break; |
583 | } | 583 | } |
584 | } | 584 | } |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 9aae360c0f28..171d51b6f359 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -8,6 +8,8 @@ | |||
8 | #include "../perf.h" | 8 | #include "../perf.h" |
9 | #include "trace-event.h" | 9 | #include "trace-event.h" |
10 | 10 | ||
11 | #include <linux/bitmap.h> | ||
12 | |||
11 | /* | 13 | /* |
12 | * Create new perf.data header attribute: | 14 | * Create new perf.data header attribute: |
13 | */ | 15 | */ |
@@ -48,25 +50,17 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) | |||
48 | */ | 50 | */ |
49 | struct perf_header *perf_header__new(void) | 51 | struct perf_header *perf_header__new(void) |
50 | { | 52 | { |
51 | struct perf_header *self = malloc(sizeof(*self)); | 53 | struct perf_header *self = calloc(sizeof(*self), 1); |
52 | 54 | ||
53 | if (!self) | 55 | if (!self) |
54 | die("nomem"); | 56 | die("nomem"); |
55 | 57 | ||
56 | self->frozen = 0; | ||
57 | |||
58 | self->attrs = 0; | ||
59 | self->size = 1; | 58 | self->size = 1; |
60 | self->attr = malloc(sizeof(void *)); | 59 | self->attr = malloc(sizeof(void *)); |
61 | 60 | ||
62 | if (!self->attr) | 61 | if (!self->attr) |
63 | die("nomem"); | 62 | die("nomem"); |
64 | 63 | ||
65 | self->data_offset = 0; | ||
66 | self->data_size = 0; | ||
67 | self->trace_info_offset = 0; | ||
68 | self->trace_info_size = 0; | ||
69 | |||
70 | return self; | 64 | return self; |
71 | } | 65 | } |
72 | 66 | ||
@@ -149,14 +143,12 @@ struct perf_file_header { | |||
149 | struct perf_file_section attrs; | 143 | struct perf_file_section attrs; |
150 | struct perf_file_section data; | 144 | struct perf_file_section data; |
151 | struct perf_file_section event_types; | 145 | struct perf_file_section event_types; |
152 | struct perf_file_section trace_info; | 146 | feat_mask_t adds_features; |
153 | }; | 147 | }; |
154 | 148 | ||
155 | static int trace_info; | 149 | void perf_header__feat_trace_info(struct perf_header *header) |
156 | |||
157 | void perf_header__set_trace_info(void) | ||
158 | { | 150 | { |
159 | trace_info = 1; | 151 | set_bit(HEADER_TRACE_INFO, perf_header__adds_mask(header)); |
160 | } | 152 | } |
161 | 153 | ||
162 | static void do_write(int fd, void *buf, size_t size) | 154 | static void do_write(int fd, void *buf, size_t size) |
@@ -172,6 +164,32 @@ static void do_write(int fd, void *buf, size_t size) | |||
172 | } | 164 | } |
173 | } | 165 | } |
174 | 166 | ||
167 | static void perf_header__adds_write(struct perf_header *self, int fd) | ||
168 | { | ||
169 | struct perf_file_section trace_sec; | ||
170 | u64 cur_offset = lseek(fd, 0, SEEK_CUR); | ||
171 | unsigned long *feat_mask = perf_header__adds_mask(self); | ||
172 | |||
173 | if (test_bit(HEADER_TRACE_INFO, feat_mask)) { | ||
174 | /* Write trace info */ | ||
175 | trace_sec.offset = lseek(fd, sizeof(trace_sec), SEEK_CUR); | ||
176 | read_tracing_data(fd, attrs, nr_counters); | ||
177 | trace_sec.size = lseek(fd, 0, SEEK_CUR) - trace_sec.offset; | ||
178 | |||
179 | /* Write trace info headers */ | ||
180 | lseek(fd, cur_offset, SEEK_SET); | ||
181 | do_write(fd, &trace_sec, sizeof(trace_sec)); | ||
182 | |||
183 | /* | ||
184 | * Update cur_offset. So that other (future) | ||
185 | * features can set their own infos in this place. But if we are | ||
186 | * the only feature, at least that seeks to the place the data | ||
187 | * should begin. | ||
188 | */ | ||
189 | cur_offset = lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); | ||
190 | } | ||
191 | }; | ||
192 | |||
175 | void perf_header__write(struct perf_header *self, int fd) | 193 | void perf_header__write(struct perf_header *self, int fd) |
176 | { | 194 | { |
177 | struct perf_file_header f_header; | 195 | struct perf_file_header f_header; |
@@ -210,23 +228,7 @@ void perf_header__write(struct perf_header *self, int fd) | |||
210 | if (events) | 228 | if (events) |
211 | do_write(fd, events, self->event_size); | 229 | do_write(fd, events, self->event_size); |
212 | 230 | ||
213 | if (trace_info) { | 231 | perf_header__adds_write(self, fd); |
214 | static int trace_info_written; | ||
215 | |||
216 | /* | ||
217 | * Write it only once | ||
218 | */ | ||
219 | if (!trace_info_written) { | ||
220 | self->trace_info_offset = lseek(fd, 0, SEEK_CUR); | ||
221 | read_tracing_data(fd, attrs, nr_counters); | ||
222 | self->trace_info_size = lseek(fd, 0, SEEK_CUR) - | ||
223 | self->trace_info_offset; | ||
224 | trace_info_written = 1; | ||
225 | } else { | ||
226 | lseek(fd, self->trace_info_offset + | ||
227 | self->trace_info_size, SEEK_SET); | ||
228 | } | ||
229 | } | ||
230 | 232 | ||
231 | self->data_offset = lseek(fd, 0, SEEK_CUR); | 233 | self->data_offset = lseek(fd, 0, SEEK_CUR); |
232 | 234 | ||
@@ -246,12 +248,10 @@ void perf_header__write(struct perf_header *self, int fd) | |||
246 | .offset = self->event_offset, | 248 | .offset = self->event_offset, |
247 | .size = self->event_size, | 249 | .size = self->event_size, |
248 | }, | 250 | }, |
249 | .trace_info = { | ||
250 | .offset = self->trace_info_offset, | ||
251 | .size = self->trace_info_size, | ||
252 | }, | ||
253 | }; | 251 | }; |
254 | 252 | ||
253 | memcpy(&f_header.adds_features, &self->adds_features, sizeof(feat_mask_t)); | ||
254 | |||
255 | lseek(fd, 0, SEEK_SET); | 255 | lseek(fd, 0, SEEK_SET); |
256 | do_write(fd, &f_header, sizeof(f_header)); | 256 | do_write(fd, &f_header, sizeof(f_header)); |
257 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); | 257 | lseek(fd, self->data_offset + self->data_size, SEEK_SET); |
@@ -274,6 +274,20 @@ static void do_read(int fd, void *buf, size_t size) | |||
274 | } | 274 | } |
275 | } | 275 | } |
276 | 276 | ||
277 | static void perf_header__adds_read(struct perf_header *self, int fd) | ||
278 | { | ||
279 | const unsigned long *feat_mask = perf_header__adds_mask(self); | ||
280 | |||
281 | if (test_bit(HEADER_TRACE_INFO, feat_mask)) { | ||
282 | struct perf_file_section trace_sec; | ||
283 | |||
284 | do_read(fd, &trace_sec, sizeof(trace_sec)); | ||
285 | lseek(fd, trace_sec.offset, SEEK_SET); | ||
286 | trace_report(fd); | ||
287 | lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); | ||
288 | } | ||
289 | }; | ||
290 | |||
277 | struct perf_header *perf_header__read(int fd) | 291 | struct perf_header *perf_header__read(int fd) |
278 | { | 292 | { |
279 | struct perf_header *self = perf_header__new(); | 293 | struct perf_header *self = perf_header__new(); |
@@ -292,9 +306,11 @@ struct perf_header *perf_header__read(int fd) | |||
292 | 306 | ||
293 | if (f_header.size != sizeof(f_header)) { | 307 | if (f_header.size != sizeof(f_header)) { |
294 | /* Support the previous format */ | 308 | /* Support the previous format */ |
295 | if (f_header.size == offsetof(typeof(f_header), trace_info)) | 309 | if (f_header.size == offsetof(typeof(f_header), adds_features)) { |
296 | f_header.trace_info.size = 0; | 310 | unsigned long *mask = (unsigned long *)(void *) |
297 | else | 311 | &f_header.adds_features; |
312 | bitmap_zero(mask, HEADER_FEAT_BITS); | ||
313 | } else | ||
298 | die("incompatible file format"); | 314 | die("incompatible file format"); |
299 | } | 315 | } |
300 | nr_attrs = f_header.attrs.size / sizeof(f_attr); | 316 | nr_attrs = f_header.attrs.size / sizeof(f_attr); |
@@ -330,13 +346,9 @@ struct perf_header *perf_header__read(int fd) | |||
330 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); | 346 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); |
331 | } | 347 | } |
332 | 348 | ||
333 | self->trace_info_offset = f_header.trace_info.offset; | 349 | memcpy(&self->adds_features, &f_header.adds_features, sizeof(feat_mask_t)); |
334 | self->trace_info_size = f_header.trace_info.size; | ||
335 | 350 | ||
336 | if (self->trace_info_size) { | 351 | perf_header__adds_read(self, fd); |
337 | lseek(fd, self->trace_info_offset, SEEK_SET); | ||
338 | trace_report(fd); | ||
339 | } | ||
340 | 352 | ||
341 | self->event_offset = f_header.event_types.offset; | 353 | self->event_offset = f_header.event_types.offset; |
342 | self->event_size = f_header.event_types.size; | 354 | self->event_size = f_header.event_types.size; |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 30aee5160dc0..0eb4a9126b7c 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -12,19 +12,29 @@ struct perf_header_attr { | |||
12 | off_t id_offset; | 12 | off_t id_offset; |
13 | }; | 13 | }; |
14 | 14 | ||
15 | #define HEADER_TRACE_INFO 1 | ||
16 | |||
17 | #define HEADER_FEAT_BITS 256 | ||
18 | |||
19 | typedef typeof(u64[HEADER_FEAT_BITS / 8]) feat_mask_t; | ||
20 | |||
15 | struct perf_header { | 21 | struct perf_header { |
16 | int frozen; | 22 | int frozen; |
17 | int attrs, size; | 23 | int attrs, size; |
18 | struct perf_header_attr **attr; | 24 | struct perf_header_attr **attr; |
19 | s64 attr_offset; | 25 | s64 attr_offset; |
20 | u64 data_offset; | 26 | u64 data_offset; |
21 | u64 data_size; | 27 | u64 data_size; |
22 | u64 event_offset; | 28 | u64 event_offset; |
23 | u64 event_size; | 29 | u64 event_size; |
24 | u64 trace_info_offset; | 30 | feat_mask_t adds_features; |
25 | u64 trace_info_size; | ||
26 | }; | 31 | }; |
27 | 32 | ||
33 | static inline unsigned long *perf_header__adds_mask(struct perf_header *self) | ||
34 | { | ||
35 | return (unsigned long *)(void *)&self->adds_features; | ||
36 | } | ||
37 | |||
28 | struct perf_header *perf_header__read(int fd); | 38 | struct perf_header *perf_header__read(int fd); |
29 | void perf_header__write(struct perf_header *self, int fd); | 39 | void perf_header__write(struct perf_header *self, int fd); |
30 | 40 | ||
@@ -42,7 +52,7 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id); | |||
42 | u64 perf_header__sample_type(struct perf_header *header); | 52 | u64 perf_header__sample_type(struct perf_header *header); |
43 | struct perf_event_attr * | 53 | struct perf_event_attr * |
44 | perf_header__find_attr(u64 id, struct perf_header *header); | 54 | perf_header__find_attr(u64 id, struct perf_header *header); |
45 | void perf_header__set_trace_info(void); | 55 | void perf_header__feat_trace_info(struct perf_header *header); |
46 | 56 | ||
47 | struct perf_header *perf_header__new(void); | 57 | struct perf_header *perf_header__new(void); |
48 | 58 | ||