summaryrefslogtreecommitdiff
path: root/lib/profile/GCDAProfiling.c
diff options
context:
space:
mode:
authorBill Wendling <isanbard@gmail.com>2012-09-14 18:55:32 +0000
committerBill Wendling <isanbard@gmail.com>2012-09-14 18:55:32 +0000
commit843f359862fb8370eacf8aed4e749c46a92b2e38 (patch)
tree0683abd7f51ce2671162a09a937d0eba10384744 /lib/profile/GCDAProfiling.c
parent78103db90782ca30593d7b1066b77792ca2f3459 (diff)
Add support for reading the GCDA file and merging the arc information.
With the advent of the __llvm_gcov_flush function, we need to be able to merge counts into the .gcda files in an intelligent manner. This involves reading the file if it exists, adding the counts together, and then writing the results. <rdar://problem/12185886> git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@163923 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/profile/GCDAProfiling.c')
-rw-r--r--lib/profile/GCDAProfiling.c96
1 files changed, 80 insertions, 16 deletions
diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c
index 8f92a9154..ba2e12aeb 100644
--- a/lib/profile/GCDAProfiling.c
+++ b/lib/profile/GCDAProfiling.c
@@ -66,6 +66,24 @@ static void write_string(const char *s) {
fwrite("\0\0\0\0", 4 - (strlen(s) % 4), 1, output_file);
}
+static uint32_t read_int32() {
+ uint32_t tmp;
+
+ if (fread(&tmp, 1, 4, output_file) != 4)
+ return (uint32_t)-1;
+
+ return tmp;
+}
+
+static uint64_t read_int64() {
+ uint64_t tmp;
+
+ if (fread(&tmp, 1, 8, output_file) != 8)
+ return (uint64_t)-1;
+
+ return tmp;
+}
+
static char *mangle_filename(const char *orig_filename) {
char *filename = 0;
int prefix_len = 0;
@@ -129,15 +147,24 @@ static void recursive_mkdir(char *filename) {
*/
void llvm_gcda_start_file(const char *orig_filename) {
char *filename = mangle_filename(orig_filename);
- output_file = fopen(filename, "w+b");
+ char buffer[13];
+
+ /* Try just opening the file. */
+ output_file = fopen(filename, "r+b");
if (!output_file) {
- recursive_mkdir(filename);
+ /* Try opening the file, creating it if necessary. */
output_file = fopen(filename, "w+b");
if (!output_file) {
- fprintf(stderr, "profiling:%s: cannot open\n", filename);
- free(filename);
- return;
+ /* Try creating the directories first then opening the file. */
+ recursive_mkdir(filename);
+ output_file = fopen(filename, "w+b");
+ if (!output_file) {
+ /* Bah! It's hopeless. */
+ fprintf(stderr, "profiling:%s: cannot open\n", filename);
+ free(filename);
+ return;
+ }
}
}
@@ -148,11 +175,11 @@ void llvm_gcda_start_file(const char *orig_filename) {
fwrite("adcg*404MVLL", 12, 1, output_file);
#endif
+ free(filename);
+
#ifdef DEBUG_GCDAPROFILING
- printf("llvmgcda: [%s]\n", orig_filename);
+ fprintf(stderr, "llvmgcda: [%s]\n", orig_filename);
#endif
-
- free(filename);
}
/* Given an array of pointers to counters (counters), increment the n-th one,
@@ -175,14 +202,14 @@ void llvm_gcda_increment_indirect_counter(uint32_t *predecessor,
#ifdef DEBUG_GCDAPROFILING
else
fprintf(stderr,
- "llvmgcda: increment_indirect_counter counters=%x, pred=%u\n",
- state_table_row, *predecessor);
+ "llvmgcda: increment_indirect_counter counters=%08llx, pred=%u\n",
+ *counter, *predecessor);
#endif
}
void llvm_gcda_emit_function(uint32_t ident, const char *function_name) {
#ifdef DEBUG_GCDAPROFILING
- printf("llvmgcda: function id=%x\n", ident);
+ fprintf(stderr, "llvmgcda: function id=0x%08x\n", ident);
#endif
if (!output_file) return;
@@ -197,18 +224,55 @@ void llvm_gcda_emit_function(uint32_t ident, const char *function_name) {
void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
uint32_t i;
+ uint64_t *old_ctrs = NULL;
+ uint32_t val = 0;
+ long pos = 0;
- /* Counter #1 (arcs) tag */
if (!output_file) return;
+
+ pos = ftell(output_file);
+ val = read_int32();
+
+ fprintf(stderr, "Read: 0x%08x\n", val);
+
+ if (val != (uint32_t)-1) {
+ /* There are counters present in the file. Merge them. */
+ uint32_t j;
+
+ if (val != 0x01a10000) {
+ fprintf(stderr, "profiling: invalid magic number (0x%08x)\n", val);
+ return;
+ }
+
+ val = read_int32();
+ if (val == (uint32_t)-1 || val / 2 != num_counters) {
+ fprintf(stderr, "profiling: invalid number of counters (%d)\n", val);
+ return;
+ }
+
+ old_ctrs = malloc(sizeof(uint64_t) * num_counters);
+
+ for (j = 0; j < num_counters; ++j) {
+ old_ctrs[j] = read_int64();
+ fprintf(stderr, "old counter[%d]: %lld\n", j, old_ctrs[j]);
+ }
+ }
+
+ /* Reset for writing. */
+ fseek(output_file, pos, SEEK_SET);
+
+ /* Counter #1 (arcs) tag */
fwrite("\0\0\xa1\1", 4, 1, output_file);
write_int32(num_counters * 2);
for (i = 0; i < num_counters; ++i)
- write_int64(counters[i]);
+ write_int64(counters[i] + (old_ctrs ? old_ctrs[i] : 0));
+
+ free(old_ctrs);
#ifdef DEBUG_GCDAPROFILING
- printf("llvmgcda: %u arcs\n", num_counters);
+ fprintf(stderr, "llvmgcda: %u arcs\n", num_counters);
for (i = 0; i < num_counters; ++i)
- printf("llvmgcda: %llu\n", (unsigned long long)counters[i]);
+ fprintf(stderr, "llvmgcda: %llu\n", (unsigned long long)counters[i]);
#endif
}
@@ -220,6 +284,6 @@ void llvm_gcda_end_file() {
output_file = NULL;
#ifdef DEBUG_GCDAPROFILING
- printf("llvmgcda: -----\n");
+ fprintf(stderr, "llvmgcda: -----\n");
#endif
}