Skip to content

Commit

Permalink
adds benchmarks and fixes link issues
Browse files Browse the repository at this point in the history
  • Loading branch information
universenox committed Jul 7, 2019
1 parent 002a0e0 commit e2a3632
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 115 deletions.
1 change: 0 additions & 1 deletion CMakeLists.txt
Expand Up @@ -25,7 +25,6 @@ include_directories(include external/include ${Boost_INCLUDE_DIRS})
# add Boost.Real as a 'linkable' target
add_library(Boost.Real INTERFACE)


#Library Headers
add_executable(Boost.Real_headers include)
set_target_properties(Boost.Real_headers PROPERTIES
Expand Down
33 changes: 24 additions & 9 deletions bench/CMakeLists.txt
Expand Up @@ -2,18 +2,33 @@ set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Suppressing benchmark's tests" FORC

add_subdirectory(benchmark)

# remember to add src's here
set(benchSrcs
operation_tree_bench.cpp
main_bench.cpp
)
FILE(GLOB BenchSources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *_bench.cpp)

# NOTE: main-bench (to run all benchmarks)
# to run a subset of benchmarks, use:
# ./main_bench --benchmark_filter=<regex>
add_executable(main_bench ${benchSrcs})
target_include_directories(main_bench
# ./main_bench --benchmark_filter=<regex>

foreach(benchSrc ${BenchSources})
get_filename_component(benchName ${benchSrc} NAME_WE)
add_executable(${benchName} main-bench.cpp ${benchSrc})
target_include_directories(${benchName}
PRIVATE ./include
PUBLIC ./benchmark/include
)
target_link_libraries(${benchName}
PUBLIC Boost.Real
PUBLIC benchmark
)
endforeach(benchSrc)

add_executable(main-bench main-bench.cpp ${BenchSources})
target_include_directories(main-bench
PRIVATE ./include
PUBLIC ./benchmark/include
)
target_link_libraries(main_bench
target_link_libraries(main-bench
PUBLIC Boost.Real
PUBLIC benchmark
)

# TODO: add a target to run all benches and create reports
42 changes: 29 additions & 13 deletions bench/include/benchmark_helpers.hpp
@@ -1,17 +1,33 @@
#include <iostream>
#ifndef BOOST_REAL_BENCHMARK_HELPERS_HPP
#define BOOST_REAL_BENCHMARK_HELPERS_HPP

#include <real/real.hpp>

class NullBuffer : public std::streambuf
{
public:
int overflow(int c) { return c; }
};
constexpr void realOperationEq(boost::real::real& lhs, boost::real::real& rhs,
boost::real::OPERATION op) {
switch (op) {
case boost::real::OPERATION::ADDITION:
lhs += rhs;
break;
case boost::real::OPERATION::SUBTRACTION:
lhs -= rhs;
break;
case boost::real::OPERATION::MULTIPLICATION:
lhs *= rhs;
break;
}
}

class NullStream: public std::ostream
{
public:
NullStream() : std::ostream(&sb) {}
enum class Comparison {greater_than, less_than, equals};
constexpr bool realComp(boost::real::real& lhs,boost::real::real& rhs, Comparison comp) {
switch (comp) {
case (Comparison::greater_than):
return lhs > rhs;
case (Comparison::less_than):
return lhs < rhs;
case(Comparison::equals):
return lhs==rhs;
}
}

private:
NullBuffer sb;
};
#endif // BOOST_REAL_BENCHMARK_HELPERS_HPP
8 changes: 8 additions & 0 deletions bench/main-bench.cpp
@@ -0,0 +1,8 @@
#include <benchmark/benchmark.h>
#include <real/real.hpp>

// ensure this is >= to MAX_NUM_DIGITS_XX for all benchmarks, else we will get
// a precision error and the benchmarks will not be meaningful.
std::optional<unsigned int> boost::real::const_precision_iterator::maximum_precision = 10000;

BENCHMARK_MAIN();
7 changes: 0 additions & 7 deletions bench/main_bench.cpp

This file was deleted.

52 changes: 0 additions & 52 deletions bench/operation_tree_bench.cpp

This file was deleted.

67 changes: 67 additions & 0 deletions bench/real_construction_bench.cpp
@@ -0,0 +1,67 @@
#include <benchmark/benchmark.h>
#include <benchmark_helpers.hpp>

/** benchmarks the construction of a real number
* for some varying parameter
* (number of tree nodes, or number of digits)
*/

const int MIN_TREE_NODES = 10;
const int MAX_TREE_NODES = 10000;
const int MULTIPLIER_TC = 10; // for range evaluation of tree construction benchmarks
/// benchmarks the construction speed of doing a op= b, n times, where n is the set of powers of
/// MULTIPLIER_TC between MIN_TREE_NODES and MAX_TREE_NODES
void BM_RealOperationTreeConstruction(benchmark::State& state, boost::real::OPERATION op) {
for (auto i : state) {
boost::real::real a ("1234567891");
boost::real::real b ("9876532198");

// We keep the precision constant here because in constructing the *= tree, we would get way more digits
// than in +=, -= trees. This should make the benchmarks more meaningful
a.set_maximum_precision(10);

for (int i = 0; i < state.range(0); i++)
realOperationEq(a,b,op);

state.SetComplexityN(state.range(0));
}
}

// these benchmark the operation tree constructors for each operation type.
/// @TODO: add division bench
BENCHMARK_CAPTURE(BM_RealOperationTreeConstruction, addition, boost::real::OPERATION(boost::real::OPERATION::ADDITION))
->RangeMultiplier(MULTIPLIER_TC)->Range(MIN_TREE_NODES ,MAX_TREE_NODES)->Unit(benchmark::kMillisecond)
->Complexity();

BENCHMARK_CAPTURE(BM_RealOperationTreeConstruction, subtraction, boost::real::OPERATION(boost::real::OPERATION::SUBTRACTION))
->RangeMultiplier(MULTIPLIER_TC)->Range(MIN_TREE_NODES ,MAX_TREE_NODES)->Unit(benchmark::kMillisecond)
->Complexity();

BENCHMARK_CAPTURE(BM_RealOperationTreeConstruction, multiplication, boost::real::OPERATION(boost::real::OPERATION::MULTIPLICATION))
->RangeMultiplier(MULTIPLIER_TC)->Range(MIN_TREE_NODES ,MAX_TREE_NODES)->Unit(benchmark::kMillisecond)
->Complexity();

const int MIN_NUM_DIGITS_EC = 10;
const int MAX_NUM_DIGITS_EC = 10000;
const int MULTIPLIER_EC = 10; // for range evaluation of explicit construction benchmarks

/// benchmarks real explicit's string constructor for a varying number of digits
void BM_RealExplicitConstruction_String(benchmark::State& state) {
for (auto i : state) {
state.PauseTiming(); // construct a string representing a number of n digits
std::string number;

for (int i = 0; i < state.range(0); i++) {
number.push_back('1');
}
state.ResumeTiming();

boost::real::real a(number);
state.SetComplexityN(state.range(0));
}
}
BENCHMARK(BM_RealExplicitConstruction_String)
->RangeMultiplier(MULTIPLIER_EC)->Range(MIN_NUM_DIGITS_EC,MAX_NUM_DIGITS_EC)->Unit(benchmark::kMillisecond)
->Complexity();

// benchmarks for real_algorithm construction seem unnecessary because there's not much that goes on in it
111 changes: 111 additions & 0 deletions bench/real_op_evaluation_bench.cpp
@@ -0,0 +1,111 @@
#include <benchmark/benchmark.h>
#include <benchmark_helpers.hpp>

const int MIN_TREE_NODES = 10;
const int MAX_TREE_NODES = 10000;
const int MULTIPLIER_TE = 10; // for range evaluation of tree evaluation benchmarks

/// benchmarks the evaluation speed of doing a op= b, n times, where n is the set of powers of
/// MULTIPLIER_TE between MIN_TREE_NODES and MAX_TREE_NODES
void BM_RealOperationTreeEvaluation(benchmark::State& state, boost::real::OPERATION op) {
for (auto i : state) {
boost::real::real a ("12");
boost::real::real b ("34");

state.PauseTiming();
for (int i = 0; i < state.range(0); i++) {
realOperationEq(a,b,op);
}
state.ResumeTiming();

a.get_real_itr().cend(); // force evaluation
state.SetComplexityN(state.range(0));
}
}

/// @TODO: add division.
BENCHMARK_CAPTURE(BM_RealOperationTreeEvaluation, addition, boost::real::OPERATION(boost::real::OPERATION::ADDITION))
->RangeMultiplier(MULTIPLIER_TE)->Range(MIN_TREE_NODES ,MAX_TREE_NODES)->Unit(benchmark::kMillisecond)
->Complexity();

BENCHMARK_CAPTURE(BM_RealOperationTreeEvaluation, subtraction, boost::real::OPERATION(boost::real::OPERATION::SUBTRACTION))
->RangeMultiplier(MULTIPLIER_TE)->Range(MIN_TREE_NODES ,MAX_TREE_NODES)->Unit(benchmark::kMillisecond)
->Complexity();

BENCHMARK_CAPTURE(BM_RealOperationTreeEvaluation, multiplication, boost::real::OPERATION(boost::real::OPERATION::MULTIPLICATION))
->RangeMultiplier(MULTIPLIER_TE)->Range(MIN_TREE_NODES ,MAX_TREE_NODES)->Unit(benchmark::kMillisecond)
->Complexity();


const int MIN_NUM_DIGITS = 1000;
const int MAX_NUM_DIGITS = 10000;
const int MULTIPLIER_OE = 6;

/// benchmarks a op= b, where a, b, have n digits, where n is the set of powers of
/// MULTIPLIER_OE, between MIN_NUM_DIGITS and MAX_NUM_DIGITS
void BM_RealOperationEvaluation(benchmark::State& state, boost::real::OPERATION op) {
for (auto i : state) {
state.PauseTiming(); // construct a, b
std::string tmp;
for (int i = 0; i < state.range(0); i++) {
tmp.push_back('2');
}
boost::real::real a(tmp);

tmp.clear();
for (int i = 0; i < state.range(0); i++) {
tmp.push_back('3');
}
boost::real::real b(tmp);
realOperationEq(a,b,op);
state.ResumeTiming();

a.get_real_itr().cend(); // force evaluation
state.SetComplexityN(state.range(0));
}
}

///@TODO: add division
// The BM_RealOperationEvaluation operations are much faster, so these use nanoseconds in the result.
BENCHMARK_CAPTURE(BM_RealOperationEvaluation, addition, boost::real::OPERATION(boost::real::OPERATION::ADDITION))
->RangeMultiplier(MULTIPLIER_OE)->Range(MIN_NUM_DIGITS,MAX_NUM_DIGITS)
->Complexity();

BENCHMARK_CAPTURE(BM_RealOperationEvaluation, subtraction, boost::real::OPERATION(boost::real::OPERATION::SUBTRACTION))
->RangeMultiplier(MULTIPLIER_OE)->Range(MIN_NUM_DIGITS,MAX_NUM_DIGITS)
->Complexity();

BENCHMARK_CAPTURE(BM_RealOperationEvaluation, multiplication, boost::real::OPERATION(boost::real::OPERATION::MULTIPLICATION))
->RangeMultiplier(MULTIPLIER_OE)->Range(MIN_NUM_DIGITS,MAX_NUM_DIGITS)
->Complexity();


/// benchmarks operator> operator< and operator== for numbers a, b, where a == b, with n digits
void BM_RealComparisonEvaluation(benchmark::State& state, Comparison comp) {
for (auto i : state) {
state.PauseTiming(); // construct a, b
std::string tmp;
for (int i = 0; i < state.range(0); i++) { // we compare 111...1 and 111..1
tmp.push_back('1');
}
boost::real::real a(tmp);
boost::real::real b(tmp);

state.ResumeTiming();

bool boo = realComp(a,b,comp); // evaluation
state.SetComplexityN(state.range(0));
}
}

BENCHMARK_CAPTURE(BM_RealComparisonEvaluation, less_than, Comparison::less_than)
->RangeMultiplier(MULTIPLIER_OE)->Range(MIN_NUM_DIGITS,MAX_NUM_DIGITS)->Unit(benchmark::kMillisecond)
->Complexity();

BENCHMARK_CAPTURE(BM_RealComparisonEvaluation, greater_than, Comparison::greater_than)
->RangeMultiplier(MULTIPLIER_OE)->Range(MIN_NUM_DIGITS,MAX_NUM_DIGITS)->Unit(benchmark::kMillisecond)
->Complexity();

BENCHMARK_CAPTURE(BM_RealComparisonEvaluation, equals, Comparison::equals)
->RangeMultiplier(MULTIPLIER_OE)->Range(MIN_NUM_DIGITS,MAX_NUM_DIGITS)->Unit(benchmark::kMillisecond)
->Complexity();
8 changes: 4 additions & 4 deletions include/real/const_precision_iterator.hpp
Expand Up @@ -126,7 +126,7 @@ namespace boost {


// fwd decl'd. Definition found in real_data.hpp
void update_operation_boundaries(real_operation &ro);
inline void update_operation_boundaries(real_operation &ro);

/**
* @brief Constructor for the least precise precision iterator
Expand Down Expand Up @@ -182,7 +182,7 @@ namespace boost {
}

// fwd decl, defined in real_data.hpp
void init_operation_itr(real_operation &ro, bool cend);
inline void init_operation_itr(real_operation &ro, bool cend);

/**
* @brief Constructor for max_precision precision iterator, from real_number
Expand Down Expand Up @@ -234,7 +234,7 @@ namespace boost {
}

// fwd decl, defined in real_data.hpp
void operation_iterate(real_operation &ro);
inline void operation_iterate(real_operation &ro);

/**
* @brief It recalculates the approximation interval boundaries increasing the used
Expand All @@ -258,7 +258,7 @@ namespace boost {
}

// fwd decl, defined in real_data.hpp
void operation_iterate_n_times(real_operation &ro, int n);
inline void operation_iterate_n_times(real_operation &ro, int n);

void iterate_n_times(int n) {
std::visit( overloaded { // perform operation on whatever is held in variant
Expand Down

0 comments on commit e2a3632

Please sign in to comment.