The dyld shared cache lives in /var/db/dyld/. The two files of interest are dyld_shared_cache_i386.map (for x86-32) and shared_region_roots/Applications.paths. Both are regular text files. The former shows the contents of the shared cache for the i386 architecture and the latter is what update_dyld_shared_cache inspects.
There’s no prebinding on newer versions of Mac OSX and the dyld shared cache is automatically updated as needed. Tracing Safari disk activity during startup reveals that basically all its dynamic libraries are pulled from the dyld shared cache.
It’s possible to add Firefox (…/Firefox.app/Contents/MacOS/firefox-bin) to Applications.paths and the change will persist across reboots. Unfortunately, only a handful of libraries that Firefox uses are pulled into the cache by update_dyld_shared_cache. I’m speculating that this may have something to do with @executable_path/XUL and friends (otool -L …/firefox-bin).
Safari uses absolute paths to frameworks in /System/Library/Frameworks so I speculate that relative paths are what is preventing XUL and others from going into the cache.
It’s possible to fix relative library paths in a given library, e.g. fix.sh XUL where fix.sh looks like this
1 2 3 4 5 6 7 8 9 10 11 12 | |
Firefox has to be recompiled with LDFLAGS=-header-pad_max_install_names__ in MOZCONFIG_ to make this happen since new library paths are greater than the space allocated in the Mach-O binary. See the man page for install_name_tool for details.
It’s possible to force dynamic libraries into the cache by putting dynamic library paths into shared_region_roots/Applications.paths instead of executables. I wasn’t successful in caching XUL, though, regardless of what I did. XUL is the Firefox dynamic library, it doesn’t even have a dylib extension.
In the end it doesn’t seem to matter since there’s a baffling lack of difference between Firefox and Safari cold stats, despite Safari pulling everything from the cache and Firefox using a large number of non-cached dylibs.
Here are the cold startup stats for Safari
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
and Firefox
1 2 3 4 5 6 7 8 9 10 11 12 | |
Notice a large and significant difference? Me neither.
The other thing that I cannot explain at the moment is where the rest of the startup time goes, e.g.
1 2 | |
So it took less than 1 second to dynamically link Firefox but where did the other 9 seconds of startup go?
cold.sh is rather simple
1 2 3 4 5 | |
and the startup.d script doesn’t do much either
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
main-entry is my static probe, built into the Firefox source code. It fires once the main Firefox function, XRE_main, is entered.
I don’t have an explanation yet but 9 seconds is a very large difference but it just may be DTrace because of similar cold startup timings for Safari and Firefox.