#include #include #include #include #include #include #include #include #include #include #include #include void parse_int(std::string_view arg, std::uint64_t &i) { auto [_, ec] = std::from_chars(arg.data(), arg.data() + arg.size(), i); if (ec == std::errc{}) { return; } else { throw std::runtime_error(std::format("failed to parse {} as u64", arg)); } } std::uint64_t random_u64() { std::ifstream ifstream{"/dev/random", std::ios::binary}; if (!ifstream.is_open()) { throw std::runtime_error( std::format("failed to open /dev/random: {}", std::strerror(errno))); } std::array buff; ifstream.read(buff.data(), 8); std::uint64_t i; std::memcpy(&i, buff.data(), 8); return i; } int main(int argc, char **argv) { if (argc < 3) { std::println(stderr, "usage: bench [seed]"); return 1; } auto *path = argv[1]; auto *limit = argv[2]; std::println(stderr, "starting benchmark"); std::uint64_t seed; if (argc > 3) { try { parse_int(argv[3], seed); } catch (std::exception &e) { std::println(stderr, "{}", e.what()); return 1; } } else { try { seed = random_u64(); } catch (std::exception &e) { std::println(stderr, "{}", e.what()); return 1; } } std::println(stderr, "using random seed: {}", seed); boost::sqlite::connection connection{path}; std::vector keys; auto st = connection.prepare("select kv.key from kv limit ?"); for (const auto row : st.execute({limit})) { auto key = row.at(0).get_text(); keys.push_back(key); } std::default_random_engine rng{seed}; std::shuffle(keys.begin(), keys.end(), rng); std::println(stderr, "slurped {} keys into memory", keys.size()); auto start = std::chrono::system_clock::now(); st = connection.prepare("select kv.value from kv where kv.key=?"); for (const auto &key : keys) { auto row = st.execute({key}); if (row.done()) { std::println(stderr, "found no value for key: {}", key); } else { continue; } } auto end = std::chrono::system_clock::now(); std::chrono::duration d = end - start; std::println(stderr, "selected {} keys in {} ({})", keys.size(), d, keys.size() / d.count()); return 0; }