aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/header.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r--tools/perf/util/header.c342
1 files changed, 237 insertions, 105 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 7d26659b806..b01a9537977 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2,11 +2,15 @@
2#include <unistd.h> 2#include <unistd.h>
3#include <stdio.h> 3#include <stdio.h>
4#include <stdlib.h> 4#include <stdlib.h>
5#include <linux/list.h>
5 6
6#include "util.h" 7#include "util.h"
7#include "header.h" 8#include "header.h"
8#include "../perf.h" 9#include "../perf.h"
9#include "trace-event.h" 10#include "trace-event.h"
11#include "symbol.h"
12#include "data_map.h"
13#include "debug.h"
10 14
11/* 15/*
12 * Create new perf.data header attribute: 16 * Create new perf.data header attribute:
@@ -15,32 +19,43 @@ struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
15{ 19{
16 struct perf_header_attr *self = malloc(sizeof(*self)); 20 struct perf_header_attr *self = malloc(sizeof(*self));
17 21
18 if (!self) 22 if (self != NULL) {
19 die("nomem"); 23 self->attr = *attr;
20 24 self->ids = 0;
21 self->attr = *attr; 25 self->size = 1;
22 self->ids = 0; 26 self->id = malloc(sizeof(u64));
23 self->size = 1; 27 if (self->id == NULL) {
24 self->id = malloc(sizeof(u64)); 28 free(self);
25 29 self = NULL;
26 if (!self->id) 30 }
27 die("nomem"); 31 }
28 32
29 return self; 33 return self;
30} 34}
31 35
32void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) 36void perf_header_attr__delete(struct perf_header_attr *self)
37{
38 free(self->id);
39 free(self);
40}
41
42int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
33{ 43{
34 int pos = self->ids; 44 int pos = self->ids;
35 45
36 self->ids++; 46 self->ids++;
37 if (self->ids > self->size) { 47 if (self->ids > self->size) {
38 self->size *= 2; 48 int nsize = self->size * 2;
39 self->id = realloc(self->id, self->size * sizeof(u64)); 49 u64 *nid = realloc(self->id, nsize * sizeof(u64));
40 if (!self->id) 50
41 die("nomem"); 51 if (nid == NULL)
52 return -1;
53
54 self->size = nsize;
55 self->id = nid;
42 } 56 }
43 self->id[pos] = id; 57 self->id[pos] = id;
58 return 0;
44} 59}
45 60
46/* 61/*
@@ -50,34 +65,41 @@ struct perf_header *perf_header__new(void)
50{ 65{
51 struct perf_header *self = calloc(sizeof(*self), 1); 66 struct perf_header *self = calloc(sizeof(*self), 1);
52 67
53 if (!self) 68 if (self != NULL) {
54 die("nomem"); 69 self->size = 1;
55 70 self->attr = malloc(sizeof(void *));
56 self->size = 1;
57 self->attr = malloc(sizeof(void *));
58 71
59 if (!self->attr) 72 if (self->attr == NULL) {
60 die("nomem"); 73 free(self);
74 self = NULL;
75 }
76 }
61 77
62 return self; 78 return self;
63} 79}
64 80
65void perf_header__add_attr(struct perf_header *self, 81int perf_header__add_attr(struct perf_header *self,
66 struct perf_header_attr *attr) 82 struct perf_header_attr *attr)
67{ 83{
68 int pos = self->attrs; 84 int pos = self->attrs;
69 85
70 if (self->frozen) 86 if (self->frozen)
71 die("frozen"); 87 return -1;
72 88
73 self->attrs++; 89 self->attrs++;
74 if (self->attrs > self->size) { 90 if (self->attrs > self->size) {
75 self->size *= 2; 91 int nsize = self->size * 2;
76 self->attr = realloc(self->attr, self->size * sizeof(void *)); 92 struct perf_header_attr **nattr;
77 if (!self->attr) 93
78 die("nomem"); 94 nattr = realloc(self->attr, nsize * sizeof(void *));
95 if (nattr == NULL)
96 return -1;
97
98 self->size = nsize;
99 self->attr = nattr;
79 } 100 }
80 self->attr[pos] = attr; 101 self->attr[pos] = attr;
102 return 0;
81} 103}
82 104
83#define MAX_EVENT_NAME 64 105#define MAX_EVENT_NAME 64
@@ -124,71 +146,110 @@ static const char *__perf_magic = "PERFFILE";
124 146
125#define PERF_MAGIC (*(u64 *)__perf_magic) 147#define PERF_MAGIC (*(u64 *)__perf_magic)
126 148
127struct perf_file_section {
128 u64 offset;
129 u64 size;
130};
131
132struct perf_file_attr { 149struct perf_file_attr {
133 struct perf_event_attr attr; 150 struct perf_event_attr attr;
134 struct perf_file_section ids; 151 struct perf_file_section ids;
135}; 152};
136 153
137struct perf_file_header { 154void perf_header__set_feat(struct perf_header *self, int feat)
138 u64 magic; 155{
139 u64 size; 156 set_bit(feat, self->adds_features);
140 u64 attr_size; 157}
141 struct perf_file_section attrs;
142 struct perf_file_section data;
143 struct perf_file_section event_types;
144 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
145};
146 158
147void perf_header__feat_trace_info(struct perf_header *header) 159bool perf_header__has_feat(const struct perf_header *self, int feat)
148{ 160{
149 set_bit(HEADER_TRACE_INFO, header->adds_features); 161 return test_bit(feat, self->adds_features);
150} 162}
151 163
152static void do_write(int fd, void *buf, size_t size) 164static int do_write(int fd, const void *buf, size_t size)
153{ 165{
154 while (size) { 166 while (size) {
155 int ret = write(fd, buf, size); 167 int ret = write(fd, buf, size);
156 168
157 if (ret < 0) 169 if (ret < 0)
158 die("failed to write"); 170 return -1;
159 171
160 size -= ret; 172 size -= ret;
161 buf += ret; 173 buf += ret;
162 } 174 }
175
176 return 0;
177}
178
179static int write_buildid_table(int fd, struct list_head *id_head)
180{
181 struct build_id_list *iter, *next;
182
183 list_for_each_entry_safe(iter, next, id_head, list) {
184 struct build_id_event *b = &iter->event;
185
186 if (do_write(fd, b, sizeof(*b)) < 0 ||
187 do_write(fd, iter->dso_name, iter->len) < 0)
188 return -1;
189 list_del(&iter->list);
190 free(iter);
191 }
192
193 return 0;
163} 194}
164 195
165static void perf_header__adds_write(struct perf_header *self, int fd) 196static void
197perf_header__adds_write(struct perf_header *self, int fd)
166{ 198{
167 struct perf_file_section trace_sec; 199 LIST_HEAD(id_list);
168 u64 cur_offset = lseek(fd, 0, SEEK_CUR); 200 int nr_sections;
169 unsigned long *feat_mask = self->adds_features; 201 struct perf_file_section *feat_sec;
202 int sec_size;
203 u64 sec_start;
204 int idx = 0;
205
206 if (fetch_build_id_table(&id_list))
207 perf_header__set_feat(self, HEADER_BUILD_ID);
208
209 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
210 if (!nr_sections)
211 return;
212
213 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
214 if (!feat_sec)
215 die("No memory");
216
217 sec_size = sizeof(*feat_sec) * nr_sections;
218
219 sec_start = self->data_offset + self->data_size;
220 lseek(fd, sec_start + sec_size, SEEK_SET);
221
222 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
223 struct perf_file_section *trace_sec;
224
225 trace_sec = &feat_sec[idx++];
170 226
171 if (test_bit(HEADER_TRACE_INFO, feat_mask)) {
172 /* Write trace info */ 227 /* Write trace info */
173 trace_sec.offset = lseek(fd, sizeof(trace_sec), SEEK_CUR); 228 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
174 read_tracing_data(fd, attrs, nr_counters); 229 read_tracing_data(fd, attrs, nr_counters);
175 trace_sec.size = lseek(fd, 0, SEEK_CUR) - trace_sec.offset; 230 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
176
177 /* Write trace info headers */
178 lseek(fd, cur_offset, SEEK_SET);
179 do_write(fd, &trace_sec, sizeof(trace_sec));
180
181 /*
182 * Update cur_offset. So that other (future)
183 * features can set their own infos in this place. But if we are
184 * the only feature, at least that seeks to the place the data
185 * should begin.
186 */
187 cur_offset = lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET);
188 } 231 }
189};
190 232
191void perf_header__write(struct perf_header *self, int fd) 233
234 if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
235 struct perf_file_section *buildid_sec;
236
237 buildid_sec = &feat_sec[idx++];
238
239 /* Write build-ids */
240 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
241 if (write_buildid_table(fd, &id_list) < 0)
242 die("failed to write buildid table");
243 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
244 }
245
246 lseek(fd, sec_start, SEEK_SET);
247 if (do_write(fd, feat_sec, sec_size) < 0)
248 die("failed to write feature section");
249 free(feat_sec);
250}
251
252void perf_header__write(struct perf_header *self, int fd, bool at_exit)
192{ 253{
193 struct perf_file_header f_header; 254 struct perf_file_header f_header;
194 struct perf_file_attr f_attr; 255 struct perf_file_attr f_attr;
@@ -202,7 +263,8 @@ void perf_header__write(struct perf_header *self, int fd)
202 attr = self->attr[i]; 263 attr = self->attr[i];
203 264
204 attr->id_offset = lseek(fd, 0, SEEK_CUR); 265 attr->id_offset = lseek(fd, 0, SEEK_CUR);
205 do_write(fd, attr->id, attr->ids * sizeof(u64)); 266 if (do_write(fd, attr->id, attr->ids * sizeof(u64)) < 0)
267 die("failed to write perf header");
206 } 268 }
207 269
208 270
@@ -218,18 +280,21 @@ void perf_header__write(struct perf_header *self, int fd)
218 .size = attr->ids * sizeof(u64), 280 .size = attr->ids * sizeof(u64),
219 } 281 }
220 }; 282 };
221 do_write(fd, &f_attr, sizeof(f_attr)); 283 if (do_write(fd, &f_attr, sizeof(f_attr)) < 0)
284 die("failed to write perf header attribute");
222 } 285 }
223 286
224 self->event_offset = lseek(fd, 0, SEEK_CUR); 287 self->event_offset = lseek(fd, 0, SEEK_CUR);
225 self->event_size = event_count * sizeof(struct perf_trace_event_type); 288 self->event_size = event_count * sizeof(struct perf_trace_event_type);
226 if (events) 289 if (events)
227 do_write(fd, events, self->event_size); 290 if (do_write(fd, events, self->event_size) < 0)
228 291 die("failed to write perf header events");
229 perf_header__adds_write(self, fd);
230 292
231 self->data_offset = lseek(fd, 0, SEEK_CUR); 293 self->data_offset = lseek(fd, 0, SEEK_CUR);
232 294
295 if (at_exit)
296 perf_header__adds_write(self, fd);
297
233 f_header = (struct perf_file_header){ 298 f_header = (struct perf_file_header){
234 .magic = PERF_MAGIC, 299 .magic = PERF_MAGIC,
235 .size = sizeof(f_header), 300 .size = sizeof(f_header),
@@ -251,7 +316,8 @@ void perf_header__write(struct perf_header *self, int fd)
251 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); 316 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
252 317
253 lseek(fd, 0, SEEK_SET); 318 lseek(fd, 0, SEEK_SET);
254 do_write(fd, &f_header, sizeof(f_header)); 319 if (do_write(fd, &f_header, sizeof(f_header)) < 0)
320 die("failed to write perf header");
255 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 321 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
256 322
257 self->frozen = 1; 323 self->frozen = 1;
@@ -272,43 +338,112 @@ static void do_read(int fd, void *buf, size_t size)
272 } 338 }
273} 339}
274 340
275static void perf_header__adds_read(struct perf_header *self, int fd) 341int perf_header__process_sections(struct perf_header *self, int fd,
342 int (*process)(struct perf_file_section *self,
343 int feat, int fd))
276{ 344{
277 const unsigned long *feat_mask = self->adds_features; 345 struct perf_file_section *feat_sec;
346 int nr_sections;
347 int sec_size;
348 int idx = 0;
349 int err = 0, feat = 1;
278 350
279 if (test_bit(HEADER_TRACE_INFO, feat_mask)) { 351 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
280 struct perf_file_section trace_sec; 352 if (!nr_sections)
353 return 0;
281 354
282 do_read(fd, &trace_sec, sizeof(trace_sec)); 355 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
283 lseek(fd, trace_sec.offset, SEEK_SET); 356 if (!feat_sec)
284 trace_report(fd); 357 return -1;
285 lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); 358
359 sec_size = sizeof(*feat_sec) * nr_sections;
360
361 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
362
363 do_read(fd, feat_sec, sec_size);
364
365 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
366 if (perf_header__has_feat(self, feat)) {
367 struct perf_file_section *sec = &feat_sec[idx++];
368
369 err = process(sec, feat, fd);
370 if (err < 0)
371 break;
372 }
373 ++feat;
286 } 374 }
375
376 free(feat_sec);
377 return err;
287}; 378};
288 379
380int perf_file_header__read(struct perf_file_header *self,
381 struct perf_header *ph, int fd)
382{
383 lseek(fd, 0, SEEK_SET);
384 do_read(fd, self, sizeof(*self));
385
386 if (self->magic != PERF_MAGIC ||
387 self->attr_size != sizeof(struct perf_file_attr))
388 return -1;
389
390 if (self->size != sizeof(*self)) {
391 /* Support the previous format */
392 if (self->size == offsetof(typeof(*self), adds_features))
393 bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
394 else
395 return -1;
396 }
397
398 memcpy(&ph->adds_features, &self->adds_features,
399 sizeof(self->adds_features));
400
401 ph->event_offset = self->event_types.offset;
402 ph->event_size = self->event_types.size;
403 ph->data_offset = self->data.offset;
404 ph->data_size = self->data.size;
405 return 0;
406}
407
408static int perf_file_section__process(struct perf_file_section *self,
409 int feat, int fd)
410{
411 if (lseek(fd, self->offset, SEEK_SET) < 0) {
412 pr_debug("Failed to lseek to %Ld offset for feature %d, "
413 "continuing...\n", self->offset, feat);
414 return 0;
415 }
416
417 switch (feat) {
418 case HEADER_TRACE_INFO:
419 trace_report(fd);
420 break;
421
422 case HEADER_BUILD_ID:
423 if (perf_header__read_build_ids(fd, self->offset, self->size))
424 pr_debug("Failed to read buildids, continuing...\n");
425 break;
426 default:
427 pr_debug("unknown feature %d, continuing...\n", feat);
428 }
429
430 return 0;
431}
432
289struct perf_header *perf_header__read(int fd) 433struct perf_header *perf_header__read(int fd)
290{ 434{
291 struct perf_header *self = perf_header__new(); 435 struct perf_header *self = perf_header__new();
292 struct perf_file_header f_header; 436 struct perf_file_header f_header;
293 struct perf_file_attr f_attr; 437 struct perf_file_attr f_attr;
294 u64 f_id; 438 u64 f_id;
295
296 int nr_attrs, nr_ids, i, j; 439 int nr_attrs, nr_ids, i, j;
297 440
298 lseek(fd, 0, SEEK_SET); 441 if (self == NULL)
299 do_read(fd, &f_header, sizeof(f_header)); 442 die("nomem");
300 443
301 if (f_header.magic != PERF_MAGIC || 444 if (perf_file_header__read(&f_header, self, fd) < 0)
302 f_header.attr_size != sizeof(f_attr))
303 die("incompatible file format"); 445 die("incompatible file format");
304 446
305 if (f_header.size != sizeof(f_header)) {
306 /* Support the previous format */
307 if (f_header.size == offsetof(typeof(f_header), adds_features))
308 bitmap_zero(f_header.adds_features, HEADER_FEAT_BITS);
309 else
310 die("incompatible file format");
311 }
312 nr_attrs = f_header.attrs.size / sizeof(f_attr); 447 nr_attrs = f_header.attrs.size / sizeof(f_attr);
313 lseek(fd, f_header.attrs.offset, SEEK_SET); 448 lseek(fd, f_header.attrs.offset, SEEK_SET);
314 449
@@ -320,6 +455,8 @@ struct perf_header *perf_header__read(int fd)
320 tmp = lseek(fd, 0, SEEK_CUR); 455 tmp = lseek(fd, 0, SEEK_CUR);
321 456
322 attr = perf_header_attr__new(&f_attr.attr); 457 attr = perf_header_attr__new(&f_attr.attr);
458 if (attr == NULL)
459 die("nomem");
323 460
324 nr_ids = f_attr.ids.size / sizeof(u64); 461 nr_ids = f_attr.ids.size / sizeof(u64);
325 lseek(fd, f_attr.ids.offset, SEEK_SET); 462 lseek(fd, f_attr.ids.offset, SEEK_SET);
@@ -327,9 +464,12 @@ struct perf_header *perf_header__read(int fd)
327 for (j = 0; j < nr_ids; j++) { 464 for (j = 0; j < nr_ids; j++) {
328 do_read(fd, &f_id, sizeof(f_id)); 465 do_read(fd, &f_id, sizeof(f_id));
329 466
330 perf_header_attr__add_id(attr, f_id); 467 if (perf_header_attr__add_id(attr, f_id) < 0)
468 die("nomem");
331 } 469 }
332 perf_header__add_attr(self, attr); 470 if (perf_header__add_attr(self, attr) < 0)
471 die("nomem");
472
333 lseek(fd, tmp, SEEK_SET); 473 lseek(fd, tmp, SEEK_SET);
334 } 474 }
335 475
@@ -342,15 +482,7 @@ struct perf_header *perf_header__read(int fd)
342 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 482 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
343 } 483 }
344 484
345 memcpy(&self->adds_features, &f_header.adds_features, sizeof(f_header.adds_features)); 485 perf_header__process_sections(self, fd, perf_file_section__process);
346
347 perf_header__adds_read(self, fd);
348
349 self->event_offset = f_header.event_types.offset;
350 self->event_size = f_header.event_types.size;
351
352 self->data_offset = f_header.data.offset;
353 self->data_size = f_header.data.size;
354 486
355 lseek(fd, self->data_offset, SEEK_SET); 487 lseek(fd, self->data_offset, SEEK_SET);
356 488