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

Reid Kleckner rnk at google.com
Thu May 16 09:22:37 PDT 2013


On Wed, May 15, 2013 at 5:31 PM, Bill Wendling <isanbard at gmail.com> wrote:

> 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();
>

Can len be > WRITE_BUFFER_SIZE?


> +  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;
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20130516/d1c54816/attachment.html>


More information about the llvm-commits mailing list