<div dir="ltr"><div style>On Wed, May 15, 2013 at 5:31 PM, Bill Wendling <span dir="ltr"><<a href="mailto:isanbard@gmail.com" target="_blank">isanbard@gmail.com</a>></span> wrote:<br></div><div class="gmail_extra"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: void<br>
Date: Wed May 15 16:31:22 2013<br>
New Revision: 181924<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=181924&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=181924&view=rev</a><br>
Log:<br>
Try to improve performance by using a read/write buffer instead of I/O.<br>
<br>
The calls to fwrite/fread can be very expensive. GCC avoids this by using a<br>
buffer to read and write from the file, thus limiting the number of fwrite/fread<br>
calls.<br>
<br>
<rdar://problem/13466086><br>
<br>
Modified:<br>
    compiler-rt/trunk/SDKs/darwin/usr/include/stdio.h<br>
    compiler-rt/trunk/SDKs/darwin/usr/include/string.h<br>
    compiler-rt/trunk/SDKs/linux/usr/include/stdio.h<br>
    compiler-rt/trunk/SDKs/linux/usr/include/string.h<br>
    compiler-rt/trunk/lib/profile/GCDAProfiling.c<br>
<br>
Modified: compiler-rt/trunk/SDKs/darwin/usr/include/stdio.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/SDKs/darwin/usr/include/stdio.h?rev=181924&r1=181923&r2=181924&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/SDKs/darwin/usr/include/stdio.h?rev=181924&r1=181923&r2=181924&view=diff</a><br>

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

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

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

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

==============================================================================<br>
--- compiler-rt/trunk/lib/profile/GCDAProfiling.c (original)<br>
+++ compiler-rt/trunk/lib/profile/GCDAProfiling.c Wed May 15 16:31:22 2013<br>
@@ -48,6 +48,15 @@ typedef unsigned int uint64_t;<br>
 static FILE *output_file = NULL;<br>
<br>
 /*<br>
+ * Buffer that we write things into.<br>
+ */<br>
+#define WRITE_BUFFER_SIZE (1 << 12)<br>
+static char write_buffer[WRITE_BUFFER_SIZE];<br>
+static int64_t cur_file_pos = 0;<br>
+static uint32_t cur_offset = 0;<br>
+static int new_file = 0;<br>
+<br>
+/*<br>
  * A list of functions to write out the data.<br>
  */<br>
 typedef void (*writeout_fn)();<br>
@@ -57,8 +66,8 @@ struct writeout_fn_node {<br>
   struct writeout_fn_node *next;<br>
 };<br>
<br>
-struct writeout_fn_node *writeout_fn_head = NULL;<br>
-struct writeout_fn_node *writeout_fn_tail = NULL;<br>
+static struct writeout_fn_node *writeout_fn_head = NULL;<br>
+static struct writeout_fn_node *writeout_fn_tail = NULL;<br>
<br>
 /*<br>
  *  A list of flush functions that our __gcov_flush() function should call.<br>
@@ -70,18 +79,41 @@ struct flush_fn_node {<br>
   struct flush_fn_node *next;<br>
 };<br>
<br>
-struct flush_fn_node *flush_fn_head = NULL;<br>
-struct flush_fn_node *flush_fn_tail = NULL;<br>
+static struct flush_fn_node *flush_fn_head = NULL;<br>
+static struct flush_fn_node *flush_fn_tail = NULL;<br>
+<br>
+static void flush_buffer() {<br>
+  /* Flush the buffer to file. */<br>
+  fwrite(write_buffer, cur_offset, 1, output_file);<br>
+<br>
+  if (new_file) {<br>
+    cur_offset = 0;<br>
+    return;<br>
+  }<br>
+<br>
+  /* Read in more of the file. */<br>
+  fread(write_buffer,1, WRITE_BUFFER_SIZE, output_file);<br>
+  fseek(output_file, cur_file_pos, SEEK_SET);<br>
<br>
-static void write_int32(uint32_t i) {<br>
-  fwrite(&i, 4, 1, output_file);<br>
+  cur_offset = 0;<br>
 }<br>
