Speed up application startup by using ld.so.cache#207061
Speed up application startup by using ld.so.cache#207061winterqt wants to merge 2 commits intoNixOS:stagingfrom
ld.so.cache#207061Conversation
ld.so.cache
|
After looking around some more, I stumbled across @fzakaria'a nix-harden-needed, which may be a better choice over Guix's solution (per the README, they want to integrate it into Nixpkgs). (Farid: hi, figured I'd loop you in here, considering you have interest in this problem :) |
Hi Winter! Thank you for pinging me. My hot-take: Edit: This is a great PR btw -- very concise if it works. Only unfortunate thing is patching but maybe you can upstream something to make it configurable based on an ELF file section. It has the added benefit of supporting LD_LIBRARY_PATH which the other options don't (maybe though that's a feature?) |
|
Here is a document of some other much more "visionary" ideas I have for Nix + NixOS. |
|
So I hope you don't mind me asking this here (if you'd rather discuss over e.g. IRC, Matrix, or email to avoid cluttering up this PR, let me know), but what does Shrinkwrap provide that this cache approach doesn't? They seemingly both eliminate the intensive RPATH traversal. I know there's one advantage you list in the README:
but I admit I'm confused as to what a practical example of this would look like/what the problem is in general 😅. Do you mind explaining? |
It does work; I've tested it with I think an advantage to this solution is definitely that it's minimally invasive and concise, as you mention.
(Why doesn't Shrinkwrap support it, since it just lifts dependencies up to the parent ELF?) |
|
Reached out on Matrix. |
|
Some questions:
|
| ../../build-support/setup-hooks/set-source-date-epoch-to-latest.sh | ||
| ../../build-support/setup-hooks/strip.sh | ||
| ] ++ lib.optionals hasCC [ cc ]; | ||
| ] ++ lib.optionals hostPlatform.isLinux [ ../../build-support/setup-hooks/generate-ld-cache.sh ] |
There was a problem hiding this comment.
hostPlatform.isLinux is no specific enough, for example pkgsMusl doesn't have a ldconfig. Maybe hostPlatform.isLinux && hostPlatform.isGnu?
generating LD cache for ELF executables in /nix/store/bgm2nivmwfa94pw6xlial071z9
0vv5pg-nano-7.1
found lib: /nix/store/62hdd7jfmj90wrwl6dp94hj6xzl9cgvq-ncurses-6.3-p20220507/lib
/libncursesw.so.6
found lib: /nix/store/mpgmlwjdd9g61w92q5d9g8y7r66fp8j6-musl-1.2.3/lib/ld-musl-x8
6_64.so.1
found lib dirs: /nix/store/62hdd7jfmj90wrwl6dp94hj6xzl9cgvq-ncurses-6.3-p2022050
7/lib /nix/store/mpgmlwjdd9g61w92q5d9g8y7r66fp8j6-musl-1.2.3/lib
/nix/store/6j095nxqj7qylwbbp4m00kb640gca06x-generate-ld-cache.sh: line 41: ldcon
fig: command not found
failed to generate LD cache
(nix-build -A pkgsMusl.nano)
There was a problem hiding this comment.
Good point this only works for Glibc
|
building stdenv comes up with some errors (that are probably not fatal only because shell is terrible): might be better to add this hook to the final linux stdenv stage only. cross-building an armv7 test system from scratch fails at python: buildEnv (and presumably symlinkJoin and friends) don't seem to like the approach :( edit |
Adding Not sure what to do about |
|
|
||
| fixupOutputHooks+=('if [ -z "${dontGenerateLDCache-}" ]; then generateLDCache "$prefix"; fi') | ||
|
|
||
| generateLDCache() { |
There was a problem hiding this comment.
why not just use patchelf to list the dependencies rather than this bash ?
(does patchelf list the needed transitive? if not, you can write a tiny C binary using https://github.com/lief-project/LIEF)
Might be more maintainable.
There was a problem hiding this comment.
we've done some investigating and it looks like a purpose-built tool that crawls a dep tree and generates a cache file will be the best thing to do. ld and ldconfig apparently can't be made to work in cross-builds (ldd certainly not, for ldconfig we've found nothing doing it with glibc. only one instance with uclibc, which doesn't want to build for armv7 right now (and that doesn't bode well for using its ldconfig))
would very much like to make this rust though, C ought to disappear and rustc is in our closures anyways
|
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: |
|
There was a similar patch and discussion from NixOS/patchelf#357 (comment) that started to fold this into the patchelf phase. I'm a fan of the ld.so.cache approach due to the possibility of providing a different cache en-masse, or to mutable locations for testing/debugging!) (but the shrinkwrap also has merits. Looks like the ldd searching for transitive deps is the main difference. I fear this makes the approach more fragile. What are the pros/cons here?
This would make it easier to then patch or redirect to a new place later. I can imagine a |
| + static const char store[] = @STORE_DIRECTORY@; | ||
| + const char *origin = _dl_get_origin (); | ||
| + | ||
| + /* Check whether ORIGIN is something like "/gnu/store/…-foo/bin". */ |
There was a problem hiding this comment.
| + /* Check whether ORIGIN is something like "/gnu/store/…-foo/bin". */ | |
| + /* Check whether ORIGIN is something like "/nix/store/…-foo/bin". */ |
|
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/2022-01-03-nixpkgs-architecture-team-meeting-23/24404/1 |
|
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: |
|
What the status on this currently? |
|
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: |
|
I don't understand, why aren't fzakaria's solutions plain better, compared to a cache? |
|
I have some interesting work in similar vein for relocation processing that is a clear win for Nixpkgs as well; I plan to speak + write about it. |
|
This looks interesting, is there any progress still being made? Did everyone involved just leave the nix ecosystem, or what happened? And what would be needed to get this to a usable state? |
|
Biggest wins seem to be if you are on NFS; I guess they are a minor (non-vocal) community :) |
|
Why? because of latency/bandwidth limit of network? In that case i'd expect some improvements for my external USB based setups too... |
Yes latency; I wrote more in depth about it in https://arxiv.org/abs/2211.05118 |
Description of changes
This PR does two things:
$ORIGIN/../etc/ld.so.cacheinstead of/etc/ld.so.cache, and to prefer the cache overRPATHentriesgenerate-ld-cache, to facilitate the generation of these cachesThis was originally implemented by Guix's Ludovic Courtès in August of 2021 (after Ricardo came up with the idea) -- see their blog post and their discussion on the change for more information + some benchmarks. The glibc patch is copied verbatim from the Guix codebase.
As noted in the linked Guix issue, there are a few things to consider here:
$ORIGIN/../etc/ld.so.cachepath means that it can only be used with first-level sub-directories likebinandsbinld.so.cachelddto get the required dependencies, as opposed to just using the data from the ELF.When discussing this with pennae, they brought up the idea of embedding an absolute path to the cache in an ELF section, and adjusting the patch to do that. We may want to do this instead; I'd appreciate thoughts on the matter.
I'd like to thank the Guix folks mentioned above for originally coming up with and implementing this idea, as well as pennae for nerd sniping me into looking at perf stuff, and their thoughts on the matter.
Things done
sandbox = trueset innix.conf? (See Nix manual)nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage./result/bin/)nixos/doc/manual/md-to-db.shto update generated release notes