Store Attrs inside Bindings

This prevents a double allocation per attribute set.
This commit is contained in:
Eelco Dolstra 2014-09-19 16:49:41 +02:00
parent 0342eb1705
commit 5b58991a71
9 changed files with 101 additions and 60 deletions

View file

@ -25,17 +25,19 @@ bool parseAutoArgs(Strings::iterator & i,
} }
void evalAutoArgs(EvalState & state, std::map<string, string> & in, Bindings & out) Bindings * evalAutoArgs(EvalState & state, std::map<string, string> & in)
{ {
for (auto & i: in) { Bindings * res = state.allocBindings(in.size());
for (auto & i : in) {
Value * v = state.allocValue(); Value * v = state.allocValue();
if (i.second[0] == 'E') if (i.second[0] == 'E')
state.mkThunk_(*v, state.parseExprFromString(string(i.second, 1), absPath("."))); state.mkThunk_(*v, state.parseExprFromString(string(i.second, 1), absPath(".")));
else else
mkString(*v, string(i.second, 1)); mkString(*v, string(i.second, 1));
out.push_back(Attr(state.symbols.create(i.first), v)); res->push_back(Attr(state.symbols.create(i.first), v));
} }
out.sort(); res->sort();
return res;
} }

View file

@ -8,7 +8,7 @@ namespace nix {
bool parseAutoArgs(Strings::iterator & i, bool parseAutoArgs(Strings::iterator & i,
const Strings::iterator & argsEnd, std::map<string, string> & res); const Strings::iterator & argsEnd, std::map<string, string> & res);
void evalAutoArgs(EvalState & state, std::map<string, string> & in, Bindings & out); Bindings * evalAutoArgs(EvalState & state, std::map<string, string> & in);
bool parseSearchPathArg(Strings::iterator & i, bool parseSearchPathArg(Strings::iterator & i,
const Strings::iterator & argsEnd, Strings & searchPath); const Strings::iterator & argsEnd, Strings & searchPath);

View file

@ -35,7 +35,7 @@ namespace nix {
Bindings::iterator Bindings::find(const Symbol & name) Bindings::iterator Bindings::find(const Symbol & name)
{ {
Attr key(name, 0); Attr key(name, 0);
iterator i = lower_bound(begin(), end(), key); iterator i = std::lower_bound(begin(), end(), key);
if (i != end() && i->name == name) return i; if (i != end() && i->name == name) return i;
return end(); return end();
} }
@ -175,7 +175,7 @@ EvalState::EvalState(const Strings & _searchPath)
, baseEnvDispl(0) , baseEnvDispl(0)
{ {
nrEnvs = nrValuesInEnvs = nrValues = nrListElems = 0; nrEnvs = nrValuesInEnvs = nrValues = nrListElems = 0;
nrAttrsets = nrOpUpdates = nrOpUpdateValuesCopied = 0; nrAttrsets = nrAttrsInAttrsets = nrOpUpdates = nrOpUpdateValuesCopied = 0;
nrListConcats = nrPrimOpCalls = nrFunctionCalls = 0; nrListConcats = nrPrimOpCalls = nrFunctionCalls = 0;
countCalls = getEnv("NIX_COUNT_CALLS", "0") != "0"; countCalls = getEnv("NIX_COUNT_CALLS", "0") != "0";
@ -433,6 +433,12 @@ Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name)
} }
Bindings * EvalState::allocBindings(Bindings::size_t capacity)
{
return new (GC_MALLOC(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings(capacity);
}
void EvalState::mkList(Value & v, unsigned int length) void EvalState::mkList(Value & v, unsigned int length)
{ {
v.type = tList; v.type = tList;
@ -446,9 +452,9 @@ void EvalState::mkAttrs(Value & v, unsigned int expected)
{ {
clearValue(v); clearValue(v);
v.type = tAttrs; v.type = tAttrs;
v.attrs = NEW Bindings; v.attrs = allocBindings(expected);
v.attrs->reserve(expected);
nrAttrsets++; nrAttrsets++;
nrAttrsInAttrsets += expected;
} }
@ -619,7 +625,7 @@ void ExprPath::eval(EvalState & state, Env & env, Value & v)
void ExprAttrs::eval(EvalState & state, Env & env, Value & v) void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
{ {
state.mkAttrs(v, attrs.size()); state.mkAttrs(v, attrs.size() + dynamicAttrs.size());
Env *dynamicEnv = &env; Env *dynamicEnv = &env;
if (recursive) { if (recursive) {
@ -658,15 +664,19 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
if (hasOverrides) { if (hasOverrides) {
Value * vOverrides = (*v.attrs)[overrides->second.displ].value; Value * vOverrides = (*v.attrs)[overrides->second.displ].value;
state.forceAttrs(*vOverrides); state.forceAttrs(*vOverrides);
foreach (Bindings::iterator, i, *vOverrides->attrs) { Bindings * newBnds = state.allocBindings(v.attrs->size() + vOverrides->attrs->size());
AttrDefs::iterator j = attrs.find(i->name); for (auto & i : *v.attrs)
newBnds->push_back(i);
for (auto & i : *vOverrides->attrs) {
AttrDefs::iterator j = attrs.find(i.name);
if (j != attrs.end()) { if (j != attrs.end()) {
(*v.attrs)[j->second.displ] = *i; (*newBnds)[j->second.displ] = i;
env2.values[j->second.displ] = i->value; env2.values[j->second.displ] = i.value;
} else } else
v.attrs->push_back(*i); newBnds->push_back(i);
} }
v.attrs->sort(); newBnds->sort();
v.attrs = newBnds;
} }
} }
@ -692,8 +702,8 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
i->valueExpr->setName(nameSym); i->valueExpr->setName(nameSym);
/* Keep sorted order so find can catch duplicates */ /* Keep sorted order so find can catch duplicates */
v.attrs->insert(lower_bound(v.attrs->begin(), v.attrs->end(), Attr(nameSym, 0)), v.attrs->push_back(Attr(nameSym, i->valueExpr->maybeThunk(state, *dynamicEnv), &i->pos));
Attr(nameSym, i->valueExpr->maybeThunk(state, *dynamicEnv), &i->pos)); v.attrs->sort(); // FIXME: inefficient
} }
} }
@ -1424,7 +1434,8 @@ void EvalState::printStats()
printMsg(v, format(" list concatenations: %1%") % nrListConcats); printMsg(v, format(" list concatenations: %1%") % nrListConcats);
printMsg(v, format(" values allocated: %1% (%2% bytes)") printMsg(v, format(" values allocated: %1% (%2% bytes)")
% nrValues % (nrValues * sizeof(Value))); % nrValues % (nrValues * sizeof(Value)));
printMsg(v, format(" sets allocated: %1%") % nrAttrsets); printMsg(v, format(" sets allocated: %1% (%2% bytes)")
% nrAttrsets % (nrAttrsets * sizeof(Bindings) + nrAttrsInAttrsets * sizeof(Attr)));
printMsg(v, format(" right-biased unions: %1%") % nrOpUpdates); printMsg(v, format(" right-biased unions: %1%") % nrOpUpdates);
printMsg(v, format(" values copied in right-biased unions: %1%") % nrOpUpdateValuesCopied); printMsg(v, format(" values copied in right-biased unions: %1%") % nrOpUpdateValuesCopied);
printMsg(v, format(" symbols in symbol table: %1%") % symbols.size()); printMsg(v, format(" symbols in symbol table: %1%") % symbols.size());

View file

@ -16,23 +16,59 @@ namespace nix {
class EvalState; class EvalState;
struct Attr;
/* Sets are represented as a vector of attributes, sorted by symbol struct Attr
(i.e. pointer to the attribute name in the symbol table). */ {
#if HAVE_BOEHMGC Symbol name;
typedef std::vector<Attr, gc_allocator<Attr> > BindingsBase; Value * value;
#else Pos * pos;
typedef std::vector<Attr> BindingsBase; Attr(Symbol name, Value * value, Pos * pos = &noPos)
#endif : name(name), value(value), pos(pos) { };
Attr() : pos(&noPos) { };
bool operator < (const Attr & a) const
{
return name < a.name;
}
};
class Bindings : public BindingsBase class Bindings
{ {
public: public:
typedef uint32_t size_t;
private:
size_t size_, capacity;
Attr attrs[0];
Bindings(uint32_t capacity) : size_(0), capacity(capacity) { }
public:
size_t size() { return size_; }
bool empty() { return !size_; }
typedef Attr * iterator;
void push_back(const Attr & attr)
{
assert(size_ < capacity);
attrs[size_++] = attr;
}
iterator find(const Symbol & name); iterator find(const Symbol & name);
iterator begin() { return &attrs[0]; }
iterator end() { return &attrs[size_]; }
Attr & operator[](size_t pos)
{
return attrs[pos];
}
void sort(); void sort();
friend class EvalState;
}; };
@ -58,21 +94,6 @@ struct Env
}; };
struct Attr
{
Symbol name;
Value * value;
Pos * pos;
Attr(Symbol name, Value * value, Pos * pos = &noPos)
: name(name), value(value), pos(pos) { };
Attr() : pos(&noPos) { };
bool operator < (const Attr & a) const
{
return name < a.name;
}
};
void mkString(Value & v, const string & s, const PathSet & context = PathSet()); void mkString(Value & v, const string & s, const PathSet & context = PathSet());
void copyContext(const Value & v, PathSet & context); void copyContext(const Value & v, PathSet & context);
@ -245,6 +266,8 @@ public:
Value * allocAttr(Value & vAttrs, const Symbol & name); Value * allocAttr(Value & vAttrs, const Symbol & name);
Bindings * allocBindings(Bindings::size_t capacity);
void mkList(Value & v, unsigned int length); void mkList(Value & v, unsigned int length);
void mkAttrs(Value & v, unsigned int expected); void mkAttrs(Value & v, unsigned int expected);
void mkThunk_(Value & v, Expr * expr); void mkThunk_(Value & v, Expr * expr);
@ -264,6 +287,7 @@ private:
unsigned long nrValues; unsigned long nrValues;
unsigned long nrListElems; unsigned long nrListElems;
unsigned long nrAttrsets; unsigned long nrAttrsets;
unsigned long nrAttrsInAttrsets;
unsigned long nrOpUpdates; unsigned long nrOpUpdates;
unsigned long nrOpUpdateValuesCopied; unsigned long nrOpUpdateValuesCopied;
unsigned long nrListConcats; unsigned long nrListConcats;

View file

@ -161,12 +161,12 @@ void DrvInfo::setMeta(const string & name, Value * v)
{ {
getMeta(); getMeta();
Bindings * old = meta; Bindings * old = meta;
meta = new Bindings(); meta = state->allocBindings(1 + (old ? old->size() : 0));
Symbol sym = state->symbols.create(name); Symbol sym = state->symbols.create(name);
if (old) if (old)
foreach (Bindings::iterator, i, *old) for (auto i : *old)
if (i->name != sym) if (i.name != sym)
meta->push_back(*i); meta->push_back(i);
if (v) meta->push_back(Attr(sym, v)); if (v) meta->push_back(Attr(sym, v));
meta->sort(); meta->sort();
} }

View file

@ -14,8 +14,10 @@ static void skipWhitespace(const char * & s)
#if HAVE_BOEHMGC #if HAVE_BOEHMGC
typedef std::vector<Value *, gc_allocator<Value *> > ValueVector; typedef std::vector<Value *, gc_allocator<Value *> > ValueVector;
typedef std::map<Symbol, Value *, std::less<Symbol>, gc_allocator<Value *> > ValueMap;
#else #else
typedef std::vector<Value *> ValueVector; typedef std::vector<Value *> ValueVector;
typedef std::map<Symbol, Value *> ValueMap;
#endif #endif
@ -76,22 +78,25 @@ static void parseJSON(EvalState & state, const char * & s, Value & v)
else if (*s == '{') { else if (*s == '{') {
s++; s++;
state.mkAttrs(v, 1); ValueMap attrs;
while (1) { while (1) {
skipWhitespace(s); skipWhitespace(s);
if (v.attrs->empty() && *s == '}') break; if (attrs.empty() && *s == '}') break;
string name = parseJSONString(s); string name = parseJSONString(s);
skipWhitespace(s); skipWhitespace(s);
if (*s != ':') throw JSONParseError("expected : in JSON object"); if (*s != ':') throw JSONParseError("expected : in JSON object");
s++; s++;
Value * v2 = state.allocValue(); Value * v2 = state.allocValue();
parseJSON(state, s, *v2); parseJSON(state, s, *v2);
v.attrs->push_back(Attr(state.symbols.create(name), v2)); attrs[state.symbols.create(name)] = v2;
skipWhitespace(s); skipWhitespace(s);
if (*s == '}') break; if (*s == '}') break;
if (*s != ',') throw JSONParseError("expected , or } after JSON member"); if (*s != ',') throw JSONParseError("expected , or } after JSON member");
s++; s++;
} }
state.mkAttrs(v, attrs.size());
for (auto & i : attrs)
v.attrs->push_back(Attr(i.first, i.second));
v.attrs->sort(); v.attrs->sort();
s++; s++;
} }

View file

@ -44,7 +44,7 @@ struct InstallSourceInfo
Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */ Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */
Path profile; /* for srcProfile */ Path profile; /* for srcProfile */
string systemFilter; /* for srcNixExprDrvs */ string systemFilter; /* for srcNixExprDrvs */
Bindings autoArgs; Bindings * autoArgs;
}; };
@ -350,7 +350,7 @@ static void queryInstSources(EvalState & state,
Nix expression. */ Nix expression. */
DrvInfos allElems; DrvInfos allElems;
loadDerivations(state, instSource.nixExprPath, loadDerivations(state, instSource.nixExprPath,
instSource.systemFilter, instSource.autoArgs, "", allElems); instSource.systemFilter, *instSource.autoArgs, "", allElems);
elems = filterBySelector(state, allElems, args, newestOnly); elems = filterBySelector(state, allElems, args, newestOnly);
@ -373,7 +373,7 @@ static void queryInstSources(EvalState & state,
Value vFun, vTmp; Value vFun, vTmp;
state.eval(eFun, vFun); state.eval(eFun, vFun);
mkApp(vTmp, vFun, vArg); mkApp(vTmp, vFun, vArg);
getDerivations(state, vTmp, "", instSource.autoArgs, elems, true); getDerivations(state, vTmp, "", *instSource.autoArgs, elems, true);
} }
break; break;
@ -423,8 +423,8 @@ static void queryInstSources(EvalState & state,
Value vRoot; Value vRoot;
loadSourceExpr(state, instSource.nixExprPath, vRoot); loadSourceExpr(state, instSource.nixExprPath, vRoot);
foreach (Strings::const_iterator, i, args) { foreach (Strings::const_iterator, i, args) {
Value & v(*findAlongAttrPath(state, *i, instSource.autoArgs, vRoot)); Value & v(*findAlongAttrPath(state, *i, *instSource.autoArgs, vRoot));
getDerivations(state, v, "", instSource.autoArgs, elems, true); getDerivations(state, v, "", *instSource.autoArgs, elems, true);
} }
break; break;
} }
@ -926,7 +926,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
if (source == sAvailable || compareVersions) if (source == sAvailable || compareVersions)
loadDerivations(*globals.state, globals.instSource.nixExprPath, loadDerivations(*globals.state, globals.instSource.nixExprPath,
globals.instSource.systemFilter, globals.instSource.autoArgs, globals.instSource.systemFilter, *globals.instSource.autoArgs,
attrPath, availElems); attrPath, availElems);
DrvInfos elems_ = filterBySelector(*globals.state, DrvInfos elems_ = filterBySelector(*globals.state,
@ -1423,7 +1423,7 @@ int main(int argc, char * * argv)
if (file != "") if (file != "")
globals.instSource.nixExprPath = lookupFileArg(*globals.state, file); globals.instSource.nixExprPath = lookupFileArg(*globals.state, file);
evalAutoArgs(*globals.state, autoArgs_, globals.instSource.autoArgs); globals.instSource.autoArgs = evalAutoArgs(*globals.state, autoArgs_);
if (globals.profile == "") if (globals.profile == "")
globals.profile = getEnv("NIX_PROFILE", ""); globals.profile = getEnv("NIX_PROFILE", "");

View file

@ -19,7 +19,7 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
if (pathExists(manifestFile)) { if (pathExists(manifestFile)) {
Value v; Value v;
state.evalFile(manifestFile, v); state.evalFile(manifestFile, v);
Bindings bindings; Bindings & bindings(*state.allocBindings(0));
getDerivations(state, v, "", bindings, elems, false); getDerivations(state, v, "", bindings, elems, false);
} }
return elems; return elems;

View file

@ -159,8 +159,7 @@ int main(int argc, char * * argv)
EvalState state(searchPath); EvalState state(searchPath);
state.repair = repair; state.repair = repair;
Bindings autoArgs; Bindings & autoArgs(*evalAutoArgs(state, autoArgs_));
evalAutoArgs(state, autoArgs_, autoArgs);
if (evalOnly && !wantsReadWrite) if (evalOnly && !wantsReadWrite)
settings.readOnlyMode = true; settings.readOnlyMode = true;