GCDAProfiling.c revision 288943
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 "InstrProfilingUtil.h" 24 25#include <errno.h> 26#include <fcntl.h> 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30#include <sys/mman.h> 31#include <sys/file.h> 32 33#define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__)) 34 35#if !defined(_MSC_VER) && !I386_FREEBSD 36#include <stdint.h> 37#endif 38 39#if defined(_MSC_VER) 40typedef unsigned int uint32_t; 41typedef unsigned long long uint64_t; 42#elif I386_FREEBSD 43/* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to 44 * FreeBSD 10, r232261) when compiled in 32-bit mode. 45 */ 46typedef unsigned char uint8_t; 47typedef unsigned int uint32_t; 48typedef unsigned long long uint64_t; 49#endif 50 51/* #define DEBUG_GCDAPROFILING */ 52 53/* 54 * --- GCOV file format I/O primitives --- 55 */ 56 57/* 58 * The current file name we're outputting. Used primarily for error logging. 59 */ 60static char *filename = NULL; 61 62/* 63 * The current file we're outputting. 64 */ 65static FILE *output_file = NULL; 66 67/* 68 * Buffer that we write things into. 69 */ 70#define WRITE_BUFFER_SIZE (128 * 1024) 71static char *write_buffer = NULL; 72static uint64_t cur_buffer_size = 0; 73static uint64_t cur_pos = 0; 74static uint64_t file_size = 0; 75static int new_file = 0; 76static int fd = -1; 77 78/* 79 * A list of functions to write out the data. 80 */ 81typedef void (*writeout_fn)(); 82 83struct writeout_fn_node { 84 writeout_fn fn; 85 struct writeout_fn_node *next; 86}; 87 88static struct writeout_fn_node *writeout_fn_head = NULL; 89static struct writeout_fn_node *writeout_fn_tail = NULL; 90 91/* 92 * A list of flush functions that our __gcov_flush() function should call. 93 */ 94typedef void (*flush_fn)(); 95 96struct flush_fn_node { 97 flush_fn fn; 98 struct flush_fn_node *next; 99}; 100 101static struct flush_fn_node *flush_fn_head = NULL; 102static struct flush_fn_node *flush_fn_tail = NULL; 103 104static void resize_write_buffer(uint64_t size) { 105 if (!new_file) return; 106 size += cur_pos; 107 if (size <= cur_buffer_size) return; 108 size = (size - 1) / WRITE_BUFFER_SIZE + 1; 109 size *= WRITE_BUFFER_SIZE; 110 write_buffer = realloc(write_buffer, size); 111 cur_buffer_size = size; 112} 113 114static void write_bytes(const char *s, size_t len) { 115 resize_write_buffer(len); 116 memcpy(&write_buffer[cur_pos], s, len); 117 cur_pos += len; 118} 119 120static void write_32bit_value(uint32_t i) { 121 write_bytes((char*)&i, 4); 122} 123 124static void write_64bit_value(uint64_t i) { 125 write_bytes((char*)&i, 8); 126} 127 128static uint32_t length_of_string(const char *s) { 129 return (strlen(s) / 4) + 1; 130} 131 132static void write_string(const char *s) { 133 uint32_t len = length_of_string(s); 134 write_32bit_value(len); 135 write_bytes(s, strlen(s)); 136 write_bytes("\0\0\0\0", 4 - (strlen(s) % 4)); 137} 138 139static uint32_t read_32bit_value() { 140 uint32_t val; 141 142 if (new_file) 143 return (uint32_t)-1; 144 145 val = *(uint32_t*)&write_buffer[cur_pos]; 146 cur_pos += 4; 147 return val; 148} 149 150static uint64_t read_64bit_value() { 151 uint64_t val; 152 153 if (new_file) 154 return (uint64_t)-1; 155 156 val = *(uint64_t*)&write_buffer[cur_pos]; 157 cur_pos += 8; 158 return val; 159} 160 161static char *mangle_filename(const char *orig_filename) { 162 char *new_filename; 163 size_t filename_len, prefix_len; 164 int prefix_strip; 165 int level = 0; 166 const char *fname, *ptr; 167 const char *prefix = getenv("GCOV_PREFIX"); 168 const char *prefix_strip_str = getenv("GCOV_PREFIX_STRIP"); 169 170 if (prefix == NULL || prefix[0] == '\0') 171 return strdup(orig_filename); 172 173 if (prefix_strip_str) { 174 prefix_strip = atoi(prefix_strip_str); 175 176 /* Negative GCOV_PREFIX_STRIP values are ignored */ 177 if (prefix_strip < 0) 178 prefix_strip = 0; 179 } else { 180 prefix_strip = 0; 181 } 182 183 fname = orig_filename; 184 for (level = 0, ptr = fname + 1; level < prefix_strip; ++ptr) { 185 if (*ptr == '\0') 186 break; 187 if (*ptr != '/') 188 continue; 189 fname = ptr; 190 ++level; 191 } 192 193 filename_len = strlen(fname); 194 prefix_len = strlen(prefix); 195 new_filename = malloc(prefix_len + 1 + filename_len + 1); 196 memcpy(new_filename, prefix, prefix_len); 197 198 if (prefix[prefix_len - 1] != '/') 199 new_filename[prefix_len++] = '/'; 200 memcpy(new_filename + prefix_len, fname, filename_len + 1); 201 202 return new_filename; 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 uint32_t checksum) { 250 const char *mode = "r+b"; 251 filename = mangle_filename(orig_filename); 252 253 /* Try just opening the file. */ 254 new_file = 0; 255 fd = open(filename, O_RDWR); 256 257 if (fd == -1) { 258 /* Try opening the file, creating it if necessary. */ 259 new_file = 1; 260 mode = "w+b"; 261 fd = open(filename, O_RDWR | O_CREAT, 0644); 262 if (fd == -1) { 263 /* Try creating the directories first then opening the file. */ 264 __llvm_profile_recursive_mkdir(filename); 265 fd = open(filename, O_RDWR | O_CREAT, 0644); 266 if (fd == -1) { 267 /* Bah! It's hopeless. */ 268 int errnum = errno; 269 fprintf(stderr, "profiling: %s: cannot open: %s\n", filename, 270 strerror(errnum)); 271 return; 272 } 273 } 274 } 275 276 /* Try to flock the file to serialize concurrent processes writing out to the 277 * same GCDA. This can fail if the filesystem doesn't support it, but in that 278 * case we'll just carry on with the old racy behaviour and hope for the best. 279 */ 280 flock(fd, LOCK_EX); 281 output_file = fdopen(fd, mode); 282 283 /* Initialize the write buffer. */ 284 write_buffer = NULL; 285 cur_buffer_size = 0; 286 cur_pos = 0; 287 288 if (new_file) { 289 resize_write_buffer(WRITE_BUFFER_SIZE); 290 memset(write_buffer, 0, WRITE_BUFFER_SIZE); 291 } else { 292 if (map_file() == -1) { 293 /* mmap failed, try to recover by clobbering */ 294 new_file = 1; 295 write_buffer = NULL; 296 cur_buffer_size = 0; 297 resize_write_buffer(WRITE_BUFFER_SIZE); 298 memset(write_buffer, 0, WRITE_BUFFER_SIZE); 299 } 300 } 301 302 /* gcda file, version, stamp checksum. */ 303 write_bytes("adcg", 4); 304 write_bytes(version, 4); 305 write_32bit_value(checksum); 306 307#ifdef DEBUG_GCDAPROFILING 308 fprintf(stderr, "llvmgcda: [%s]\n", orig_filename); 309#endif 310} 311 312/* Given an array of pointers to counters (counters), increment the n-th one, 313 * where we're also given a pointer to n (predecessor). 314 */ 315void llvm_gcda_increment_indirect_counter(uint32_t *predecessor, 316 uint64_t **counters) { 317 uint64_t *counter; 318 uint32_t pred; 319 320 pred = *predecessor; 321 if (pred == 0xffffffff) 322 return; 323 counter = counters[pred]; 324 325 /* Don't crash if the pred# is out of sync. This can happen due to threads, 326 or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */ 327 if (counter) 328 ++*counter; 329#ifdef DEBUG_GCDAPROFILING 330 else 331 fprintf(stderr, 332 "llvmgcda: increment_indirect_counter counters=%08llx, pred=%u\n", 333 *counter, *predecessor); 334#endif 335} 336 337void llvm_gcda_emit_function(uint32_t ident, const char *function_name, 338 uint32_t func_checksum, uint8_t use_extra_checksum, 339 uint32_t cfg_checksum) { 340 uint32_t len = 2; 341 342 if (use_extra_checksum) 343 len++; 344#ifdef DEBUG_GCDAPROFILING 345 fprintf(stderr, "llvmgcda: function id=0x%08x name=%s\n", ident, 346 function_name ? function_name : "NULL"); 347#endif 348 if (!output_file) return; 349 350 /* function tag */ 351 write_bytes("\0\0\0\1", 4); 352 if (function_name) 353 len += 1 + length_of_string(function_name); 354 write_32bit_value(len); 355 write_32bit_value(ident); 356 write_32bit_value(func_checksum); 357 if (use_extra_checksum) 358 write_32bit_value(cfg_checksum); 359 if (function_name) 360 write_string(function_name); 361} 362 363void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { 364 uint32_t i; 365 uint64_t *old_ctrs = NULL; 366 uint32_t val = 0; 367 uint64_t save_cur_pos = cur_pos; 368 369 if (!output_file) return; 370 371 val = read_32bit_value(); 372 373 if (val != (uint32_t)-1) { 374 /* There are counters present in the file. Merge them. */ 375 if (val != 0x01a10000) { 376 fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " 377 "corrupt arc tag (0x%08x)\n", 378 filename, val); 379 return; 380 } 381 382 val = read_32bit_value(); 383 if (val == (uint32_t)-1 || val / 2 != num_counters) { 384 fprintf(stderr, "profiling: %s: cannot merge previous GCDA file: " 385 "mismatched number of counters (%d)\n", 386 filename, val); 387 return; 388 } 389 390 old_ctrs = malloc(sizeof(uint64_t) * num_counters); 391 for (i = 0; i < num_counters; ++i) 392 old_ctrs[i] = read_64bit_value(); 393 } 394 395 cur_pos = save_cur_pos; 396 397 /* Counter #1 (arcs) tag */ 398 write_bytes("\0\0\xa1\1", 4); 399 write_32bit_value(num_counters * 2); 400 for (i = 0; i < num_counters; ++i) { 401 counters[i] += (old_ctrs ? old_ctrs[i] : 0); 402 write_64bit_value(counters[i]); 403 } 404 405 free(old_ctrs); 406 407#ifdef DEBUG_GCDAPROFILING 408 fprintf(stderr, "llvmgcda: %u arcs\n", num_counters); 409 for (i = 0; i < num_counters; ++i) 410 fprintf(stderr, "llvmgcda: %llu\n", (unsigned long long)counters[i]); 411#endif 412} 413 414void llvm_gcda_summary_info() { 415 const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */ 416 uint32_t i; 417 uint32_t runs = 1; 418 uint32_t val = 0; 419 uint64_t save_cur_pos = cur_pos; 420 421 if (!output_file) return; 422 423 val = read_32bit_value(); 424 425 if (val != (uint32_t)-1) { 426 /* There are counters present in the file. Merge them. */ 427 if (val != 0xa1000000) { 428 fprintf(stderr, "profiling: %s: cannot merge previous run count: " 429 "corrupt object tag (0x%08x)\n", 430 filename, val); 431 return; 432 } 433 434 val = read_32bit_value(); /* length */ 435 if (val != obj_summary_len) { 436 fprintf(stderr, "profiling: %s: cannot merge previous run count: " 437 "mismatched object length (%d)\n", 438 filename, val); 439 return; 440 } 441 442 read_32bit_value(); /* checksum, unused */ 443 read_32bit_value(); /* num, unused */ 444 runs += read_32bit_value(); /* Add previous run count to new counter. */ 445 } 446 447 cur_pos = save_cur_pos; 448 449 /* Object summary tag */ 450 write_bytes("\0\0\0\xa1", 4); 451 write_32bit_value(obj_summary_len); 452 write_32bit_value(0); /* checksum, unused */ 453 write_32bit_value(0); /* num, unused */ 454 write_32bit_value(runs); 455 for (i = 3; i < obj_summary_len; ++i) 456 write_32bit_value(0); 457 458 /* Program summary tag */ 459 write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */ 460 write_32bit_value(0); /* 0 length */ 461 462#ifdef DEBUG_GCDAPROFILING 463 fprintf(stderr, "llvmgcda: %u runs\n", runs); 464#endif 465} 466 467void llvm_gcda_end_file() { 468 /* Write out EOF record. */ 469 if (output_file) { 470 write_bytes("\0\0\0\0\0\0\0\0", 8); 471 472 if (new_file) { 473 fwrite(write_buffer, cur_pos, 1, output_file); 474 free(write_buffer); 475 } else { 476 unmap_file(); 477 } 478 479 fclose(output_file); 480 flock(fd, LOCK_UN); 481 output_file = NULL; 482 write_buffer = NULL; 483 } 484 free(filename); 485 486#ifdef DEBUG_GCDAPROFILING 487 fprintf(stderr, "llvmgcda: -----\n"); 488#endif 489} 490 491void llvm_register_writeout_function(writeout_fn fn) { 492 struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node)); 493 new_node->fn = fn; 494 new_node->next = NULL; 495 496 if (!writeout_fn_head) { 497 writeout_fn_head = writeout_fn_tail = new_node; 498 } else { 499 writeout_fn_tail->next = new_node; 500 writeout_fn_tail = new_node; 501 } 502} 503 504void llvm_writeout_files() { 505 struct writeout_fn_node *curr = writeout_fn_head; 506 507 while (curr) { 508 curr->fn(); 509 curr = curr->next; 510 } 511} 512 513void llvm_delete_writeout_function_list() { 514 while (writeout_fn_head) { 515 struct writeout_fn_node *node = writeout_fn_head; 516 writeout_fn_head = writeout_fn_head->next; 517 free(node); 518 } 519 520 writeout_fn_head = writeout_fn_tail = NULL; 521} 522 523void llvm_register_flush_function(flush_fn fn) { 524 struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node)); 525 new_node->fn = fn; 526 new_node->next = NULL; 527 528 if (!flush_fn_head) { 529 flush_fn_head = flush_fn_tail = new_node; 530 } else { 531 flush_fn_tail->next = new_node; 532 flush_fn_tail = new_node; 533 } 534} 535 536void __gcov_flush() { 537 struct flush_fn_node *curr = flush_fn_head; 538 539 while (curr) { 540 curr->fn(); 541 curr = curr->next; 542 } 543} 544 545void llvm_delete_flush_function_list() { 546 while (flush_fn_head) { 547 struct flush_fn_node *node = flush_fn_head; 548 flush_fn_head = flush_fn_head->next; 549 free(node); 550 } 551 552 flush_fn_head = flush_fn_tail = NULL; 553} 554 555void llvm_gcov_init(writeout_fn wfn, flush_fn ffn) { 556 static int atexit_ran = 0; 557 558 if (wfn) 559 llvm_register_writeout_function(wfn); 560 561 if (ffn) 562 llvm_register_flush_function(ffn); 563 564 if (atexit_ran == 0) { 565 atexit_ran = 1; 566 567 /* Make sure we write out the data and delete the data structures. */ 568 atexit(llvm_delete_flush_function_list); 569 atexit(llvm_delete_writeout_function_list); 570 atexit(llvm_writeout_files); 571 } 572} 573