This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH: remove lseek in pre-compiled header output
- From: Robert Bowdidge <bowdidge at apple dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Robert Bowdidge <bowdidge at apple dot com>
- Date: Fri, 3 Oct 2003 13:56:43 -0700
- Subject: PATCH: remove lseek in pre-compiled header output
The current pre-compiled header generation code uses fseek to skip
ahead when a written-out object doesn't completely fill the buffer
given it by the garbage-collected memory allocator. This turns out to
be very inefficient on Mac OS X when writing to an NFS file system
because the file system code communicates with the remote server on
each fseek.
For example, Apple's SimpleText example creates a pre-compiled header
file that holds most required system headers. Creating this
pre-compiled header file would take 10 seconds on on a local disk, but
would take 120 seconds when writing to an NFS disk because of the
frequent flushes.
The solution is to replace the fseek with a write that fills out the
buffer size. The memory written out is filled with zeros to ensure pch
files can still be diff'd and not show random differences because of
garbage in unused memory. On operating systems using a standard
library derived from BSD (like Mac OS X), the change will result in a
significant improvement. On other operating systems, the fact that the
code now uses one function (fwrite) instead of a mix of functions
(fwrite and fseek) should ensure this doesn't sacrifice performance on
other systems.
A fixed-size array is used for the padding contents; if the padding is
larger than the contents (256 bytes), then it falls back to the old
approach. In the examples I checked out, the padding was never larger
than 256 bytes.
I tested this code with the gcc test suites, and found no differences
from the unmodified compiler. To check performance, I generated
pre-compiled headers on a Mac OS X system with both our local version
of gcc and a Mac-only set of headers, and an FSF version of the
compiler with a generic C program. I measured precompiled header
generation times with and without the change. In both cases, the time
required to generate the precompiled header on an NFS file system
dropped significantly; writing to a file on a local disk also improved.
Changes are below.
Thanks,
Robert Bowdidge
-------------------------------
ChangeLog entry:
2003-10-03 Robert Bowdidge <bowdidge@apple.com>
* ggc-page.c: (ggc_pch_write_object) replace fseek() with
fwrite() in PCH generation, avoiding
too-frequent flushes when writing to NFS file system
diff -u -b -d -c -3 -p -r1.75 ggc-page.c
cvs server: conflicting specifications of output style
*** gcc/ggc-page.c 19 Aug 2003 23:21:59 -0000 1.75
--- gcc/ggc-page.c 3 Oct 2003 20:52:35 -0000
*************** ggc_pch_write_object (struct ggc_pch_dat
*** 1969,1974 ****
--- 1969,1975 ----
size_t size)
{
unsigned order;
+ static const char emptyBytes[256];
if (size <= 256)
order = size_lookup[size];
*************** ggc_pch_write_object (struct ggc_pch_dat
*** 1982,1992 ****
if (fwrite (x, size, 1, f) != 1)
fatal_error ("can't write PCH file: %m");
! /* In the current implementation, SIZE is always equal to
! OBJECT_SIZE (order) and so the fseek is never executed. */
! if (size != OBJECT_SIZE (order)
! && fseek (f, OBJECT_SIZE (order) - size, SEEK_CUR) != 0)
! fatal_error ("can't write PCH file: %m");
d->written[order]++;
if (d->written[order] == d->d.totals[order]
--- 1983,2012 ----
if (fwrite (x, size, 1, f) != 1)
fatal_error ("can't write PCH file: %m");
! /* If SIZE is not the same as OBJECT_SIZE(order), then we need to
pad the
! object out to OBJECT_SIZE(order). This happens for strings. */
!
! if (size != OBJECT_SIZE (order))
! {
! unsigned padding = OBJECT_SIZE(order) - size;
!
! /* To speed small writes, we use a nulled-out array that's
larger
! than most padding requests as the source for our null bytes.
This
! permits us to do the padding with fwrite() rather than
fseek(), and
! limits the chance the the OS may try to flush any outstanding
! writes. */
! if (padding <= sizeof(emptyBytes))
! {
! if (fwrite (emptyBytes, 1, padding, f) != padding)
! fatal_error ("can't write PCH file");
! }
! else
! {
! /* Larger than our buffer? Just default to fseek. */
! if (fseek (f, padding, SEEK_CUR) != 0)
! fatal_error ("can't write PCH file");
! }
! }
d->written[order]++;
if (d->written[order] == d->d.totals[order]