aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/nixexpr.cc
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2020-02-24 01:32:01 +0100
committerEelco Dolstra <edolstra@gmail.com>2021-11-04 15:03:40 +0100
commit81e7c40264520b387358917987d101f5f5ae4705 (patch)
tree23fd5cda61df0808c67583571be182d8fd77e036 /src/libexpr/nixexpr.cc
parentab35cbd675610a52513f746051e98d0a50815bc1 (diff)
Optimize primop calls
We now parse function applications as a vector of arguments rather than as a chain of binary applications, e.g. 'substring 1 2 "foo"' is parsed as ExprCall { .fun = <substring>, .args = [ <1>, <2>, <"foo"> ] } rather than ExprApp (ExprApp (ExprApp <substring> <1>) <2>) <"foo"> This allows primops to be called immediately (if enough arguments are supplied) without having to allocate intermediate tPrimOpApp values. On $ nix-instantiate --dry-run '<nixpkgs/nixos/release-combined.nix>' -A nixos.tests.simple.x86_64-linux this gives a substantial performance improvement: user CPU time: median = 0.9209 mean = 0.9218 stddev = 0.0073 min = 0.9086 max = 0.9340 [rejected, p=0.00000, Δ=-0.21433±0.00677] elapsed time: median = 1.0585 mean = 1.0584 stddev = 0.0024 min = 1.0523 max = 1.0623 [rejected, p=0.00000, Δ=-0.20594±0.00236] because it reduces the number of tPrimOpApp allocations from 551990 to 42534 (i.e. only small minority of primop calls are partially applied) which in turn reduces time spent in the garbage collector.
Diffstat (limited to 'src/libexpr/nixexpr.cc')
-rw-r--r--src/libexpr/nixexpr.cc18
1 files changed, 17 insertions, 1 deletions
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 95a353a40..372e323bc 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -143,6 +143,16 @@ void ExprLambda::show(std::ostream & str) const
str << ": " << *body << ")";
}
+void ExprCall::show(std::ostream & str) const
+{
+ str << '(' << *fun;
+ for (auto e : args) {
+ str << ' ';
+ str << *e;
+ }
+ str << ')';
+}
+
void ExprLet::show(std::ostream & str) const
{
str << "(let ";
@@ -366,6 +376,13 @@ void ExprLambda::bindVars(const StaticEnv & env)
body->bindVars(newEnv);
}
+void ExprCall::bindVars(const StaticEnv & env)
+{
+ fun->bindVars(env);
+ for (auto e : args)
+ e->bindVars(env);
+}
+
void ExprLet::bindVars(const StaticEnv & env)
{
StaticEnv newEnv(false, &env, attrs->attrs.size());
@@ -461,5 +478,4 @@ size_t SymbolTable::totalSize() const
return n;
}
-
}