LCOV - code coverage report
Current view: directory - src/shared/platform/win - time_win.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 76 1 1.3 %
Date: 2014-09-25 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2011 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : 
       8                 : // Make sure that winmm.lib is added to the linker's input.
       9                 : #pragma comment(lib, "winmm.lib")
      10                 : #include "native_client/src/include/portability.h"
      11                 : #include <mmsystem.h>
      12                 : #include <windows.h>
      13                 : 
      14                 : #include "native_client/src/include/checked_cast.h"
      15                 : #include "native_client/src/shared/platform/win/time.h"
      16                 : #include "native_client/src/shared/platform/win/lock.h"
      17                 : 
      18                 : namespace {
      19                 : 
      20                 : // From MSDN, FILETIME "Contains a 64-bit value representing the number of
      21                 : // 100-nanosecond intervals since January 1, 1601 (UTC)."
      22               0 : int64_t FileTimeToMicroseconds(const FILETIME& ft) {
      23                 :   // Need to nacl_bit_cast to fix alignment, then divide by 10 to convert
      24                 :   // 100-nanoseconds to milliseconds. This only works on little-endian
      25                 :   // machines.
      26               0 :   return nacl_bit_cast<int64_t, FILETIME>(ft) / 10;
      27               0 : }
      28                 : 
      29               0 : void MicrosecondsToFileTime(int64_t us, FILETIME* ft) {
      30                 : /*  DCHECK(us >= 0) << "Time is less than 0, negative values are not "
      31                 :  *      "representable in FILETIME";
      32                 :  */
      33                 : 
      34                 :   // Multiply by 10 to convert milliseconds to 100-nanoseconds. Nacl_bit_cast
      35                 :   // will handle alignment problems. This only works on little-endian machines.
      36               0 :   *ft = nacl_bit_cast<FILETIME, int64_t>(us * 10);
      37               0 : }
      38                 : 
      39                 : }  // namespace
      40                 : 
      41                 : // Time -----------------------------------------------------------------------
      42                 : 
      43                 : // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01
      44                 : // 00:00:00 UTC.  ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
      45                 : // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
      46                 : // 1700, 1800, and 1900.
      47                 : // static
      48                 : const int64_t NaCl::Time::kTimeTToMicrosecondsOffset =
      49                 :     GG_INT64_C(11644473600000000);
      50                 : 
      51                 : // static
      52               0 : int64_t NaCl::Time::CurrentWallclockMicroseconds() {
      53                 :   FILETIME ft;
      54               0 :   ::GetSystemTimeAsFileTime(&ft);
      55               0 :   return FileTimeToMicroseconds(ft);
      56               0 : }
      57                 : 
      58                 : // static
      59               0 : NaCl::Time NaCl::Time::FromFileTime(FILETIME ft) {
      60               0 :   return Time(FileTimeToMicroseconds(ft));
      61               0 : }
      62                 : 
      63               0 : FILETIME NaCl::Time::ToFileTime() const {
      64                 :   FILETIME utc_ft;
      65               0 :   MicrosecondsToFileTime(us_, &utc_ft);
      66               0 :   return utc_ft;
      67               0 : }
      68                 : 
      69                 : // static
      70               0 : NaCl::Time NaCl::Time::FromExploded(bool is_local, const Exploded& exploded) {
      71                 :   // Create the system struct representing our exploded time. It will either be
      72                 :   // in local time or UTC.
      73                 :   SYSTEMTIME st;
      74               0 :   st.wYear = nacl::assert_cast<WORD>(exploded.year);
      75               0 :   st.wMonth = nacl::assert_cast<WORD>(exploded.month);
      76               0 :   st.wDayOfWeek = nacl::assert_cast<WORD>(exploded.day_of_week);
      77               0 :   st.wDay = nacl::assert_cast<WORD>(exploded.day_of_month);
      78               0 :   st.wHour = nacl::assert_cast<WORD>(exploded.hour);
      79               0 :   st.wMinute = nacl::assert_cast<WORD>(exploded.minute);
      80               0 :   st.wSecond = nacl::assert_cast<WORD>(exploded.second);
      81               0 :   st.wMilliseconds = nacl::assert_cast<WORD>(exploded.millisecond);
      82                 : 
      83                 :   // Convert to FILETIME.
      84                 :   FILETIME ft;
      85               0 :   if (!SystemTimeToFileTime(&st, &ft)) {
      86                 :     // NOTREACHED() << "Unable to convert time";
      87               0 :     return Time(0);
      88                 :   }
      89                 : 
      90                 :   // Ensure that it's in UTC.
      91               0 :   if (is_local) {
      92                 :     FILETIME utc_ft;
      93               0 :     LocalFileTimeToFileTime(&ft, &utc_ft);
      94               0 :     return Time(FileTimeToMicroseconds(utc_ft));
      95                 :   }
      96               0 :   return Time(FileTimeToMicroseconds(ft));
      97               0 : }
      98                 : 
      99               0 : void NaCl::Time::Explode(bool is_local, Exploded* exploded) const {
     100                 :   // FILETIME in UTC.
     101                 :   FILETIME utc_ft;
     102               0 :   MicrosecondsToFileTime(us_, &utc_ft);
     103                 : 
     104                 :   // FILETIME in local time if necessary.
     105               0 :   BOOL success = TRUE;
     106                 :   FILETIME ft;
     107               0 :   if (is_local)
     108               0 :     success = FileTimeToLocalFileTime(&utc_ft, &ft);
     109               0 :   else
     110               0 :     ft = utc_ft;
     111                 : 
     112                 :   // FILETIME in SYSTEMTIME (exploded).
     113                 :   SYSTEMTIME st;
     114               0 :   if (!success || !FileTimeToSystemTime(&ft, &st)) {
     115                 :     // NOTREACHED() << "Unable to convert time, don't know why";
     116               0 :     ZeroMemory(exploded, sizeof(*exploded));
     117               0 :     return;
     118                 :   }
     119                 : 
     120               0 :   exploded->year = st.wYear;
     121               0 :   exploded->month = st.wMonth;
     122               0 :   exploded->day_of_week = st.wDayOfWeek;
     123               0 :   exploded->day_of_month = st.wDay;
     124               0 :   exploded->hour = st.wHour;
     125               0 :   exploded->minute = st.wMinute;
     126               0 :   exploded->second = st.wSecond;
     127               0 :   exploded->millisecond = st.wMilliseconds;
     128               0 : }
     129                 : 
     130                 : // TimeTicks ------------------------------------------------------------------
     131                 : NaCl::TimeTicks::TickFunction NaCl::TimeTicks::tick_function_=
     132              36 :     reinterpret_cast<TickFunction>(&timeGetTime);
     133                 : 
     134                 : // static
     135               0 : NaCl::TimeTicks NaCl::TimeTicks::Now() {
     136                 :   // Uses the multimedia timers on Windows to get a higher resolution clock.
     137                 :   // timeGetTime() provides a resolution which is variable depending on
     138                 :   // hardware and system configuration.  It can also be changed by other
     139                 :   // apps.  This class does not attempt to change the resolution of the
     140                 :   // timer, because we don't want to affect other applications.
     141                 : 
     142                 :   // timeGetTime() should at least be accurate to ~5ms on all systems.
     143                 :   // timeGetTime() returns a 32-bit millisecond counter which has rollovers
     144                 :   // every ~49 days.
     145                 :   static DWORD last_tick_count = 0;
     146                 :   static int64_t tick_rollover_accum = 0;
     147                 :   static Lock* tick_lock = NULL;  // To protect during rollover periods.
     148                 : 
     149                 :   // Lazily create the lock we use.
     150               0 :   if (!tick_lock) {
     151               0 :     Lock* new_lock = new Lock;
     152                 :     if (InterlockedCompareExchangePointer(
     153               0 :         reinterpret_cast<PVOID*>(&tick_lock), new_lock, NULL)) {
     154               0 :       delete new_lock;
     155                 :     }
     156                 :   }
     157                 : 
     158                 :   // Atomically protect the low and high 32bit values for time.
     159                 :   // In the future we may be able to optimize with
     160                 :   // InterlockedCompareExchange64, but that doesn't work on XP.
     161                 :   DWORD tick_count;
     162                 :   int64_t rollover_count;
     163                 :   /* lint complains about this, ignore */{
     164               0 :     AutoLock lock(*tick_lock);
     165               0 :     tick_count = tick_function_();
     166               0 :     if (tick_count < last_tick_count)
     167               0 :       tick_rollover_accum += GG_INT64_C(0x100000000);
     168                 : 
     169               0 :     last_tick_count = tick_count;
     170               0 :     rollover_count = tick_rollover_accum;
     171               0 :   }
     172                 : 
     173                 :   // GetTickCount returns milliseconds, we want microseconds.
     174                 :   return TimeTicks((tick_count + rollover_count) *
     175               0 :                    Time::kMicrosecondsPerMillisecond);
     176               0 : }
     177                 : 
     178                 : // Overview of time counters:
     179                 : // (1) CPU cycle counter. (Retrieved via RDTSC)
     180                 : // The CPU counter provides the highest resolution time stamp and is the least
     181                 : // expensive to retrieve. However, the CPU counter is unreliable and should not
     182                 : // be used in production. Its biggest issue is that it is per processor and it
     183                 : // is not synchronized between processors. Also, on some computers, the counters
     184                 : // will change frequency due to thermal and power changes, and stop in some
     185                 : // states.
     186                 : //
     187                 : // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
     188                 : // resolution (100 nanoseconds) time stamp but is comparatively more expensive
     189                 : // to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
     190                 : // (with some help from ACPI).
     191                 : // According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
     192                 : // in the worst case, it gets the counter from the rollover interrupt on the
     193                 : // programmable interrupt timer. In best cases, the HAL may conclude that the
     194                 : // RDTSC counter runs at a constant frequency, then it uses that instead. On
     195                 : // multiprocessor machines, it will try to verify the values returned from
     196                 : // RDTSC on each processor are consistent with each other, and apply a handful
     197                 : // of workarounds for known buggy hardware. In other words, QPC is supposed to
     198                 : // give consistent result on a multiprocessor computer, but it is unreliable in
     199                 : // reality due to bugs in BIOS or HAL on some, especially old computers.
     200                 : // With recent updates on HAL and newer BIOS, QPC is getting more reliable but
     201                 : // it should be used with caution.
     202                 : //
     203                 : // (3) System time. The system time provides a low-resolution (typically 10ms
     204                 : // to 55 milliseconds) time stamp but is comparatively less expensive to
     205                 : // retrieve and more reliable.
     206                 : 
     207                 : // static
     208               0 : NaCl::TimeTicks NaCl::TimeTicks::UnreliableHighResNow() {
     209                 :   // Cached clock frequency -> microseconds. This assumes that the clock
     210                 :   // frequency is faster than one microsecond (which is 1MHz, should be OK).
     211                 :   static int64_t ticks_per_microsecond = 0;
     212                 : 
     213               0 :   if (ticks_per_microsecond == 0) {
     214               0 :     LARGE_INTEGER ticks_per_sec = { 0, 0 };
     215               0 :     if (!QueryPerformanceFrequency(&ticks_per_sec))
     216               0 :       return TimeTicks(0);  // Broken, we don't guarantee this function works.
     217                 :     ticks_per_microsecond =
     218               0 :         ticks_per_sec.QuadPart / Time::kMicrosecondsPerSecond;
     219                 :   }
     220                 : 
     221                 :   LARGE_INTEGER now;
     222               0 :   QueryPerformanceCounter(&now);
     223               0 :   return TimeTicks(now.QuadPart / ticks_per_microsecond);
     224               0 : }

Generated by: LCOV version 1.7