4 * Copyright IBM, Corp. 2010
6 * This work is licensed under the terms of the GNU GPL, version 2. See
7 * the COPYING file in the top-level directory.
17 /** Trace file header event ID */
18 #define HEADER_EVENT_ID (~(uint64_t)0) /* avoids conflicting with TraceEventIDs */
20 /** Trace file magic number */
21 #define HEADER_MAGIC 0xf2b177cb0aa429b4ULL
23 /** Trace file version number, bump if format changes */
24 #define HEADER_VERSION 0
26 /** Trace buffer entry */
29 uint64_t timestamp_ns
;
39 TRACE_BUF_LEN
= 64 * 1024 / sizeof(TraceRecord
),
42 static TraceRecord trace_buf
[TRACE_BUF_LEN
];
43 static unsigned int trace_idx
;
44 static FILE *trace_fp
;
46 static bool write_header(FILE *fp
)
48 static const TraceRecord header
= {
49 .event
= HEADER_EVENT_ID
,
50 .timestamp_ns
= HEADER_MAGIC
,
54 return fwrite(&header
, sizeof header
, 1, fp
) == 1;
57 static void flush_trace_buffer(void)
60 trace_fp
= fopen("trace.log", "w");
62 write_header(trace_fp
);
66 size_t unused
; /* for when fwrite(3) is declared warn_unused_result */
67 unused
= fwrite(trace_buf
, trace_idx
* sizeof(trace_buf
[0]), 1, trace_fp
);
70 /* Discard written trace records */
74 void st_set_trace_file_enabled(bool enable
)
76 if (enable
== trace_file_enabled
) {
77 return; /* no change */
80 /* Flush/discard trace buffer */
81 st_flush_trace_buffer();
83 /* To disable, close trace file */
89 trace_file_enabled
= enable
;
92 static void trace(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
,
93 uint64_t x4
, uint64_t x5
, uint64_t x6
)
95 TraceRecord
*rec
= &trace_buf
[trace_idx
];
98 /* TODO Windows? It would be good to use qemu-timer here but that isn't
99 * linked into qemu-tools. Also we should avoid recursion in the tracing
100 * code, therefore it is useful to be self-contained.
102 clock_gettime(CLOCK_MONOTONIC
, &ts
);
104 if (!trace_list
[event
].state
) {
109 rec
->timestamp_ns
= ts
.tv_sec
* 1000000000LL + ts
.tv_nsec
;
117 if (++trace_idx
== TRACE_BUF_LEN
) {
118 flush_trace_buffer();
122 void trace0(TraceEventID event
)
124 trace(event
, 0, 0, 0, 0, 0, 0);
127 void trace1(TraceEventID event
, uint64_t x1
)
129 trace(event
, x1
, 0, 0, 0, 0, 0);
132 void trace2(TraceEventID event
, uint64_t x1
, uint64_t x2
)
134 trace(event
, x1
, x2
, 0, 0, 0, 0);
137 void trace3(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
)
139 trace(event
, x1
, x2
, x3
, 0, 0, 0);
142 void trace4(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
, uint64_t x4
)
144 trace(event
, x1
, x2
, x3
, x4
, 0, 0);
147 void trace5(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
, uint64_t x4
, uint64_t x5
)
149 trace(event
, x1
, x2
, x3
, x4
, x5
, 0);
152 void trace6(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
, uint64_t x4
, uint64_t x5
, uint64_t x6
)
154 trace(event
, x1
, x2
, x3
, x4
, x5
, x6
);
158 * Flush the trace buffer on exit
160 static void __attribute__((constructor
)) st_init(void)
162 atexit(st_flush_trace_buffer
);
165 void st_print_trace(FILE *stream
, int (*stream_printf
)(FILE *stream
, const char *fmt
, ...))
169 for (i
= 0; i
< trace_idx
; i
++) {
170 stream_printf(stream
, "Event %lu : %lx %lx %lx %lx %lx\n",
171 trace_buf
[i
].event
, trace_buf
[i
].x1
, trace_buf
[i
].x2
,
172 trace_buf
[i
].x3
, trace_buf
[i
].x4
, trace_buf
[i
].x5
);
176 void st_print_trace_events(FILE *stream
, int (*stream_printf
)(FILE *stream
, const char *fmt
, ...))
180 for (i
= 0; i
< NR_TRACE_EVENTS
; i
++) {
181 stream_printf(stream
, "%s [Event ID %u] : state %u\n",
182 trace_list
[i
].tp_name
, i
, trace_list
[i
].state
);
186 static TraceEvent
* find_trace_event_by_name(const char *tname
)
194 for (i
= 0; i
< NR_TRACE_EVENTS
; i
++) {
195 if (!strcmp(trace_list
[i
].tp_name
, tname
)) {
196 return &trace_list
[i
];
199 return NULL
; /* indicates end of list reached without a match */
202 void st_change_trace_event_state(const char *tname
, bool tstate
)
206 tp
= find_trace_event_by_name(tname
);