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 #ifndef BENCHMARK_OS_FUCHSIA
19 #include <sys/resource.h>
27 #include <condition_variable>
37 #include "benchmark/benchmark.h"
38 #include "benchmark_api_internal.h"
40 #include "commandlineflags.h"
41 #include "complexity.h"
42 #include "internal_macros.h"
46 #include "statistics.h"
47 #include "string_util.h"
53 // For non-dense Range, intermediate values are powers of kRangeMultiplier.
54 static const int kRangeMultiplier
= 8;
55 // The size of a benchmark family determines is the number of inputs to repeat
56 // the benchmark on. If this is "large" then warn the user during configuration.
57 static const size_t kMaxFamilySize
= 100;
62 //=============================================================================//
64 //=============================================================================//
66 // Class for managing registered benchmarks. Note that each registered
67 // benchmark identifies a family of related benchmarks to run.
68 class BenchmarkFamilies
{
70 static BenchmarkFamilies
* GetInstance();
72 // Registers a benchmark family and returns the index assigned to it.
73 size_t AddBenchmark(std::unique_ptr
<Benchmark
> family
);
75 // Clear all registered benchmark families.
76 void ClearBenchmarks();
78 // Extract the list of benchmark instances that match the specified
79 // regular expression.
80 bool FindBenchmarks(std::string re
,
81 std::vector
<Benchmark::Instance
>* benchmarks
,
85 BenchmarkFamilies() {}
87 std::vector
<std::unique_ptr
<Benchmark
>> families_
;
91 BenchmarkFamilies
* BenchmarkFamilies::GetInstance() {
92 static BenchmarkFamilies instance
;
96 size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr
<Benchmark
> family
) {
98 size_t index
= families_
.size();
99 families_
.push_back(std::move(family
));
103 void BenchmarkFamilies::ClearBenchmarks() {
106 families_
.shrink_to_fit();
109 bool BenchmarkFamilies::FindBenchmarks(
110 std::string spec
, std::vector
<Benchmark::Instance
>* benchmarks
,
111 std::ostream
* ErrStream
) {
113 auto& Err
= *ErrStream
;
114 // Make regular expression out of command-line flag
115 std::string error_msg
;
117 bool isNegativeFilter
= false;
119 spec
.replace(0, 1, "");
120 isNegativeFilter
= true;
122 if (!re
.Init(spec
, &error_msg
)) {
123 Err
<< "Could not compile benchmark re: " << error_msg
<< std::endl
;
127 // Special list of thread counts to use when none are specified
128 const std::vector
<int> one_thread
= {1};
131 for (std::unique_ptr
<Benchmark
>& family
: families_
) {
132 // Family was deleted or benchmark doesn't match
133 if (!family
) continue;
135 if (family
->ArgsCnt() == -1) {
138 const std::vector
<int>* thread_counts
=
139 (family
->thread_counts_
.empty()
141 : &static_cast<const std::vector
<int>&>(family
->thread_counts_
));
142 const size_t family_size
= family
->args_
.size() * thread_counts
->size();
143 // The benchmark will be run at least 'family_size' different inputs.
144 // If 'family_size' is very large warn the user.
145 if (family_size
> kMaxFamilySize
) {
146 Err
<< "The number of inputs is very large. " << family
->name_
147 << " will be repeated at least " << family_size
<< " times.\n";
149 // reserve in the special case the regex ".", since we know the final
151 if (spec
== ".") benchmarks
->reserve(family_size
);
153 for (auto const& args
: family
->args_
) {
154 for (int num_threads
: *thread_counts
) {
155 Benchmark::Instance instance
;
156 instance
.name
= family
->name_
;
157 instance
.benchmark
= family
.get();
158 instance
.report_mode
= family
->report_mode_
;
160 instance
.time_unit
= family
->time_unit_
;
161 instance
.range_multiplier
= family
->range_multiplier_
;
162 instance
.min_time
= family
->min_time_
;
163 instance
.iterations
= family
->iterations_
;
164 instance
.repetitions
= family
->repetitions_
;
165 instance
.use_real_time
= family
->use_real_time_
;
166 instance
.use_manual_time
= family
->use_manual_time_
;
167 instance
.complexity
= family
->complexity_
;
168 instance
.complexity_lambda
= family
->complexity_lambda_
;
169 instance
.statistics
= &family
->statistics_
;
170 instance
.threads
= num_threads
;
172 // Add arguments to instance name
174 for (auto const& arg
: args
) {
175 instance
.name
+= "/";
177 if (arg_i
< family
->arg_names_
.size()) {
178 const auto& arg_name
= family
->arg_names_
[arg_i
];
179 if (!arg_name
.empty()) {
181 StrFormat("%s:", family
->arg_names_
[arg_i
].c_str());
185 instance
.name
+= StrFormat("%d", arg
);
189 if (!IsZero(family
->min_time_
))
190 instance
.name
+= StrFormat("/min_time:%0.3f", family
->min_time_
);
191 if (family
->iterations_
!= 0)
192 instance
.name
+= StrFormat("/iterations:%d", family
->iterations_
);
193 if (family
->repetitions_
!= 0)
194 instance
.name
+= StrFormat("/repeats:%d", family
->repetitions_
);
196 if (family
->use_manual_time_
) {
197 instance
.name
+= "/manual_time";
198 } else if (family
->use_real_time_
) {
199 instance
.name
+= "/real_time";
202 // Add the number of threads used to the name
203 if (!family
->thread_counts_
.empty()) {
204 instance
.name
+= StrFormat("/threads:%d", instance
.threads
);
207 if ((re
.Match(instance
.name
) && !isNegativeFilter
) ||
208 (!re
.Match(instance
.name
) && isNegativeFilter
)) {
209 instance
.last_benchmark_instance
= (&args
== &family
->args_
.back());
210 benchmarks
->push_back(std::move(instance
));
218 Benchmark
* RegisterBenchmarkInternal(Benchmark
* bench
) {
219 std::unique_ptr
<Benchmark
> bench_ptr(bench
);
220 BenchmarkFamilies
* families
= BenchmarkFamilies::GetInstance();
221 families
->AddBenchmark(std::move(bench_ptr
));
225 // FIXME: This function is a hack so that benchmark.cc can access
226 // `BenchmarkFamilies`
227 bool FindBenchmarksInternal(const std::string
& re
,
228 std::vector
<Benchmark::Instance
>* benchmarks
,
230 return BenchmarkFamilies::GetInstance()->FindBenchmarks(re
, benchmarks
, Err
);
233 //=============================================================================//
235 //=============================================================================//
237 Benchmark::Benchmark(const char* name
)
239 report_mode_(RM_Unspecified
),
240 time_unit_(kNanosecond
),
241 range_multiplier_(kRangeMultiplier
),
245 use_real_time_(false),
246 use_manual_time_(false),
248 complexity_lambda_(nullptr) {
249 ComputeStatistics("mean", StatisticsMean
);
250 ComputeStatistics("median", StatisticsMedian
);
251 ComputeStatistics("stddev", StatisticsStdDev
);
254 Benchmark::~Benchmark() {}
256 Benchmark
* Benchmark::Arg(int64_t x
) {
257 CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
258 args_
.push_back({x
});
262 Benchmark
* Benchmark::Unit(TimeUnit unit
) {
267 Benchmark
* Benchmark::Range(int64_t start
, int64_t limit
) {
268 CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
269 std::vector
<int64_t> arglist
;
270 AddRange(&arglist
, start
, limit
, range_multiplier_
);
272 for (int64_t i
: arglist
) {
273 args_
.push_back({i
});
278 Benchmark
* Benchmark::Ranges(
279 const std::vector
<std::pair
<int64_t, int64_t>>& ranges
) {
280 CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(ranges
.size()));
281 std::vector
<std::vector
<int64_t>> arglists(ranges
.size());
282 std::size_t total
= 1;
283 for (std::size_t i
= 0; i
< ranges
.size(); i
++) {
284 AddRange(&arglists
[i
], ranges
[i
].first
, ranges
[i
].second
,
286 total
*= arglists
[i
].size();
289 std::vector
<std::size_t> ctr(arglists
.size(), 0);
291 for (std::size_t i
= 0; i
< total
; i
++) {
292 std::vector
<int64_t> tmp
;
293 tmp
.reserve(arglists
.size());
295 for (std::size_t j
= 0; j
< arglists
.size(); j
++) {
296 tmp
.push_back(arglists
[j
].at(ctr
[j
]));
299 args_
.push_back(std::move(tmp
));
301 for (std::size_t j
= 0; j
< arglists
.size(); j
++) {
302 if (ctr
[j
] + 1 < arglists
[j
].size()) {
312 Benchmark
* Benchmark::ArgName(const std::string
& name
) {
313 CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
318 Benchmark
* Benchmark::ArgNames(const std::vector
<std::string
>& names
) {
319 CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(names
.size()));
324 Benchmark
* Benchmark::DenseRange(int64_t start
, int64_t limit
, int step
) {
325 CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
327 CHECK_LE(start
, limit
);
328 for (int64_t arg
= start
; arg
<= limit
; arg
+= step
) {
329 args_
.push_back({arg
});
334 Benchmark
* Benchmark::Args(const std::vector
<int64_t>& args
) {
335 CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(args
.size()));
336 args_
.push_back(args
);
340 Benchmark
* Benchmark::Apply(void (*custom_arguments
)(Benchmark
* benchmark
)) {
341 custom_arguments(this);
345 Benchmark
* Benchmark::RangeMultiplier(int multiplier
) {
346 CHECK(multiplier
> 1);
347 range_multiplier_
= multiplier
;
351 Benchmark
* Benchmark::MinTime(double t
) {
353 CHECK(iterations_
== 0);
358 Benchmark
* Benchmark::Iterations(size_t n
) {
360 CHECK(IsZero(min_time_
));
365 Benchmark
* Benchmark::Repetitions(int n
) {
371 Benchmark
* Benchmark::ReportAggregatesOnly(bool value
) {
372 report_mode_
= value
? RM_ReportAggregatesOnly
: RM_Default
;
376 Benchmark
* Benchmark::UseRealTime() {
377 CHECK(!use_manual_time_
)
378 << "Cannot set UseRealTime and UseManualTime simultaneously.";
379 use_real_time_
= true;
383 Benchmark
* Benchmark::UseManualTime() {
384 CHECK(!use_real_time_
)
385 << "Cannot set UseRealTime and UseManualTime simultaneously.";
386 use_manual_time_
= true;
390 Benchmark
* Benchmark::Complexity(BigO complexity
) {
391 complexity_
= complexity
;
395 Benchmark
* Benchmark::Complexity(BigOFunc
* complexity
) {
396 complexity_lambda_
= complexity
;
397 complexity_
= oLambda
;
401 Benchmark
* Benchmark::ComputeStatistics(std::string name
,
402 StatisticsFunc
* statistics
) {
403 statistics_
.emplace_back(name
, statistics
);
407 Benchmark
* Benchmark::Threads(int t
) {
409 thread_counts_
.push_back(t
);
413 Benchmark
* Benchmark::ThreadRange(int min_threads
, int max_threads
) {
414 CHECK_GT(min_threads
, 0);
415 CHECK_GE(max_threads
, min_threads
);
417 AddRange(&thread_counts_
, min_threads
, max_threads
, 2);
421 Benchmark
* Benchmark::DenseThreadRange(int min_threads
, int max_threads
,
423 CHECK_GT(min_threads
, 0);
424 CHECK_GE(max_threads
, min_threads
);
427 for (auto i
= min_threads
; i
< max_threads
; i
+= stride
) {
428 thread_counts_
.push_back(i
);
430 thread_counts_
.push_back(max_threads
);
434 Benchmark
* Benchmark::ThreadPerCpu() {
435 thread_counts_
.push_back(CPUInfo::Get().num_cpus
);
439 void Benchmark::SetName(const char* name
) { name_
= name
; }
441 int Benchmark::ArgsCnt() const {
443 if (arg_names_
.empty()) return -1;
444 return static_cast<int>(arg_names_
.size());
446 return static_cast<int>(args_
.front().size());
449 //=============================================================================//
451 //=============================================================================//
453 void FunctionBenchmark::Run(State
& st
) { func_(st
); }
455 } // end namespace internal
457 void ClearRegisteredBenchmarks() {
458 internal::BenchmarkFamilies::GetInstance()->ClearBenchmarks();
461 } // end namespace benchmark