Files
conflict-set/Bench.cpp
Andrew Noyes be5f1b67c8
All checks were successful
Tests / Release [gcc] total: 704, passed: 704
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/57//gcc">weaselab » conflict-set » main #57</a>
Tests / Release [gcc,aarch64] total: 703, passed: 703
Tests / Coverage total: 702, passed: 702
weaselab/conflict-set/pipeline/head This commit looks good
Interface change! addWrites now takes a single write version
2024-03-05 16:55:27 -08:00

263 lines
6.6 KiB
C++

#include "ConflictSet.h"
#include "Internal.h"
#include <cstdint>
#include <cstring>
#if SHOW_MEMORY
void showMemory(const ConflictSet &cs);
#endif
#define ANKERL_NANOBENCH_IMPLEMENT
#include "third_party/nanobench.h"
constexpr int kNumKeys = 1000000;
constexpr int kOpsPerTx = 100;
constexpr int kPrefixLen = 0;
constexpr int kMvccWindow = 100000;
std::span<const uint8_t> makeKey(Arena &arena, int index) {
auto result =
std::span<uint8_t>{new (arena) uint8_t[4 + kPrefixLen], 4 + kPrefixLen};
index = __builtin_bswap32(index);
memset(result.data(), 0, kPrefixLen);
memcpy(result.data() + kPrefixLen, &index, 4);
return result;
}
ConflictSet::ReadRange singleton(Arena &arena, std::span<const uint8_t> key) {
auto r =
std::span<uint8_t>(new (arena) uint8_t[key.size() + 1], key.size() + 1);
memcpy(r.data(), key.data(), key.size());
r[key.size()] = 0;
return {key.data(), int(key.size()), r.data(), int(r.size())};
}
ConflictSet::ReadRange prefixRange(Arena &arena, std::span<const uint8_t> key) {
int index;
for (index = key.size() - 1; index >= 0; index--)
if ((key[index]) != 255)
break;
// Must not be called with a string that consists only of zero or more '\xff'
// bytes.
if (index < 0) {
assert(false);
}
auto r = std::span<uint8_t>(new (arena) uint8_t[index + 1], index + 1);
memcpy(r.data(), key.data(), index + 1);
r[r.size() - 1]++;
return {key.data(), int(key.size()), r.data(), int(r.size())};
}
void benchConflictSet() {
ankerl::nanobench::Bench bench;
ConflictSet cs{0};
bench.batch(kOpsPerTx);
bench.minEpochIterations(10000);
int64_t version = 0;
// Populate conflict set
Arena arena;
{
std::vector<ConflictSet::WriteRange> writes;
writes.reserve(kNumKeys);
for (int i = 0; i < kNumKeys; ++i) {
auto key = makeKey(arena, i);
ConflictSet::WriteRange w;
auto r = singleton(arena, key);
w.begin.p = r.begin.p;
w.begin.len = r.begin.len;
w.end.p = r.end.p;
w.end.len = 0;
writes.push_back(w);
}
cs.addWrites(writes.data(), writes.size(), version + 1);
++version;
}
// I don't know why std::less didn't work /shrug
struct Less {
bool operator()(const std::span<const uint8_t> &lhs,
const std::span<const uint8_t> &rhs) const {
return lhs < rhs;
}
};
auto points = set<std::span<const uint8_t>, Less>(arena);
while (points.size() < kOpsPerTx * 2 + 1) {
// TODO don't use rand?
points.insert(makeKey(arena, rand() % kNumKeys));
}
// Make short-circuiting non-trivial
{
std::vector<ConflictSet::WriteRange> writes;
auto iter = points.begin();
++iter; // Complement of the set we'll be reading with range reads. Almost.
for (int i = 0; i < kOpsPerTx; ++i) {
auto begin = *iter++;
auto end = *iter++;
ConflictSet::WriteRange w;
w.begin.p = begin.data();
w.begin.len = begin.size();
w.end.p = end.data();
w.end.len = end.size();
writes.push_back(w);
}
cs.addWrites(writes.data(), kOpsPerTx, version + 1);
++version;
}
{
std::vector<ConflictSet::ReadRange> reads;
auto iter = points.begin();
for (int i = 0; i < kOpsPerTx; ++i) {
auto r = singleton(arena, *iter);
r.end.len = 0;
r.readVersion = version - 1;
reads.push_back(r);
++iter;
}
auto *results = new (arena) ConflictSet::Result[kOpsPerTx];
bench.run("point reads",
[&]() { cs.check(reads.data(), results, kOpsPerTx); });
}
{
std::vector<ConflictSet::ReadRange> reads;
auto iter = points.begin();
for (int i = 0; i < kOpsPerTx; ++i) {
auto r = prefixRange(arena, *iter);
r.readVersion = version - 1;
reads.push_back(r);
++iter;
}
auto *results = new (arena) ConflictSet::Result[kOpsPerTx];
bench.run("prefix reads",
[&]() { cs.check(reads.data(), results, kOpsPerTx); });
}
{
std::vector<ConflictSet::ReadRange> reads;
auto iter = points.begin();
for (int i = 0; i < kOpsPerTx; ++i) {
auto begin = *iter++;
auto end = *iter++;
ConflictSet::ReadRange r;
r.begin.p = begin.data();
r.begin.len = begin.size();
r.end.p = end.data();
r.end.len = end.size();
r.readVersion = version - 1;
reads.push_back(r);
}
auto *results = new (arena) ConflictSet::Result[kOpsPerTx];
bench.run("range reads",
[&]() { cs.check(reads.data(), results, kOpsPerTx); });
}
{
std::vector<ConflictSet::WriteRange> writes;
auto iter = points.begin();
for (int i = 0; i < kOpsPerTx; ++i) {
ConflictSet::WriteRange w;
auto r = singleton(arena, *iter);
w.begin.p = r.begin.p;
w.begin.len = r.begin.len;
w.end.p = r.end.p;
w.end.len = 0;
writes.push_back(w);
++iter;
}
while (version < kMvccWindow) {
auto v = ++version;
cs.addWrites(writes.data(), 1, v);
}
bench.run("point writes", [&]() {
auto v = ++version;
cs.addWrites(writes.data(), writes.size(), v);
cs.setOldestVersion(version - kMvccWindow);
});
}
{
std::vector<ConflictSet::WriteRange> writes;
auto iter = points.begin();
for (int i = 0; i < kOpsPerTx; ++i) {
ConflictSet::WriteRange w;
auto r = prefixRange(arena, *iter);
w.begin.p = r.begin.p;
w.begin.len = r.begin.len;
w.end.p = r.end.p;
w.end.len = r.end.len;
writes.push_back(w);
++iter;
}
bench.run("prefix writes", [&]() {
auto v = ++version;
cs.addWrites(writes.data(), writes.size(), v);
cs.setOldestVersion(version - kMvccWindow);
});
}
{
std::vector<ConflictSet::WriteRange> writes;
auto iter = points.begin();
for (int i = 0; i < kOpsPerTx; ++i) {
auto begin = *iter++;
auto end = *iter++;
ConflictSet::WriteRange w;
w.begin.p = begin.data();
w.begin.len = begin.size();
w.end.p = end.data();
w.end.len = end.size();
writes.push_back(w);
}
bench.run("range writes", [&]() {
auto v = ++version;
cs.addWrites(writes.data(), writes.size(), v);
cs.setOldestVersion(version - kMvccWindow);
});
}
bench.batch(1);
{
bench.run("monotonic increasing point writes", [&]() {
auto v = ++version;
ConflictSet::WriteRange w;
uint8_t b[9];
b[8] = 0;
auto x = __builtin_bswap64(version);
memcpy(b, &x, 8);
w.begin.p = b;
w.begin.len = 8;
w.end.len = 0;
w.end.p = b;
cs.addWrites(&w, 1, v);
cs.setOldestVersion(version - kMvccWindow);
});
}
}
int main(void) { benchConflictSet(); }