Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Side by Side Diff: base/time/time_win.cc

Issue 1122153002: Fixit: Fork base::TimeTicks --> TimeTicks + ThreadTicks + TraceTicks (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@FIXIT_timeclasses_1of2
Patch Set: Comment tweaks in base/time/time.h Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698