summaryrefslogtreecommitdiff
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
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
-rw-r--r--SDKs/darwin/usr/include/stdio.h13
-rw-r--r--lib/profile/GCDAProfiling.c96
2 files changed, 93 insertions, 16 deletions
diff --git a/SDKs/darwin/usr/include/stdio.h b/SDKs/darwin/usr/include/stdio.h
index 3b560369f..744138806 100644
--- a/SDKs/darwin/usr/include/stdio.h
+++ b/SDKs/darwin/usr/include/stdio.h
@@ -51,11 +51,24 @@ typedef __SIZE_TYPE__ size_t;
# define stderr __stderrp
extern FILE *__stderrp;
+#ifndef SEEK_SET
+#define SEEK_SET 0 /* set file offset to offset */
+#endif
+#ifndef SEEK_CUR
+#define SEEK_CUR 1 /* set file offset to current plus offset */
+#endif
+#ifndef SEEK_END
+#define SEEK_END 2 /* set file offset to EOF plus offset */
+#endif
+
int fclose(FILE *);
int fflush(FILE *);
FILE *fopen(const char * restrict, const char * restrict) __asm(__FOPEN_NAME);
int fprintf(FILE * restrict, const char * restrict, ...);
size_t fwrite(const void * restrict, size_t, size_t, FILE * restrict)
__asm(__FWRITE_NAME);
+size_t fread(void * __restrict, size_t, size_t, FILE * __restrict);
+long ftell(FILE *);
+int fseek(FILE *, long, int);
#endif /* __STDIO_H__ */
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
}