Use our own bitset

This commit is contained in:
2024-04-30 16:39:24 -07:00
parent c607f77b3b
commit 5fc72a294d

View File

@@ -8,8 +8,6 @@
#include <unistd.h> #include <unistd.h>
#include <unordered_set> #include <unordered_set>
#include <roaring.h>
void *mmapSafe(void *addr, size_t len, int prot, int flags, int fd, void *mmapSafe(void *addr, size_t len, int prot, int flags, int fd,
off_t offset) { off_t offset) {
void *result = mmap(addr, len, prot, flags, fd, offset); void *result = mmap(addr, len, prot, flags, fd, offset);
@@ -111,53 +109,30 @@ constexpr uint32_t kUpsizeBytes = 1 << 20;
constexpr uint32_t kUpsizeNodes = kUpsizeBytes / sizeof(Node); constexpr uint32_t kUpsizeNodes = kUpsizeBytes / sizeof(Node);
static_assert(kUpsizeNodes * sizeof(Node) == kUpsizeBytes); static_assert(kUpsizeNodes * sizeof(Node) == kUpsizeBytes);
struct BitSetUnorderedSet { struct BitSet {
explicit BitSetUnorderedSet(uint32_t size) : s() {} explicit BitSet(uint32_t size) : words((uint64_t *)malloc(size / 64 + 64)) {}
bool test(uint32_t i) const { return s.find(i) != s.end(); } bool test(uint32_t i) const {
return words[i >> 6] & (uint64_t(1) << (i & 63));
}
// Returns former value // Returns former value
bool set(uint32_t i) { bool set(uint32_t i) {
auto [it, inserted] = s.insert(i); const auto prev = words[i >> 6];
const auto mask = uint64_t(1) << (i & 63);
words[i >> 6] |= mask;
max_ = std::max(i, max_); max_ = std::max(i, max_);
return !inserted; return prev & mask;
} }
// Returns 0 if set is empty // Returns 0 if set is empty
uint32_t max() const { return max_; } uint32_t max() const { return max_; }
template <class F> template <class F>
void iterateAbsentBackwards(F f, uint32_t begin, uint32_t end) const { void iterateAbsentApproxBackwards(F f, uint32_t begin, uint32_t end) const {
for (uint32_t i = end - 1; i >= begin; --i) { // TODO can this be improved? We can do something with a word at a time
if (!test(i)) { // instead of a bit at a time. The first attempt at doing so benchmarked as
f(i); // slower.
}
}
}
private:
uint32_t max_ = 0;
std::unordered_set<uint32_t> s;
};
struct BitSetR {
explicit BitSetR(uint32_t size) : s(bitset_create_with_capacity(size)) {}
bool test(uint32_t i) const { return bitset_get(s, i); }
// Returns former value
bool set(uint32_t i) {
max_ = std::max(i, max_);
auto result = test(i);
bitset_set(s, i);
return result;
}
// Returns 0 if set is empty
uint32_t max() const { return max_; }
template <class F>
void iterateAbsentBackwards(F f, uint32_t begin, uint32_t end) const {
assert(begin != 0); assert(begin != 0);
for (uint32_t i = end - 1; i >= begin; --i) { for (uint32_t i = end - 1; i >= begin; --i) {
if (!test(i)) { if (!test(i)) {
@@ -166,11 +141,11 @@ struct BitSetR {
} }
} }
~BitSetR() { bitset_free(s); } ~BitSet() { free(words); }
private: private:
uint32_t max_ = 0; uint32_t max_ = 0;
bitset_t *s; uint64_t *const words;
}; };
struct MemManager { struct MemManager {
@@ -212,10 +187,8 @@ struct MemManager {
} }
void gc(const uint32_t *roots, int numRoots, int64_t oldestVersion) { void gc(const uint32_t *roots, int numRoots, int64_t oldestVersion) {
// TODO better bitset?
// Calculate reachable set // Calculate reachable set
BitSetR reachable{next}; BitSet reachable{next};
uint32_t stack[1000]; // Much more than bound imposed by max height of tree uint32_t stack[1000]; // Much more than bound imposed by max height of tree
int stackIndex = 0; int stackIndex = 0;
auto tryPush = [&](uint32_t p) { auto tryPush = [&](uint32_t p) {
@@ -272,7 +245,7 @@ struct MemManager {
// Rebuild free list and delref entries // Rebuild free list and delref entries
freeList = 0; freeList = 0;
reachable.iterateAbsentBackwards( reachable.iterateAbsentApproxBackwards(
[&](uint32_t i) { [&](uint32_t i) {
if (base[i].entry != nullptr) { if (base[i].entry != nullptr) {
base[i].entry->delref(); base[i].entry->delref();
@@ -298,6 +271,7 @@ struct VersionedMap::Impl {};
int main() { int main() {
ankerl::nanobench::Bench bench; ankerl::nanobench::Bench bench;
bench.minEpochIterations(5000);
weaselab::MemManager mm; weaselab::MemManager mm;
bench.run("allocate", [&]() { bench.run("allocate", [&]() {
auto x = mm.allocate(); auto x = mm.allocate();