1 // Copyright 2015 Google Inc. All rights reserved.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 #include "benchmark_register.h"
17 #ifndef BENCHMARK_OS_WINDOWS
18 #if !defined(BENCHMARK_OS_FUCHSIA) && !defined(BENCHMARK_OS_QURT)
19 #include <sys/resource.h>
28 #include <condition_variable>
39 #include "benchmark/benchmark.h"
40 #include "benchmark_api_internal.h"
42 #include "commandlineflags.h"
43 #include "complexity.h"
44 #include "internal_macros.h"
48 #include "statistics.h"
49 #include "string_util.h"
55 // For non-dense Range, intermediate values are powers of kRangeMultiplier.
56 static constexpr int kRangeMultiplier
= 8;
58 // The size of a benchmark family determines is the number of inputs to repeat
59 // the benchmark on. If this is "large" then warn the user during configuration.
60 static constexpr size_t kMaxFamilySize
= 100;
62 static constexpr char kDisabledPrefix
[] = "DISABLED_";
67 //=============================================================================//
69 //=============================================================================//
71 // Class for managing registered benchmarks. Note that each registered
72 // benchmark identifies a family of related benchmarks to run.
73 class BenchmarkFamilies
{
75 static BenchmarkFamilies
* GetInstance();
77 // Registers a benchmark family and returns the index assigned to it.
78 size_t AddBenchmark(std::unique_ptr
<Benchmark
> family
);
80 // Clear all registered benchmark families.
81 void ClearBenchmarks();
83 // Extract the list of benchmark instances that match the specified
84 // regular expression.
85 bool FindBenchmarks(std::string re
,
86 std::vector
<BenchmarkInstance
>* benchmarks
,
90 BenchmarkFamilies() {}
92 std::vector
<std::unique_ptr
<Benchmark
>> families_
;
96 BenchmarkFamilies
* BenchmarkFamilies::GetInstance() {
97 static BenchmarkFamilies instance
;
101 size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr
<Benchmark
> family
) {
103 size_t index
= families_
.size();
104 families_
.push_back(std::move(family
));
108 void BenchmarkFamilies::ClearBenchmarks() {
111 families_
.shrink_to_fit();
114 bool BenchmarkFamilies::FindBenchmarks(
115 std::string spec
, std::vector
<BenchmarkInstance
>* benchmarks
,
116 std::ostream
* ErrStream
) {
118 auto& Err
= *ErrStream
;
119 // Make regular expression out of command-line flag
120 std::string error_msg
;
122 bool is_negative_filter
= false;
123 if (spec
[0] == '-') {
124 spec
.replace(0, 1, "");
125 is_negative_filter
= true;
127 if (!re
.Init(spec
, &error_msg
)) {
128 Err
<< "Could not compile benchmark re: " << error_msg
<< std::endl
;
132 // Special list of thread counts to use when none are specified
133 const std::vector
<int> one_thread
= {1};
135 int next_family_index
= 0;
138 for (std::unique_ptr
<Benchmark
>& family
: families_
) {
139 int family_index
= next_family_index
;
140 int per_family_instance_index
= 0;
142 // Family was deleted or benchmark doesn't match
143 if (!family
) continue;
145 if (family
->ArgsCnt() == -1) {
148 const std::vector
<int>* thread_counts
=
149 (family
->thread_counts_
.empty()
151 : &static_cast<const std::vector
<int>&>(family
->thread_counts_
));
152 const size_t family_size
= family
->args_
.size() * thread_counts
->size();
153 // The benchmark will be run at least 'family_size' different inputs.
154 // If 'family_size' is very large warn the user.
155 if (family_size
> kMaxFamilySize
) {
156 Err
<< "The number of inputs is very large. " << family
->name_
157 << " will be repeated at least " << family_size
<< " times.\n";
159 // reserve in the special case the regex ".", since we know the final
160 // family size. this doesn't take into account any disabled benchmarks
161 // so worst case we reserve more than we need.
162 if (spec
== ".") benchmarks
->reserve(benchmarks
->size() + family_size
);
164 for (auto const& args
: family
->args_
) {
165 for (int num_threads
: *thread_counts
) {
166 BenchmarkInstance
instance(family
.get(), family_index
,
167 per_family_instance_index
, args
,
170 const auto full_name
= instance
.name().str();
171 if (full_name
.rfind(kDisabledPrefix
, 0) != 0 &&
172 ((re
.Match(full_name
) && !is_negative_filter
) ||
173 (!re
.Match(full_name
) && is_negative_filter
))) {
174 benchmarks
->push_back(std::move(instance
));
176 ++per_family_instance_index
;
178 // Only bump the next family index once we've estabilished that
179 // at least one instance of this family will be run.
180 if (next_family_index
== family_index
) ++next_family_index
;
188 Benchmark
* RegisterBenchmarkInternal(Benchmark
* bench
) {
189 std::unique_ptr
<Benchmark
> bench_ptr(bench
);
190 BenchmarkFamilies
* families
= BenchmarkFamilies::GetInstance();
191 families
->AddBenchmark(std::move(bench_ptr
));
195 // FIXME: This function is a hack so that benchmark.cc can access
196 // `BenchmarkFamilies`
197 bool FindBenchmarksInternal(const std::string
& re
,
198 std::vector
<BenchmarkInstance
>* benchmarks
,
200 return BenchmarkFamilies::GetInstance()->FindBenchmarks(re
, benchmarks
, Err
);
203 //=============================================================================//
205 //=============================================================================//
207 Benchmark::Benchmark(const std::string
& name
)
209 aggregation_report_mode_(ARM_Unspecified
),
210 time_unit_(GetDefaultTimeUnit()),
211 use_default_time_unit_(true),
212 range_multiplier_(kRangeMultiplier
),
217 measure_process_cpu_time_(false),
218 use_real_time_(false),
219 use_manual_time_(false),
221 complexity_lambda_(nullptr),
224 ComputeStatistics("mean", StatisticsMean
);
225 ComputeStatistics("median", StatisticsMedian
);
226 ComputeStatistics("stddev", StatisticsStdDev
);
227 ComputeStatistics("cv", StatisticsCV
, kPercentage
);
230 Benchmark::~Benchmark() {}
232 Benchmark
* Benchmark::Name(const std::string
& name
) {
237 Benchmark
* Benchmark::Arg(int64_t x
) {
238 BM_CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
239 args_
.push_back({x
});
243 Benchmark
* Benchmark::Unit(TimeUnit unit
) {
245 use_default_time_unit_
= false;
249 Benchmark
* Benchmark::Range(int64_t start
, int64_t limit
) {
250 BM_CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
251 std::vector
<int64_t> arglist
;
252 AddRange(&arglist
, start
, limit
, range_multiplier_
);
254 for (int64_t i
: arglist
) {
255 args_
.push_back({i
});
260 Benchmark
* Benchmark::Ranges(
261 const std::vector
<std::pair
<int64_t, int64_t>>& ranges
) {
262 BM_CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(ranges
.size()));
263 std::vector
<std::vector
<int64_t>> arglists(ranges
.size());
264 for (std::size_t i
= 0; i
< ranges
.size(); i
++) {
265 AddRange(&arglists
[i
], ranges
[i
].first
, ranges
[i
].second
,
269 ArgsProduct(arglists
);
274 Benchmark
* Benchmark::ArgsProduct(
275 const std::vector
<std::vector
<int64_t>>& arglists
) {
276 BM_CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(arglists
.size()));
278 std::vector
<std::size_t> indices(arglists
.size());
279 const std::size_t total
= std::accumulate(
280 std::begin(arglists
), std::end(arglists
), std::size_t{1},
281 [](const std::size_t res
, const std::vector
<int64_t>& arglist
) {
282 return res
* arglist
.size();
284 std::vector
<int64_t> args
;
285 args
.reserve(arglists
.size());
286 for (std::size_t i
= 0; i
< total
; i
++) {
287 for (std::size_t arg
= 0; arg
< arglists
.size(); arg
++) {
288 args
.push_back(arglists
[arg
][indices
[arg
]]);
290 args_
.push_back(args
);
295 indices
[arg
] = (indices
[arg
] + 1) % arglists
[arg
].size();
296 } while (indices
[arg
++] == 0 && arg
< arglists
.size());
302 Benchmark
* Benchmark::ArgName(const std::string
& name
) {
303 BM_CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
308 Benchmark
* Benchmark::ArgNames(const std::vector
<std::string
>& names
) {
309 BM_CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(names
.size()));
314 Benchmark
* Benchmark::DenseRange(int64_t start
, int64_t limit
, int step
) {
315 BM_CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
316 BM_CHECK_LE(start
, limit
);
317 for (int64_t arg
= start
; arg
<= limit
; arg
+= step
) {
318 args_
.push_back({arg
});
323 Benchmark
* Benchmark::Args(const std::vector
<int64_t>& args
) {
324 BM_CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(args
.size()));
325 args_
.push_back(args
);
329 Benchmark
* Benchmark::Apply(void (*custom_arguments
)(Benchmark
* benchmark
)) {
330 custom_arguments(this);
334 Benchmark
* Benchmark::Setup(void (*setup
)(const benchmark::State
&)) {
335 BM_CHECK(setup
!= nullptr);
340 Benchmark
* Benchmark::Teardown(void (*teardown
)(const benchmark::State
&)) {
341 BM_CHECK(teardown
!= nullptr);
342 teardown_
= teardown
;
346 Benchmark
* Benchmark::RangeMultiplier(int multiplier
) {
347 BM_CHECK(multiplier
> 1);
348 range_multiplier_
= multiplier
;
352 Benchmark
* Benchmark::MinTime(double t
) {
354 BM_CHECK(iterations_
== 0);
359 Benchmark
* Benchmark::MinWarmUpTime(double t
) {
361 BM_CHECK(iterations_
== 0);
362 min_warmup_time_
= t
;
366 Benchmark
* Benchmark::Iterations(IterationCount n
) {
368 BM_CHECK(IsZero(min_time_
));
369 BM_CHECK(IsZero(min_warmup_time_
));
374 Benchmark
* Benchmark::Repetitions(int n
) {
380 Benchmark
* Benchmark::ReportAggregatesOnly(bool value
) {
381 aggregation_report_mode_
= value
? ARM_ReportAggregatesOnly
: ARM_Default
;
385 Benchmark
* Benchmark::DisplayAggregatesOnly(bool value
) {
386 // If we were called, the report mode is no longer 'unspecified', in any case.
387 aggregation_report_mode_
= static_cast<AggregationReportMode
>(
388 aggregation_report_mode_
| ARM_Default
);
391 aggregation_report_mode_
= static_cast<AggregationReportMode
>(
392 aggregation_report_mode_
| ARM_DisplayReportAggregatesOnly
);
394 aggregation_report_mode_
= static_cast<AggregationReportMode
>(
395 aggregation_report_mode_
& ~ARM_DisplayReportAggregatesOnly
);
401 Benchmark
* Benchmark::MeasureProcessCPUTime() {
402 // Can be used together with UseRealTime() / UseManualTime().
403 measure_process_cpu_time_
= true;
407 Benchmark
* Benchmark::UseRealTime() {
408 BM_CHECK(!use_manual_time_
)
409 << "Cannot set UseRealTime and UseManualTime simultaneously.";
410 use_real_time_
= true;
414 Benchmark
* Benchmark::UseManualTime() {
415 BM_CHECK(!use_real_time_
)
416 << "Cannot set UseRealTime and UseManualTime simultaneously.";
417 use_manual_time_
= true;
421 Benchmark
* Benchmark::Complexity(BigO complexity
) {
422 complexity_
= complexity
;
426 Benchmark
* Benchmark::Complexity(BigOFunc
* complexity
) {
427 complexity_lambda_
= complexity
;
428 complexity_
= oLambda
;
432 Benchmark
* Benchmark::ComputeStatistics(const std::string
& name
,
433 StatisticsFunc
* statistics
,
434 StatisticUnit unit
) {
435 statistics_
.emplace_back(name
, statistics
, unit
);
439 Benchmark
* Benchmark::Threads(int t
) {
441 thread_counts_
.push_back(t
);
445 Benchmark
* Benchmark::ThreadRange(int min_threads
, int max_threads
) {
446 BM_CHECK_GT(min_threads
, 0);
447 BM_CHECK_GE(max_threads
, min_threads
);
449 AddRange(&thread_counts_
, min_threads
, max_threads
, 2);
453 Benchmark
* Benchmark::DenseThreadRange(int min_threads
, int max_threads
,
455 BM_CHECK_GT(min_threads
, 0);
456 BM_CHECK_GE(max_threads
, min_threads
);
457 BM_CHECK_GE(stride
, 1);
459 for (auto i
= min_threads
; i
< max_threads
; i
+= stride
) {
460 thread_counts_
.push_back(i
);
462 thread_counts_
.push_back(max_threads
);
466 Benchmark
* Benchmark::ThreadPerCpu() {
467 thread_counts_
.push_back(CPUInfo::Get().num_cpus
);
471 void Benchmark::SetName(const std::string
& name
) { name_
= name
; }
473 const char* Benchmark::GetName() const { return name_
.c_str(); }
475 int Benchmark::ArgsCnt() const {
477 if (arg_names_
.empty()) return -1;
478 return static_cast<int>(arg_names_
.size());
480 return static_cast<int>(args_
.front().size());
483 const char* Benchmark::GetArgName(int arg
) const {
485 BM_CHECK_LT(arg
, static_cast<int>(arg_names_
.size()));
486 return arg_names_
[arg
].c_str();
489 TimeUnit
Benchmark::GetTimeUnit() const {
490 return use_default_time_unit_
? GetDefaultTimeUnit() : time_unit_
;
493 //=============================================================================//
495 //=============================================================================//
497 void FunctionBenchmark::Run(State
& st
) { func_(st
); }
499 } // end namespace internal
501 void ClearRegisteredBenchmarks() {
502 internal::BenchmarkFamilies::GetInstance()->ClearBenchmarks();
505 std::vector
<int64_t> CreateRange(int64_t lo
, int64_t hi
, int multi
) {
506 std::vector
<int64_t> args
;
507 internal::AddRange(&args
, lo
, hi
, multi
);
511 std::vector
<int64_t> CreateDenseRange(int64_t start
, int64_t limit
, int step
) {
512 BM_CHECK_LE(start
, limit
);
513 std::vector
<int64_t> args
;
514 for (int64_t arg
= start
; arg
<= limit
; arg
+= step
) {
520 } // end namespace benchmark