From ec4a0419ad5374ad56137458e8de8bc4047cebe3 Mon Sep 17 00:00:00 2001 From: Zdenek Dvorak Date: Tue, 4 Mar 2003 21:56:24 +0100 Subject: [PATCH] gcov-io.h (gcov_save_position, [...]): Modified to enable reading/ writing of whole .da file just once. * gcov-io.h (gcov_save_position, gcov_reserve_length, gcov_resync, gcov_skip, gcov_skip_string, gcov_write_unsigned, gcov_write_counter, gcov_write_string, gcov_read_unsigned, gcov_read_counter, gcov_read_string, gcov_write_length): Modified to enable reading/ writing of whole .da file just once. (da_file_open, da_file_close, da_file_eof, da_file_error, da_file_position, da_file_seek, da_file_write, da_file_read): New functions. (actual_da_file, actual_da_file_position, actual_da_file_length, actual_da_file_buffer, actual_da_file_buffer_size): New static functions. * libgcov.c (gcov_exit): Modified to read/write the whole .da file at just once. From-SVN: r63800 --- gcc/ChangeLog | 17 +++ gcc/gcov-io.h | 326 +++++++++++++++++++++++++++++++++++++++++++++++--- gcc/libgcov.c | 122 +++++++++---------- 3 files changed, 383 insertions(+), 82 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c8b290ee62e..79e0741e5d3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2003-03-04 Zdenek Dvorak + + * gcov-io.h (gcov_save_position, gcov_reserve_length, gcov_resync, + gcov_skip, gcov_skip_string, gcov_write_unsigned, gcov_write_counter, + gcov_write_string, gcov_read_unsigned, gcov_read_counter, + gcov_read_string, gcov_write_length): Modified to enable reading/ + writing of whole .da file just once. + (da_file_open, da_file_close, da_file_eof, da_file_error, + da_file_position, da_file_seek, da_file_write, da_file_read): New + functions. + (actual_da_file, actual_da_file_position, actual_da_file_length, + actual_da_file_buffer, actual_da_file_buffer_size): New static + functions. + * libgcov.c (gcov_exit): Modified to read/write the whole .da file at + just once. + + 2003-03-04 Andreas Schwab * config/m68k/m68k.c (m68k_output_function_prologue): Fix CFA diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h index ce29f67c8cb..4fcd7de5d21 100644 --- a/gcc/gcov-io.h +++ b/gcc/gcov-io.h @@ -302,18 +302,27 @@ static int gcov_write_summary PARAMS ((FILE *, unsigned, ATTRIBUTE_UNUSED; #endif #define gcov_save_position(STREAM) \ - ftell (STREAM) + da_file_position (STREAM) #define gcov_reserve_length(STREAM) \ - (gcov_write_unsigned (STREAM, 0) ? 0 : ftell (STREAM) - 4) + (gcov_write_unsigned (STREAM, 0) ? 0 : da_file_position (STREAM) - 4) static int gcov_write_length PARAMS((FILE *, long)) ATTRIBUTE_UNUSED; #define gcov_resync(STREAM, BASE, LENGTH) \ - fseek (STREAM, BASE + (long)LENGTH, SEEK_SET) + da_file_seek (STREAM, BASE + (long)LENGTH, SEEK_SET) #define gcov_skip(STREAM, LENGTH) \ - fseek (STREAM, LENGTH, SEEK_CUR) + da_file_seek (STREAM, LENGTH, SEEK_CUR) #define gcov_skip_string(STREAM, LENGTH) \ - fseek (STREAM, (LENGTH) + 4 - ((LENGTH) & 3), SEEK_CUR) - + da_file_seek (STREAM, (LENGTH) + 4 - ((LENGTH) & 3), SEEK_CUR) +#if IN_LIBGCC2 +static FILE *da_file_open PARAMS ((const char *, int *)); +static int da_file_close PARAMS ((void)); +static int da_file_eof PARAMS ((void)); +static int da_file_error PARAMS ((void)); +#endif +static unsigned long da_file_position PARAMS ((FILE *)); +static int da_file_seek PARAMS ((FILE *, long, int)); +static size_t da_file_write PARAMS ((const void *, size_t, size_t, FILE *)); +static size_t da_file_read PARAMS ((void *, size_t, size_t, FILE *)); /* Write VALUE to coverage file FILE. Return nonzero if failed due to file i/o error, or value error. */ @@ -332,7 +341,7 @@ gcov_write_unsigned (file, value) value >>= 8; } return ((sizeof (value) > sizeof (buffer) && value) - || fwrite (buffer, sizeof (buffer), 1, file) != 1); + || da_file_write (buffer, 1, sizeof (buffer), file) != sizeof (buffer)); } /* Write VALUE to coverage file FILE. Return nonzero if failed due to @@ -353,7 +362,7 @@ gcov_write_counter (file, value) value >>= 8; } return ((sizeof (value) > sizeof (buffer) && value != 0 && value != -1) - || fwrite (buffer, sizeof (buffer), 1, file) != 1); + || da_file_write (buffer, 1, sizeof (buffer), file) != sizeof (buffer)); } /* Write VALUE to coverage file FILE. Return nonzero if failed due to @@ -366,11 +375,12 @@ gcov_write_string (file, string, length) const char *string; { unsigned pad = 0; + unsigned rem = 4 - (length & 3); if (string) return (gcov_write_unsigned (file, length) - || fwrite (string, length, 1, file) != 1 - || fwrite (&pad, 4 - (length & 3), 1, file) != 1); + || da_file_write (string, 1, length, file) != length + || da_file_write (&pad, 1, rem, file) != rem); else return gcov_write_unsigned (file, 0); } @@ -387,7 +397,7 @@ gcov_read_unsigned (file, value_p) unsigned ix; unsigned char buffer[4]; - if (fread (buffer, sizeof (buffer), 1, file) != 1) + if (da_file_read (buffer, 1, sizeof (buffer), file) != sizeof (buffer)) return 1; for (ix = sizeof (value); ix < sizeof (buffer); ix++) if (buffer[ix]) @@ -413,7 +423,7 @@ gcov_read_counter (file, value_p) unsigned ix; unsigned char buffer[8]; - if (fread (buffer, sizeof (buffer), 1, file) != 1) + if (da_file_read (buffer, 1, sizeof (buffer), file) != sizeof (buffer)) return 1; for (ix = sizeof (value); ix < sizeof (buffer); ix++) if (buffer[ix]) @@ -457,7 +467,7 @@ gcov_read_string (file, string_p, length_p) length += 4 - (length & 3); *string_p = (char *) xmalloc (length); - return fread (*string_p, length, 1, file) != 1; + return da_file_read (*string_p, 1, length, file) != length; } @@ -472,10 +482,10 @@ gcov_write_length (file, place) FILE *file; long place; { - long here = ftell (file); - int result = (!place || fseek (file, place, SEEK_SET) + long here = da_file_position (file); + int result = (!place || da_file_seek (file, place, SEEK_SET) || gcov_write_unsigned (file, here - place - 4)); - if (fseek (file, here, SEEK_SET)) + if (da_file_seek (file, here, SEEK_SET)) result = 1; return result; } @@ -517,4 +527,288 @@ gcov_write_summary (da_file, tag, summary) } #endif +#if IN_LIBGCC2 +/* The kernel had problems with managing a lot of small reads/writes we use; + the functions below are used to buffer whole file in memory, thus reading and + writing it only once. This should be feasible, as we have this amount + of memory for counters allocated anyway. */ + +static FILE *actual_da_file; +static unsigned long actual_da_file_position; +static unsigned long actual_da_file_length; +static char *actual_da_file_buffer; +static unsigned long actual_da_file_buffer_size; + +/* Open the file NAME and return it; in EXISTED return 1 if it existed + already. */ +static FILE * +da_file_open (name, existed) + const char *name; + int *existed; +{ +#if defined (TARGET_HAS_F_SETLKW) + struct flock s_flock; + + s_flock.l_type = F_WRLCK; + s_flock.l_whence = SEEK_SET; + s_flock.l_start = 0; + s_flock.l_len = 0; /* Until EOF. */ + s_flock.l_pid = getpid (); +#endif + + if (actual_da_file) + return 0; + actual_da_file_position = 0; + if (!actual_da_file_buffer) + { + actual_da_file_buffer = malloc (1); + actual_da_file_buffer_size = 1; + } + + actual_da_file = fopen (name, "r+t"); + if (actual_da_file) + *existed = 1; + else + { + actual_da_file = fopen (name, "w+t"); + if (actual_da_file) + *existed = 0; + else + return 0; + } + +#if defined (TARGET_HAS_F_SETLKW) + /* After a fork, another process might try to read and/or write + the same file simultaneously. So if we can, lock the file to + avoid race conditions. */ + while (fcntl (fileno (actual_da_file), F_SETLKW, &s_flock) + && errno == EINTR) + continue; +#endif + + if (*existed) + { + if (fseek (actual_da_file, 0, SEEK_END)) + { + fclose (actual_da_file); + actual_da_file = 0; + return 0; + } + actual_da_file_length = ftell (actual_da_file); + rewind (actual_da_file); + } + else + actual_da_file_length = 0; + + if (actual_da_file_length > actual_da_file_buffer_size) + { + actual_da_file_buffer_size = actual_da_file_length; + actual_da_file_buffer = realloc (actual_da_file_buffer, + actual_da_file_buffer_size); + if (!actual_da_file_buffer) + { + fclose (actual_da_file); + actual_da_file = 0; + return 0; + } + } + + if (*existed) + { + if (fread (actual_da_file_buffer, actual_da_file_length, + 1, actual_da_file) != 1) + { + fclose (actual_da_file); + actual_da_file = 0; + return 0; + } + rewind (actual_da_file); + } + + return actual_da_file; +} + +/* Write changes to the .da file and close it. */ +static int da_file_close () +{ + if (!actual_da_file) + return -1; + + if (fwrite (actual_da_file_buffer, actual_da_file_length, + 1, actual_da_file) != 1) + return da_file_error (); + + if (fclose (actual_da_file)) + { + actual_da_file = 0; + return -1; + } + + actual_da_file = 0; + return 0; +} + +/* Returns current position in .da file. */ +static unsigned long +da_file_position (file) + FILE *file; +{ + if (file) + return ftell (file); + return actual_da_file_position; +} + +/* Tests whether we have reached end of .da file. */ +static int +da_file_eof () +{ + return actual_da_file_position == actual_da_file_length; +} + +/* Change position in the .da file. */ +static int +da_file_seek (file, pos, whence) + FILE *file; + long pos; + int whence; +{ + if (file) + return fseek (file, pos, whence); + + if (!actual_da_file) + return -1; + + switch (whence) + { + case SEEK_CUR: + if (pos < 0 && (unsigned long) -pos > actual_da_file_position) + return da_file_error (); + + actual_da_file_position += pos; + break; + case SEEK_SET: + actual_da_file_position = pos; + break; + case SEEK_END: + if ((unsigned long) -pos > actual_da_file_length) + return da_file_error (); + actual_da_file_position = actual_da_file_length + pos; + } + if (actual_da_file_position > actual_da_file_length) + return da_file_error (); + return 0; +} + +/* Write LEN chars of DATA to actual .da file; ELTS is expected to be 1, + FILE 0. */ +static size_t +da_file_write (data, elts, len, file) + const void *data; + size_t elts; + size_t len; + FILE *file; +{ + size_t l = len; + const char *dat = data; + + if (file) + return fwrite (data, elts, len, file); + + if (elts != 1) + abort (); + + if (!actual_da_file) + return -1; + if (actual_da_file_position + len > actual_da_file_buffer_size) + { + actual_da_file_buffer_size = 2 * (actual_da_file_position + len); + actual_da_file_buffer = realloc (actual_da_file_buffer, + actual_da_file_buffer_size); + if (!actual_da_file_buffer) + return da_file_error (); + } + while (len--) + actual_da_file_buffer[actual_da_file_position++] = *dat++; + if (actual_da_file_position > actual_da_file_length) + actual_da_file_length = actual_da_file_position; + + return l; +} + +/* Read LEN chars of DATA from actual .da file; ELTS is expected to be 1, + FILE 0. */ +static size_t +da_file_read (data, elts, len, file) + void *data; + size_t elts; + size_t len; + FILE *file; +{ + size_t l; + char *dat = data; + + if (file) + return fread (data, elts, len, file); + + if (elts != 1) + abort (); + + if (!actual_da_file) + return -1; + if (actual_da_file_position + len > actual_da_file_length) + len = actual_da_file_length - actual_da_file_position; + l = len; + + while (len--) + *dat++ = actual_da_file_buffer[actual_da_file_position++]; + return l; +} + +/* Close the current .da file and report error. */ +static int +da_file_error () +{ + if (actual_da_file) + fclose (actual_da_file); + actual_da_file = 0; + return -1; +} +#else /* !IN_LIBGCC2 */ +static size_t +da_file_write (data, elts, len, file) + const void *data; + size_t elts; + size_t len; + FILE *file; +{ + return fwrite (data, elts, len, file); +} + +static size_t +da_file_read (data, elts, len, file) + void *data; + size_t elts; + size_t len; + FILE *file; +{ + return fread (data, elts, len, file); +} + +static unsigned long +da_file_position (file) + FILE *file; +{ + return ftell (file); +} + +static int +da_file_seek (file, pos, whence) + FILE *file; + long pos; + int whence; +{ + return fseek (file, pos, whence); +} +#endif + #endif /* GCC_GCOV_IO_H */ diff --git a/gcc/libgcov.c b/gcc/libgcov.c index 657de36d300..31a160eec20 100644 --- a/gcc/libgcov.c +++ b/gcc/libgcov.c @@ -41,12 +41,12 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */ #include -#include "gcov-io.h" #include #if defined (TARGET_HAS_F_SETLKW) #include #include #endif +#include "gcov-io.h" /* Chain of per-object gcov structures. */ static struct gcov_info *gcov_list; @@ -106,7 +106,6 @@ gcov_exit (void) for (ptr = gcov_list; ptr; ptr = ptr->next) { - FILE *da_file; struct gcov_summary object; struct gcov_summary local_prg; int merging = 0; @@ -154,39 +153,27 @@ gcov_exit (void) memset (&object, 0, sizeof (object)); /* Open for modification */ - if ((da_file = fopen (ptr->filename, "r+b"))) - merging = 1; - else if ((da_file = fopen (ptr->filename, "w+b"))) - ; - else + if (!da_file_open (ptr->filename, &merging)) { fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename); ptr->filename = 0; continue; } -#if defined (TARGET_HAS_F_SETLKW) - /* After a fork, another process might try to read and/or write - the same file simultaneously. So if we can, lock the file to - avoid race conditions. */ - while (fcntl (fileno (da_file), F_SETLKW, &s_flock) - && errno == EINTR) - continue; -#endif if (merging) { /* Merge data from file. */ - if (gcov_read_unsigned (da_file, &tag) || tag != GCOV_DATA_MAGIC) + if (gcov_read_unsigned (0, &tag) || tag != GCOV_DATA_MAGIC) { fprintf (stderr, "profiling:%s:Not a gcov data file\n", ptr->filename); read_fatal:; - fclose (da_file); + da_file_close (); ptr->filename = 0; continue; } - if (gcov_read_unsigned (da_file, &length) || length != GCOV_VERSION) + if (gcov_read_unsigned (0, &length) || length != GCOV_VERSION) { gcov_version_mismatch (ptr, length); goto read_fatal; @@ -196,8 +183,8 @@ gcov_exit (void) for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++) { - if (gcov_read_unsigned (da_file, &tag) - || gcov_read_unsigned (da_file, &length)) + if (gcov_read_unsigned (0, &tag) + || gcov_read_unsigned (0, &length)) { read_error:; fprintf (stderr, "profiling:%s:Error merging\n", @@ -214,9 +201,9 @@ gcov_exit (void) goto read_fatal; } - if (gcov_read_unsigned (da_file, &flength) - || gcov_skip_string (da_file, flength) - || gcov_read_unsigned (da_file, &checksum)) + if (gcov_read_unsigned (0, &flength) + || gcov_skip_string (0, flength) + || gcov_read_unsigned (0, &checksum)) goto read_error; if (flength != strlen (fn_info->name) || checksum != fn_info->checksum) @@ -227,46 +214,51 @@ gcov_exit (void) f_sect_index < fn_info->n_counter_sections; f_sect_index++) { - if (gcov_read_unsigned (da_file, &tag) - || gcov_read_unsigned (da_file, &length)) + unsigned n_counters; + + if (gcov_read_unsigned (0, &tag) + || gcov_read_unsigned (0, &length)) goto read_error; for (sect_index = 0; sect_index < ptr->n_counter_sections; sect_index++) if (ptr->counter_sections[sect_index].tag == tag) break; - if (fn_info->counter_sections[f_sect_index].tag != tag - || sect_index == ptr->n_counter_sections - || length / 8 != fn_info->counter_sections[f_sect_index].n_counters) + if (sect_index == ptr->n_counter_sections + || fn_info->counter_sections[f_sect_index].tag != tag) goto read_mismatch; - - for (jx = fn_info->counter_sections[f_sect_index].n_counters; - jx--; counters[sect_index]++) - if (gcov_read_counter (da_file, &count)) - goto read_error; + + n_counters = fn_info->counter_sections[f_sect_index].n_counters; + if (n_counters != length / 8) + goto read_mismatch; + + for (jx = 0; jx < n_counters; jx++) + if (gcov_read_counter (0, &count)) + goto read_error; else - *counters[sect_index] += count; + counters[sect_index][jx] += count; + counters[sect_index] += n_counters; } } /* Check object summary */ - if (gcov_read_unsigned (da_file, &tag) - || gcov_read_unsigned (da_file, &length)) + if (gcov_read_unsigned (0, &tag) + || gcov_read_unsigned (0, &length)) goto read_error; if (tag != GCOV_TAG_OBJECT_SUMMARY) goto read_mismatch; - if (gcov_read_summary (da_file, &object)) + if (gcov_read_summary (0, &object)) goto read_error; /* Check program summary */ while (1) { - long base = ftell (da_file); + long base = da_file_position (0); - if (gcov_read_unsigned (da_file, &tag) - || gcov_read_unsigned (da_file, &length)) + if (gcov_read_unsigned (0, &tag) + || gcov_read_unsigned (0, &length)) { - if (feof (da_file)) + if (da_file_eof ()) break; goto read_error; } @@ -274,7 +266,7 @@ gcov_exit (void) && tag != GCOV_TAG_PLACEHOLDER_SUMMARY && tag != GCOV_TAG_INCORRECT_SUMMARY) goto read_mismatch; - if (gcov_read_summary (da_file, &local_prg)) + if (gcov_read_summary (0, &local_prg)) goto read_error; if (local_prg.checksum != program.checksum) continue; @@ -301,7 +293,7 @@ gcov_exit (void) ptr->wkspc = base; break; } - fseek (da_file, 0, SEEK_SET); + da_file_seek (0, 0, SEEK_SET); } object.runs++; @@ -313,12 +305,12 @@ gcov_exit (void) /* Write out the data. */ if (/* magic */ - gcov_write_unsigned (da_file, GCOV_DATA_MAGIC) + gcov_write_unsigned (0, GCOV_DATA_MAGIC) /* version number */ - || gcov_write_unsigned (da_file, GCOV_VERSION)) + || gcov_write_unsigned (0, GCOV_VERSION)) { write_error:; - fclose (da_file); + da_file_close (); fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename); ptr->filename = 0; continue; @@ -330,14 +322,14 @@ gcov_exit (void) for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++) { /* Announce function. */ - if (gcov_write_unsigned (da_file, GCOV_TAG_FUNCTION) - || !(base = gcov_reserve_length (da_file)) + if (gcov_write_unsigned (0, GCOV_TAG_FUNCTION) + || !(base = gcov_reserve_length (0)) /* function name */ - || gcov_write_string (da_file, fn_info->name, + || gcov_write_string (0, fn_info->name, strlen (fn_info->name)) /* function checksum */ - || gcov_write_unsigned (da_file, fn_info->checksum) - || gcov_write_length (da_file, base)) + || gcov_write_unsigned (0, fn_info->checksum) + || gcov_write_length (0, base)) goto write_error; /* counters. */ @@ -354,8 +346,8 @@ gcov_exit (void) if (sect_index == ptr->n_counter_sections) abort (); - if (gcov_write_unsigned (da_file, tag) - || !(base = gcov_reserve_length (da_file))) + if (gcov_write_unsigned (0, tag) + || !(base = gcov_reserve_length (0))) goto write_error; for (jx = fn_info->counter_sections[f_sect_index].n_counters; jx--;) @@ -368,43 +360,41 @@ gcov_exit (void) if (object.arc_max_sum < count) object.arc_max_sum = count; } - if (gcov_write_counter (da_file, count)) + if (gcov_write_counter (0, count)) goto write_error; /* RIP Edsger Dijkstra */ } - if (gcov_write_length (da_file, base)) + if (gcov_write_length (0, base)) goto write_error; } } /* Object file summary. */ - if (gcov_write_summary (da_file, GCOV_TAG_OBJECT_SUMMARY, &object)) + if (gcov_write_summary (0, GCOV_TAG_OBJECT_SUMMARY, &object)) goto write_error; if (merging >= 0) { - if (fseek (da_file, 0, SEEK_END)) + if (da_file_seek (0, 0, SEEK_END)) goto write_error; - ptr->wkspc = ftell (da_file); - if (gcov_write_summary (da_file, GCOV_TAG_PLACEHOLDER_SUMMARY, + ptr->wkspc = da_file_position (0); + if (gcov_write_summary (0, GCOV_TAG_PLACEHOLDER_SUMMARY, &program)) goto write_error; } else if (ptr->wkspc) { /* Zap trailing program summary */ - if (fseek (da_file, ptr->wkspc, SEEK_SET)) + if (da_file_seek (0, ptr->wkspc, SEEK_SET)) goto write_error; if (!local_prg.runs) ptr->wkspc = 0; - if (gcov_write_unsigned (da_file, - local_prg.runs ? GCOV_TAG_PLACEHOLDER_SUMMARY - : GCOV_TAG_INCORRECT_SUMMARY)) + if (gcov_write_unsigned (0, local_prg.runs + ? GCOV_TAG_PLACEHOLDER_SUMMARY + : GCOV_TAG_INCORRECT_SUMMARY)) goto write_error; } - if (fflush (da_file)) - goto write_error; - if (fclose (da_file)) + if (da_file_close ()) { fprintf (stderr, "profiling:%s:Error closing\n", ptr->filename); ptr->filename = 0;