1 //  runtime_resolution.cpp  ----------------------------------------------------------//
2 
3 //  Copyright 2008 Howard Hinnant
4 //  Copyright 2008 Beman Dawes
5 //  Copyright 2009 Vicente J. Botet Escriba
6 //  Copyright (c) Microsoft Corporation 2014
7 
8 //  Distributed under the Boost Software License, Version 1.0.
9 //  See http://www.boost.org/LICENSE_1_0.txt
10 
11 /*
12 This code was extracted by Vicente J. Botet Escriba from Beman Dawes time2_demo.cpp which
13 was derived by Beman Dawes from Howard Hinnant's time2_demo prototype.
14 Many thanks to Howard for making his code available under the Boost license.
15 The original code was modified to conform to Boost conventions and to section
16 20.9 Time utilities [time] of the C++ committee's working paper N2798.
17 See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf.
18 
19 time2_demo contained this comment:
20 
21     Much thanks to Andrei Alexandrescu,
22                    Walter Brown,
23                    Peter Dimov,
24                    Jeff Garland,
25                    Terry Golubiewski,
26                    Daniel Krugler,
27                    Anthony Williams.
28 */
29 #define _CRT_SECURE_NO_WARNINGS  // disable VC++ foolishness
30 
31 #include <boost/chrono/chrono.hpp>
32 #include <boost/type_traits.hpp>
33 
34 #include <iostream>
35 
36 #if defined(BOOST_CHRONO_MAC_API)
37 #include <sys/time.h> //for gettimeofday and timeval
38 #include <mach/mach_time.h>  // mach_absolute_time, mach_timebase_info_data_t
39 #endif
40 
41 #if defined(BOOST_CHRONO_WINDOWS_API)
42 #include <windows.h>
43 
44 namespace
45 {
46   #if defined UNDER_CE || BOOST_PLAT_WINDOWS_RUNTIME
47   // Windows CE and Windows store does not define timeval
48   struct timeval {
49           long    tv_sec;         /* seconds */
50           long    tv_usec;        /* and microseconds */
51   };
52   #endif
53 
gettimeofday(struct timeval * tp,void *)54   int gettimeofday(struct timeval * tp, void *)
55   {
56     FILETIME ft;
57   #if defined(UNDER_CE)
58     // Windows CE does not define GetSystemTimeAsFileTime so we do it in two steps.
59     SYSTEMTIME st;
60     ::GetSystemTime( &st );
61     ::SystemTimeToFileTime( &st, &ft );
62   #else
63     ::GetSystemTimeAsFileTime( &ft );  // never fails
64   #endif
65     long long t = (static_cast<long long>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
66   # if !defined( BOOST_MSVC ) || BOOST_MSVC > 1300 // > VC++ 7.0
67     t -= 116444736000000000LL;
68   # else
69     t -= 116444736000000000;
70   # endif
71     t /= 10;  // microseconds
72     tp->tv_sec = static_cast<long>( t / 1000000UL);
73     tp->tv_usec = static_cast<long>( t % 1000000UL);
74     return 0;
75   }
76 }  // unnamed namespace
77 
78 #endif
79 
80 // Handle duration with resolution not known until run time
81 using namespace boost::chrono;
82 
83 namespace runtime_resolution
84 {
85 
86 class duration
87 {
88 public:
89     typedef long long rep;
90 private:
91     rep rep_;
92 
93     static const double ticks_per_nanosecond;
94 
95 public:
96     typedef boost::chrono::duration<double, boost::nano> tonanosec;
97 
duration()98     duration() {} // = default;
duration(const rep & r)99     explicit duration(const rep& r) : rep_(r) {}
100 
101     // conversions
duration(const tonanosec & d)102     explicit duration(const tonanosec& d)
103             : rep_(static_cast<rep>(d.count() * ticks_per_nanosecond)) {}
104 
105     // explicit
convert_to_nanosec() const106     tonanosec convert_to_nanosec() const {return tonanosec(rep_/ticks_per_nanosecond);}
107 
108     // observer
109 
count() const110     rep count() const {return rep_;}
111 
112     // arithmetic
113 
operator +=(const duration & d)114     duration& operator+=(const duration& d) {rep_ += d.rep_; return *this;}
operator -=(const duration & d)115     duration& operator-=(const duration& d) {rep_ += d.rep_; return *this;}
operator *=(rep rhs)116     duration& operator*=(rep rhs)           {rep_ *= rhs; return *this;}
operator /=(rep rhs)117     duration& operator/=(rep rhs)           {rep_ /= rhs; return *this;}
118 
operator +() const119     duration  operator+() const {return *this;}
operator -() const120     duration  operator-() const {return duration(-rep_);}
operator ++()121     duration& operator++()      {++rep_; return *this;}
operator ++(int)122     duration  operator++(int)   {return duration(rep_++);}
operator --()123     duration& operator--()      {--rep_; return *this;}
operator --(int)124     duration  operator--(int)   {return duration(rep_--);}
125 
operator +(duration x,duration y)126     friend duration operator+(duration x, duration y) {return x += y;}
operator -(duration x,duration y)127     friend duration operator-(duration x, duration y) {return x -= y;}
operator *(duration x,rep y)128     friend duration operator*(duration x, rep y)      {return x *= y;}
operator *(rep x,duration y)129     friend duration operator*(rep x, duration y)      {return y *= x;}
operator /(duration x,rep y)130     friend duration operator/(duration x, rep y)      {return x /= y;}
131 
operator ==(duration x,duration y)132     friend bool operator==(duration x, duration y) {return x.rep_ == y.rep_;}
operator !=(duration x,duration y)133     friend bool operator!=(duration x, duration y) {return !(x == y);}
operator <(duration x,duration y)134     friend bool operator< (duration x, duration y) {return x.rep_ < y.rep_;}
operator <=(duration x,duration y)135     friend bool operator<=(duration x, duration y) {return !(y < x);}
operator >(duration x,duration y)136     friend bool operator> (duration x, duration y) {return y < x;}
operator >=(duration x,duration y)137     friend bool operator>=(duration x, duration y) {return !(x < y);}
138 };
139 
140 static
141 double
init_duration()142 init_duration()
143 {
144 #if defined(BOOST_CHRONO_WINDOWS_API)
145     return static_cast<double>(1) / 1000; // Windows FILETIME is 1 per microsec
146 #elif defined(BOOST_CHRONO_MAC_API)
147     mach_timebase_info_data_t MachInfo;
148     mach_timebase_info(&MachInfo);
149     return static_cast<double>(MachInfo.denom) / MachInfo.numer;
150 #elif defined(BOOST_CHRONO_POSIX_API)
151     return static_cast<double>(1) / 1000;
152 #endif
153 
154 }
155 
156 const double duration::ticks_per_nanosecond = init_duration();
157 
158 class clock;
159 
160 class time_point
161 {
162 public:
163     typedef runtime_resolution::clock clock;
164     typedef long long rep;
165 private:
166     rep rep_;
167 
168 
count() const169     rep count() const {return rep_;}
170 public:
171 
time_point()172     time_point() : rep_(0) {}
time_point(const duration & d)173     explicit time_point(const duration& d)
174         : rep_(d.count()) {}
175 
176     // arithmetic
177 
operator +=(const duration & d)178     time_point& operator+=(const duration& d) {rep_ += d.count(); return *this;}
operator -=(const duration & d)179     time_point& operator-=(const duration& d) {rep_ -= d.count(); return *this;}
180 
operator +(time_point x,duration y)181     friend time_point operator+(time_point x, duration y) {return x += y;}
operator +(duration x,time_point y)182     friend time_point operator+(duration x, time_point y) {return y += x;}
operator -(time_point x,duration y)183     friend time_point operator-(time_point x, duration y) {return x -= y;}
operator -(time_point x,time_point y)184     friend duration operator-(time_point x, time_point y) {return duration(x.rep_ - y.rep_);}
185 };
186 
187 
188 class clock
189 {
190 public:
191     typedef runtime_resolution::duration::rep rep;
192     typedef runtime_resolution::duration duration;
193     typedef runtime_resolution::time_point time_point;
194 
now()195     static time_point now()
196     {
197 
198 #if defined(BOOST_CHRONO_WINDOWS_API)
199       timeval tv;
200       gettimeofday( &tv, 0 );
201       return time_point(duration((static_cast<rep>(tv.tv_sec)<<32) | tv.tv_usec));
202 
203 #elif defined(BOOST_CHRONO_MAC_API)
204 
205       timeval tv;
206       gettimeofday( &tv, 0 );
207       return time_point(duration((static_cast<rep>(tv.tv_sec)<<32) | tv.tv_usec));
208 
209 #elif defined(BOOST_CHRONO_POSIX_API)
210     timespec ts;
211     ::clock_gettime( CLOCK_REALTIME, &ts );
212 
213     return time_point(duration((static_cast<rep>(ts.tv_sec)<<32) | ts.tv_nsec/1000));
214 
215 
216 #endif  // POSIX
217 
218     }
219 };
220 
test()221 void test()
222 {
223     std::cout << "runtime_resolution test\n";
224     clock::duration delay(boost::chrono::milliseconds(5));
225     clock::time_point start = clock::now();
226     while (clock::now() - start <= delay)
227       ;
228     clock::time_point stop = clock::now();
229     clock::duration elapsed = stop - start;
230     std::cout << "paused " <<
231     boost::chrono::nanoseconds(
232         boost::chrono::duration_cast<boost::chrono::nanoseconds>( elapsed.convert_to_nanosec() )).count()
233                            << " nanoseconds\n";
234 }
235 
236 }  // runtime_resolution
237 
238 
main()239 int main()
240 {
241     runtime_resolution::test();
242     return 0;
243 }
244 
245