Allow custom multiplier in Benchmark::ThreadRange (#2304)
Currently Benchmark::ThreadRange hardcodes a geometric multiplier of 2 when generating thread counts across [min_threads, max_threads]. In contrast, DenseThreadRange allows a configurable stride parameter.
Add an optional mult parameter to Benchmark::ThreadRange (defaulting to 2) so users can specify geometric multipliers other than 2 (e.g. powers of 4 or 8) across thread ranges.
- Update ThreadRange in benchmark_api.h and benchmark_register.cc.
- Add unit tests in test/benchmark_test.cc and test/options_test.cc.
- Document the mult parameter and DenseThreadRange in docs/user_guide.md.
Closes #1531.
Co-authored-by: Roman Lebedev <lebedev.ri@gmail.com>
diff --git a/docs/user_guide.md b/docs/user_guide.md
index 5848b65..cd96baf 100644
--- a/docs/user_guide.md
+++ b/docs/user_guide.md
@@ -1218,14 +1218,28 @@
```
To run the benchmark across a range of thread counts, instead of `Threads`, use
-`ThreadRange`. This takes two parameters (`min_threads` and `max_threads`) and
-runs the benchmark once for values in the inclusive range. For example:
+`ThreadRange`. This takes two parameters (`min_threads` and `max_threads`), and an
+optional geometric multiplier `mult` (defaulting to 2), and runs the benchmark once
+for values in the inclusive range. For example:
```c++
BENCHMARK(BM_MultiThreaded)->ThreadRange(1, 8);
```
-will run `BM_MultiThreaded` with thread counts 1, 2, 4, and 8.
+will run `BM_MultiThreaded` with thread counts 1, 2, 4, and 8, while:
+
+```c++
+BENCHMARK(BM_MultiThreaded)->ThreadRange(1, 16, 4);
+```
+
+will run `BM_MultiThreaded` with thread counts 1, 4, and 16.
+
+You can also use `DenseThreadRange(min_threads, max_threads, stride = 1)` to step
+by an arithmetic stride:
+
+```c++
+BENCHMARK(BM_MultiThreaded)->DenseThreadRange(1, 4);
+```
If the benchmarked code itself uses threads and you want to compare it to
single-threaded code, you may want to use real-time ("wallclock") measurements
diff --git a/include/benchmark/benchmark_api.h b/include/benchmark/benchmark_api.h
index 1bff472..d7ba187 100644
--- a/include/benchmark/benchmark_api.h
+++ b/include/benchmark/benchmark_api.h
@@ -138,7 +138,7 @@
StatisticsFunc* statistics,
StatisticUnit unit = kTime);
Benchmark* Threads(int t);
- Benchmark* ThreadRange(int min_threads, int max_threads);
+ Benchmark* ThreadRange(int min_threads, int max_threads, int mult = 2);
Benchmark* DenseThreadRange(int min_threads, int max_threads, int stride = 1);
Benchmark* ThreadPerCpu();
Benchmark* ThreadRunner(threadrunner_factory&& factory);
diff --git a/src/benchmark_register.cc b/src/benchmark_register.cc
index 560a762..97dee29 100644
--- a/src/benchmark_register.cc
+++ b/src/benchmark_register.cc
@@ -470,11 +470,12 @@
return this;
}
-Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads) {
+Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads, int mult) {
BM_CHECK_GT(min_threads, 0);
BM_CHECK_GE(max_threads, min_threads);
+ BM_CHECK_GE(mult, 2);
- internal::AddRange(&thread_counts_, min_threads, max_threads, 2);
+ internal::AddRange(&thread_counts_, min_threads, max_threads, mult);
return this;
}
diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc
index b98fbdf..0dd37bf 100644
--- a/test/benchmark_test.cc
+++ b/test/benchmark_test.cc
@@ -261,6 +261,29 @@
BENCHMARK_TEMPLATE1_CAPTURE(BM_template1_capture, void, foo, 24UL);
BENCHMARK_CAPTURE(BM_template1_capture<void>, foo, 24UL);
+void BM_ThreadRanges(benchmark::State& st) {
+ switch (st.range(0)) {
+ case 1:
+ assert(st.threads() == 1 || st.threads() == 2 || st.threads() == 4 ||
+ st.threads() == 8);
+ break;
+ case 2:
+ assert(st.threads() == 1 || st.threads() == 4 || st.threads() == 16);
+ break;
+ case 3:
+ assert(st.threads() == 2 || st.threads() == 4 || st.threads() == 16 ||
+ st.threads() == 32);
+ break;
+ default:
+ assert(false && "Invalid test case number");
+ }
+ while (st.KeepRunning()) {
+ }
+}
+BENCHMARK(BM_ThreadRanges)->Arg(1)->ThreadRange(1, 8);
+BENCHMARK(BM_ThreadRanges)->Arg(2)->ThreadRange(1, 16, 4);
+BENCHMARK(BM_ThreadRanges)->Arg(3)->ThreadRange(2, 32, 4);
+
void BM_DenseThreadRanges(benchmark::State& st) {
switch (st.range(0)) {
case 1:
diff --git a/test/options_test.cc b/test/options_test.cc
index 7ace933..9056093 100644
--- a/test/options_test.cc
+++ b/test/options_test.cc
@@ -41,6 +41,7 @@
BENCHMARK(BM_basic)->MinTime(0.1)->MinWarmUpTime(0.2);
BENCHMARK(BM_basic)->UseRealTime();
BENCHMARK(BM_basic)->ThreadRange(2, 4);
+BENCHMARK(BM_basic)->ThreadRange(1, 16, 4);
BENCHMARK(BM_basic)->ThreadPerCpu();
BENCHMARK(BM_basic)->Repetitions(3);
BENCHMARK(BM_basic)