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.
15 #include "qemu-timer.h"
18 /** Trace file header event ID */
19 #define HEADER_EVENT_ID (~(uint64_t)0) /* avoids conflicting with TraceEventIDs */
21 /** Trace file magic number */
22 #define HEADER_MAGIC 0xf2b177cb0aa429b4ULL
24 /** Trace file version number, bump if format changes */
25 #define HEADER_VERSION 0
27 /** Trace buffer entry */
30 uint64_t timestamp_ns
;
40 TRACE_BUF_LEN
= 64 * 1024 / sizeof(TraceRecord
),
43 static TraceRecord trace_buf
[TRACE_BUF_LEN
];
44 static unsigned int trace_idx
;
45 static FILE *trace_fp
;
46 static char *trace_file_name
= NULL
;
47 static bool trace_file_enabled
= false;
49 void st_print_trace_file_status(FILE *stream
, int (*stream_printf
)(FILE *stream
, const char *fmt
, ...))
51 stream_printf(stream
, "Trace file \"%s\" %s.\n",
52 trace_file_name
, trace_file_enabled
? "on" : "off");
55 static bool write_header(FILE *fp
)
57 static const TraceRecord header
= {
58 .event
= HEADER_EVENT_ID
,
59 .timestamp_ns
= HEADER_MAGIC
,
63 return fwrite(&header
, sizeof header
, 1, fp
) == 1;
67 * set_trace_file : To set the name of a trace file.
68 * @file : pointer to the name to be set.
69 * If NULL, set to the default name-<pid> set at config time.
71 bool st_set_trace_file(const char *file
)
73 st_set_trace_file_enabled(false);
75 free(trace_file_name
);
78 if (asprintf(&trace_file_name
, CONFIG_TRACE_FILE
, getpid()) < 0) {
79 trace_file_name
= NULL
;
83 if (asprintf(&trace_file_name
, "%s", file
) < 0) {
84 trace_file_name
= NULL
;
89 st_set_trace_file_enabled(true);
93 static void flush_trace_file(void)
95 /* If the trace file is not open yet, open it now */
97 trace_fp
= fopen(trace_file_name
, "w");
99 /* Avoid repeatedly trying to open file on failure */
100 trace_file_enabled
= false;
103 write_header(trace_fp
);
107 size_t unused
; /* for when fwrite(3) is declared warn_unused_result */
108 unused
= fwrite(trace_buf
, trace_idx
* sizeof(trace_buf
[0]), 1, trace_fp
);
112 void st_flush_trace_buffer(void)
114 if (trace_file_enabled
) {
118 /* Discard written trace records */
122 void st_set_trace_file_enabled(bool enable
)
124 if (enable
== trace_file_enabled
) {
125 return; /* no change */
128 /* Flush/discard trace buffer */
129 st_flush_trace_buffer();
131 /* To disable, close trace file */
137 trace_file_enabled
= enable
;
140 static void trace(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
,
141 uint64_t x4
, uint64_t x5
, uint64_t x6
)
143 TraceRecord
*rec
= &trace_buf
[trace_idx
];
145 if (!trace_list
[event
].state
) {
150 rec
->timestamp_ns
= get_clock();
158 if (++trace_idx
== TRACE_BUF_LEN
) {
159 st_flush_trace_buffer();
163 void trace0(TraceEventID event
)
165 trace(event
, 0, 0, 0, 0, 0, 0);
168 void trace1(TraceEventID event
, uint64_t x1
)
170 trace(event
, x1
, 0, 0, 0, 0, 0);
173 void trace2(TraceEventID event
, uint64_t x1
, uint64_t x2
)
175 trace(event
, x1
, x2
, 0, 0, 0, 0);
178 void trace3(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
)
180 trace(event
, x1
, x2
, x3
, 0, 0, 0);
183 void trace4(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
, uint64_t x4
)
185 trace(event
, x1
, x2
, x3
, x4
, 0, 0);
188 void trace5(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
, uint64_t x4
, uint64_t x5
)
190 trace(event
, x1
, x2
, x3
, x4
, x5
, 0);
193 void trace6(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
, uint64_t x4
, uint64_t x5
, uint64_t x6
)
195 trace(event
, x1
, x2
, x3
, x4
, x5
, x6
);
199 * Flush the trace buffer on exit
201 static void __attribute__((constructor
)) st_init(void)
203 atexit(st_flush_trace_buffer
);
206 void st_print_trace(FILE *stream
, int (*stream_printf
)(FILE *stream
, const char *fmt
, ...))
210 for (i
= 0; i
< trace_idx
; i
++) {
211 stream_printf(stream
, "Event %" PRIu64
" : %" PRIx64
" %" PRIx64
212 " %" PRIx64
" %" PRIx64
" %" PRIx64
" %" PRIx64
"\n",
213 trace_buf
[i
].event
, trace_buf
[i
].x1
, trace_buf
[i
].x2
,
214 trace_buf
[i
].x3
, trace_buf
[i
].x4
, trace_buf
[i
].x5
,
219 void st_print_trace_events(FILE *stream
, int (*stream_printf
)(FILE *stream
, const char *fmt
, ...))
223 for (i
= 0; i
< NR_TRACE_EVENTS
; i
++) {
224 stream_printf(stream
, "%s [Event ID %u] : state %u\n",
225 trace_list
[i
].tp_name
, i
, trace_list
[i
].state
);
229 static TraceEvent
* find_trace_event_by_name(const char *tname
)
237 for (i
= 0; i
< NR_TRACE_EVENTS
; i
++) {
238 if (!strcmp(trace_list
[i
].tp_name
, tname
)) {
239 return &trace_list
[i
];
242 return NULL
; /* indicates end of list reached without a match */
245 bool st_change_trace_event_state(const char *tname
, bool tstate
)
249 tp
= find_trace_event_by_name(tname
);