mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-27 19:47:30 -03:00
0b1b9148cd
We were saving a div by caching the inverse as a float, but this ended up requiring a int -> float -> int conversion, which takes almost as much time as the difference between float mul and div. There are lots of other more pressing issues with the bench framework which probably require simply removing the adaptive iteration count stuff anyway.
104 lines
3.5 KiB
C++
104 lines
3.5 KiB
C++
// Copyright (c) 2015-2016 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include "bench.h"
|
|
#include "perf.h"
|
|
|
|
#include <assert.h>
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <sys/time.h>
|
|
|
|
benchmark::BenchRunner::BenchmarkMap &benchmark::BenchRunner::benchmarks() {
|
|
static std::map<std::string, benchmark::BenchFunction> benchmarks_map;
|
|
return benchmarks_map;
|
|
}
|
|
|
|
static double gettimedouble(void) {
|
|
struct timeval tv;
|
|
gettimeofday(&tv, nullptr);
|
|
return tv.tv_usec * 0.000001 + tv.tv_sec;
|
|
}
|
|
|
|
benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)
|
|
{
|
|
benchmarks().insert(std::make_pair(name, func));
|
|
}
|
|
|
|
void
|
|
benchmark::BenchRunner::RunAll(double elapsedTimeForOne)
|
|
{
|
|
perf_init();
|
|
std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << ","
|
|
<< "min_cycles" << "," << "max_cycles" << "," << "average_cycles" << "\n";
|
|
|
|
for (const auto &p: benchmarks()) {
|
|
State state(p.first, elapsedTimeForOne);
|
|
p.second(state);
|
|
}
|
|
perf_fini();
|
|
}
|
|
|
|
bool benchmark::State::KeepRunning()
|
|
{
|
|
if (count & countMask) {
|
|
++count;
|
|
return true;
|
|
}
|
|
double now;
|
|
uint64_t nowCycles;
|
|
if (count == 0) {
|
|
lastTime = beginTime = now = gettimedouble();
|
|
lastCycles = beginCycles = nowCycles = perf_cpucycles();
|
|
}
|
|
else {
|
|
now = gettimedouble();
|
|
double elapsed = now - lastTime;
|
|
double elapsedOne = elapsed / (countMask + 1);
|
|
if (elapsedOne < minTime) minTime = elapsedOne;
|
|
if (elapsedOne > maxTime) maxTime = elapsedOne;
|
|
|
|
// We only use relative values, so don't have to handle 64-bit wrap-around specially
|
|
nowCycles = perf_cpucycles();
|
|
uint64_t elapsedOneCycles = (nowCycles - lastCycles) / (countMask + 1);
|
|
if (elapsedOneCycles < minCycles) minCycles = elapsedOneCycles;
|
|
if (elapsedOneCycles > maxCycles) maxCycles = elapsedOneCycles;
|
|
|
|
if (elapsed*128 < maxElapsed) {
|
|
// If the execution was much too fast (1/128th of maxElapsed), increase the count mask by 8x and restart timing.
|
|
// The restart avoids including the overhead of this code in the measurement.
|
|
countMask = ((countMask<<3)|7) & ((1LL<<60)-1);
|
|
count = 0;
|
|
minTime = std::numeric_limits<double>::max();
|
|
maxTime = std::numeric_limits<double>::min();
|
|
minCycles = std::numeric_limits<uint64_t>::max();
|
|
maxCycles = std::numeric_limits<uint64_t>::min();
|
|
return true;
|
|
}
|
|
if (elapsed*16 < maxElapsed) {
|
|
uint64_t newCountMask = ((countMask<<1)|1) & ((1LL<<60)-1);
|
|
if ((count & newCountMask)==0) {
|
|
countMask = newCountMask;
|
|
}
|
|
}
|
|
}
|
|
lastTime = now;
|
|
lastCycles = nowCycles;
|
|
++count;
|
|
|
|
if (now - beginTime < maxElapsed) return true; // Keep going
|
|
|
|
--count;
|
|
|
|
assert(count != 0 && "count == 0 => (now == 0 && beginTime == 0) => return above");
|
|
|
|
// Output results
|
|
double average = (now-beginTime)/count;
|
|
int64_t averageCycles = (nowCycles-beginCycles)/count;
|
|
std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << minTime << "," << maxTime << "," << average << ","
|
|
<< minCycles << "," << maxCycles << "," << averageCycles << "\n";
|
|
std::cout.copyfmt(std::ios(nullptr));
|
|
|
|
return false;
|
|
}
|