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 | } |