/* Copyright (C) 2018 David Robillard This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "bench_utils.hpp" #include "test_utils.hpp" #include "chilbert/BoundedBitVec.hpp" // IWYU pragma: keep #include "chilbert/DynamicBitVec.hpp" // IWYU pragma: keep #include "chilbert/SmallBitVec.hpp" #include "chilbert/StaticBitVec.hpp" // IWYU pragma: keep #include #include #include #include #include template struct BenchAnd { Duration operator()(Context& ctx) { const T v = make_random_bitvec(ctx); T r = make_random_bitvec(ctx); return run_bench([&](auto) { r &= v; }); } }; template struct BenchOr { Duration operator()(Context& ctx) { const T v = make_random_bitvec(ctx); T r = make_random_bitvec(ctx); return run_bench([&](auto) { r |= v; }); } }; template struct BenchXor { Duration operator()(Context& ctx) { const T v = make_random_bitvec(ctx); T r = make_random_bitvec(ctx); return run_bench([&](auto) { r ^= v; }); } }; template struct BenchSetOne { Duration operator()(Context& ctx) { T v = make_random_bitvec(ctx); return run_bench([&](const auto i) { v.set(i % N); }); } }; template struct BenchSetAll { Duration operator()(Context& ctx) { T v = make_random_bitvec(ctx); return run_bench([&](auto) { v.set(); }); } }; template struct BenchResetOne { Duration operator()(Context& ctx) { T v = make_random_bitvec(ctx); return run_bench([&](const auto i) { v.reset(i % N); }); } }; template struct BenchResetAll { Duration operator()(Context& ctx) { T v = make_random_bitvec(ctx); return run_bench([&](auto) { v.reset(); }); } }; template struct BenchFlipOne { Duration operator()(Context& ctx) { T v = make_random_bitvec(ctx); return run_bench([&](const auto i) { v.flip(i % N); }); } }; template struct BenchFlipAll { Duration operator()(Context& ctx) { T v = make_random_bitvec(ctx); return run_bench([&](auto) { v.flip(); }); } }; template struct BenchNone { Duration operator()(Context& ctx) { T v = make_random_bitvec(ctx); bool r = false; (void)r; return run_bench([&](auto) { r = v.none(); }); } }; template struct BenchCount { Duration operator()(Context& ctx) { T v = make_random_bitvec(ctx); volatile size_t r = 0; (void)r; return run_bench([&](auto) { r = v.count(); }); } }; template struct BenchLeftShift { Duration operator()(Context& ctx) { const T v = make_random_bitvec(ctx); T r = v; return run_bench([&](const auto i) { r <<= (i % N); }); } }; template struct BenchRightShift { Duration operator()(Context& ctx) { const T v = make_random_bitvec(ctx); T r = v; return run_bench([&](const auto i) { r >>= (i % N); }); } }; template struct BenchLeftRotate { Duration operator()(Context& ctx) { T v = make_random_bitvec(ctx); return run_bench([&](const auto i) { v.rotl(i % N); }); } }; template struct BenchRightRotate { Duration operator()(Context& ctx) { T v = make_random_bitvec(ctx); volatile bool r = false; (void)r; return run_bench([&](const auto i) { v.rotr(i % N); r = v.test(0); }); } }; template struct BenchFindFirst { Duration operator()(Context& ctx) { T v = make_random_bitvec(ctx); volatile size_t r = 0; (void)r; return run_bench([&](auto) { r = v.find_first(); }); } }; template struct BenchGrayCode { Duration operator()(Context& ctx) { const T v = make_random_bitvec(ctx); T r = v; return run_bench([&](auto) { chilbert::detail::gray_code(r); }); } }; template struct BenchGrayCodeInv { Duration operator()(Context& ctx) { const T v = make_random_bitvec(ctx); T r = v; return run_bench([&](auto) { chilbert::detail::gray_code_inv(r); }); } }; template struct BenchComparison { Duration operator()(Context& ctx) { std::vector vecs; for (size_t i = 0; i < 32; ++i) { vecs.emplace_back(make_random_bitvec(ctx)); } volatile bool r = false; return run_bench([&](const auto i) { r |= vecs[i % vecs.size()] < vecs[(i + 1) % vecs.size()]; }); } }; template struct BenchIteration { Duration operator()(Context& ctx) { T v = make_random_bitvec(ctx); auto i = v.begin(); volatile bool r = false; return run_bench([&](const auto) { r = (++i == v.end()); if (r) { i = v.begin(); } }); } }; /// Run benchmark for size N template class Bench, size_t N> void bench_row(Context& ctx, std::ostream& os) { std::array results = { ((N <= chilbert::SmallBitVec::bits_per_rack) ? Bench{}(ctx) : Duration{}), Bench, N>{}(ctx), Bench, N>{}(ctx), Bench{}(ctx), }; write_row(os, N, results); } /// Terminate recursion template class Bench> void bench_rec(Context&, std::ostream&) {} /// Run benchmark for sizes N, Ns... (recursive helper) template class Bench, size_t N, size_t... Ns> void bench_rec(Context& ctx, std::ostream& os) { bench_row(ctx, os); bench_rec(ctx, os); } /// Run benchmark template class Bench> void bench(Context& ctx, const std::string& name) { std::ofstream out("bitvec_" + name + ".txt"); out << "n\tsmall\tstatic\tbounded\tdynamic\n"; bench_rec(ctx, out); } int main() { Context ctx; bench(ctx, "and"); bench(ctx, "or"); bench(ctx, "xor"); bench(ctx, "none"); bench(ctx, "set_one"); bench(ctx, "set_all"); bench(ctx, "reset_one"); bench(ctx, "reset_all"); bench(ctx, "flip_one"); bench(ctx, "flip_all"); bench(ctx, "count"); bench(ctx, "find_first"); bench(ctx, "left_shift"); bench(ctx, "right_shift"); bench(ctx, "left_rotate"); bench(ctx, "right_rotate"); bench(ctx, "gray_code"); bench(ctx, "gray_code_inv"); bench(ctx, "comparison"); bench(ctx, "iteration"); return 0; }