Skip to content

Commit b7d78fd

Browse files
committed
Merge pull request #6733
7072c54 Support very-fast-running benchmarks (Gavin Andresen) 535ed92 Simple benchmarking framework (Gavin Andresen)
2 parents 66a86a3 + 7072c54 commit b7d78fd

File tree

7 files changed

+250
-0
lines changed

7 files changed

+250
-0
lines changed

Diff for: configure.ac

+6
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ AC_ARG_ENABLE(tests,
9191
[use_tests=$enableval],
9292
[use_tests=yes])
9393

94+
AC_ARG_ENABLE(bench,
95+
AS_HELP_STRING([--enable-bench],[compile benchmarks (default is yes)]),
96+
[use_bench=$enableval],
97+
[use_bench=yes])
98+
9499
AC_ARG_WITH([comparison-tool],
95100
AS_HELP_STRING([--with-comparison-tool],[path to java comparison tool (requires --enable-tests)]),
96101
[use_comparison_tool=$withval],
@@ -876,6 +881,7 @@ AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes])
876881
AM_CONDITIONAL([ENABLE_TESTS],[test x$use_tests = xyes])
877882
AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes])
878883
AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$use_tests$bitcoin_enable_qt_test = xyesyes])
884+
AM_CONDITIONAL([ENABLE_BENCH],[test x$use_bench = xyes])
879885
AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes])
880886
AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes])
881887
AM_CONDITIONAL([USE_COMPARISON_TOOL],[test x$use_comparison_tool != xno])

Diff for: src/Makefile.am

+5
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ endif
6464

6565
bin_PROGRAMS =
6666
TESTS =
67+
BENCHMARKS =
6768

6869
if BUILD_BITCOIND
6970
bin_PROGRAMS += bitcoind
@@ -439,6 +440,10 @@ if ENABLE_TESTS
439440
include Makefile.test.include
440441
endif
441442

443+
if ENABLE_BENCH
444+
include Makefile.bench.include
445+
endif
446+
442447
if ENABLE_QT
443448
include Makefile.qt.include
444449
endif

Diff for: src/Makefile.bench.include

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
bin_PROGRAMS += bench/bench_bitcoin
2+
BENCH_SRCDIR = bench
3+
BENCH_BINARY = bench/bench_bitcoin$(EXEEXT)
4+
5+
6+
bench_bench_bitcoin_SOURCES = \
7+
bench/bench_bitcoin.cpp \
8+
bench/bench.cpp \
9+
bench/bench.h \
10+
bench/Examples.cpp
11+
12+
bench_bench_bitcoin_CPPFLAGS = $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
13+
bench_bench_bitcoin_LDADD = \
14+
$(LIBBITCOIN_SERVER) \
15+
$(LIBBITCOIN_COMMON) \
16+
$(LIBBITCOIN_UNIVALUE) \
17+
$(LIBBITCOIN_UTIL) \
18+
$(LIBBITCOIN_CRYPTO) \
19+
$(LIBLEVELDB) \
20+
$(LIBMEMENV) \
21+
$(LIBSECP256K1)
22+
23+
if ENABLE_ZMQ
24+
bench_bench_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
25+
endif
26+
27+
if ENABLE_WALLET
28+
bench_bench_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
29+
endif
30+
31+
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
32+
bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
33+
34+
35+
CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno
36+
37+
CLEANFILES += $(CLEAN_BITCOIN_BENCH)
38+
39+
bitcoin_bench: $(BENCH_BINARY)
40+
41+
bench: $(BENCH_BINARY) FORCE
42+
$(BENCH_BINARY)
43+
44+
bitcoin_bench_clean : FORCE
45+
rm -f $(CLEAN_BITCOIN_BENCH) $(bench_bench_bitcoin_OBJECTS) $(BENCH_BINARY)

Diff for: src/bench/Examples.cpp

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) 2015 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.
4+
5+
#include "bench.h"
6+
#include "main.h"
7+
#include "utiltime.h"
8+
9+
// Sanity test: this should loop ten times, and
10+
// min/max/average should be close to 100ms.
11+
static void Sleep100ms(benchmark::State& state)
12+
{
13+
while (state.KeepRunning()) {
14+
MilliSleep(100);
15+
}
16+
}
17+
18+
BENCHMARK(Sleep100ms);
19+
20+
// Extremely fast-running benchmark:
21+
#include <math.h>
22+
23+
volatile double sum = 0.0; // volatile, global so not optimized away
24+
25+
static void Trig(benchmark::State& state)
26+
{
27+
double d = 0.01;
28+
while (state.KeepRunning()) {
29+
sum += sin(d);
30+
d += 0.000001;
31+
}
32+
}
33+
34+
BENCHMARK(Trig);

