aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2009-08-17 10:18:05 -0400
committerIngo Molnar <mingo@elte.hu>2009-08-17 10:32:38 -0400
commit520509436417901f30106e021e037c75dfe5386c (patch)
tree7433a9dac06d557801bf85260f53b68431295aac /tools
parent8f28827a162fd1e8da4e96bed69b06d2606e8322 (diff)
perf tools: Add trace event debugfs IO handler
Add util/trace-event-info.c which handles ftrace file IO from debugfs and provides general helpers to fetch/save ftrace events informations. This file is a rename of the trace-cmd.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 a perf tools integration. For now, ftrace events information is saved in a separate file than the standard perf.data [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-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/trace-event-info.c491
-rw-r--r--tools/perf/util/trace-event.h238
2 files changed, 729 insertions, 0 deletions
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
new file mode 100644
index 000000000000..78adff189bba
--- /dev/null
+++ b/tools/perf/util/trace-event-info.c
@@ -0,0 +1,491 @@
1/*
2 * Copyright (C) 2008,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 _GNU_SOURCE
22#include <dirent.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdarg.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/wait.h>
30#include <pthread.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <ctype.h>
34#include <errno.h>
35
36#include "trace-event.h"
37
38
39#define VERSION "0.5"
40
41#define _STR(x) #x
42#define STR(x) _STR(x)
43#define MAX_PATH 256
44
45#define TRACE_CTRL "tracing_on"
46#define TRACE "trace"
47#define AVAILABLE "available_tracers"
48#define CURRENT "current_tracer"
49#define ITER_CTRL "trace_options"
50#define MAX_LATENCY "tracing_max_latency"
51
52unsigned int page_size;
53
54static const char *output_file = "trace.info";
55static int output_fd;
56
57struct event_list {
58 struct event_list *next;
59 const char *event;
60};
61
62struct events {
63 struct events *sibling;
64 struct events *children;
65 struct events *next;
66 char *name;
67};
68
69
70
71static void die(const char *fmt, ...)
72{
73 va_list ap;
74 int ret = errno;
75
76 if (errno)
77 perror("trace-cmd");
78 else
79 ret = -1;
80
81 va_start(ap, fmt);
82 fprintf(stderr, " ");
83 vfprintf(stderr, fmt, ap);
84 va_end(ap);
85
86 fprintf(stderr, "\n");
87 exit(ret);
88}
89
90void *malloc_or_die(unsigned int size)
91{
92 void *data;
93
94 data = malloc(size);
95 if (!data)
96 die("malloc");
97 return data;
98}
99
100static const char *find_debugfs(void)
101{
102 static char debugfs[MAX_PATH+1];
103 static int debugfs_found;
104 char type[100];
105 FILE *fp;
106
107 if (debugfs_found)
108 return debugfs;
109
110 if ((fp = fopen("/proc/mounts","r")) == NULL)
111 die("Can't open /proc/mounts for read");
112
113 while (fscanf(fp, "%*s %"
114 STR(MAX_PATH)
115 "s %99s %*s %*d %*d\n",
116 debugfs, type) == 2) {
117 if (strcmp(type, "debugfs") == 0)
118 break;
119 }
120 fclose(fp);
121
122 if (strcmp(type, "debugfs") != 0)
123 die("debugfs not mounted, please mount");
124
125 debugfs_found = 1;
126
127 return debugfs;
128}
129
130/*
131 * Finds the path to the debugfs/tracing
132 * Allocates the string and stores it.
133 */
134static const char *find_tracing_dir(void)
135{
136 static char *tracing;
137 static int tracing_found;
138 const char *debugfs;
139
140 if (tracing_found)
141 return tracing;
142
143 debugfs = find_debugfs();
144
145 tracing = malloc_or_die(strlen(debugfs) + 9);
146
147 sprintf(tracing, "%s/tracing", debugfs);
148
149 tracing_found = 1;
150 return tracing;
151}
152
153static char *get_tracing_file(const char *name)
154{
155 const char *tracing;
156 char *file;
157
158 tracing = find_tracing_dir();
159 if (!tracing)
160 return NULL;
161
162 file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
163
164 sprintf(file, "%s/%s", tracing, name);
165 return file;
166}
167
168static void put_tracing_file(char *file)
169{
170 free(file);
171}
172
173static ssize_t write_or_die(const void *buf, size_t len)
174{
175 int ret;
176
177 ret = write(output_fd, buf, len);
178 if (ret < 0)
179 die("writing to '%s'", output_file);
180
181 return ret;
182}
183
184int bigendian(void)
185{
186 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
187 unsigned int *ptr;
188
189 ptr = (unsigned int *)str;
190 return *ptr == 0x01020304;
191}
192
193static unsigned long long copy_file_fd(int fd)
194{
195 unsigned long long size = 0;
196 char buf[BUFSIZ];
197 int r;
198
199 do {
200 r = read(fd, buf, BUFSIZ);
201 if (r > 0) {
202 size += r;
203 write_or_die(buf, r);
204 }
205 } while (r > 0);
206
207 return size;
208}
209
210static unsigned long long copy_file(const char *file)
211{
212 unsigned long long size = 0;
213 int fd;
214
215 fd = open(file, O_RDONLY);
216 if (fd < 0)
217 die("Can't read '%s'", file);
218 size = copy_file_fd(fd);
219 close(fd);
220
221 return size;
222}
223
224static unsigned long get_size_fd(int fd)
225{
226 unsigned long long size = 0;
227 char buf[BUFSIZ];
228 int r;
229
230 do {
231 r = read(fd, buf, BUFSIZ);
232 if (r > 0)
233 size += r;
234 } while (r > 0);
235
236 lseek(fd, 0, SEEK_SET);
237
238 return size;
239}
240
241static unsigned long get_size(const char *file)
242{
243 unsigned long long size = 0;
244 int fd;
245
246 fd = open(file, O_RDONLY);
247 if (fd < 0)
248 die("Can't read '%s'", file);
249 size = get_size_fd(fd);
250 close(fd);
251
252 return size;
253}
254
255static void read_header_files(void)
256{
257 unsigned long long size, check_size;
258 char *path;
259 int fd;
260
261 path = get_tracing_file("events/header_page");
262 fd = open(path, O_RDONLY);
263 if (fd < 0)
264 die("can't read '%s'", path);
265
266 /* unfortunately, you can not stat debugfs files for size */
267 size = get_size_fd(fd);
268
269 write_or_die("header_page", 12);
270 write_or_die(&size, 8);
271 check_size = copy_file_fd(fd);
272 if (size != check_size)
273 die("wrong size for '%s' size=%lld read=%lld",
274 path, size, check_size);
275 put_tracing_file(path);
276
277 path = get_tracing_file("events/header_event");
278 fd = open(path, O_RDONLY);
279 if (fd < 0)
280 die("can't read '%s'", path);
281
282 size = get_size_fd(fd);
283
284 write_or_die("header_event", 13);
285 write_or_die(&size, 8);
286 check_size = copy_file_fd(fd);
287 if (size != check_size)
288 die("wrong size for '%s'", path);
289 put_tracing_file(path);
290}
291
292static void copy_event_system(const char *sys)
293{
294 unsigned long long size, check_size;
295 struct dirent *dent;
296 struct stat st;
297 char *format;
298 DIR *dir;
299 int count = 0;
300 int ret;
301
302 dir = opendir(sys);
303 if (!dir)
304 die("can't read directory '%s'", sys);
305
306 while ((dent = readdir(dir))) {
307 if (strcmp(dent->d_name, ".") == 0 ||
308 strcmp(dent->d_name, "..") == 0)
309 continue;
310 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
311 sprintf(format, "%s/%s/format", sys, dent->d_name);
312 ret = stat(format, &st);
313 free(format);
314 if (ret < 0)
315 continue;
316 count++;
317 }
318
319 write_or_die(&count, 4);
320
321 rewinddir(dir);
322 while ((dent = readdir(dir))) {
323 if (strcmp(dent->d_name, ".") == 0 ||
324 strcmp(dent->d_name, "..") == 0)
325 continue;
326 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
327 sprintf(format, "%s/%s/format", sys, dent->d_name);
328 ret = stat(format, &st);
329
330 if (ret >= 0) {
331 /* unfortunately, you can not stat debugfs files for size */
332 size = get_size(format);
333 write_or_die(&size, 8);
334 check_size = copy_file(format);
335 if (size != check_size)
336 die("error in size of file '%s'", format);
337 }
338
339 free(format);
340 }
341}
342
343static void read_ftrace_files(void)
344{
345 char *path;
346
347 path = get_tracing_file("events/ftrace");
348
349 copy_event_system(path);
350
351 put_tracing_file(path);
352}
353
354static void read_event_files(void)
355{
356 struct dirent *dent;
357 struct stat st;
358 char *path;
359 char *sys;
360 DIR *dir;
361 int count = 0;
362 int ret;
363
364 path = get_tracing_file("events");
365
366 dir = opendir(path);
367 if (!dir)
368 die("can't read directory '%s'", path);
369
370 while ((dent = readdir(dir))) {
371 if (strcmp(dent->d_name, ".") == 0 ||
372 strcmp(dent->d_name, "..") == 0 ||
373 strcmp(dent->d_name, "ftrace") == 0)
374 continue;
375 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
376 sprintf(sys, "%s/%s", path, dent->d_name);
377 ret = stat(sys, &st);
378 free(sys);
379 if (ret < 0)
380 continue;
381 if (S_ISDIR(st.st_mode))
382 count++;
383 }
384
385 write_or_die(&count, 4);
386
387 rewinddir(dir);
388 while ((dent = readdir(dir))) {
389 if (strcmp(dent->d_name, ".") == 0 ||
390 strcmp(dent->d_name, "..") == 0 ||
391 strcmp(dent->d_name, "ftrace") == 0)
392 continue;
393 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
394 sprintf(sys, "%s/%s", path, dent->d_name);
395 ret = stat(sys, &st);
396 if (ret >= 0) {
397 if (S_ISDIR(st.st_mode)) {
398 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
399 copy_event_system(sys);
400 }
401 }
402 free(sys);
403 }
404
405 put_tracing_file(path);
406}
407
408static void read_proc_kallsyms(void)
409{
410 unsigned int size, check_size;
411 const char *path = "/proc/kallsyms";
412 struct stat st;
413 int ret;
414
415 ret = stat(path, &st);
416 if (ret < 0) {
417 /* not found */
418 size = 0;
419 write_or_die(&size, 4);
420 return;
421 }
422 size = get_size(path);
423 write_or_die(&size, 4);
424 check_size = copy_file(path);
425 if (size != check_size)
426 die("error in size of file '%s'", path);
427
428}
429
430static void read_ftrace_printk(void)
431{
432 unsigned int size, check_size;
433 const char *path;
434 struct stat st;
435 int ret;
436
437 path = get_tracing_file("printk_formats");
438 ret = stat(path, &st);
439 if (ret < 0) {
440 /* not found */
441 size = 0;
442 write_or_die(&size, 4);
443 return;
444 }
445 size = get_size(path);
446 write_or_die(&size, 4);
447 check_size = copy_file(path);
448 if (size != check_size)
449 die("error in size of file '%s'", path);
450
451}
452
453void read_tracing_data(void)
454{
455 char buf[BUFSIZ];
456
457 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
458 if (output_fd < 0)
459 die("creating file '%s'", output_file);
460
461 buf[0] = 23;
462 buf[1] = 8;
463 buf[2] = 68;
464 memcpy(buf + 3, "tracing", 7);
465
466 write_or_die(buf, 10);
467
468 write_or_die(VERSION, strlen(VERSION) + 1);
469
470 /* save endian */
471 if (bigendian())
472 buf[0] = 1;
473 else
474 buf[0] = 0;
475
476 write_or_die(buf, 1);
477
478 /* save size of long */
479 buf[0] = sizeof(long);
480 write_or_die(buf, 1);
481
482 /* save page_size */
483 page_size = getpagesize();
484 write_or_die(&page_size, 4);
485
486 read_header_files();
487 read_ftrace_files();
488 read_event_files();
489 read_proc_kallsyms();
490 read_ftrace_printk();
491}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
new file mode 100644
index 000000000000..3ddb8947be8a
--- /dev/null
+++ b/tools/perf/util/trace-event.h
@@ -0,0 +1,238 @@
1#ifndef _PARSE_EVENTS_H
2#define _PARSE_EVENTS_H
3
4
5#define __unused __attribute__((unused))
6
7
8#ifndef PAGE_MASK
9#define PAGE_MASK (page_size - 1)
10#endif
11
12enum {
13 RINGBUF_TYPE_PADDING = 29,
14 RINGBUF_TYPE_TIME_EXTEND = 30,
15 RINGBUF_TYPE_TIME_STAMP = 31,
16};
17
18#ifndef TS_SHIFT
19#define TS_SHIFT 27
20#endif
21
22#define NSECS_PER_SEC 1000000000ULL
23#define NSECS_PER_USEC 1000ULL
24
25enum format_flags {
26 FIELD_IS_ARRAY = 1,
27 FIELD_IS_POINTER = 2,
28};
29
30struct format_field {
31 struct format_field *next;
32 char *type;
33 char *name;
34 int offset;
35 int size;
36 unsigned long flags;
37};
38
39struct format {
40 int nr_common;
41 int nr_fields;
42 struct format_field *common_fields;
43 struct format_field *fields;
44};
45
46struct print_arg_atom {
47 char *atom;
48};
49
50struct print_arg_string {
51 char *string;
52};
53
54struct print_arg_field {
55 char *name;
56 struct format_field *field;
57};
58
59struct print_flag_sym {
60 struct print_flag_sym *next;
61 char *value;
62 char *str;
63};
64
65struct print_arg_typecast {
66 char *type;
67 struct print_arg *item;
68};
69
70struct print_arg_flags {
71 struct print_arg *field;
72 char *delim;
73 struct print_flag_sym *flags;
74};
75
76struct print_arg_symbol {
77 struct print_arg *field;
78 struct print_flag_sym *symbols;
79};
80
81struct print_arg;
82
83struct print_arg_op {
84 char *op;
85 int prio;
86 struct print_arg *left;
87 struct print_arg *right;
88};
89
90struct print_arg_func {
91 char *name;
92 struct print_arg *args;
93};
94
95enum print_arg_type {
96 PRINT_NULL,
97 PRINT_ATOM,
98 PRINT_FIELD,
99 PRINT_FLAGS,
100 PRINT_SYMBOL,
101 PRINT_TYPE,
102 PRINT_STRING,
103 PRINT_OP,
104};
105
106struct print_arg {
107 struct print_arg *next;
108 enum print_arg_type type;
109 union {
110 struct print_arg_atom atom;
111 struct print_arg_field field;
112 struct print_arg_typecast typecast;
113 struct print_arg_flags flags;
114 struct print_arg_symbol symbol;
115 struct print_arg_func func;
116 struct print_arg_string string;
117 struct print_arg_op op;
118 };
119};
120
121struct print_fmt {
122 char *format;
123 struct print_arg *args;
124};
125
126struct event {
127 struct event *next;
128 char *name;
129 int id;
130 int flags;
131 struct format format;
132 struct print_fmt print_fmt;
133};
134
135enum {
136 EVENT_FL_ISFTRACE = 1,
137 EVENT_FL_ISPRINT = 2,
138 EVENT_FL_ISBPRINT = 4,
139 EVENT_FL_ISFUNC = 8,
140 EVENT_FL_ISFUNCENT = 16,
141 EVENT_FL_ISFUNCRET = 32,
142};
143
144struct record {
145 unsigned long long ts;
146 int size;
147 void *data;
148};
149
150struct record *trace_peek_data(int cpu);
151struct record *trace_read_data(int cpu);
152
153void parse_set_info(int nr_cpus, int long_sz);
154
155void trace_report(void);
156
157void *malloc_or_die(unsigned int size);
158
159void parse_cmdlines(char *file, int size);
160void parse_proc_kallsyms(char *file, unsigned int size);
161void parse_ftrace_printk(char *file, unsigned int size);
162
163void print_funcs(void);
164void print_printk(void);
165
166int parse_ftrace_file(char *buf, unsigned long size);
167int parse_event_file(char *buf, unsigned long size, char *system);
168void print_event(int cpu, void *data, int size, unsigned long long nsecs,
169 char *comm);
170
171extern int file_bigendian;
172extern int host_bigendian;
173
174int bigendian(void);
175
176static inline unsigned short __data2host2(unsigned short data)
177{
178 unsigned short swap;
179
180 if (host_bigendian == file_bigendian)
181 return data;
182
183 swap = ((data & 0xffULL) << 8) |
184 ((data & (0xffULL << 8)) >> 8);
185
186 return swap;
187}
188
189static inline unsigned int __data2host4(unsigned int data)
190{
191 unsigned int swap;
192
193 if (host_bigendian == file_bigendian)
194 return data;
195
196 swap = ((data & 0xffULL) << 24) |
197 ((data & (0xffULL << 8)) << 8) |
198 ((data & (0xffULL << 16)) >> 8) |
199 ((data & (0xffULL << 24)) >> 24);
200
201 return swap;
202}
203
204static inline unsigned long long __data2host8(unsigned long long data)
205{
206 unsigned long long swap;
207
208 if (host_bigendian == file_bigendian)
209 return data;
210
211 swap = ((data & 0xffULL) << 56) |
212 ((data & (0xffULL << 8)) << 40) |
213 ((data & (0xffULL << 16)) << 24) |
214 ((data & (0xffULL << 24)) << 8) |
215 ((data & (0xffULL << 32)) >> 8) |
216 ((data & (0xffULL << 40)) >> 24) |
217 ((data & (0xffULL << 48)) >> 40) |
218 ((data & (0xffULL << 56)) >> 56);
219
220 return swap;
221}
222
223#define data2host2(ptr) __data2host2(*(unsigned short *)ptr)
224#define data2host4(ptr) __data2host4(*(unsigned int *)ptr)
225#define data2host8(ptr) __data2host8(*(unsigned long long *)ptr)
226
227extern int header_page_ts_offset;
228extern int header_page_ts_size;
229extern int header_page_size_offset;
230extern int header_page_size_size;
231extern int header_page_data_offset;
232extern int header_page_data_size;
233
234int parse_header_page(char *buf, unsigned long size);
235
236void read_tracing_data(void);
237
238#endif /* _PARSE_EVENTS_H */