[libcxx] r290803 - chrono: implement a Windows version of system_clock::now

Saleem Abdulrasool via cfe-commits cfe-commits at lists.llvm.org
Sun Jan 1 14:16:14 PST 2017


Thanks for the review on this!  I hope you wont mind taking a look at SVN
r290806 as well which tries to address the comments.

On Sun, Jan 1, 2017 at 1:09 PM, Howard Hinnant <howard.hinnant at gmail.com>
wrote:

> On Jan 1, 2017, at 3:20 PM, Saleem Abdulrasool via cfe-commits <
> cfe-commits at lists.llvm.org> wrote:
> >
> > Author: compnerd
> > Date: Sun Jan  1 14:20:41 2017
> > New Revision: 290803
> >
> > URL: http://llvm.org/viewvc/llvm-project?rev=290803&view=rev
> > Log:
> > chrono: implement a Windows version of system_clock::now
> >
> > system_clock::now is not entirely straight forward on Windows, which
> > does not have a clock_gettime function.
> >
> > GetSystemTimeAsFileTime gives us the value relative to the NT epoch (Jan
> > 1 1601) rather than the Unix epoch (Jan 1 1970).  However, this function
> > has a low resolution (~10ms).  Newer versions of Windows provide
> > GetSystemTimePreciseAsFileTime which gives us a much more accurate time
> > (<1us).  Unfortunately, the latter is only available on Windows 8+ when
> > targeting desktop apps.
> >
> > Modified:
> >    libcxx/trunk/src/chrono.cpp
> >
> > Modified: libcxx/trunk/src/chrono.cpp
> > URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/
> chrono.cpp?rev=290803&r1=290802&r2=290803&view=diff
> > ============================================================
> ==================
> > --- libcxx/trunk/src/chrono.cpp (original)
> > +++ libcxx/trunk/src/chrono.cpp Sun Jan  1 14:20:41 2017
> > @@ -12,9 +12,18 @@
> > #include "system_error"  // __throw_system_error
> > #include <time.h>        // clock_gettime, CLOCK_MONOTONIC and
> CLOCK_REALTIME
> >
> > +#if defined(_WIN32)
> > +#define WIN32_LEAN_AND_MEAN
> > +#define VC_EXTRA_LEAN
> > +#include <Windows.h>
> > +#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
> > +#include <winapifamily.h>
> > +#endif
> > +#else
> > #if !defined(CLOCK_REALTIME)
> > #include <sys/time.h>        // for gettimeofday and timeval
> > #endif
> > +#endif
> >
> > #if !defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK) &&
> !defined(CLOCK_MONOTONIC)
> > #if __APPLE__
> > @@ -36,6 +45,28 @@ const bool system_clock::is_steady;
> > system_clock::time_point
> > system_clock::now() _NOEXCEPT
> > {
> > +#if defined(_WIN32)
> > +  // The Windows epoch is Jan 1 1601, the Unix epoch Jan 1 1970.  The
> difference
> > +  // in nanoseconds is the windows epoch offset.
> > +  static const constexpr __int64 kWindowsEpochOffset =
> 0x19db1ded53e8000;
>
> This is the correct difference, but the comment is wrong.  It isn’t
> nanoseconds.  It is 100ns units.
>
> Maybe I got the math wrong, but this was supposed to be ns, which is why I
bounced between 100ns and ns.


> > +
> > +  FILETIME ftSystemTime;
> > +#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
> > +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
> > +  GetSystemTimePreciseAsFileTime(&ftSystemTime);
> > +#else
> > +  GetSystemTimeAsFileTime(&ftSystemTime);
> > +#endif
> > +#else
> > +  GetSystemTimeAsFileTime(&ftSystemTime);
> > +#endif
> > +  __int64 llWinTimeNS =
> > +      ((static_cast<__int64>(ftSystemTime.dwHighDateTime) << 32) |
> > +       static_cast<__int64>(ftSystemTime.dwLowDateTime)) *
> > +      100;
>
> The * 100 will overflow.  The * 100 converts 100ns to ns.  ns has a signed
> 64bit range of +/- 292 years, which is greater than the difference between
> the two epochs.
>
>
This is what I get for trying to be clever and not use durations.


> > +  return time_point(duration_cast<duration>(
> > +      (nanoseconds(llWinTimeNS - kWindowsEpochOffset))));
>
> It really isn’t desirable to bounce this off of nanoseconds because of the
> overflow.


Yeap;  This now becomes a duration_cast<duration>(filetime_duration) ...
letting durations figure out how to do the conversion from 100ns
(filetime_duration) to us (sytem_clock::duration) units.


> > +#else
> > #ifdef CLOCK_REALTIME
> >     struct timespec tp;
> >     if (0 != clock_gettime(CLOCK_REALTIME, &tp))
> > @@ -46,6 +77,7 @@ system_clock::now() _NOEXCEPT
> >     gettimeofday(&tv, 0);
> >     return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec));
> > #endif  // CLOCK_REALTIME
> > +#endif
> > }
>
> Thank you for preserving the 1970 epoch.  Though not currently specified
> by the standard, it is very important.  And hopefully will be specified by
> a future standard.
>
> Here is code written by Billy O’Neal (MS) doing the conversion you’re
> looking for:
>
> https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes#FILETIME
>
> It has no intermediate results with precision finer than 100ns.  The range
> of the 64bit 100ns unit goes out to +/- 29 thousand years.


Thanks for the pointer!


>
> Howard
>
>


-- 
Saleem Abdulrasool
compnerd (at) compnerd (dot) org
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170101/068d3685/attachment.html>


More information about the cfe-commits mailing list