summaryrefslogtreecommitdiff
path: root/lib/profile/GCDAProfiling.c
diff options
context:
space:
mode:
authorBill Wendling <isanbard@gmail.com>2013-05-15 21:31:22 +0000
committerBill Wendling <isanbard@gmail.com>2013-05-15 21:31:22 +0000
commit2a46a60510948b5005d62025fbba307a0323ed8d (patch)
treebcf69b34828332f3755ef9d593b43018af34e2e4 /lib/profile/GCDAProfiling.c
parent0bdc46c7ee03e8c4e4da7c5ac43edac237aa53e2 (diff)
Try to improve performance by using a read/write buffer instead of I/O.
The calls to fwrite/fread can be very expensive. GCC avoids this by using a buffer to read and write from the file, thus limiting the number of fwrite/fread calls. <rdar://problem/13466086> git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@181924 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/profile/GCDAProfiling.c')
-rw-r--r--lib/profile/GCDAProfiling.c160
1 files changed, 108 insertions, 52 deletions
diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c
index 653f641f7..53ecff438 100644
--- a/lib/profile/GCDAProfiling.c
+++ b/lib/profile/GCDAProfiling.c
@@ -48,6 +48,15 @@ typedef unsigned int uint64_t;
static FILE *output_file = NULL;
/*
+ * Buffer that we write things into.
+ */
+#define WRITE_BUFFER_SIZE (1 << 12)
+static char write_buffer[WRITE_BUFFER_SIZE];
+static int64_t cur_file_pos = 0;
+static uint32_t cur_offset = 0;
+static int new_file = 0;
+
+/*
* A list of functions to write out the data.
*/
typedef void (*writeout_fn)();
@@ -57,8 +66,8 @@ struct writeout_fn_node {
struct writeout_fn_node *next;
};
-struct writeout_fn_node *writeout_fn_head = NULL;
-struct writeout_fn_node *writeout_fn_tail = NULL;
+static struct writeout_fn_node *writeout_fn_head = NULL;
+static struct writeout_fn_node *writeout_fn_tail = NULL;
/*
* A list of flush functions that our __gcov_flush() function should call.
@@ -70,18 +79,41 @@ struct flush_fn_node {
struct flush_fn_node *next;
};
-struct flush_fn_node *flush_fn_head = NULL;
-struct flush_fn_node *flush_fn_tail = NULL;
+static struct flush_fn_node *flush_fn_head = NULL;
+static struct flush_fn_node *flush_fn_tail = NULL;
+
+static void flush_buffer() {
+ /* Flush the buffer to file. */
+ fwrite(write_buffer, cur_offset, 1, output_file);
+
+ if (new_file) {
+ cur_offset = 0;
+ return;
+ }
+
+ /* Read in more of the file. */
+ fread(write_buffer,1, WRITE_BUFFER_SIZE, output_file);
+ fseek(output_file, cur_file_pos, SEEK_SET);
-static void write_int32(uint32_t i) {
- fwrite(&i, 4, 1, output_file);
+ cur_offset = 0;
}
-static uint64_t write_from_buffer(uint64_t *buffer, size_t size) {
- if (fwrite(buffer, 8, size, output_file) != size)
- return (uint64_t)-1;
+static void write_bytes(const char *s, size_t len) {
+ if (cur_offset + len > WRITE_BUFFER_SIZE)
+ flush_buffer();
+
+ cur_file_pos += len;
+
+ for (; len > 0; --len)
+ write_buffer[cur_offset++] = *s++;
+}
- return 0;
+static void write_32bit_value(uint32_t i) {
+ write_bytes((char*)&i, 4);
+}
+
+static void write_64bit_value(uint64_t i) {
+ write_bytes((char*)&i, 8);
}
static uint32_t length_of_string(const char *s) {
@@ -90,25 +122,39 @@ static uint32_t length_of_string(const char *s) {
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);
+ write_32bit_value(len);
+ write_bytes(s, strlen(s));
+ write_bytes("\0\0\0\0", 4 - (strlen(s) % 4));
}
-static uint32_t read_int32() {
- uint32_t tmp;
+static uint32_t read_32bit_value() {
+ uint32_t val;
+
+ if (cur_offset + 4 > WRITE_BUFFER_SIZE)
+ flush_buffer();
- if (fread(&tmp, 1, 4, output_file) != 4)
+ if (new_file)
return (uint32_t)-1;
- return tmp;
+ val = *(uint32_t*)&write_buffer[cur_offset];
+ cur_file_pos += 4;
+ cur_offset += 4;
+ return val;
}
-static uint64_t read_into_buffer(uint64_t *buffer, size_t size) {
- if (fread(buffer, 8, size, output_file) != size)
- return (uint64_t)-1;
+static uint64_t read_64bit_value() {
+ uint64_t val;
- return 0;
+ if (cur_offset + 8 > WRITE_BUFFER_SIZE)
+ flush_buffer();
+
+ if (new_file)
+ return (uint32_t)-1;
+
+ val = *(uint64_t*)&write_buffer[cur_offset];
+ cur_file_pos += 8;
+ cur_offset += 8;
+ return val;
}
static char *mangle_filename(const char *orig_filename) {
@@ -118,13 +164,13 @@ static char *mangle_filename(const char *orig_filename) {
int level = 0;
const char *fname = orig_filename, *ptr = NULL;
const char *prefix = getenv("GCOV_PREFIX");
- const char *tmp = getenv("GCOV_PREFIX_STRIP");
+ const char *prefix_strip_str = getenv("GCOV_PREFIX_STRIP");
if (!prefix)
return strdup(orig_filename);
- if (tmp) {
- prefix_strip = atoi(tmp);
+ if (prefix_strip_str) {
+ prefix_strip = atoi(prefix_strip_str);
/* Negative GCOV_PREFIX_STRIP values are ignored */
if (prefix_strip < 0)
@@ -180,6 +226,7 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4]) {
if (!output_file) {
/* Try opening the file, creating it if necessary. */
+ new_file = 1;
output_file = fopen(filename, "w+b");
if (!output_file) {
/* Try creating the directories first then opening the file. */
@@ -194,10 +241,20 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4]) {
}
}
+ setbuf(output_file, 0);
+
+ /* Initialize the write buffer. */
+ memset(write_buffer, 0, WRITE_BUFFER_SIZE);
+ fread(write_buffer, 1, WRITE_BUFFER_SIZE, output_file);
+ fseek(output_file, 0L, SEEK_SET);
+ cur_file_pos = 0;
+ cur_offset = 0;
+
/* gcda file, version, stamp LLVM. */
- fwrite("adcg", 4, 1, output_file);
- fwrite(version, 4, 1, output_file);
- fwrite("MVLL", 4, 1, output_file);
+ write_bytes("adcg", 4);
+ write_bytes(version, 4);
+ write_bytes("MVLL", 4);
+
free(filename);
#ifdef DEBUG_GCDAPROFILING
@@ -233,6 +290,7 @@ void llvm_gcda_increment_indirect_counter(uint32_t *predecessor,
void llvm_gcda_emit_function(uint32_t ident, const char *function_name,
uint8_t use_extra_checksum) {
uint32_t len = 2;
+
if (use_extra_checksum)
len++;
#ifdef DEBUG_GCDAPROFILING
@@ -242,14 +300,14 @@ void llvm_gcda_emit_function(uint32_t ident, const char *function_name,
if (!output_file) return;
/* function tag */
- fwrite("\0\0\0\1", 4, 1, output_file);
+ write_bytes("\0\0\0\1", 4);
if (function_name)
len += 1 + length_of_string(function_name);
- write_int32(len);
- write_int32(ident);
- write_int32(0);
+ write_32bit_value(len);
+ write_32bit_value(ident);
+ write_32bit_value(0);
if (use_extra_checksum)
- write_int32(0);
+ write_32bit_value(0);
if (function_name)
write_string(function_name);
}
@@ -257,13 +315,13 @@ 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;
+ int64_t save_cur_file_pos = cur_file_pos;
uint32_t val = 0;
- long pos = 0;
if (!output_file) return;
- pos = ftell(output_file);
- val = read_int32();
+ flush_buffer();
+ val = read_32bit_value();
if (val != (uint32_t)-1) {
/* There are counters present in the file. Merge them. */
@@ -272,33 +330,30 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
return;
}
- val = read_int32();
+ val = read_32bit_value();
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 (i = 0; i < num_counters; ++i)
+ old_ctrs[i] = read_64bit_value();
- if (read_into_buffer(old_ctrs, num_counters) == (uint64_t)-1) {
- fprintf(stderr, "profiling:invalid number of counters (%d)\n",
- num_counters);
- return;
- }
- }
+ /* Reset the current buffer and file position. */
+ memset(write_buffer, 0, WRITE_BUFFER_SIZE);
+ cur_file_pos = save_cur_file_pos;
+ cur_offset = 0;
- /* Reset for writing. */
- fseek(output_file, pos, SEEK_SET);
+ fseek(output_file, cur_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_bytes("\0\0\xa1\1", 4);
+ write_32bit_value(num_counters * 2);
+ for (i = 0; i < num_counters; ++i) {
counters[i] += (old_ctrs ? old_ctrs[i] : 0);
-
- if (write_from_buffer(counters, num_counters) == (uint64_t)-1) {
- fprintf(stderr, "profiling:cannot write to output file\n");
- return;
+ write_64bit_value(counters[i]);
}
free(old_ctrs);
@@ -313,7 +368,8 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
void llvm_gcda_end_file() {
/* Write out EOF record. */
if (!output_file) return;
- fwrite("\0\0\0\0\0\0\0\0", 8, 1, output_file);
+ write_bytes("\0\0\0\0\0\0\0\0", 8);
+ flush_buffer();
fclose(output_file);
output_file = NULL;