From 535ed9223dcb32bf90ead5b2c95052838b780620 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Thu, 24 Sep 2015 13:13:38 -0400 Subject: Simple benchmarking framework Benchmarking framework, loosely based on google's micro-benchmarking library (https://github.com/google/benchmark) Wny not use the Google Benchmark framework? Because adding Even More Dependencies isn't worth it. If we get a dozen or three benchmarks and need nanosecond-accurate timings of threaded code then switching to the full-blown Google Benchmark library should be considered. The benchmark framework is hard-coded to run each benchmark for one wall-clock second, and then spits out .csv-format timing information to stdout. It is left as an exercise for later (or maybe never) to add command-line arguments to specify which benchmark(s) to run, how long to run them for, how to format results, etc etc etc. Again, see the Google Benchmark framework for where that might end up. See src/bench/MilliSleep.cpp for a sanity-test benchmark that just benchmarks 'sleep 100 milliseconds.' To compile and run benchmarks: cd src; make bench Sample output: Benchmark,count,min,max,average Sleep100ms,10,0.101854,0.105059,0.103881 --- src/bench/bench.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/bench/bench.cpp (limited to 'src/bench/bench.cpp') diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp new file mode 100644 index 000000000..572080760 --- /dev/null +++ b/src/bench/bench.cpp @@ -0,0 +1,60 @@ +// Copyright (c) 2015 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 +#include + +using namespace benchmark; + +std::map BenchRunner::benchmarks; + +static double gettimedouble(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_usec * 0.000001 + tv.tv_sec; +} + +BenchRunner::BenchRunner(std::string name, BenchFunction func) +{ + benchmarks.insert(std::make_pair(name, func)); +} + +void +BenchRunner::RunAll(double elapsedTimeForOne) +{ + std::cout << "Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << "\n"; + + for (std::map::iterator it = benchmarks.begin(); + it != benchmarks.end(); ++it) { + + State state(it->first, elapsedTimeForOne); + BenchFunction& func = it->second; + func(state); + } +} + +bool State::KeepRunning() +{ + double now = gettimedouble(); + if (count == 0) { + beginTime = now; + } + else { + double elapsedOne = now - lastTime; + if (elapsedOne < minTime) minTime = elapsedOne; + if (elapsedOne > maxTime) maxTime = elapsedOne; + } + lastTime = now; + ++count; + + if (now - beginTime < maxElapsed) return true; // Keep going + + --count; + + // Output results + double average = (now-beginTime)/count; + std::cout << name << "," << count << "," << minTime << "," << maxTime << "," << average << "\n"; + + return false; +} -- cgit v1.2.3 From 7072c544b52774ac5a22835121e8e2747ad61158 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Tue, 29 Sep 2015 17:17:24 -0400 Subject: Support very-fast-running benchmarks Avoid calling gettimeofday every time through the benchmarking loop, by keeping track of how long each loop takes and doubling the number of iterations done between time checks when they take less than 1/16'th of the total elapsed time. --- src/bench/bench.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src/bench/bench.cpp') diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index 572080760..89c3b0cc2 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -36,14 +36,22 @@ BenchRunner::RunAll(double elapsedTimeForOne) bool State::KeepRunning() { - double now = gettimedouble(); + double now; if (count == 0) { - beginTime = now; + beginTime = now = gettimedouble(); } else { - double elapsedOne = now - lastTime; + // timeCheckCount is used to avoid calling gettime most of the time, + // so benchmarks that run very quickly get consistent results. + if ((count+1)%timeCheckCount != 0) { + ++count; + return true; // keep going + } + now = gettimedouble(); + double elapsedOne = (now - lastTime)/timeCheckCount; if (elapsedOne < minTime) minTime = elapsedOne; if (elapsedOne > maxTime) maxTime = elapsedOne; + if (elapsedOne*timeCheckCount < maxElapsed/16) timeCheckCount *= 2; } lastTime = now; ++count; -- cgit v1.2.3 From 214de7e54c282f7d452d9b628baaa94e6af51727 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Tue, 27 Oct 2015 17:44:13 +0100 Subject: [Trivial] ensure minimal header conventions - ensure header namespaces and end comments are correct - add missing header end comments - ensure minimal formatting (add newlines etc.) --- src/bench/bench.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/bench/bench.cpp') diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index 89c3b0cc2..6ee3cdc27 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -1,7 +1,9 @@ // Copyright (c) 2015 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 #include -- cgit v1.2.3