blob: 44889c9b56303e410bed246a19ec5d6a2eafb141 [file] [log] [blame]
Steven Rostedt538bafb2009-08-17 16:18:06 +02001/*
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 */
Xiao Guangrongf887f302010-02-04 16:46:42 +080021#define _FILE_OFFSET_BITS 64
Steven Rostedt538bafb2009-08-17 16:18:06 +020022
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
Frederic Weisbecker1ef2ed12009-08-28 03:09:58 +020039#include "../perf.h"
Steven Rostedt538bafb2009-08-17 16:18:06 +020040#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
Tom Zanussi92155452010-04-01 23:59:21 -050053static ssize_t calc_data_size;
54
55static int do_read(int fd, void *buf, int size)
56{
57 int rsize = size;
58
59 while (size) {
60 int ret = read(fd, buf, size);
61
62 if (ret <= 0)
63 return -1;
64
65 size -= ret;
66 buf += ret;
67 }
68
69 return rsize;
70}
71
Steven Rostedt538bafb2009-08-17 16:18:06 +020072static int read_or_die(void *data, int size)
73{
74 int r;
75
Tom Zanussi92155452010-04-01 23:59:21 -050076 r = do_read(input_fd, data, size);
77 if (r <= 0)
Steven Rostedt538bafb2009-08-17 16:18:06 +020078 die("reading input file (size expected=%d received=%d)",
79 size, r);
Tom Zanussi92155452010-04-01 23:59:21 -050080
81 if (calc_data_size)
82 calc_data_size += r;
83
Steven Rostedt538bafb2009-08-17 16:18:06 +020084 return r;
85}
86
87static unsigned int read4(void)
88{
89 unsigned int data;
90
91 read_or_die(&data, 4);
92 return __data2host4(data);
93}
94
95static unsigned long long read8(void)
96{
97 unsigned long long data;
98
99 read_or_die(&data, 8);
100 return __data2host8(data);
101}
102
103static char *read_string(void)
104{
105 char buf[BUFSIZ];
106 char *str = NULL;
107 int size = 0;
Xiao Guangrongf887f302010-02-04 16:46:42 +0800108 off_t r;
Tom Zanussi92155452010-04-01 23:59:21 -0500109 char c;
Steven Rostedt538bafb2009-08-17 16:18:06 +0200110
111 for (;;) {
Tom Zanussi92155452010-04-01 23:59:21 -0500112 r = read(input_fd, &c, 1);
Steven Rostedt538bafb2009-08-17 16:18:06 +0200113 if (r < 0)
114 die("reading input file");
115
116 if (!r)
117 die("no data");
118
Tom Zanussi92155452010-04-01 23:59:21 -0500119 buf[size++] = c;
120
121 if (!c)
Steven Rostedt538bafb2009-08-17 16:18:06 +0200122 break;
Steven Rostedt538bafb2009-08-17 16:18:06 +0200123 }
124
Tom Zanussi92155452010-04-01 23:59:21 -0500125 if (calc_data_size)
126 calc_data_size += size;
Ingo Molnar6f4596d2009-09-03 16:22:45 +0200127
Tom Zanussi92155452010-04-01 23:59:21 -0500128 str = malloc_or_die(size);
129 memcpy(str, buf, size);
Steven Rostedt538bafb2009-08-17 16:18:06 +0200130
131 return str;
132}
133
134static void read_proc_kallsyms(void)
135{
136 unsigned int size;
137 char *buf;
138
139 size = read4();
140 if (!size)
141 return;
142
OGAWA Hirofumi7691b1e2009-12-06 20:10:49 +0900143 buf = malloc_or_die(size + 1);
Steven Rostedt538bafb2009-08-17 16:18:06 +0200144 read_or_die(buf, size);
OGAWA Hirofumi7691b1e2009-12-06 20:10:49 +0900145 buf[size] = '\0';
Steven Rostedt538bafb2009-08-17 16:18:06 +0200146
147 parse_proc_kallsyms(buf, size);
148
149 free(buf);
150}
151
152static void read_ftrace_printk(void)
153{
154 unsigned int size;
155 char *buf;
156
157 size = read4();
158 if (!size)
159 return;
160
161 buf = malloc_or_die(size);
162 read_or_die(buf, size);
163
164 parse_ftrace_printk(buf, size);
165
166 free(buf);
167}
168
169static void read_header_files(void)
170{
171 unsigned long long size;
172 char *header_page;
173 char *header_event;
174 char buf[BUFSIZ];
175
176 read_or_die(buf, 12);
177
178 if (memcmp(buf, "header_page", 12) != 0)
179 die("did not read header page");
180
181 size = read8();
182 header_page = malloc_or_die(size);
183 read_or_die(header_page, size);
184 parse_header_page(header_page, size);
185 free(header_page);
186
187 /*
188 * The size field in the page is of type long,
189 * use that instead, since it represents the kernel.
190 */
191 long_size = header_page_size_size;
192
193 read_or_die(buf, 13);
194 if (memcmp(buf, "header_event", 13) != 0)
195 die("did not read header event");
196
197 size = read8();
198 header_event = malloc_or_die(size);
199 read_or_die(header_event, size);
200 free(header_event);
201}
202
203static void read_ftrace_file(unsigned long long size)
204{
205 char *buf;
206
207 buf = malloc_or_die(size);
208 read_or_die(buf, size);
209 parse_ftrace_file(buf, size);
210 free(buf);
211}
212
213static void read_event_file(char *sys, unsigned long long size)
214{
215 char *buf;
216
217 buf = malloc_or_die(size);
218 read_or_die(buf, size);
219 parse_event_file(buf, size, sys);
220 free(buf);
221}
222
223static void read_ftrace_files(void)
224{
225 unsigned long long size;
226 int count;
227 int i;
228
229 count = read4();
230
231 for (i = 0; i < count; i++) {
232 size = read8();
233 read_ftrace_file(size);
234 }
235}
236
237static void read_event_files(void)
238{
239 unsigned long long size;
240 char *sys;
241 int systems;
242 int count;
243 int i,x;
244
245 systems = read4();
246
247 for (i = 0; i < systems; i++) {
248 sys = read_string();
249
250 count = read4();
251 for (x=0; x < count; x++) {
252 size = read8();
253 read_event_file(sys, size);
254 }
255 }
256}
257
258struct cpu_data {
259 unsigned long long offset;
260 unsigned long long size;
261 unsigned long long timestamp;
262 struct record *next;
263 char *page;
264 int cpu;
265 int index;
266 int page_size;
267};
268
269static struct cpu_data *cpu_data;
270
271static void update_cpu_data_index(int cpu)
272{
273 cpu_data[cpu].offset += page_size;
274 cpu_data[cpu].size -= page_size;
275 cpu_data[cpu].index = 0;
276}
277
278static void get_next_page(int cpu)
279{
Xiao Guangrongf887f302010-02-04 16:46:42 +0800280 off_t save_seek;
281 off_t ret;
Steven Rostedt538bafb2009-08-17 16:18:06 +0200282
283 if (!cpu_data[cpu].page)
284 return;
285
286 if (read_page) {
287 if (cpu_data[cpu].size <= page_size) {
288 free(cpu_data[cpu].page);
289 cpu_data[cpu].page = NULL;
290 return;
291 }
292
293 update_cpu_data_index(cpu);
294
295 /* other parts of the code may expect the pointer to not move */
Xiao Guangrongf887f302010-02-04 16:46:42 +0800296 save_seek = lseek(input_fd, 0, SEEK_CUR);
Steven Rostedt538bafb2009-08-17 16:18:06 +0200297
Xiao Guangrongf887f302010-02-04 16:46:42 +0800298 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET);
299 if (ret == (off_t)-1)
Steven Rostedt538bafb2009-08-17 16:18:06 +0200300 die("failed to lseek");
301 ret = read(input_fd, cpu_data[cpu].page, page_size);
302 if (ret < 0)
303 die("failed to read page");
304
305 /* reset the file pointer back */
Xiao Guangrongf887f302010-02-04 16:46:42 +0800306 lseek(input_fd, save_seek, SEEK_SET);
Steven Rostedt538bafb2009-08-17 16:18:06 +0200307
308 return;
309 }
310
311 munmap(cpu_data[cpu].page, page_size);
312 cpu_data[cpu].page = NULL;
313
314 if (cpu_data[cpu].size <= page_size)
315 return;
316
317 update_cpu_data_index(cpu);
318
319 cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE,
320 input_fd, cpu_data[cpu].offset);
321 if (cpu_data[cpu].page == MAP_FAILED)
322 die("failed to mmap cpu %d at offset 0x%llx",
323 cpu, cpu_data[cpu].offset);
324}
325
326static unsigned int type_len4host(unsigned int type_len_ts)
327{
328 if (file_bigendian)
329 return (type_len_ts >> 27) & ((1 << 5) - 1);
330 else
331 return type_len_ts & ((1 << 5) - 1);
332}
333
334static unsigned int ts4host(unsigned int type_len_ts)
335{
336 if (file_bigendian)
337 return type_len_ts & ((1 << 27) - 1);
338 else
339 return type_len_ts >> 5;
340}
341
342static int calc_index(void *ptr, int cpu)
343{
344 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
345}
346
347struct record *trace_peek_data(int cpu)
348{
349 struct record *data;
350 void *page = cpu_data[cpu].page;
351 int idx = cpu_data[cpu].index;
352 void *ptr = page + idx;
353 unsigned long long extend;
354 unsigned int type_len_ts;
355 unsigned int type_len;
356 unsigned int delta;
357 unsigned int length = 0;
358
359 if (cpu_data[cpu].next)
360 return cpu_data[cpu].next;
361
362 if (!page)
363 return NULL;
364
365 if (!idx) {
366 /* FIXME: handle header page */
367 if (header_page_ts_size != 8)
368 die("expected a long long type for timestamp");
369 cpu_data[cpu].timestamp = data2host8(ptr);
370 ptr += 8;
371 switch (header_page_size_size) {
372 case 4:
373 cpu_data[cpu].page_size = data2host4(ptr);
374 ptr += 4;
375 break;
376 case 8:
377 cpu_data[cpu].page_size = data2host8(ptr);
378 ptr += 8;
379 break;
380 default:
381 die("bad long size");
382 }
383 ptr = cpu_data[cpu].page + header_page_data_offset;
384 }
385
386read_again:
387 idx = calc_index(ptr, cpu);
388
389 if (idx >= cpu_data[cpu].page_size) {
390 get_next_page(cpu);
391 return trace_peek_data(cpu);
392 }
393
394 type_len_ts = data2host4(ptr);
395 ptr += 4;
396
397 type_len = type_len4host(type_len_ts);
398 delta = ts4host(type_len_ts);
399
400 switch (type_len) {
401 case RINGBUF_TYPE_PADDING:
402 if (!delta)
403 die("error, hit unexpected end of page");
404 length = data2host4(ptr);
405 ptr += 4;
406 length *= 4;
407 ptr += length;
408 goto read_again;
409
410 case RINGBUF_TYPE_TIME_EXTEND:
411 extend = data2host4(ptr);
412 ptr += 4;
413 extend <<= TS_SHIFT;
414 extend += delta;
415 cpu_data[cpu].timestamp += extend;
416 goto read_again;
417
418 case RINGBUF_TYPE_TIME_STAMP:
419 ptr += 12;
420 break;
421 case 0:
422 length = data2host4(ptr);
423 ptr += 4;
424 die("here! length=%d", length);
425 break;
426 default:
427 length = type_len * 4;
428 break;
429 }
430
431 cpu_data[cpu].timestamp += delta;
432
433 data = malloc_or_die(sizeof(*data));
434 memset(data, 0, sizeof(*data));
435
436 data->ts = cpu_data[cpu].timestamp;
437 data->size = length;
438 data->data = ptr;
439 ptr += length;
440
441 cpu_data[cpu].index = calc_index(ptr, cpu);
442 cpu_data[cpu].next = data;
443
444 return data;
445}
446
447struct record *trace_read_data(int cpu)
448{
449 struct record *data;
450
451 data = trace_peek_data(cpu);
452 cpu_data[cpu].next = NULL;
453
454 return data;
455}
456
Tom Zanussi92155452010-04-01 23:59:21 -0500457ssize_t trace_report(int fd)
Steven Rostedt538bafb2009-08-17 16:18:06 +0200458{
Steven Rostedt538bafb2009-08-17 16:18:06 +0200459 char buf[BUFSIZ];
460 char test[] = { 23, 8, 68 };
461 char *version;
Ingo Molnard9340c12009-09-12 10:08:34 +0200462 int show_version = 0;
Steven Rostedt538bafb2009-08-17 16:18:06 +0200463 int show_funcs = 0;
464 int show_printk = 0;
Tom Zanussi92155452010-04-01 23:59:21 -0500465 ssize_t size;
466
467 calc_data_size = 1;
Steven Rostedt538bafb2009-08-17 16:18:06 +0200468
Frederic Weisbecker03456a12009-10-06 23:36:47 +0200469 input_fd = fd;
Steven Rostedt538bafb2009-08-17 16:18:06 +0200470
471 read_or_die(buf, 3);
472 if (memcmp(buf, test, 3) != 0)
Arnaldo Carvalho de Meloe2561362009-11-21 14:31:26 -0200473 die("no trace data in the file");
Steven Rostedt538bafb2009-08-17 16:18:06 +0200474
475 read_or_die(buf, 7);
476 if (memcmp(buf, "tracing", 7) != 0)
Arnaldo Carvalho de Meloe2561362009-11-21 14:31:26 -0200477 die("not a trace file (missing 'tracing' tag)");
Steven Rostedt538bafb2009-08-17 16:18:06 +0200478
479 version = read_string();
Ingo Molnard9340c12009-09-12 10:08:34 +0200480 if (show_version)
481 printf("version = %s\n", version);
Steven Rostedt538bafb2009-08-17 16:18:06 +0200482 free(version);
483
484 read_or_die(buf, 1);
485 file_bigendian = buf[0];
486 host_bigendian = bigendian();
487
488 read_or_die(buf, 1);
489 long_size = buf[0];
490
491 page_size = read4();
492
493 read_header_files();
494
495 read_ftrace_files();
496 read_event_files();
497 read_proc_kallsyms();
498 read_ftrace_printk();
499
Tom Zanussi92155452010-04-01 23:59:21 -0500500 size = calc_data_size - 1;
501 calc_data_size = 0;
502
Steven Rostedt538bafb2009-08-17 16:18:06 +0200503 if (show_funcs) {
504 print_funcs();
Tom Zanussi92155452010-04-01 23:59:21 -0500505 return size;
Steven Rostedt538bafb2009-08-17 16:18:06 +0200506 }
507 if (show_printk) {
508 print_printk();
Tom Zanussi92155452010-04-01 23:59:21 -0500509 return size;
Steven Rostedt538bafb2009-08-17 16:18:06 +0200510 }
511
Tom Zanussi92155452010-04-01 23:59:21 -0500512 return size;
Steven Rostedt538bafb2009-08-17 16:18:06 +0200513}