xref: /aosp_15_r20/external/google-benchmark/test/benchmark_setup_teardown_test.cc (revision dbb99499c3810fa1611fa2242a2fc446be01a57c)
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).
13 namespace singlethreaded {
14 static int setup_call = 0;
15 static int teardown_call = 0;
16 }  // namespace singlethreaded
DoSetup1(const benchmark::State & state)17 static 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 
DoTeardown1(const benchmark::State & state)24 static void DoTeardown1(const benchmark::State& state) {
25   ++singlethreaded::teardown_call;
26   assert(state.thread_index() == 0);
27 }
28 
BM_with_setup(benchmark::State & state)29 static void BM_with_setup(benchmark::State& state) {
30   for (auto s : state) {
31   }
32 }
33 BENCHMARK(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.
43 namespace concurrent {
44 static std::atomic<int> setup_call(0);
45 static std::atomic<int> teardown_call(0);
46 static std::atomic<int> func_call(0);
47 }  // namespace concurrent
48 
DoSetup2(const benchmark::State & state)49 static 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 
DoTeardown2(const benchmark::State & state)54 static 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 
BM_concurrent(benchmark::State & state)59 static 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 
65 BENCHMARK(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
74 namespace fixture_interaction {
75 int setup = 0;
76 int fixture_setup = 0;
77 }  // namespace fixture_interaction
78 
79 #define FIXTURE_BECHMARK_NAME MyFixture
80 
81 class FIXTURE_BECHMARK_NAME : public ::benchmark::Fixture {
82  public:
SetUp(const::benchmark::State &)83   void SetUp(const ::benchmark::State&) override {
84     fixture_interaction::fixture_setup++;
85   }
86 
~FIXTURE_BECHMARK_NAME()87   ~FIXTURE_BECHMARK_NAME() override {}
88 };
89 
BENCHMARK_F(FIXTURE_BECHMARK_NAME,BM_WithFixture)90 BENCHMARK_F(FIXTURE_BECHMARK_NAME, BM_WithFixture)(benchmark::State& st) {
91   for (auto _ : st) {
92   }
93 }
94 
DoSetupWithFixture(const benchmark::State &)95 static void DoSetupWithFixture(const benchmark::State&) {
96   fixture_interaction::setup++;
97 }
98 
99 BENCHMARK_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.
109 namespace repetitions {
110 int setup = 0;
111 }
112 
DoSetupWithRepetitions(const benchmark::State &)113 static void DoSetupWithRepetitions(const benchmark::State&) {
114   repetitions::setup++;
115 }
BM_WithRep(benchmark::State & state)116 static void BM_WithRep(benchmark::State& state) {
117   for (auto _ : state) {
118   }
119 }
120 
121 BENCHMARK(BM_WithRep)
122     ->Arg(1)
123     ->Arg(3)
124     ->Arg(5)
125     ->Arg(7)
126     ->Setup(DoSetupWithRepetitions)
127     ->Iterations(100)
128     ->Repetitions(4);
129 
main(int argc,char ** argv)130 int 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