From f491ae97d472bfd6305a8f3e8c58fac1fdc443a4 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Sat, 4 Feb 2012 13:50:25 +0000 Subject: [PATCH] =?UTF-8?q?*=20Inline=20some=20functions=20and=20get=20rid?= =?UTF-8?q?=20of=20the=20indirection=20through=20=20=20EvalState::eval().?= =?UTF-8?q?=20=20This=20gives=20a=2012%=20speedup=20on=20=E2=80=98nix-inst?= =?UTF-8?q?antiate=20=20=20/etc/nixos/nixos/=20-A=20system=20--readonly-mo?= =?UTF-8?q?de=E2=80=99=20(from=201.01s=20to=200.89s).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libexpr/Makefile.am | 2 +- src/libexpr/eval-inline.hh | 61 ++++++++++++ src/libexpr/eval.cc | 131 +++++-------------------- src/libexpr/eval.hh | 13 ++- src/libexpr/get-drvs.cc | 1 + src/libexpr/primops.cc | 1 + src/nix-instantiate/nix-instantiate.cc | 1 + 7 files changed, 94 insertions(+), 116 deletions(-) create mode 100644 src/libexpr/eval-inline.hh diff --git a/src/libexpr/Makefile.am b/src/libexpr/Makefile.am index 9ca4b2448..3e7e7e856 100644 --- a/src/libexpr/Makefile.am +++ b/src/libexpr/Makefile.am @@ -6,7 +6,7 @@ libexpr_la_SOURCES = \ names.cc pkginclude_HEADERS = \ - nixexpr.hh eval.hh lexer-tab.hh parser-tab.hh \ + nixexpr.hh eval.hh eval-inline.hh lexer-tab.hh parser-tab.hh \ get-drvs.hh attr-path.hh value-to-xml.hh common-opts.hh \ names.hh symbol-table.hh value.hh diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh new file mode 100644 index 000000000..6026a7d11 --- /dev/null +++ b/src/libexpr/eval-inline.hh @@ -0,0 +1,61 @@ +#ifndef __EVAL_INLINE_H +#define __EVAL_INLINE_H + +#include "eval.hh" + +#define LocalNoInline(f) static f __attribute__((noinline)); f +#define LocalNoInlineNoReturn(f) static f __attribute__((noinline, noreturn)); f + +namespace nix { + + +LocalNoInlineNoReturn(void throwEvalError(const char * s)) +{ + throw EvalError(s); +} + +LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s2)) +{ + throw TypeError(format(s) % s2); +} + + +void EvalState::forceValue(Value & v) +{ + if (v.type == tThunk) { + ValueType saved = v.type; + try { + v.type = tBlackhole; + //checkInterrupt(); + v.thunk.expr->eval(*this, *v.thunk.env, v); + } catch (Error & e) { + v.type = saved; + throw; + } + } + else if (v.type == tApp) + callFunction(*v.app.left, *v.app.right, v); + else if (v.type == tBlackhole) + throwEvalError("infinite recursion encountered"); +} + + +inline void EvalState::forceAttrs(Value & v) +{ + forceValue(v); + if (v.type != tAttrs) + throwTypeError("value is %1% while an attribute set was expected", showType(v)); +} + + +inline void EvalState::forceList(Value & v) +{ + forceValue(v); + if (v.type != tList) + throwTypeError("value is %1% while a list was expected", showType(v)); +} + + +} + +#endif /* !__EVAL_INLINE_H */ diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index fa31a85a0..6ce65e3e1 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -4,6 +4,7 @@ #include "store-api.hh" #include "derivations.hh" #include "globals.hh" +#include "eval-inline.hh" #include #include @@ -27,10 +28,6 @@ #endif -#define LocalNoInline(f) static f __attribute__((noinline)); f -#define LocalNoInlineNoReturn(f) static f __attribute__((noinline, noreturn)); f - - namespace nix { @@ -227,11 +224,6 @@ void EvalState::addPrimOp(const string & name, evaluator. So here are some helper functions for throwing exceptions. */ -LocalNoInlineNoReturn(void throwEvalError(const char * s)) -{ - throw EvalError(s); -} - LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2)) { throw EvalError(format(s) % s2); @@ -247,11 +239,6 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s)) throw TypeError(s); } -LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s2)) -{ - throw TypeError(format(s) % s2); -} - LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos, const string & s2)) { throw TypeError(format(s) % pos % s2); @@ -309,7 +296,7 @@ void mkPath(Value & v, const char * s) } -Value * EvalState::lookupVar(Env * env, const VarRef & var) +inline Value * EvalState::lookupVar(Env * env, const VarRef & var) { for (unsigned int l = var.level; l; --l, env = env->up) ; @@ -435,7 +422,6 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env) } - void EvalState::evalFile(const Path & path, Value & v) { FileEvalCache::iterator i = fileEvalCache.find(path); @@ -454,61 +440,25 @@ void EvalState::evalFile(const Path & path, Value & v) } -struct RecursionCounter -{ - EvalState & state; - RecursionCounter(EvalState & state) : state(state) - { - state.recursionDepth++; - if (state.recursionDepth > state.maxRecursionDepth) - state.maxRecursionDepth = state.recursionDepth; - } - ~RecursionCounter() - { - state.recursionDepth--; - } -}; - - -void EvalState::eval(Env & env, Expr * e, Value & v) -{ - /* When changing this function, make sure that you don't cause a - (large) increase in stack consumption! */ - - /* !!! Disable this eventually. */ - RecursionCounter r(*this); - char x; - if (&x < deepestStack) deepestStack = &x; - - //debug(format("eval: %1%") % *e); - - checkInterrupt(); - - nrEvaluated++; - - e->eval(*this, env, v); -} - - void EvalState::eval(Expr * e, Value & v) { - eval(baseEnv, e, v); + e->eval(*this, baseEnv, v); } -bool EvalState::evalBool(Env & env, Expr * e) +inline bool EvalState::evalBool(Env & env, Expr * e) { Value v; - eval(env, e, v); + e->eval(*this, env, v); if (v.type != tBool) throwTypeError("value is %1% while a Boolean was expected", showType(v)); return v.boolean; } -void EvalState::evalAttrs(Env & env, Expr * e, Value & v) +inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v) { - eval(env, e, v); + e->eval(*this, env, v); if (v.type != tAttrs) throwTypeError("value is %1% while an attribute set was expected", showType(v)); } @@ -622,7 +572,7 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v) else env2.values[displ++] = i->second.e->maybeThunk(state, env2); - state.eval(env2, body, v); + body->eval(state, env2, v); } @@ -650,7 +600,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) Pos * pos = 0; Value * vAttrs = &vTmp; - state.eval(env, e, vTmp); + e->eval(state, env, vTmp); try { @@ -662,7 +612,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) if (vAttrs->type != tAttrs || (j = vAttrs->attrs->find(*i)) == vAttrs->attrs->end()) { - state.eval(env, def, v); + def->eval(state, env, v); return; } } else { @@ -692,7 +642,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v) Value vTmp; Value * vAttrs = &vTmp; - state.eval(env, e, vTmp); + e->eval(state, env, vTmp); foreach (AttrPath::const_iterator, i, attrPath) { state.forceValue(*vAttrs); @@ -722,7 +672,7 @@ void ExprLambda::eval(EvalState & state, Env & env, Value & v) void ExprApp::eval(EvalState & state, Env & env, Value & v) { Value vFun; - state.eval(env, e1, vFun); + e1->eval(state, env, vFun); state.callFunction(vFun, *(e2->maybeThunk(state, env)), v); } @@ -814,7 +764,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v) } try { - eval(env2, fun.lambda.fun->body, v); + fun.lambda.fun->body->eval(*this, env2, v); } catch (Error & e) { addErrorPrefix(e, "while evaluating the function at %1%:\n", fun.lambda.fun->pos); throw; @@ -857,13 +807,13 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v) env2.values[0] = state.allocValue(); state.evalAttrs(env, attrs, *env2.values[0]); - state.eval(env2, body, v); + body->eval(state, env2, v); } void ExprIf::eval(EvalState & state, Env & env, Value & v) { - state.eval(env, state.evalBool(env, cond) ? then : else_, v); + (state.evalBool(env, cond) ? then : else_)->eval(state, env, v); } @@ -871,7 +821,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v) { if (!state.evalBool(env, cond)) throwAssertionError("assertion failed at %1%", pos); - state.eval(env, body, v); + body->eval(state, env, v); } @@ -883,16 +833,16 @@ void ExprOpNot::eval(EvalState & state, Env & env, Value & v) void ExprOpEq::eval(EvalState & state, Env & env, Value & v) { - Value v1; state.eval(env, e1, v1); - Value v2; state.eval(env, e2, v2); + Value v1; e1->eval(state, env, v1); + Value v2; e2->eval(state, env, v2); mkBool(v, state.eqValues(v1, v2)); } void ExprOpNEq::eval(EvalState & state, Env & env, Value & v) { - Value v1; state.eval(env, e1, v1); - Value v2; state.eval(env, e2, v2); + Value v1; e1->eval(state, env, v1); + Value v2; e2->eval(state, env, v2); mkBool(v, !state.eqValues(v1, v2)); } @@ -954,9 +904,9 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v) void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v) { - Value v1; state.eval(env, e1, v1); + Value v1; e1->eval(state, env, v1); state.forceList(v1); - Value v2; state.eval(env, e2, v2); + Value v2; e2->eval(state, env, v2); state.forceList(v2); state.mkList(v, v1.list.length + v2.list.length); for (unsigned int n = 0; n < v1.list.length; ++n) @@ -975,7 +925,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) Value vStr; foreach (vector::iterator, i, *es) { - state.eval(env, *i, vStr); + (*i)->eval(state, env, vStr); /* If the first element is a path, then the result will also be a path, we don't copy anything (yet - that's done later, @@ -999,25 +949,6 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) } -void EvalState::forceValue(Value & v) -{ - if (v.type == tThunk) { - ValueType saved = v.type; - try { - v.type = tBlackhole; - eval(*v.thunk.env, v.thunk.expr, v); - } catch (Error & e) { - v.type = saved; - throw; - } - } - else if (v.type == tApp) - callFunction(*v.app.left, *v.app.right, v); - else if (v.type == tBlackhole) - throwEvalError("infinite recursion encountered"); -} - - void EvalState::strictForceValue(Value & v) { forceValue(v); @@ -1052,22 +983,6 @@ bool EvalState::forceBool(Value & v) } -void EvalState::forceAttrs(Value & v) -{ - forceValue(v); - if (v.type != tAttrs) - throwTypeError("value is %1% while an attribute set was expected", showType(v)); -} - - -void EvalState::forceList(Value & v) -{ - forceValue(v); - if (v.type != tList) - throwTypeError("value is %1% while a list was expected", showType(v)); -} - - void EvalState::forceFunction(Value & v) { forceValue(v); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 91004fe4c..c4ba170e8 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -138,18 +138,17 @@ public: /* Evaluate an expression to normal form, storing the result in value `v'. */ void eval(Expr * e, Value & v); - void eval(Env & env, Expr * e, Value & v); /* Evaluation the expression, then verify that it has the expected type. */ - bool evalBool(Env & env, Expr * e); - void evalAttrs(Env & env, Expr * e, Value & v); + inline bool evalBool(Env & env, Expr * e); + inline void evalAttrs(Env & env, Expr * e, Value & v); /* If `v' is a thunk, enter it and overwrite `v' with the result of the evaluation of the thunk. If `v' is a delayed function application, call the function and overwrite `v' with the result. Otherwise, this is a no-op. */ - void forceValue(Value & v); + inline void forceValue(Value & v); /* Force a value, then recursively force list elements and attributes. */ @@ -158,8 +157,8 @@ public: /* Force `v', and then verify that it has the expected type. */ int forceInt(Value & v); bool forceBool(Value & v); - void forceAttrs(Value & v); - void forceList(Value & v); + inline void forceAttrs(Value & v); + inline void forceList(Value & v); void forceFunction(Value & v); // either lambda or primop string forceString(Value & v); string forceString(Value & v, PathSet & context); @@ -203,7 +202,7 @@ private: void addPrimOp(const string & name, unsigned int arity, PrimOpFun primOp); - Value * lookupVar(Env * env, const VarRef & var); + inline Value * lookupVar(Env * env, const VarRef & var); friend class ExprVar; friend class ExprAttrs; diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index a28a705d2..6670d0636 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -1,5 +1,6 @@ #include "get-drvs.hh" #include "util.hh" +#include "eval-inline.hh" namespace nix { diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index bdf8dddca..4a171a2ae 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -6,6 +6,7 @@ #include "archive.hh" #include "value-to-xml.hh" #include "names.hh" +#include "eval-inline.hh" #include #include diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index 93aa50943..8f3a290f3 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -1,6 +1,7 @@ #include "globals.hh" #include "shared.hh" #include "eval.hh" +#include "eval-inline.hh" #include "get-drvs.hh" #include "attr-path.hh" #include "value-to-xml.hh"