• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  Copyright John Maddock 2015.
2 //  Use, modification and distribution are subject to the
3 //  Boost Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef PERFORMANCE_HPP
7 #define PERFORMANCE_HPP
8 
9 #include <boost/math/special_functions/relative_difference.hpp>
10 #include <boost/array.hpp>
11 #include <boost/chrono.hpp>
12 #include <boost/regex.hpp>
13 #include <iostream>
14 #include <iomanip>
15 
16 extern std::vector<std::vector<double> > data;
17 
18 template <class Array>
add_data(const Array & a)19 void add_data(const Array& a)
20 {
21    //
22    // This function is called multiple times to merge multiple data sets into one big table:
23    //
24    for(typename Array::const_iterator i = a.begin(); i != a.end(); ++i)
25    {
26       data.push_back(std::vector<double>());
27       for(typename Array::value_type::const_iterator j = i->begin(); j != i->end(); ++j)
28       {
29          data.back().push_back(*j);
30       }
31    }
32 }
33 
34 template <class Func, class Result>
screen_data(Func f,Result r)35 void screen_data(Func f, Result r)
36 {
37    //
38    // If any of the implementations being tested produces garbage for one of our
39    // test cases (or else if we test a domain they don't support), then we remove that
40    // row from the table.  This allows us to only test a common supported sub-set for performance:
41    //
42    for(std::vector<std::vector<double> >::size_type row = 0; row < data.size(); ++row)
43    {
44       try
45       {
46          double computed = f(data[row]);
47          double expected = r(data[row]);
48          double err = boost::math::relative_difference(computed, expected);
49          if(err > 1e-7)
50          {
51             std::cout << "Erasing row: ";
52             for(unsigned i = 0; i < data[row].size(); ++i)
53             {
54                std::cout << data[row][i] << " ";
55             }
56             std::cout << "Error was " << err << std::endl;
57             data.erase(data.begin() + row);
58             --row;
59          }
60       }
61       catch(const std::exception& e)
62       {
63          std::cout << "Erasing row: ";
64          for(unsigned i = 0; i < data[row].size(); ++i)
65          {
66             std::cout << data[row][i] << " ";
67          }
68          std::cout << "due to thrown exception: " << e.what() << std::endl;
69          data.erase(data.begin() + row);
70          --row;
71       }
72    }
73 }
74 
75 template <class Clock>
76 struct stopwatch
77 {
78    typedef typename Clock::duration duration;
stopwatchstopwatch79    stopwatch()
80    {
81       m_start = Clock::now();
82    }
elapsedstopwatch83    duration elapsed()
84    {
85       return Clock::now() - m_start;
86    }
resetstopwatch87    void reset()
88    {
89       m_start = Clock::now();
90    }
91 
92 private:
93    typename Clock::time_point m_start;
94 };
95 
96 double sum = 0;
97 
98 template <class Func>
exec_timed_test(Func f)99 double exec_timed_test(Func f)
100 {
101    double t = 0;
102    unsigned repeats = 1;
103    do{
104       stopwatch<boost::chrono::high_resolution_clock> w;
105 
106       for(unsigned count = 0; count < repeats; ++count)
107       {
108          for(std::vector<std::vector<double> >::const_iterator i = data.begin(); i != data.end(); ++i)
109             sum += f(*i);
110       }
111 
112       t = boost::chrono::duration_cast<boost::chrono::duration<double>>(w.elapsed()).count();
113       if(t < 0.5)
114          repeats *= 2;
115    } while(t < 0.5);
116    return t / (repeats * data.size());
117 }
118 
119 #endif // PERFORMANCE_HPP
120