Hi Jim,
I've got a C language source code TU that is 1.3 MiB large. I didn't write it (I know better), but I have to make it coexist in a rather lengthy system build, and the leader of the system build team is justifably upset with me.
As we see, the compilation time grows by a factor of 15X. I see the rebuffer_line() (listing.c:541) routine
Since this function is only used by the listing code, you could just not enable listing when assembling your huge application...
It looks like most of listing.c was rewritten for 2.20. I tried removing the fseek(FILE *, 0, SEEK_SET) call and made a couple of refactoring changes to make sure I'm seeking the proper source line.
Unfortunately your patch does not work. It removes the fseek and rereading of the source file, but it does not actually search backwards to find an earlier line, which is the entire point of the rebuffer_line() function.
Instead, please could you try out the attached patch and let me know if it works for you.
Cheers Nick
Index: gas/listing.c =================================================================== RCS file: /cvs/src/src/gas/listing.c,v retrieving revision 1.51 diff -u -3 -p -r1.51 listing.c --- gas/listing.c 27 Jul 2012 03:32:21 -0000 1.51 +++ gas/listing.c 22 Mar 2013 14:04:25 -0000 @@ -553,7 +553,8 @@ buffer_line (file_info_type *file, char /* This function rewinds the requested file back to the line requested, reads it in again into the buffer provided and then restores the file - back to its original location. */ + back to its original location. Returns the buffer pointer upon success + or an empty string if an error occurs. */ static char * rebuffer_line (file_info_type * file, @@ -562,13 +563,15 @@ rebuffer_line (file_info_type * file, unsigned int size) { unsigned int count = 0; - unsigned int current_line = 1; + unsigned int current_line; char * p = buffer; long pos; + long pos2; int c; + bfd_boolean found = FALSE; /* Sanity checks. */ - if (file == NULL || buffer == NULL || size == 0 || file->linenum <= linenum) + if (file == NULL || buffer == NULL || size <= 1 || file->linenum <= linenum) return ""; /* Check the cache and see if we last used this file. */ @@ -596,39 +599,72 @@ rebuffer_line (file_info_type * file, } /* Remember where we are in the current file. */ - pos = ftell (last_open_file); + pos2 = pos = ftell (last_open_file); + if (pos < 3) + return ""; + current_line = file->linenum; - /* Go back to the beginning. */ - fseek (last_open_file, 0, SEEK_SET); + /* Leave room for the nul at the end of the buffer. */ + size -= 1; + buffer[size] = 0; - /* Skip lines prior to the one we are interested in. */ - while (current_line < linenum) + /* Increment the current line count by one. + This is to allow for the fact that we are searching for the + start of a previous line, but we do this by detecting end-of-line + character(s) not start-of-line characters. */ + ++ current_line; + + while (pos2 > 0 && ! found) { - /* fgets only stops on newlines and has a size limit, - so we read one character at a time instead. */ - do + char * ptr; + + /* Move backwards through the file, looking for earlier lines. */ + pos2 = (long) size > pos2 ? 0 : pos2 - size; + fseek (last_open_file, pos2, SEEK_SET); + + /* Our caller has kindly provided us with a buffer, so we use it. */ + if (fread (buffer, size, 1, last_open_file) != size) { - c = fgetc (last_open_file); + as_warn (_("unable to rebuffer file: %s\n"), file->filename); + return ""; } - while (c != EOF && c != '\n' && c != '\r'); - ++ current_line; - - if (c == '\r' || c == '\n') + for (ptr = buffer + size; ptr >= buffer; -- ptr) { - int next = fgetc (last_open_file); + if (*ptr == '\n') + { + -- current_line; - /* If '\r' is followed by '\n', swallow that. Likewise, if '\n' - is followed by '\r', swallow that as well. */ - if ((c == '\r' && next != '\n') - || (c == '\n' && next != '\r')) - ungetc (next, last_open_file); + if (current_line == linenum) + { + /* We have found the start of the line we seek. */ + found = TRUE; + + /* FIXME: We could skip the read-in-the-line code + below if we know that we already have the whole + line in the buffer. */ + + /* Advance pos2 to the newline character we have just located. */ + pos2 += (ptr - buffer); + + /* Skip the newline and, if present, the carriage return. */ + if (ptr + 1 == buffer + size) + { + ++pos2; + if (fgetc (last_open_file) == '\r') + ++ pos2; + } + else + pos2 += (ptr[1] == '\r' ? 2 : 1); + + /* Move the file pointer to this location. */ + fseek (last_open_file, pos2, SEEK_SET); + break; + } + } } } - /* Leave room for the nul at the end of the buffer. */ - size -= 1; - /* Read in the line. */ c = fgetc (last_open_file);
_______________________________________________ bug-binutils mailing list bug-binutils@gnu.org https://lists.gnu.org/mailman/listinfo/bug-binutils