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