Files
versioned-map/Bench.cpp
Andrew Noyes 57cceaf3b7 Fix an issue with versioned-only benchmark
Previously it was reading some of the keys from unversioned storage.

Also add some more benchmarks
2024-06-19 15:08:16 -07:00

198 lines
5.9 KiB
C++

#include "Facade.h"
#include "Internal.h"
#include <nanobench.h>
void iterBench(const Facade &facade, int64_t version,
const std::string &context) {
ankerl::nanobench::Bench bench;
bench.minEpochIterations(10000);
const auto begin = facade.versioned.begin(version);
const auto end = facade.versioned.end(version);
auto iter = begin;
bench.run("*iter (" + context + ")", [&] { bench.doNotOptimizeAway(*iter); });
iter = begin;
bench.run("++iter (" + context + ")", [&] {
++iter;
if (iter == end) {
iter = begin;
}
});
iter = end;
bench.run("--iter (" + context + ")", [&] {
--iter;
if (iter == begin) {
iter = end;
}
});
}
void monotonicallyIncreasing() {
constexpr int kWindow = 1000;
ankerl::nanobench::Bench bench;
Facade facade{kWindow + 1};
bench.minEpochIterations(kWindow * 20);
bench.warmup(kWindow).run("monotonically increasing", [&] {
const int64_t remove = __builtin_bswap64(facade.getVersion() - kWindow);
const int64_t next = __builtin_bswap64(facade.getVersion());
weaselab::VersionedMap::Mutation mutations[] = {
{(const uint8_t *)&remove, 8, nullptr, 0,
weaselab::VersionedMap::Clear},
{(const uint8_t *)&next, 8, (const uint8_t *)&next, 8,
weaselab::VersionedMap::Set},
};
facade.addMutations(mutations, sizeof(mutations) / sizeof(mutations[0]),
facade.getVersion() + 1);
facade.setOldestVersion(facade.getVersion() - kWindow);
});
const auto v = facade.getVersion() - kWindow / 2;
iterBench(facade, v, "monotonically increasing");
bench.run("begin", [&] { facade.versioned.begin(v); });
bench.run("begin (firstGeq)", [&] {
weaselab::VersionedMap::Key key{nullptr, 0};
weaselab::VersionedMap::Iterator iter;
facade.versioned.firstGeq(&key, &v, &iter, 1);
});
bench.run("end", [&] { facade.versioned.end(v); });
{
ankerl::nanobench::Bench bench;
bench.batch(kWindow);
bench.run("Facade monotonically-increasing read forward", [&]() {
if (facade.viewAt(facade.getVersion())
.rangeRead(String(), String({0xff}), kWindow, false)
.size() != kWindow) {
abort();
}
});
bench.run("Facade monotonically-increasing read reverse", [&]() {
if (facade.viewAt(facade.getVersion())
.rangeRead(String(), String({0xff}), kWindow, true)
.size() != kWindow) {
abort();
}
});
}
}
void bulkFirstGeq() {
constexpr int kNumKeys = 100000;
constexpr int kNumQueries = 100;
ankerl::nanobench::Bench bench;
bench.batch(kNumQueries);
bench.minEpochIterations(kNumQueries * 5);
// Initialize `versionedMap`
weaselab::VersionedMap versionedMap{0};
for (int64_t i = 0; i < kNumKeys; ++i) {
const auto bigEndian = __builtin_bswap64(i);
weaselab::VersionedMap::Mutation m;
m.param1 = (const uint8_t *)&bigEndian;
m.param1Len = sizeof(bigEndian);
m.param2 = (const uint8_t *)&bigEndian;
m.param2Len = sizeof(bigEndian);
m.type = weaselab::VersionedMap::Set;
versionedMap.addMutations(&m, 1, i + 1);
}
// Prepare queries
Arena arena;
auto *keys = new (arena) weaselab::VersionedMap::Key[kNumQueries];
auto *versions = new (arena) int64_t[kNumQueries];
for (int64_t i = 0; i < kNumQueries; ++i) {
int64_t key = i * kNumKeys / kNumQueries;
static_assert(kNumKeys >= kNumQueries);
versions[i] = kNumKeys - i;
const auto bigEndian = __builtin_bswap64(key);
uint8_t *k = new (arena) uint8_t[sizeof(bigEndian)];
memcpy(k, &bigEndian, sizeof(bigEndian));
keys[i].p = k;
keys[i].len = sizeof(bigEndian);
}
weaselab::VersionedMap::Iterator iterators[kNumQueries];
// Bench
bench.run("bulkFirstGeq", [&] {
versionedMap.firstGeq(keys, versions, iterators, kNumQueries);
});
bench.run("bulkFirstGeq (latest version)",
[&] { versionedMap.firstGeq(keys, iterators, kNumQueries); });
}
void facadeVersionedOnlyRead() {
Facade facade{0};
constexpr int kNumKeys = 1000;
ankerl::nanobench::Bench bench;
bench.batch(kNumKeys);
const int64_t beginBytes = __builtin_bswap64(0);
const int64_t endBytes = __builtin_bswap64(kNumKeys);
const String begin{(const uint8_t *)&beginBytes, 8};
const String end{(const uint8_t *)&endBytes, 8};
// Insert clear in entire range, so that all reads are served from versioned,
// logically and hopefully physically.
{
weaselab::VersionedMap::Mutation mutations[] = {
{begin.data(), int(begin.size()), end.data(), int(end.size()),
weaselab::VersionedMap::Clear},
};
facade.addMutations(mutations, sizeof(mutations) / sizeof(mutations[0]),
facade.getVersion() + 1);
}
Arena arena;
weaselab::VersionedMap::Mutation *mutations =
new (arena) weaselab::VersionedMap::Mutation[kNumKeys];
for (int i = 0; i < kNumKeys; ++i) {
const int64_t k = __builtin_bswap64(i);
uint8_t *buf = new (arena) uint8_t[8];
memcpy(buf, &k, 8);
mutations[i] = {buf, 8, buf, 8, weaselab::VersionedMap::Set};
}
// Add keys
facade.addMutations(mutations, kNumKeys, facade.getVersion() + 1);
// Populate the unversioned map
facade.addMutations(mutations, kNumKeys, facade.getVersion() + 1);
facade.setOldestVersion(facade.getVersion() - 1, /*force*/ true);
iterBench(facade, facade.getVersion(), "adjacent sets/clears");
bench.run("Facade versioned-only read forward", [&]() {
if (facade.viewAt(facade.getVersion())
.rangeRead(begin, end, kNumKeys, false)
.size() != kNumKeys) {
abort();
}
});
bench.run("Facade versioned-only read reverse", [&]() {
if (facade.viewAt(facade.getVersion())
.rangeRead(begin, end, kNumKeys, true)
.size() != kNumKeys) {
abort();
}
});
}
int main() {
monotonicallyIncreasing();
bulkFirstGeq();
facadeVersionedOnlyRead();
}