perf utils: Use a define for the maximum length of a trace event
[safe/jmp/linux-2.6] / tools / perf / util / header.c
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  * Create new perf.data header attribute:
11  */
12 struct perf_header_attr *perf_header_attr__new(struct perf_counter_attr *attr)
13 {
14         struct perf_header_attr *self = malloc(sizeof(*self));
15
16         if (!self)
17                 die("nomem");
18
19         self->attr = *attr;
20         self->ids = 0;
21         self->size = 1;
22         self->id = malloc(sizeof(u64));
23
24         if (!self->id)
25                 die("nomem");
26
27         return self;
28 }
29
30 void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
31 {
32         int pos = self->ids;
33
34         self->ids++;
35         if (self->ids > self->size) {
36                 self->size *= 2;
37                 self->id = realloc(self->id, self->size * sizeof(u64));
38                 if (!self->id)
39                         die("nomem");
40         }
41         self->id[pos] = id;
42 }
43
44 /*
45  * Create new perf.data header:
46  */
47 struct perf_header *perf_header__new(void)
48 {
49         struct perf_header *self = malloc(sizeof(*self));
50
51         if (!self)
52                 die("nomem");
53
54         self->frozen = 0;
55
56         self->attrs = 0;
57         self->size = 1;
58         self->attr = malloc(sizeof(void *));
59
60         if (!self->attr)
61                 die("nomem");
62
63         self->data_offset = 0;
64         self->data_size = 0;
65
66         return self;
67 }
68
69 void 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
87 #define MAX_EVENT_NAME 64
88
89 struct perf_trace_event_type {
90         u64     event_id;
91         char    name[MAX_EVENT_NAME];
92 };
93
94 static int event_count;
95 static struct perf_trace_event_type *events;
96
97 void perf_header__push_event(u64 id, const char *name)
98 {
99         if (strlen(name) > MAX_EVENT_NAME)
100                 printf("Event %s will be truncated\n", name);
101
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;
113         strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
114         event_count++;
115 }
116
117 char *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
127 static const char *__perf_magic = "PERFFILE";
128
129 #define PERF_MAGIC      (*(u64 *)__perf_magic)
130
131 struct perf_file_section {
132         u64 offset;
133         u64 size;
134 };
135
136 struct perf_file_attr {
137         struct perf_counter_attr        attr;
138         struct perf_file_section        ids;
139 };
140
141 struct perf_file_header {
142         u64                             magic;
143         u64                             size;
144         u64                             attr_size;
145         struct perf_file_section        attrs;
146         struct perf_file_section        data;
147         struct perf_file_section        event_types;
148 };
149
150 static void do_write(int fd, void *buf, size_t size)
151 {
152         while (size) {
153                 int ret = write(fd, buf, size);
154
155                 if (ret < 0)
156                         die("failed to write");
157
158                 size -= ret;
159                 buf += ret;
160         }
161 }
162
163 void perf_header__write(struct perf_header *self, int fd)
164 {
165         struct perf_file_header f_header;
166         struct perf_file_attr   f_attr;
167         struct perf_header_attr *attr;
168         int i;
169
170         lseek(fd, sizeof(f_header), SEEK_SET);
171
172
173         for (i = 0; i < self->attrs; i++) {
174                 attr = self->attr[i];
175
176                 attr->id_offset = lseek(fd, 0, SEEK_CUR);
177                 do_write(fd, attr->id, attr->ids * sizeof(u64));
178         }
179
180
181         self->attr_offset = lseek(fd, 0, SEEK_CUR);
182
183         for (i = 0; i < self->attrs; i++) {
184                 attr = self->attr[i];
185
186                 f_attr = (struct perf_file_attr){
187                         .attr = attr->attr,
188                         .ids  = {
189                                 .offset = attr->id_offset,
190                                 .size   = attr->ids * sizeof(u64),
191                         }
192                 };
193                 do_write(fd, &f_attr, sizeof(f_attr));
194         }
195
196         self->event_offset = lseek(fd, 0, SEEK_CUR);
197         self->event_size = event_count * sizeof(struct perf_trace_event_type);
198         if (events)
199                 do_write(fd, events, self->event_size);
200
201
202         self->data_offset = lseek(fd, 0, SEEK_CUR);
203
204         f_header = (struct perf_file_header){
205                 .magic     = PERF_MAGIC,
206                 .size      = sizeof(f_header),
207                 .attr_size = sizeof(f_attr),
208                 .attrs = {
209                         .offset = self->attr_offset,
210                         .size   = self->attrs * sizeof(f_attr),
211                 },
212                 .data = {
213                         .offset = self->data_offset,
214                         .size   = self->data_size,
215                 },
216                 .event_types = {
217                         .offset = self->event_offset,
218                         .size   = self->event_size,
219                 },
220         };
221
222         lseek(fd, 0, SEEK_SET);
223         do_write(fd, &f_header, sizeof(f_header));
224         lseek(fd, self->data_offset + self->data_size, SEEK_SET);
225
226         self->frozen = 1;
227 }
228
229 static void do_read(int fd, void *buf, size_t size)
230 {
231         while (size) {
232                 int ret = read(fd, buf, size);
233
234                 if (ret < 0)
235                         die("failed to read");
236                 if (ret == 0)
237                         die("failed to read: missing data");
238
239                 size -= ret;
240                 buf += ret;
241         }
242 }
243
244 struct perf_header *perf_header__read(int fd)
245 {
246         struct perf_header      *self = perf_header__new();
247         struct perf_file_header f_header;
248         struct perf_file_attr   f_attr;
249         u64                     f_id;
250
251         int nr_attrs, nr_ids, i, j;
252
253         lseek(fd, 0, SEEK_SET);
254         do_read(fd, &f_header, sizeof(f_header));
255
256         if (f_header.magic      != PERF_MAGIC           ||
257             f_header.size       != sizeof(f_header)     ||
258             f_header.attr_size  != sizeof(f_attr))
259                 die("incompatible file format");
260
261         nr_attrs = f_header.attrs.size / sizeof(f_attr);
262         lseek(fd, f_header.attrs.offset, SEEK_SET);
263
264         for (i = 0; i < nr_attrs; i++) {
265                 struct perf_header_attr *attr;
266                 off_t tmp;
267
268                 do_read(fd, &f_attr, sizeof(f_attr));
269                 tmp = lseek(fd, 0, SEEK_CUR);
270
271                 attr = perf_header_attr__new(&f_attr.attr);
272
273                 nr_ids = f_attr.ids.size / sizeof(u64);
274                 lseek(fd, f_attr.ids.offset, SEEK_SET);
275
276                 for (j = 0; j < nr_ids; j++) {
277                         do_read(fd, &f_id, sizeof(f_id));
278
279                         perf_header_attr__add_id(attr, f_id);
280                 }
281                 perf_header__add_attr(self, attr);
282                 lseek(fd, tmp, SEEK_SET);
283         }
284
285         if (f_header.event_types.size) {
286                 lseek(fd, f_header.event_types.offset, SEEK_SET);
287                 events = malloc(f_header.event_types.size);
288                 if (!events)
289                         die("nomem");
290                 do_read(fd, events, f_header.event_types.size);
291                 event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
292         }
293         self->event_offset = f_header.event_types.offset;
294         self->event_size   = f_header.event_types.size;
295
296         self->data_offset = f_header.data.offset;
297         self->data_size   = f_header.data.size;
298
299         lseek(fd, self->data_offset, SEEK_SET);
300
301         self->frozen = 1;
302
303         return self;
304 }
305
306 u64 perf_header__sample_type(struct perf_header *header)
307 {
308         u64 type = 0;
309         int i;
310
311         for (i = 0; i < header->attrs; i++) {
312                 struct perf_header_attr *attr = header->attr[i];
313
314                 if (!type)
315                         type = attr->attr.sample_type;
316                 else if (type != attr->attr.sample_type)
317                         die("non matching sample_type");
318         }
319
320         return type;
321 }
322
323 struct perf_counter_attr *
324 perf_header__find_attr(u64 id, struct perf_header *header)
325 {
326         int i;
327
328         for (i = 0; i < header->attrs; i++) {
329                 struct perf_header_attr *attr = header->attr[i];
330                 int j;
331
332                 for (j = 0; j < attr->ids; j++) {
333                         if (attr->id[j] == id)
334                                 return &attr->attr;
335                 }
336         }
337
338         return NULL;
339 }