1 // Copyright (c) 2015-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #include <bench/bench.h>
6 #include <bench/perf.h>
12 benchmark::BenchRunner::BenchmarkMap
&benchmark::BenchRunner::benchmarks() {
13 static std::map
<std::string
, benchmark::BenchFunction
> benchmarks_map
;
14 return benchmarks_map
;
17 benchmark::BenchRunner::BenchRunner(std::string name
, benchmark::BenchFunction func
)
19 benchmarks().insert(std::make_pair(name
, func
));
23 benchmark::BenchRunner::RunAll(benchmark::duration elapsedTimeForOne
)
26 if (std::ratio_less_equal
<benchmark::clock::period
, std::micro
>::value
) {
27 std::cerr
<< "WARNING: Clock precision is worse than microsecond - benchmarks may be less accurate!\n";
29 std::cout
<< "#Benchmark" << "," << "count" << "," << "min(ns)" << "," << "max(ns)" << "," << "average(ns)" << ","
30 << "min_cycles" << "," << "max_cycles" << "," << "average_cycles" << "\n";
32 for (const auto &p
: benchmarks()) {
33 State
state(p
.first
, elapsedTimeForOne
);
39 bool benchmark::State::KeepRunning()
41 if (count
& countMask
) {
49 lastTime
= beginTime
= now
= clock::now();
50 lastCycles
= beginCycles
= nowCycles
= perf_cpucycles();
54 auto elapsed
= now
- lastTime
;
55 auto elapsedOne
= elapsed
/ (countMask
+ 1);
56 if (elapsedOne
< minTime
) minTime
= elapsedOne
;
57 if (elapsedOne
> maxTime
) maxTime
= elapsedOne
;
59 // We only use relative values, so don't have to handle 64-bit wrap-around specially
60 nowCycles
= perf_cpucycles();
61 uint64_t elapsedOneCycles
= (nowCycles
- lastCycles
) / (countMask
+ 1);
62 if (elapsedOneCycles
< minCycles
) minCycles
= elapsedOneCycles
;
63 if (elapsedOneCycles
> maxCycles
) maxCycles
= elapsedOneCycles
;
65 if (elapsed
*128 < maxElapsed
) {
66 // If the execution was much too fast (1/128th of maxElapsed), increase the count mask by 8x and restart timing.
67 // The restart avoids including the overhead of this code in the measurement.
68 countMask
= ((countMask
<<3)|7) & ((1LL<<60)-1);
70 minTime
= duration::max();
71 maxTime
= duration::zero();
72 minCycles
= std::numeric_limits
<uint64_t>::max();
73 maxCycles
= std::numeric_limits
<uint64_t>::min();
76 if (elapsed
*16 < maxElapsed
) {
77 uint64_t newCountMask
= ((countMask
<<1)|1) & ((1LL<<60)-1);
78 if ((count
& newCountMask
)==0) {
79 countMask
= newCountMask
;
84 lastCycles
= nowCycles
;
87 if (now
- beginTime
< maxElapsed
) return true; // Keep going
91 assert(count
!= 0 && "count == 0 => (now == 0 && beginTime == 0) => return above");
94 // Duration casts are only necessary here because hardware with sub-nanosecond clocks
95 // will lose precision.
96 int64_t min_elapsed
= std::chrono::duration_cast
<std::chrono::nanoseconds
>(minTime
).count();
97 int64_t max_elapsed
= std::chrono::duration_cast
<std::chrono::nanoseconds
>(maxTime
).count();
98 int64_t avg_elapsed
= std::chrono::duration_cast
<std::chrono::nanoseconds
>((now
-beginTime
)/count
).count();
99 int64_t averageCycles
= (nowCycles
-beginCycles
)/count
;
100 std::cout
<< std::fixed
<< std::setprecision(15) << name
<< "," << count
<< "," << min_elapsed
<< "," << max_elapsed
<< "," << avg_elapsed
<< ","
101 << minCycles
<< "," << maxCycles
<< "," << averageCycles
<< "\n";
102 std::cout
.copyfmt(std::ios(nullptr));