]> git.karo-electronics.de Git - mv-sheeva.git/blob - tools/perf/util/trace-event-info.c
35729f4c40cb7a98e891a2013d4b6e812a24237e
[mv-sheeva.git] / tools / perf / util / trace-event-info.c
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 <mntent.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/wait.h>
31 #include <pthread.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <stdbool.h>
37 #include <linux/list.h>
38 #include <linux/kernel.h>
39
40 #include "../perf.h"
41 #include "trace-event.h"
42 #include "debugfs.h"
43 #include "evsel.h"
44
45 #define VERSION "0.5"
46
47 #define _STR(x) #x
48 #define STR(x) _STR(x)
49 #define MAX_PATH 256
50
51 #define TRACE_CTRL      "tracing_on"
52 #define TRACE           "trace"
53 #define AVAILABLE       "available_tracers"
54 #define CURRENT         "current_tracer"
55 #define ITER_CTRL       "trace_options"
56 #define MAX_LATENCY     "tracing_max_latency"
57
58 unsigned int page_size;
59
60 static const char *output_file = "trace.info";
61 static int output_fd;
62
63 struct event_list {
64         struct event_list *next;
65         const char *event;
66 };
67
68 struct events {
69         struct events *sibling;
70         struct events *children;
71         struct events *next;
72         char *name;
73 };
74
75
76
77 static void die(const char *fmt, ...)
78 {
79         va_list ap;
80         int ret = errno;
81
82         if (errno)
83                 perror("trace-cmd");
84         else
85                 ret = -1;
86
87         va_start(ap, fmt);
88         fprintf(stderr, "  ");
89         vfprintf(stderr, fmt, ap);
90         va_end(ap);
91
92         fprintf(stderr, "\n");
93         exit(ret);
94 }
95
96 void *malloc_or_die(unsigned int size)
97 {
98         void *data;
99
100         data = malloc(size);
101         if (!data)
102                 die("malloc");
103         return data;
104 }
105
106 static const char *find_debugfs(void)
107 {
108         const char *path = debugfs_mount(NULL);
109
110         if (!path)
111                 die("Your kernel not support debugfs filesystem");
112
113         return path;
114 }
115
116 /*
117  * Finds the path to the debugfs/tracing
118  * Allocates the string and stores it.
119  */
120 static const char *find_tracing_dir(void)
121 {
122         static char *tracing;
123         static int tracing_found;
124         const char *debugfs;
125
126         if (tracing_found)
127                 return tracing;
128
129         debugfs = find_debugfs();
130
131         tracing = malloc_or_die(strlen(debugfs) + 9);
132
133         sprintf(tracing, "%s/tracing", debugfs);
134
135         tracing_found = 1;
136         return tracing;
137 }
138
139 static char *get_tracing_file(const char *name)
140 {
141         const char *tracing;
142         char *file;
143
144         tracing = find_tracing_dir();
145         if (!tracing)
146                 return NULL;
147
148         file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
149
150         sprintf(file, "%s/%s", tracing, name);
151         return file;
152 }
153
154 static void put_tracing_file(char *file)
155 {
156         free(file);
157 }
158
159 static ssize_t calc_data_size;
160
161 static ssize_t write_or_die(const void *buf, size_t len)
162 {
163         int ret;
164
165         if (calc_data_size) {
166                 calc_data_size += len;
167                 return len;
168         }
169
170         ret = write(output_fd, buf, len);
171         if (ret < 0)
172                 die("writing to '%s'", output_file);
173
174         return ret;
175 }
176
177 int bigendian(void)
178 {
179         unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
180         unsigned int *ptr;
181
182         ptr = (unsigned int *)(void *)str;
183         return *ptr == 0x01020304;
184 }
185
186 static unsigned long long copy_file_fd(int fd)
187 {
188         unsigned long long size = 0;
189         char buf[BUFSIZ];
190         int r;
191
192         do {
193                 r = read(fd, buf, BUFSIZ);
194                 if (r > 0) {
195                         size += r;
196                         write_or_die(buf, r);
197                 }
198         } while (r > 0);
199
200         return size;
201 }
202
203 static unsigned long long copy_file(const char *file)
204 {
205         unsigned long long size = 0;
206         int fd;
207
208         fd = open(file, O_RDONLY);
209         if (fd < 0)
210                 die("Can't read '%s'", file);
211         size = copy_file_fd(fd);
212         close(fd);
213
214         return size;
215 }
216
217 static unsigned long get_size_fd(int fd)
218 {
219         unsigned long long size = 0;
220         char buf[BUFSIZ];
221         int r;
222
223         do {
224                 r = read(fd, buf, BUFSIZ);
225                 if (r > 0)
226                         size += r;
227         } while (r > 0);
228
229         lseek(fd, 0, SEEK_SET);
230
231         return size;
232 }
233
234 static unsigned long get_size(const char *file)
235 {
236         unsigned long long size = 0;
237         int fd;
238
239         fd = open(file, O_RDONLY);
240         if (fd < 0)
241                 die("Can't read '%s'", file);
242         size = get_size_fd(fd);
243         close(fd);
244
245         return size;
246 }
247
248 static void read_header_files(void)
249 {
250         unsigned long long size, check_size;
251         char *path;
252         int fd;
253
254         path = get_tracing_file("events/header_page");
255         fd = open(path, O_RDONLY);
256         if (fd < 0)
257                 die("can't read '%s'", path);
258
259         /* unfortunately, you can not stat debugfs files for size */
260         size = get_size_fd(fd);
261
262         write_or_die("header_page", 12);
263         write_or_die(&size, 8);
264         check_size = copy_file_fd(fd);
265         close(fd);
266
267         if (size != check_size)
268                 die("wrong size for '%s' size=%lld read=%lld",
269                     path, size, check_size);
270         put_tracing_file(path);
271
272         path = get_tracing_file("events/header_event");
273         fd = open(path, O_RDONLY);
274         if (fd < 0)
275                 die("can't read '%s'", path);
276
277         size = get_size_fd(fd);
278
279         write_or_die("header_event", 13);
280         write_or_die(&size, 8);
281         check_size = copy_file_fd(fd);
282         if (size != check_size)
283                 die("wrong size for '%s'", path);
284         put_tracing_file(path);
285         close(fd);
286 }
287
288 static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
289 {
290         while (tps) {
291                 if (!strcmp(sys, tps->name))
292                         return true;
293                 tps = tps->next;
294         }
295
296         return false;
297 }
298
299 static void copy_event_system(const char *sys, struct tracepoint_path *tps)
300 {
301         unsigned long long size, check_size;
302         struct dirent *dent;
303         struct stat st;
304         char *format;
305         DIR *dir;
306         int count = 0;
307         int ret;
308
309         dir = opendir(sys);
310         if (!dir)
311                 die("can't read directory '%s'", sys);
312
313         while ((dent = readdir(dir))) {
314                 if (dent->d_type != DT_DIR ||
315                     strcmp(dent->d_name, ".") == 0 ||
316                     strcmp(dent->d_name, "..") == 0 ||
317                     !name_in_tp_list(dent->d_name, tps))
318                         continue;
319                 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
320                 sprintf(format, "%s/%s/format", sys, dent->d_name);
321                 ret = stat(format, &st);
322                 free(format);
323                 if (ret < 0)
324                         continue;
325                 count++;
326         }
327
328         write_or_die(&count, 4);
329
330         rewinddir(dir);
331         while ((dent = readdir(dir))) {
332                 if (dent->d_type != DT_DIR ||
333                     strcmp(dent->d_name, ".") == 0 ||
334                     strcmp(dent->d_name, "..") == 0 ||
335                     !name_in_tp_list(dent->d_name, tps))
336                         continue;
337                 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
338                 sprintf(format, "%s/%s/format", sys, dent->d_name);
339                 ret = stat(format, &st);
340
341                 if (ret >= 0) {
342                         /* unfortunately, you can not stat debugfs files for size */
343                         size = get_size(format);
344                         write_or_die(&size, 8);
345                         check_size = copy_file(format);
346                         if (size != check_size)
347                                 die("error in size of file '%s'", format);
348                 }
349
350                 free(format);
351         }
352         closedir(dir);
353 }
354
355 static void read_ftrace_files(struct tracepoint_path *tps)
356 {
357         char *path;
358
359         path = get_tracing_file("events/ftrace");
360
361         copy_event_system(path, tps);
362
363         put_tracing_file(path);
364 }
365
366 static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
367 {
368         while (tps) {
369                 if (!strcmp(sys, tps->system))
370                         return true;
371                 tps = tps->next;
372         }
373
374         return false;
375 }
376
377 static void read_event_files(struct tracepoint_path *tps)
378 {
379         struct dirent *dent;
380         struct stat st;
381         char *path;
382         char *sys;
383         DIR *dir;
384         int count = 0;
385         int ret;
386
387         path = get_tracing_file("events");
388
389         dir = opendir(path);
390         if (!dir)
391                 die("can't read directory '%s'", path);
392
393         while ((dent = readdir(dir))) {
394                 if (dent->d_type != DT_DIR ||
395                     strcmp(dent->d_name, ".") == 0 ||
396                     strcmp(dent->d_name, "..") == 0 ||
397                     strcmp(dent->d_name, "ftrace") == 0 ||
398                     !system_in_tp_list(dent->d_name, tps))
399                         continue;
400                 count++;
401         }
402
403         write_or_die(&count, 4);
404
405         rewinddir(dir);
406         while ((dent = readdir(dir))) {
407                 if (dent->d_type != DT_DIR ||
408                     strcmp(dent->d_name, ".") == 0 ||
409                     strcmp(dent->d_name, "..") == 0 ||
410                     strcmp(dent->d_name, "ftrace") == 0 ||
411                     !system_in_tp_list(dent->d_name, tps))
412                         continue;
413                 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
414                 sprintf(sys, "%s/%s", path, dent->d_name);
415                 ret = stat(sys, &st);
416                 if (ret >= 0) {
417                         write_or_die(dent->d_name, strlen(dent->d_name) + 1);
418                         copy_event_system(sys, tps);
419                 }
420                 free(sys);
421         }
422
423         closedir(dir);
424         put_tracing_file(path);
425 }
426
427 static void read_proc_kallsyms(void)
428 {
429         unsigned int size, check_size;
430         const char *path = "/proc/kallsyms";
431         struct stat st;
432         int ret;
433
434         ret = stat(path, &st);
435         if (ret < 0) {
436                 /* not found */
437                 size = 0;
438                 write_or_die(&size, 4);
439                 return;
440         }
441         size = get_size(path);
442         write_or_die(&size, 4);
443         check_size = copy_file(path);
444         if (size != check_size)
445                 die("error in size of file '%s'", path);
446
447 }
448
449 static void read_ftrace_printk(void)
450 {
451         unsigned int size, check_size;
452         char *path;
453         struct stat st;
454         int ret;
455
456         path = get_tracing_file("printk_formats");
457         ret = stat(path, &st);
458         if (ret < 0) {
459                 /* not found */
460                 size = 0;
461                 write_or_die(&size, 4);
462                 goto out;
463         }
464         size = get_size(path);
465         write_or_die(&size, 4);
466         check_size = copy_file(path);
467         if (size != check_size)
468                 die("error in size of file '%s'", path);
469 out:
470         put_tracing_file(path);
471 }
472
473 static struct tracepoint_path *
474 get_tracepoints_path(struct list_head *pattrs)
475 {
476         struct tracepoint_path path, *ppath = &path;
477         struct perf_evsel *pos;
478         int nr_tracepoints = 0;
479
480         list_for_each_entry(pos, pattrs, node) {
481                 if (pos->attr.type != PERF_TYPE_TRACEPOINT)
482                         continue;
483                 ++nr_tracepoints;
484                 ppath->next = tracepoint_id_to_path(pos->attr.config);
485                 if (!ppath->next)
486                         die("%s\n", "No memory to alloc tracepoints list");
487                 ppath = ppath->next;
488         }
489
490         return nr_tracepoints > 0 ? path.next : NULL;
491 }
492
493 bool have_tracepoints(struct list_head *pattrs)
494 {
495         struct perf_evsel *pos;
496
497         list_for_each_entry(pos, pattrs, node)
498                 if (pos->attr.type == PERF_TYPE_TRACEPOINT)
499                         return true;
500
501         return false;
502 }
503
504 int read_tracing_data(int fd, struct list_head *pattrs)
505 {
506         char buf[BUFSIZ];
507         struct tracepoint_path *tps = get_tracepoints_path(pattrs);
508
509         /*
510          * What? No tracepoints? No sense writing anything here, bail out.
511          */
512         if (tps == NULL)
513                 return -1;
514
515         output_fd = fd;
516
517         buf[0] = 23;
518         buf[1] = 8;
519         buf[2] = 68;
520         memcpy(buf + 3, "tracing", 7);
521
522         write_or_die(buf, 10);
523
524         write_or_die(VERSION, strlen(VERSION) + 1);
525
526         /* save endian */
527         if (bigendian())
528                 buf[0] = 1;
529         else
530                 buf[0] = 0;
531
532         write_or_die(buf, 1);
533
534         /* save size of long */
535         buf[0] = sizeof(long);
536         write_or_die(buf, 1);
537
538         /* save page_size */
539         page_size = sysconf(_SC_PAGESIZE);
540         write_or_die(&page_size, 4);
541
542         read_header_files();
543         read_ftrace_files(tps);
544         read_event_files(tps);
545         read_proc_kallsyms();
546         read_ftrace_printk();
547
548         return 0;
549 }
550
551 ssize_t read_tracing_data_size(int fd, struct list_head *pattrs)
552 {
553         ssize_t size;
554         int err = 0;
555
556         calc_data_size = 1;
557         err = read_tracing_data(fd, pattrs);
558         size = calc_data_size - 1;
559         calc_data_size = 0;
560
561         if (err < 0)
562                 return err;
563
564         return size;
565 }