nsec_clock.hpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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 <boost/move/detail/workaround.hpp>
  28. #include <cstdlib>
  29. # if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32))
  30. # define BOOST_MOVE_DETAIL_WINDOWS_API
  31. # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
  32. # define BOOST_MOVE_DETAIL_MAC_API
  33. # else
  34. # define BOOST_MOVE_DETAIL_POSIX_API
  35. # endif
  36. #if defined(BOOST_MOVE_DETAIL_WINDOWS_API)
  37. #include <cassert>
  38. #if defined( BOOST_USE_WINDOWS_H )
  39. #include <Windows.h>
  40. #else
  41. #if defined (WIN32_PLATFORM_PSPC)
  42. #define BOOST_MOVE_WINAPI_IMPORT BOOST_SYMBOL_IMPORT
  43. #define BOOST_MOVE_WINAPI_IMPORT_EXCEPT_WM
  44. #elif defined (_WIN32_WCE)
  45. #define BOOST_MOVE_WINAPI_IMPORT
  46. #define BOOST_MOVE_WINAPI_IMPORT_EXCEPT_WM
  47. #else
  48. #define BOOST_MOVE_WINAPI_IMPORT BOOST_SYMBOL_IMPORT
  49. #define BOOST_MOVE_WINAPI_IMPORT_EXCEPT_WM BOOST_SYMBOL_IMPORT
  50. #endif
  51. #if defined(WINAPI)
  52. #define BOOST_MOVE_WINAPI_CC WINAPI
  53. #else
  54. #if defined(_M_IX86) || defined(__i386__)
  55. #define BOOST_MOVE_WINAPI_CC __stdcall
  56. #else
  57. // On architectures other than 32-bit x86 __stdcall is ignored. Clang also issues a warning.
  58. #define BOOST_MOVE_WINAPI_CC
  59. #endif
  60. #endif
  61. extern "C" {
  62. union _LARGE_INTEGER;
  63. typedef long long QuadPart;
  64. BOOST_MOVE_WINAPI_IMPORT_EXCEPT_WM int BOOST_MOVE_WINAPI_CC
  65. QueryPerformanceCounter(::_LARGE_INTEGER* lpPerformanceCount);
  66. BOOST_MOVE_WINAPI_IMPORT_EXCEPT_WM int BOOST_MOVE_WINAPI_CC
  67. QueryPerformanceFrequency(::_LARGE_INTEGER* lpFrequency);
  68. } // extern "C"
  69. #endif
  70. namespace boost { namespace move_detail {
  71. BOOST_FORCEINLINE int QueryPerformanceCounter(long long* lpPerformanceCount)
  72. {
  73. return ::QueryPerformanceCounter(reinterpret_cast< ::_LARGE_INTEGER* >(lpPerformanceCount));
  74. }
  75. BOOST_FORCEINLINE int QueryPerformanceFrequency(long long* lpFrequency)
  76. {
  77. return ::QueryPerformanceFrequency(reinterpret_cast< ::_LARGE_INTEGER* >(lpFrequency));
  78. }
  79. template<int Dummy>
  80. struct QPFHolder
  81. {
  82. static inline double get_nsec_per_tic()
  83. {
  84. long long freq;
  85. //According to MS documentation:
  86. //"On systems that run Windows XP or later, the function will always succeed and will thus never return zero"
  87. (void)boost::move_detail::QueryPerformanceFrequency(&freq);
  88. return double(1000000000.0L / double(freq));
  89. }
  90. static const double nanosecs_per_tic;
  91. };
  92. template<int Dummy>
  93. const double QPFHolder<Dummy>::nanosecs_per_tic = get_nsec_per_tic();
  94. inline boost::uint64_t nsec_clock() BOOST_NOEXCEPT
  95. {
  96. double nanosecs_per_tic = QPFHolder<0>::nanosecs_per_tic;
  97. long long pcount;
  98. //According to MS documentation:
  99. //"On systems that run Windows XP or later, the function will always succeed and will thus never return zero"
  100. (void)boost::move_detail::QueryPerformanceCounter( &pcount );
  101. return static_cast<boost::uint64_t>(nanosecs_per_tic * double(pcount));
  102. }
  103. }} //namespace boost { namespace move_detail {
  104. #elif defined(BOOST_MOVE_DETAIL_MAC_API)
  105. #include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t
  106. inline boost::uint64_t nsec_clock() BOOST_NOEXCEPT
  107. {
  108. boost::uint64_t count = ::mach_absolute_time();
  109. mach_timebase_info_data_t info;
  110. mach_timebase_info(&info);
  111. return static_cast<boost::uint64_t>
  112. ( static_cast<double>(count)*(static_cast<double>(info.numer) / info.denom) );
  113. }
  114. #elif defined(BOOST_MOVE_DETAIL_POSIX_API)
  115. #include <time.h>
  116. # if defined(CLOCK_MONOTONIC_PRECISE) //BSD
  117. # define BOOST_MOVE_DETAIL_CLOCK_MONOTONIC CLOCK_MONOTONIC_PRECISE
  118. # elif defined(CLOCK_MONOTONIC_RAW) //Linux
  119. # define BOOST_MOVE_DETAIL_CLOCK_MONOTONIC CLOCK_MONOTONIC_RAW
  120. # elif defined(CLOCK_HIGHRES) //Solaris
  121. # define BOOST_MOVE_DETAIL_CLOCK_MONOTONIC CLOCK_HIGHRES
  122. # elif defined(CLOCK_MONOTONIC) //POSIX (AIX, BSD, Linux, Solaris)
  123. # define BOOST_MOVE_DETAIL_CLOCK_MONOTONIC CLOCK_MONOTONIC
  124. # else
  125. # error "No high resolution steady clock in your system, please provide a patch"
  126. # endif
  127. inline boost::uint64_t nsec_clock() BOOST_NOEXCEPT
  128. {
  129. struct timespec count;
  130. ::clock_gettime(BOOST_MOVE_DETAIL_CLOCK_MONOTONIC, &count);
  131. boost::uint64_t r = static_cast<boost::uint64_t>(count.tv_sec);
  132. r *= 1000000000U;
  133. r += static_cast<boost::uint64_t>(count.tv_nsec);
  134. return r;
  135. }
  136. #endif // POSIX
  137. namespace boost { namespace move_detail {
  138. typedef boost::uint64_t nanosecond_type;
  139. struct cpu_times
  140. {
  141. nanosecond_type wall;
  142. nanosecond_type user;
  143. nanosecond_type system;
  144. void clear() { wall = user = system = 0; }
  145. cpu_times()
  146. { this->clear(); }
  147. };
  148. inline void get_cpu_times(boost::move_detail::cpu_times& current)
  149. {
  150. current.wall = nsec_clock();
  151. }
  152. class cpu_timer
  153. {
  154. public:
  155. // constructor
  156. cpu_timer() BOOST_NOEXCEPT { start(); }
  157. // observers
  158. bool is_stopped() const BOOST_NOEXCEPT { return m_is_stopped; }
  159. cpu_times elapsed() const BOOST_NOEXCEPT; // does not stop()
  160. // actions
  161. void start() BOOST_NOEXCEPT;
  162. void stop() BOOST_NOEXCEPT;
  163. void resume() BOOST_NOEXCEPT;
  164. private:
  165. cpu_times m_times;
  166. bool m_is_stopped;
  167. };
  168. // cpu_timer ---------------------------------------------------------------------//
  169. inline void cpu_timer::start() BOOST_NOEXCEPT
  170. {
  171. m_is_stopped = false;
  172. get_cpu_times(m_times);
  173. }
  174. inline void cpu_timer::stop() BOOST_NOEXCEPT
  175. {
  176. if (is_stopped())
  177. return;
  178. m_is_stopped = true;
  179. cpu_times current;
  180. get_cpu_times(current);
  181. m_times.wall = (current.wall - m_times.wall);
  182. m_times.user = (current.user - m_times.user);
  183. m_times.system = (current.system - m_times.system);
  184. }
  185. inline cpu_times cpu_timer::elapsed() const BOOST_NOEXCEPT
  186. {
  187. if (is_stopped())
  188. return m_times;
  189. cpu_times current;
  190. get_cpu_times(current);
  191. current.wall -= m_times.wall;
  192. current.user -= m_times.user;
  193. current.system -= m_times.system;
  194. return current;
  195. }
  196. inline void cpu_timer::resume() BOOST_NOEXCEPT
  197. {
  198. if (is_stopped())
  199. {
  200. cpu_times current (m_times);
  201. start();
  202. m_times.wall -= current.wall;
  203. m_times.user -= current.user;
  204. m_times.system -= current.system;
  205. }
  206. }
  207. } // namespace move_detail
  208. } // namespace boost
  209. #endif //BOOST_MOVE_DETAIL_NSEC_CLOCK_HPP