116 lines
3.0 KiB
C++
116 lines
3.0 KiB
C++
// Copyright John Maddock 2015.
|
|
// Use, modification and distribution are subject to the
|
|
// Boost Software License, Version 1.0. (See accompanying file
|
|
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
#ifndef PERFORMANCE_HPP
|
|
#define PERFORMANCE_HPP
|
|
|
|
#include <boost/math/special_functions/relative_difference.hpp>
|
|
#include <boost/array.hpp>
|
|
#include <boost/chrono.hpp>
|
|
#include <boost/regex.hpp>
|
|
|
|
template <class Array>
|
|
void add_data(const Array& a)
|
|
{
|
|
//
|
|
// This function is called multiple times to merge multiple data sets into one big table:
|
|
//
|
|
for(typename Array::const_iterator i = a.begin(); i != a.end(); ++i)
|
|
{
|
|
data.push_back(std::vector<double>());
|
|
for(typename Array::value_type::const_iterator j = i->begin(); j != i->end(); ++j)
|
|
{
|
|
data.back().push_back(*j);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class Func, class Result>
|
|
void screen_data(Func f, Result r)
|
|
{
|
|
//
|
|
// If any of the implementations being tested produces garbage for one of our
|
|
// test cases (or else if we test a domain they don't support), then we remove that
|
|
// row from the table. This allows us to only test a common supported sub-set for performance:
|
|
//
|
|
for(std::vector<std::vector<double> >::size_type row = 0; row < data.size(); ++row)
|
|
{
|
|
try
|
|
{
|
|
double computed = f(data[row]);
|
|
double expected = r(data[row]);
|
|
double err = boost::math::relative_difference(computed, expected);
|
|
if(err > 1e-7)
|
|
{
|
|
std::cout << "Erasing row: ";
|
|
for(unsigned i = 0; i < data[row].size(); ++i)
|
|
{
|
|
std::cout << data[row][i] << " ";
|
|
}
|
|
std::cout << "Error was " << err << std::endl;
|
|
data.erase(data.begin() + row);
|
|
--row;
|
|
}
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
std::cout << "Erasing row: ";
|
|
for(unsigned i = 0; i < data[row].size(); ++i)
|
|
{
|
|
std::cout << data[row][i] << " ";
|
|
}
|
|
std::cout << "due to thrown exception: " << e.what() << std::endl;
|
|
data.erase(data.begin() + row);
|
|
--row;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class Clock>
|
|
struct stopwatch
|
|
{
|
|
typedef typename Clock::duration duration;
|
|
stopwatch()
|
|
{
|
|
m_start = Clock::now();
|
|
}
|
|
duration elapsed()
|
|
{
|
|
return Clock::now() - m_start;
|
|
}
|
|
void reset()
|
|
{
|
|
m_start = Clock::now();
|
|
}
|
|
|
|
private:
|
|
typename Clock::time_point m_start;
|
|
};
|
|
|
|
double sum = 0;
|
|
|
|
template <class Func>
|
|
double exec_timed_test(Func f)
|
|
{
|
|
double t = 0;
|
|
unsigned repeats = 1;
|
|
do{
|
|
stopwatch<boost::chrono::high_resolution_clock> w;
|
|
|
|
for(unsigned count = 0; count < repeats; ++count)
|
|
{
|
|
for(std::vector<std::vector<double> >::const_iterator i = data.begin(); i != data.end(); ++i)
|
|
sum += f(*i);
|
|
}
|
|
|
|
t = boost::chrono::duration_cast<boost::chrono::duration<double>>(w.elapsed()).count();
|
|
if(t < 0.5)
|
|
repeats *= 2;
|
|
} while(t < 0.5);
|
|
return t / (repeats * data.size());
|
|
}
|
|
|
|
#endif // PERFORMANCE_HPP
|