Skip to content

Commit 8065d70

Browse files
authored
Merge 63c31b0 into bc83262
2 parents bc83262 + 63c31b0 commit 8065d70

File tree

4 files changed

+100
-19
lines changed

4 files changed

+100
-19
lines changed

include/benchmark/benchmark.h

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
172172

173173
#include <stdint.h>
174174

175+
#include <algorithm>
175176
#include <cassert>
176177
#include <cstddef>
177178
#include <iosfwd>
@@ -429,16 +430,18 @@ class State {
429430
// Returns true if the benchmark should continue through another iteration.
430431
// NOTE: A benchmark may not return from the test until KeepRunning() has
431432
// returned false.
432-
bool KeepRunning() {
433-
if (BENCHMARK_BUILTIN_EXPECT(!started_, false)) {
434-
StartKeepRunning();
435-
}
436-
bool const res = (--total_iterations_ != 0);
437-
if (BENCHMARK_BUILTIN_EXPECT(!res, false)) {
438-
FinishKeepRunning();
439-
}
440-
return res;
441-
}
433+
bool KeepRunning();
434+
435+
// Returns true iff the benchmark should run n more iterations.
436+
// NOTE: A benchmark must not return from the test until KeepRunningBatch()
437+
// has returned false.
438+
// NOTE: KeepRunningBatch() may overshoot by up to 'n' iterations.
439+
//
440+
// Intended usage:
441+
// while (state.KeepRunningBatch(1000)) {
442+
// // process 1000 elements
443+
// }
444+
bool KeepRunningBatch(int n);
442445

443446
// REQUIRES: timer is running and 'SkipWithError(...)' has not been called
444447
// by the current thread.
@@ -565,12 +568,16 @@ class State {
565568
int range_y() const { return range(1); }
566569

567570
BENCHMARK_ALWAYS_INLINE
568-
size_t iterations() const { return (max_iterations - total_iterations_) + 1; }
571+
size_t iterations() const {
572+
return (max_iterations - total_iterations_ + batch_leftover_);
573+
}
569574

570575
private:
571576
bool started_;
572577
bool finished_;
573-
size_t total_iterations_;
578+
// When total_iterations_ is 0, KeepRunning() and friends will return false.
579+
int64_t total_iterations_;
580+
// May be larger than max_iterations.
574581

575582
std::vector<int> range_;
576583

@@ -581,6 +588,11 @@ class State {
581588

582589
bool error_occurred_;
583590

591+
// When using KeepRunningBatch(), batch_leftover_ holds the number of
592+
// iterations beyond max_iters that were run. Used to track
593+
// completed_iterations_ accurately.
594+
size_t batch_leftover_;
595+
584596
public:
585597
// Container for user-defined counters.
586598
UserCounters counters;
@@ -603,6 +615,53 @@ class State {
603615
BENCHMARK_DISALLOW_COPY_AND_ASSIGN(State);
604616
};
605617

618+
inline BENCHMARK_ALWAYS_INLINE
619+
bool State::KeepRunning() {
620+
// total_iterations_ is set to 0 by the constructor, and always set to a
621+
// nonzero value by StartKepRunning().
622+
if (BENCHMARK_BUILTIN_EXPECT(total_iterations_ != 0, true)) {
623+
--total_iterations_;
624+
return true;
625+
}
626+
if (!started_ && !error_occurred_) {
627+
StartKeepRunning();
628+
// max_iterations > 0. The first iteration is always valid.
629+
--total_iterations_;
630+
return true;
631+
} else {
632+
FinishKeepRunning();
633+
return false;
634+
}
635+
}
636+
637+
inline BENCHMARK_ALWAYS_INLINE
638+
bool State::KeepRunningBatch(int n) {
639+
// total_iterations_ is set to 0 by the constructor, and always set to a
640+
// nonzero value by StartKepRunning().
641+
if (BENCHMARK_BUILTIN_EXPECT(total_iterations_ >= n, true)) {
642+
total_iterations_ -= n;
643+
return true;
644+
}
645+
if (!started_ && !error_occurred_) {
646+
StartKeepRunning();
647+
if (total_iterations_ >= n) {
648+
total_iterations_-= n;
649+
} else {
650+
batch_leftover_ = n - total_iterations_;
651+
total_iterations_ = 0;
652+
}
653+
return true;
654+
}
655+
if (total_iterations_ != 0) {
656+
batch_leftover_ = n - total_iterations_;
657+
total_iterations_ = 0;
658+
return true;
659+
} else {
660+
FinishKeepRunning();
661+
return false;
662+
}
663+
}
664+
606665
struct State::StateIterator {
607666
struct BENCHMARK_UNUSED Value {};
608667
typedef std::forward_iterator_tag iterator_category;

src/benchmark.cc

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ void RunInThread(const benchmark::internal::Benchmark::Instance* b,
268268
internal::ThreadTimer timer;
269269
State st(iters, b->arg, thread_id, b->threads, &timer, manager);
270270
b->benchmark->Run(st);
271-
CHECK(st.iterations() == st.max_iterations)
271+
CHECK(st.iterations() >= st.max_iterations)
272272
<< "Benchmark returned before State::KeepRunning() returned false!";
273273
{
274274
MutexLock l(manager->GetBenchmarkMutex());
@@ -399,20 +399,20 @@ State::State(size_t max_iters, const std::vector<int>& ranges, int thread_i,
399399
internal::ThreadManager* manager)
400400
: started_(false),
401401
finished_(false),
402-
total_iterations_(max_iters + 1),
402+
total_iterations_(0),
403403
range_(ranges),
404404
bytes_processed_(0),
405405
items_processed_(0),
406406
complexity_n_(0),
407407
error_occurred_(false),
408+
batch_leftover_(0),
408409
counters(),
409410
thread_index(thread_i),
410411
threads(n_threads),
411412
max_iterations(max_iters),
412413
timer_(timer),
413414
manager_(manager) {
414415
CHECK(max_iterations != 0) << "At least one iteration must be run";
415-
CHECK(total_iterations_ != 0) << "max iterations wrapped around";
416416
CHECK_LT(thread_index, threads) << "thread_index must be less than threads";
417417
}
418418

@@ -437,7 +437,7 @@ void State::SkipWithError(const char* msg) {
437437
manager_->results.has_error_ = true;
438438
}
439439
}
440-
total_iterations_ = 1;
440+
total_iterations_ = 0;
441441
if (timer_->running()) timer_->StopTimer();
442442
}
443443

@@ -453,6 +453,7 @@ void State::SetLabel(const char* label) {
453453
void State::StartKeepRunning() {
454454
CHECK(!started_ && !finished_);
455455
started_ = true;
456+
total_iterations_ = error_occurred_ ? 0 : max_iterations;
456457
manager_->StartStopBarrier();
457458
if (!error_occurred_) ResumeTiming();
458459
}
@@ -462,8 +463,8 @@ void State::FinishKeepRunning() {
462463
if (!error_occurred_) {
463464
PauseTiming();
464465
}
465-
// Total iterations has now wrapped around zero. Fix this.
466-
total_iterations_ = 1;
466+
// Total iterations has now wrapped around past 0. Fix this.
467+
total_iterations_ = 0;
467468
finished_ = true;
468469
manager_->StartStopBarrier();
469470
}

test/basic_test.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,21 @@ void BM_KeepRunning(benchmark::State& state) {
102102
while (state.KeepRunning()) {
103103
++iter_count;
104104
}
105-
assert(iter_count == state.max_iterations);
105+
assert(iter_count == state.iterations());
106106
}
107107
BENCHMARK(BM_KeepRunning);
108108

109+
void BM_KeepRunningBatch(benchmark::State& state) {
110+
// Choose a prime batch size to avoid evenly dividing max_iterations.
111+
const size_t batch_size = 101;
112+
size_t iter_count = 0;
113+
while (state.KeepRunningBatch(batch_size)) {
114+
iter_count += batch_size;
115+
}
116+
assert(state.iterations() == iter_count);
117+
}
118+
BENCHMARK(BM_KeepRunningBatch);
119+
109120
void BM_RangedFor(benchmark::State& state) {
110121
size_t iter_count = 0;
111122
for (auto _ : state) {

test/skip_with_error_test.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ void BM_error_before_running(benchmark::State& state) {
7070
BENCHMARK(BM_error_before_running);
7171
ADD_CASES("BM_error_before_running", {{"", true, "error message"}});
7272

73+
74+
void BM_error_before_running_batch(benchmark::State& state) {
75+
state.SkipWithError("error message");
76+
while (state.KeepRunningBatch(17)) {
77+
assert(false);
78+
}
79+
}
80+
BENCHMARK(BM_error_before_running_batch);
81+
ADD_CASES("BM_error_before_running_batch", {{"", true, "error message"}});
82+
7383
void BM_error_before_running_range_for(benchmark::State& state) {
7484
state.SkipWithError("error message");
7585
for (auto _ : state) {

0 commit comments

Comments
 (0)