security/sandbox/chromium/base/time/time_win.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5
michael@0 6 // Windows Timer Primer
michael@0 7 //
michael@0 8 // A good article: http://www.ddj.com/windows/184416651
michael@0 9 // A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258
michael@0 10 //
michael@0 11 // The default windows timer, GetSystemTimeAsFileTime is not very precise.
michael@0 12 // It is only good to ~15.5ms.
michael@0 13 //
michael@0 14 // QueryPerformanceCounter is the logical choice for a high-precision timer.
michael@0 15 // However, it is known to be buggy on some hardware. Specifically, it can
michael@0 16 // sometimes "jump". On laptops, QPC can also be very expensive to call.
michael@0 17 // It's 3-4x slower than timeGetTime() on desktops, but can be 10x slower
michael@0 18 // on laptops. A unittest exists which will show the relative cost of various
michael@0 19 // timers on any system.
michael@0 20 //
michael@0 21 // The next logical choice is timeGetTime(). timeGetTime has a precision of
michael@0 22 // 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other
michael@0 23 // applications on the system. By default, precision is only 15.5ms.
michael@0 24 // Unfortunately, we don't want to call timeBeginPeriod because we don't
michael@0 25 // want to affect other applications. Further, on mobile platforms, use of
michael@0 26 // faster multimedia timers can hurt battery life. See the intel
michael@0 27 // article about this here:
michael@0 28 // http://softwarecommunity.intel.com/articles/eng/1086.htm
michael@0 29 //
michael@0 30 // To work around all this, we're going to generally use timeGetTime(). We
michael@0 31 // will only increase the system-wide timer if we're not running on battery
michael@0 32 // power. Using timeBeginPeriod(1) is a requirement in order to make our
michael@0 33 // message loop waits have the same resolution that our time measurements
michael@0 34 // do. Otherwise, WaitForSingleObject(..., 1) will no less than 15ms when
michael@0 35 // there is nothing else to waken the Wait.
michael@0 36
michael@0 37 #include "base/time/time.h"
michael@0 38
michael@0 39 #pragma comment(lib, "winmm.lib")
michael@0 40 #include <windows.h>
michael@0 41 #include <mmsystem.h>
michael@0 42
michael@0 43 #include "base/basictypes.h"
michael@0 44 #include "base/cpu.h"
michael@0 45 #include "base/logging.h"
michael@0 46 #include "base/memory/singleton.h"
michael@0 47 #include "base/synchronization/lock.h"
michael@0 48
michael@0 49 using base::Time;
michael@0 50 using base::TimeDelta;
michael@0 51 using base::TimeTicks;
michael@0 52
michael@0 53 namespace {
michael@0 54
michael@0 55 // From MSDN, FILETIME "Contains a 64-bit value representing the number of
michael@0 56 // 100-nanosecond intervals since January 1, 1601 (UTC)."
michael@0 57 int64 FileTimeToMicroseconds(const FILETIME& ft) {
michael@0 58 // Need to bit_cast to fix alignment, then divide by 10 to convert
michael@0 59 // 100-nanoseconds to milliseconds. This only works on little-endian
michael@0 60 // machines.
michael@0 61 return bit_cast<int64, FILETIME>(ft) / 10;
michael@0 62 }
michael@0 63
michael@0 64 void MicrosecondsToFileTime(int64 us, FILETIME* ft) {
michael@0 65 DCHECK_GE(us, 0LL) << "Time is less than 0, negative values are not "
michael@0 66 "representable in FILETIME";
michael@0 67
michael@0 68 // Multiply by 10 to convert milliseconds to 100-nanoseconds. Bit_cast will
michael@0 69 // handle alignment problems. This only works on little-endian machines.
michael@0 70 *ft = bit_cast<FILETIME, int64>(us * 10);
michael@0 71 }
michael@0 72
michael@0 73 int64 CurrentWallclockMicroseconds() {
michael@0 74 FILETIME ft;
michael@0 75 ::GetSystemTimeAsFileTime(&ft);
michael@0 76 return FileTimeToMicroseconds(ft);
michael@0 77 }
michael@0 78
michael@0 79 // Time between resampling the un-granular clock for this API. 60 seconds.
michael@0 80 const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond;
michael@0 81
michael@0 82 int64 initial_time = 0;
michael@0 83 TimeTicks initial_ticks;
michael@0 84
michael@0 85 void InitializeClock() {
michael@0 86 initial_ticks = TimeTicks::Now();
michael@0 87 initial_time = CurrentWallclockMicroseconds();
michael@0 88 }
michael@0 89
michael@0 90 } // namespace
michael@0 91
michael@0 92 // Time -----------------------------------------------------------------------
michael@0 93
michael@0 94 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01
michael@0 95 // 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
michael@0 96 // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
michael@0 97 // 1700, 1800, and 1900.
michael@0 98 // static
michael@0 99 const int64 Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000);
michael@0 100
michael@0 101 bool Time::high_resolution_timer_enabled_ = false;
michael@0 102 int Time::high_resolution_timer_activated_ = 0;
michael@0 103
michael@0 104 // static
michael@0 105 Time Time::Now() {
michael@0 106 if (initial_time == 0)
michael@0 107 InitializeClock();
michael@0 108
michael@0 109 // We implement time using the high-resolution timers so that we can get
michael@0 110 // timeouts which are smaller than 10-15ms. If we just used
michael@0 111 // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
michael@0 112 //
michael@0 113 // To make this work, we initialize the clock (initial_time) and the
michael@0 114 // counter (initial_ctr). To compute the initial time, we can check
michael@0 115 // the number of ticks that have elapsed, and compute the delta.
michael@0 116 //
michael@0 117 // To avoid any drift, we periodically resync the counters to the system
michael@0 118 // clock.
michael@0 119 while (true) {
michael@0 120 TimeTicks ticks = TimeTicks::Now();
michael@0 121
michael@0 122 // Calculate the time elapsed since we started our timer
michael@0 123 TimeDelta elapsed = ticks - initial_ticks;
michael@0 124
michael@0 125 // Check if enough time has elapsed that we need to resync the clock.
michael@0 126 if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) {
michael@0 127 InitializeClock();
michael@0 128 continue;
michael@0 129 }
michael@0 130
michael@0 131 return Time(elapsed + Time(initial_time));
michael@0 132 }
michael@0 133 }
michael@0 134
michael@0 135 // static
michael@0 136 Time Time::NowFromSystemTime() {
michael@0 137 // Force resync.
michael@0 138 InitializeClock();
michael@0 139 return Time(initial_time);
michael@0 140 }
michael@0 141
michael@0 142 // static
michael@0 143 Time Time::FromFileTime(FILETIME ft) {
michael@0 144 if (bit_cast<int64, FILETIME>(ft) == 0)
michael@0 145 return Time();
michael@0 146 if (ft.dwHighDateTime == std::numeric_limits<DWORD>::max() &&
michael@0 147 ft.dwLowDateTime == std::numeric_limits<DWORD>::max())
michael@0 148 return Max();
michael@0 149 return Time(FileTimeToMicroseconds(ft));
michael@0 150 }
michael@0 151
michael@0 152 FILETIME Time::ToFileTime() const {
michael@0 153 if (is_null())
michael@0 154 return bit_cast<FILETIME, int64>(0);
michael@0 155 if (is_max()) {
michael@0 156 FILETIME result;
michael@0 157 result.dwHighDateTime = std::numeric_limits<DWORD>::max();
michael@0 158 result.dwLowDateTime = std::numeric_limits<DWORD>::max();
michael@0 159 return result;
michael@0 160 }
michael@0 161 FILETIME utc_ft;
michael@0 162 MicrosecondsToFileTime(us_, &utc_ft);
michael@0 163 return utc_ft;
michael@0 164 }
michael@0 165
michael@0 166 // static
michael@0 167 void Time::EnableHighResolutionTimer(bool enable) {
michael@0 168 // Test for single-threaded access.
michael@0 169 static PlatformThreadId my_thread = PlatformThread::CurrentId();
michael@0 170 DCHECK(PlatformThread::CurrentId() == my_thread);
michael@0 171
michael@0 172 if (high_resolution_timer_enabled_ == enable)
michael@0 173 return;
michael@0 174
michael@0 175 high_resolution_timer_enabled_ = enable;
michael@0 176 }
michael@0 177
michael@0 178 // static
michael@0 179 bool Time::ActivateHighResolutionTimer(bool activating) {
michael@0 180 if (!high_resolution_timer_enabled_ && activating)
michael@0 181 return false;
michael@0 182
michael@0 183 // Using anything other than 1ms makes timers granular
michael@0 184 // to that interval.
michael@0 185 const int kMinTimerIntervalMs = 1;
michael@0 186 MMRESULT result;
michael@0 187 if (activating) {
michael@0 188 result = timeBeginPeriod(kMinTimerIntervalMs);
michael@0 189 high_resolution_timer_activated_++;
michael@0 190 } else {
michael@0 191 result = timeEndPeriod(kMinTimerIntervalMs);
michael@0 192 high_resolution_timer_activated_--;
michael@0 193 }
michael@0 194 return result == TIMERR_NOERROR;
michael@0 195 }
michael@0 196
michael@0 197 // static
michael@0 198 bool Time::IsHighResolutionTimerInUse() {
michael@0 199 // Note: we should track the high_resolution_timer_activated_ value
michael@0 200 // under a lock if we want it to be accurate in a system with multiple
michael@0 201 // message loops. We don't do that - because we don't want to take the
michael@0 202 // expense of a lock for this. We *only* track this value so that unit
michael@0 203 // tests can see if the high resolution timer is on or off.
michael@0 204 return high_resolution_timer_enabled_ &&
michael@0 205 high_resolution_timer_activated_ > 0;
michael@0 206 }
michael@0 207
michael@0 208 // static
michael@0 209 Time Time::FromExploded(bool is_local, const Exploded& exploded) {
michael@0 210 // Create the system struct representing our exploded time. It will either be
michael@0 211 // in local time or UTC.
michael@0 212 SYSTEMTIME st;
michael@0 213 st.wYear = exploded.year;
michael@0 214 st.wMonth = exploded.month;
michael@0 215 st.wDayOfWeek = exploded.day_of_week;
michael@0 216 st.wDay = exploded.day_of_month;
michael@0 217 st.wHour = exploded.hour;
michael@0 218 st.wMinute = exploded.minute;
michael@0 219 st.wSecond = exploded.second;
michael@0 220 st.wMilliseconds = exploded.millisecond;
michael@0 221
michael@0 222 FILETIME ft;
michael@0 223 bool success = true;
michael@0 224 // Ensure that it's in UTC.
michael@0 225 if (is_local) {
michael@0 226 SYSTEMTIME utc_st;
michael@0 227 success = TzSpecificLocalTimeToSystemTime(NULL, &st, &utc_st) &&
michael@0 228 SystemTimeToFileTime(&utc_st, &ft);
michael@0 229 } else {
michael@0 230 success = !!SystemTimeToFileTime(&st, &ft);
michael@0 231 }
michael@0 232
michael@0 233 if (!success) {
michael@0 234 NOTREACHED() << "Unable to convert time";
michael@0 235 return Time(0);
michael@0 236 }
michael@0 237 return Time(FileTimeToMicroseconds(ft));
michael@0 238 }
michael@0 239
michael@0 240 void Time::Explode(bool is_local, Exploded* exploded) const {
michael@0 241 if (us_ < 0LL) {
michael@0 242 // We are not able to convert it to FILETIME.
michael@0 243 ZeroMemory(exploded, sizeof(*exploded));
michael@0 244 return;
michael@0 245 }
michael@0 246
michael@0 247 // FILETIME in UTC.
michael@0 248 FILETIME utc_ft;
michael@0 249 MicrosecondsToFileTime(us_, &utc_ft);
michael@0 250
michael@0 251 // FILETIME in local time if necessary.
michael@0 252 bool success = true;
michael@0 253 // FILETIME in SYSTEMTIME (exploded).
michael@0 254 SYSTEMTIME st;
michael@0 255 if (is_local) {
michael@0 256 SYSTEMTIME utc_st;
michael@0 257 // We don't use FileTimeToLocalFileTime here, since it uses the current
michael@0 258 // settings for the time zone and daylight saving time. Therefore, if it is
michael@0 259 // daylight saving time, it will take daylight saving time into account,
michael@0 260 // even if the time you are converting is in standard time.
michael@0 261 success = FileTimeToSystemTime(&utc_ft, &utc_st) &&
michael@0 262 SystemTimeToTzSpecificLocalTime(NULL, &utc_st, &st);
michael@0 263 } else {
michael@0 264 success = !!FileTimeToSystemTime(&utc_ft, &st);
michael@0 265 }
michael@0 266
michael@0 267 if (!success) {
michael@0 268 NOTREACHED() << "Unable to convert time, don't know why";
michael@0 269 ZeroMemory(exploded, sizeof(*exploded));
michael@0 270 return;
michael@0 271 }
michael@0 272
michael@0 273 exploded->year = st.wYear;
michael@0 274 exploded->month = st.wMonth;
michael@0 275 exploded->day_of_week = st.wDayOfWeek;
michael@0 276 exploded->day_of_month = st.wDay;
michael@0 277 exploded->hour = st.wHour;
michael@0 278 exploded->minute = st.wMinute;
michael@0 279 exploded->second = st.wSecond;
michael@0 280 exploded->millisecond = st.wMilliseconds;
michael@0 281 }
michael@0 282
michael@0 283 // TimeTicks ------------------------------------------------------------------
michael@0 284 namespace {
michael@0 285
michael@0 286 // We define a wrapper to adapt between the __stdcall and __cdecl call of the
michael@0 287 // mock function, and to avoid a static constructor. Assigning an import to a
michael@0 288 // function pointer directly would require setup code to fetch from the IAT.
michael@0 289 DWORD timeGetTimeWrapper() {
michael@0 290 return timeGetTime();
michael@0 291 }
michael@0 292
michael@0 293 DWORD (*tick_function)(void) = &timeGetTimeWrapper;
michael@0 294
michael@0 295 // Accumulation of time lost due to rollover (in milliseconds).
michael@0 296 int64 rollover_ms = 0;
michael@0 297
michael@0 298 // The last timeGetTime value we saw, to detect rollover.
michael@0 299 DWORD last_seen_now = 0;
michael@0 300
michael@0 301 // Lock protecting rollover_ms and last_seen_now.
michael@0 302 // Note: this is a global object, and we usually avoid these. However, the time
michael@0 303 // code is low-level, and we don't want to use Singletons here (it would be too
michael@0 304 // easy to use a Singleton without even knowing it, and that may lead to many
michael@0 305 // gotchas). Its impact on startup time should be negligible due to low-level
michael@0 306 // nature of time code.
michael@0 307 base::Lock rollover_lock;
michael@0 308
michael@0 309 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic
michael@0 310 // because it returns the number of milliseconds since Windows has started,
michael@0 311 // which will roll over the 32-bit value every ~49 days. We try to track
michael@0 312 // rollover ourselves, which works if TimeTicks::Now() is called at least every
michael@0 313 // 49 days.
michael@0 314 TimeDelta RolloverProtectedNow() {
michael@0 315 base::AutoLock locked(rollover_lock);
michael@0 316 // We should hold the lock while calling tick_function to make sure that
michael@0 317 // we keep last_seen_now stay correctly in sync.
michael@0 318 DWORD now = tick_function();
michael@0 319 if (now < last_seen_now)
michael@0 320 rollover_ms += 0x100000000I64; // ~49.7 days.
michael@0 321 last_seen_now = now;
michael@0 322 return TimeDelta::FromMilliseconds(now + rollover_ms);
michael@0 323 }
michael@0 324
michael@0 325 bool IsBuggyAthlon(const base::CPU& cpu) {
michael@0 326 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is
michael@0 327 // unreliable. Fallback to low-res clock.
michael@0 328 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15;
michael@0 329 }
michael@0 330
michael@0 331 // Overview of time counters:
michael@0 332 // (1) CPU cycle counter. (Retrieved via RDTSC)
michael@0 333 // The CPU counter provides the highest resolution time stamp and is the least
michael@0 334 // expensive to retrieve. However, the CPU counter is unreliable and should not
michael@0 335 // be used in production. Its biggest issue is that it is per processor and it
michael@0 336 // is not synchronized between processors. Also, on some computers, the counters
michael@0 337 // will change frequency due to thermal and power changes, and stop in some
michael@0 338 // states.
michael@0 339 //
michael@0 340 // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
michael@0 341 // resolution (100 nanoseconds) time stamp but is comparatively more expensive
michael@0 342 // to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
michael@0 343 // (with some help from ACPI).
michael@0 344 // According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
michael@0 345 // in the worst case, it gets the counter from the rollover interrupt on the
michael@0 346 // programmable interrupt timer. In best cases, the HAL may conclude that the
michael@0 347 // RDTSC counter runs at a constant frequency, then it uses that instead. On
michael@0 348 // multiprocessor machines, it will try to verify the values returned from
michael@0 349 // RDTSC on each processor are consistent with each other, and apply a handful
michael@0 350 // of workarounds for known buggy hardware. In other words, QPC is supposed to
michael@0 351 // give consistent result on a multiprocessor computer, but it is unreliable in
michael@0 352 // reality due to bugs in BIOS or HAL on some, especially old computers.
michael@0 353 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but
michael@0 354 // it should be used with caution.
michael@0 355 //
michael@0 356 // (3) System time. The system time provides a low-resolution (typically 10ms
michael@0 357 // to 55 milliseconds) time stamp but is comparatively less expensive to
michael@0 358 // retrieve and more reliable.
michael@0 359 class HighResNowSingleton {
michael@0 360 public:
michael@0 361 static HighResNowSingleton* GetInstance() {
michael@0 362 return Singleton<HighResNowSingleton>::get();
michael@0 363 }
michael@0 364
michael@0 365 bool IsUsingHighResClock() {
michael@0 366 return ticks_per_second_ != 0.0;
michael@0 367 }
michael@0 368
michael@0 369 void DisableHighResClock() {
michael@0 370 ticks_per_second_ = 0.0;
michael@0 371 }
michael@0 372
michael@0 373 TimeDelta Now() {
michael@0 374 if (IsUsingHighResClock())
michael@0 375 return TimeDelta::FromMicroseconds(UnreliableNow());
michael@0 376
michael@0 377 // Just fallback to the slower clock.
michael@0 378 return RolloverProtectedNow();
michael@0 379 }
michael@0 380
michael@0 381 int64 GetQPCDriftMicroseconds() {
michael@0 382 if (!IsUsingHighResClock())
michael@0 383 return 0;
michael@0 384 return abs((UnreliableNow() - ReliableNow()) - skew_);
michael@0 385 }
michael@0 386
michael@0 387 int64 QPCValueToMicroseconds(LONGLONG qpc_value) {
michael@0 388 if (!ticks_per_second_)
michael@0 389 return 0;
michael@0 390
michael@0 391 // Intentionally calculate microseconds in a round about manner to avoid
michael@0 392 // overflow and precision issues. Think twice before simplifying!
michael@0 393 int64 whole_seconds = qpc_value / ticks_per_second_;
michael@0 394 int64 leftover_ticks = qpc_value % ticks_per_second_;
michael@0 395 int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) +
michael@0 396 ((leftover_ticks * Time::kMicrosecondsPerSecond) /
michael@0 397 ticks_per_second_);
michael@0 398 return microseconds;
michael@0 399 }
michael@0 400
michael@0 401 private:
michael@0 402 HighResNowSingleton()
michael@0 403 : ticks_per_second_(0),
michael@0 404 skew_(0) {
michael@0 405 InitializeClock();
michael@0 406
michael@0 407 base::CPU cpu;
michael@0 408 if (IsBuggyAthlon(cpu))
michael@0 409 DisableHighResClock();
michael@0 410 }
michael@0 411
michael@0 412 // Synchronize the QPC clock with GetSystemTimeAsFileTime.
michael@0 413 void InitializeClock() {
michael@0 414 LARGE_INTEGER ticks_per_sec = {0};
michael@0 415 if (!QueryPerformanceFrequency(&ticks_per_sec))
michael@0 416 return; // Broken, we don't guarantee this function works.
michael@0 417 ticks_per_second_ = ticks_per_sec.QuadPart;
michael@0 418
michael@0 419 skew_ = UnreliableNow() - ReliableNow();
michael@0 420 }
michael@0 421
michael@0 422 // Get the number of microseconds since boot in an unreliable fashion.
michael@0 423 int64 UnreliableNow() {
michael@0 424 LARGE_INTEGER now;
michael@0 425 QueryPerformanceCounter(&now);
michael@0 426 return QPCValueToMicroseconds(now.QuadPart);
michael@0 427 }
michael@0 428
michael@0 429 // Get the number of microseconds since boot in a reliable fashion.
michael@0 430 int64 ReliableNow() {
michael@0 431 return RolloverProtectedNow().InMicroseconds();
michael@0 432 }
michael@0 433
michael@0 434 int64 ticks_per_second_; // 0 indicates QPF failed and we're broken.
michael@0 435 int64 skew_; // Skew between lo-res and hi-res clocks (for debugging).
michael@0 436
michael@0 437 friend struct DefaultSingletonTraits<HighResNowSingleton>;
michael@0 438 };
michael@0 439
michael@0 440 TimeDelta HighResNowWrapper() {
michael@0 441 return HighResNowSingleton::GetInstance()->Now();
michael@0 442 }
michael@0 443
michael@0 444 typedef TimeDelta (*NowFunction)(void);
michael@0 445 NowFunction now_function = RolloverProtectedNow;
michael@0 446
michael@0 447 bool CPUReliablySupportsHighResTime() {
michael@0 448 base::CPU cpu;
michael@0 449 if (!cpu.has_non_stop_time_stamp_counter())
michael@0 450 return false;
michael@0 451
michael@0 452 if (IsBuggyAthlon(cpu))
michael@0 453 return false;
michael@0 454
michael@0 455 return true;
michael@0 456 }
michael@0 457
michael@0 458 } // namespace
michael@0 459
michael@0 460 // static
michael@0 461 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
michael@0 462 TickFunctionType ticker) {
michael@0 463 base::AutoLock locked(rollover_lock);
michael@0 464 TickFunctionType old = tick_function;
michael@0 465 tick_function = ticker;
michael@0 466 rollover_ms = 0;
michael@0 467 last_seen_now = 0;
michael@0 468 return old;
michael@0 469 }
michael@0 470
michael@0 471 // static
michael@0 472 bool TimeTicks::SetNowIsHighResNowIfSupported() {
michael@0 473 if (!CPUReliablySupportsHighResTime()) {
michael@0 474 return false;
michael@0 475 }
michael@0 476
michael@0 477 now_function = HighResNowWrapper;
michael@0 478 return true;
michael@0 479 }
michael@0 480
michael@0 481 // static
michael@0 482 TimeTicks TimeTicks::Now() {
michael@0 483 return TimeTicks() + now_function();
michael@0 484 }
michael@0 485
michael@0 486 // static
michael@0 487 TimeTicks TimeTicks::HighResNow() {
michael@0 488 return TimeTicks() + HighResNowSingleton::GetInstance()->Now();
michael@0 489 }
michael@0 490
michael@0 491 // static
michael@0 492 TimeTicks TimeTicks::ThreadNow() {
michael@0 493 NOTREACHED();
michael@0 494 return TimeTicks();
michael@0 495 }
michael@0 496
michael@0 497 // static
michael@0 498 TimeTicks TimeTicks::NowFromSystemTraceTime() {
michael@0 499 return HighResNow();
michael@0 500 }
michael@0 501
michael@0 502 // static
michael@0 503 int64 TimeTicks::GetQPCDriftMicroseconds() {
michael@0 504 return HighResNowSingleton::GetInstance()->GetQPCDriftMicroseconds();
michael@0 505 }
michael@0 506
michael@0 507 // static
michael@0 508 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) {
michael@0 509 return TimeTicks(
michael@0 510 HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value));
michael@0 511 }
michael@0 512
michael@0 513 // static
michael@0 514 bool TimeTicks::IsHighResClockWorking() {
michael@0 515 return HighResNowSingleton::GetInstance()->IsUsingHighResClock();
michael@0 516 }
michael@0 517
michael@0 518 TimeTicks TimeTicks::UnprotectedNow() {
michael@0 519 if (now_function == HighResNowWrapper) {
michael@0 520 return Now();
michael@0 521 } else {
michael@0 522 return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime());
michael@0 523 }
michael@0 524 }
michael@0 525
michael@0 526 // TimeDelta ------------------------------------------------------------------
michael@0 527
michael@0 528 // static
michael@0 529 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) {
michael@0 530 return TimeDelta(
michael@0 531 HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value));
michael@0 532 }

mercurial