[compiler-rt] r181924 - Try to improve performance by using a read/write buffer instead of I/O.

Bill Wendling isanbard at gmail.com
Wed May 15 14:31:23 PDT 2013


Author: void
Date: Wed May 15 16:31:22 2013
New Revision: 181924

URL: http://llvm.org/viewvc/llvm-project?rev=181924&view=rev
Log:
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>

Modified:
    compiler-rt/trunk/SDKs/darwin/usr/include/stdio.h
    compiler-rt/trunk/SDKs/darwin/usr/include/string.h
    compiler-rt/trunk/SDKs/linux/usr/include/stdio.h
    compiler-rt/trunk/SDKs/linux/usr/include/string.h
    compiler-rt/trunk/lib/profile/GCDAProfiling.c

Modified: compiler-rt/trunk/SDKs/darwin/usr/include/stdio.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/SDKs/darwin/usr/include/stdio.h?rev=181924&r1=181923&r2=181924&view=diff
==============================================================================
--- compiler-rt/trunk/SDKs/darwin/usr/include/stdio.h (original)
+++ compiler-rt/trunk/SDKs/darwin/usr/include/stdio.h Wed May 15 16:31:22 2013
@@ -74,6 +74,7 @@ size_t fwrite(const void * __restrict, s
 size_t fread(void * __restrict, size_t, size_t, FILE * __restrict);
 long ftell(FILE *);
 int fseek(FILE *, long, int);
+void setbuf(FILE * __restrict, char * __restrict);
 
 int snprintf(char * __restrict, size_t, const char * __restrict, ...);
 

Modified: compiler-rt/trunk/SDKs/darwin/usr/include/string.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/SDKs/darwin/usr/include/string.h?rev=181924&r1=181923&r2=181924&view=diff
==============================================================================
--- compiler-rt/trunk/SDKs/darwin/usr/include/string.h (original)
+++ compiler-rt/trunk/SDKs/darwin/usr/include/string.h Wed May 15 16:31:22 2013
@@ -21,6 +21,7 @@ typedef __SIZE_TYPE__ size_t;
 
 int memcmp(const void *, const void *, size_t);
 void *memcpy(void *, const void *, size_t);
+void *memset(void *, int, size_t);
 char *strcat(char *, const char *);
 char *strcpy(char *, const char *);
 char *strdup(const char *);

Modified: compiler-rt/trunk/SDKs/linux/usr/include/stdio.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/SDKs/linux/usr/include/stdio.h?rev=181924&r1=181923&r2=181924&view=diff
==============================================================================
--- compiler-rt/trunk/SDKs/linux/usr/include/stdio.h (original)
+++ compiler-rt/trunk/SDKs/linux/usr/include/stdio.h Wed May 15 16:31:22 2013
@@ -38,5 +38,6 @@ extern size_t fwrite(const void * restri
 extern size_t fread(void * restrict, size_t, size_t, FILE * restrict);
 extern long ftell(FILE *);
 extern int fseek(FILE *, long, int);
+extern void setbuf(FILE * restrict, char * restrict);
 
 #endif /* __STDIO_H__ */

Modified: compiler-rt/trunk/SDKs/linux/usr/include/string.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/SDKs/linux/usr/include/string.h?rev=181924&r1=181923&r2=181924&view=diff
==============================================================================
--- compiler-rt/trunk/SDKs/linux/usr/include/string.h (original)
+++ compiler-rt/trunk/SDKs/linux/usr/include/string.h Wed May 15 16:31:22 2013
@@ -21,6 +21,7 @@ typedef __SIZE_TYPE__ size_t;
 
 int memcmp(const void *, const void *, size_t);
 void *memcpy(void *, const void *, size_t);
+void *memset(void *, int, size_t);
 char *strcat(char *, const char *);
 char *strcpy(char *, const char *);
 char *strdup(const char *);

Modified: compiler-rt/trunk/lib/profile/GCDAProfiling.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/profile/GCDAProfiling.c?rev=181924&r1=181923&r2=181924&view=diff
==============================================================================
--- compiler-rt/trunk/lib/profile/GCDAProfiling.c (original)
+++ compiler-rt/trunk/lib/profile/GCDAProfiling.c Wed May 15 16:31:22 2013
@@ -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 c
 
 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
   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 *or
 
   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 *or
     }
   }
 
+  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_counte
 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 id
   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 id
 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_co
       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_co
 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;
 





More information about the llvm-commits mailing list