#include "Facade.h" #include "Internal.h" #include 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(); }