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

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: REBASE after it passed CQ but did not commit to tree Created 5 years, 6 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
« no previous file with comments | « base/time/time_unittest.cc ('k') | base/time/time_win_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 26 matching lines...) Expand all
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « base/time/time_unittest.cc ('k') | base/time/time_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698