diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index cd9c64594..02a9ea701 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -16,9 +16,9 @@ namespace nix { EvalState::EvalState() - : normalForms(32768), primOps(128) + : sessionNormalForms(32768), normalForms(32768), primOps(128) { - nrEvaluated = nrCached = 0; + nrEvaluated = nrCached = nrDephtAfterReset = 0; initNixExprHelpers(); @@ -803,10 +803,17 @@ Expr evalExpr(EvalState & state, Expr e) #endif state.nrEvaluated++; + state.nrDephtAfterReset++; /* Consult the memo table to quickly get the normal form of previously evaluated expressions. */ Expr nf = state.normalForms.get(e); + if (nf) { + state.nrCached++; + return nf; + } + + nf = state.sessionNormalForms.get(e); if (nf) { if (nf == makeBlackHole()) throwEvalError("infinite recursion encountered"); @@ -815,14 +822,22 @@ Expr evalExpr(EvalState & state, Expr e) } /* Otherwise, evaluate and memoize. */ - state.normalForms.set(e, makeBlackHole()); + state.sessionNormalForms.set(e, makeBlackHole()); try { nf = evalExpr2(state, e); } catch (Error & err) { - state.normalForms.remove(e); + state.sessionNormalForms.remove(e); throw; } - state.normalForms.set(e, nf); + + if (state.nrDephtAfterReset) { + state.sessionNormalForms.remove(e); + state.normalForms.set(e, nf); + state.nrDephtAfterReset--; + } else { + state.sessionNormalForms.set(e, nf); + } + return nf; } @@ -830,6 +845,7 @@ Expr evalExpr(EvalState & state, Expr e) Expr evalFile(EvalState & state, const Path & path) { startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); + state.nrDephtAfterReset = 0; Expr e = parseExprFromFile(state, path); try { return evalExpr(state, e); @@ -901,11 +917,13 @@ void printEvalStats(EvalState & state) char x; bool showStats = getEnv("NIX_SHOW_STATS", "0") != "0"; printMsg(showStats ? lvlInfo : lvlDebug, - format("evaluated %1% expressions, %2% cache hits, %3%%% efficiency, used %4% ATerm bytes, used %5% bytes of stack space") + format("evaluated %1% expressions, %2% cache hits, %3%%% efficiency, used %4% ATerm bytes, used %5% bytes of stack space, %6% normal reduction, %7% session dependent reduction.") % state.nrEvaluated % state.nrCached % ((float) state.nrCached / (float) state.nrEvaluated * 100) % AT_calcAllocatedSize() - % (&x - deepestStack)); + % (&x - deepestStack) + % state.normalForms.size() + % state.sessionNormalForms.size()); if (showStats) printATermMapStats(); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index fed6d3472..c8557a4b3 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -29,6 +29,7 @@ typedef Expr (* PrimOp) (EvalState &, const ATermVector & args); struct EvalState { + ATermMap sessionNormalForms; ATermMap normalForms; ATermMap primOps; DrvRoots drvRoots; @@ -37,6 +38,7 @@ struct EvalState unsigned int nrEvaluated; unsigned int nrCached; + unsigned int nrDephtAfterReset; bool allowUnsafeEquality; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 016e6abdb..223954f72 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -74,12 +74,14 @@ static Expr prim_null(EvalState & state, const ATermVector & args) platforms. */ static Expr prim_currentSystem(EvalState & state, const ATermVector & args) { + state.nrDephtAfterReset = 0; return makeStr(thisSystem); } static Expr prim_currentTime(EvalState & state, const ATermVector & args) { + state.nrDephtAfterReset = 0; return ATmake("Int()", time(0)); } @@ -228,6 +230,7 @@ static Expr prim_addErrorContext(EvalState & state, const ATermVector & args) static Expr prim_getEnv(EvalState & state, const ATermVector & args) { string name = evalStringNoCtx(state, args[0]); + state.nrDephtAfterReset = 0; return makeStr(getEnv(name)); } @@ -316,6 +319,7 @@ static Hash hashDerivationModulo(EvalState & state, Derivation drv) static Expr prim_derivationStrict(EvalState & state, const ATermVector & args) { startNest(nest, lvlVomit, "evaluating derivation"); + state.nrDephtAfterReset = 0; ATermMap attrs; queryAllAttrs(evalExpr(state, args[0]), attrs, true); @@ -549,6 +553,7 @@ static Expr prim_storePath(EvalState & state, const ATermVector & args) { PathSet context; Path path = canonPath(coerceToPath(state, args[0], context)); + state.nrDephtAfterReset = 0; if (!isInStore(path)) throw EvalError(format("path `%1%' is not in the Nix store") % path); Path path2 = toStorePath(path); @@ -565,6 +570,7 @@ static Expr prim_pathExists(EvalState & state, const ATermVector & args) Path path = coerceToPath(state, args[0], context); if (!context.empty()) throw EvalError(format("string `%1%' cannot refer to other paths") % path); + state.nrDephtAfterReset = 0; return makeBool(pathExists(path)); } @@ -598,6 +604,7 @@ static Expr prim_readFile(EvalState & state, const ATermVector & args) Path path = coerceToPath(state, args[0], context); if (!context.empty()) throw EvalError(format("string `%1%' cannot refer to other paths") % path); + state.nrDephtAfterReset = 0; return makeStr(readFile(path)); } @@ -637,6 +644,7 @@ static Expr prim_toFile(EvalState & state, const ATermVector & args) refs.insert(path); } + state.nrDephtAfterReset = 0; Path storePath = readOnlyMode ? computeStorePathForText(name, contents, refs) : store->addTextToStore(name, contents, refs); @@ -689,6 +697,7 @@ static Expr prim_filterSource(EvalState & state, const ATermVector & args) FilterFromExpr filter(state, args[0]); + state.nrDephtAfterReset = 0; Path dstPath = readOnlyMode ? computeStorePathForPath(path, true, htSHA256, filter).first : store->addToStore(path, true, htSHA256, filter);