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
This commit is contained in:
Eelco Dolstra 2024-04-26 15:48:46 +02:00 committed by Qyriad
parent c55dcc6c13
commit fb7d315411
2 changed files with 24 additions and 8 deletions

View file

@ -393,13 +393,10 @@ ref<eval_cache::EvalCache> openEvalCache(
EvalState & state, EvalState & state,
std::shared_ptr<flake::LockedFlake> lockedFlake) std::shared_ptr<flake::LockedFlake> lockedFlake)
{ {
auto fingerprint = lockedFlake->getFingerprint(); auto fingerprint = evalSettings.useEvalCache && evalSettings.pureEval
return make_ref<nix::eval_cache::EvalCache>( ? std::make_optional(lockedFlake->getFingerprint())
evalSettings.useEvalCache && evalSettings.pureEval : std::nullopt;
? std::optional { std::cref(fingerprint) } auto rootLoader = [&state, lockedFlake]()
: std::nullopt,
state,
[&state, lockedFlake]()
{ {
/* For testing whether the evaluation cache is /* For testing whether the evaluation cache is
complete. */ complete. */
@ -415,7 +412,17 @@ ref<eval_cache::EvalCache> openEvalCache(
assert(aOutputs); assert(aOutputs);
return aOutputs->value; 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<nix::eval_cache::EvalCache>(fingerprint, state, rootLoader)).first;
}
return search->second;
} else {
return make_ref<nix::eval_cache::EvalCache>(std::nullopt, state, rootLoader);
}
} }
Installables SourceExprCommand::parseInstallables( Installables SourceExprCommand::parseInstallables(

View file

@ -33,6 +33,10 @@ class EvalState;
class StorePath; class StorePath;
struct SingleDerivedPath; struct SingleDerivedPath;
enum RepairFlag : bool; enum RepairFlag : bool;
struct MemoryInputAccessor;
namespace eval_cache {
class EvalCache;
}
/** /**
@ -234,6 +238,11 @@ public:
return *new EvalErrorBuilder<T>(*this, args...); return *new EvalErrorBuilder<T>(*this, args...);
} }
/**
* A cache for evaluation caches, so as to reuse the same root value if possible
*/
std::map<const Hash, ref<eval_cache::EvalCache>> evalCaches;
private: private:
/* Cache for calls to addToStore(); maps source paths to the store /* Cache for calls to addToStore(); maps source paths to the store