Statistics
| Branch: | Revision:

root / simpletrace.c @ f871d689

History | View | Annotate | Download (6.1 kB)

1 26f7227b Stefan Hajnoczi
/*
2 26f7227b Stefan Hajnoczi
 * Simple trace backend
3 26f7227b Stefan Hajnoczi
 *
4 26f7227b Stefan Hajnoczi
 * Copyright IBM, Corp. 2010
5 26f7227b Stefan Hajnoczi
 *
6 26f7227b Stefan Hajnoczi
 * This work is licensed under the terms of the GNU GPL, version 2.  See
7 26f7227b Stefan Hajnoczi
 * the COPYING file in the top-level directory.
8 26f7227b Stefan Hajnoczi
 *
9 26f7227b Stefan Hajnoczi
 */
10 26f7227b Stefan Hajnoczi
11 26f7227b Stefan Hajnoczi
#include <stdlib.h>
12 26f7227b Stefan Hajnoczi
#include <stdint.h>
13 26f7227b Stefan Hajnoczi
#include <stdio.h>
14 26f7227b Stefan Hajnoczi
#include <time.h>
15 26f7227b Stefan Hajnoczi
#include "trace.h"
16 26f7227b Stefan Hajnoczi
17 26f7227b Stefan Hajnoczi
/** Trace file header event ID */
18 26f7227b Stefan Hajnoczi
#define HEADER_EVENT_ID (~(uint64_t)0) /* avoids conflicting with TraceEventIDs */
19 26f7227b Stefan Hajnoczi
20 26f7227b Stefan Hajnoczi
/** Trace file magic number */
21 26f7227b Stefan Hajnoczi
#define HEADER_MAGIC 0xf2b177cb0aa429b4ULL
22 26f7227b Stefan Hajnoczi
23 26f7227b Stefan Hajnoczi
/** Trace file version number, bump if format changes */
24 26f7227b Stefan Hajnoczi
#define HEADER_VERSION 0
25 26f7227b Stefan Hajnoczi
26 26f7227b Stefan Hajnoczi
/** Trace buffer entry */
27 26f7227b Stefan Hajnoczi
typedef struct {
28 26f7227b Stefan Hajnoczi
    uint64_t event;
29 26f7227b Stefan Hajnoczi
    uint64_t timestamp_ns;
30 26f7227b Stefan Hajnoczi
    uint64_t x1;
31 26f7227b Stefan Hajnoczi
    uint64_t x2;
32 26f7227b Stefan Hajnoczi
    uint64_t x3;
33 26f7227b Stefan Hajnoczi
    uint64_t x4;
34 26f7227b Stefan Hajnoczi
    uint64_t x5;
35 26f7227b Stefan Hajnoczi
    uint64_t x6;
36 26f7227b Stefan Hajnoczi
} TraceRecord;
37 26f7227b Stefan Hajnoczi
38 26f7227b Stefan Hajnoczi
enum {
39 26f7227b Stefan Hajnoczi
    TRACE_BUF_LEN = 64 * 1024 / sizeof(TraceRecord),
40 26f7227b Stefan Hajnoczi
};
41 26f7227b Stefan Hajnoczi
42 26f7227b Stefan Hajnoczi
static TraceRecord trace_buf[TRACE_BUF_LEN];
43 26f7227b Stefan Hajnoczi
static unsigned int trace_idx;
44 26f7227b Stefan Hajnoczi
static FILE *trace_fp;
45 c5ceb523 Stefan Hajnoczi
static char *trace_file_name = NULL;
46 c5ceb523 Stefan Hajnoczi
static bool trace_file_enabled = false;
47 c5ceb523 Stefan Hajnoczi
48 c5ceb523 Stefan Hajnoczi
void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
49 c5ceb523 Stefan Hajnoczi
{
50 c5ceb523 Stefan Hajnoczi
    stream_printf(stream, "Trace file \"%s\" %s.\n",
51 c5ceb523 Stefan Hajnoczi
                  trace_file_name, trace_file_enabled ? "on" : "off");
52 c5ceb523 Stefan Hajnoczi
}
53 26f7227b Stefan Hajnoczi
54 26f7227b Stefan Hajnoczi
static bool write_header(FILE *fp)
55 26f7227b Stefan Hajnoczi
{
56 26f7227b Stefan Hajnoczi
    static const TraceRecord header = {
57 26f7227b Stefan Hajnoczi
        .event = HEADER_EVENT_ID,
58 26f7227b Stefan Hajnoczi
        .timestamp_ns = HEADER_MAGIC,
59 26f7227b Stefan Hajnoczi
        .x1 = HEADER_VERSION,
60 26f7227b Stefan Hajnoczi
    };
61 26f7227b Stefan Hajnoczi
62 26f7227b Stefan Hajnoczi
    return fwrite(&header, sizeof header, 1, fp) == 1;
63 26f7227b Stefan Hajnoczi
}
64 26f7227b Stefan Hajnoczi
65 c5ceb523 Stefan Hajnoczi
/**
66 c5ceb523 Stefan Hajnoczi
 * set_trace_file : To set the name of a trace file.
67 c5ceb523 Stefan Hajnoczi
 * @file : pointer to the name to be set.
68 c5ceb523 Stefan Hajnoczi
 *         If NULL, set to the default name-<pid> set at config time.
69 c5ceb523 Stefan Hajnoczi
 */