Diff for: src/bench/bench.cpp

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright (c) 2015 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.
4+
#include "bench.h"
5+
#include <iostream>
6+
#include <sys/time.h>
7+
8+
using namespace benchmark;
9+
10+
std::map<std::string, BenchFunction> BenchRunner::benchmarks;
11+
12+
static double gettimedouble(void) {
13+
struct timeval tv;
14+
gettimeofday(&tv, NULL);
15+
return tv.tv_usec * 0.000001 + tv.tv_sec;
16+
}
17+
18+
BenchRunner::BenchRunner(std::string name, BenchFunction func)
19+
{
20+
benchmarks.insert(std::make_pair(name, func));
21+
}
22+
23+
void
24+
BenchRunner::RunAll(double elapsedTimeForOne)
25+
{
26+
std::cout << "Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << "\n";
27+
28+
for (std::map<std::string,BenchFunction>::iterator it = benchmarks.begin();
29+
it != benchmarks.end(); ++it) {
30+
31+
State state(it->first, elapsedTimeForOne);
32+
BenchFunction& func = it->second;
33+
func(state);
34+
}
35+
}
36+
37+
bool State::KeepRunning()
38+
{
39+
double now;
40+
if (count == 0) {
41+
beginTime = now = gettimedouble();
42+
}
43+
else {
44+
// timeCheckCount is used to avoid calling gettime most of the time,
45+
// so benchmarks that run very quickly get consistent results.
46+
if ((count+1)%timeCheckCount != 0) {
47+
++count;
48+
return true; // keep going
49+
}
50+
now = gettimedouble();
51+
double elapsedOne = (now - lastTime)/timeCheckCount;
52+
if (elapsedOne < minTime) minTime = elapsedOne;
53+
if (elapsedOne > maxTime) maxTime = elapsedOne;
54+
if (elapsedOne*timeCheckCount < maxElapsed/16) timeCheckCount *= 2;
55+
}
56+
lastTime = now;
57+
++count;
58+
59+
if (now - beginTime < maxElapsed) return true; // Keep going
60+
61+
--count;
62+
63+
// Output results
64+
double average = (now-beginTime)/count;
65+
std::cout << name << "," << count << "," << minTime << "," << maxTime << "," << average << "\n";
66+
67+
return false;
68+
}

Diff for: src/bench/bench.h

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) 2015 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.
4+
#ifndef BITCOIN_BENCH_H
5+
#define BITCOIN_BENCH_H
6+
7+
// Simple micro-benchmarking framework; API mostly matches a subset of the Google Benchmark
8+
// framework (see https://github.com/google/benchmark)
9+
// Wny not use the Google Benchmark framework? Because adding Yet Another Dependency
10+
// (that uses cmake as its build system and has lots of features we don't need) isn't
11+
// worth it.
12+
13+
/*
14+
* Usage:
15+
16+
static void CODE_TO_TIME(benchmark::State& state)
17+
{
18+
... do any setup needed...
19+
while (state.KeepRunning()) {
20+
... do stuff you want to time...
21+
}
22+
... do any cleanup needed...
23+
}
24+
25+
BENCHMARK(CODE_TO_TIME);
26+
27+
*/
28+
29+
30+
#include <boost/function.hpp>
31+
#include <boost/preprocessor/cat.hpp>
32+
#include <boost/preprocessor/stringize.hpp>
33+
#include <map>
34+
#include <string>
35+
36+
namespace benchmark {
37+
38+
class State {
39+
std::string name;
40+
double maxElapsed;
41+
double beginTime;
42+
double lastTime, minTime, maxTime;
43+
int64_t count;
44+
int64_t timeCheckCount;
45+
public:
46+
State(std::string _name, double _maxElapsed) : name(_name), maxElapsed(_maxElapsed), count(0) {
47+
minTime = std::numeric_limits<double>::max();
48+
maxTime = std::numeric_limits<double>::min();
49+
timeCheckCount = 1;
50+
}
51+
bool KeepRunning();
52+
};
53+
54+
typedef boost::function<void(State&)> BenchFunction;
55+
56+
class BenchRunner
57+
{
58+
static std::map<std::string, BenchFunction> benchmarks;
59+
60+
public:
61+
BenchRunner(std::string name, BenchFunction func);
62+
63+
static void RunAll(double elapsedTimeForOne=1.0);
64+
};
65+
}
66+
67+
// BENCHMARK(foo) expands to: benchmark::BenchRunner bench_11foo("foo", foo);
68+
#define BENCHMARK(n) \
69+
benchmark::BenchRunner BOOST_PP_CAT(bench_, BOOST_PP_CAT(__LINE__, n))(BOOST_PP_STRINGIZE(n), n);
70+
71+
#endif // BITCOIN_BENCH_H

Diff for: src/bench/bench_bitcoin.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) 2015 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.
4+
5+
#include "bench.h"
6+
7+
#include "key.h"
8+
#include "main.h"
9+
#include "util.h"
10+
11+
int
12+
main(int argc, char** argv)
13+
{
14+
ECC_Start();
15+
SetupEnvironment();
16+
fPrintToDebugLog = false; // don't want to write to debug.log file
17+
18+
benchmark::BenchRunner::RunAll();
19+
20+
ECC_Stop();
21+
}

0 commit comments

Comments
 (0)