aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpennae <github@quasiparticle.net>2021-12-20 13:28:54 +0100
committerpennae <github@quasiparticle.net>2021-12-20 23:01:28 +0100
commit09b245690a9ab40847e3faa96646e4bd6ce033e0 (patch)
tree426d9a6c71141f027316e3aba1e408fb6f0b2865
parent6e6e998930f0d7361d64644eb37d9134e74e8501 (diff)
bulk-allocate Value instances in the evaluator
calling GC_malloc for each value is significantly more expensive than allocating a bunch of values at once with GC_malloc_many. "a bunch" here is a GC block size, ie 16KiB or less. this gives a 1.5% performance boost when evaluating our nixos system. tested with nix eval --raw --impure --expr 'with import <nixpkgs/nixos> {}; system' # on master Time (mean ± σ): 3.335 s ± 0.007 s [User: 2.774 s, System: 0.293 s] Range (min … max): 3.315 s … 3.347 s 50 runs # with this change Time (mean ± σ): 3.288 s ± 0.006 s [User: 2.728 s, System: 0.292 s] Range (min … max): 3.274 s … 3.307 s 50 runs
-rw-r--r--src/libexpr/eval.cc17
-rw-r--r--src/libexpr/eval.hh3
2 files changed, 19 insertions, 1 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 8cf4d9549..a95726f5f 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -821,8 +821,23 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
Value * EvalState::allocValue()
{
+ /* We use the boehm batch allocator to speed up allocations of Values (of which there are many).
+ GC_malloc_many returns a linked list of objects of the given size, where the first word
+ of each object is also the pointer to the next object in the list. This also means that we
+ have to explicitly clear the first word of every object we take. */
+ if (!valueAllocCache) {
+ valueAllocCache = GC_malloc_many(sizeof(Value));
+ if (!valueAllocCache) throw std::bad_alloc();
+ }
+
+ /* GC_NEXT is a convenience macro for accessing the first word of an object.
+ Take the first list item, advance the list to the next item, and clear the next pointer. */
+ void * p = valueAllocCache;
+ GC_PTR_STORE_AND_DIRTY(&valueAllocCache, GC_NEXT(p));
+ GC_NEXT(p) = nullptr;
+
nrValues++;
- auto v = (Value *) allocBytes(sizeof(Value));
+ auto v = (Value *) p;
return v;
}
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 1aab8e166..cc63294c6 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -133,6 +133,9 @@ private:
/* Cache used by prim_match(). */
std::shared_ptr<RegexCache> regexCache;
+ /* Allocation cache for GC'd Value objects. */
+ void * valueAllocCache = nullptr;
+
public:
EvalState(