Skip to content
Closed
1 change: 0 additions & 1 deletion include/nonius/chronometer.h++
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include <nonius/detail/complete_invoke.h++>
#include <nonius/detail/meta.h++>
#include <nonius/param.h++>
#include <boost/lexical_cast.hpp>

namespace nonius {
namespace detail {
Expand Down
4 changes: 2 additions & 2 deletions include/nonius/configuration.h++
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#define NONIUS_CONFIGURATION_HPP

#include <nonius/param.h++>
#include <boost/optional.hpp>
#include <nonius/detail/optional.h++>
#include <string>
#include <vector>

Expand All @@ -30,7 +30,7 @@ namespace nonius {

struct param_configuration {
parameters map;
boost::optional<run_configuration> run;
optional<run_configuration> run;
};

struct configuration {
Expand Down
1 change: 1 addition & 0 deletions include/nonius/detail/benchmark_function.h++
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <nonius/detail/complete_invoke.h++>
#include <nonius/detail/meta.h++>

#include <cassert>
#include <type_traits>
#include <utility>
#include <memory>
Expand Down
26 changes: 14 additions & 12 deletions include/nonius/detail/cpptempl.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,13 @@
#include <map>
#include <memory>
#include <unordered_map>
#include <boost/lexical_cast.hpp>

#include <ostream>

#include <sstream>
#include <boost/algorithm/string.hpp>

#include <nonius/detail/noexcept.h++>
#include <nonius/detail/string_utils.h++>

namespace cpptempl
{
Expand Down Expand Up @@ -123,7 +122,10 @@ namespace cpptempl
template<> void data_ptr::operator = (const data_map& data);
template<typename T>
void data_ptr::operator = (const T& data) {
std::string data_str = boost::lexical_cast<std::string>(data);
std::stringstream ss;
ss << data;
ss.exceptions(std::ios::failbit);
std::string data_str = ss.str();
this->operator =(data_str);
}

Expand Down Expand Up @@ -384,7 +386,7 @@ namespace cpptempl
// quoted string
if (key[0] == '\"')
{
return make_data(boost::trim_copy_if(key, [](char c){ return c == '"'; }));
return make_data(nonius::trim_copy_if(key, [](char c){ return c == '"'; }));
}
// check for dotted notation, i.e [foo.bar]
size_t index = key.find(".") ;
Expand Down Expand Up @@ -447,7 +449,7 @@ namespace cpptempl
inline TokenFor::TokenFor(std::string expr)
{
std::vector<std::string> elements ;
boost::split(elements, expr, boost::is_space()) ;
nonius::split(elements, expr, nonius::is_space()) ;
if (elements.size() != 4u)
{
throw TemplateException("Invalid syntax in for statement") ;
Expand All @@ -468,8 +470,8 @@ namespace cpptempl
for (size_t i = 0 ; i < items.size() ; ++i)
{
data_map loop ;
loop["index"] = make_data(boost::lexical_cast<std::string>(i+1)) ;
loop["index0"] = make_data(boost::lexical_cast<std::string>(i)) ;
loop["index"] = make_data(std::to_string(i+1)) ;
loop["index0"] = make_data(std::to_string(i)) ;
data["loop"] = make_data(loop);
data[m_val] = items[i] ;
for(size_t j = 0 ; j < m_children.size() ; ++j)
Expand Down Expand Up @@ -509,7 +511,7 @@ namespace cpptempl
inline bool TokenIf::is_true( std::string expr, data_map &data )
{
std::vector<std::string> elements ;
boost::split(elements, expr, boost::is_space()) ;
nonius::split(elements, expr, nonius::is_space()) ;

if (elements[1] == "not")
{
Expand Down Expand Up @@ -634,19 +636,19 @@ namespace cpptempl
pos = text.find("}") ;
if (pos != std::string::npos)
{
std::string expression = boost::trim_copy(text.substr(1, pos-2)) ;
std::string expression = nonius::trim_copy(text.substr(1, pos-2)) ;
text = text.substr(pos+1) ;
if (boost::starts_with(expression, "for"))
if (nonius::starts_with(expression, "for"))
{
tokens.push_back(token_ptr (new TokenFor(expression))) ;
}
else if (boost::starts_with(expression, "if"))
else if (nonius::starts_with(expression, "if"))
{
tokens.push_back(token_ptr (new TokenIf(expression))) ;
}
else
{
tokens.push_back(token_ptr (new TokenEnd(boost::trim_copy(expression)))) ;
tokens.push_back(token_ptr (new TokenEnd(nonius::trim_copy(expression)))) ;
}
}
}
Expand Down
132 changes: 132 additions & 0 deletions include/nonius/detail/optional.h++
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Nonius - C++ benchmarking tool
//
// Written in 2014- by the nonius contributors <nonius@rmf.io>
//
// To the extent possible under law, the author(s) have dedicated all copyright and related
// and neighboring rights to this software to the public domain worldwide. This software is
// distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>

// Simple optional type implementation partially based on C++17 interface

#ifndef NONIUS_OPTIONAL_HPP
#define NONIUS_OPTIONAL_HPP

#include <type_traits>
#include <cassert>

namespace nonius {
struct nullopt_t {
constexpr nullopt_t(int) {}
};
constexpr nullopt_t nullopt() { return {0}; }

template <typename T>
class optional {
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage;
bool initialized;

T& get_impl() {
assert(initialized);
return *reinterpret_cast<T*>(&storage);
}
T const& get_impl() const {
assert(initialized);
return *reinterpret_cast<T const*>(&storage);
}

void construct(T const& value) {
assert(!initialized);
new (&storage) T(value);
initialized = true;
}
void construct(T&& value) {
assert(!initialized);
new (&storage) T(std::move(value));
initialized = true;
}
void destroy() {
if (initialized) {
get_impl().~T();
initialized = false;
}
}
optional<T>& assign(T const& value) {
destroy();
construct(value);
return *this;
}
optional<T>& assign(T&& value) {
destroy();
construct(std::move(value));
return *this;
}
public:
constexpr optional() : initialized(false) {}
constexpr optional(nullopt_t) : initialized(false) {}
optional(optional<T> const& rhs) : initialized(false) {
if (rhs.initialized) {
construct(rhs.get_impl());
}
}
optional(optional<T>&& rhs) : initialized(false) {
if (rhs.initialized) {
construct(std::move(rhs.get_impl()));
}
}
optional(T const& value) : initialized(false) {
construct(value);
}
optional(T&& value) : initialized(false) {
construct(std::move(value));
}
~optional() {
destroy();
}

optional<T>& operator=(optional<T> const& rhs) {
destroy();
if (rhs.initialized) {
construct(rhs.get_impl());
}
return *this;
}
optional<T>& operator=(optional<T> && rhs) {
destroy();
if (rhs.initialized) {
construct(std::move(rhs.get_impl()));
}
return *this;
}
optional<T>& operator=(T const& rhs) {
destroy();
construct(rhs);
return *this;
}
optional<T>& operator=(T&& rhs) {
destroy();
construct(std::move(rhs));
return *this;
}
optional<T>& operator=(nullopt_t) {
destroy();
return *this;
}

constexpr T const* operator->() const { return &get_impl(); }
T* operator->() { return &get_impl(); }

constexpr T const& operator*() const { return get_impl(); }
T& operator*() { return get_impl(); }

constexpr bool has_value() const { return initialized; }
constexpr explicit operator bool() const { return initialized; }

constexpr bool operator!() const { return !initialized; }
};
} // namespace nonius

#endif // NONIUS_OPTIONAL_HPP

113 changes: 106 additions & 7 deletions include/nonius/detail/stats.h++
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@
#include <nonius/estimate.h++>
#include <nonius/outlier_classification.h++>

#include <boost/math/distributions/normal.hpp>

#include <algorithm>
#include <cassert>
#include <functional>
#include <iterator>
#include <vector>
Expand Down Expand Up @@ -124,10 +123,109 @@ namespace nonius {
return results;
}

inline double normal_cdf(double x) {
return std::erfc(-x / std::sqrt(2.0)) / 2.0;
}

inline double erf_inv(double x) {
// Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2
double w, p;

w = - log((1.0-x)*(1.0+x));

if (w < 6.250000) {
w = w - 3.125000;
p = -3.6444120640178196996e-21;
p = -1.685059138182016589e-19 + p*w;
p = 1.2858480715256400167e-18 + p*w;
p = 1.115787767802518096e-17 + p*w;
p = -1.333171662854620906e-16 + p*w;
p = 2.0972767875968561637e-17 + p*w;
p = 6.6376381343583238325e-15 + p*w;
p = -4.0545662729752068639e-14 + p*w;
p = -8.1519341976054721522e-14 + p*w;
p = 2.6335093153082322977e-12 + p*w;
p = -1.2975133253453532498e-11 + p*w;
p = -5.4154120542946279317e-11 + p*w;
p = 1.051212273321532285e-09 + p*w;
p = -4.1126339803469836976e-09 + p*w;
p = -2.9070369957882005086e-08 + p*w;
p = 4.2347877827932403518e-07 + p*w;
p = -1.3654692000834678645e-06 + p*w;
p = -1.3882523362786468719e-05 + p*w;
p = 0.0001867342080340571352 + p*w;
p = -0.00074070253416626697512 + p*w;
p = -0.0060336708714301490533 + p*w;
p = 0.24015818242558961693 + p*w;
p = 1.6536545626831027356 + p*w;
}
else if (w < 16.000000) {
w = sqrt(w) - 3.250000;
p = 2.2137376921775787049e-09;
p = 9.0756561938885390979e-08 + p*w;
p = -2.7517406297064545428e-07 + p*w;
p = 1.8239629214389227755e-08 + p*w;
p = 1.5027403968909827627e-06 + p*w;
p = -4.013867526981545969e-06 + p*w;
p = 2.9234449089955446044e-06 + p*w;
p = 1.2475304481671778723e-05 + p*w;
p = -4.7318229009055733981e-05 + p*w;
p = 6.8284851459573175448e-05 + p*w;
p = 2.4031110387097893999e-05 + p*w;
p = -0.0003550375203628474796 + p*w;
p = 0.00095328937973738049703 + p*w;
p = -0.0016882755560235047313 + p*w;
p = 0.0024914420961078508066 + p*w;
p = -0.0037512085075692412107 + p*w;
p = 0.005370914553590063617 + p*w;
p = 1.0052589676941592334 + p*w;
p = 3.0838856104922207635 + p*w;
}
else {
w = sqrt(w) - 5.000000;
p = -2.7109920616438573243e-11;
p = -2.5556418169965252055e-10 + p*w;
p = 1.5076572693500548083e-09 + p*w;
p = -3.7894654401267369937e-09 + p*w;
p = 7.6157012080783393804e-09 + p*w;
p = -1.4960026627149240478e-08 + p*w;
p = 2.9147953450901080826e-08 + p*w;
p = -6.7711997758452339498e-08 + p*w;
p = 2.2900482228026654717e-07 + p*w;
p = -9.9298272942317002539e-07 + p*w;
p = 4.5260625972231537039e-06 + p*w;
p = -1.9681778105531670567e-05 + p*w;
p = 7.5995277030017761139e-05 + p*w;
p = -0.00021503011930044477347 + p*w;
p = -0.00013871931833623122026 + p*w;
p = 1.0103004648645343977 + p*w;
p = 4.8499064014085844221 + p*w;
}
return p*x;
}

inline double erfc_inv(double x) {
return erf_inv(1.0 - x);
}

inline double normal_quantile(double p) {
static const double ROOT_TWO = std::sqrt(2.0);

double result = 0.0;
assert(p >= 0 && p <= 1);
if (p < 0 || p > 1) {
return result;
}

result = -erfc_inv(2.0 * p);
// result *= normal distribution standard deviation (1.0) * sqrt(2)
result *= /*sd * */ ROOT_TWO;
// result += normal disttribution mean (0)
return result;
}

template <typename Iterator, typename Estimator>
estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) {
namespace bm = boost::math;

auto n_samples = last - first;

double point = estimator(first, last);
Expand All @@ -150,10 +248,11 @@ namespace nonius {
// degenerate case with uniform samples
if(prob_n == 0) return { point, point, point, confidence_level };

double bias = bm::quantile(bm::normal{}, prob_n);
double z1 = bm::quantile(bm::normal{}, (1. - confidence_level) / 2.);
double bias = normal_quantile(prob_n);
double z1 = normal_quantile((1. - confidence_level) / 2.);

auto cumn = [n](double x) -> int { return std::lround(bm::cdf(bm::normal{}, x) * n); };
auto cumn = [n](double x) -> int {
return std::lround(normal_cdf(x) * n); };
auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); };
double b1 = bias + z1;
double b2 = bias - z1;
Expand Down
Loading