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()70 inline 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()94 inline 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