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

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

Issue 1284053004: Makes TraceTicks use lowres times on Win when highres are buggy or slow (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Removed g_system_trace_now_function Created 5 years, 3 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 | « no previous file | no next file » | 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 364 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 // more reliable. Time::EnableHighResolutionTimer() and 375 // more reliable. Time::EnableHighResolutionTimer() and
376 // Time::ActivateHighResolutionTimer() can be called to alter the resolution of 376 // Time::ActivateHighResolutionTimer() can be called to alter the resolution of
377 // 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
378 // one. 378 // one.
379 379
380 using NowFunction = TimeDelta (*)(void); 380 using NowFunction = TimeDelta (*)(void);
381 381
382 TimeDelta InitialNowFunction(); 382 TimeDelta InitialNowFunction();
383 TimeDelta InitialSystemTraceNowFunction(); 383 TimeDelta InitialSystemTraceNowFunction();
384 384
385 // See "threading notes" in InitializeNowFunctionPointers() for details on how 385 // See "threading notes" in InitializeNowFunctionPointer() for details on how
386 // concurrent reads/writes to these globals has been made safe. 386 // concurrent reads/writes to these globals has been made safe.
387 NowFunction g_now_function = &InitialNowFunction; 387 NowFunction g_now_function = &InitialNowFunction;
388 NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction;
389 int64 g_qpc_ticks_per_second = 0; 388 int64 g_qpc_ticks_per_second = 0;
390 389
391 // 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
392 // 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
393 // 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:
394 #define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier(); 393 #define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier();
395 394
396 TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) { 395 TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) {
397 // Ensure that the assignment to |g_qpc_ticks_per_second|, made in 396 // Ensure that the assignment to |g_qpc_ticks_per_second|, made in
398 // InitializeNowFunctionPointers(), has happened by this point. 397 // InitializeNowFunctionPointer(), has happened by this point.
399 ATOMIC_THREAD_FENCE(memory_order_acquire); 398 ATOMIC_THREAD_FENCE(memory_order_acquire);
400 399
401 DCHECK_GT(g_qpc_ticks_per_second, 0); 400 DCHECK_GT(g_qpc_ticks_per_second, 0);
402 401
403 // If the QPC Value is below the overflow threshold, we proceed with 402 // If the QPC Value is below the overflow threshold, we proceed with
404 // simple multiply and divide. 403 // simple multiply and divide.
405 if (qpc_value < Time::kQPCOverflowThreshold) { 404 if (qpc_value < Time::kQPCOverflowThreshold) {
406 return TimeDelta::FromMicroseconds( 405 return TimeDelta::FromMicroseconds(
407 qpc_value * Time::kMicrosecondsPerSecond / g_qpc_ticks_per_second); 406 qpc_value * Time::kMicrosecondsPerSecond / g_qpc_ticks_per_second);
408 } 407 }
(...skipping 11 matching lines...) Expand all
420 LARGE_INTEGER now; 419 LARGE_INTEGER now;
421 QueryPerformanceCounter(&now); 420 QueryPerformanceCounter(&now);
422 return QPCValueToTimeDelta(now.QuadPart); 421 return QPCValueToTimeDelta(now.QuadPart);
423 } 422 }
424 423
425 bool IsBuggyAthlon(const base::CPU& cpu) { 424 bool IsBuggyAthlon(const base::CPU& cpu) {
426 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. 425 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable.
427 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; 426 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15;
428 } 427 }
429 428
430 void InitializeNowFunctionPointers() { 429 void InitializeNowFunctionPointer() {
431 LARGE_INTEGER ticks_per_sec = {}; 430 LARGE_INTEGER ticks_per_sec = {};
432 if (!QueryPerformanceFrequency(&ticks_per_sec)) 431 if (!QueryPerformanceFrequency(&ticks_per_sec))
433 ticks_per_sec.QuadPart = 0; 432 ticks_per_sec.QuadPart = 0;
434 433
435 // If Windows cannot provide a QPC implementation, both TimeTicks::Now() and 434 // If Windows cannot provide a QPC implementation, TimeTicks::Now() must use
436 // TraceTicks::Now() must use the low-resolution clock. 435 // the low-resolution clock.
437 // 436 //
438 // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now() 437 // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now()
439 // will use the low-resolution clock, but TraceTicks::Now() will use the QPC 438 // will still use the low-resolution clock. A CPU lacking a non-stop time
440 // (in the hope that it is still useful for tracing purposes). A CPU lacking a 439 // counter will cause Windows to provide an alternate QPC implementation that
441 // non-stop time counter will cause Windows to provide an alternate QPC 440 // works, but is expensive to use. Certain Athlon CPUs are known to make the
442 // implementation that works, but is expensive to use. Certain Athlon CPUs are 441 // QPC implementation unreliable.
443 // known to make the QPC implementation unreliable.
444 // 442 //
445 // Otherwise, both Now functions can use the high-resolution QPC clock. As of 443 // Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015,
446 // 4 January 2015, ~68% of users fall within this category. 444 // ~72% of users fall within this category.
447 NowFunction now_function; 445 NowFunction now_function;
danakj 2015/08/25 18:37:53 Can you add comments saying that TraceTicks::Now()
charliea (OOO until 10-5) 2015/08/25 20:17:16 Done.
448 NowFunction system_trace_now_function;
449 base::CPU cpu; 446 base::CPU cpu;
450 if (ticks_per_sec.QuadPart <= 0) { 447 if (ticks_per_sec.QuadPart <= 0 ||
451 now_function = system_trace_now_function = &RolloverProtectedNow; 448 !cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) {
452 } else if (!cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) {
453 now_function = &RolloverProtectedNow; 449 now_function = &RolloverProtectedNow;
454 system_trace_now_function = &QPCNow;
455 } else { 450 } else {
456 now_function = system_trace_now_function = &QPCNow; 451 now_function = &QPCNow;
457 } 452 }
458 453
459 // Threading note 1: In an unlikely race condition, it's possible for two or 454 // Threading note 1: In an unlikely race condition, it's possible for two or
460 // more threads to enter InitializeNowFunctionPointers() in parallel. This is 455 // more threads to enter InitializeNowFunctionPointer() in parallel. This is
461 // not a problem since all threads should end up writing out the same values 456 // not a problem since all threads should end up writing out the same values
462 // to the global variables. 457 // to the global variables.
463 // 458 //
464 // Threading note 2: A release fence is placed here to ensure, from the 459 // Threading note 2: A release fence is placed here to ensure, from the
465 // perspective of other threads using the function pointers, that the 460 // perspective of other threads using the function pointers, that the
466 // assignment to |g_qpc_ticks_per_second| happens before the function pointers 461 // assignment to |g_qpc_ticks_per_second| happens before the function pointers
467 // are changed. 462 // are changed.
468 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; 463 g_qpc_ticks_per_second = ticks_per_sec.QuadPart;
469 ATOMIC_THREAD_FENCE(memory_order_release); 464 ATOMIC_THREAD_FENCE(memory_order_release);
470 g_now_function = now_function; 465 g_now_function = now_function;
471 g_system_trace_now_function = system_trace_now_function;
472 } 466 }
473 467
474 TimeDelta InitialNowFunction() { 468 TimeDelta InitialNowFunction() {
475 InitializeNowFunctionPointers(); 469 InitializeNowFunctionPointer();
476 return g_now_function(); 470 return g_now_function();
477 } 471 }
478 472
479 TimeDelta InitialSystemTraceNowFunction() {
480 InitializeNowFunctionPointers();
481 return g_system_trace_now_function();
482 }
483
484 } // namespace 473 } // namespace
485 474
486 // static 475 // static
487 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( 476 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
488 TickFunctionType ticker) { 477 TickFunctionType ticker) {
489 base::AutoLock locked(g_rollover_lock); 478 base::AutoLock locked(g_rollover_lock);
490 TickFunctionType old = g_tick_function; 479 TickFunctionType old = g_tick_function;
491 g_tick_function = ticker; 480 g_tick_function = ticker;
492 g_rollover_ms = 0; 481 g_rollover_ms = 0;
493 g_last_seen_now = 0; 482 g_last_seen_now = 0;
494 return old; 483 return old;
495 } 484 }
496 485
497 // static 486 // static
498 TimeTicks TimeTicks::Now() { 487 TimeTicks TimeTicks::Now() {
499 return TimeTicks() + g_now_function(); 488 return TimeTicks() + g_now_function();
500 } 489 }
501 490
502 // static 491 // static
503 bool TimeTicks::IsHighResolution() { 492 bool TimeTicks::IsHighResolution() {
504 if (g_now_function == &InitialNowFunction) 493 if (g_now_function == &InitialNowFunction)
505 InitializeNowFunctionPointers(); 494 InitializeNowFunctionPointer();
506 return g_now_function == &QPCNow; 495 return g_now_function == &QPCNow;
507 } 496 }
508 497
509 // static 498 // static
510 ThreadTicks ThreadTicks::Now() { 499 ThreadTicks ThreadTicks::Now() {
511 NOTREACHED(); 500 NOTREACHED();
512 return ThreadTicks(); 501 return ThreadTicks();
513 } 502 }
514 503
515 // static 504 // static
516 TraceTicks TraceTicks::Now() { 505 TraceTicks TraceTicks::Now() {
517 return TraceTicks() + g_system_trace_now_function(); 506 return TraceTicks() + g_now_function();
518 } 507 }
519 508
520 // static 509 // static
521 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { 510 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) {
522 return TimeTicks() + QPCValueToTimeDelta(qpc_value); 511 return TimeTicks() + QPCValueToTimeDelta(qpc_value);
523 } 512 }
524 513
525 // TimeDelta ------------------------------------------------------------------ 514 // TimeDelta ------------------------------------------------------------------
526 515
527 // static 516 // static
528 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { 517 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) {
529 return QPCValueToTimeDelta(qpc_value); 518 return QPCValueToTimeDelta(qpc_value);
530 } 519 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698