From 1d363c39844bde5fb303d262bd04ed4f0e788063 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 26 Apr 2024 15:48:46 +0200 Subject: [PATCH] Merge pull request #10570 from layus/shared_caches Share evaluation caches across installables Before: $ rm -rf ~/.cache/nix && time -f '%E' nix build --dry-run \ 'nixpkgs#hello' \ 'nixpkgs#clang' \ 'nixpkgs#cargo' \ 'nixpkgs#rustup' \ 'nixpkgs#bear' \ 'nixpkgs#firefox' \ 'nixpkgs#git-revise' \ 'nixpkgs#hyperfine' \ 'nixpkgs#curlie' \ 'nixpkgs#xz' \ 'nixpkgs#ripgrep' 0:03.61 After: $ rm -rf ~/.cache/nix && time -f '%E' nix build --dry-run \ 'nixpkgs#hello' \ 'nixpkgs#clang' \ 'nixpkgs#cargo' \ 'nixpkgs#rustup' \ 'nixpkgs#bear' \ 'nixpkgs#firefox' \ 'nixpkgs#git-revise' \ 'nixpkgs#hyperfine' \ 'nixpkgs#curlie' \ 'nixpkgs#xz' \ 'nixpkgs#ripgrep' 0:01.46 This could probably use a more proper benchmark... Fixes #313 (cherry picked from commit de51e5c335865e3e0a8cccd283fec1a52cce243f) Change-Id: I9350bebd462b6af12c51db5bf432321abfe84a16 --- src/libcmd/installables.cc | 23 +++++++++++++++-------- src/libexpr/eval.hh | 9 +++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index dca17555a..919db8c41 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -398,13 +398,10 @@ ref openEvalCache( EvalState & state, std::shared_ptr lockedFlake) { - auto fingerprint = lockedFlake->getFingerprint(); - return make_ref( - evalSettings.useEvalCache && evalSettings.pureEval - ? std::optional { std::cref(fingerprint) } - : std::nullopt, - state, - [&state, lockedFlake]() + auto fingerprint = evalSettings.useEvalCache && evalSettings.pureEval + ? std::make_optional(lockedFlake->getFingerprint()) + : std::nullopt; + auto rootLoader = [&state, lockedFlake]() { /* For testing whether the evaluation cache is complete. */ @@ -420,7 +417,17 @@ ref openEvalCache( assert(aOutputs); return aOutputs->value; - }); + }; + + if (fingerprint) { + auto search = state.evalCaches.find(fingerprint.value()); + if (search == state.evalCaches.end()) { + search = state.evalCaches.emplace(fingerprint.value(), make_ref(fingerprint, state, rootLoader)).first; + } + return search->second; + } else { + return make_ref(std::nullopt, state, rootLoader); + } } Installables SourceExprCommand::parseInstallables( diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 2291d618c..69f56f6a8 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -32,6 +32,10 @@ class EvalState; class StorePath; struct SingleDerivedPath; enum RepairFlag : bool; +struct MemoryInputAccessor; +namespace eval_cache { + class EvalCache; +} /** @@ -233,6 +237,11 @@ public: return *new EvalErrorBuilder(*this, args...); } + /** + * A cache for evaluation caches, so as to reuse the same root value if possible + */ + std::map> evalCaches; + private: /* Cache for calls to addToStore(); maps source paths to the store