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