70 c5ceb523 Stefan Hajnoczi
bool st_set_trace_file(const char *file)
71 9410b56c Prerna Saxena
{
72 c5ceb523 Stefan Hajnoczi
    st_set_trace_file_enabled(false);
73 c5ceb523 Stefan Hajnoczi
74 c5ceb523 Stefan Hajnoczi
    free(trace_file_name);
75 c5ceb523 Stefan Hajnoczi
76 c5ceb523 Stefan Hajnoczi
    if (!file) {
77 c5ceb523 Stefan Hajnoczi
        if (asprintf(&trace_file_name, CONFIG_TRACE_FILE, getpid()) < 0) {
78 c5ceb523 Stefan Hajnoczi
            trace_file_name = NULL;
79 c5ceb523 Stefan Hajnoczi
            return false;
80 c5ceb523 Stefan Hajnoczi
        }
81 c5ceb523 Stefan Hajnoczi
    } else {
82 c5ceb523 Stefan Hajnoczi
        if (asprintf(&trace_file_name, "%s", file) < 0) {
83 c5ceb523 Stefan Hajnoczi
            trace_file_name = NULL;
84 c5ceb523 Stefan Hajnoczi
            return false;
85 c5ceb523 Stefan Hajnoczi
        }
86 9410b56c Prerna Saxena
    }
87 9410b56c Prerna Saxena
88 c5ceb523 Stefan Hajnoczi
    st_set_trace_file_enabled(true);
89 c5ceb523 Stefan Hajnoczi
    return true;
90 9410b56c Prerna Saxena
}
91 9410b56c Prerna Saxena
92 c5ceb523 Stefan Hajnoczi
static void flush_trace_file(void)
93 26f7227b Stefan Hajnoczi
{
94 c5ceb523 Stefan Hajnoczi
    /* If the trace file is not open yet, open it now */
95 26f7227b Stefan Hajnoczi
    if (!trace_fp) {
96 c5ceb523 Stefan Hajnoczi
        trace_fp = fopen(trace_file_name, "w");
97 c5ceb523 Stefan Hajnoczi
        if (!trace_fp) {
98 c5ceb523 Stefan Hajnoczi
            /* Avoid repeatedly trying to open file on failure */
99 c5ceb523 Stefan Hajnoczi
            trace_file_enabled = false;
100 c5ceb523 Stefan Hajnoczi
            return;
101 c5ceb523 Stefan Hajnoczi
        }
102 c5ceb523 Stefan Hajnoczi
        write_header(trace_fp);
103 26f7227b Stefan Hajnoczi
    }
104 c5ceb523 Stefan Hajnoczi
105 26f7227b Stefan Hajnoczi
    if (trace_fp) {
106 26f7227b Stefan Hajnoczi
        size_t unused; /* for when fwrite(3) is declared warn_unused_result */
107 26f7227b Stefan Hajnoczi
        unused = fwrite(trace_buf, trace_idx * sizeof(trace_buf[0]), 1, trace_fp);
108 26f7227b Stefan Hajnoczi
    }
109 c5ceb523 Stefan Hajnoczi
}
110 c5ceb523 Stefan Hajnoczi
111 c5ceb523 Stefan Hajnoczi
void st_flush_trace_buffer(void)
112 c5ceb523 Stefan Hajnoczi
{
113 c5ceb523 Stefan Hajnoczi
    if (trace_file_enabled) {
114 c5ceb523 Stefan Hajnoczi
        flush_trace_file();
115 c5ceb523 Stefan Hajnoczi
    }
116 26f7227b Stefan Hajnoczi
117 26f7227b Stefan Hajnoczi
    /* Discard written trace records */
118 26f7227b Stefan Hajnoczi
    trace_idx = 0;
119 26f7227b Stefan Hajnoczi
}
120 26f7227b Stefan Hajnoczi
121 26f7227b Stefan Hajnoczi
void st_set_trace_file_enabled(bool enable)
122 26f7227b Stefan Hajnoczi
{
123 26f7227b Stefan Hajnoczi
    if (enable == trace_file_enabled) {
124 26f7227b Stefan Hajnoczi
        return; /* no change */
125 26f7227b Stefan Hajnoczi
    }
126 26f7227b Stefan Hajnoczi
127 26f7227b Stefan Hajnoczi
    /* Flush/discard trace buffer */
128 26f7227b Stefan Hajnoczi
    st_flush_trace_buffer();
129 26f7227b Stefan Hajnoczi
130 26f7227b Stefan Hajnoczi
    /* To disable, close trace file */
131 26f7227b Stefan Hajnoczi
    if (!enable) {
132 26f7227b Stefan Hajnoczi
        fclose(trace_fp);
133 26f7227b Stefan Hajnoczi
        trace_fp = NULL;
134 26f7227b Stefan Hajnoczi
    }
135 26f7227b Stefan Hajnoczi
136 26f7227b Stefan Hajnoczi
    trace_file_enabled = enable;
137 26f7227b Stefan Hajnoczi
}
138 26f7227b Stefan Hajnoczi
139 26f7227b Stefan Hajnoczi
static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
140 26f7227b Stefan Hajnoczi
                  uint64_t x4, uint64_t x5, uint64_t x6)
