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

Side by Side Diff: src/platform/time.cc

Issue 25468003: Always use timeGetTime() for TimeTicks::Now() on Windows. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: REBASE Created 7 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « src/platform/time.h ('k') | src/utils/random-number-generator.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 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 25 matching lines...) Expand all
36 36
37 #include <cstring> 37 #include <cstring>
38 38
39 #include "checks.h" 39 #include "checks.h"
40 #include "cpu.h" 40 #include "cpu.h"
41 #include "platform.h" 41 #include "platform.h"
42 #if V8_OS_WIN 42 #if V8_OS_WIN
43 #include "win32-headers.h" 43 #include "win32-headers.h"
44 #endif 44 #endif
45 45
46 #if V8_OS_WIN
47 // Prototype for GetTickCount64() procedure.
48 extern "C" {
49 typedef ULONGLONG (WINAPI *GETTICKCOUNT64PROC)(void);
50 }
51 #endif
52
53 namespace v8 { 46 namespace v8 {
54 namespace internal { 47 namespace internal {
55 48
56 TimeDelta TimeDelta::FromDays(int days) { 49 TimeDelta TimeDelta::FromDays(int days) {
57 return TimeDelta(days * Time::kMicrosecondsPerDay); 50 return TimeDelta(days * Time::kMicrosecondsPerDay);
58 } 51 }
59 52
60 53
61 TimeDelta TimeDelta::FromHours(int hours) { 54 TimeDelta TimeDelta::FromHours(int hours) {
62 return TimeDelta(hours * Time::kMicrosecondsPerHour); 55 return TimeDelta(hours * Time::kMicrosecondsPerHour);
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 #endif // V8_OS_POSIX 161 #endif // V8_OS_POSIX
169 162
170 163
171 #if V8_OS_WIN 164 #if V8_OS_WIN
172 165
173 // We implement time using the high-resolution timers so that we can get 166 // We implement time using the high-resolution timers so that we can get
174 // timeouts which are smaller than 10-15ms. To avoid any drift, we 167 // timeouts which are smaller than 10-15ms. To avoid any drift, we
175 // periodically resync the internal clock to the system clock. 168 // periodically resync the internal clock to the system clock.
176 class Clock V8_FINAL { 169 class Clock V8_FINAL {
177 public: 170 public:
178 Clock() : initial_time_(CurrentWallclockTime()), 171 Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {}
179 initial_ticks_(TimeTicks::Now()) {}
180 172
181 Time Now() { 173 Time Now() {
182 // This must be executed under lock. 174 // Time between resampling the un-granular clock for this API (1 minute).
175 const TimeDelta kMaxElapsedTime = TimeDelta::FromMinutes(1);
176
183 LockGuard<Mutex> lock_guard(&mutex_); 177 LockGuard<Mutex> lock_guard(&mutex_);
184 178
185 // Calculate the time elapsed since we started our timer. 179 // Determine current time and ticks.
186 TimeDelta elapsed = TimeTicks::Now() - initial_ticks_; 180 TimeTicks ticks = GetSystemTicks();
181 Time time = GetSystemTime();
187 182
188 // Check if we don't need to synchronize with the wallclock yet. 183 // Check if we need to synchronize with the system clock due to a backwards
189 if (elapsed.InMicroseconds() <= kMaxMicrosecondsToAvoidDrift) { 184 // time change or the amount of time elapsed.
190 return initial_time_ + elapsed; 185 TimeDelta elapsed = ticks - initial_ticks_;
186 if (time < initial_time_ || elapsed > kMaxElapsedTime) {
187 initial_ticks_ = ticks;
188 initial_time_ = time;
189 return time;
191 } 190 }
192 191
193 // Resynchronize with the wallclock. 192 return initial_time_ + elapsed;
194 initial_ticks_ = TimeTicks::Now();
195 initial_time_ = CurrentWallclockTime();
196 return initial_time_;
197 } 193 }
198 194
199 Time NowFromSystemTime() { 195 Time NowFromSystemTime() {
200 // This must be executed under lock.
201 LockGuard<Mutex> lock_guard(&mutex_); 196 LockGuard<Mutex> lock_guard(&mutex_);
202 197 initial_ticks_ = GetSystemTicks();
203 // Resynchronize with the wallclock. 198 initial_time_ = GetSystemTime();
204 initial_ticks_ = TimeTicks::Now();
205 initial_time_ = CurrentWallclockTime();
206 return initial_time_; 199 return initial_time_;
207 } 200 }
208 201
209 private: 202 private:
210 // Time between resampling the un-granular clock for this API (1 minute). 203 static TimeTicks GetSystemTicks() {
211 static const int64_t kMaxMicrosecondsToAvoidDrift = 204 return TimeTicks::Now();
212 Time::kMicrosecondsPerMinute; 205 }
213 206
214 static Time CurrentWallclockTime() { 207 static Time GetSystemTime() {
215 FILETIME ft; 208 FILETIME ft;
216 ::GetSystemTimeAsFileTime(&ft); 209 ::GetSystemTimeAsFileTime(&ft);
217 return Time::FromFiletime(ft); 210 return Time::FromFiletime(ft);
218 } 211 }
219 212
220 TimeTicks initial_ticks_; 213 TimeTicks initial_ticks_;
221 Time initial_time_; 214 Time initial_time_;
222 Mutex mutex_; 215 Mutex mutex_;
223 }; 216 };
224 217
225 218
226 static LazyDynamicInstance<Clock, 219 static LazyStaticInstance<Clock,
227 DefaultCreateTrait<Clock>, 220 DefaultConstructTrait<Clock>,
228 ThreadSafeInitOnceTrait>::type clock = LAZY_DYNAMIC_INSTANCE_INITIALIZER; 221 ThreadSafeInitOnceTrait>::type clock = LAZY_STATIC_INSTANCE_INITIALIZER;
229 222
230 223
231 Time Time::Now() { 224 Time Time::Now() {
232 return clock.Pointer()->Now(); 225 return clock.Pointer()->Now();
233 } 226 }
234 227
235 228
236 Time Time::NowFromSystemTime() { 229 Time Time::NowFromSystemTime() {
237 return clock.Pointer()->NowFromSystemTime(); 230 return clock.Pointer()->NowFromSystemTime();
238 } 231 }
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 return static_cast<double>(us_) / kMicrosecondsPerMillisecond; 374 return static_cast<double>(us_) / kMicrosecondsPerMillisecond;
382 } 375 }
383 376
384 377
385 #if V8_OS_WIN 378 #if V8_OS_WIN
386 379
387 class TickClock { 380 class TickClock {
388 public: 381 public:
389 virtual ~TickClock() {} 382 virtual ~TickClock() {}
390 virtual int64_t Now() = 0; 383 virtual int64_t Now() = 0;
384 virtual bool IsHighResolution() = 0;
391 }; 385 };
392 386
393 387
394 // Overview of time counters: 388 // Overview of time counters:
395 // (1) CPU cycle counter. (Retrieved via RDTSC) 389 // (1) CPU cycle counter. (Retrieved via RDTSC)
396 // The CPU counter provides the highest resolution time stamp and is the least 390 // The CPU counter provides the highest resolution time stamp and is the least
397 // expensive to retrieve. However, the CPU counter is unreliable and should not 391 // expensive to retrieve. However, the CPU counter is unreliable and should not
398 // be used in production. Its biggest issue is that it is per processor and it 392 // be used in production. Its biggest issue is that it is per processor and it
399 // is not synchronized between processors. Also, on some computers, the counters 393 // is not synchronized between processors. Also, on some computers, the counters
400 // will change frequency due to thermal and power changes, and stop in some 394 // will change frequency due to thermal and power changes, and stop in some
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 ASSERT(result); 427 ASSERT(result);
434 USE(result); 428 USE(result);
435 429
436 // Intentionally calculate microseconds in a round about manner to avoid 430 // Intentionally calculate microseconds in a round about manner to avoid
437 // overflow and precision issues. Think twice before simplifying! 431 // overflow and precision issues. Think twice before simplifying!
438 int64_t whole_seconds = now.QuadPart / ticks_per_second_; 432 int64_t whole_seconds = now.QuadPart / ticks_per_second_;
439 int64_t leftover_ticks = now.QuadPart % ticks_per_second_; 433 int64_t leftover_ticks = now.QuadPart % ticks_per_second_;
440 int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) + 434 int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) +
441 ((leftover_ticks * Time::kMicrosecondsPerSecond) / ticks_per_second_); 435 ((leftover_ticks * Time::kMicrosecondsPerSecond) / ticks_per_second_);
442 436
443 // Make sure we never return 0 here, so that TimeTicks::HighResNow() 437 // Make sure we never return 0 here, so that TimeTicks::HighResolutionNow()
444 // will never return 0. 438 // will never return 0.
445 return ticks + 1; 439 return ticks + 1;
446 } 440 }
447 441
442 virtual bool IsHighResolution() V8_OVERRIDE {
443 return true;
444 }
445
448 private: 446 private:
449 int64_t ticks_per_second_; 447 int64_t ticks_per_second_;
450 }; 448 };
451 449
452 450
453 // The GetTickCount64() API is what we actually want for the regular tick
454 // clock, but this is only available starting with Windows Vista.
455 class WindowsVistaTickClock V8_FINAL : public TickClock {
456 public:
457 explicit WindowsVistaTickClock(GETTICKCOUNT64PROC func) : func_(func) {
458 ASSERT(func_ != NULL);
459 }
460 virtual ~WindowsVistaTickClock() {}
461
462 virtual int64_t Now() V8_OVERRIDE {
463 // Query the current ticks (in ms).
464 ULONGLONG tick_count_ms = (*func_)();
465
466 // Convert to microseconds (make sure to never return 0 here).
467 return (tick_count_ms * Time::kMicrosecondsPerMillisecond) + 1;
468 }
469
470 private:
471 GETTICKCOUNT64PROC func_;
472 };
473
474
475 class RolloverProtectedTickClock V8_FINAL : public TickClock { 451 class RolloverProtectedTickClock V8_FINAL : public TickClock {
476 public: 452 public:
477 // We initialize rollover_ms_ to 1 to ensure that we will never 453 // We initialize rollover_ms_ to 1 to ensure that we will never
478 // return 0 from TimeTicks::HighResNow() and TimeTicks::Now() below. 454 // return 0 from TimeTicks::HighResolutionNow() and TimeTicks::Now() below.
479 RolloverProtectedTickClock() : last_seen_now_(0), rollover_ms_(1) {} 455 RolloverProtectedTickClock() : last_seen_now_(0), rollover_ms_(1) {}
480 virtual ~RolloverProtectedTickClock() {} 456 virtual ~RolloverProtectedTickClock() {}
481 457
482 virtual int64_t Now() V8_OVERRIDE { 458 virtual int64_t Now() V8_OVERRIDE {
483 LockGuard<Mutex> lock_guard(&mutex_); 459 LockGuard<Mutex> lock_guard(&mutex_);
484 // We use timeGetTime() to implement TimeTicks::Now(), which rolls over 460 // We use timeGetTime() to implement TimeTicks::Now(), which rolls over
485 // every ~49.7 days. We try to track rollover ourselves, which works if 461 // every ~49.7 days. We try to track rollover ourselves, which works if
486 // TimeTicks::Now() is called at least every 49 days. 462 // TimeTicks::Now() is called at least every 49 days.
487 // Note that we do not use GetTickCount() here, since timeGetTime() gives 463 // Note that we do not use GetTickCount() here, since timeGetTime() gives
488 // more predictable delta values, as described here: 464 // more predictable delta values, as described here:
489 // http://blogs.msdn.com/b/larryosterman/archive/2009/09/02/what-s-the-diffe rence-between-gettickcount-and-timegettime.aspx 465 // http://blogs.msdn.com/b/larryosterman/archive/2009/09/02/what-s-the-diffe rence-between-gettickcount-and-timegettime.aspx
466 // timeGetTime() provides 1ms granularity when combined with
467 // timeBeginPeriod(). If the host application for V8 wants fast timers, it
468 // can use timeBeginPeriod() to increase the resolution.
490 DWORD now = timeGetTime(); 469 DWORD now = timeGetTime();
491 if (now < last_seen_now_) { 470 if (now < last_seen_now_) {
492 rollover_ms_ += V8_INT64_C(0x100000000); // ~49.7 days. 471 rollover_ms_ += V8_INT64_C(0x100000000); // ~49.7 days.
493 } 472 }
494 last_seen_now_ = now; 473 last_seen_now_ = now;
495 return (now + rollover_ms_) * Time::kMicrosecondsPerMillisecond; 474 return (now + rollover_ms_) * Time::kMicrosecondsPerMillisecond;
496 } 475 }
497 476
477 virtual bool IsHighResolution() V8_OVERRIDE {
478 return false;
479 }
480
498 private: 481 private:
499 Mutex mutex_; 482 Mutex mutex_;
500 DWORD last_seen_now_; 483 DWORD last_seen_now_;
501 int64_t rollover_ms_; 484 int64_t rollover_ms_;
502 }; 485 };
503 486
504 487
505 struct CreateTickClockTrait { 488 static LazyStaticInstance<RolloverProtectedTickClock,
506 static TickClock* Create() { 489 DefaultConstructTrait<RolloverProtectedTickClock>,
507 // Try to load GetTickCount64() from kernel32.dll (available since Vista).
508 HMODULE kernel32 = ::GetModuleHandleA("kernel32.dll");
509 ASSERT(kernel32 != NULL);
510 FARPROC proc = ::GetProcAddress(kernel32, "GetTickCount64");
511 if (proc != NULL) {
512 return new WindowsVistaTickClock(
513 reinterpret_cast<GETTICKCOUNT64PROC>(proc));
514 }
515
516 // Fallback to the rollover protected tick clock.
517 return new RolloverProtectedTickClock;
518 }
519 };
520
521
522 static LazyDynamicInstance<TickClock,
523 CreateTickClockTrait,
524 ThreadSafeInitOnceTrait>::type tick_clock = 490 ThreadSafeInitOnceTrait>::type tick_clock =
525 LAZY_DYNAMIC_INSTANCE_INITIALIZER; 491 LAZY_STATIC_INSTANCE_INITIALIZER;
526 492
527 493
528 struct CreateHighResTickClockTrait { 494 struct CreateHighResTickClockTrait {
529 static TickClock* Create() { 495 static TickClock* Create() {
530 // Check if the installed hardware supports a high-resolution performance 496 // Check if the installed hardware supports a high-resolution performance
531 // counter, and if not fallback to the low-resolution tick clock. 497 // counter, and if not fallback to the low-resolution tick clock.
532 LARGE_INTEGER ticks_per_second; 498 LARGE_INTEGER ticks_per_second;
533 if (!QueryPerformanceFrequency(&ticks_per_second)) { 499 if (!QueryPerformanceFrequency(&ticks_per_second)) {
534 return tick_clock.Pointer(); 500 return tick_clock.Pointer();
535 } 501 }
(...skipping 17 matching lines...) Expand all
553 519
554 520
555 TimeTicks TimeTicks::Now() { 521 TimeTicks TimeTicks::Now() {
556 // Make sure we never return 0 here. 522 // Make sure we never return 0 here.
557 TimeTicks ticks(tick_clock.Pointer()->Now()); 523 TimeTicks ticks(tick_clock.Pointer()->Now());
558 ASSERT(!ticks.IsNull()); 524 ASSERT(!ticks.IsNull());
559 return ticks; 525 return ticks;
560 } 526 }
561 527
562 528
563 TimeTicks TimeTicks::HighResNow() { 529 TimeTicks TimeTicks::HighResolutionNow() {
564 // Make sure we never return 0 here. 530 // Make sure we never return 0 here.
565 TimeTicks ticks(high_res_tick_clock.Pointer()->Now()); 531 TimeTicks ticks(high_res_tick_clock.Pointer()->Now());
566 ASSERT(!ticks.IsNull()); 532 ASSERT(!ticks.IsNull());
567 return ticks; 533 return ticks;
568 } 534 }
569 535
536
537 // static
538 bool TimeTicks::IsHighResolutionClockWorking() {
539 return high_res_tick_clock.Pointer()->IsHighResolution();
540 }
541
570 #else // V8_OS_WIN 542 #else // V8_OS_WIN
571 543
572 TimeTicks TimeTicks::Now() { 544 TimeTicks TimeTicks::Now() {
573 return HighResNow(); 545 return HighResolutionNow();
574 } 546 }
575 547
576 548
577 TimeTicks TimeTicks::HighResNow() { 549 TimeTicks TimeTicks::HighResolutionNow() {
578 int64_t ticks; 550 int64_t ticks;
579 #if V8_OS_MACOSX 551 #if V8_OS_MACOSX
580 static struct mach_timebase_info info; 552 static struct mach_timebase_info info;
581 if (info.denom == 0) { 553 if (info.denom == 0) {
582 kern_return_t result = mach_timebase_info(&info); 554 kern_return_t result = mach_timebase_info(&info);
583 ASSERT_EQ(KERN_SUCCESS, result); 555 ASSERT_EQ(KERN_SUCCESS, result);
584 USE(result); 556 USE(result);
585 } 557 }
586 ticks = (mach_absolute_time() / Time::kNanosecondsPerMicrosecond * 558 ticks = (mach_absolute_time() / Time::kNanosecondsPerMicrosecond *
587 info.numer / info.denom); 559 info.numer / info.denom);
(...skipping 13 matching lines...) Expand all
601 int result = clock_gettime(CLOCK_MONOTONIC, &ts); 573 int result = clock_gettime(CLOCK_MONOTONIC, &ts);
602 ASSERT_EQ(0, result); 574 ASSERT_EQ(0, result);
603 USE(result); 575 USE(result);
604 ticks = (ts.tv_sec * Time::kMicrosecondsPerSecond + 576 ticks = (ts.tv_sec * Time::kMicrosecondsPerSecond +
605 ts.tv_nsec / Time::kNanosecondsPerMicrosecond); 577 ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
606 #endif // V8_OS_MACOSX 578 #endif // V8_OS_MACOSX
607 // Make sure we never return 0 here. 579 // Make sure we never return 0 here.
608 return TimeTicks(ticks + 1); 580 return TimeTicks(ticks + 1);
609 } 581 }
610 582
583
584 // static
585 bool TimeTicks::IsHighResolutionClockWorking() {
586 return true;
587 }
588
611 #endif // V8_OS_WIN 589 #endif // V8_OS_WIN
612 590
613 } } // namespace v8::internal 591 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/platform/time.h ('k') | src/utils/random-number-generator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698