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

Side by Side Diff: time/time_win.cc

Issue 2045303002: Update to Chromium //base at Chromium commit 3e81715e6d3a4324362635aea46ce1f1a163cca1. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/domokit/base@master
Patch Set: Created 4 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 | « threading/thread_checker.h ('k') | trace_event/memory_dump_manager.h » ('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 362 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 // (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
374 // milliseconds) time stamp but is comparatively less expensive to retrieve and 374 // milliseconds) time stamp but is comparatively less expensive to retrieve and
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();
384 383
385 // See "threading notes" in InitializeNowFunctionPointers() for details on how 384 // See "threading notes" in InitializeNowFunctionPointer() for details on how
386 // concurrent reads/writes to these globals has been made safe. 385 // concurrent reads/writes to these globals has been made safe.
387 NowFunction g_now_function = &InitialNowFunction; 386 NowFunction g_now_function = &InitialNowFunction;
388 NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction;
389 int64 g_qpc_ticks_per_second = 0; 387 int64 g_qpc_ticks_per_second = 0;
390 388
391 // As of January 2015, use of <atomic> is forbidden in Chromium code. This is 389 // 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 390 // 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: 391 // the memory_order argument is anything but std::memory_order_seq_cst:
394 #define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier(); 392 #define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier();
395 393
396 TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) { 394 TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) {
397 // Ensure that the assignment to |g_qpc_ticks_per_second|, made in 395 // Ensure that the assignment to |g_qpc_ticks_per_second|, made in
398 // InitializeNowFunctionPointers(), has happened by this point. 396 // InitializeNowFunctionPointer(), has happened by this point.
399 ATOMIC_THREAD_FENCE(memory_order_acquire); 397 ATOMIC_THREAD_FENCE(memory_order_acquire);
400 398
401 DCHECK_GT(g_qpc_ticks_per_second, 0); 399 DCHECK_GT(g_qpc_ticks_per_second, 0);
402 400
403 // If the QPC Value is below the overflow threshold, we proceed with 401 // If the QPC Value is below the overflow threshold, we proceed with
404 // simple multiply and divide. 402 // simple multiply and divide.
405 if (qpc_value < Time::kQPCOverflowThreshold) { 403 if (qpc_value < Time::kQPCOverflowThreshold) {
406 return TimeDelta::FromMicroseconds( 404 return TimeDelta::FromMicroseconds(
407 qpc_value * Time::kMicrosecondsPerSecond / g_qpc_ticks_per_second); 405 qpc_value * Time::kMicrosecondsPerSecond / g_qpc_ticks_per_second);
408 } 406 }
(...skipping 11 matching lines...) Expand all
420 LARGE_INTEGER now; 418 LARGE_INTEGER now;
421 QueryPerformanceCounter(&now); 419 QueryPerformanceCounter(&now);
422 return QPCValueToTimeDelta(now.QuadPart); 420 return QPCValueToTimeDelta(now.QuadPart);
423 } 421 }
424 422
425 bool IsBuggyAthlon(const base::CPU& cpu) { 423 bool IsBuggyAthlon(const base::CPU& cpu) {
426 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. 424 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable.
427 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; 425 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15;
428 } 426 }
429 427
430 void InitializeNowFunctionPointers() { 428 void InitializeNowFunctionPointer() {
431 LARGE_INTEGER ticks_per_sec = {}; 429 LARGE_INTEGER ticks_per_sec = {};
432 if (!QueryPerformanceFrequency(&ticks_per_sec)) 430 if (!QueryPerformanceFrequency(&ticks_per_sec))
433 ticks_per_sec.QuadPart = 0; 431 ticks_per_sec.QuadPart = 0;
434 432
435 // If Windows cannot provide a QPC implementation, both TimeTicks::Now() and 433 // If Windows cannot provide a QPC implementation, TimeTicks::Now() must use
436 // TraceTicks::Now() must use the low-resolution clock. 434 // the low-resolution clock.
437 // 435 //
438 // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now() 436 // 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 437 // 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 438 // counter will cause Windows to provide an alternate QPC implementation that
441 // non-stop time counter will cause Windows to provide an alternate QPC 439 // 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 440 // QPC implementation unreliable.
443 // known to make the QPC implementation unreliable.
444 // 441 //
445 // Otherwise, both Now functions can use the high-resolution QPC clock. As of 442 // Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015,
446 // 4 January 2015, ~68% of users fall within this category. 443 // ~72% of users fall within this category.
444 //
445 // TraceTicks::Now() always uses the same clock as TimeTicks::Now(), even
446 // when the QPC exists but is expensive or unreliable. This is because we'd
447 // eventually like to merge TraceTicks and TimeTicks and have one type of
448 // timestamp that is reliable, monotonic, and comparable. Also, while we could
449 // use the high-resolution timer for TraceTicks even when it's unreliable or
450 // slow, it's easier to make tracing tools accommodate a coarse timer than
451 // one that's unreliable or slow.
447 NowFunction now_function; 452 NowFunction now_function;
448 NowFunction system_trace_now_function;
449 base::CPU cpu; 453 base::CPU cpu;
450 if (ticks_per_sec.QuadPart <= 0) { 454 if (ticks_per_sec.QuadPart <= 0 || !cpu.has_non_stop_time_stamp_counter() ||
451 now_function = system_trace_now_function = &RolloverProtectedNow; 455 IsBuggyAthlon(cpu)) {
452 } else if (!cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) {
453 now_function = &RolloverProtectedNow; 456 now_function = &RolloverProtectedNow;
454 system_trace_now_function = &QPCNow;
455 } else { 457 } else {
456 now_function = system_trace_now_function = &QPCNow; 458 now_function = &QPCNow;
457 } 459 }
458 460
459 // Threading note 1: In an unlikely race condition, it's possible for two or 461 // Threading note 1: In an unlikely race condition, it's possible for two or
460 // more threads to enter InitializeNowFunctionPointers() in parallel. This is 462 // more threads to enter InitializeNowFunctionPointer() in parallel. This is
461 // not a problem since all threads should end up writing out the same values 463 // not a problem since all threads should end up writing out the same values
462 // to the global variables. 464 // to the global variables.
463 // 465 //
464 // Threading note 2: A release fence is placed here to ensure, from the 466 // Threading note 2: A release fence is placed here to ensure, from the
465 // perspective of other threads using the function pointers, that the 467 // perspective of other threads using the function pointers, that the
466 // assignment to |g_qpc_ticks_per_second| happens before the function pointers 468 // assignment to |g_qpc_ticks_per_second| happens before the function pointers
467 // are changed. 469 // are changed.
468 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; 470 g_qpc_ticks_per_second = ticks_per_sec.QuadPart;
469 ATOMIC_THREAD_FENCE(memory_order_release); 471 ATOMIC_THREAD_FENCE(memory_order_release);
470 g_now_function = now_function; 472 g_now_function = now_function;
471 g_system_trace_now_function = system_trace_now_function;
472 } 473 }
473 474
474 TimeDelta InitialNowFunction() { 475 TimeDelta InitialNowFunction() {
475 InitializeNowFunctionPointers(); 476 InitializeNowFunctionPointer();
476 return g_now_function(); 477 return g_now_function();
477 } 478 }
478 479
479 TimeDelta InitialSystemTraceNowFunction() {
480 InitializeNowFunctionPointers();
481 return g_system_trace_now_function();
482 }
483
484 } // namespace 480 } // namespace
485 481
486 // static 482 // static
487 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( 483 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
488 TickFunctionType ticker) { 484 TickFunctionType ticker) {
489 base::AutoLock locked(g_rollover_lock); 485 base::AutoLock locked(g_rollover_lock);
490 TickFunctionType old = g_tick_function; 486 TickFunctionType old = g_tick_function;
491 g_tick_function = ticker; 487 g_tick_function = ticker;
492 g_rollover_ms = 0; 488 g_rollover_ms = 0;
493 g_last_seen_now = 0; 489 g_last_seen_now = 0;
494 return old; 490 return old;
495 } 491 }
496 492
497 // static 493 // static
498 TimeTicks TimeTicks::Now() { 494 TimeTicks TimeTicks::Now() {
499 return TimeTicks() + g_now_function(); 495 return TimeTicks() + g_now_function();
500 } 496 }
501 497
502 // static 498 // static
503 bool TimeTicks::IsHighResolution() { 499 bool TimeTicks::IsHighResolution() {
504 if (g_now_function == &InitialNowFunction) 500 if (g_now_function == &InitialNowFunction)
505 InitializeNowFunctionPointers(); 501 InitializeNowFunctionPointer();
506 return g_now_function == &QPCNow; 502 return g_now_function == &QPCNow;
507 } 503 }
508 504
509 // static 505 // static
510 ThreadTicks ThreadTicks::Now() { 506 ThreadTicks ThreadTicks::Now() {
511 NOTREACHED(); 507 NOTREACHED();
512 return ThreadTicks(); 508 return ThreadTicks();
513 } 509 }
514 510
515 // static 511 // static
516 TraceTicks TraceTicks::Now() { 512 TraceTicks TraceTicks::Now() {
517 return TraceTicks() + g_system_trace_now_function(); 513 return TraceTicks() + g_now_function();
518 } 514 }
519 515
520 // static 516 // static
521 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { 517 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) {
522 return TimeTicks() + QPCValueToTimeDelta(qpc_value); 518 return TimeTicks() + QPCValueToTimeDelta(qpc_value);
523 } 519 }
524 520
525 // TimeDelta ------------------------------------------------------------------ 521 // TimeDelta ------------------------------------------------------------------
526 522
527 // static 523 // static
528 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { 524 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) {
529 return QPCValueToTimeDelta(qpc_value); 525 return QPCValueToTimeDelta(qpc_value);
530 } 526 }
OLDNEW
« no previous file with comments | « threading/thread_checker.h ('k') | trace_event/memory_dump_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698