Skip to content

Commit 84bc4d7

Browse files
committed
Add a per benchmark 'Repetitions' option.
1 parent 1080b17 commit 84bc4d7

File tree

4 files changed

+44
-3
lines changed

4 files changed

+44
-3
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,17 @@ the minimum time, or the wallclock time is 5x minimum time. The minimum time is
279279
set as a flag `--benchmark_min_time` or per benchmark by calling `MinTime` on
280280
the registered benchmark object.
281281
282+
## Reporting the mean and standard devation by repeated benchmarks
283+
By default each benchmark is run once and that single result is reported.
284+
However benchmarks are often noisy and a single result may not be representative
285+
of the overall behavior. For this reason it's possible to repeatedly rerun the
286+
benchmark.
287+
288+
The number of runs of each benchmark is specified globally by the
289+
`--benchmark_repetitions` flag or on a per benchmark basis by calling
290+
`Repetitions` on the registered benchmark object. When a benchmark is run
291+
more than once the mean and standard deviation of the runs will be reported.
292+
282293
## Fixtures
283294
Fixture tests are created by
284295
first defining a type that derives from ::benchmark::Fixture and then

include/benchmark/benchmark_api.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,8 +477,14 @@ class Benchmark {
477477

478478
// Set the minimum amount of time to use when running this benchmark. This
479479
// option overrides the `benchmark_min_time` flag.
480+
// REQUIRES: `t > 0`
480481
Benchmark* MinTime(double t);
481482

483+
// Specify the amount of times to repeat this benchmark. This option overrides
484+
// the `benchmark_repetitions` flag.
485+
// REQUIRES: `n > 0`
486+
Benchmark* Repetitions(int n);
487+
482488
// If a particular benchmark is I/O bound, runs multiple threads internally or
483489
// if for some reason CPU timings are not representative, call this method. If
484490
// called, the elapsed time will be used to control how many iterations are

src/benchmark.cc

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ struct Benchmark::Instance {
293293
bool use_manual_time;
294294
BigO complexity;
295295
bool last_benchmark_instance;
296+
int repetitions;
296297
double min_time;
297298
int threads; // Number of concurrent threads to use
298299
bool multithreaded; // Is benchmark multi-threaded?
@@ -332,6 +333,7 @@ class BenchmarkImp {
332333
void RangePair(int lo1, int hi1, int lo2, int hi2);
333334
void RangeMultiplier(int multiplier);
334335
void MinTime(double n);
336+
void Repetitions(int n);
335337
void UseRealTime();
336338
void UseManualTime();
337339
void Complexity(BigO complexity);
@@ -351,6 +353,7 @@ class BenchmarkImp {
351353
TimeUnit time_unit_;
352354
int range_multiplier_;
353355
double min_time_;
356+
int repetitions_;
354357
bool use_real_time_;
355358
bool use_manual_time_;
356359
BigO complexity_;
@@ -414,6 +417,7 @@ bool BenchmarkFamilies::FindBenchmarks(
414417
instance.time_unit = family->time_unit_;
415418
instance.range_multiplier = family->range_multiplier_;
416419
instance.min_time = family->min_time_;
420+
instance.repetitions = family->repetitions_;
417421
instance.use_real_time = family->use_real_time_;
418422
instance.use_manual_time = family->use_manual_time_;
419423
instance.complexity = family->complexity_;
@@ -430,6 +434,9 @@ bool BenchmarkFamilies::FindBenchmarks(
430434
if (!IsZero(family->min_time_)) {
431435
instance.name += StringPrintF("/min_time:%0.3f", family->min_time_);
432436
}
437+
if (family->repetitions_ != 0) {
438+
instance.name += StringPrintF("/repeats:%d", family->repetitions_);
439+
}
433440
if (family->use_manual_time_) {
434441
instance.name += "/manual_time";
435442
} else if (family->use_real_time_) {
@@ -453,7 +460,7 @@ bool BenchmarkFamilies::FindBenchmarks(
453460

454461
BenchmarkImp::BenchmarkImp(const char* name)
455462
: name_(name), arg_count_(-1), time_unit_(kNanosecond),
456-
range_multiplier_(kRangeMultiplier), min_time_(0.0),
463+
range_multiplier_(kRangeMultiplier), min_time_(0.0), repetitions_(0),
457464
use_real_time_(false), use_manual_time_(false),
458465
complexity_(oNone) {
459466
}
@@ -521,6 +528,12 @@ void BenchmarkImp::MinTime(double t) {
521528
min_time_ = t;
522529
}
523530

531+
532+
void BenchmarkImp::Repetitions(int n) {
533+
CHECK(n > 0);
534+
repetitions_ = n;
535+
}
536+
524537
void BenchmarkImp::UseRealTime() {
525538
CHECK(!use_manual_time_) << "Cannot set UseRealTime and UseManualTime simultaneously.";
526539
use_real_time_ = true;
@@ -633,6 +646,12 @@ Benchmark* Benchmark::RangeMultiplier(int multiplier) {
633646
return this;
634647
}
635648

649+
650+
Benchmark* Benchmark::Repetitions(int t) {
651+
imp_->Repetitions(t);
652+
return this;
653+
}
654+
636655
Benchmark* Benchmark::MinTime(double t) {
637656
imp_->MinTime(t);
638657
return this;
@@ -712,7 +731,9 @@ void RunBenchmark(const benchmark::internal::Benchmark::Instance& b,
712731
if (b.multithreaded)
713732
pool.resize(b.threads);
714733

715-
for (int i = 0; i < FLAGS_benchmark_repetitions; i++) {
734+
const int repeats = b.repetitions != 0 ? b.repetitions
735+
: FLAGS_benchmark_repetitions;
736+
for (int i = 0; i < repeats; i++) {
716737
std::string mem;
717738
for (;;) {
718739
// Try benchmark
@@ -893,12 +914,14 @@ void RunMatchingBenchmarks(const std::vector<Benchmark::Instance>& benchmarks,
893914
CHECK(reporter != nullptr);
894915

895916
// Determine the width of the name field using a minimum width of 10.
917+
bool has_repetitions = FLAGS_benchmark_repetitions > 1;
896918
size_t name_field_width = 10;
897919
for (const Benchmark::Instance& benchmark : benchmarks) {
898920
name_field_width =
899921
std::max<size_t>(name_field_width, benchmark.name.size());
922+
has_repetitions |= benchmark.repetitions > 1;
900923
}
901-
if (FLAGS_benchmark_repetitions > 1)
924+
if (has_repetitions)
902925
name_field_width += std::strlen("_stddev");
903926

904927
// Print header here

test/options_test.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ BENCHMARK(BM_basic)->MinTime(0.7);
3131
BENCHMARK(BM_basic)->UseRealTime();
3232
BENCHMARK(BM_basic)->ThreadRange(2, 4);
3333
BENCHMARK(BM_basic)->ThreadPerCpu();
34+
BENCHMARK(BM_basic)->Repetitions(3);
3435

3536
void CustomArgs(benchmark::internal::Benchmark* b) {
3637
for (int i = 0; i < 10; ++i) {

0 commit comments

Comments
 (0)