This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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]


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]