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
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:
44
Bench.cpp
44
Bench.cpp
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@@ -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(),
|
||||||
|
Reference in New Issue
Block a user