@@ -172,6 +172,7 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
172
172
173
173
#include < stdint.h>
174
174
175
+ #include < algorithm>
175
176
#include < cassert>
176
177
#include < cstddef>
177
178
#include < iosfwd>
@@ -429,16 +430,18 @@ class State {
429
430
// Returns true if the benchmark should continue through another iteration.
430
431
// NOTE: A benchmark may not return from the test until KeepRunning() has
431
432
// 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);
442
445
443
446
// REQUIRES: timer is running and 'SkipWithError(...)' has not been called
444
447
// by the current thread.
@@ -565,12 +568,16 @@ class State {
565
568
int range_y () const { return range (1 ); }
566
569
567
570
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
+ }
569
574
570
575
private:
571
576
bool started_;
572
577
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.
574
581
575
582
std::vector<int > range_;
576
583
@@ -581,6 +588,11 @@ class State {
581
588
582
589
bool error_occurred_;
583
590
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
+
584
596
public:
585
597
// Container for user-defined counters.
586
598
UserCounters counters;
@@ -603,6 +615,53 @@ class State {
603
615
BENCHMARK_DISALLOW_COPY_AND_ASSIGN (State);
604
616
};
605
617
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
+
606
665
struct State ::StateIterator {
607
666
struct BENCHMARK_UNUSED Value {};
608
667
typedef std::forward_iterator_tag iterator_category;
0 commit comments