Range reads are slow with dense keys
All checks were successful
Tests / Release [gcc] total: 363, passed: 363
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap: Reference build: <a href="https://jenkins.weaselab.dev/job/weaselab/job/conflict-set/job/main/13//gcc">weaselab » conflict-set » main #13</a>
Tests / Coverage total: 361, passed: 361
weaselab/conflict-set/pipeline/head This commit looks good

This commit is contained in:
2024-02-12 15:46:56 -08:00
parent f8acc5ee86
commit d5bde56921
2 changed files with 26 additions and 22 deletions

View File

@@ -543,8 +543,8 @@ private:
}; };
struct SkipListConflictSet { struct SkipListConflictSet {
int64_t oldestVersion; SkipListConflictSet(int64_t oldestVersion)
SkipListConflictSet(int64_t oldestVersion) : oldestVersion(oldestVersion) {} : oldestVersion(oldestVersion), skipList(oldestVersion) {}
void check(const ConflictSet::ReadRange *reads, ConflictSet::Result *results, void check(const ConflictSet::ReadRange *reads, ConflictSet::Result *results,
int count) const { int count) const {
Arena arena; Arena arena;
@@ -594,29 +594,37 @@ struct SkipListConflictSet {
} }
private: private:
int64_t oldestVersion;
SkipList skipList; SkipList skipList;
}; };
} // namespace } // namespace
constexpr int kNumKeys = 100000; constexpr int kNumKeys = 1000000;
constexpr int kOpsPerTx = 100; constexpr int kOpsPerTx = 100;
constexpr int kPrefixLen = 0; constexpr int kPrefixLen = 0;
std::span<const uint8_t> makeKey(Arena &arena, int index) { std::span<const uint8_t> makeKey(Arena &arena, int index) {
auto result = auto result =
std::span<uint8_t>{new (arena) uint8_t[4 + kPrefixLen], 4 + kPrefixLen}; std::span<uint8_t>{new (arena) uint8_t[4 + kPrefixLen], 4 + kPrefixLen};
index = __builtin_bswap32(index); index = __builtin_bswap32(index);
memset(result.data(), 0, kPrefixLen); memset(result.data(), 0, kPrefixLen);
memcpy(result.data() + kPrefixLen, &index, 4); memcpy(result.data() + kPrefixLen, &index, 4);
// auto result =
// std::span<uint8_t>{new (arena) uint8_t[32], 32};
// for (int i = 0; i < 32; ++i) {
// result[i] = index & (1 << (31 - i)) ? '1' : '0';
// }
return result; return result;
} }
template <class ConflictSet_> void benchConflictSet(const std::string &name) { template <class ConflictSet_> void benchConflictSet(const std::string &name) {
ankerl::nanobench::Bench bench; ankerl::nanobench::Bench bench;
bench.minEpochIterations(1000);
ConflictSet_ cs{0}; ConflictSet_ cs{0};
bench.batch(kOpsPerTx); bench.batch(kOpsPerTx);
@@ -650,8 +658,6 @@ template <class ConflictSet_> void benchConflictSet(const std::string &name) {
}; };
auto points = set<std::span<const uint8_t>, Less>(arena); auto points = set<std::span<const uint8_t>, Less>(arena);
// Two points for each range read, one for each point read, and one for each
// point write
while (points.size() < kOpsPerTx * 2 + 1) { while (points.size() < kOpsPerTx * 2 + 1) {
// TODO don't use rand? // TODO don't use rand?
points.insert(makeKey(arena, rand() % kNumKeys)); points.insert(makeKey(arena, rand() % kNumKeys));
@@ -660,21 +666,21 @@ template <class ConflictSet_> void benchConflictSet(const std::string &name) {
// Make short-circuiting non-trivial // Make short-circuiting non-trivial
{ {
std::vector<ConflictSet::WriteRange> writes; std::vector<ConflictSet::WriteRange> writes;
writes.reserve(kNumKeys); auto iter = points.begin();
for (int i = 0; i < kNumKeys; ++i) { ++iter; // Complement of the set we'll be reading with range reads. Almost.
auto key = makeKey(arena, i); for (int i = 0; i < kOpsPerTx; ++i) {
if (points.find(key) != points.end()) { auto begin = *iter++;
continue; auto end = *iter++;
} ConflictSet::WriteRange w;
ConflictSet::WriteRange conflict; w.begin.p = begin.data();
conflict.begin.p = key.data(); w.begin.len = begin.size();
conflict.begin.len = key.size(); w.end.p = end.data();
conflict.end.len = 0; w.end.len = end.size();
conflict.writeVersion = version + 1; w.writeVersion = version + 1;
writes.push_back(conflict); writes.push_back(w);
} }
cs.addWrites(writes.data(), writes.size());
++version; ++version;
cs.addWrites(writes.data(), kOpsPerTx);
} }
{ {

View File

@@ -894,9 +894,7 @@ bytes:
bool checkRangeRead(Node *n, const std::span<const uint8_t> begin, bool checkRangeRead(Node *n, const std::span<const uint8_t> begin,
const std::span<const uint8_t> end, int64_t readVersion, const std::span<const uint8_t> end, int64_t readVersion,
Arena &arena) { Arena &arena) {
auto left = FirstGeqStepwise{n, begin}; auto left = firstGeq(n, begin);
while (!left.step())
;
#if DEBUG_VERBOSE && !defined(NDEBUG) #if DEBUG_VERBOSE && !defined(NDEBUG)
fprintf(stderr, "firstGeq for `%s' got `%s'\n", printable(begin).c_str(), fprintf(stderr, "firstGeq for `%s' got `%s'\n", printable(begin).c_str(),