From 43535499f38acc04367eeb4dd0d9938e9f8666f8 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Sun, 24 Oct 2010 20:09:37 +0000 Subject: [PATCH] * When allocating an attribute set, reserve enough space for all elements. This prevents the vector from having to resize itself. --- src/libexpr/eval.cc | 16 +++++----------- src/libexpr/eval.hh | 4 +--- src/libexpr/primops.cc | 23 ++++++++++++----------- src/nix-env/user-env.cc | 6 +++--- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 4aa8fc1e4..919ebd4ba 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -340,11 +340,12 @@ void EvalState::mkList(Value & v, unsigned int length) } -void EvalState::mkAttrs(Value & v) +void EvalState::mkAttrs(Value & v, unsigned int expected) { clearValue(v); v.type = tAttrs; v.attrs = NEW Bindings; + v.attrs->reserve(expected); nrAttrsets++; } @@ -391,13 +392,6 @@ Value * EvalState::maybeThunk(Env & env, Expr * expr) } -void EvalState::cloneAttrs(Value & src, Value & dst) -{ - mkAttrs(dst); - *dst.attrs = *src.attrs; -} - - void EvalState::evalFile(const Path & path, Value & v) { startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path); @@ -504,7 +498,7 @@ void ExprPath::eval(EvalState & state, Env & env, Value & v) void ExprAttrs::eval(EvalState & state, Env & env, Value & v) { - state.mkAttrs(v); // !!! reserve size + state.mkAttrs(v, attrs.size()); if (recursive) { /* Create a new environment that contains the attributes in @@ -758,7 +752,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) } Value actualArgs; - mkAttrs(actualArgs); + mkAttrs(actualArgs, fun.lambda.fun->formals->formals.size()); foreach (Formals::Formals_::iterator, i, fun.lambda.fun->formals->formals) { Bindings::iterator j = args.find(i->name); @@ -852,7 +846,7 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v) if (v1.attrs->size() == 0) { v = v2; return; } if (v2.attrs->size() == 0) { v = v1; return; } - state.mkAttrs(v); + state.mkAttrs(v, v1.attrs->size() + v2.attrs->size()); /* Merge the attribute sets, preferring values from the second set. Make sure to keep the resulting vector in sorted diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 7f801d112..7453ac189 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -319,13 +319,11 @@ public: Value * allocAttr(Value & vAttrs, const Symbol & name); void mkList(Value & v, unsigned int length); - void mkAttrs(Value & v); + void mkAttrs(Value & v, unsigned int expected); void mkThunk_(Value & v, Expr * expr); Value * maybeThunk(Env & env, Expr * expr); - void cloneAttrs(Value & src, Value & dst); - /* Print statistics. */ void printStats(); diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 7c713f384..a4812de06 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -206,7 +206,7 @@ static void prim_addErrorContext(EvalState & state, Value * * args, Value & v) * else => {success=false; value=false;} */ static void prim_tryEval(EvalState & state, Value * * args, Value & v) { - state.mkAttrs(v); + state.mkAttrs(v, 2); try { state.forceValue(*args[0]); v.attrs->push_back(Attr(state.symbols.create("value"), args[0])); @@ -484,7 +484,7 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v) state.drvHashes[drvPath] = hashDerivationModulo(state, drv); /* !!! assumes a single output */ - state.mkAttrs(v); + state.mkAttrs(v, 2); mkString(*state.allocAttr(v, state.sOutPath), outPath, singleton(drvPath)); mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton("=" + drvPath)); v.attrs->sort(); @@ -745,7 +745,7 @@ static void prim_removeAttrs(EvalState & state, Value * * args, Value & v) /* Copy all attributes not in that set. Note that we don't need to sort v.attrs because it's a subset of an already sorted vector. */ - state.mkAttrs(v); + state.mkAttrs(v, args[0]->attrs->size()); foreach (Bindings::iterator, i, *args[0]->attrs) { if (names.find(i->name) == names.end()) v.attrs->push_back(*i); @@ -761,7 +761,7 @@ static void prim_listToAttrs(EvalState & state, Value * * args, Value & v) { state.forceList(*args[0]); - state.mkAttrs(v); + state.mkAttrs(v, args[0]->list.length); std::set seen; @@ -798,7 +798,7 @@ static void prim_intersectAttrs(EvalState & state, Value * * args, Value & v) state.forceAttrs(*args[0]); state.forceAttrs(*args[1]); - state.mkAttrs(v); + state.mkAttrs(v, std::min(args[0]->attrs->size(), args[1]->attrs->size())); foreach (Bindings::iterator, i, *args[0]->attrs) { Bindings::iterator j = args[1]->attrs->find(i->name); @@ -827,14 +827,15 @@ static void prim_functionArgs(EvalState & state, Value * * args, Value & v) if (args[0]->type != tLambda) throw TypeError("`functionArgs' requires a function"); - state.mkAttrs(v); - - if (!args[0]->lambda.fun->matchAttrs) return; + if (!args[0]->lambda.fun->matchAttrs) { + state.mkAttrs(v, 0); + return; + } + state.mkAttrs(v, args[0]->lambda.fun->formals->formals.size()); foreach (Formals::Formals_::iterator, i, args[0]->lambda.fun->formals->formals) // !!! should optimise booleans (allocate only once) mkBool(*state.allocAttr(v, i->name), i->def); - v.attrs->sort(); } @@ -1015,7 +1016,7 @@ static void prim_parseDrvName(EvalState & state, Value * * args, Value & v) { string name = state.forceStringNoCtx(*args[0]); DrvName parsed(name); - state.mkAttrs(v); + state.mkAttrs(v, 2); mkString(*state.allocAttr(v, state.sName), parsed.name); mkString(*state.allocAttr(v, state.symbols.create("version")), parsed.version); v.attrs->sort(); @@ -1043,7 +1044,7 @@ void EvalState::createBaseEnv() Value v; /* `builtins' must be first! */ - mkAttrs(v); + mkAttrs(v, 128); addConstant("builtins", v); mkBool(v, true); diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index acd866197..865d24e2f 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -61,7 +61,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, Value & v(*state.allocValue()); manifest.list.elems[n++] = &v; - state.mkAttrs(v); + state.mkAttrs(v, 8); mkString(*state.allocAttr(v, state.sType), "derivation"); mkString(*state.allocAttr(v, state.sName), i->name); @@ -71,7 +71,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, mkString(*state.allocAttr(v, state.sDrvPath), i->queryDrvPath(state)); Value & vMeta = *state.allocAttr(v, state.sMeta); - state.mkAttrs(vMeta); + state.mkAttrs(vMeta, 16); MetaInfo meta = i->queryMetaInfo(state); @@ -118,7 +118,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, /* Construct a Nix expression that calls the user environment builder with the manifest as argument. */ Value args, topLevel; - state.mkAttrs(args); + state.mkAttrs(args, 3); mkString(*state.allocAttr(args, state.sSystem), thisSystem); mkString(*state.allocAttr(args, state.symbols.create("manifest")), manifestFile, singleton(manifestFile));