aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/trace-event-read.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/trace-event-read.c')
-rw-r--r--tools/perf/util/trace-event-read.c509
1 files changed, 509 insertions, 0 deletions
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
new file mode 100644
index 000000000000..b12e4903739a
--- /dev/null
+++ b/tools/perf/util/trace-event-read.c
@@ -0,0 +1,509 @@
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
43static int input_fd;
44
45static int read_page;
46
47int file_bigendian;
48int host_bigendian;
49static int long_size;
50
51static unsigned long page_size;
52
53static 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
64static unsigned int read4(void)
65{
66 unsigned int data;
67
68 read_or_die(&data, 4);
69 return __data2host4(data);
70}
71
72static unsigned long long read8(void)
73{
74 unsigned long long data;
75
76 read_or_die(&data, 8);
77 return __data2host8(data);
78}
79
80static 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
136static 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
153static 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
170static 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
204static 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
214static 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
224static 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
238static 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
259struct 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
270static struct cpu_data *cpu_data;
271
272static 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
279static 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
327static 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
335static 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
343static int calc_index(void *ptr, int cpu)
344{
345 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
346}
347
348struct 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
387read_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
448struct 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
458void 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}