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

Archive Download this file



interactive