141 26f7227b Stefan Hajnoczi
{
142 26f7227b Stefan Hajnoczi
    TraceRecord *rec = &trace_buf[trace_idx];
143 26f7227b Stefan Hajnoczi
    struct timespec ts;
144 26f7227b Stefan Hajnoczi
145 26f7227b Stefan Hajnoczi
    /* TODO Windows?  It would be good to use qemu-timer here but that isn't
146 26f7227b Stefan Hajnoczi
     * linked into qemu-tools.  Also we should avoid recursion in the tracing
147 26f7227b Stefan Hajnoczi
     * code, therefore it is useful to be self-contained.
148 26f7227b Stefan Hajnoczi
     */
149 26f7227b Stefan Hajnoczi
    clock_gettime(CLOCK_MONOTONIC, &ts);
150 26f7227b Stefan Hajnoczi
151 22890ab5 Prerna Saxena
    if (!trace_list[event].state) {
152 22890ab5 Prerna Saxena
        return;
153 22890ab5 Prerna Saxena
    }
154 22890ab5 Prerna Saxena
155 26f7227b Stefan Hajnoczi
    rec->event = event;
156 26f7227b Stefan Hajnoczi
    rec->timestamp_ns = ts.tv_sec * 1000000000LL + ts.tv_nsec;
157 26f7227b Stefan Hajnoczi
    rec->x1 = x1;
158 26f7227b Stefan Hajnoczi
    rec->x2 = x2;
159 26f7227b Stefan Hajnoczi
    rec->x3 = x3;
160 26f7227b Stefan Hajnoczi
    rec->x4 = x4;
161 26f7227b Stefan Hajnoczi
    rec->x5 = x5;
162 26f7227b Stefan Hajnoczi
    rec->x6 = x6;
163 26f7227b Stefan Hajnoczi
164 26f7227b Stefan Hajnoczi
    if (++trace_idx == TRACE_BUF_LEN) {
165 c5ceb523 Stefan Hajnoczi
        st_flush_trace_buffer();
166 26f7227b Stefan Hajnoczi
    }
167 26f7227b Stefan Hajnoczi
}
168 26f7227b Stefan Hajnoczi
169 26f7227b Stefan Hajnoczi
void trace0(TraceEventID event)
170 26f7227b Stefan Hajnoczi
{
171 26f7227b Stefan Hajnoczi
    trace(event, 0, 0, 0, 0, 0, 0);
172 26f7227b Stefan Hajnoczi
}
173 26f7227b Stefan Hajnoczi
174 26f7227b Stefan Hajnoczi
void trace1(TraceEventID event, uint64_t x1)
175 26f7227b Stefan Hajnoczi
{
176 26f7227b Stefan Hajnoczi
    trace(event, x1, 0, 0, 0, 0, 0);
177 26f7227b Stefan Hajnoczi
}
178 26f7227b Stefan Hajnoczi
179 26f7227b Stefan Hajnoczi
void trace2(TraceEventID event, uint64_t x1, uint64_t x2)
180 26f7227b Stefan Hajnoczi
{
181 26f7227b Stefan Hajnoczi
    trace(event, x1, x2, 0, 0, 0, 0);
182 26f7227b Stefan Hajnoczi
}
183 26f7227b Stefan Hajnoczi
184 26f7227b Stefan Hajnoczi
void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3)
185 26f7227b Stefan Hajnoczi
{
186 26f7227b Stefan Hajnoczi
    trace(event, x1, x2, x3, 0, 0, 0);
187 26f7227b Stefan Hajnoczi
}
188 26f7227b Stefan Hajnoczi
189 26f7227b Stefan Hajnoczi
void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4)
190 26f7227b Stefan Hajnoczi
{
191 26f7227b Stefan Hajnoczi
    trace(event, x1, x2, x3, x4, 0, 0);
192 26f7227b Stefan Hajnoczi
}
193 26f7227b Stefan Hajnoczi
194 26f7227b Stefan Hajnoczi
void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5)
195 26f7227b Stefan Hajnoczi
{
196 26f7227b Stefan Hajnoczi
    trace(event, x1, x2, x3, x4, x5, 0);
197 26f7227b Stefan Hajnoczi
}
198 26f7227b Stefan Hajnoczi
199 26f7227b Stefan Hajnoczi
void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6)
200 26f7227b Stefan Hajnoczi
{
201 26f7227b Stefan Hajnoczi
    trace(event, x1, x2, x3, x4, x5, x6);
202 26f7227b Stefan Hajnoczi
}
203 26f7227b Stefan Hajnoczi
204 26f7227b Stefan Hajnoczi
/**
205 26f7227b Stefan Hajnoczi
 * Flush the trace buffer on exit
206 26f7227b Stefan Hajnoczi
 */
