feat(3p/nix): Statically pass bindings capacity where possible
To aid in making the decision of where to (currently just statically) use a vector or btree as the backing implementation, add an extra constructor argument to Bindings::NewGC for a capacity, and use a (currently hardcoded at 32, for no good reason other than it felt like a reasonable number) pivot to switch between our possible backing implementations. Then, update all the call sites where it feels reasonable that we know the capacity statically to *pass* that capacity to the constructor. Paired-With: Luke Granger-Brown <git@lukegb.com> Paired-With: Vincent Ambo <mail@tazj.in> Paired-With: Perry Lorier <isomer@tvl.fyi> Change-Id: I1858c161301a1cd0e83aeeb9a58839378869e71d Reviewed-on: https://cl.tvl.fyi/c/depot/+/1124 Tested-by: BuildkiteCI Reviewed-by: lukegb <lukegb@tvl.fyi> Reviewed-by: isomer <isomer@tvl.fyi>
This commit is contained in:
parent
d5505fcff9
commit
d5597b4784
5 changed files with 39 additions and 31 deletions
56
third_party/nix/src/libexpr/attr-set.cc
vendored
56
third_party/nix/src/libexpr/attr-set.cc
vendored
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
constexpr size_t ATTRS_CAPACITY_PIVOT = 32;
|
||||||
|
|
||||||
BindingsIterator& BindingsIterator::operator++() {
|
BindingsIterator& BindingsIterator::operator++() {
|
||||||
std::visit(util::overloaded{
|
std::visit(util::overloaded{
|
||||||
[](AttributeMap::iterator& iter) { ++iter; },
|
[](AttributeMap::iterator& iter) { ++iter; },
|
||||||
|
@ -132,27 +134,13 @@ void BTreeBindings::merge(Bindings& other) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EvalState::mkAttrs(Value& v, size_t capacity) {
|
|
||||||
clearValue(v);
|
|
||||||
v.type = tAttrs;
|
|
||||||
v.attrs = Bindings::NewGC();
|
|
||||||
assert(v.attrs->begin() == v.attrs->begin());
|
|
||||||
assert(v.attrs->end() == v.attrs->end());
|
|
||||||
nrAttrsets++;
|
|
||||||
nrAttrsInAttrsets += capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a new attribute named 'name' on an existing attribute set stored
|
|
||||||
in 'vAttrs' and return the newly allocated Value which is associated with
|
|
||||||
this attribute. */
|
|
||||||
Value* EvalState::allocAttr(Value& vAttrs, const Symbol& name) {
|
|
||||||
Value* v = allocValue();
|
|
||||||
vAttrs.attrs->push_back(Attr(name, v));
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
class VectorBindings : public Bindings {
|
class VectorBindings : public Bindings {
|
||||||
public:
|
public:
|
||||||
|
VectorBindings() {};
|
||||||
|
VectorBindings(size_t capacity) : attributes_() {
|
||||||
|
attributes_.reserve(capacity);
|
||||||
|
};
|
||||||
|
|
||||||
size_t size() override;
|
size_t size() override;
|
||||||
bool empty() override;
|
bool empty() override;
|
||||||
void push_back(const Attr& attr) override;
|
void push_back(const Attr& attr) override;
|
||||||
|
@ -246,8 +234,32 @@ Bindings::iterator VectorBindings::end() {
|
||||||
return BindingsIterator{attributes_.end()};
|
return BindingsIterator{attributes_.end()};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO pick what to do based on size
|
Bindings* Bindings::NewGC(size_t capacity) {
|
||||||
Bindings* Bindings::NewGC() { return new (GC) BTreeBindings; }
|
if (capacity > ATTRS_CAPACITY_PIVOT) {
|
||||||
// Bindings* Bindings::NewGC() { return new (GC) VectorBindings; }
|
return new (GC) BTreeBindings;
|
||||||
|
} else {
|
||||||
|
return new (GC) VectorBindings(capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EvalState::mkAttrs(Value& v, size_t capacity) {
|
||||||
|
clearValue(v);
|
||||||
|
v.type = tAttrs;
|
||||||
|
v.attrs = Bindings::NewGC(capacity);
|
||||||
|
assert(v.attrs->begin() == v.attrs->begin());
|
||||||
|
assert(v.attrs->end() == v.attrs->end());
|
||||||
|
nrAttrsets++;
|
||||||
|
nrAttrsInAttrsets += capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a new attribute named 'name' on an existing attribute set stored
|
||||||
|
in 'vAttrs' and return the newly allocated Value which is associated with
|
||||||
|
this attribute. */
|
||||||
|
Value* EvalState::allocAttr(Value& vAttrs, const Symbol& name) {
|
||||||
|
Value* v = allocValue();
|
||||||
|
vAttrs.attrs->push_back(Attr(name, v));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace nix
|
} // namespace nix
|
||||||
|
|
6
third_party/nix/src/libexpr/attr-set.hh
vendored
6
third_party/nix/src/libexpr/attr-set.hh
vendored
|
@ -67,13 +67,9 @@ class Bindings {
|
||||||
public:
|
public:
|
||||||
typedef BindingsIterator iterator;
|
typedef BindingsIterator iterator;
|
||||||
|
|
||||||
// Allocate a new attribute set that is visible to the garbage
|
|
||||||
// collector.
|
|
||||||
static Bindings* NewGC();
|
|
||||||
|
|
||||||
// Allocate a new attribute set with a static capacity that is visible to the
|
// Allocate a new attribute set with a static capacity that is visible to the
|
||||||
// garbage collector.
|
// garbage collector.
|
||||||
// static Bindings* NewGC(size_t capacity);
|
static Bindings* NewGC(size_t capacity = 0);
|
||||||
|
|
||||||
// Return the number of contained elements.
|
// Return the number of contained elements.
|
||||||
virtual size_t size() = 0;
|
virtual size_t size() = 0;
|
||||||
|
|
|
@ -33,7 +33,7 @@ MixEvalArgs::MixEvalArgs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Bindings* MixEvalArgs::getAutoArgs(EvalState& state) {
|
Bindings* MixEvalArgs::getAutoArgs(EvalState& state) {
|
||||||
Bindings* res = Bindings::NewGC();
|
Bindings* res = Bindings::NewGC(autoArgs.size());
|
||||||
for (auto& i : autoArgs) {
|
for (auto& i : autoArgs) {
|
||||||
Value* v = state.allocValue();
|
Value* v = state.allocValue();
|
||||||
if (i.second[0] == 'E') {
|
if (i.second[0] == 'E') {
|
||||||
|
|
4
third_party/nix/src/libexpr/eval.cc
vendored
4
third_party/nix/src/libexpr/eval.cc
vendored
|
@ -1240,9 +1240,9 @@ void ExprOpUpdate::eval(EvalState& state, Env& env, Value& dest) {
|
||||||
|
|
||||||
state.nrOpUpdates++;
|
state.nrOpUpdates++;
|
||||||
|
|
||||||
state.mkAttrs(dest, /* capacity = */ 0);
|
state.mkAttrs(dest, v1.attrs->size() + v2.attrs->size());
|
||||||
|
|
||||||
/* Merge the sets, preferring values from the second set. */
|
// Merge the sets, preferring values from the second set.
|
||||||
dest.attrs->merge(*v1.attrs);
|
dest.attrs->merge(*v1.attrs);
|
||||||
dest.attrs->merge(*v2.attrs);
|
dest.attrs->merge(*v2.attrs);
|
||||||
}
|
}
|
||||||
|
|
2
third_party/nix/src/libexpr/get-drvs.cc
vendored
2
third_party/nix/src/libexpr/get-drvs.cc
vendored
|
@ -294,7 +294,7 @@ bool DrvInfo::queryMetaBool(const std::string& name, bool def) {
|
||||||
void DrvInfo::setMeta(const std::string& name, Value* v) {
|
void DrvInfo::setMeta(const std::string& name, Value* v) {
|
||||||
getMeta();
|
getMeta();
|
||||||
Bindings* old = meta;
|
Bindings* old = meta;
|
||||||
meta = Bindings::NewGC();
|
meta = Bindings::NewGC(old->size());
|
||||||
Symbol sym = state->symbols.Create(name);
|
Symbol sym = state->symbols.Create(name);
|
||||||
if (old != nullptr) {
|
if (old != nullptr) {
|
||||||
for (auto i : *old) {
|
for (auto i : *old) {
|
||||||
|
|
Loading…
Reference in a new issue