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 //----------------------------------------------------------------------------// 22 // Windows // 23 //----------------------------------------------------------------------------// 24 #ifndef BOOST_MOVE_DETAIL_NSEC_CLOCK_HPP 25 #define BOOST_MOVE_DETAIL_NSEC_CLOCK_HPP 26 27 #include <boost/config.hpp> 28 #include <boost/cstdint.hpp> 29 #include <boost/cstdlib.hpp> 30 31 32 # if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) 33 # define BOOST_MOVE_DETAIL_WINDOWS_API 34 # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) 35 # define BOOST_MOVE_DETAIL_MAC_API 36 # else 37 # define BOOST_MOVE_DETAIL_POSIX_API 38 # endif 39 40 #if defined(BOOST_MOVE_DETAIL_WINDOWS_API) 41 42 #include <boost/winapi/time.hpp> 43 #include <boost/winapi/timers.hpp> 44 #include <boost/winapi/get_last_error.hpp> 45 #include <boost/winapi/error_codes.hpp> 46 #include <boost/assert.hpp> 47 #include <boost/core/ignore_unused.hpp> 48 49 namespace boost { namespace move_detail { 50 51 template<int Dummy> 52 struct QPFHolder 53 { get_nsec_per_ticboost::move_detail::QPFHolder54 static inline double get_nsec_per_tic() 55 { 56 boost::winapi::LARGE_INTEGER_ freq; 57 boost::winapi::BOOL_ r = boost::winapi::QueryPerformanceFrequency( &freq ); 58 boost::ignore_unused(r); 59 BOOST_ASSERT(r != 0 && "Boost::Move - get_nanosecs_per_tic Internal Error"); 60 61 return double(1000000000.0L / freq.QuadPart); 62 } 63 64 static const double nanosecs_per_tic; 65 }; 66 67 template<int Dummy> 68 const double QPFHolder<Dummy>::nanosecs_per_tic = get_nsec_per_tic(); 69 nsec_clock()70inline boost::uint64_t nsec_clock() BOOST_NOEXCEPT 71 { 72 double nanosecs_per_tic = QPFHolder<0>::nanosecs_per_tic; 73 74 boost::winapi::LARGE_INTEGER_ pcount; 75 unsigned times=0; 76 while ( !boost::winapi::QueryPerformanceCounter( &pcount ) ) 77 { 78 if ( ++times > 3 ) 79 { 80 BOOST_ASSERT("Boost::Move - QueryPerformanceCounter Internal Error"); 81 return 0u; 82 } 83 } 84 85 return static_cast<boost::uint64_t>((nanosecs_per_tic) * pcount.QuadPart); 86 } 87 88 }} //namespace boost { namespace move_detail { 89 90 #elif defined(BOOST_MOVE_DETAIL_MAC_API) 91 92 #include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t 93 nsec_clock()94inline boost::uint64_t nsec_clock() BOOST_NOEXCEPT 95 { 96 boost::uint64_t count = ::mach_absolute_time(); 97 98 mach_timebase_info_data_t info; 99 mach_timebase_info(&info); 100 return static_cast<boost::uint64_t> 101 ( static_cast<double>(count)*(static_cast<double>(info.numer) / info.denom); 102 } 103 104 #elif defined(BOOST_MOVE_DETAIL_POSIX_API) 105 106 #include <time.h> 107 108 # if defined(CLOCK_MONOTONIC_PRECISE) //BSD 109 # define BOOST_MOVE_DETAIL_CLOCK_MONOTONIC CLOCK_MONOTONIC_PRECISE 110 # elif defined(CLOCK_MONOTONIC_RAW) //Linux 111 # define BOOST_MOVE_DETAIL_CLOCK_MONOTONIC CLOCK_MONOTONIC_RAW 112 # elif defined(CLOCK_HIGHRES) //Solaris 113 # define BOOST_MOVE_DETAIL_CLOCK_MONOTONIC CLOCK_HIGHRES 114 # elif defined(CLOCK_MONOTONIC) //POSIX (AIX, BSD, Linux, Solaris) 115 # define BOOST_MOVE_DETAIL_CLOCK_MONOTONIC CLOCK_MONOTONIC 116 # else 117 # error "No high resolution steady clock in your system, please provide a patch" 118 # endif 119 120 inline boost::uint64_t nsec_clock() BOOST_NOEXCEPT 121 { 122 struct timespec count; 123 ::clock_gettime(BOOST_MOVE_DETAIL_CLOCK_MONOTONIC, &count); 124 boost::uint64_t r = count.tv_sec; 125 r *= 1000000000U; 126 r += count.tv_nsec; 127 return r; 128 } 129 130 #endif // POSIX 131 132 namespace boost { namespace move_detail { 133 134 typedef boost::uint64_t nanosecond_type; 135 136 struct cpu_times 137 { 138 nanosecond_type wall; 139 nanosecond_type user; 140 nanosecond_type system; 141 142 void clear() { wall = user = system = 0; } 143 }; 144 145 146 inline void get_cpu_times(boost::move_detail::cpu_times& current) 147 { 148 current.wall = nsec_clock(); 149 } 150 151 152 class cpu_timer 153 { 154 public: 155 156 // constructor 157 cpu_timer() BOOST_NOEXCEPT { start(); } 158 159 // observers 160 bool is_stopped() const BOOST_NOEXCEPT { return m_is_stopped; } 161 cpu_times elapsed() const BOOST_NOEXCEPT; // does not stop() 162 163 // actions 164 void start() BOOST_NOEXCEPT; 165 void stop() BOOST_NOEXCEPT; 166 void resume() BOOST_NOEXCEPT; 167 168 private: 169 cpu_times m_times; 170 bool m_is_stopped; 171 }; 172 173 174 // cpu_timer ---------------------------------------------------------------------// 175 176 inline void cpu_timer::start() BOOST_NOEXCEPT 177 { 178 m_is_stopped = false; 179 get_cpu_times(m_times); 180 } 181 182 inline void cpu_timer::stop() BOOST_NOEXCEPT 183 { 184 if (is_stopped()) 185 return; 186 m_is_stopped = true; 187 188 cpu_times current; 189 get_cpu_times(current); 190 m_times.wall = (current.wall - m_times.wall); 191 m_times.user = (current.user - m_times.user); 192 m_times.system = (current.system - m_times.system); 193 } 194 195 inline cpu_times cpu_timer::elapsed() const BOOST_NOEXCEPT 196 { 197 if (is_stopped()) 198 return m_times; 199 cpu_times current; 200 get_cpu_times(current); 201 current.wall -= m_times.wall; 202 current.user -= m_times.user; 203 current.system -= m_times.system; 204 return current; 205 } 206 207 inline void cpu_timer::resume() BOOST_NOEXCEPT 208 { 209 if (is_stopped()) 210 { 211 cpu_times current (m_times); 212 start(); 213 m_times.wall -= current.wall; 214 m_times.user -= current.user; 215 m_times.system -= current.system; 216 } 217 } 218 219 220 221 } // namespace move_detail 222 } // namespace boost 223 224 #endif //BOOST_MOVE_DETAIL_NSEC_CLOCK_HPP 225