Merge branch 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.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 _FILE_OFFSET_BITS 64
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 ssize_t calc_data_size;
54 static bool repipe;
55
56 /* If it fails, the next read will report it */
57 static void skip(int size)
58 {
59         lseek(input_fd, size, SEEK_CUR);
60 }
61
62 static int do_read(int fd, void *buf, int size)
63 {
64         int rsize = size;
65
66         while (size) {
67                 int ret = read(fd, buf, size);
68
69                 if (ret <= 0)
70                         return -1;
71
72                 if (repipe) {
73                         int retw = write(STDOUT_FILENO, buf, ret);
74
75                         if (retw <= 0 || retw != ret)
76                                 die("repiping input file");
77                 }
78
79                 size -= ret;
80                 buf += ret;
81         }
82
83         return rsize;
84 }
85
86 static int read_or_die(void *data, int size)
87 {
88         int r;
89
90         r = do_read(input_fd, data, size);
91         if (r <= 0)
92                 die("reading input file (size expected=%d received=%d)",
93                     size, r);
94
95         if (calc_data_size)
96                 calc_data_size += r;
97
98         return r;
99 }
100
101 static unsigned int read4(void)
102 {
103         unsigned int data;
104
105         read_or_die(&data, 4);
106         return __data2host4(data);
107 }
108
109 static unsigned long long read8(void)
110 {
111         unsigned long long data;
112
113         read_or_die(&data, 8);
114         return __data2host8(data);
115 }
116
117 static char *read_string(void)
118 {
119         char buf[BUFSIZ];
120         char *str = NULL;
121         int size = 0;
122         off_t r;
123         char c;
124
125         for (;;) {
126                 r = read(input_fd, &c, 1);
127                 if (r < 0)
128                         die("reading input file");
129
130                 if (!r)
131                         die("no data");
132
133                 if (repipe) {
134                         int retw = write(STDOUT_FILENO, &c, 1);
135
136                         if (retw <= 0 || retw != r)
137                                 die("repiping input file string");
138                 }
139
140                 buf[size++] = c;
141
142                 if (!c)
143                         break;
144         }
145
146         if (calc_data_size)
147                 calc_data_size += size;
148
149         str = malloc_or_die(size);
150         memcpy(str, buf, size);
151
152         return str;
153 }
154
155 static void read_proc_kallsyms(void)
156 {
157         unsigned int size;
158         char *buf;
159
160         size = read4();
161         if (!size)
162                 return;
163
164         buf = malloc_or_die(size + 1);
165         read_or_die(buf, size);
166         buf[size] = '\0';
167
168         parse_proc_kallsyms(buf, size);
169
170         free(buf);
171 }
172
173 static void read_ftrace_printk(void)
174 {
175         unsigned int size;
176         char *buf;
177
178         size = read4();
179         if (!size)
180                 return;
181
182         buf = malloc_or_die(size);
183         read_or_die(buf, size);
184
185         parse_ftrace_printk(buf, size);
186
187         free(buf);
188 }
189
190 static void read_header_files(void)
191 {
192         unsigned long long size;
193         char *header_event;
194         char buf[BUFSIZ];
195
196         read_or_die(buf, 12);
197
198         if (memcmp(buf, "header_page", 12) != 0)
199                 die("did not read header page");
200
201         size = read8();
202         skip(size);
203
204         /*
205          * The size field in the page is of type long,
206          * use that instead, since it represents the kernel.
207          */
208         long_size = header_page_size_size;
209
210         read_or_die(buf, 13);
211         if (memcmp(buf, "header_event", 13) != 0)
212                 die("did not read header event");
213
214         size = read8();
215         header_event = malloc_or_die(size);
216         read_or_die(header_event, size);
217         free(header_event);
218 }
219
220 static void read_ftrace_file(unsigned long long size)
221 {
222         char *buf;
223
224         buf = malloc_or_die(size);
225         read_or_die(buf, size);
226         parse_ftrace_file(buf, size);
227         free(buf);
228 }
229
230 static void read_event_file(char *sys, unsigned long long size)
231 {
232         char *buf;
233
234         buf = malloc_or_die(size);
235         read_or_die(buf, size);
236         parse_event_file(buf, size, sys);
237         free(buf);
238 }
239
240 static void read_ftrace_files(void)
241 {
242         unsigned long long size;
243         int count;
244         int i;
245
246         count = read4();
247
248         for (i = 0; i < count; i++) {
249                 size = read8();
250                 read_ftrace_file(size);
251         }
252 }
253
254 static void read_event_files(void)
255 {
256         unsigned long long size;
257         char *sys;
258         int systems;
259         int count;
260         int i,x;
261
262         systems = read4();
263
264         for (i = 0; i < systems; i++) {
265                 sys = read_string();
266
267                 count = read4();
268                 for (x=0; x < count; x++) {
269                         size = read8();
270                         read_event_file(sys, size);
271                 }
272         }
273 }
274
275 struct cpu_data {
276         unsigned long long      offset;
277         unsigned long long      size;
278         unsigned long long      timestamp;
279         struct record           *next;
280         char                    *page;
281         int                     cpu;
282         int                     index;
283         int                     page_size;
284 };
285
286 static struct cpu_data *cpu_data;
287
288 static void update_cpu_data_index(int cpu)
289 {
290         cpu_data[cpu].offset += page_size;
291         cpu_data[cpu].size -= page_size;
292         cpu_data[cpu].index = 0;
293 }
294
295 static void get_next_page(int cpu)
296 {
297         off_t save_seek;
298         off_t ret;
299
300         if (!cpu_data[cpu].page)
301                 return;
302
303         if (read_page) {
304                 if (cpu_data[cpu].size <= page_size) {
305                         free(cpu_data[cpu].page);
306                         cpu_data[cpu].page = NULL;
307                         return;
308                 }
309
310                 update_cpu_data_index(cpu);
311
312                 /* other parts of the code may expect the pointer to not move */
313                 save_seek = lseek(input_fd, 0, SEEK_CUR);
314
315                 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET);
316                 if (ret == (off_t)-1)
317                         die("failed to lseek");
318                 ret = read(input_fd, cpu_data[cpu].page, page_size);
319                 if (ret < 0)
320                         die("failed to read page");
321
322                 /* reset the file pointer back */
323                 lseek(input_fd, save_seek, SEEK_SET);
324
325                 return;
326         }
327
328         munmap(cpu_data[cpu].page, page_size);
329         cpu_data[cpu].page = NULL;
330
331         if (cpu_data[cpu].size <= page_size)
332                 return;
333
334         update_cpu_data_index(cpu);
335
336         cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE,
337                                   input_fd, cpu_data[cpu].offset);
338         if (cpu_data[cpu].page == MAP_FAILED)
339                 die("failed to mmap cpu %d at offset 0x%llx",
340                     cpu, cpu_data[cpu].offset);
341 }
342
343 static unsigned int type_len4host(unsigned int type_len_ts)
344 {
345         if (file_bigendian)
346                 return (type_len_ts >> 27) & ((1 << 5) - 1);
347         else
348                 return type_len_ts & ((1 << 5) - 1);
349 }
350
351 static unsigned int ts4host(unsigned int type_len_ts)
352 {
353         if (file_bigendian)
354                 return type_len_ts & ((1 << 27) - 1);
355         else
356                 return type_len_ts >> 5;
357 }
358
359 static int calc_index(void *ptr, int cpu)
360 {
361         return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
362 }
363
364 struct record *trace_peek_data(int cpu)
365 {
366         struct record *data;
367         void *page = cpu_data[cpu].page;
368         int idx = cpu_data[cpu].index;
369         void *ptr = page + idx;
370         unsigned long long extend;
371         unsigned int type_len_ts;
372         unsigned int type_len;
373         unsigned int delta;
374         unsigned int length = 0;
375
376         if (cpu_data[cpu].next)
377                 return cpu_data[cpu].next;
378
379         if (!page)
380                 return NULL;
381
382         if (!idx) {
383                 /* FIXME: handle header page */
384                 if (header_page_ts_size != 8)
385                         die("expected a long long type for timestamp");
386                 cpu_data[cpu].timestamp = data2host8(ptr);
387                 ptr += 8;
388                 switch (header_page_size_size) {
389                 case 4:
390                         cpu_data[cpu].page_size = data2host4(ptr);
391                         ptr += 4;
392                         break;
393                 case 8:
394                         cpu_data[cpu].page_size = data2host8(ptr);
395                         ptr += 8;
396                         break;
397                 default:
398                         die("bad long size");
399                 }
400                 ptr = cpu_data[cpu].page + header_page_data_offset;
401         }
402
403 read_again:
404         idx = calc_index(ptr, cpu);
405
406         if (idx >= cpu_data[cpu].page_size) {
407                 get_next_page(cpu);
408                 return trace_peek_data(cpu);
409         }
410
411         type_len_ts = data2host4(ptr);
412         ptr += 4;
413
414         type_len = type_len4host(type_len_ts);
415         delta = ts4host(type_len_ts);
416
417         switch (type_len) {
418         case RINGBUF_TYPE_PADDING:
419                 if (!delta)
420                         die("error, hit unexpected end of page");
421                 length = data2host4(ptr);
422                 ptr += 4;
423                 length *= 4;
424                 ptr += length;
425                 goto read_again;
426
427         case RINGBUF_TYPE_TIME_EXTEND:
428                 extend = data2host4(ptr);
429                 ptr += 4;
430                 extend <<= TS_SHIFT;
431                 extend += delta;
432                 cpu_data[cpu].timestamp += extend;
433                 goto read_again;
434
435         case RINGBUF_TYPE_TIME_STAMP:
436                 ptr += 12;
437                 break;
438         case 0:
439                 length = data2host4(ptr);
440                 ptr += 4;
441                 die("here! length=%d", length);
442                 break;
443         default:
444                 length = type_len * 4;
445                 break;
446         }
447
448         cpu_data[cpu].timestamp += delta;
449
450         data = malloc_or_die(sizeof(*data));
451         memset(data, 0, sizeof(*data));
452
453         data->ts = cpu_data[cpu].timestamp;
454         data->size = length;
455         data->data = ptr;
456         ptr += length;
457
458         cpu_data[cpu].index = calc_index(ptr, cpu);
459         cpu_data[cpu].next = data;
460
461         return data;
462 }
463
464 struct record *trace_read_data(int cpu)
465 {
466         struct record *data;
467
468         data = trace_peek_data(cpu);
469         cpu_data[cpu].next = NULL;
470
471         return data;
472 }
473
474 ssize_t trace_report(int fd, bool __repipe)
475 {
476         char buf[BUFSIZ];
477         char test[] = { 23, 8, 68 };
478         char *version;
479         int show_version = 0;
480         int show_funcs = 0;
481         int show_printk = 0;
482         ssize_t size;
483
484         calc_data_size = 1;
485         repipe = __repipe;
486
487         input_fd = fd;
488
489         read_or_die(buf, 3);
490         if (memcmp(buf, test, 3) != 0)
491                 die("no trace data in the file");
492
493         read_or_die(buf, 7);
494         if (memcmp(buf, "tracing", 7) != 0)
495                 die("not a trace file (missing 'tracing' tag)");
496
497         version = read_string();
498         if (show_version)
499                 printf("version = %s\n", version);
500         free(version);
501
502         read_or_die(buf, 1);
503         file_bigendian = buf[0];
504         host_bigendian = bigendian();
505
506         read_or_die(buf, 1);
507         long_size = buf[0];
508
509         page_size = read4();
510
511         read_header_files();
512
513         read_ftrace_files();
514         read_event_files();
515         read_proc_kallsyms();
516         read_ftrace_printk();
517
518         size = calc_data_size - 1;
519         calc_data_size = 0;
520         repipe = false;
521
522         if (show_funcs) {
523                 print_funcs();
524                 return size;
525         }
526         if (show_printk) {
527                 print_printk();
528                 return size;
529         }
530
531         return size;
532 }