aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/trace-event-read.c
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2009-08-17 10:18:06 -0400
committerIngo Molnar <mingo@elte.hu>2009-08-17 10:32:38 -0400
commit538bafb5cc92a86d97b427421231f185574fe3db (patch)
tree74fa4f0bf5ccbd4e7b0bc635698b3f67e66354c9 /tools/perf/util/trace-event-read.c
parent520509436417901f30106e021e037c75dfe5386c (diff)
perf tools: Add trace event debugfs stream reader
Add util/trace-event-read.c which handles trace events informations reading. This file is a rename of the trace-read.c file from the trace-cmd tools, written by Steven Rostedt and Josh Triplett, originated from the git tree: git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git This is its perf tools integration. [ fweisbec@gmail.com: various changes for perf tools integration. ] Signed-off-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Mike Galbraith <efault@gmx.de> Cc: "Luis Claudio R. Goncalves" <lclaudio@uudg.org> Cc: Clark Williams <williams@redhat.com> Cc: Jon Masters <jonathan@jonmasters.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> Cc: Christoph Hellwig <hch@infradead.org> Cc: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> Cc: Zhaolei <zhaolei@cn.fujitsu.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Lai Jiangshan <laijs@cn.fujitsu.com> Cc: Masami Hiramatsu <mhiramat@redhat.com> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: "Frank Ch. Eigler" <fche@redhat.com> Cc: Roland McGrath <roland@redhat.com> Cc: Jason Baron <jbaron@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Jiaying Zhang <jiayingz@google.com> Cc: Anton Blanchard <anton@samba.org> LKML-Reference: <1250518688-7207-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/trace-event-read.c')
-rw-r--r--tools/perf/util/trace-event-read.c508
1 files changed, 508 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..1dac301ae54f
--- /dev/null
+++ b/tools/perf/util/trace-event-read.c
@@ -0,0 +1,508 @@
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 "util.h"
40#include "trace-event.h"
41
42static int input_fd;
43
44static int read_page;
45
46int file_bigendian;
47int host_bigendian;
48static int long_size;
49
50static unsigned long page_size;
51
52static int read_or_die(void *data, int size)
53{
54 int r;
55
56 r = read(input_fd, data, size);
57 if (r != size)
58 die("reading input file (size expected=%d received=%d)",
59 size, r);
60 return r;
61}
62
63static unsigned int read4(void)
64{
65 unsigned int data;
66
67 read_or_die(&data, 4);
68 return __data2host4(data);
69}
70
71static unsigned long long read8(void)
72{
73 unsigned long long data;
74
75 read_or_die(&data, 8);
76 return __data2host8(data);
77}
78
79static char *read_string(void)
80{
81 char buf[BUFSIZ];
82 char *str = NULL;
83 int size = 0;
84 int i;
85 int r;
86
87 for (;;) {
88 r = read(input_fd, buf, BUFSIZ);
89 if (r < 0)
90 die("reading input file");
91
92 if (!r)
93 die("no data");
94
95 for (i = 0; i < r; i++) {
96 if (!buf[i])
97 break;
98 }
99 if (i < r)
100 break;
101
102 if (str) {
103 size += BUFSIZ;
104 str = realloc(str, size);
105 if (!str)
106 die("malloc of size %d", size);
107 memcpy(str + (size - BUFSIZ), buf, BUFSIZ);
108 } else {
109 size = BUFSIZ;
110 str = malloc_or_die(size);
111 memcpy(str, buf, size);
112 }
113 }
114
115 /* move the file descriptor to the end of the string */
116 r = lseek(input_fd, -(r - (i+1)), SEEK_CUR);
117 if (r < 0)
118 die("lseek");
119
120 if (str) {
121 size += i;
122 str = realloc(str, size);
123 if (!str)
124 die("malloc of size %d", size);
125 memcpy(str + (size - i), buf, i);
126 } else {
127 size = i;
128 str = malloc_or_die(i);
129 memcpy(str, buf, i);
130 }
131
132 return str;
133}
134
135static void read_proc_kallsyms(void)
136{
137 unsigned int size;
138 char *buf;
139
140 size = read4();
141 if (!size)
142 return;
143
144 buf = malloc_or_die(size);
145 read_or_die(buf, size);
146
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{
280 off64_t save_seek;
281 off64_t ret;
282
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 */
296 save_seek = lseek64(input_fd, 0, SEEK_CUR);
297
298 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET);
299 if (ret < 0)
300 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 */
306 lseek64(input_fd, save_seek, SEEK_SET);
307
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
457void trace_report (void)
458{
459 const char *input_file = "trace.info";
460 char buf[BUFSIZ];
461 char test[] = { 23, 8, 68 };
462 char *version;
463 int show_funcs = 0;
464 int show_printk = 0;
465
466 input_fd = open(input_file, O_RDONLY);
467 if (input_fd < 0)
468 die("opening '%s'\n", input_file);
469
470 read_or_die(buf, 3);
471 if (memcmp(buf, test, 3) != 0)
472 die("not an trace data file");
473
474 read_or_die(buf, 7);
475 if (memcmp(buf, "tracing", 7) != 0)
476 die("not a trace file (missing tracing)");
477
478 version = read_string();
479 printf("version = %s\n", version);
480 free(version);
481
482 read_or_die(buf, 1);
483 file_bigendian = buf[0];
484 host_bigendian = bigendian();
485
486 read_or_die(buf, 1);
487 long_size = buf[0];
488
489 page_size = read4();
490
491 read_header_files();
492
493 read_ftrace_files();
494 read_event_files();
495 read_proc_kallsyms();
496 read_ftrace_printk();
497
498 if (show_funcs) {
499 print_funcs();
500 return;
501 }
502 if (show_printk) {
503 print_printk();
504 return;
505 }
506
507 return;
508}