blob: d8416f0111798ab5fe5c4e016192d4d1f0b1a6b4 [file] [log] [blame]
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001#include <sys/types.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
Frederic Weisbecker8671dab2009-11-11 04:51:03 +01005#include <linux/list.h>
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02006
7#include "util.h"
8#include "header.h"
Frederic Weisbecker03456a12009-10-06 23:36:47 +02009#include "../perf.h"
10#include "trace-event.h"
Frederic Weisbecker8671dab2009-11-11 04:51:03 +010011#include "symbol.h"
Frederic Weisbecker4778d2e2009-11-11 04:51:05 +010012#include "data_map.h"
13#include "debug.h"
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020014
15/*
Arjan van de Venec60a3f2009-09-19 13:36:30 +020016 * Create new perf.data header attribute:
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020017 */
Ingo Molnarcdd6c482009-09-21 12:02:48 +020018struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020019{
20 struct perf_header_attr *self = malloc(sizeof(*self));
21
22 if (!self)
23 die("nomem");
24
25 self->attr = *attr;
26 self->ids = 0;
27 self->size = 1;
28 self->id = malloc(sizeof(u64));
29
30 if (!self->id)
31 die("nomem");
32
33 return self;
34}
35
36void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
37{
38 int pos = self->ids;
39
40 self->ids++;
41 if (self->ids > self->size) {
42 self->size *= 2;
43 self->id = realloc(self->id, self->size * sizeof(u64));
44 if (!self->id)
45 die("nomem");
46 }
47 self->id[pos] = id;
48}
49
50/*
Arjan van de Venec60a3f2009-09-19 13:36:30 +020051 * Create new perf.data header:
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020052 */
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020053struct perf_header *perf_header__new(void)
54{
Frederic Weisbecker2ba08252009-10-17 17:12:34 +020055 struct perf_header *self = calloc(sizeof(*self), 1);
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020056
57 if (!self)
58 die("nomem");
59
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020060 self->size = 1;
61 self->attr = malloc(sizeof(void *));
62
63 if (!self->attr)
64 die("nomem");
65
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020066 return self;
67}
68
69void perf_header__add_attr(struct perf_header *self,
70 struct perf_header_attr *attr)
71{
72 int pos = self->attrs;
73
74 if (self->frozen)
75 die("frozen");
76
77 self->attrs++;
78 if (self->attrs > self->size) {
79 self->size *= 2;
80 self->attr = realloc(self->attr, self->size * sizeof(void *));
81 if (!self->attr)
82 die("nomem");
83 }
84 self->attr[pos] = attr;
85}
86
Arjan van de Venec60a3f2009-09-19 13:36:30 +020087#define MAX_EVENT_NAME 64
88
Arjan van de Ven8755a8f2009-09-12 07:52:51 +020089struct perf_trace_event_type {
90 u64 event_id;
Arjan van de Venec60a3f2009-09-19 13:36:30 +020091 char name[MAX_EVENT_NAME];
Arjan van de Ven8755a8f2009-09-12 07:52:51 +020092};
93
94static int event_count;
95static struct perf_trace_event_type *events;
96
97void perf_header__push_event(u64 id, const char *name)
98{
Arjan van de Venec60a3f2009-09-19 13:36:30 +020099 if (strlen(name) > MAX_EVENT_NAME)
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200100 pr_warning("Event %s will be truncated\n", name);
Arjan van de Ven8755a8f2009-09-12 07:52:51 +0200101
102 if (!events) {
103 events = malloc(sizeof(struct perf_trace_event_type));
104 if (!events)
105 die("nomem");
106 } else {
107 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type));
108 if (!events)
109 die("nomem");
110 }
111 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
112 events[event_count].event_id = id;
Arjan van de Venec60a3f2009-09-19 13:36:30 +0200113 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
Arjan van de Ven8755a8f2009-09-12 07:52:51 +0200114 event_count++;
115}
116
117char *perf_header__find_event(u64 id)
118{
119 int i;
120 for (i = 0 ; i < event_count; i++) {
121 if (events[i].event_id == id)
122 return events[i].name;
123 }
124 return NULL;
125}
126
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200127static const char *__perf_magic = "PERFFILE";
128
129#define PERF_MAGIC (*(u64 *)__perf_magic)
130
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200131struct perf_file_attr {
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200132 struct perf_event_attr attr;
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200133 struct perf_file_section ids;
134};
135
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200136void perf_header__set_feat(struct perf_header *self, int feat)
137{
138 set_bit(feat, self->adds_features);
139}
140
141bool perf_header__has_feat(const struct perf_header *self, int feat)
142{
143 return test_bit(feat, self->adds_features);
144}
145
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200146static void do_write(int fd, void *buf, size_t size)
147{
148 while (size) {
149 int ret = write(fd, buf, size);
150
151 if (ret < 0)
152 die("failed to write");
153
154 size -= ret;
155 buf += ret;
156 }
157}
158
Frederic Weisbecker57f395a2009-11-11 04:51:04 +0100159static void write_buildid_table(int fd, struct list_head *id_head)
Frederic Weisbecker8671dab2009-11-11 04:51:03 +0100160{
Frederic Weisbecker57f395a2009-11-11 04:51:04 +0100161 struct build_id_list *iter, *next;
Frederic Weisbecker8671dab2009-11-11 04:51:03 +0100162
Frederic Weisbecker57f395a2009-11-11 04:51:04 +0100163 list_for_each_entry_safe(iter, next, id_head, list) {
164 struct build_id_event *b = &iter->event;
Frederic Weisbecker8671dab2009-11-11 04:51:03 +0100165
Frederic Weisbecker57f395a2009-11-11 04:51:04 +0100166 do_write(fd, b, sizeof(*b));
167 do_write(fd, (void *)iter->dso_name, iter->len);
168 list_del(&iter->list);
169 free(iter);
Frederic Weisbecker8671dab2009-11-11 04:51:03 +0100170 }
Frederic Weisbecker8671dab2009-11-11 04:51:03 +0100171}
172
173static void
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100174perf_header__adds_write(struct perf_header *self, int fd)
Frederic Weisbecker2ba08252009-10-17 17:12:34 +0200175{
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100176 LIST_HEAD(id_list);
177 int nr_sections;
178 struct perf_file_section *feat_sec;
179 int sec_size;
180 u64 sec_start;
181 int idx = 0;
182
183 if (fetch_build_id_table(&id_list))
184 perf_header__set_feat(self, HEADER_BUILD_ID);
185
186 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
187 if (!nr_sections)
188 return;
189
190 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
191 if (!feat_sec)
192 die("No memory");
193
194 sec_size = sizeof(*feat_sec) * nr_sections;
195
196 sec_start = self->data_offset + self->data_size;
197 lseek(fd, sec_start + sec_size, SEEK_SET);
Frederic Weisbecker2ba08252009-10-17 17:12:34 +0200198
Frederic Weisbecker3e13ab22009-11-11 04:51:06 +0100199 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100200 struct perf_file_section *trace_sec;
201
202 trace_sec = &feat_sec[idx++];
203
Frederic Weisbecker2ba08252009-10-17 17:12:34 +0200204 /* Write trace info */
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100205 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
Frederic Weisbecker2ba08252009-10-17 17:12:34 +0200206 read_tracing_data(fd, attrs, nr_counters);
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100207 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
Frederic Weisbecker2ba08252009-10-17 17:12:34 +0200208 }
Frederic Weisbecker8671dab2009-11-11 04:51:03 +0100209
Frederic Weisbecker57f395a2009-11-11 04:51:04 +0100210
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100211 if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
212 struct perf_file_section *buildid_sec;
213
214 buildid_sec = &feat_sec[idx++];
215
216 /* Write build-ids */
217 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
218 write_buildid_table(fd, &id_list);
219 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
Frederic Weisbecker8671dab2009-11-11 04:51:03 +0100220 }
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100221
222 lseek(fd, sec_start, SEEK_SET);
223 do_write(fd, feat_sec, sec_size);
224 free(feat_sec);
225}
Frederic Weisbecker2ba08252009-10-17 17:12:34 +0200226
Frederic Weisbecker8671dab2009-11-11 04:51:03 +0100227void perf_header__write(struct perf_header *self, int fd, bool at_exit)
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200228{
229 struct perf_file_header f_header;
230 struct perf_file_attr f_attr;
231 struct perf_header_attr *attr;
232 int i;
233
234 lseek(fd, sizeof(f_header), SEEK_SET);
235
236
237 for (i = 0; i < self->attrs; i++) {
238 attr = self->attr[i];
239
240 attr->id_offset = lseek(fd, 0, SEEK_CUR);
241 do_write(fd, attr->id, attr->ids * sizeof(u64));
242 }
243
244
245 self->attr_offset = lseek(fd, 0, SEEK_CUR);
246
247 for (i = 0; i < self->attrs; i++) {
248 attr = self->attr[i];
249
250 f_attr = (struct perf_file_attr){
251 .attr = attr->attr,
252 .ids = {
253 .offset = attr->id_offset,
254 .size = attr->ids * sizeof(u64),
255 }
256 };
257 do_write(fd, &f_attr, sizeof(f_attr));
258 }
259
Arjan van de Ven8755a8f2009-09-12 07:52:51 +0200260 self->event_offset = lseek(fd, 0, SEEK_CUR);
261 self->event_size = event_count * sizeof(struct perf_trace_event_type);
262 if (events)
263 do_write(fd, events, self->event_size);
264
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200265 self->data_offset = lseek(fd, 0, SEEK_CUR);
266
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100267 if (at_exit)
268 perf_header__adds_write(self, fd);
269
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200270 f_header = (struct perf_file_header){
271 .magic = PERF_MAGIC,
272 .size = sizeof(f_header),
273 .attr_size = sizeof(f_attr),
274 .attrs = {
275 .offset = self->attr_offset,
276 .size = self->attrs * sizeof(f_attr),
277 },
278 .data = {
279 .offset = self->data_offset,
280 .size = self->data_size,
281 },
Arjan van de Ven8755a8f2009-09-12 07:52:51 +0200282 .event_types = {
283 .offset = self->event_offset,
284 .size = self->event_size,
285 },
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200286 };
287
Frederic Weisbeckerdb9f11e2009-10-17 17:57:18 +0200288 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
Frederic Weisbecker2ba08252009-10-17 17:12:34 +0200289
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200290 lseek(fd, 0, SEEK_SET);
291 do_write(fd, &f_header, sizeof(f_header));
292 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
293
294 self->frozen = 1;
295}
296
297static void do_read(int fd, void *buf, size_t size)
298{
299 while (size) {
300 int ret = read(fd, buf, size);
301
302 if (ret < 0)
303 die("failed to read");
Pierre Habouzit7eac7e92009-08-07 14:16:00 +0200304 if (ret == 0)
305 die("failed to read: missing data");
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200306
307 size -= ret;
308 buf += ret;
309 }
310}
311
Arnaldo Carvalho de Melo37562ea2009-11-16 16:32:43 -0200312int perf_header__process_sections(struct perf_header *self, int fd,
313 int (*process)(struct perf_file_section *self,
314 int feat, int fd))
Frederic Weisbecker2ba08252009-10-17 17:12:34 +0200315{
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100316 struct perf_file_section *feat_sec;
317 int nr_sections;
318 int sec_size;
319 int idx = 0;
Arnaldo Carvalho de Melo37562ea2009-11-16 16:32:43 -0200320 int err = 0, feat = 1;
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100321
322 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
323 if (!nr_sections)
Arnaldo Carvalho de Melo37562ea2009-11-16 16:32:43 -0200324 return 0;
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100325
326 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
327 if (!feat_sec)
Arnaldo Carvalho de Melo37562ea2009-11-16 16:32:43 -0200328 return -1;
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100329
330 sec_size = sizeof(*feat_sec) * nr_sections;
331
332 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
333
334 do_read(fd, feat_sec, sec_size);
335
Arnaldo Carvalho de Melo37562ea2009-11-16 16:32:43 -0200336 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
337 if (perf_header__has_feat(self, feat)) {
338 struct perf_file_section *sec = &feat_sec[idx++];
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100339
Arnaldo Carvalho de Melo37562ea2009-11-16 16:32:43 -0200340 err = process(sec, feat, fd);
341 if (err < 0)
342 break;
343 }
344 ++feat;
Frederic Weisbecker4778d2e2009-11-11 04:51:05 +0100345 }
Frederic Weisbecker9e827dd2009-11-11 04:51:07 +0100346
347 free(feat_sec);
Arnaldo Carvalho de Melo37562ea2009-11-16 16:32:43 -0200348 return err;
Frederic Weisbecker2ba08252009-10-17 17:12:34 +0200349};
350
Arnaldo Carvalho de Melo37562ea2009-11-16 16:32:43 -0200351int perf_file_header__read(struct perf_file_header *self,
352 struct perf_header *ph, int fd)
353{
354 lseek(fd, 0, SEEK_SET);
355 do_read(fd, self, sizeof(*self));
356
357 if (self->magic != PERF_MAGIC ||
358 self->attr_size != sizeof(struct perf_file_attr))
359 return -1;
360
361 if (self->size != sizeof(*self)) {
362 /* Support the previous format */
363 if (self->size == offsetof(typeof(*self), adds_features))
364 bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
365 else
366 return -1;
367 }
368
369 memcpy(&ph->adds_features, &self->adds_features,
370 sizeof(self->adds_features));
371
372 ph->event_offset = self->event_types.offset;
373 ph->event_size = self->event_types.size;
374 ph->data_offset = self->data.offset;
375 ph->data_size = self->data.size;
376 return 0;
377}
378
379static int perf_file_section__process(struct perf_file_section *self,
380 int feat, int fd)
381{
382 if (lseek(fd, self->offset, SEEK_SET) < 0) {
383 pr_debug("Failed to lseek to %Ld offset for feature %d, "
384 "continuing...\n", self->offset, feat);
385 return 0;
386 }
387
388 switch (feat) {
389 case HEADER_TRACE_INFO:
390 trace_report(fd);
391 break;
392
393 case HEADER_BUILD_ID:
394 if (perf_header__read_build_ids(fd, self->offset, self->size))
395 pr_debug("Failed to read buildids, continuing...\n");
396 break;
397 default:
398 pr_debug("unknown feature %d, continuing...\n", feat);
399 }
400
401 return 0;
402}
403
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200404struct perf_header *perf_header__read(int fd)
405{
406 struct perf_header *self = perf_header__new();
407 struct perf_file_header f_header;
408 struct perf_file_attr f_attr;
409 u64 f_id;
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200410 int nr_attrs, nr_ids, i, j;
411
Arnaldo Carvalho de Melo37562ea2009-11-16 16:32:43 -0200412 if (perf_file_header__read(&f_header, self, fd) < 0)
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200413 die("incompatible file format");
414
415 nr_attrs = f_header.attrs.size / sizeof(f_attr);
416 lseek(fd, f_header.attrs.offset, SEEK_SET);
417
418 for (i = 0; i < nr_attrs; i++) {
419 struct perf_header_attr *attr;
Peter Zijlstra1c222bc2009-08-06 20:57:41 +0200420 off_t tmp;
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200421
422 do_read(fd, &f_attr, sizeof(f_attr));
Peter Zijlstra1c222bc2009-08-06 20:57:41 +0200423 tmp = lseek(fd, 0, SEEK_CUR);
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200424
425 attr = perf_header_attr__new(&f_attr.attr);
426
427 nr_ids = f_attr.ids.size / sizeof(u64);
428 lseek(fd, f_attr.ids.offset, SEEK_SET);
429
430 for (j = 0; j < nr_ids; j++) {
431 do_read(fd, &f_id, sizeof(f_id));
432
433 perf_header_attr__add_id(attr, f_id);
434 }
435 perf_header__add_attr(self, attr);
436 lseek(fd, tmp, SEEK_SET);
437 }
438
Arjan van de Ven8755a8f2009-09-12 07:52:51 +0200439 if (f_header.event_types.size) {
440 lseek(fd, f_header.event_types.offset, SEEK_SET);
441 events = malloc(f_header.event_types.size);
442 if (!events)
443 die("nomem");
444 do_read(fd, events, f_header.event_types.size);
445 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
446 }
Frederic Weisbecker03456a12009-10-06 23:36:47 +0200447
Arnaldo Carvalho de Melo37562ea2009-11-16 16:32:43 -0200448 perf_header__process_sections(self, fd, perf_file_section__process);
Frederic Weisbecker4778d2e2009-11-11 04:51:05 +0100449
Ingo Molnar2e01d172009-09-03 16:21:11 +0200450 lseek(fd, self->data_offset, SEEK_SET);
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +0200451
452 self->frozen = 1;
453
454 return self;
455}
Frederic Weisbecker0d3a5c82009-08-16 20:56:37 +0200456
457u64 perf_header__sample_type(struct perf_header *header)
458{
459 u64 type = 0;
460 int i;
461
462 for (i = 0; i < header->attrs; i++) {
463 struct perf_header_attr *attr = header->attr[i];
464
465 if (!type)
466 type = attr->attr.sample_type;
467 else if (type != attr->attr.sample_type)
468 die("non matching sample_type");
469 }
470
471 return type;
472}
473
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200474struct perf_event_attr *
Frederic Weisbecker0d3a5c82009-08-16 20:56:37 +0200475perf_header__find_attr(u64 id, struct perf_header *header)
476{
477 int i;
478
479 for (i = 0; i < header->attrs; i++) {
480 struct perf_header_attr *attr = header->attr[i];
481 int j;
482
483 for (j = 0; j < attr->ids; j++) {
484 if (attr->id[j] == id)
485 return &attr->attr;
486 }
487 }
488
489 return NULL;
490}