timer.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // (C) Copyright Raffi Enficiaud 2019.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. // See http://www.boost.org/libs/test for the library home page.
  6. //
  7. // Description : timer and elapsed types
  8. // ***************************************************************************
  9. #ifndef BOOST_TEST_UTILS_TIMER_HPP
  10. #define BOOST_TEST_UTILS_TIMER_HPP
  11. #include <boost/config.hpp>
  12. #include <boost/cstdint.hpp>
  13. #include <utility>
  14. #include <ctime>
  15. # if defined(_WIN32) || defined(__CYGWIN__)
  16. # define BOOST_TEST_TIMER_WINDOWS_API
  17. # elif defined(__MACH__) && defined(__APPLE__)// && !defined(CLOCK_MONOTONIC)
  18. # // we compile for all macs the same, CLOCK_MONOTONIC introduced in 10.12
  19. # define BOOST_TEST_TIMER_MACH_API
  20. # else
  21. # define BOOST_TEST_TIMER_POSIX_API
  22. # if !defined(CLOCK_MONOTONIC)
  23. # error "CLOCK_MONOTONIC not defined"
  24. # endif
  25. # endif
  26. # if defined(BOOST_TEST_TIMER_WINDOWS_API)
  27. # include <windows.h>
  28. # elif defined(BOOST_TEST_TIMER_MACH_API)
  29. # include <mach/mach_time.h>
  30. //# include <mach/mach.h> /* host_get_clock_service, mach_... */
  31. # else
  32. # include <sys/time.h>
  33. # endif
  34. # ifdef BOOST_NO_STDC_NAMESPACE
  35. namespace std { using ::clock_t; using ::clock; }
  36. # endif
  37. namespace boost {
  38. namespace unit_test {
  39. namespace timer {
  40. struct elapsed_time
  41. {
  42. typedef boost::int_least64_t nanosecond_type;
  43. nanosecond_type wall;
  44. nanosecond_type system;
  45. void clear() {
  46. wall = 0;
  47. system = 0;
  48. }
  49. };
  50. inline double
  51. microsecond_wall_time( elapsed_time const& elapsed )
  52. {
  53. return elapsed.wall / 1E3;
  54. }
  55. inline double
  56. second_wall_time( elapsed_time const& elapsed )
  57. {
  58. return elapsed.wall / 1E9;
  59. }
  60. namespace details {
  61. #if defined(BOOST_TEST_TIMER_WINDOWS_API)
  62. elapsed_time::nanosecond_type get_tick_freq() {
  63. LARGE_INTEGER freq;
  64. ::QueryPerformanceFrequency( &freq );
  65. return static_cast<elapsed_time::nanosecond_type>(freq.QuadPart);
  66. }
  67. #elif defined(BOOST_TEST_TIMER_MACH_API)
  68. std::pair<elapsed_time::nanosecond_type, elapsed_time::nanosecond_type> get_time_base() {
  69. mach_timebase_info_data_t timebase;
  70. if(mach_timebase_info(&timebase) == 0)
  71. return std::pair<elapsed_time::nanosecond_type, elapsed_time::nanosecond_type>(timebase.numer, timebase.denom);
  72. return std::pair<elapsed_time::nanosecond_type, elapsed_time::nanosecond_type>(0, 1);
  73. }
  74. #endif
  75. }
  76. //! Simple timing class
  77. //!
  78. //! This class measures the wall clock time.
  79. class timer
  80. {
  81. public:
  82. timer()
  83. {
  84. restart();
  85. }
  86. void restart()
  87. {
  88. _start_time_clock = std::clock();
  89. #if defined(BOOST_TEST_TIMER_WINDOWS_API)
  90. ::QueryPerformanceCounter(&_start_time_wall);
  91. #elif defined(BOOST_TEST_TIMER_MACH_API)
  92. _start_time_wall = mach_absolute_time();
  93. #else
  94. if( ::clock_gettime( CLOCK_MONOTONIC, &_start_time_wall ) != 0 )
  95. {
  96. _start_time_wall.tv_nsec = -1;
  97. _start_time_wall.tv_sec = -1;
  98. }
  99. #endif
  100. }
  101. // return elapsed time in seconds
  102. elapsed_time elapsed() const
  103. {
  104. typedef elapsed_time::nanosecond_type nanosecond_type;
  105. static const double clock_to_nano_seconds = 1E9 / CLOCKS_PER_SEC;
  106. elapsed_time return_value;
  107. // processor / system time
  108. return_value.system = static_cast<nanosecond_type>(double(std::clock() - _start_time_clock) * clock_to_nano_seconds);
  109. #if defined(BOOST_TEST_TIMER_WINDOWS_API)
  110. static const nanosecond_type tick_per_sec = details::get_tick_freq();
  111. LARGE_INTEGER end_time;
  112. ::QueryPerformanceCounter(&end_time);
  113. return_value.wall = static_cast<nanosecond_type>(((end_time.QuadPart - _start_time_wall.QuadPart) * 1E9) / tick_per_sec);
  114. #elif defined(BOOST_TEST_TIMER_MACH_API)
  115. static std::pair<nanosecond_type, nanosecond_type> timebase = details::get_time_base();
  116. nanosecond_type clock = mach_absolute_time() - _start_time_wall;
  117. return_value.wall = static_cast<nanosecond_type>((clock * timebase.first) / timebase.second);
  118. #else
  119. struct timespec end_time;
  120. return_value.wall = 0;
  121. if( ::clock_gettime( CLOCK_MONOTONIC, &end_time ) == 0 )
  122. {
  123. return_value.wall = static_cast<nanosecond_type>((end_time.tv_sec - _start_time_wall.tv_sec) * 1E9 + (end_time.tv_nsec - _start_time_wall.tv_nsec));
  124. }
  125. #endif
  126. return return_value;
  127. }
  128. private:
  129. std::clock_t _start_time_clock;
  130. #if defined(BOOST_TEST_TIMER_WINDOWS_API)
  131. LARGE_INTEGER _start_time_wall;
  132. #elif defined(BOOST_TEST_TIMER_MACH_API)
  133. elapsed_time::nanosecond_type _start_time_wall;
  134. #else
  135. struct timespec _start_time_wall;
  136. #endif
  137. };
  138. //____________________________________________________________________________//
  139. } // namespace timer
  140. } // namespace unit_test
  141. } // namespace boost
  142. #endif // BOOST_TEST_UTILS_TIMER_HPP