#include #include #include #include #include #include #include #include "benchmark/benchmark.h" // Test that Setup() and Teardown() are called exactly once // for each benchmark run (single-threaded). namespace singlethreaded { static int setup_call = 0; static int teardown_call = 0; } // namespace singlethreaded static void DoSetup1(const benchmark::State& state) { ++singlethreaded::setup_call; // Setup/Teardown should never be called with any thread_idx != 0. assert(state.thread_index() == 0); } static void DoTeardown1(const benchmark::State& state) { ++singlethreaded::teardown_call; assert(state.thread_index() == 0); } static void BM_with_setup(benchmark::State& state) { for (auto s : state) { } } BENCHMARK(BM_with_setup) ->Arg(1) ->Arg(3) ->Arg(5) ->Arg(7) ->Iterations(100) ->Setup(DoSetup1) ->Teardown(DoTeardown1); // Test that Setup() and Teardown() are called once for each group of threads. namespace concurrent { static std::atomic setup_call(0); static std::atomic teardown_call(0); static std::atomic func_call(0); } // namespace concurrent static void DoSetup2(const benchmark::State& state) { concurrent::setup_call.fetch_add(1, std::memory_order_acquire); assert(state.thread_index() == 0); } static void DoTeardown2(const benchmark::State& state) { concurrent::teardown_call.fetch_add(1, std::memory_order_acquire); assert(state.thread_index() == 0); } static void BM_concurrent(benchmark::State& state) { for (auto s : state) { } concurrent::func_call.fetch_add(1, std::memory_order_acquire); } BENCHMARK(BM_concurrent) ->Setup(DoSetup2) ->Teardown(DoTeardown2) ->Iterations(100) ->Threads(5) ->Threads(10) ->Threads(15); // Testing interaction with Fixture::Setup/Teardown namespace fixture_interaction { int setup = 0; int fixture_setup = 0; } // namespace fixture_interaction #define FIXTURE_BECHMARK_NAME MyFixture class FIXTURE_BECHMARK_NAME : public ::benchmark::Fixture { public: void SetUp(const ::benchmark::State&) override { fixture_interaction::fixture_setup++; } ~FIXTURE_BECHMARK_NAME() override {} }; BENCHMARK_F(FIXTURE_BECHMARK_NAME, BM_WithFixture)(benchmark::State& st) { for (auto _ : st) { } } static void DoSetupWithFixture(const benchmark::State&) { fixture_interaction::setup++; } BENCHMARK_REGISTER_F(FIXTURE_BECHMARK_NAME, BM_WithFixture) ->Arg(1) ->Arg(3) ->Arg(5) ->Arg(7) ->Setup(DoSetupWithFixture) ->Repetitions(1) ->Iterations(100); // Testing repetitions. namespace repetitions { int setup = 0; } static void DoSetupWithRepetitions(const benchmark::State&) { repetitions::setup++; } static void BM_WithRep(benchmark::State& state) { for (auto _ : state) { } } BENCHMARK(BM_WithRep) ->Arg(1) ->Arg(3) ->Arg(5) ->Arg(7) ->Setup(DoSetupWithRepetitions) ->Iterations(100) ->Repetitions(4); int main(int argc, char** argv) { benchmark::Initialize(&argc, argv); size_t ret = benchmark::RunSpecifiedBenchmarks("."); assert(ret > 0); // Setup/Teardown is called once for each arg group (1,3,5,7). assert(singlethreaded::setup_call == 4); assert(singlethreaded::teardown_call == 4); // 3 group of threads calling this function (3,5,10). assert(concurrent::setup_call.load(std::memory_order_relaxed) == 3); assert(concurrent::teardown_call.load(std::memory_order_relaxed) == 3); assert((5 + 10 + 15) == concurrent::func_call.load(std::memory_order_relaxed)); // Setup is called 4 times, once for each arg group (1,3,5,7) assert(fixture_interaction::setup == 4); // Fixture::Setup is called every time the bm routine is run. // The exact number is indeterministic, so we just assert that // it's more than setup. assert(fixture_interaction::fixture_setup > fixture_interaction::setup); // Setup is call once for each repetition * num_arg = 4 * 4 = 16. assert(repetitions::setup == 16); return 0; }