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