207 26f7227b Stefan Hajnoczi
static void __attribute__((constructor)) st_init(void)
208 26f7227b Stefan Hajnoczi
{
209 26f7227b Stefan Hajnoczi
    atexit(st_flush_trace_buffer);
210 26f7227b Stefan Hajnoczi
}
211 22890ab5 Prerna Saxena
212 22890ab5 Prerna Saxena
void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
213 22890ab5 Prerna Saxena
{
214 22890ab5 Prerna Saxena
    unsigned int i;
215 22890ab5 Prerna Saxena
216 22890ab5 Prerna Saxena
    for (i = 0; i < trace_idx; i++) {
217 22890ab5 Prerna Saxena
        stream_printf(stream, "Event %lu : %lx %lx %lx %lx %lx\n",
218 22890ab5 Prerna Saxena
                      trace_buf[i].event, trace_buf[i].x1, trace_buf[i].x2,
219 22890ab5 Prerna Saxena
                      trace_buf[i].x3, trace_buf[i].x4, trace_buf[i].x5);
220 22890ab5 Prerna Saxena
    }
221 22890ab5 Prerna Saxena
}
222 22890ab5 Prerna Saxena
223 22890ab5 Prerna Saxena
void st_print_trace_events(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
224 22890ab5 Prerna Saxena
{
225 22890ab5 Prerna Saxena
    unsigned int i;
226 22890ab5 Prerna Saxena
227 22890ab5 Prerna Saxena
    for (i = 0; i < NR_TRACE_EVENTS; i++) {
228 22890ab5 Prerna Saxena
        stream_printf(stream, "%s [Event ID %u] : state %u\n",
229 22890ab5 Prerna Saxena
                      trace_list[i].tp_name, i, trace_list[i].state);
230 22890ab5 Prerna Saxena
    }
231 22890ab5 Prerna Saxena
}
232 22890ab5 Prerna Saxena
233 22890ab5 Prerna Saxena
static TraceEvent* find_trace_event_by_name(const char *tname)
234 22890ab5 Prerna Saxena
{
235 22890ab5 Prerna Saxena
    unsigned int i;
236 22890ab5 Prerna Saxena
237 22890ab5 Prerna Saxena
    if (!tname) {
238 22890ab5 Prerna Saxena
        return NULL;
239 22890ab5 Prerna Saxena
    }
240 22890ab5 Prerna Saxena
241 22890ab5 Prerna Saxena
    for (i = 0; i < NR_TRACE_EVENTS; i++) {
242 22890ab5 Prerna Saxena
        if (!strcmp(trace_list[i].tp_name, tname)) {
243 22890ab5 Prerna Saxena
            return &trace_list[i];
244 22890ab5 Prerna Saxena
        }
245 22890ab5 Prerna Saxena
    }
246 22890ab5 Prerna Saxena
    return NULL; /* indicates end of list reached without a match */
247 22890ab5 Prerna Saxena
}
248 22890ab5 Prerna Saxena
249 f871d689 Blue Swirl
bool st_change_trace_event_state(const char *tname, bool tstate)
250 22890ab5 Prerna Saxena
{
251 22890ab5 Prerna Saxena
    TraceEvent *tp;
252 22890ab5 Prerna Saxena
253 22890ab5 Prerna Saxena
    tp = find_trace_event_by_name(tname);
254 22890ab5 Prerna Saxena
    if (tp) {
255 22890ab5 Prerna Saxena
        tp->state = tstate;
256 f871d689 Blue Swirl
        return true;
257 22890ab5 Prerna Saxena
    }
258 f871d689 Blue Swirl
    return false;
259 22890ab5 Prerna Saxena
}