X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=runtime%2Flibprofile%2FGCDAProfiling.c;h=ac3a62c79f4bbc7a1e60e5697e72cbc53a59310f;hb=adf01b3f18442ae8db6b8948e70d82d9df415119;hp=d5fcd17529bde0e95ee5b3d4936401ab6aa35b45;hpb=ece78a30bdd4c26edcd5304aca1415ebc8b27756;p=oota-llvm.git diff --git a/runtime/libprofile/GCDAProfiling.c b/runtime/libprofile/GCDAProfiling.c index d5fcd17529b..ac3a62c79f4 100644 --- a/runtime/libprofile/GCDAProfiling.c +++ b/runtime/libprofile/GCDAProfiling.c @@ -15,13 +15,20 @@ |* are only close enough that LCOV will happily parse them. Anything that lcov |* ignores is missing. |* +|* TODO: gcov is multi-process safe by having each exit open the existing file +|* and append to it. We'd like to achieve that and be thread-safe too. +|* \*===----------------------------------------------------------------------===*/ #include "llvm/Support/DataTypes.h" -#include #include #include #include +#include +#include +#ifdef _MSC_VER +#include +#endif /* #define DEBUG_GCDAPROFILING */ @@ -37,13 +44,61 @@ static void write_int32(uint32_t i) { static void write_int64(uint64_t i) { uint32_t lo, hi; - lo = i & 0x00000000ffffffff; - hi = i & 0xffffffff00000000; + lo = i >> 0; + hi = i >> 32; write_int32(lo); write_int32(hi); } +static uint32_t length_of_string(const char *s) { + return (strlen(s) / 4) + 1; +} + +static void write_string(const char *s) { + uint32_t len = length_of_string(s); + write_int32(len); + fwrite(s, strlen(s), 1, output_file); + fwrite("\0\0\0\0", 4 - (strlen(s) % 4), 1, output_file); +} + +static char *mangle_filename(const char *orig_filename) { + /* TODO: handle GCOV_PREFIX_STRIP */ + const char *prefix; + char *filename = 0; + + prefix = getenv("GCOV_PREFIX"); + + if (!prefix) + return strdup(orig_filename); + + filename = malloc(strlen(prefix) + 1 + strlen(orig_filename) + 1); + strcpy(filename, prefix); + strcat(filename, "/"); + strcat(filename, orig_filename); + + return filename; +} + +static void recursive_mkdir(const char *filename) { + char *pathname; + int i, e; + + for (i = 1, e = strlen(filename); i != e; ++i) { + if (filename[i] == '/') { + pathname = malloc(i + 1); + strncpy(pathname, filename, i); + pathname[i] = '\0'; +#ifdef _WIN32 + _mkdir(pathname); +#else + mkdir(pathname, 0750); /* some of these will fail, ignore it. */ +#endif + free(pathname); + } + } +} + /* * --- LLVM line counter API --- */ @@ -52,27 +107,62 @@ static void write_int64(uint64_t i) { * profiling enabled will emit to a different file. Only one file may be * started at a time. */ -void llvm_gcda_start_file(const char *filename) { - output_file = fopen(filename, "w+"); +void llvm_gcda_start_file(const char *orig_filename) { + char *filename; + filename = mangle_filename(orig_filename); + recursive_mkdir(filename); + output_file = fopen(filename, "wb"); /* gcda file, version 404*, stamp LLVM. */ +#ifdef __APPLE__ + fwrite("adcg*204MVLL", 12, 1, output_file); +#else fwrite("adcg*404MVLL", 12, 1, output_file); +#endif + +#ifdef DEBUG_GCDAPROFILING + printf("llvmgcda: [%s]\n", orig_filename); +#endif + + free(filename); +} +/* Given an array of pointers to counters (counters), increment the n-th one, + * where we're also given a pointer to n (predecessor). + */ +void llvm_gcda_increment_indirect_counter(uint32_t *predecessor, + uint64_t **counters) { + uint64_t *counter; + uint32_t pred; + + pred = *predecessor; + if (pred == 0xffffffff) + return; + counter = counters[pred]; + + /* Don't crash if the pred# is out of sync. This can happen due to threads, + or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */ + if (counter) + ++*counter; #ifdef DEBUG_GCDAPROFILING - printf("[%s]\n", filename); + else + printf("llvmgcda: increment_indirect_counter counters=%x, pred=%u\n", + state_table_row, *predecessor); #endif } -void llvm_gcda_emit_function(uint32_t ident) { +void llvm_gcda_emit_function(uint32_t ident, const char *function_name) { #ifdef DEBUG_GCDAPROFILING - printf("function id=%x\n", ident); + printf("llvmgcda: function id=%x\n", ident); #endif /* function tag */ fwrite("\0\0\0\1", 4, 1, output_file); - write_int32(2); + write_int32(3 + 1 + length_of_string(function_name)); write_int32(ident); write_int32(0); + write_int32(0); + write_string(function_name); } void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { @@ -85,9 +175,9 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { } #ifdef DEBUG_GCDAPROFILING - printf(" %u arcs\n", num_counters); + printf("llvmgcda: %u arcs\n", num_counters); for (i = 0; i < num_counters; ++i) { - printf(" %llu\n", (unsigned long long)counters[i]); + printf("llvmgcda: %llu\n", (unsigned long long)counters[i]); } #endif } @@ -99,6 +189,6 @@ void llvm_gcda_end_file() { output_file = NULL; #ifdef DEBUG_GCDAPROFILING - printf("-----\n"); + printf("llvmgcda: -----\n"); #endif }