Bug 84257 - Extremely slow compilation from gcc source code under macOS 10.13
Summary: Extremely slow compilation from gcc source code under macOS 10.13
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: bootstrap (show other bugs)
Version: 7.3.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: build, compile-time-hog
Depends on:
Blocks:
 
Reported: 2018-02-07 08:09 UTC by 191919
Modified: 2024-01-24 22:38 UTC (History)
3 users (show)

See Also:
Host: *-*-darwin*
Target:
Build: *-*-darwin*
Known to work:
Known to fail:
Last reconfirmed: 2018-02-11 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description 191919 2018-02-07 08:09:58 UTC
In fact, this problem exists since very old version of gcc, but only in macOS 10.13 with SIP (System Integrity Protection) disabled.

I upgraded my Mac from 10.12.6 to 10.13.3 and recompiled gcc, the compilation time is about 5 times longer. To be exactly, it is not the compilation which was slowed down, but the configure step. Every single output, like 'checking build system type... x86_64-apple-darwin17.4.0', takes more time than in 10.12.6. This check, 'checking compiler gcc -g  ... yes' takes about 7 seconds. The entire compilation was unbearable SIX hours.

I ran a lot of checks and found that this only happens when compiling gcc. Other autoconf based configure script, such as php and mysql, runs as fast as before. And even inside gcc, if I run configure for gmp or isl in a separated terminal session, it is still as fast as before.

Finally I found the problem is caused by the DYLD_LIBRARY_PATH environment variable which during the configuration process is

/mv/objs/./gmp/.libs:/mv/objs/./prev-gmp/.libs:/mv/objs/./mpfr/src/.libs:/mv/objs/./prev-mpfr/src/.libs:/mv/objs/./mpc/src/.libs:/mv/objs/./prev-mpc/src/.libs:/mv/objs/./isl/.libs:/mv/objs/./prev-isl/.libs:/mv/objs/x86_64-apple-darwin17.3.0/libstdc++-v3/src/.libs:/mv/objs/x86_64-apple-darwin17.3.0/libsanitizer/.libs:/mv/objs/x86_64-apple-darwin17.3.0/libcilkrts/.libs:/mv/objs/x86_64-apple-darwin17.3.0/libssp/.libs:/mv/objs/x86_64-apple-darwin17.3.0/libgomp/.libs:/mv/objs/x86_64-apple-darwin17.3.0/libitm/.libs:/mv/objs/x86_64-apple-darwin17.3.0/libatomic/.libs:/mv/objs/./gcc:/mv/objs/./prev-gcc

(where /mv/objs is where I ran the configure script.)

The change of value of DYLD_LIBRARY_PATH was introduced by the root Makefile

...
	$(RPATH_ENVVAR)=`echo "$(TARGET_LIB_PATH)$$$(RPATH_ENVVAR)" | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; export $(RPATH_ENVVAR); \
	$(RPATH_ENVVAR)=`echo "$(HOST_LIB_PATH)$$$(RPATH_ENVVAR)" | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; export $(RPATH_ENVVAR);
...

then exported, in macOS 10.13.3 with SIP enabled, the DYLD_LIBRARY_PATH environment variable will be automatically ignored, but my Mac has had SIP disabled, so DYLD_LIBRARY_PATH got exported and every single step after that, the mach-o loader will  be affected. In macOS 10.12.6, even with SIP disabled, the compilation speed is not affected.

I commented out this line in the root Makefile:

RPATH_ENVVAR = DYLD_LIBRARY_PATH

(BTW, in ChangeLog, I know this was brought by this:

2005-03-25  Paolo Bonzini  <bonzini@gnu.org>

	* configure.in (RPATH_ENVVAR): Set to DYLD_LIBRARY_PATH on Darwin.
	* configure: Regenerate.
)

and recompiled gcc, this time, it took only *30 minutes* (vs. 6 hours).

I don't think setting RPATH_ENVVAR to DYLD_LIBRARY_PATH is necessary on modern macOS versions, please check.
Comment 1 Andrew Pinski 2018-02-07 09:20:02 UTC
From the sound of it, dyld is slow at searching directories for libraries.
What file system are you using?  

Also does Apple have a recommended way around the slowness of setting DYLD_LIBRARY_PATH; that is have you reported the slowness to them ?
Comment 2 191919 2018-02-07 09:29:35 UTC
I tried with the combination of the following settings under macOS 10.13.3:

internal SSD / external HD
HFS+ / APFS
SIP enabled / SIP disabled

The only factor that affects is SIP status. Once I disable it, DYLD_LIBRARY_PATH will be exported, then the scripts run slowly.

I have reported the problem to Apple, but since turning off SIP is not recommended, I don't think they are going to fix it in short future.
Comment 3 191919 2018-02-07 13:13:11 UTC
In macOS 10.12.6 with SIP disabled, the value of DYLD_LIBRARY_PATH was modified to the same as in macOS 10.13.3, but the compilation speed was not affected.

I guess this is a regression of macOS code to handle DYLD_LIBRARY_PATH in an SIP-disabled environment.

Long since OS X El Capitan which introduced SIP (aka rootless), DYLD_LIBRARY_PATH was practically screened and no one complained about it, I think it is safe to say that the line #3 of the following code taken from configure.ac of gcc is not necessary and can be removed.

