Line data Source code
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; 54 : void clear() { 55 : wall = 0; 56 : system = 0; 57 : } 58 : }; 59 : 60 : inline double 61 44486 : microsecond_wall_time( elapsed_time const& elapsed ) 62 : { 63 44486 : return elapsed.wall / 1E3; 64 : } 65 : 66 : inline double 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) 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 146 : std::pair<elapsed_time::nanosecond_type, elapsed_time::nanosecond_type> get_time_base() { 81 : mach_timebase_info_data_t timebase; 82 146 : if(mach_timebase_info(&timebase) == 0) 83 146 : return std::pair<elapsed_time::nanosecond_type, elapsed_time::nanosecond_type>(timebase.numer, timebase.denom); 84 0 : return std::pair<elapsed_time::nanosecond_type, elapsed_time::nanosecond_type>(0, 1); 85 146 : } 86 : #endif 87 : } 88 : 89 : //! Simple timing class 90 : //! 91 : //! This class measures the wall clock time. 92 : class timer 93 : { 94 : public: 95 2046 : timer() 96 1023 : { 97 1023 : restart(); 98 2046 : } 99 1023 : void restart() 100 : { 101 1023 : _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 1023 : _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 1023 : } 114 : 115 : // return elapsed time in seconds 116 44486 : 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 44486 : 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 44486 : static std::pair<nanosecond_type, nanosecond_type> timebase = details::get_time_base(); 132 44486 : nanosecond_type clock = mach_absolute_time() - _start_time_wall; 133 44486 : 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 44486 : return return_value; 144 0 : } 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 :