perf tools: Only save the event formats we need
[linux-2.6.git] / tools / perf / util / trace-event-read.c
1 /*
2  * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
3  *
4  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License (not later!)
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20  */
21 #define _LARGEFILE64_SOURCE
22
23 #include <dirent.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <getopt.h>
28 #include <stdarg.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/wait.h>
32 #include <sys/mman.h>
33 #include <pthread.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <ctype.h>
37 #include <errno.h>
38
39 #include "../perf.h"
40 #include "util.h"
41 #include "trace-event.h"
42
43 static int input_fd;
44
45 static int read_page;
46
47 int file_bigendian;
48 int host_bigendian;
49 static int long_size;
50
51 static unsigned long    page_size;
52
53 static int read_or_die(void *data, int size)
54 {
55         int r;
56
57         r = read(input_fd, data, size);
58         if (r != size)
59                 die("reading input file (size expected=%d received=%d)",
60                     size, r);
61         return r;
62 }
63
64 static unsigned int read4(void)
65 {
66         unsigned int data;
67
68         read_or_die(&data, 4);
69         return __data2host4(data);
70 }
71
72 static unsigned long long read8(void)
73 {
74         unsigned long long data;
75
76         read_or_die(&data, 8);
77         return __data2host8(data);
78 }
79
80 static char *read_string(void)
81 {
82         char buf[BUFSIZ];
83         char *str = NULL;
84         int size = 0;
85         int i;
86         int r;
87
88         for (;;) {
89                 r = read(input_fd, buf, BUFSIZ);
90                 if (r < 0)
91                         die("reading input file");
92
93                 if (!r)
94                         die("no data");
95
96                 for (i = 0; i < r; i++) {
97                         if (!buf[i])
98                                 break;
99                 }
100                 if (i < r)
101                         break;
102
103                 if (str) {
104                         size += BUFSIZ;
105                         str = realloc(str, size);
106                         if (!str)
107                                 die("malloc of size %d", size);
108                         memcpy(str + (size - BUFSIZ), buf, BUFSIZ);
109                 } else {
110                         size = BUFSIZ;
111                         str = malloc_or_die(size);
112                         memcpy(str, buf, size);
113                 }
114         }
115
116         /* move the file descriptor to the end of the string */
117         r = lseek(input_fd, -(r - (i+1)), SEEK_CUR);
118         if (r < 0)
119                 die("lseek");
120
121         if (str) {
122                 size += i;
123                 str = realloc(str, size);
124                 if (!str)
125                         die("malloc of size %d", size);
126                 memcpy(str + (size - i), buf, i);
127         } else {
128                 size = i;
129                 str = malloc_or_die(i);
130                 memcpy(str, buf, i);
131         }
132
133         return str;
134 }
135
136 static void read_proc_kallsyms(void)
137 {
138         unsigned int size;
139         char *buf;
140
141         size = read4();
142         if (!size)
143                 return;
144
145         buf = malloc_or_die(size);
146         read_or_die(buf, size);
147
148         parse_proc_kallsyms(buf, size);
149
150         free(buf);
151 }
152
153 static void read_ftrace_printk(void)
154 {
155         unsigned int size;
156         char *buf;
157
158         size = read4();
159         if (!size)
160                 return;
161
162         buf = malloc_or_die(size);
163         read_or_die(buf, size);
164
165         parse_ftrace_printk(buf, size);
166
167         free(buf);
168 }
169
170 static void read_header_files(void)
171 {
172         unsigned long long size;
173         char *header_page;
174         char *header_event;
175         char buf[BUFSIZ];
176
177         read_or_die(buf, 12);
178
179         if (memcmp(buf, "header_page", 12) != 0)
180                 die("did not read header page");
181
182         size = read8();
183         header_page = malloc_or_die(size);
184         read_or_die(header_page, size);
185         parse_header_page(header_page, size);
186         free(header_page);
187
188         /*
189          * The size field in the page is of type long,
190          * use that instead, since it represents the kernel.
191          */
192         long_size = header_page_size_size;
193
194         read_or_die(buf, 13);
195         if (memcmp(buf, "header_event", 13) != 0)
196                 die("did not read header event");
197
198         size = read8();
199         header_event = malloc_or_die(size);
200         read_or_die(header_event, size);
201         free(header_event);
202 }
203
204 static void read_ftrace_file(unsigned long long size)
205 {
206         char *buf;
207
208         buf = malloc_or_die(size);
209         read_or_die(buf, size);
210         parse_ftrace_file(buf, size);
211         free(buf);
212 }
213
214 static void read_event_file(char *sys, unsigned long long size)
215 {
216         char *buf;
217
218         buf = malloc_or_die(size);
219         read_or_die(buf, size);
220         parse_event_file(buf, size, sys);
221         free(buf);
222 }
223
224 static void read_ftrace_files(void)
225 {
226         unsigned long long size;
227         int count;
228         int i;
229
230         count = read4();
231
232         for (i = 0; i < count; i++) {
233                 size = read8();
234                 read_ftrace_file(size);
235         }
236 }
237
238 static void read_event_files(void)
239 {
240         unsigned long long size;
241         char *sys;
242         int systems;
243         int count;
244         int i,x;
245
246         systems = read4();
247
248         for (i = 0; i < systems; i++) {
249                 sys = read_string();
250
251                 count = read4();
252                 for (x=0; x < count; x++) {
253                         size = read8();
254                         read_event_file(sys, size);
255                 }
256         }
257 }
258
259 struct cpu_data {
260         unsigned long long      offset;
261         unsigned long long      size;
262         unsigned long long      timestamp;
263         struct record           *next;
264         char                    *page;
265         int                     cpu;
266         int                     index;
267         int                     page_size;
268 };
269
270 static struct cpu_data *cpu_data;
271
272 static void update_cpu_data_index(int cpu)
273 {
274         cpu_data[cpu].offset += page_size;
275         cpu_data[cpu].size -= page_size;
276         cpu_data[cpu].index = 0;
277 }
278
279 static void get_next_page(int cpu)
280 {
281         off64_t save_seek;
282         off64_t ret;
283
284         if (!cpu_data[cpu].page)
285                 return;
286
287         if (read_page) {
288                 if (cpu_data[cpu].size <= page_size) {
289                         free(cpu_data[cpu].page);
290                         cpu_data[cpu].page = NULL;
291                         return;
292                 }
293
294                 update_cpu_data_index(cpu);
295
296                 /* other parts of the code may expect the pointer to not move */
297                 save_seek = lseek64(input_fd, 0, SEEK_CUR);
298
299                 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET);
300                 if (ret < 0)
301                         die("failed to lseek");
302                 ret = read(input_fd, cpu_data[cpu].page, page_size);
303                 if (ret < 0)
304                         die("failed to read page");
305
306                 /* reset the file pointer back */
307                 lseek64(input_fd, save_seek, SEEK_SET);
308
309                 return;
310         }
311
312         munmap(cpu_data[cpu].page, page_size);
313         cpu_data[cpu].page = NULL;
314
315         if (cpu_data[cpu].size <= page_size)
316                 return;
317
318         update_cpu_data_index(cpu);
319
320         cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE,
321                                   input_fd, cpu_data[cpu].offset);
322         if (cpu_data[cpu].page == MAP_FAILED)
323                 die("failed to mmap cpu %d at offset 0x%llx",
324                     cpu, cpu_data[cpu].offset);
325 }
326
327 static unsigned int type_len4host(unsigned int type_len_ts)
328 {
329         if (file_bigendian)
330                 return (type_len_ts >> 27) & ((1 << 5) - 1);
331         else
332                 return type_len_ts & ((1 << 5) - 1);
333 }
334
335 static unsigned int ts4host(unsigned int type_len_ts)
336 {
337         if (file_bigendian)
338                 return type_len_ts & ((1 << 27) - 1);
339         else
340                 return type_len_ts >> 5;
341 }
342
343 static int calc_index(void *ptr, int cpu)
344 {
345         return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
346 }
347
348 struct record *trace_peek_data(int cpu)
349 {
350         struct record *data;
351         void *page = cpu_data[cpu].page;
352         int idx = cpu_data[cpu].index;
353         void *ptr = page + idx;
354         unsigned long long extend;
355         unsigned int type_len_ts;
356         unsigned int type_len;
357         unsigned int delta;
358         unsigned int length = 0;
359
360         if (cpu_data[cpu].next)
361                 return cpu_data[cpu].next;
362
363         if (!page)
364                 return NULL;
365
366         if (!idx) {
367                 /* FIXME: handle header page */
368                 if (header_page_ts_size != 8)
369                         die("expected a long long type for timestamp");
370                 cpu_data[cpu].timestamp = data2host8(ptr);
371                 ptr += 8;
372                 switch (header_page_size_size) {
373                 case 4:
374                         cpu_data[cpu].page_size = data2host4(ptr);
375                         ptr += 4;
376                         break;
377                 case 8:
378                         cpu_data[cpu].page_size = data2host8(ptr);
379                         ptr += 8;
380                         break;
381                 default:
382                         die("bad long size");
383                 }
384                 ptr = cpu_data[cpu].page + header_page_data_offset;
385         }
386
387 read_again:
388         idx = calc_index(ptr, cpu);
389
390         if (idx >= cpu_data[cpu].page_size) {
391                 get_next_page(cpu);
392                 return trace_peek_data(cpu);
393         }
394
395         type_len_ts = data2host4(ptr);
396         ptr += 4;
397
398         type_len = type_len4host(type_len_ts);
399         delta = ts4host(type_len_ts);
400
401         switch (type_len) {
402         case RINGBUF_TYPE_PADDING:
403                 if (!delta)
404                         die("error, hit unexpected end of page");
405                 length = data2host4(ptr);
406                 ptr += 4;
407                 length *= 4;
408                 ptr += length;
409                 goto read_again;
410
411         case RINGBUF_TYPE_TIME_EXTEND:
412                 extend = data2host4(ptr);
413                 ptr += 4;
414                 extend <<= TS_SHIFT;
415                 extend += delta;
416                 cpu_data[cpu].timestamp += extend;
417                 goto read_again;
418
419         case RINGBUF_TYPE_TIME_STAMP:
420                 ptr += 12;
421                 break;
422         case 0:
423                 length = data2host4(ptr);
424                 ptr += 4;
425                 die("here! length=%d", length);
426                 break;
427         default:
428                 length = type_len * 4;
429                 break;
430         }
431
432         cpu_data[cpu].timestamp += delta;
433
434         data = malloc_or_die(sizeof(*data));
435         memset(data, 0, sizeof(*data));
436
437         data->ts = cpu_data[cpu].timestamp;
438         data->size = length;
439         data->data = ptr;
440         ptr += length;
441
442         cpu_data[cpu].index = calc_index(ptr, cpu);
443         cpu_data[cpu].next = data;
444
445         return data;
446 }
447
448 struct record *trace_read_data(int cpu)
449 {
450         struct record *data;
451
452         data = trace_peek_data(cpu);
453         cpu_data[cpu].next = NULL;
454
455         return data;
456 }
457
458 void trace_report (void)
459 {
460         const char *input_file = "trace.info";
461         char buf[BUFSIZ];
462         char test[] = { 23, 8, 68 };
463         char *version;
464         int show_funcs = 0;
465         int show_printk = 0;
466
467         input_fd = open(input_file, O_RDONLY);
468         if (input_fd < 0)
469                 die("opening '%s'\n", input_file);
470
471         read_or_die(buf, 3);
472         if (memcmp(buf, test, 3) != 0)
473                 die("not an trace data file");
474
475         read_or_die(buf, 7);
476         if (memcmp(buf, "tracing", 7) != 0)
477                 die("not a trace file (missing tracing)");
478
479         version = read_string();
480         printf("version = %s\n", version);
481         free(version);
482
483         read_or_die(buf, 1);
484         file_bigendian = buf[0];
485         host_bigendian = bigendian();
486
487         read_or_die(buf, 1);
488         long_size = buf[0];
489
490         page_size = read4();
491
492         read_header_files();
493
494         read_ftrace_files();
495         read_event_files();
496         read_proc_kallsyms();
497         read_ftrace_printk();
498
499         if (show_funcs) {
500                 print_funcs();
501                 return;
502         }
503         if (show_printk) {
504                 print_printk();
505                 return;
506         }
507
508         return;
509 }