1 /* 2 * Simple trace backend 3 * 4 * Copyright IBM, Corp. 2010 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2. See 7 * the COPYING file in the top-level directory. 8 * 9 */ 10 11 #include "qemu/osdep.h" 12 #ifndef _WIN32 13 #include <pthread.h> 14 #endif 15 #include "qemu/timer.h" 16 #include "trace/control.h" 17 #include "trace/simple.h" 18 #include "qemu/error-report.h" 19 #include "qemu/qemu-print.h" 20 21 /** Trace file header event ID, picked to avoid conflict with real event IDs */ 22 #define HEADER_EVENT_ID (~(uint64_t)0) 23 24 /** Trace file magic number */ 25 #define HEADER_MAGIC 0xf2b177cb0aa429b4ULL 26 27 /** Trace file version number, bump if format changes */ 28 #define HEADER_VERSION 4 29 30 /** Records were dropped event ID */ 31 #define DROPPED_EVENT_ID (~(uint64_t)0 - 1) 32 33 /** Trace record is valid */ 34 #define TRACE_RECORD_VALID ((uint64_t)1 << 63) 35 36 /* 37 * Trace records are written out by a dedicated thread. The thread waits for 38 * records to become available, writes them out, and then waits again. 39 */ 40 static GMutex trace_lock; 41 static GCond trace_available_cond; 42 static GCond trace_empty_cond; 43 44 static bool trace_available; 45 static bool trace_writeout_enabled; 46 47 enum { 48 TRACE_BUF_LEN = 4096 * 64, 49 TRACE_BUF_FLUSH_THRESHOLD = TRACE_BUF_LEN / 4, 50 }; 51 52 uint8_t trace_buf[TRACE_BUF_LEN]; 53 static volatile gint trace_idx; 54 static unsigned int writeout_idx; 55 static volatile gint dropped_events; 56 static uint32_t trace_pid; 57 static FILE *trace_fp; 58 static char *trace_file_name; 59 60 #define TRACE_RECORD_TYPE_MAPPING 0 61 #define TRACE_RECORD_TYPE_EVENT 1 62 63 /* * Trace buffer entry */ 64 typedef struct { 65 uint64_t event; /* event ID value */ 66 uint64_t timestamp_ns; 67 uint32_t length; /* in bytes */ 68 uint32_t pid; 69 uint64_t arguments[]; 70 } TraceRecord; 71 72 typedef struct { 73 uint64_t header_event_id; /* HEADER_EVENT_ID */ 74 uint64_t header_magic; /* HEADER_MAGIC */ 75 uint64_t header_version; /* HEADER_VERSION */ 76 } TraceLogHeader; 77 78 79 static void read_from_buffer(unsigned int idx, void *dataptr, size_t size); 80 static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size); 81 82 static void clear_buffer_range(unsigned int idx, size_t len) 83 { 84 uint32_t num = 0; 85 while (num < len) { 86 if (idx >= TRACE_BUF_LEN) { 87 idx = idx % TRACE_BUF_LEN; 88 } 89 trace_buf[idx++] = 0; 90 num++; 91 } 92 } 93 /** 94 * Read a trace record from the trace buffer 95 * 96 * @idx Trace buffer index 97 * @record Trace record to fill 98 * 99 * Returns false if the record is not valid. 100 */ 101 static bool get_trace_record(unsigned int idx, TraceRecord **recordptr) 102 { 103 uint64_t event_flag = 0; 104 TraceRecord record; 105 /* read the event flag to see if its a valid record */ 106 read_from_buffer(idx, &record, sizeof(event_flag)); 107 108 if (!(record.event & TRACE_RECORD_VALID)) { 109 return false; 110 } 111 112 smp_rmb(); /* read memory barrier before accessing record */ 113 /* read the record header to know record length */ 114 read_from_buffer(idx, &record, sizeof(TraceRecord)); 115 *recordptr = malloc(record.length); /* don't use g_malloc, can deadlock when traced */ 116 /* make a copy of record to avoid being overwritten */ 117 read_from_buffer(idx, *recordptr, record.length); 118 smp_rmb(); /* memory barrier before clearing valid flag */ 119 (*recordptr)->event &= ~TRACE_RECORD_VALID; 120 /* clear the trace buffer range for consumed record otherwise any byte 121 * with its MSB set may be considered as a valid event id when the writer 122 * thread crosses this range of buffer again. 123 */ 124 clear_buffer_range(idx, record.length); 125 return true; 126 } 127 128 /** 129 * Kick writeout thread 130 * 131 * @wait Whether to wait for writeout thread to complete 132 */ 133 static void flush_trace_file(bool wait) 134 { 135 g_mutex_lock(&trace_lock); 136 trace_available = true; 137 g_cond_signal(&trace_available_cond); 138 139 if (wait) { 140 g_cond_wait(&trace_empty_cond, &trace_lock); 141 } 142 143 g_mutex_unlock(&trace_lock); 144 } 145 146 static void wait_for_trace_records_available(void) 147 { 148 g_mutex_lock(&trace_lock); 149 while (!(trace_available && trace_writeout_enabled)) { 150 g_cond_signal(&trace_empty_cond); 151 g_cond_wait(&trace_available_cond, &trace_lock); 152 } 153 trace_available = false; 154 g_mutex_unlock(&trace_lock); 155 } 156 157 static gpointer writeout_thread(gpointer opaque) 158 { 159 TraceRecord *recordptr; 160 union { 161 TraceRecord rec; 162 uint8_t bytes[sizeof(TraceRecord) + sizeof(uint64_t)]; 163 } dropped; 164 unsigned int idx = 0; 165 int dropped_count; 166 size_t unused __attribute__ ((unused)); 167 uint64_t type = TRACE_RECORD_TYPE_EVENT; 168 169 for (;;) { 170 wait_for_trace_records_available(); 171 172 if (g_atomic_int_get(&dropped_events)) { 173 dropped.rec.event = DROPPED_EVENT_ID; 174 dropped.rec.timestamp_ns = get_clock(); 175 dropped.rec.length = sizeof(TraceRecord) + sizeof(uint64_t); 176 dropped.rec.pid = trace_pid; 177 do { 178 dropped_count = g_atomic_int_get(&dropped_events); 179 } while (!g_atomic_int_compare_and_exchange(&dropped_events, 180 dropped_count, 0)); 181 dropped.rec.arguments[0] = dropped_count; 182 unused = fwrite(&type, sizeof(type), 1, trace_fp); 183 unused = fwrite(&dropped.rec, dropped.rec.length, 1, trace_fp); 184 } 185 186 while (get_trace_record(idx, &recordptr)) { 187 unused = fwrite(&type, sizeof(type), 1, trace_fp); 188 unused = fwrite(recordptr, recordptr->length, 1, trace_fp); 189 writeout_idx += recordptr->length; 190 free(recordptr); /* don't use g_free, can deadlock when traced */ 191 idx = writeout_idx % TRACE_BUF_LEN; 192 } 193 194 fflush(trace_fp); 195 } 196 return NULL; 197 } 198 199 void trace_record_write_u64(TraceBufferRecord *rec, uint64_t val) 200 { 201 rec->rec_off = write_to_buffer(rec->rec_off, &val, sizeof(uint64_t)); 202 } 203 204 void trace_record_write_str(TraceBufferRecord *rec, const char *s, uint32_t slen) 205 { 206 /* Write string length first */ 207 rec->rec_off = write_to_buffer(rec->rec_off, &slen, sizeof(slen)); 208 /* Write actual string now */ 209 rec->rec_off = write_to_buffer(rec->rec_off, (void*)s, slen); 210 } 211 212 int trace_record_start(TraceBufferRecord *rec, uint32_t event, size_t datasize) 213 { 214 unsigned int idx, rec_off, old_idx, new_idx; 215 uint32_t rec_len = sizeof(TraceRecord) + datasize; 216 uint64_t event_u64 = event; 217 uint64_t timestamp_ns = get_clock(); 218 219 do { 220 old_idx = g_atomic_int_get(&trace_idx); 221 smp_rmb(); 222 new_idx = old_idx + rec_len; 223 224 if (new_idx - writeout_idx > TRACE_BUF_LEN) { 225 /* Trace Buffer Full, Event dropped ! */ 226 g_atomic_int_inc(&dropped_events); 227 return -ENOSPC; 228 } 229 } while (!g_atomic_int_compare_and_exchange(&trace_idx, old_idx, new_idx)); 230 231 idx = old_idx % TRACE_BUF_LEN; 232 233 rec_off = idx; 234 rec_off = write_to_buffer(rec_off, &event_u64, sizeof(event_u64)); 235 rec_off = write_to_buffer(rec_off, ×tamp_ns, sizeof(timestamp_ns)); 236 rec_off = write_to_buffer(rec_off, &rec_len, sizeof(rec_len)); 237 rec_off = write_to_buffer(rec_off, &trace_pid, sizeof(trace_pid)); 238 239 rec->tbuf_idx = idx; 240 rec->rec_off = (idx + sizeof(TraceRecord)) % TRACE_BUF_LEN; 241 return 0; 242 } 243 244 static void read_from_buffer(unsigned int idx, void *dataptr, size_t size) 245 { 246 uint8_t *data_ptr = dataptr; 247 uint32_t x = 0; 248 while (x < size) { 249 if (idx >= TRACE_BUF_LEN) { 250 idx = idx % TRACE_BUF_LEN; 251 } 252 data_ptr[x++] = trace_buf[idx++]; 253 } 254 } 255 256 static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size) 257 { 258 uint8_t *data_ptr = dataptr; 259 uint32_t x = 0; 260 while (x < size) { 261 if (idx >= TRACE_BUF_LEN) { 262 idx = idx % TRACE_BUF_LEN; 263 } 264 trace_buf[idx++] = data_ptr[x++]; 265 } 266 return idx; /* most callers wants to know where to write next */ 267 } 268 269 void trace_record_finish(TraceBufferRecord *rec) 270 { 271 TraceRecord record; 272 read_from_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord)); 273 smp_wmb(); /* write barrier before marking as valid */ 274 record.event |= TRACE_RECORD_VALID; 275 write_to_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord)); 276 277 if (((unsigned int)g_atomic_int_get(&trace_idx) - writeout_idx) 278 > TRACE_BUF_FLUSH_THRESHOLD) { 279 flush_trace_file(false); 280 } 281 } 282 283 static int st_write_event_mapping(void) 284 { 285 uint64_t type = TRACE_RECORD_TYPE_MAPPING; 286 TraceEventIter iter; 287 TraceEvent *ev; 288 289 trace_event_iter_init(&iter, NULL); 290 while ((ev = trace_event_iter_next(&iter)) != NULL) { 291 uint64_t id = trace_event_get_id(ev); 292 const char *name = trace_event_get_name(ev); 293 uint32_t len = strlen(name); 294 if (fwrite(&type, sizeof(type), 1, trace_fp) != 1 || 295 fwrite(&id, sizeof(id), 1, trace_fp) != 1 || 296 fwrite(&len, sizeof(len), 1, trace_fp) != 1 || 297 fwrite(name, len, 1, trace_fp) != 1) { 298 return -1; 299 } 300 } 301 302 return 0; 303 } 304 305 void st_set_trace_file_enabled(bool enable) 306 { 307 if (enable == !!trace_fp) { 308 return; /* no change */ 309 } 310 311 /* Halt trace writeout */ 312 flush_trace_file(true); 313 trace_writeout_enabled = false; 314 flush_trace_file(true); 315 316 if (enable) { 317 static const TraceLogHeader header = { 318 .header_event_id = HEADER_EVENT_ID, 319 .header_magic = HEADER_MAGIC, 320 /* Older log readers will check for version at next location */ 321 .header_version = HEADER_VERSION, 322 }; 323 324 trace_fp = fopen(trace_file_name, "wb"); 325 if (!trace_fp) { 326 return; 327 } 328 329 if (fwrite(&header, sizeof header, 1, trace_fp) != 1 || 330 st_write_event_mapping() < 0) { 331 fclose(trace_fp); 332 trace_fp = NULL; 333 return; 334 } 335 336 /* Resume trace writeout */ 337 trace_writeout_enabled = true; 338 flush_trace_file(false); 339 } else { 340 fclose(trace_fp); 341 trace_fp = NULL; 342 } 343 } 344 345 /** 346 * Set the name of a trace file 347 * 348 * @file The trace file name or NULL for the default name-<pid> set at 349 * config time 350 */ 351 void st_set_trace_file(const char *file) 352 { 353 st_set_trace_file_enabled(false); 354 355 g_free(trace_file_name); 356 357 if (!file) { 358 /* Type cast needed for Windows where getpid() returns an int. */ 359 trace_file_name = g_strdup_printf(CONFIG_TRACE_FILE, (pid_t)getpid()); 360 } else { 361 trace_file_name = g_strdup_printf("%s", file); 362 } 363 364 st_set_trace_file_enabled(true); 365 } 366 367 void st_print_trace_file_status(void) 368 { 369 qemu_printf("Trace file \"%s\" %s.\n", 370 trace_file_name, trace_fp ? "on" : "off"); 371 } 372 373 void st_flush_trace_buffer(void) 374 { 375 flush_trace_file(true); 376 } 377 378 /* Helper function to create a thread with signals blocked. Use glib's 379 * portable threads since QEMU abstractions cannot be used due to reentrancy in 380 * the tracer. Also note the signal masking on POSIX hosts so that the thread 381 * does not steal signals when the rest of the program wants them blocked. 382 */ 383 static GThread *trace_thread_create(GThreadFunc fn) 384 { 385 GThread *thread; 386 #ifndef _WIN32 387 sigset_t set, oldset; 388 389 sigfillset(&set); 390 pthread_sigmask(SIG_SETMASK, &set, &oldset); 391 #endif 392 393 thread = g_thread_new("trace-thread", fn, NULL); 394 395 #ifndef _WIN32 396 pthread_sigmask(SIG_SETMASK, &oldset, NULL); 397 #endif 398 399 return thread; 400 } 401 402 bool st_init(void) 403 { 404 GThread *thread; 405 406 trace_pid = getpid(); 407 408 thread = trace_thread_create(writeout_thread); 409 if (!thread) { 410 warn_report("unable to initialize simple trace backend"); 411 return false; 412 } 413 414 atexit(st_flush_trace_buffer); 415 return true; 416 } 417