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 bool open_trace_file(void)
61 if (asprintf(&filename
, CONFIG_TRACE_FILE
, getpid()) < 0) {
65 trace_fp
= fopen(filename
, "w");
70 return write_header(trace_fp
);
73 static void flush_trace_buffer(void)
79 size_t unused
; /* for when fwrite(3) is declared warn_unused_result */
80 unused
= fwrite(trace_buf
, trace_idx
* sizeof(trace_buf
[0]), 1, trace_fp
);
83 /* Discard written trace records */
87 void st_set_trace_file_enabled(bool enable
)
89 if (enable
== trace_file_enabled
) {
90 return; /* no change */
93 /* Flush/discard trace buffer */
94 st_flush_trace_buffer();
96 /* To disable, close trace file */
102 trace_file_enabled
= enable
;
105 static void trace(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
,
106 uint64_t x4
, uint64_t x5
, uint64_t x6
)
108 TraceRecord
*rec
= &trace_buf
[trace_idx
];
111 /* TODO Windows? It would be good to use qemu-timer here but that isn't
112 * linked into qemu-tools. Also we should avoid recursion in the tracing
113 * code, therefore it is useful to be self-contained.
115 clock_gettime(CLOCK_MONOTONIC
, &ts
);
117 if (!trace_list
[event
].state
) {
122 rec
->timestamp_ns
= ts
.tv_sec
* 1000000000LL + ts
.tv_nsec
;
130 if (++trace_idx
== TRACE_BUF_LEN
) {
131 flush_trace_buffer();
135 void trace0(TraceEventID event
)
137 trace(event
, 0, 0, 0, 0, 0, 0);
140 void trace1(TraceEventID event
, uint64_t x1
)
142 trace(event
, x1
, 0, 0, 0, 0, 0);
145 void trace2(TraceEventID event
, uint64_t x1
, uint64_t x2
)
147 trace(event
, x1
, x2
, 0, 0, 0, 0);
150 void trace3(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
)
152 trace(event
, x1
, x2
, x3
, 0, 0, 0);
155 void trace4(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
, uint64_t x4
)
157 trace(event
, x1
, x2
, x3
, x4
, 0, 0);
160 void trace5(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
, uint64_t x4
, uint64_t x5
)
162 trace(event
, x1
, x2
, x3
, x4
, x5
, 0);
165 void trace6(TraceEventID event
, uint64_t x1
, uint64_t x2
, uint64_t x3
, uint64_t x4
, uint64_t x5
, uint64_t x6
)
167 trace(event
, x1
, x2
, x3
, x4
, x5
, x6
);
171 * Flush the trace buffer on exit
173 static void __attribute__((constructor
)) st_init(void)
175 atexit(st_flush_trace_buffer
);
178 void st_print_trace(FILE *stream
, int (*stream_printf
)(FILE *stream
, const char *fmt
, ...))
182 for (i
= 0; i
< trace_idx
; i
++) {
183 stream_printf(stream
, "Event %lu : %lx %lx %lx %lx %lx\n",
184 trace_buf
[i
].event
, trace_buf
[i
].x1
, trace_buf
[i
].x2
,
185 trace_buf
[i
].x3
, trace_buf
[i
].x4
, trace_buf
[i
].x5
);
189 void st_print_trace_events(FILE *stream
, int (*stream_printf
)(FILE *stream
, const char *fmt
, ...))
193 for (i
= 0; i
< NR_TRACE_EVENTS
; i
++) {
194 stream_printf(stream
, "%s [Event ID %u] : state %u\n",
195 trace_list
[i
].tp_name
, i
, trace_list
[i
].state
);
199 static TraceEvent
* find_trace_event_by_name(const char *tname
)
207 for (i
= 0; i
< NR_TRACE_EVENTS
; i
++) {
208 if (!strcmp(trace_list
[i
].tp_name
, tname
)) {
209 return &trace_list
[i
];
212 return NULL
; /* indicates end of list reached without a match */
215 void st_change_trace_event_state(const char *tname
, bool tstate
)
219 tp
= find_trace_event_by_name(tname
);