GCDAProfiling.c revision 7bb5d49a6402c5a1d20911e6992ebb7e9e4468c4
1/*===- GCDAProfiling.c - Support library for GCDA file emission -----------===*\ 2|* 3|* The LLVM Compiler Infrastructure 4|* 5|* This file is distributed under the University of Illinois Open Source 6|* License. See LICENSE.TXT for details. 7|* 8|*===----------------------------------------------------------------------===*| 9|* 10|* This file implements the call back routines for the gcov profiling 11|* instrumentation pass. Link against this library when running code through 12|* the -insert-gcov-profiling LLVM pass. 13|* 14|* We emit files in a corrupt version of GCOV's "gcda" file format. These files 15|* are only close enough that LCOV will happily parse them. Anything that lcov 16|* ignores is missing. 17|* 18|* TODO: gcov is multi-process safe by having each exit open the existing file 19|* and append to it. We'd like to achieve that and be thread-safe too. 20|* 21\*===----------------------------------------------------------------------===*/ 22 23#include <errno.h> 24#include <fcntl.h> 25#include <stdio.h> 26#include <stdlib.h> 27#include <string.h> 28#include <sys/stat.h> 29#include <sys/mman.h> 30#include <sys/types.h> 31#ifdef _WIN32 32#include <direct.h> 33#endif 34 35#ifndef _MSC_VER 36#include <stdint.h> 37#else 38typedef unsigned int uint32_t; 39typedef unsigned int uint64_t; 40#endif 41 42/* #define DEBUG_GCDAPROFILING */ 43 44/* 45 * --- GCOV file format I/O primitives --- 46 */ 47 48/* 49 * The current file name we're outputting. Used primarily for error logging. 50 */ 51static char *filename = NULL; 52 53/* 54 * The current file we're outputting. 55 */ 56static FILE *output_file = NULL; 57 58/* 59 * Buffer that we write things into. 60 */ 61#define WRITE_BUFFER_SIZE (128 * 1024) 62static char *write_buffer = NULL; 63static uint64_t cur_buffer_size = 0; 64static uint64_t cur_pos = 0; 65static uint64_t file_size = 0; 66static int new_file = 0; 67static int fd = -1; 68 69/* 70 * A list of functions to write out the data. 71 */ 72typedef void (*writeout_fn)(); 73 74struct writeout_fn_node { 75 writeout_fn fn; 76 struct writeout_fn_node *next; 77}; 78 79static struct writeout_fn_node *writeout_fn_head = NULL; 80static struct writeout_fn_node *writeout_fn_tail = NULL; 81 82/* 83 * A list of flush functions that our __gcov_flush() function should call. 84 */ 85typedef void (*flush_fn)(); 86 87struct flush_fn_node { 88 flush_fn fn; 89 struct flush_fn_node *next; 90}; 91 92static struct flush_fn_node *flush_fn_head = NULL; 93static struct flush_fn_node *flush_fn_tail = NULL; 94 95static void resize_write_buffer(uint64_t size) { 96 if (!new_file) return; 97 size += cur_pos; 98 if (size <= cur_buffer_size) return; 99 size = (size - 1) / WRITE_BUFFER_SIZE + 1; 100 size *= WRITE_BUFFER_SIZE; 101 write_buffer = realloc(write_buffer, size); 102 cur_buffer_size = size; 103} 104 105static void write_bytes(const char *s, size_t len) { 106 resize_write_buffer(len); 107 memcpy(&write_buffer[cur_pos], s, len); 108 cur_pos += len; 109} 110 111static void write_32bit_value(uint32_t i) { 112 write_bytes((char*)&i, 4); 113} 114 115static void write_64bit_value(uint64_t i) { 116 write_bytes((char*)&i, 8); 117} 118 119static uint32_t length_of_string(const char *s) { 120 return (strlen(s) / 4) + 1; 121} 122 123static void write_string(const char *s) { 124 uint32_t len = length_of_string(s); 125 write_32bit_value(len); 126 write_bytes(s, strlen(s)); 127 write_bytes("\0\0\0\0", 4 - (strlen(s) % 4)); 128} 129 130static uint32_t read_32bit_value() { 131 uint32_t val; 132 133 if (new_file) 134 return (uint32_t)-1; 135 136 val = *(uint32_t*)&write_buffer[cur_pos]; 137 cur_pos += 4; 138 return val; 139} 140 141static uint64_t read_64bit_value() { 142 uint64_t val; 143 144 if (new_file) 145 return (uint64_t)-1; 146 147 val = *(uint64_t*)&write_buffer[cur_pos]; 148 cur_pos += 8; 149 return val; 150} 151 152static char *mangle_filename(const char *orig_filename) { 153 char *filename = 0; 154 int prefix_len = 0; 155 int prefix_strip = 0; 156 int level = 0; 157 const char *fname = orig_filename, *ptr = NULL; 158 const char *prefix = getenv("GCOV_PREFIX"); 159 const char *prefix_strip_str = getenv("GCOV_PREFIX_STRIP"); 160 161 if (!prefix) 162 return strdup(orig_filename); 163 164 if (prefix_strip_str) { 165 prefix_strip = atoi(prefix_strip_str); 166 167 /* Negative GCOV_PREFIX_STRIP values are ignored */ 168 if (prefix_strip < 0) 169 prefix_strip = 0; 170 } 171 172 prefix_len = strlen(prefix); 173 filename = malloc(prefix_len + 1 + strlen(orig_filename) + 1); 174 strcpy(filename, prefix); 175 176 if (prefix[prefix_len - 1] != '/') 177 strcat(filename, "/"); 178 179 for (ptr = fname + 1; *ptr != '\0' && level < prefix_strip; ++ptr) { 180 if (*ptr != '/') continue; 181 fname = ptr; 182 ++level; 183 } 184 185 strcat(filename, fname); 186 187 return filename; 188} 189 190static void recursive_mkdir(char *filename) { 191 int i; 192 193 for (i = 1; filename[i] != '\0'; ++i) { 194 if (filename[i] != '/') continue; 195 filename[i] = '\0'; 196#ifdef _WIN32 197 _mkdir(filename); 198#else 199 mkdir(filename, 0755); /* Some of these will fail, ignore it. */ 200#endif 201 filename[i] = '/'; 202 } 203} 204 205static int map_file() { 206 fseek(output_file, 0L, SEEK_END); 207 file_size = ftell(output_file); 208 209 /* A size of 0 is invalid to `mmap'. Return a fail here, but don't issue an 210 * error message because it should "just work" for the user. */ 211 if (file_size == 0) 212 return -1; 213 214 write_buffer = mmap(0, file_size, PROT_READ | PROT_WRITE, 215 MAP_FILE | MAP_SHARED, fd, 0); 216 if (write_buffer == (void *)-1) { 217 int errnum = errno; 218 fprintf(stderr, "profiling: %s: cannot map: %s\n", filename, 219 strerror(errnum)); 220 return -1; 221 } 222 return 0; 223} 224 225static void unmap_file() { 226 if (msync(write_buffer, file_size, MS_SYNC) == -1) { 227 int errnum = errno; 228 fprintf(stderr, "profiling: %s: cannot msync: %s\n", filename, 229 strerror(errnum)); 230 } 231 232 /* We explicitly ignore errors from unmapping because at this point the data 233 * is written and we don't care. 234 */ 235 (void)munmap(write_buffer, file_size); 236 write_buffer = NULL; 237 file_size = 0; 238} 239 240/* 241 * --- LLVM line counter API --- 242 */ 243 244/* A file in this case is a translation unit. Each .o file built with line 245 * profiling enabled will emit to a different file. Only one file may be 246 * started at a time. 247 */ 248void llvm_gcda_start_file(const char *orig_filename, const char version[4]) { 249 const char *mode = "r+b"; 250 filename = mangle_filename(orig_filename); 251 252 /* Try just opening the file. */ 253 new_file = 0; 254 fd = open(filename, O_RDWR); 255 256 if (fd == -1) { 257 /* Try opening the file, creating it if necessary. */ 258 new_file = 1; 259 mode = "w+b"; 260 fd = open(filename, O_RDWR | O_CREAT, 0644); 261 if (fd == -1) { 262 /* Try creating the directories first then opening the file. */ 263 recursive_mkdir(filename); 264 fd = open(filename, O_RDWR | O_CREAT, 0644); 265 if (fd == -1) { 266 /* Bah! It's hopeless. */ 267 int errnum = errno; 268 fprintf(stderr, "profiling: %s: cannot open: %s\n", filename, 269 strerror(errnum)); 270 return; 271 } 272 } 273 } 274 275 output_file = fdopen(fd, mode); 276 277 /* Initialize the write buffer. */ 278 write_buffer = NULL; 279 cur_buffer_size = 0; 280 cur_pos = 0; 281 282 if (new_file) { 283 resize_write_buffer(WRITE_BUFFER_SIZE); 284 memset(write_buffer, 0, WRITE_BUFFER_SIZE); 285 } else { 286 if (map_file() == -1) { 287 /* mmap failed, try to recover by clobbering */ 288 new_file = 1; 289 write_buffer = NULL; 290 cur_buffer_size = 0; 291 resize_write_buffer(WRITE_BUFFER_SIZE); 292 memset(write_buffer, 0, WRITE_BUFFER_SIZE); 293 } 294 } 295 296 /* gcda file, version, stamp LLVM. */ 297 write_bytes("adcg", 4); 298 write_bytes(version, 4); 299 write_bytes("MVLL", 4); 300 301#ifdef DEBUG_GCDAPROFILING 302 fprintf(stderr, "llvmgcda: [%s]\n", orig_filename); 303#endif 304} 305 306/* Given an array of pointers to counters (counters), increment the n-th one, 307 * where we're also given a pointer to n (predecessor). 308 */ 309void llvm_gcda_increment_indirect_counter(uint32_t *predecessor, 310 uint64_t **counters) { 311 uint64_t *counter; 312 uint32_t pred; 313 314 pred = *predecessor; 315 if (pred == 0xffffffff) 316 return; 317 counter = counters[pred]; 318 319 /* Don't crash if the pred# is out of sync. This can happen due to threads, 320 or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */ 321 if (counter) 322 ++*counter; 323#ifdef DEBUG_GCDAPROFILING 324 else 325 fprintf(stderr, 326 "llvmgcda: increment_indirect_counter counters=%08llx, pred=%u\n", 327 *counter, *predecessor); 328#endif 329} 330 331void llvm_gcda_emit_function(uint32_t ident, const char *function_name, 332 uint8_t use_extra_checksum) { 333 uint32_t len = 2; 334 335 if (use_extra_checksum) 336 len++; 337#ifdef DEBUG_GCDAPROFILING 338 fprintf(stderr, "llvmgcda: function id=0x%08x name=%s\n", ident, 339 function_name ? function_name : "NULL"); 340#endif 341 if (!output_file) return; 342 343 /* function tag */ 344 write_bytes("\0\0\0\1", 4); 345 if (function_name) 346 len += 1 + length_of_string(function_name); 347 write_32bit_value(len); 348 write_32bit_value(ident); 349 write_32bit_value(0); 350 if (use_extra_checksum) 351 write_32bit_value(0); 352 if (function_name) 353 write_string(function_name); 354} 355 356void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { 357 uint32_t i; 358 uint64_t *old_ctrs = NULL; 359 uint32_t val = 0; 360 uint64_t save_cur_pos = cur_pos; 361 362 if (!output_file) return; 363 364 val = read_32bit_value(); 365 366 if (val != (uint32_t)-1) { 367 /* There are counters present in the file. Merge them. */ 368 if (val != 0x01a10000) { 369 fprintf(stderr, "profiling:invalid arc tag (0x%08x)\n", val); 370 return; 371 } 372 373 val = read_32bit_value(); 374 if (val == (uint32_t)-1 || val / 2 != num_counters) { 375 fprintf(stderr, "profiling:invalid number of counters (%d)\n", val); 376 return; 377 } 378 379 old_ctrs = malloc(sizeof(uint64_t) * num_counters); 380 for (i = 0; i < num_counters; ++i) 381 old_ctrs[i] = read_64bit_value(); 382 } 383 384 cur_pos = save_cur_pos; 385 386 /* Counter #1 (arcs) tag */ 387 write_bytes("\0\0\xa1\1", 4); 388 write_32bit_value(num_counters * 2); 389 for (i = 0; i < num_counters; ++i) { 390 counters[i] += (old_ctrs ? old_ctrs[i] : 0); 391 write_64bit_value(counters[i]); 392 } 393 394 free(old_ctrs); 395 396#ifdef DEBUG_GCDAPROFILING 397 fprintf(stderr, "llvmgcda: %u arcs\n", num_counters); 398 for (i = 0; i < num_counters; ++i) 399 fprintf(stderr, "llvmgcda: %llu\n", (unsigned long long)counters[i]); 400#endif 401} 402 403void llvm_gcda_summary_info() { 404 const int obj_summary_len = 9; // length for gcov compatibility 405 uint32_t i; 406 uint32_t runs = 1; 407 uint32_t val = 0; 408 uint64_t save_cur_pos = cur_pos; 409 410 if (!output_file) return; 411 412 val = read_32bit_value(); 413 414 if (val != (uint32_t)-1) { 415 /* There are counters present in the file. Merge them. */ 416 if (val != 0xa1000000) { 417 fprintf(stderr, "profiling:invalid object tag (0x%08x)\n", val); 418 return; 419 } 420 421 val = read_32bit_value(); // length 422 if (val != obj_summary_len) { 423 fprintf(stderr, "profiling:invalid object length (%d)\n", val); // length 424 return; 425 } 426 427 read_32bit_value(); // checksum, unused 428 read_32bit_value(); // num, unused 429 runs += read_32bit_value(); // add previous run count to new counter 430 } 431 432 cur_pos = save_cur_pos; 433 434 /* Object summary tag */ 435 write_bytes("\0\0\0\xa1", 4); 436 write_32bit_value(obj_summary_len); 437 write_32bit_value(0); // checksum, unused 438 write_32bit_value(0); // num, unused 439 write_32bit_value(runs); 440 for (i = 3; i < obj_summary_len; ++i) 441 write_32bit_value(0); 442 443 /* Program summary tag */ 444 write_bytes("\0\0\0\xa3", 4); // tag indicates 1 program 445 write_32bit_value(0); // 0 length 446 447#ifdef DEBUG_GCDAPROFILING 448 fprintf(stderr, "llvmgcda: %u runs\n", runs); 449#endif 450} 451 452void llvm_gcda_end_file() { 453 /* Write out EOF record. */ 454 if (output_file) { 455 write_bytes("\0\0\0\0\0\0\0\0", 8); 456 457 if (new_file) { 458 fwrite(write_buffer, cur_pos, 1, output_file); 459 free(write_buffer); 460 } else { 461 unmap_file(); 462 } 463 464 fclose(output_file); 465 output_file = NULL; 466 write_buffer = NULL; 467 } 468 free(filename); 469 470#ifdef DEBUG_GCDAPROFILING 471 fprintf(stderr, "llvmgcda: -----\n"); 472#endif 473} 474 475void llvm_register_writeout_function(writeout_fn fn) { 476 struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node)); 477 new_node->fn = fn; 478 new_node->next = NULL; 479 480 if (!writeout_fn_head) { 481 writeout_fn_head = writeout_fn_tail = new_node; 482 } else { 483 writeout_fn_tail->next = new_node; 484 writeout_fn_tail = new_node; 485 } 486} 487 488void llvm_writeout_files() { 489 struct writeout_fn_node *curr = writeout_fn_head; 490 491 while (curr) { 492 curr->fn(); 493 curr = curr->next; 494 } 495} 496 497void llvm_delete_writeout_function_list() { 498 while (writeout_fn_head) { 499 struct writeout_fn_node *node = writeout_fn_head; 500 writeout_fn_head = writeout_fn_head->next; 501 free(node); 502 } 503 504 writeout_fn_head = writeout_fn_tail = NULL; 505} 506 507void llvm_register_flush_function(flush_fn fn) { 508 struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node)); 509 new_node->fn = fn; 510 new_node->next = NULL; 511 512 if (!flush_fn_head) { 513 flush_fn_head = flush_fn_tail = new_node; 514 } else { 515 flush_fn_tail->next = new_node; 516 flush_fn_tail = new_node; 517 } 518} 519 520void __gcov_flush() { 521 struct flush_fn_node *curr = flush_fn_head; 522 523 while (curr) { 524 curr->fn(); 525 curr = curr->next; 526 } 527} 528 529void llvm_delete_flush_function_list() { 530 while (flush_fn_head) { 531 struct flush_fn_node *node = flush_fn_head; 532 flush_fn_head = flush_fn_head->next; 533 free(node); 534 } 535 536 flush_fn_head = flush_fn_tail = NULL; 537} 538 539void llvm_gcov_init(writeout_fn wfn, flush_fn ffn) { 540 static int atexit_ran = 0; 541 542 if (wfn) 543 llvm_register_writeout_function(wfn); 544 545 if (ffn) 546 llvm_register_flush_function(ffn); 547 548 if (atexit_ran == 0) { 549 atexit_ran = 1; 550 551 /* Make sure we write out the data and delete the data structures. */ 552 atexit(llvm_delete_flush_function_list); 553 atexit(llvm_delete_writeout_function_list); 554 atexit(llvm_writeout_files); 555 } 556} 557