performance.hpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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. #ifndef PERFORMANCE_HPP
  6. #define PERFORMANCE_HPP
  7. #include <boost/math/special_functions/relative_difference.hpp>
  8. #include <boost/array.hpp>
  9. #include <boost/chrono.hpp>
  10. #include <boost/regex.hpp>
  11. template <class Array>
  12. void add_data(const Array& a)
  13. {
  14. //
  15. // This function is called multiple times to merge multiple data sets into one big table:
  16. //
  17. for(typename Array::const_iterator i = a.begin(); i != a.end(); ++i)
  18. {
  19. data.push_back(std::vector<double>());
  20. for(typename Array::value_type::const_iterator j = i->begin(); j != i->end(); ++j)
  21. {
  22. data.back().push_back(*j);
  23. }
  24. }
  25. }
  26. template <class Func, class Result>
  27. void screen_data(Func f, Result r)
  28. {
  29. //
  30. // If any of the implementations being tested produces garbage for one of our
  31. // test cases (or else if we test a domain they don't support), then we remove that
  32. // row from the table. This allows us to only test a common supported sub-set for performance:
  33. //
  34. for(std::vector<std::vector<double> >::size_type row = 0; row < data.size(); ++row)
  35. {
  36. try
  37. {
  38. double computed = f(data[row]);
  39. double expected = r(data[row]);
  40. double err = boost::math::relative_difference(computed, expected);
  41. if(err > 1e-7)
  42. {
  43. std::cout << "Erasing row: ";
  44. for(unsigned i = 0; i < data[row].size(); ++i)
  45. {
  46. std::cout << data[row][i] << " ";
  47. }
  48. std::cout << "Error was " << err << std::endl;
  49. data.erase(data.begin() + row);
  50. --row;
  51. }
  52. }
  53. catch(const std::exception& e)
  54. {
  55. std::cout << "Erasing row: ";
  56. for(unsigned i = 0; i < data[row].size(); ++i)
  57. {
  58. std::cout << data[row][i] << " ";
  59. }
  60. std::cout << "due to thrown exception: " << e.what() << std::endl;
  61. data.erase(data.begin() + row);
  62. --row;
  63. }
  64. }
  65. }
  66. template <class Clock>
  67. struct stopwatch
  68. {
  69. typedef typename Clock::duration duration;
  70. stopwatch()
  71. {
  72. m_start = Clock::now();
  73. }
  74. duration elapsed()
  75. {
  76. return Clock::now() - m_start;
  77. }
  78. void reset()
  79. {
  80. m_start = Clock::now();
  81. }
  82. private:
  83. typename Clock::time_point m_start;
  84. };
  85. double sum = 0;
  86. template <class Func>
  87. double exec_timed_test(Func f)
  88. {
  89. double t = 0;
  90. unsigned repeats = 1;
  91. do{
  92. stopwatch<boost::chrono::high_resolution_clock> w;
  93. for(unsigned count = 0; count < repeats; ++count)
  94. {
  95. for(std::vector<std::vector<double> >::const_iterator i = data.begin(); i != data.end(); ++i)
  96. sum += f(*i);
  97. }
  98. t = boost::chrono::duration_cast<boost::chrono::duration<double>>(w.elapsed()).count();
  99. if(t < 0.5)
  100. repeats *= 2;
  101. } while(t < 0.5);
  102. return t / (repeats * data.size());
  103. }
  104. #endif // PERFORMANCE_HPP