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)19void 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)35void 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)99double 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