Coverage for /Syzygy/trace/common/clock.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
93.8%60640.C++source

Line-by-line coverage:

   1    :  // Copyright 2013 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/trace/common/clock.h"
  16    :  
  17    :  #include <WinBase.h>
  18    :  #include <type_traits>
  19    :  
  20    :  #include "base/logging.h"
  21    :  #include "base/win/registry.h"
  22    :  
  23    :  namespace trace {
  24    :  namespace common {
  25    :  
  26    :  namespace {
  27    :  
  28    :  union LargeInteger {
  29    :    LARGE_INTEGER li;
  30    :    uint64 ui64;
  31    :    COMPILE_ASSERT(sizeof(LARGE_INTEGER) == sizeof(uint64),
  32    :                   LARGE_INTEGER_and_uint64_must_have_same_size);
  33    :  };
  34    :  
  35    :  typedef ULONGLONG (*GetTickCount64Ptr)();
  36    :  
  37    :  }  // namespace
  38    :  
  39  E :  void GetTickTimerInfo(TimerInfo* timer_info) {
  40  E :    DCHECK(timer_info != NULL);
  41    :  
  42    :    // Ticks are in milliseconds.
  43  E :    timer_info->frequency = 1000;
  44    :  
  45    :    // The resolution of the tick counter varies, but is documented to have a
  46    :    // worst case of 16 ms.
  47  E :    timer_info->resolution = 16;
  48  E :  }
  49    :  
  50  E :  void GetTscTimerInfo(TimerInfo* timer_info) {
  51  E :    DCHECK(timer_info != NULL);
  52    :  
  53  E :    ::memset(timer_info, 0, sizeof(TimerInfo));
  54    :  
  55    :    // Check the TscInvariant flag to see if we can rely on TSC as a constant
  56    :    // rate timer that is synchronous across all cores. This is in
  57    :    // CPUID.80000007.EDX[8].
  58    :    int info[4];
  59  E :    ::__cpuid(info, 0x80000007);
  60  E :    if ((info[3] & (1 << 8)) == 0)
  61  i :      return;
  62    :  
  63    :    // Get the CPU frequency. If all is well, this is the frequency of the TSC
  64    :    // timer.
  65  E :    base::win::RegKey cpureg;
  66  E :    DWORD mhz = 0;
  67    :    if (cpureg.Open(HKEY_LOCAL_MACHINE,
  68    :                    L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
  69    :                    KEY_READ) != 0 ||
  70  E :        cpureg.ReadValueDW(L"~MHz", &mhz) != 0) {
  71  i :      LOG(WARNING) << "Unable to get CPU frequency from registry.";
  72  i :      return;
  73    :    }
  74    :  
  75    :    // An invariant TSC is documented to run at the fastest clock speed of the
  76    :    // CPU.
  77  E :    timer_info->frequency = mhz * 1000000;
  78  E :    timer_info->resolution = 1;
  79  E :  }
  80    :  
  81    :  bool TimerToFileTime(const FILETIME& file_time_ref,
  82    :                       const TimerInfo& timer_info,
  83    :                       const uint64& timer_ref,
  84    :                       const uint64& timer_value,
  85  E :                       FILETIME* file_time) {
  86  E :    DCHECK(file_time != NULL);
  87    :  
  88    :    // This only works if we have valid timer information.
  89  E :    if (timer_info.frequency == 0 || timer_info.resolution == 0)
  90  E :      return false;
  91    :  
  92    :    uint64 t = (static_cast<uint64>(file_time_ref.dwHighDateTime) << 32) |
  93  E :        file_time_ref.dwLowDateTime;
  94    :  
  95    :      // The filetime is expressed in 100ns intervals.
  96  E :    double cycles_per_100ns = 1.0e-7 * timer_info.frequency;
  97    :    double elapsed_100ns_intervals =
  98  E :        (static_cast<double>(timer_value) - timer_ref) / cycles_per_100ns;
  99  E :    double new_file_time = t + elapsed_100ns_intervals;
 100  E :    if (new_file_time < 0)
 101  E :      return false;
 102    :  
 103  E :    t = static_cast<uint64>(new_file_time);
 104  E :    file_time->dwLowDateTime = t & 0xFFFFFFFF;
 105  E :    file_time->dwHighDateTime = t >> 32;
 106    :  
 107  E :    return true;
 108  E :  }
 109    :  
 110  E :  uint64 GetTicks() {
 111    :    // We can't explicitly invoke GetTickCount64 as it doesn't exist in Windows
 112    :    // XP. This would make all of our trace code unable to be run on XP systems.
 113    :    const GetTickCount64Ptr kUninitialized =
 114  E :        reinterpret_cast<GetTickCount64Ptr>(1);
 115  E :    static GetTickCount64Ptr get_tick_count64 = kUninitialized;
 116    :  
 117    :    // This is racy but safe. Worst case scenario multiple threads do the lookup,
 118    :    // each of them writing the same value to |get_tick_count64|. Since writes are
 119    :    // atomic all will be well by the time it is dereferenced.
 120  E :    if (get_tick_count64 == kUninitialized) {
 121  E :      HMODULE kernel32 = ::GetModuleHandleA("kernel32.dll");
 122  E :      DCHECK(kernel32 != NULL);
 123    :  
 124    :      get_tick_count64 = reinterpret_cast<GetTickCount64Ptr>(
 125  E :          ::GetProcAddress(kernel32, "GetTickCount64"));
 126    :    }
 127  E :    DCHECK(get_tick_count64 != kUninitialized);
 128    :  
 129  E :    if (get_tick_count64 != NULL)
 130  E :      return (*get_tick_count64)();
 131    :  
 132    :    // Fall back to using the 32-bit counter if the 64-bit one is not available.
 133  i :    return ::GetTickCount();
 134  E :  }
 135    :  
 136  E :  void GetClockInfo(ClockInfo* clock_info) {
 137  E :    DCHECK(clock_info != NULL);
 138  E :    ::memset(clock_info, 0, sizeof(ClockInfo));
 139  E :    GetTickTimerInfo(&clock_info->ticks_info);
 140  E :    GetTscTimerInfo(&clock_info->tsc_info);
 141    :  
 142  E :    ::GetSystemTimeAsFileTime(&clock_info->file_time);
 143    :  
 144    :    // The TSC timer may not always be valid/available.
 145  E :    if (clock_info->tsc_info.frequency)
 146  E :      clock_info->tsc_reference = GetTsc();
 147    :  
 148    :    // The tick counter is always valid.
 149  E :    clock_info->ticks_reference = GetTicks();
 150  E :  }
 151    :  
 152    :  bool TicksToFileTime(const ClockInfo& clock_info,
 153    :                       uint64 ticks,
 154  E :                       FILETIME* file_time) {
 155  E :    DCHECK(file_time != NULL);
 156    :    return TimerToFileTime(clock_info.file_time,
 157    :                           clock_info.ticks_info,
 158    :                           clock_info.ticks_reference,
 159    :                           ticks,
 160  E :                           file_time);
 161  E :  }
 162    :  
 163    :  bool TscToFileTime(const ClockInfo& clock_info,
 164    :                     uint64 tsc,
 165  E :                     FILETIME* file_time) {
 166  E :    DCHECK(file_time != NULL);
 167    :    return TimerToFileTime(clock_info.file_time,
 168    :                           clock_info.tsc_info,
 169    :                           clock_info.tsc_reference,
 170    :                           tsc,
 171  E :                           file_time);
 172  E :  }
 173    :  
 174    :  }  // namespace common
 175    :  }  // namespace trace

Coverage information generated Thu Mar 26 16:15:41 2015.