Fixups following addition of KeepRunningBatch (296ec5693) (#526)

* Support State::KeepRunningBatch().

State::KeepRunning() can take large amounts of time relative to quick
operations (on the order of 1ns, depending on hardware). For such
sensitive operations, it is recommended to run batches of repeated
operations.

This commit simplifies handling of total_iterations_. Rather than
predecrementing such that total_iterations_ == 1 signals that
KeepRunning() should exit, total_iterations_ == 0 now signals the
intention for the benchmark to exit.

* Create better fast path in State::KeepRunningBatch()

* Replace int parameter with size_t to fix signed mismatch warnings

* Ensure benchmark State has been started even on error.

* Simplify KeepRunningBatch()

* Implement KeepRunning() in terms of KeepRunningBatch().

* Improve codegen by helping the compiler undestand dead code.

* Dummy commit for build bots' benefit.
This commit is contained in:
Samuel Panzer 2018-02-13 15:54:46 -05:00 committed by Eric
parent 37dbe80f9b
commit 3924ee7b8a
1 changed files with 15 additions and 17 deletions

View File

@ -433,6 +433,7 @@ class State {
bool KeepRunning(); bool KeepRunning();
// Returns true iff the benchmark should run n more iterations. // Returns true iff the benchmark should run n more iterations.
// REQUIRES: 'n' > 0.
// NOTE: A benchmark must not return from the test until KeepRunningBatch() // NOTE: A benchmark must not return from the test until KeepRunningBatch()
// has returned false. // has returned false.
// NOTE: KeepRunningBatch() may overshoot by up to 'n' iterations. // NOTE: KeepRunningBatch() may overshoot by up to 'n' iterations.
@ -609,6 +610,9 @@ class State {
private: private:
void StartKeepRunning(); void StartKeepRunning();
// Implementation of KeepRunning() and KeepRunningBatch().
// is_batch must be true unless n is 1.
bool KeepRunningInternal(size_t n, bool is_batch);
void FinishKeepRunning(); void FinishKeepRunning();
internal::ThreadTimer* timer_; internal::ThreadTimer* timer_;
internal::ThreadManager* manager_; internal::ThreadManager* manager_;
@ -617,28 +621,21 @@ class State {
inline BENCHMARK_ALWAYS_INLINE inline BENCHMARK_ALWAYS_INLINE
bool State::KeepRunning() { bool State::KeepRunning() {
// total_iterations_ is set to 0 by the constructor, and always set to a return KeepRunningInternal(1, /*is_batch=*/ false);
// nonzero value by StartKepRunning().
if (BENCHMARK_BUILTIN_EXPECT(total_iterations_ != 0, true)) {
--total_iterations_;
return true;
}
if (!started_) {
StartKeepRunning();
if (!error_occurred_) {
// max_iterations > 0. The first iteration is always valid.
--total_iterations_;
return true;
}
}
FinishKeepRunning();
return false;
} }
inline BENCHMARK_ALWAYS_INLINE inline BENCHMARK_ALWAYS_INLINE
bool State::KeepRunningBatch(size_t n) { bool State::KeepRunningBatch(size_t n) {
return KeepRunningInternal(n, /*is_batch=*/ true);
}
inline BENCHMARK_ALWAYS_INLINE
bool State::KeepRunningInternal(size_t n, bool is_batch) {
// total_iterations_ is set to 0 by the constructor, and always set to a // total_iterations_ is set to 0 by the constructor, and always set to a
// nonzero value by StartKepRunning(). // nonzero value by StartKepRunning().
assert(n > 0);
// n must be 1 unless is_batch is true.
assert(is_batch || n == 1);
if (BENCHMARK_BUILTIN_EXPECT(total_iterations_ >= n, true)) { if (BENCHMARK_BUILTIN_EXPECT(total_iterations_ >= n, true)) {
total_iterations_ -= n; total_iterations_ -= n;
return true; return true;
@ -650,7 +647,8 @@ bool State::KeepRunningBatch(size_t n) {
return true; return true;
} }
} }
if (total_iterations_ != 0) { // For non-batch runs, total_iterations_ must be 0 by now.
if (is_batch && total_iterations_ != 0) {
batch_leftover_ = n - total_iterations_; batch_leftover_ = n - total_iterations_;
total_iterations_ = 0; total_iterations_ = 0;
return true; return true;