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