Add RootSet
This commit is contained in:
116
VersionedMap.cpp
116
VersionedMap.cpp
@@ -216,6 +216,9 @@ struct MemManager {
|
||||
}
|
||||
};
|
||||
for (int i = 0; i < numRoots; ++i) {
|
||||
if (roots[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
tryPush(roots[i]);
|
||||
while (stackIndex > 0) {
|
||||
uint32_t p = stack[--stackIndex];
|
||||
@@ -281,7 +284,100 @@ private:
|
||||
uint32_t freeList = 0;
|
||||
};
|
||||
|
||||
struct VersionedMap::Impl {};
|
||||
struct RootSet {
|
||||
|
||||
/// Register the root node for version after adding mutations
|
||||
void add(uint32_t node, int64_t version) {
|
||||
if (end == 0) {
|
||||
nodes[end] = node;
|
||||
versions[end] = version;
|
||||
++end;
|
||||
return;
|
||||
}
|
||||
if (nodes[end - 1] == node) {
|
||||
return;
|
||||
}
|
||||
if (end == capacity) {
|
||||
capacity *= 2;
|
||||
nodes = (uint32_t *)realloc(nodes, capacity * sizeof(uint32_t));
|
||||
versions = (int64_t *)realloc(versions, capacity * sizeof(int64_t));
|
||||
}
|
||||
|
||||
nodes[end] = node;
|
||||
versions[end] = version;
|
||||
++end;
|
||||
}
|
||||
|
||||
/// Inform that there will be no calls to rootForVersion with a version less
|
||||
/// than `oldestVersion`
|
||||
void setOldestVersion(int64_t oldestVersion) {
|
||||
const uint32_t firstToKeep = rootForVersion(oldestVersion);
|
||||
|
||||
if (firstToKeep != 0) {
|
||||
memmove(nodes, nodes + firstToKeep,
|
||||
(end - firstToKeep) * sizeof(uint32_t));
|
||||
memmove(versions, versions + firstToKeep,
|
||||
(end - firstToKeep) * sizeof(int64_t));
|
||||
end -= firstToKeep;
|
||||
}
|
||||
assert(end > 0);
|
||||
assert(nodes[0] <= oldestVersion);
|
||||
}
|
||||
|
||||
/// Get a root node that can correctly be used for `version`
|
||||
uint32_t rootForVersion(int64_t version) const {
|
||||
assert(end > 0);
|
||||
assert(nodes[0] <= version);
|
||||
|
||||
// Find the last version <= oldestVersion
|
||||
int left = 0;
|
||||
int right = end;
|
||||
int result = 0;
|
||||
while (left <= right) {
|
||||
int mid = left + (right - left) / 2;
|
||||
if (versions[mid] <= version) {
|
||||
result = mid;
|
||||
left = mid + 1;
|
||||
} else {
|
||||
right = mid - 1;
|
||||
}
|
||||
}
|
||||
assert(result < end);
|
||||
return result;
|
||||
}
|
||||
|
||||
const uint32_t *roots() const { return nodes; }
|
||||
int rootCount() const { return end; }
|
||||
|
||||
RootSet() {
|
||||
nodes = (uint32_t *)malloc(kMinCapacity * sizeof(uint32_t));
|
||||
versions = (int64_t *)malloc(kMinCapacity * sizeof(int64_t));
|
||||
capacity = kMinCapacity;
|
||||
nodes[0] = 0;
|
||||
versions[0] = 0;
|
||||
end = 1;
|
||||
}
|
||||
|
||||
~RootSet() {
|
||||
free(versions);
|
||||
free(nodes);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t *nodes;
|
||||
// versions[i] is the version of nodes[i]
|
||||
int64_t *versions;
|
||||
|
||||
constexpr static uint32_t kMinCapacity = 16;
|
||||
uint32_t capacity;
|
||||
uint32_t end;
|
||||
};
|
||||
|
||||
struct VersionedMap::Impl {
|
||||
|
||||
MemManager mm;
|
||||
RootSet roots;
|
||||
};
|
||||
} // namespace weaselab
|
||||
|
||||
#ifdef ENABLE_MAIN
|
||||
@@ -311,5 +407,23 @@ int main() {
|
||||
mm.base[root].pointers[1] = 0;
|
||||
mm.base[root].updated.store(false, std::memory_order_relaxed);
|
||||
bench.run("gc", [&]() { mm.gc(&root, 1, 0); });
|
||||
|
||||
{
|
||||
int i = 0;
|
||||
constexpr int kNumVersions = 1000;
|
||||
weaselab::RootSet roots;
|
||||
for (; i < kNumVersions; i += 2) {
|
||||
roots.add(i, i);
|
||||
roots.add(i, i + 1);
|
||||
}
|
||||
bench.run("roots - setOldestVersion", [&]() {
|
||||
roots.add(i, i);
|
||||
roots.setOldestVersion(i - kNumVersions);
|
||||
++i;
|
||||
});
|
||||
bench.run("roots - rootForVersion", [&]() {
|
||||
bench.doNotOptimizeAway(roots.rootForVersion(i - kNumVersions / 2));
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user