OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 | 5 |
6 // Windows Timer Primer | 6 // Windows Timer Primer |
7 // | 7 // |
8 // A good article: http://www.ddj.com/windows/184416651 | 8 // A good article: http://www.ddj.com/windows/184416651 |
9 // A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258 | 9 // A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258 |
10 // | 10 // |
(...skipping 18 matching lines...) Expand all Loading... |
29 // | 29 // |
30 // To work around all this, we're going to generally use timeGetTime(). We | 30 // To work around all this, we're going to generally use timeGetTime(). We |
31 // will only increase the system-wide timer if we're not running on battery | 31 // will only increase the system-wide timer if we're not running on battery |
32 // power. | 32 // power. |
33 | 33 |
34 #include "base/time/time.h" | 34 #include "base/time/time.h" |
35 | 35 |
36 #pragma comment(lib, "winmm.lib") | 36 #pragma comment(lib, "winmm.lib") |
37 #include <windows.h> | 37 #include <windows.h> |
38 #include <mmsystem.h> | 38 #include <mmsystem.h> |
| 39 #include <stdint.h> |
39 | 40 |
40 #include "base/basictypes.h" | 41 #include "base/basictypes.h" |
41 #include "base/cpu.h" | 42 #include "base/cpu.h" |
42 #include "base/lazy_instance.h" | 43 #include "base/lazy_instance.h" |
43 #include "base/logging.h" | 44 #include "base/logging.h" |
44 #include "base/synchronization/lock.h" | 45 #include "base/synchronization/lock.h" |
45 | 46 |
| 47 using base::ThreadTicks; |
46 using base::Time; | 48 using base::Time; |
47 using base::TimeDelta; | 49 using base::TimeDelta; |
48 using base::TimeTicks; | 50 using base::TimeTicks; |
| 51 using base::TraceTicks; |
49 | 52 |
50 namespace { | 53 namespace { |
51 | 54 |
52 // From MSDN, FILETIME "Contains a 64-bit value representing the number of | 55 // From MSDN, FILETIME "Contains a 64-bit value representing the number of |
53 // 100-nanosecond intervals since January 1, 1601 (UTC)." | 56 // 100-nanosecond intervals since January 1, 1601 (UTC)." |
54 int64 FileTimeToMicroseconds(const FILETIME& ft) { | 57 int64 FileTimeToMicroseconds(const FILETIME& ft) { |
55 // Need to bit_cast to fix alignment, then divide by 10 to convert | 58 // Need to bit_cast to fix alignment, then divide by 10 to convert |
56 // 100-nanoseconds to milliseconds. This only works on little-endian | 59 // 100-nanoseconds to milliseconds. This only works on little-endian |
57 // machines. | 60 // machines. |
58 return bit_cast<int64, FILETIME>(ft) / 10; | 61 return bit_cast<int64, FILETIME>(ft) / 10; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 | 102 |
100 } // namespace | 103 } // namespace |
101 | 104 |
102 // Time ----------------------------------------------------------------------- | 105 // Time ----------------------------------------------------------------------- |
103 | 106 |
104 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01 | 107 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01 |
105 // 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the | 108 // 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the |
106 // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding | 109 // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding |
107 // 1700, 1800, and 1900. | 110 // 1700, 1800, and 1900. |
108 // static | 111 // static |
109 const int64 Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000); | 112 const int64 Time::kTimeTToMicrosecondsOffset = INT64_C(11644473600000000); |
110 | 113 |
111 // static | 114 // static |
112 Time Time::Now() { | 115 Time Time::Now() { |
113 if (initial_time == 0) | 116 if (initial_time == 0) |
114 InitializeClock(); | 117 InitializeClock(); |
115 | 118 |
116 // We implement time using the high-resolution timers so that we can get | 119 // We implement time using the high-resolution timers so that we can get |
117 // timeouts which are smaller than 10-15ms. If we just used | 120 // timeouts which are smaller than 10-15ms. If we just used |
118 // CurrentWallclockMicroseconds(), we'd have the less-granular timer. | 121 // CurrentWallclockMicroseconds(), we'd have the less-granular timer. |
119 // | 122 // |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 // easy to use a Singleton without even knowing it, and that may lead to many | 324 // easy to use a Singleton without even knowing it, and that may lead to many |
322 // gotchas). Its impact on startup time should be negligible due to low-level | 325 // gotchas). Its impact on startup time should be negligible due to low-level |
323 // nature of time code. | 326 // nature of time code. |
324 base::Lock g_rollover_lock; | 327 base::Lock g_rollover_lock; |
325 | 328 |
326 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic | 329 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic |
327 // because it returns the number of milliseconds since Windows has started, | 330 // because it returns the number of milliseconds since Windows has started, |
328 // which will roll over the 32-bit value every ~49 days. We try to track | 331 // which will roll over the 32-bit value every ~49 days. We try to track |
329 // rollover ourselves, which works if TimeTicks::Now() is called at least every | 332 // rollover ourselves, which works if TimeTicks::Now() is called at least every |
330 // 49 days. | 333 // 49 days. |
331 TimeTicks RolloverProtectedNow() { | 334 TimeDelta RolloverProtectedNow() { |
332 base::AutoLock locked(g_rollover_lock); | 335 base::AutoLock locked(g_rollover_lock); |
333 // We should hold the lock while calling tick_function to make sure that | 336 // We should hold the lock while calling tick_function to make sure that |
334 // we keep last_seen_now stay correctly in sync. | 337 // we keep last_seen_now stay correctly in sync. |
335 DWORD now = g_tick_function(); | 338 DWORD now = g_tick_function(); |
336 if (now < g_last_seen_now) | 339 if (now < g_last_seen_now) |
337 g_rollover_ms += 0x100000000I64; // ~49.7 days. | 340 g_rollover_ms += 0x100000000I64; // ~49.7 days. |
338 g_last_seen_now = now; | 341 g_last_seen_now = now; |
339 return TimeTicks() + TimeDelta::FromMilliseconds(now + g_rollover_ms); | 342 return TimeDelta::FromMilliseconds(now + g_rollover_ms); |
340 } | 343 } |
341 | 344 |
342 // Discussion of tick counter options on Windows: | 345 // Discussion of tick counter options on Windows: |
343 // | 346 // |
344 // (1) CPU cycle counter. (Retrieved via RDTSC) | 347 // (1) CPU cycle counter. (Retrieved via RDTSC) |
345 // The CPU counter provides the highest resolution time stamp and is the least | 348 // The CPU counter provides the highest resolution time stamp and is the least |
346 // expensive to retrieve. However, on older CPUs, two issues can affect its | 349 // expensive to retrieve. However, on older CPUs, two issues can affect its |
347 // reliability: First it is maintained per processor and not synchronized | 350 // reliability: First it is maintained per processor and not synchronized |
348 // between processors. Also, the counters will change frequency due to thermal | 351 // between processors. Also, the counters will change frequency due to thermal |
349 // and power changes, and stop in some states. | 352 // and power changes, and stop in some states. |
(...skipping 17 matching lines...) Expand all Loading... |
367 // give consistent results on a multiprocessor computer, but for older CPUs it | 370 // give consistent results on a multiprocessor computer, but for older CPUs it |
368 // can be unreliable due bugs in BIOS or HAL. | 371 // can be unreliable due bugs in BIOS or HAL. |
369 // | 372 // |
370 // (3) System time. The system time provides a low-resolution (from ~1 to ~15.6 | 373 // (3) System time. The system time provides a low-resolution (from ~1 to ~15.6 |
371 // milliseconds) time stamp but is comparatively less expensive to retrieve and | 374 // milliseconds) time stamp but is comparatively less expensive to retrieve and |
372 // more reliable. Time::EnableHighResolutionTimer() and | 375 // more reliable. Time::EnableHighResolutionTimer() and |
373 // Time::ActivateHighResolutionTimer() can be called to alter the resolution of | 376 // Time::ActivateHighResolutionTimer() can be called to alter the resolution of |
374 // this timer; and also other Windows applications can alter it, affecting this | 377 // this timer; and also other Windows applications can alter it, affecting this |
375 // one. | 378 // one. |
376 | 379 |
377 using NowFunction = TimeTicks (*)(void); | 380 using NowFunction = TimeDelta (*)(void); |
378 | 381 |
379 TimeTicks InitialNowFunction(); | 382 TimeDelta InitialNowFunction(); |
380 TimeTicks InitialSystemTraceNowFunction(); | 383 TimeDelta InitialSystemTraceNowFunction(); |
381 | 384 |
382 // See "threading notes" in InitializeNowFunctionPointers() for details on how | 385 // See "threading notes" in InitializeNowFunctionPointers() for details on how |
383 // concurrent reads/writes to these globals has been made safe. | 386 // concurrent reads/writes to these globals has been made safe. |
384 NowFunction g_now_function = &InitialNowFunction; | 387 NowFunction g_now_function = &InitialNowFunction; |
385 NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction; | 388 NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction; |
386 int64 g_qpc_ticks_per_second = 0; | 389 int64 g_qpc_ticks_per_second = 0; |
387 | 390 |
388 // As of January 2015, use of <atomic> is forbidden in Chromium code. This is | 391 // As of January 2015, use of <atomic> is forbidden in Chromium code. This is |
389 // what std::atomic_thread_fence does on Windows on all Intel architectures when | 392 // what std::atomic_thread_fence does on Windows on all Intel architectures when |
390 // the memory_order argument is anything but std::memory_order_seq_cst: | 393 // the memory_order argument is anything but std::memory_order_seq_cst: |
(...skipping 15 matching lines...) Expand all Loading... |
406 // Otherwise, calculate microseconds in a round about manner to avoid | 409 // Otherwise, calculate microseconds in a round about manner to avoid |
407 // overflow and precision issues. | 410 // overflow and precision issues. |
408 int64 whole_seconds = qpc_value / g_qpc_ticks_per_second; | 411 int64 whole_seconds = qpc_value / g_qpc_ticks_per_second; |
409 int64 leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second); | 412 int64 leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second); |
410 return TimeDelta::FromMicroseconds( | 413 return TimeDelta::FromMicroseconds( |
411 (whole_seconds * Time::kMicrosecondsPerSecond) + | 414 (whole_seconds * Time::kMicrosecondsPerSecond) + |
412 ((leftover_ticks * Time::kMicrosecondsPerSecond) / | 415 ((leftover_ticks * Time::kMicrosecondsPerSecond) / |
413 g_qpc_ticks_per_second)); | 416 g_qpc_ticks_per_second)); |
414 } | 417 } |
415 | 418 |
416 TimeTicks QPCNow() { | 419 TimeDelta QPCNow() { |
417 LARGE_INTEGER now; | 420 LARGE_INTEGER now; |
418 QueryPerformanceCounter(&now); | 421 QueryPerformanceCounter(&now); |
419 return TimeTicks() + QPCValueToTimeDelta(now.QuadPart); | 422 return QPCValueToTimeDelta(now.QuadPart); |
420 } | 423 } |
421 | 424 |
422 bool IsBuggyAthlon(const base::CPU& cpu) { | 425 bool IsBuggyAthlon(const base::CPU& cpu) { |
423 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. | 426 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. |
424 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; | 427 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; |
425 } | 428 } |
426 | 429 |
427 void InitializeNowFunctionPointers() { | 430 void InitializeNowFunctionPointers() { |
428 LARGE_INTEGER ticks_per_sec = {0}; | 431 LARGE_INTEGER ticks_per_sec = {0}; |
429 if (!QueryPerformanceFrequency(&ticks_per_sec)) | 432 if (!QueryPerformanceFrequency(&ticks_per_sec)) |
430 ticks_per_sec.QuadPart = 0; | 433 ticks_per_sec.QuadPart = 0; |
431 | 434 |
432 // If Windows cannot provide a QPC implementation, both Now() and | 435 // If Windows cannot provide a QPC implementation, both TimeTicks::Now() and |
433 // NowFromSystemTraceTime() must use the low-resolution clock. | 436 // TraceTicks::Now() must use the low-resolution clock. |
434 // | 437 // |
435 // If the QPC implementation is expensive and/or unreliable, Now() will use | 438 // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now() |
436 // the low-resolution clock, but NowFromSystemTraceTime() will use the QPC (in | 439 // will use the low-resolution clock, but TraceTicks::Now() will use the QPC |
437 // the hope that it is still useful for tracing purposes). A CPU lacking a | 440 // (in the hope that it is still useful for tracing purposes). A CPU lacking a |
438 // non-stop time counter will cause Windows to provide an alternate QPC | 441 // non-stop time counter will cause Windows to provide an alternate QPC |
439 // implementation that works, but is expensive to use. Certain Athlon CPUs are | 442 // implementation that works, but is expensive to use. Certain Athlon CPUs are |
440 // known to make the QPC implementation unreliable. | 443 // known to make the QPC implementation unreliable. |
441 // | 444 // |
442 // Otherwise, both Now functions can use the high-resolution QPC clock. As of | 445 // Otherwise, both Now functions can use the high-resolution QPC clock. As of |
443 // 4 January 2015, ~68% of users fall within this category. | 446 // 4 January 2015, ~68% of users fall within this category. |
444 NowFunction now_function; | 447 NowFunction now_function; |
445 NowFunction system_trace_now_function; | 448 NowFunction system_trace_now_function; |
446 base::CPU cpu; | 449 base::CPU cpu; |
447 if (ticks_per_sec.QuadPart <= 0) { | 450 if (ticks_per_sec.QuadPart <= 0) { |
(...skipping 13 matching lines...) Expand all Loading... |
461 // Threading note 2: A release fence is placed here to ensure, from the | 464 // Threading note 2: A release fence is placed here to ensure, from the |
462 // perspective of other threads using the function pointers, that the | 465 // perspective of other threads using the function pointers, that the |
463 // assignment to |g_qpc_ticks_per_second| happens before the function pointers | 466 // assignment to |g_qpc_ticks_per_second| happens before the function pointers |
464 // are changed. | 467 // are changed. |
465 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; | 468 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; |
466 ATOMIC_THREAD_FENCE(memory_order_release); | 469 ATOMIC_THREAD_FENCE(memory_order_release); |
467 g_now_function = now_function; | 470 g_now_function = now_function; |
468 g_system_trace_now_function = system_trace_now_function; | 471 g_system_trace_now_function = system_trace_now_function; |
469 } | 472 } |
470 | 473 |
471 TimeTicks InitialNowFunction() { | 474 TimeDelta InitialNowFunction() { |
472 InitializeNowFunctionPointers(); | 475 InitializeNowFunctionPointers(); |
473 return g_now_function(); | 476 return g_now_function(); |
474 } | 477 } |
475 | 478 |
476 TimeTicks InitialSystemTraceNowFunction() { | 479 TimeDelta InitialSystemTraceNowFunction() { |
477 InitializeNowFunctionPointers(); | 480 InitializeNowFunctionPointers(); |
478 return g_system_trace_now_function(); | 481 return g_system_trace_now_function(); |
479 } | 482 } |
480 | 483 |
481 } // namespace | 484 } // namespace |
482 | 485 |
483 // static | 486 // static |
484 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( | 487 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( |
485 TickFunctionType ticker) { | 488 TickFunctionType ticker) { |
486 base::AutoLock locked(g_rollover_lock); | 489 base::AutoLock locked(g_rollover_lock); |
487 TickFunctionType old = g_tick_function; | 490 TickFunctionType old = g_tick_function; |
488 g_tick_function = ticker; | 491 g_tick_function = ticker; |
489 g_rollover_ms = 0; | 492 g_rollover_ms = 0; |
490 g_last_seen_now = 0; | 493 g_last_seen_now = 0; |
491 return old; | 494 return old; |
492 } | 495 } |
493 | 496 |
494 // static | 497 // static |
495 TimeTicks TimeTicks::Now() { | 498 TimeTicks TimeTicks::Now() { |
496 return g_now_function(); | 499 return TimeTicks() + g_now_function(); |
497 } | 500 } |
498 | 501 |
499 // static | 502 // static |
500 bool TimeTicks::IsHighResolution() { | 503 bool TimeTicks::IsHighResolution() { |
501 if (g_now_function == &InitialNowFunction) | 504 if (g_now_function == &InitialNowFunction) |
502 InitializeNowFunctionPointers(); | 505 InitializeNowFunctionPointers(); |
503 return g_now_function == &QPCNow; | 506 return g_now_function == &QPCNow; |
504 } | 507 } |
505 | 508 |
506 // static | 509 // static |
507 TimeTicks TimeTicks::ThreadNow() { | 510 ThreadTicks ThreadTicks::Now() { |
508 NOTREACHED(); | 511 NOTREACHED(); |
509 return TimeTicks(); | 512 return ThreadTicks(); |
510 } | 513 } |
511 | 514 |
512 // static | 515 // static |
513 TimeTicks TimeTicks::NowFromSystemTraceTime() { | 516 TraceTicks TraceTicks::Now() { |
514 return g_system_trace_now_function(); | 517 return TraceTicks() + g_system_trace_now_function(); |
515 } | 518 } |
516 | 519 |
517 // static | 520 // static |
518 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { | 521 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { |
519 return TimeTicks() + QPCValueToTimeDelta(qpc_value); | 522 return TimeTicks() + QPCValueToTimeDelta(qpc_value); |
520 } | 523 } |
521 | 524 |
522 // TimeDelta ------------------------------------------------------------------ | 525 // TimeDelta ------------------------------------------------------------------ |
523 | 526 |
524 // static | 527 // static |
525 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 528 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
526 return QPCValueToTimeDelta(qpc_value); | 529 return QPCValueToTimeDelta(qpc_value); |
527 } | 530 } |
OLD | NEW |