Skip to content

Commit 4aebb60

Browse files
committed
Simple benchmarking framework
- backports bitcoin/bitcoin@535ed92 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
1 parent 73d26f2 commit 4aebb60

File tree

8 files changed

+216
-1
lines changed

8 files changed

+216
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ src/pivx
1111
src/pivxd
1212
src/pivx-cli
1313
src/pivx-tx
14+
src/bench/bench_pivx
1415
src/test/test_pivx
1516
src/qt/test/test_pivx-qt
1617

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ AC_ARG_ENABLE(gui-tests,
132132
AC_ARG_ENABLE(bench,
133133
AS_HELP_STRING([--disable-bench],[do not compile benchmarks (default is to compile)]),
134134
[use_bench=$enableval],
135-
[use_bench=no])
135+
[use_bench=yes])
136136

137137
AC_ARG_ENABLE([extended-functional-tests],
138138
AS_HELP_STRING([--enable-extended-functional-tests],[enable expensive functional tests when using lcov (default no)]),

src/Makefile.am

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,10 @@ if ENABLE_TESTS
621621
include Makefile.test.include
622622
endif
623623

624+
if ENABLE_BENCH
625+
include Makefile.bench.include
626+
endif
627+
624628
if ENABLE_QT
625629
include Makefile.qt.include
626630
endif

src/Makefile.bench.include

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

src/bench/MilliSleep.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+
static void Sleep100ms(benchmark::State& state)
10+
{
11+
while (state.KeepRunning()) {
12+
MilliSleep(100);
13+
}
14+
}
15+
16+
BENCHMARK(Sleep100ms);

src/bench/bench.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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 = gettimedouble();
40+
if (count == 0) {
41+
beginTime = now;
42+
}
43+
else {
44+
double elapsedOne = now - lastTime;
45+
if (elapsedOne < minTime) minTime = elapsedOne;
46+
if (elapsedOne > maxTime) maxTime = elapsedOne;
47+
}
48+
lastTime = now;
49+
++count;
50+
51+
if (now - beginTime < maxElapsed) return true; // Keep going
52+
53+
--count;
54+
55+
// Output results
56+
double average = (now-beginTime)/count;
57+
std::cout << name << "," << count << "," << minTime << "," << maxTime << "," << average << "\n";
58+
59+
return false;
60+
}

src/bench/bench.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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+
static void CODE_TO_TIME(benchmark::State& state)
16+
{
17+
... do any setup needed...
18+
while (state.KeepRunning()) {
19+
... do stuff you want to time...
20+
}
21+
... do any cleanup needed...
22+
}
23+
BENCHMARK(CODE_TO_TIME);
24+
*/
25+
26+
27+
#include <boost/function.hpp>
28+
#include <boost/preprocessor/cat.hpp>
29+
#include <boost/preprocessor/stringize.hpp>
30+
#include <map>
31+
#include <string>
32+
33+
namespace benchmark {
34+
35+
class State {
36+
std::string name;
37+
double maxElapsed;
38+
double beginTime;
39+
double lastTime, minTime, maxTime;
40+
int64_t count;
41+
public:
42+
State(std::string _name, double _maxElapsed) : name(_name), maxElapsed(_maxElapsed), count(0) {
43+
minTime = std::numeric_limits<double>::max();
44+
maxTime = std::numeric_limits<double>::min();
45+
}
46+
bool KeepRunning();
47+
};
48+
49+
typedef boost::function<void(State&)> BenchFunction;
50+
51+
class BenchRunner
52+
{
53+
static std::map<std::string, BenchFunction> benchmarks;
54+
55+
public:
56+
BenchRunner(std::string name, BenchFunction func);
57+
58+
static void RunAll(double elapsedTimeForOne=1.0);
59+
};
60+
}
61+
62+
// BENCHMARK(foo) expands to: benchmark::BenchRunner bench_11foo("foo", foo);
63+
#define BENCHMARK(n) \
64+
benchmark::BenchRunner BOOST_PP_CAT(bench_, BOOST_PP_CAT(__LINE__, n))(BOOST_PP_STRINGIZE(n), n);
65+
66+
#endif // BITCOIN_BENCH_H

src/bench/bench_pivx.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) 2015-2020 The Bitcoin Core developers
2+
// Copyright (c) 2020 The PIVX developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
#include "bench.h"
7+
8+
#include "key.h"
9+
#include "main.h"
10+
#include "util.h"
11+
12+
int
13+
main(int argc, char** argv)
14+
{
15+
ECC_Start();
16+
SetupEnvironment();
17+
g_logger->m_print_to_file = false; // don't want to write to debug.log file
18+
19+
benchmark::BenchRunner::RunAll();
20+
21+
ECC_Stop();
22+
}

0 commit comments

Comments
 (0)