nsec_clock.hpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // This code is based on Timer and Chrono code. Thanks to authors:
  2. //
  3. // Boost.Timer:
  4. // Copyright Beman Dawes 1994-2007, 2011
  5. //
  6. // Boost.Chrono:
  7. // Copyright Beman Dawes 2008
  8. // Copyright 2009-2010 Vicente J. Botet Escriba
  9. //
  10. // Simplified and modified to be able to support exceptionless (-fno-exceptions).
  11. // Boost.Timer depends on Boost.Chorno wich uses boost::throw_exception.
  12. // And Boost.Chrono DLLs don't build in Win32 as there is no
  13. // boost::throw_exception(std::exception const&) implementation
  14. // in Boost.Chrono:
  15. //
  16. // Copyright 2020 Ion Gaztanaga
  17. //
  18. // Distributed under the Boost Software License, Version 1.0.
  19. // See http://www.boost.org/LICENSE_1_0.txt
  20. //----------------------------------------------------------------------------//
  21. // Windows //
  22. //----------------------------------------------------------------------------//
  23. #ifndef BOOST_MOVE_DETAIL_NSEC_CLOCK_HPP
  24. #define BOOST_MOVE_DETAIL_NSEC_CLOCK_HPP
  25. #include <boost/config.hpp>
  26. #include <boost/cstdint.hpp>
  27. #include <cstdlib>
  28. # if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32))
  29. # define BOOST_MOVE_DETAIL_WINDOWS_API
  30. # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
  31. # define BOOST_MOVE_DETAIL_MAC_API
  32. # else
  33. # define BOOST_MOVE_DETAIL_POSIX_API
  34. # endif
  35. #if defined(BOOST_MOVE_DETAIL_WINDOWS_API)
  36. #include <boost/winapi/time.hpp>
  37. #include <boost/winapi/timers.hpp>
  38. #include <boost/winapi/get_last_error.hpp>
  39. #include <boost/winapi/error_codes.hpp>
  40. #include <boost/assert.hpp>
  41. #include <boost/core/ignore_unused.hpp>
  42. namespace boost { namespace move_detail {
  43. template<int Dummy>
  44. struct QPFHolder
  45. {
  46. static inline double get_nsec_per_tic()
  47. {
  48. boost::winapi::LARGE_INTEGER_ freq;
  49. boost::winapi::BOOL_ r = boost::winapi::QueryPerformanceFrequency( &freq );
  50. boost::ignore_unused(r);
  51. BOOST_ASSERT(r != 0 && "Boost::Move - get_nanosecs_per_tic Internal Error");
  52. return double(1000000000.0L / freq.QuadPart);
  53. }
  54. static const double nanosecs_per_tic;
  55. };
  56. template<int Dummy>
  57. const double QPFHolder<Dummy>::nanosecs_per_tic = get_nsec_per_tic();
  58. inline boost::uint64_t nsec_clock() BOOST_NOEXCEPT
  59. {
  60. double nanosecs_per_tic = QPFHolder<0>::nanosecs_per_tic;
  61. boost::winapi::LARGE_INTEGER_ pcount;
  62. unsigned times=0;
  63. while ( !boost::winapi::QueryPerformanceCounter( &pcount ) )
  64. {
  65. if ( ++times > 3 )
  66. {
  67. BOOST_ASSERT("Boost::Move - QueryPerformanceCounter Internal Error");
  68. return 0u;
  69. }
  70. }
  71. return static_cast<boost::uint64_t>((nanosecs_per_tic) * pcount.QuadPart);
  72. }
  73. }} //namespace boost { namespace move_detail {
  74. #elif defined(BOOST_MOVE_DETAIL_MAC_API)
  75. #include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t
  76. inline boost::uint64_t nsec_clock() BOOST_NOEXCEPT
  77. {
  78. boost::uint64_t count = ::mach_absolute_time();
  79. mach_timebase_info_data_t info;
  80. mach_timebase_info(&info);
  81. return static_cast<boost::uint64_t>
  82. ( static_cast<double>(count)*(static_cast<double>(info.numer) / info.denom);
  83. }
  84. #elif defined(BOOST_MOVE_DETAIL_POSIX_API)
  85. #include <time.h>
  86. # if defined(CLOCK_MONOTONIC_PRECISE) //BSD
  87. # define BOOST_MOVE_DETAIL_CLOCK_MONOTONIC CLOCK_MONOTONIC_PRECISE
  88. # elif defined(CLOCK_MONOTONIC_RAW) //Linux
  89. # define BOOST_MOVE_DETAIL_CLOCK_MONOTONIC CLOCK_MONOTONIC_RAW
  90. # elif defined(CLOCK_HIGHRES) //Solaris
  91. # define BOOST_MOVE_DETAIL_CLOCK_MONOTONIC CLOCK_HIGHRES
  92. # elif defined(CLOCK_MONOTONIC) //POSIX (AIX, BSD, Linux, Solaris)
  93. # define BOOST_MOVE_DETAIL_CLOCK_MONOTONIC CLOCK_MONOTONIC
  94. # else
  95. # error "No high resolution steady clock in your system, please provide a patch"
  96. # endif
  97. inline boost::uint64_t nsec_clock() BOOST_NOEXCEPT
  98. {
  99. struct timespec count;
  100. ::clock_gettime(BOOST_MOVE_DETAIL_CLOCK_MONOTONIC, &count);
  101. boost::uint64_t r = count.tv_sec;
  102. r *= 1000000000U;
  103. r += count.tv_nsec;
  104. return r;
  105. }
  106. #endif // POSIX
  107. namespace boost { namespace move_detail {
  108. typedef boost::uint64_t nanosecond_type;
  109. struct cpu_times
  110. {
  111. nanosecond_type wall;
  112. nanosecond_type user;
  113. nanosecond_type system;
  114. void clear() { wall = user = system = 0; }
  115. };
  116. inline void get_cpu_times(boost::move_detail::cpu_times& current)
  117. {
  118. current.wall = nsec_clock();
  119. }
  120. class cpu_timer
  121. {
  122. public:
  123. // constructor
  124. cpu_timer() BOOST_NOEXCEPT { start(); }
  125. // observers
  126. bool is_stopped() const BOOST_NOEXCEPT { return m_is_stopped; }
  127. cpu_times elapsed() const BOOST_NOEXCEPT; // does not stop()
  128. // actions
  129. void start() BOOST_NOEXCEPT;
  130. void stop() BOOST_NOEXCEPT;
  131. void resume() BOOST_NOEXCEPT;
  132. private:
  133. cpu_times m_times;
  134. bool m_is_stopped;
  135. };
  136. // cpu_timer ---------------------------------------------------------------------//
  137. inline void cpu_timer::start() BOOST_NOEXCEPT
  138. {
  139. m_is_stopped = false;
  140. get_cpu_times(m_times);
  141. }
  142. inline void cpu_timer::stop() BOOST_NOEXCEPT
  143. {
  144. if (is_stopped())
  145. return;
  146. m_is_stopped = true;
  147. cpu_times current;
  148. get_cpu_times(current);
  149. m_times.wall = (current.wall - m_times.wall);
  150. m_times.user = (current.user - m_times.user);
  151. m_times.system = (current.system - m_times.system);
  152. }
  153. inline cpu_times cpu_timer::elapsed() const BOOST_NOEXCEPT
  154. {
  155. if (is_stopped())
  156. return m_times;
  157. cpu_times current;
  158. get_cpu_times(current);
  159. current.wall -= m_times.wall;
  160. current.user -= m_times.user;
  161. current.system -= m_times.system;
  162. return current;
  163. }
  164. inline void cpu_timer::resume() BOOST_NOEXCEPT
  165. {
  166. if (is_stopped())
  167. {
  168. cpu_times current (m_times);
  169. start();
  170. m_times.wall -= current.wall;
  171. m_times.user -= current.user;
  172. m_times.system -= current.system;
  173. }
  174. }
  175. } // namespace move_detail
  176. } // namespace boost
  177. #endif //BOOST_MOVE_DETAIL_NSEC_CLOCK_HPP