1#include <atomic> 2#include <cassert> 3#include <cstdlib> 4#include <cstring> 5#include <iostream> 6#include <limits> 7#include <string> 8 9#include "benchmark/benchmark.h" 10 11// Test that Setup() and Teardown() are called exactly once 12// for each benchmark run (single-threaded). 13namespace singlethreaded { 14static int setup_call = 0; 15static int teardown_call = 0; 16} // namespace singlethreaded 17static void DoSetup1(const benchmark::State& state) { 18 ++singlethreaded::setup_call; 19 20 // Setup/Teardown should never be called with any thread_idx != 0. 21 assert(state.thread_index() == 0); 22} 23 24static void DoTeardown1(const benchmark::State& state) { 25 ++singlethreaded::teardown_call; 26 assert(state.thread_index() == 0); 27} 28 29static void BM_with_setup(benchmark::State& state) { 30 for (auto s : state) { 31 } 32} 33BENCHMARK(BM_with_setup) 34 ->Arg(1) 35 ->Arg(3) 36 ->Arg(5) 37 ->Arg(7) 38 ->Iterations(100) 39 ->Setup(DoSetup1) 40 ->Teardown(DoTeardown1); 41 42// Test that Setup() and Teardown() are called once for each group of threads. 43namespace concurrent { 44static std::atomic<int> setup_call(0); 45static std::atomic<int> teardown_call(0); 46static std::atomic<int> func_call(0); 47} // namespace concurrent 48 49static void DoSetup2(const benchmark::State& state) { 50 concurrent::setup_call.fetch_add(1, std::memory_order_acquire); 51 assert(state.thread_index() == 0); 52} 53 54static void DoTeardown2(const benchmark::State& state) { 55 concurrent::teardown_call.fetch_add(1, std::memory_order_acquire); 56 assert(state.thread_index() == 0); 57} 58 59static void BM_concurrent(benchmark::State& state) { 60 for (auto s : state) { 61 } 62 concurrent::func_call.fetch_add(1, std::memory_order_acquire); 63} 64 65BENCHMARK(BM_concurrent) 66 ->Setup(DoSetup2) 67 ->Teardown(DoTeardown2) 68 ->Iterations(100) 69 ->Threads(5) 70 ->Threads(10) 71 ->Threads(15); 72 73// Testing interaction with Fixture::Setup/Teardown 74namespace fixture_interaction { 75int setup = 0; 76int fixture_setup = 0; 77} // namespace fixture_interaction 78 79#define FIXTURE_BECHMARK_NAME MyFixture 80 81class FIXTURE_BECHMARK_NAME : public ::benchmark::Fixture { 82 public: 83 void SetUp(const ::benchmark::State&) override { 84 fixture_interaction::fixture_setup++; 85 } 86 87 ~FIXTURE_BECHMARK_NAME() override {} 88}; 89 90BENCHMARK_F(FIXTURE_BECHMARK_NAME, BM_WithFixture)(benchmark::State& st) { 91 for (auto _ : st) { 92 } 93} 94 95static void DoSetupWithFixture(const benchmark::State&) { 96 fixture_interaction::setup++; 97} 98 99BENCHMARK_REGISTER_F(FIXTURE_BECHMARK_NAME, BM_WithFixture) 100 ->Arg(1) 101 ->Arg(3) 102 ->Arg(5) 103 ->Arg(7) 104 ->Setup(DoSetupWithFixture) 105 ->Repetitions(1) 106 ->Iterations(100); 107 108// Testing repetitions. 109namespace repetitions { 110int setup = 0; 111} 112 113static void DoSetupWithRepetitions(const benchmark::State&) { 114 repetitions::setup++; 115} 116static void BM_WithRep(benchmark::State& state) { 117 for (auto _ : state) { 118 } 119} 120 121BENCHMARK(BM_WithRep) 122 ->Arg(1) 123 ->Arg(3) 124 ->Arg(5) 125 ->Arg(7) 126 ->Setup(DoSetupWithRepetitions) 127 ->Iterations(100) 128 ->Repetitions(4); 129 130int main(int argc, char** argv) { 131 benchmark::Initialize(&argc, argv); 132 133 size_t ret = benchmark::RunSpecifiedBenchmarks("."); 134 assert(ret > 0); 135 136 // Setup/Teardown is called once for each arg group (1,3,5,7). 137 assert(singlethreaded::setup_call == 4); 138 assert(singlethreaded::teardown_call == 4); 139 140 // 3 group of threads calling this function (3,5,10). 141 assert(concurrent::setup_call.load(std::memory_order_relaxed) == 3); 142 assert(concurrent::teardown_call.load(std::memory_order_relaxed) == 3); 143 assert((5 + 10 + 15) == 144 concurrent::func_call.load(std::memory_order_relaxed)); 145 146 // Setup is called 4 times, once for each arg group (1,3,5,7) 147 assert(fixture_interaction::setup == 4); 148 // Fixture::Setup is called every time the bm routine is run. 149 // The exact number is indeterministic, so we just assert that 150 // it's more than setup. 151 assert(fixture_interaction::fixture_setup > fixture_interaction::setup); 152 153 // Setup is call once for each repetition * num_arg = 4 * 4 = 16. 154 assert(repetitions::setup == 16); 155 156 return 0; 157} 158