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 26 matching lines...) Expand all Loading... |
37 #include <windows.h> | 37 #include <windows.h> |
38 #include <mmsystem.h> | 38 #include <mmsystem.h> |
39 #include <stdint.h> | 39 #include <stdint.h> |
40 | 40 |
41 #include "base/basictypes.h" | 41 #include "base/basictypes.h" |
42 #include "base/cpu.h" | 42 #include "base/cpu.h" |
43 #include "base/lazy_instance.h" | 43 #include "base/lazy_instance.h" |
44 #include "base/logging.h" | 44 #include "base/logging.h" |
45 #include "base/synchronization/lock.h" | 45 #include "base/synchronization/lock.h" |
46 | 46 |
| 47 using base::ThreadTicks; |
47 using base::Time; | 48 using base::Time; |
48 using base::TimeDelta; | 49 using base::TimeDelta; |
49 using base::TimeTicks; | 50 using base::TimeTicks; |
| 51 using base::TraceTicks; |
50 | 52 |
51 namespace { | 53 namespace { |
52 | 54 |
53 // 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 |
54 // 100-nanosecond intervals since January 1, 1601 (UTC)." | 56 // 100-nanosecond intervals since January 1, 1601 (UTC)." |
55 int64 FileTimeToMicroseconds(const FILETIME& ft) { | 57 int64 FileTimeToMicroseconds(const FILETIME& ft) { |
56 // 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 |
57 // 100-nanoseconds to milliseconds. This only works on little-endian | 59 // 100-nanoseconds to milliseconds. This only works on little-endian |
58 // machines. | 60 // machines. |
59 return bit_cast<int64, FILETIME>(ft) / 10; | 61 return bit_cast<int64, FILETIME>(ft) / 10; |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 // 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 |
323 // 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 |
324 // nature of time code. | 326 // nature of time code. |
325 base::Lock g_rollover_lock; | 327 base::Lock g_rollover_lock; |
326 | 328 |
327 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic | 329 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic |
328 // because it returns the number of milliseconds since Windows has started, | 330 // because it returns the number of milliseconds since Windows has started, |
329 // 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 |
330 // 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 |
331 // 49 days. | 333 // 49 days. |
332 TimeTicks RolloverProtectedNow() { | 334 TimeDelta RolloverProtectedNow() { |
333 base::AutoLock locked(g_rollover_lock); | 335 base::AutoLock locked(g_rollover_lock); |
334 // 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 |
335 // we keep last_seen_now stay correctly in sync. | 337 // we keep last_seen_now stay correctly in sync. |
336 DWORD now = g_tick_function(); | 338 DWORD now = g_tick_function(); |
337 if (now < g_last_seen_now) | 339 if (now < g_last_seen_now) |
338 g_rollover_ms += 0x100000000I64; // ~49.7 days. | 340 g_rollover_ms += 0x100000000I64; // ~49.7 days. |
339 g_last_seen_now = now; | 341 g_last_seen_now = now; |
340 return TimeTicks() + TimeDelta::FromMilliseconds(now + g_rollover_ms); | 342 return TimeDelta::FromMilliseconds(now + g_rollover_ms); |
341 } | 343 } |
342 | 344 |
343 // Discussion of tick counter options on Windows: | 345 // Discussion of tick counter options on Windows: |
344 // | 346 // |
345 // (1) CPU cycle counter. (Retrieved via RDTSC) | 347 // (1) CPU cycle counter. (Retrieved via RDTSC) |
346 // 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 |
347 // 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 |
348 // reliability: First it is maintained per processor and not synchronized | 350 // reliability: First it is maintained per processor and not synchronized |
349 // between processors. Also, the counters will change frequency due to thermal | 351 // between processors. Also, the counters will change frequency due to thermal |
350 // and power changes, and stop in some states. | 352 // and power changes, and stop in some states. |
(...skipping 17 matching lines...) Expand all Loading... |
368 // 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 |
369 // can be unreliable due bugs in BIOS or HAL. | 371 // can be unreliable due bugs in BIOS or HAL. |
370 // | 372 // |
371 // (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 |
372 // milliseconds) time stamp but is comparatively less expensive to retrieve and | 374 // milliseconds) time stamp but is comparatively less expensive to retrieve and |
373 // more reliable. Time::EnableHighResolutionTimer() and | 375 // more reliable. Time::EnableHighResolutionTimer() and |
374 // Time::ActivateHighResolutionTimer() can be called to alter the resolution of | 376 // Time::ActivateHighResolutionTimer() can be called to alter the resolution of |
375 // 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 |
376 // one. | 378 // one. |
377 | 379 |
378 using NowFunction = TimeTicks (*)(void); | 380 using NowFunction = TimeDelta (*)(void); |
379 | 381 |
380 TimeTicks InitialNowFunction(); | 382 TimeDelta InitialNowFunction(); |
381 TimeTicks InitialSystemTraceNowFunction(); | 383 TimeDelta InitialSystemTraceNowFunction(); |
382 | 384 |
383 // See "threading notes" in InitializeNowFunctionPointers() for details on how | 385 // See "threading notes" in InitializeNowFunctionPointers() for details on how |
384 // concurrent reads/writes to these globals has been made safe. | 386 // concurrent reads/writes to these globals has been made safe. |
385 NowFunction g_now_function = &InitialNowFunction; | 387 NowFunction g_now_function = &InitialNowFunction; |
386 NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction; | 388 NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction; |
387 int64 g_qpc_ticks_per_second = 0; | 389 int64 g_qpc_ticks_per_second = 0; |
388 | 390 |
389 // 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 |
390 // 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 |
391 // 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... |
407 // Otherwise, calculate microseconds in a round about manner to avoid | 409 // Otherwise, calculate microseconds in a round about manner to avoid |
408 // overflow and precision issues. | 410 // overflow and precision issues. |
409 int64 whole_seconds = qpc_value / g_qpc_ticks_per_second; | 411 int64 whole_seconds = qpc_value / g_qpc_ticks_per_second; |
410 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); |
411 return TimeDelta::FromMicroseconds( | 413 return TimeDelta::FromMicroseconds( |
412 (whole_seconds * Time::kMicrosecondsPerSecond) + | 414 (whole_seconds * Time::kMicrosecondsPerSecond) + |
413 ((leftover_ticks * Time::kMicrosecondsPerSecond) / | 415 ((leftover_ticks * Time::kMicrosecondsPerSecond) / |
414 g_qpc_ticks_per_second)); | 416 g_qpc_ticks_per_second)); |
415 } | 417 } |
416 | 418 |
417 TimeTicks QPCNow() { | 419 TimeDelta QPCNow() { |
418 LARGE_INTEGER now; | 420 LARGE_INTEGER now; |
419 QueryPerformanceCounter(&now); | 421 QueryPerformanceCounter(&now); |
420 return TimeTicks() + QPCValueToTimeDelta(now.QuadPart); | 422 return QPCValueToTimeDelta(now.QuadPart); |
421 } | 423 } |
422 | 424 |
423 bool IsBuggyAthlon(const base::CPU& cpu) { | 425 bool IsBuggyAthlon(const base::CPU& cpu) { |
424 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. | 426 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. |
425 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; | 427 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; |
426 } | 428 } |
427 | 429 |
428 void InitializeNowFunctionPointers() { | 430 void InitializeNowFunctionPointers() { |
429 LARGE_INTEGER ticks_per_sec = {0}; | 431 LARGE_INTEGER ticks_per_sec = {0}; |
430 if (!QueryPerformanceFrequency(&ticks_per_sec)) | 432 if (!QueryPerformanceFrequency(&ticks_per_sec)) |
431 ticks_per_sec.QuadPart = 0; | 433 ticks_per_sec.QuadPart = 0; |
432 | 434 |
433 // If Windows cannot provide a QPC implementation, both Now() and | 435 // If Windows cannot provide a QPC implementation, both TimeTicks::Now() and |
434 // NowFromSystemTraceTime() must use the low-resolution clock. | 436 // TraceTicks::Now() must use the low-resolution clock. |
435 // | 437 // |
436 // If the QPC implementation is expensive and/or unreliable, Now() will use | 438 // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now() |
437 // 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 |
438 // 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 |
439 // 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 |
440 // 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 |
441 // known to make the QPC implementation unreliable. | 443 // known to make the QPC implementation unreliable. |
442 // | 444 // |
443 // 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 |
444 // 4 January 2015, ~68% of users fall within this category. | 446 // 4 January 2015, ~68% of users fall within this category. |
445 NowFunction now_function; | 447 NowFunction now_function; |
446 NowFunction system_trace_now_function; | 448 NowFunction system_trace_now_function; |
447 base::CPU cpu; | 449 base::CPU cpu; |
448 if (ticks_per_sec.QuadPart <= 0) { | 450 if (ticks_per_sec.QuadPart <= 0) { |
(...skipping 13 matching lines...) Expand all Loading... |
462 // 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 |
463 // perspective of other threads using the function pointers, that the | 465 // perspective of other threads using the function pointers, that the |
464 // 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 |
465 // are changed. | 467 // are changed. |
466 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; | 468 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; |
467 ATOMIC_THREAD_FENCE(memory_order_release); | 469 ATOMIC_THREAD_FENCE(memory_order_release); |
468 g_now_function = now_function; | 470 g_now_function = now_function; |
469 g_system_trace_now_function = system_trace_now_function; | 471 g_system_trace_now_function = system_trace_now_function; |
470 } | 472 } |
471 | 473 |
472 TimeTicks InitialNowFunction() { | 474 TimeDelta InitialNowFunction() { |
473 InitializeNowFunctionPointers(); | 475 InitializeNowFunctionPointers(); |
474 return g_now_function(); | 476 return g_now_function(); |
475 } | 477 } |
476 | 478 |
477 TimeTicks InitialSystemTraceNowFunction() { | 479 TimeDelta InitialSystemTraceNowFunction() { |
478 InitializeNowFunctionPointers(); | 480 InitializeNowFunctionPointers(); |
479 return g_system_trace_now_function(); | 481 return g_system_trace_now_function(); |
480 } | 482 } |
481 | 483 |
482 } // namespace | 484 } // namespace |
483 | 485 |
484 // static | 486 // static |
485 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( | 487 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( |
486 TickFunctionType ticker) { | 488 TickFunctionType ticker) { |
487 base::AutoLock locked(g_rollover_lock); | 489 base::AutoLock locked(g_rollover_lock); |
488 TickFunctionType old = g_tick_function; | 490 TickFunctionType old = g_tick_function; |
489 g_tick_function = ticker; | 491 g_tick_function = ticker; |
490 g_rollover_ms = 0; | 492 g_rollover_ms = 0; |
491 g_last_seen_now = 0; | 493 g_last_seen_now = 0; |
492 return old; | 494 return old; |
493 } | 495 } |
494 | 496 |
495 // static | 497 // static |
496 TimeTicks TimeTicks::Now() { | 498 TimeTicks TimeTicks::Now() { |
497 return g_now_function(); | 499 return TimeTicks() + g_now_function(); |
498 } | 500 } |
499 | 501 |
500 // static | 502 // static |
501 bool TimeTicks::IsHighResolution() { | 503 bool TimeTicks::IsHighResolution() { |
502 if (g_now_function == &InitialNowFunction) | 504 if (g_now_function == &InitialNowFunction) |
503 InitializeNowFunctionPointers(); | 505 InitializeNowFunctionPointers(); |
504 return g_now_function == &QPCNow; | 506 return g_now_function == &QPCNow; |
505 } | 507 } |
506 | 508 |
507 // static | 509 // static |
508 TimeTicks TimeTicks::ThreadNow() { | 510 ThreadTicks ThreadTicks::Now() { |
509 NOTREACHED(); | 511 NOTREACHED(); |
510 return TimeTicks(); | 512 return ThreadTicks(); |
511 } | 513 } |
512 | 514 |
513 // static | 515 // static |
514 TimeTicks TimeTicks::NowFromSystemTraceTime() { | 516 TraceTicks TraceTicks::Now() { |
515 return g_system_trace_now_function(); | 517 return TraceTicks() + g_system_trace_now_function(); |
516 } | 518 } |
517 | 519 |
518 // static | 520 // static |
519 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { | 521 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { |
520 return TimeTicks() + QPCValueToTimeDelta(qpc_value); | 522 return TimeTicks() + QPCValueToTimeDelta(qpc_value); |
521 } | 523 } |
522 | 524 |
523 // TimeDelta ------------------------------------------------------------------ | 525 // TimeDelta ------------------------------------------------------------------ |
524 | 526 |
525 // static | 527 // static |
526 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 528 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
527 return QPCValueToTimeDelta(qpc_value); | 529 return QPCValueToTimeDelta(qpc_value); |
528 } | 530 } |
OLD | NEW |