<br>
-static uint64_t write_from_buffer(uint64_t *buffer, size_t size) {<br>
-  if (fwrite(buffer, 8, size, output_file) != size)<br>
-    return (uint64_t)-1;<br>
+static void write_bytes(const char *s, size_t len) {<br>
+  if (cur_offset + len > WRITE_BUFFER_SIZE)<br>
+    flush_buffer();<br></blockquote><div><br></div><div style>Can len be > WRITE_BUFFER_SIZE? </div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+  cur_file_pos += len;<br>
+<br>
+  for (; len > 0; --len)<br>
+    write_buffer[cur_offset++] = *s++;<br>
+}<br>
<br>
-  return 0;<br>
+static void write_32bit_value(uint32_t i) {<br>
+  write_bytes((char*)&i, 4);<br>
+}<br>
+<br>
+static void write_64bit_value(uint64_t i) {<br>
+  write_bytes((char*)&i, 8);<br>
 }<br>
<br>
 static uint32_t length_of_string(const char *s) {<br>
@@ -90,25 +122,39 @@ static uint32_t length_of_string(const c<br>
<br>
 static void write_string(const char *s) {<br>
   uint32_t len = length_of_string(s);<br>
-  write_int32(len);<br>
-  fwrite(s, strlen(s), 1, output_file);<br>
-  fwrite("\0\0\0\0", 4 - (strlen(s) % 4), 1, output_file);<br>
+  write_32bit_value(len);<br>
+  write_bytes(s, strlen(s));<br>
+  write_bytes("\0\0\0\0", 4 - (strlen(s) % 4));<br>
 }<br>
<br>
-static uint32_t read_int32() {<br>
-  uint32_t tmp;<br>
+static uint32_t read_32bit_value() {<br>
+  uint32_t val;<br>
+<br>
+  if (cur_offset + 4 > WRITE_BUFFER_SIZE)<br>
+    flush_buffer();<br>
<br>
-  if (fread(&tmp, 1, 4, output_file) != 4)<br>
+  if (new_file)<br>
     return (uint32_t)-1;<br>
<br>
-  return tmp;<br>
+  val = *(uint32_t*)&write_buffer[cur_offset];<br>
+  cur_file_pos += 4;<br>
+  cur_offset += 4;<br>
+  return val;<br>
 }<br>
<br>
-static uint64_t read_into_buffer(uint64_t *buffer, size_t size) {<br>
-  if (fread(buffer, 8, size, output_file) != size)<br>
-    return (uint64_t)-1;<br>
+static uint64_t read_64bit_value() {<br>
+  uint64_t val;<br>
<br>
-  return 0;<br>
+  if (cur_offset + 8 > WRITE_BUFFER_SIZE)<br>
+    flush_buffer();<br>
+<br>
+  if (new_file)<br>
+    return (uint32_t)-1;<br>
+<br>
+  val = *(uint64_t*)&write_buffer[cur_offset];<br>
+  cur_file_pos += 8;<br>
+  cur_offset += 8;<br>
+  return val;<br>
 }<br>
<br>
 static char *mangle_filename(const char *orig_filename) {<br>
@@ -118,13 +164,13 @@ static char *mangle_filename(const char<br>
   int level = 0;<br>
   const char *fname = orig_filename, *ptr = NULL;<br>
   const char *prefix = getenv("GCOV_PREFIX");<br>
-  const char *tmp = getenv("GCOV_PREFIX_STRIP");<br>
+  const char *prefix_strip_str = getenv("GCOV_PREFIX_STRIP");<br>
<br>
   if (!prefix)<br>
     return strdup(orig_filename);<br>
<br>
-  if (tmp) {<br>
-    prefix_strip = atoi(tmp);<br>
+  if (prefix_strip_str) {<br>
+    prefix_strip = atoi(prefix_strip_str);<br>
<br>
     /* Negative GCOV_PREFIX_STRIP values are ignored */<br>
     if (prefix_strip < 0)<br>
@@ -180,6 +226,7 @@ void llvm_gcda_start_file(const char *or<br>
<br>
   if (!output_file) {<br>
     /* Try opening the file, creating it if necessary. */<br>
+    new_file = 1;<br>
     output_file = fopen(filename, "w+b");<br>
     if (!output_file) {<br>
       /* Try creating the directories first then opening the file. */<br>
@@ -194,10 +241,20 @@ void llvm_gcda_start_file(const char *or<br>
     }<br>
   }<br>
<br>
+  setbuf(output_file, 0);<br>
+<br>
+  /* Initialize the write buffer. */<br>
+  memset(write_buffer, 0, WRITE_BUFFER_SIZE);<br>
+  fread(write_buffer, 1, WRITE_BUFFER_SIZE, output_file);<br>
+  fseek(output_file, 0L, SEEK_SET);<br>
+  cur_file_pos = 0;<br>
+  cur_offset = 0;<br>
+<br>
   /* gcda file, version, stamp LLVM. */<br>
-  fwrite("adcg", 4, 1, output_file);<br>
-  fwrite(version, 4, 1, output_file);<br>
-  fwrite("MVLL", 4, 1, output_file);<br>
+  write_bytes("adcg", 4);<br>
+  write_bytes(version, 4);<br>
+  write_bytes("MVLL", 4);<br>
+<br>
   free(filename);<br>
<br>
 #ifdef DEBUG_GCDAPROFILING<br>
@@ -233,6 +290,7 @@ void llvm_gcda_increment_indirect_counte<br>
 void llvm_gcda_emit_function(uint32_t ident, const char *function_name,<br>
                              uint8_t use_extra_checksum) {<br>
   uint32_t len = 2;<br>
+<br>
   if (use_extra_checksum)<br>
     len++;<br>
 #ifdef DEBUG_GCDAPROFILING<br>
@@ -242,14 +300,14 @@ void llvm_gcda_emit_function(uint32_t id<br>
   if (!output_file) return;<br>
<br>
   /* function tag */<br>
-  fwrite("\0\0\0\1", 4, 1, output_file);<br>
+  write_bytes("\0\0\0\1", 4);<br>
   if (function_name)<br>
     len += 1 + length_of_string(function_name);<br>
-  write_int32(len);<br>
-  write_int32(ident);<br>
-  write_int32(0);<br>
+  write_32bit_value(len);<br>
+  write_32bit_value(ident);<br>
+  write_32bit_value(0);<br>
   if (use_extra_checksum)<br>
-    write_int32(0);<br>
+    write_32bit_value(0);<br>
   if (function_name)<br>
     write_string(function_name);<br>
 }<br>
@@ -257,13 +315,13 @@ void llvm_gcda_emit_function(uint32_t id<br>
 void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {<br>
   uint32_t i;<br>
   uint64_t *old_ctrs = NULL;<br>
+  int64_t save_cur_file_pos = cur_file_pos;<br>
   uint32_t val = 0;<br>
-  long pos = 0;<br>
<br>
   if (!output_file) return;<br>
<br>
-  pos = ftell(output_file);<br>
-  val = read_int32();<br>
+  flush_buffer();<br>
+  val = read_32bit_value();<br>
<br>
   if (val != (uint32_t)-1) {<br>
     /* There are counters present in the file. Merge them. */<br>
@@ -272,33 +330,30 @@ void llvm_gcda_emit_arcs(uint32_t num_co<br>
       return;<br>
     }<br>
<br>
-    val = read_int32();<br>
+    val = read_32bit_value();<br>
     if (val == (uint32_t)-1 || val / 2 != num_counters) {<br>
       fprintf(stderr, "profiling:invalid number of counters (%d)\n", val);<br>
       return;<br>
     }<br>
<br>
     old_ctrs = malloc(sizeof(uint64_t) * num_counters);<br>
+    for (i = 0; i < num_counters; ++i)<br>
+      old_ctrs[i] = read_64bit_value();<br>
<br>
-    if (read_into_buffer(old_ctrs, num_counters) == (uint64_t)-1) {<br>
-      fprintf(stderr, "profiling:invalid number of counters (%d)\n",<br>
-              num_counters);<br>
-      return;<br>
-    }<br>
-  }<br>
+    /* Reset the current buffer and file position. */<br>
+    memset(write_buffer, 0, WRITE_BUFFER_SIZE);<br>
+    cur_file_pos = save_cur_file_pos;<br>
+    cur_offset = 0;<br>
<br>
-  /* Reset for writing. */<br>
-  fseek(output_file, pos, SEEK_SET);<br>
+    fseek(output_file, cur_file_pos, SEEK_SET);<br>
+  }<br>
<br>
   /* Counter #1 (arcs) tag */<br>
-  fwrite("\0\0\xa1\1", 4, 1, output_file);<br>
-  write_int32(num_counters * 2);<br>
-  for (i = 0; i < num_counters; ++i)<br>
+  write_bytes("\0\0\xa1\1", 4);<br>
+  write_32bit_value(num_counters * 2);<br>
+  for (i = 0; i < num_counters; ++i) {<br>
     counters[i] += (old_ctrs ? old_ctrs[i] : 0);<br>
-<br>
-  if (write_from_buffer(counters, num_counters) == (uint64_t)-1) {<br>
-    fprintf(stderr, "profiling:cannot write to output file\n");<br>
-    return;<br>
+    write_64bit_value(counters[i]);<br>
   }<br>
<br>
   free(old_ctrs);<br>
@@ -313,7 +368,8 @@ void llvm_gcda_emit_arcs(uint32_t num_co<br>
 void llvm_gcda_end_file() {<br>
   /* Write out EOF record. */<br>
   if (!output_file) return;<br>
-  fwrite("\0\0\0\0\0\0\0\0", 8, 1, output_file);<br>
+  write_bytes("\0\0\0\0\0\0\0\0", 8);<br>
+  flush_buffer();<br>
   fclose(output_file);<br>
   output_file = NULL;<br>
<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>