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