1 | case "${host}" in
2 |  *-*-hpux*) RPATH_ENVVAR=SHLIB_PATH ;;
3 |  *-*-darwin*) RPATH_ENVVAR=DYLD_LIBRARY_PATH ;;
4 |  *-*-mingw* | *-*-cygwin ) RPATH_ENVVAR=PATH ;;
5 |  *) RPATH_ENVVAR=LD_LIBRARY_PATH ;;
6 | esac
Comment 4 Dominique d'Humieres 2018-02-11 18:40:40 UTC
Confirmed even if I recover only a factor 2.
Comment 5 Iain Sandoe 2018-12-19 10:33:35 UTC
(In reply to Dominique d'Humieres from comment #4)
> Confirmed even if I recover only a factor 2.

Unfortunately, neither SIP's ignoring - nor removing RPATH_ENVVAR - produces the intended result.

Quoting from the Makefile 
"
# This is the list of directories that may be needed in RPATH_ENVVAR
# so that programs built for the target machine work.
TARGET_LIB_PATH =

# This is the list of directories that may be needed in RPATH_ENVVAR
# so that programs built for the host machine work.
HOST_LIB_PATH =
"

> I don't think setting RPATH_ENVVAR to DYLD_LIBRARY_PATH is necessary on modern macOS > versions, please check.

The requirement has nothing to do with 'modern' c.f. 'old' macOS/Darwin; these paths are intended to ensure that the correct (just-built, or even not present in the system installation) libraries are available to the stage#1 target libraries build and stage#2+ where needed.  For most people's "usual" build the compiler is statically linked with libstdc++ &c. and so this really only affects configure steps when the new compiler is generating code that _should_ use the newly-built support libs.

When SIP is enabled (or when you remove the DYLD_LIBRARY_PATH setting) we have been "getting away" falling back to system versions of libstdc++ and libgcc_s.x ... this doesn't work if one introduces a new lib that isn't present on the system (which I want to do to solve the long-standing hassles with the unwinder).

* As an aside, there is no Good Solution to using DYLD_LIBRARY_PATH - if it's exported at the top level, since it must be honoured for *every* exe that runs below this, which means that it also affects system-utils (e.g. ld).. this has been a source of instability on occasion.

So.. what to do?

We don't (well I don't) really want to be forced to switch SIP off to build toolchains, but OTOH it's necessary to manipulate the library load ordering when building a toolchain....

1) Speculation: that there are a lot of paths to search and they might contain many files, so that if there's no caching of the results (perhaps that was present pre-SIP and is now removed) .. it could mean a lot of work to find the libgcc_s - that's the last path in the list.  

 * To test this hypothesis, I'm going to experiment with re-ordering the search path (temporary fix).

2) A possible proper fix is to make use of @rpath/ and set appropriate rpaths in the build.  A while ago I was experimenting with this to solve some of our general deployment issues
 * will look out those patches.

3) We could (probably) abandon the shared libgcc_ext lib, after some patches in progress to eliminate the unwinder hassles.  This would hide (most) of the problem, but not really solve it.
  * I can easily try this.

1 and 3 are, of course, the easier options (they paper over cracks for the short-term) - but 2 might be quite tricky to get right (it has to work in the build layout _and_ when installed).

4) I did think that we could perhaps move all built host libs to a Known Place in the build tree [e.g. $(builddir)/host-libs, prev-host-libs] (likewise target libs, to a separate Known Place).  That would mean a reduced number of paths to search, and that path would only have the libs - not thousands of other files too.  That's probably quite a bit of build/test system hacking tho ..
Comment 6 Iain Sandoe 2018-12-19 13:41:42 UTC
(In reply to Iain Sandoe from comment #5)

> 1) Speculation: that there are a lot of paths to search and they might
> contain many files, so that if there's no caching of the results (perhaps
> that was present pre-SIP and is now removed) .. it could mean a lot of work
> to find the libgcc_s - that's the last path in the list.  
> 
>  * To test this hypothesis, I'm going to experiment with re-ordering the
> search path (temporary fix).

So some experiments

 * average GCC build time difference (loaded machine, 80% of threads in use) - 3:1

 * variation is quite high - from 3:1 - 20:1 if one just does a single configure operation repeatedly (I speculate that when dyld is busy, then things slow down).

 * Removing all but the GCC path, more or less behaves the same as an empty DYLD_LIBRARY_PATH

 * However, simply re-ordering the paths doesn't seem to be effective, so I speculate that it's the process of searching the paths for libs that are _not_ found (and therefore then picked up from their usual place) that's the time sink
Comment 7 Eric Gallager 2020-05-07 22:43:43 UTC
(In reply to 191919 from comment #2)
> I tried with the combination of the following settings under macOS 10.13.3:
> 
> internal SSD / external HD
> HFS+ / APFS
> SIP enabled / SIP disabled
> 
> The only factor that affects is SIP status. Once I disable it,
> DYLD_LIBRARY_PATH will be exported, then the scripts run slowly.
> 
> I have reported the problem to Apple, but since turning off SIP is not
> recommended, I don't think they are going to fix it in short future.

This is a great example of why it'd be so good to have a fully-FOSS fork of Darwin that can make different recommendations about things like that.
Comment 8 Eric Gallager 2021-07-31 22:07:09 UTC
the MacPorts project applies the following patch to work around this issue: https://github.com/macports/macports-ports/commit/0641e588e989b7b3e5049ca79e354339ccb403ca
Comment 9 Iain Sandoe 2021-07-31 22:42:49 UTC
(In reply to Eric Gallager from comment #8)
> the MacPorts project applies the following patch to work around this issue:
> https://github.com/macports/macports-ports/commit/
> 0641e588e989b7b3e5049ca79e354339ccb403ca

Well, that disables the use of DYLD_LIBRARY_PATH, but does not provide a replacement (i.e. it's a workaround only).

---

I have patches that resolve this by using @rpath for libraries on macOS versions that support it - and switch off the use of DYLD_LIBRARY_PATH there (which isn't acted on).  This solution also restores the ability to test the compiler without first installing it.

The patches are on trial branches (they are needed on the arm64 port) - and AFAIK the build problems with a couple of packages were resolved.  It remains to tidy them up for application / posting as needed.