benchmark 1.10.0
Loading...
Searching...
No Matches
state.h
1// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef BENCHMARK_STATE_H_
16#define BENCHMARK_STATE_H_
17
18#if defined(_MSC_VER)
19#pragma warning(push)
20#pragma warning(disable : 4251 4324)
21#endif
22
23#include <cassert>
24#include <string>
25#include <vector>
26
27#include "benchmark/counter.h"
28#include "benchmark/macros.h"
29#include "benchmark/statistics.h"
30#include "benchmark/types.h"
31
32namespace benchmark {
33
34namespace internal {
36class ThreadTimer;
37class ThreadManager;
39} // namespace internal
40
41class ProfilerManager;
42
43class BENCHMARK_EXPORT BENCHMARK_INTERNAL_CACHELINE_ALIGNED State {
44 public:
45 struct StateIterator;
46 friend struct StateIterator;
47
48 inline BENCHMARK_ALWAYS_INLINE StateIterator begin();
49 inline BENCHMARK_ALWAYS_INLINE StateIterator end();
50
51 inline bool KeepRunning();
52
53 inline bool KeepRunningBatch(IterationCount n);
54
55 // Only valid while the benchmark loop is running.
56 //
57 // Forced inline so the assertion is compiled with the caller's NDEBUG.
58 // State is exported, and MSVC otherwise calls the copy of this function
59 // inside benchmark.dll, which was built with the library's NDEBUG.
60 inline BENCHMARK_ALWAYS_INLINE void PauseTiming() {
61 assert(in_timed_section() &&
62 "PauseTiming() called outside of the benchmark loop");
63 PauseTimingImpl();
64 }
65
66 // Only valid while the benchmark loop is running. Forced inline for the
67 // same reason as PauseTiming().
68 inline BENCHMARK_ALWAYS_INLINE void ResumeTiming() {
69 assert(in_timed_section() &&
70 "ResumeTiming() called outside of the benchmark loop");
71 ResumeTimingImpl();
72 }
73
74 void SkipWithMessage(const std::string& msg);
75
76 void SkipWithError(const std::string& msg);
77
78 bool skipped() const { return internal::NotSkipped != skipped_; }
79
80 bool in_timed_section() const { return started_ && !finished_ && !skipped(); }
81
82 bool error_occurred() const { return internal::SkippedWithError == skipped_; }
83
84 void SetIterationTime(double seconds);
85
86 BENCHMARK_ALWAYS_INLINE
87 void SetBytesProcessed(int64_t bytes) {
88 counters["bytes_per_second"] =
89 Counter(static_cast<double>(bytes), Counter::kIsRate, Counter::kIs1024);
90 }
91
92 BENCHMARK_ALWAYS_INLINE
93 int64_t bytes_processed() const {
94 if (counters.find("bytes_per_second") != counters.end())
95 return static_cast<int64_t>(counters.at("bytes_per_second"));
96 return 0;
97 }
98
99 BENCHMARK_ALWAYS_INLINE
100 void SetComplexityN(ComplexityN complexity_n) {
101 complexity_n_ = complexity_n;
102 }
103
104 BENCHMARK_ALWAYS_INLINE
105 ComplexityN complexity_length_n() const { return complexity_n_; }
106
107 BENCHMARK_ALWAYS_INLINE
108 void SetItemsProcessed(int64_t items) {
109 counters["items_per_second"] =
110 Counter(static_cast<double>(items), benchmark::Counter::kIsRate);
111 }
112
113 BENCHMARK_ALWAYS_INLINE
114 int64_t items_processed() const {
115 if (counters.find("items_per_second") != counters.end())
116 return static_cast<int64_t>(counters.at("items_per_second"));
117 return 0;
118 }
119
120 void SetLabel(const std::string& label);
121
122 BENCHMARK_ALWAYS_INLINE
123 int64_t range(std::size_t pos = 0) const {
124 assert(range_.size() > pos);
125 return range_[pos];
126 }
127
128 BENCHMARK_DEPRECATED_MSG("use 'range(0)' instead")
129 int64_t range_x() const { return range(0); }
130
131 BENCHMARK_DEPRECATED_MSG("use 'range(1)' instead")
132 int64_t range_y() const { return range(1); }
133
134 BENCHMARK_ALWAYS_INLINE
135 int threads() const { return threads_; }
136
137 BENCHMARK_ALWAYS_INLINE
138 int thread_index() const { return thread_index_; }
139
140 BENCHMARK_ALWAYS_INLINE
141 IterationCount iterations() const {
142 if (BENCHMARK_BUILTIN_EXPECT(!started_, false)) {
143 return 0;
144 }
145 return max_iterations - total_iterations_ + batch_leftover_;
146 }
147
148 BENCHMARK_ALWAYS_INLINE
149 std::string name() const { return name_; }
150
151 size_t range_size() const { return range_.size(); }
152
153 private:
154 IterationCount total_iterations_;
155
156 IterationCount batch_leftover_;
157
158 public:
159 const IterationCount max_iterations;
160
161 private:
162 bool started_;
163 bool finished_;
164 internal::Skipped skipped_;
165
166 std::vector<int64_t> range_;
167
168 ComplexityN complexity_n_;
169
170 public:
171 UserCounters counters;
172
173 private:
174 State(std::string name, IterationCount max_iters,
175 const std::vector<int64_t>& ranges, int thread_i, int n_threads,
177 internal::PerfCountersMeasurement* perf_counters_measurement,
178 ProfilerManager* profiler_manager);
179
180 void StartKeepRunning();
181 inline bool KeepRunningInternal(IterationCount n, bool is_batch);
182 void FinishKeepRunning();
183
184 // The checked entry points above forward here; keeping the bodies out of
185 // line keeps the assertions with the caller, whose NDEBUG decides whether
186 // they are compiled in.
187 void PauseTimingImpl();
188 void ResumeTimingImpl();
189
190 const std::string name_;
191 const int thread_index_;
192 const int threads_;
193
194 internal::ThreadTimer* const timer_;
195 internal::ThreadManager* const manager_;
196 internal::PerfCountersMeasurement* const perf_counters_measurement_;
197 ProfilerManager* const profiler_manager_;
198
199 friend class internal::BenchmarkInstance;
200};
201
202inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunning() {
203 return KeepRunningInternal(1, /*is_batch=*/false);
204}
205
206inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningBatch(IterationCount n) {
207 return KeepRunningInternal(n, /*is_batch=*/true);
208}
209
210inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningInternal(IterationCount n,
211 bool is_batch) {
212 assert(n > 0);
213 assert(is_batch || n == 1);
214 if (BENCHMARK_BUILTIN_EXPECT(total_iterations_ >= n, true)) {
215 total_iterations_ -= n;
216 return true;
217 }
218 if (!started_) {
219 StartKeepRunning();
220 if (!skipped() && total_iterations_ >= n) {
221 total_iterations_ -= n;
222 return true;
223 }
224 }
225 if (is_batch && total_iterations_ != 0) {
226 batch_leftover_ = n - total_iterations_;
227 total_iterations_ = 0;
228 return true;
229 }
230 FinishKeepRunning();
231 return false;
232}
233
235 struct BENCHMARK_UNUSED Value {};
236 typedef std::forward_iterator_tag iterator_category;
237 typedef Value value_type;
238 typedef Value reference;
239 typedef Value pointer;
240 typedef std::ptrdiff_t difference_type;
241
242 private:
243 friend class State;
244 BENCHMARK_ALWAYS_INLINE
245 StateIterator() : cached_(0), parent_() {}
246
247 BENCHMARK_ALWAYS_INLINE
248 explicit StateIterator(State* st)
249 : cached_(st->skipped() ? 0 : st->max_iterations), parent_(st) {}
250
251 public:
252 BENCHMARK_ALWAYS_INLINE
253 Value operator*() const { return Value(); }
254
255 BENCHMARK_ALWAYS_INLINE
256 StateIterator& operator++() {
257 assert(cached_ > 0);
258 --cached_;
259 return *this;
260 }
261
262 BENCHMARK_ALWAYS_INLINE
263 bool operator!=(StateIterator const&) const {
264 if (BENCHMARK_BUILTIN_EXPECT(cached_ != 0, true)) return true;
265 parent_->FinishKeepRunning();
266 return false;
267 }
268
269 private:
270 IterationCount cached_;
271 State* const parent_;
272};
273
274inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::begin() {
275 return StateIterator(this);
276}
277inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::end() {
278 StartKeepRunning();
279 return StateIterator();
280}
281
282class ScopedPauseTiming {
283 public:
284 explicit ScopedPauseTiming(State& state) : state_(state) {
285 state_.PauseTiming();
286 }
287 ~ScopedPauseTiming() {
288 if (!state_.skipped()) state_.ResumeTiming();
289 }
290
291 ScopedPauseTiming(const ScopedPauseTiming&) = delete;
292 void operator=(const ScopedPauseTiming&) = delete;
293
294 ScopedPauseTiming(ScopedPauseTiming&&) = delete;
295 void operator=(ScopedPauseTiming&&) = delete;
296
297 private:
298 State& state_;
299};
300
301} // namespace benchmark
302
303#if defined(_MSC_VER)
304#pragma warning(pop)
305#endif
306
307#endif // BENCHMARK_STATE_H_
Definition counter.h:31
Definition managers.h:55
Definition state.h:43
Definition benchmark_api_internal.h:20
Definition perf_counters.h:152
Definition thread_manager.h:14
Definition thread_timer.h:10
Definition state.h:234