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

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: 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
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 resynchronize due to backwards time
Hannes Payer (out of office) 2013/10/02 11:27:25 Move words up until you hit the 80 chars barrier.
Benedikt Meurer 2013/10/02 12:27:46 Done.
189 if (elapsed.InMicroseconds() <= kMaxMicrosecondsToAvoidDrift) { 184 // change or elapsed time.
Hannes Payer (out of office) 2013/10/02 11:27:25 What do you mean here? Should it be "Check if we h
Benedikt Meurer 2013/10/02 12:27:46 Done.
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;
Hannes Payer (out of office) 2013/10/02 11:27:25 space missing
Benedikt Meurer 2013/10/02 12:27:46 Done.
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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
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::HighResNow()
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::HighResNow() 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
Hannes Payer (out of office) 2013/10/02 11:27:25 can we fix that link - 80 chars
Benedikt Meurer 2013/10/02 12:27:46 As discussed offline, this is how we do it in othe
466 //
Hannes Payer (out of office) 2013/10/02 11:27:25 remove that // with a newline
Benedikt Meurer 2013/10/02 12:27:46 Done.
467 // timeGetTime() provides 1ms granularity when combined with
468 // timeBeginPeriod(). If the host application for V8 wants fast timers, it
469 // can use timeBeginPeriod() to increase the resolution.
490 DWORD now = timeGetTime(); 470 DWORD now = timeGetTime();
491 if (now < last_seen_now_) { 471 if (now < last_seen_now_) {
492 rollover_ms_ += V8_INT64_C(0x100000000); // ~49.7 days. 472 rollover_ms_ += V8_INT64_C(0x100000000); // ~49.7 days.
493 } 473 }
494 last_seen_now_ = now; 474 last_seen_now_ = now;
495 return (now + rollover_ms_) * Time::kMicrosecondsPerMillisecond; 475 return (now + rollover_ms_) * Time::kMicrosecondsPerMillisecond;
496 } 476 }
497 477
478 virtual bool IsHighResolution() V8_OVERRIDE {
479 return false;
480 }
481
498 private: 482 private:
499 Mutex mutex_; 483 Mutex mutex_;
500 DWORD last_seen_now_; 484 DWORD last_seen_now_;
501 int64_t rollover_ms_; 485 int64_t rollover_ms_;
502 }; 486 };
503 487
504 488
505 struct CreateTickClockTrait { 489 static LazyStaticInstance<RolloverProtectedTickClock,
506 static TickClock* Create() { 490 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 = 491 ThreadSafeInitOnceTrait>::type tick_clock =
525 LAZY_DYNAMIC_INSTANCE_INITIALIZER; 492 LAZY_STATIC_INSTANCE_INITIALIZER;
526 493
527 494
528 struct CreateHighResTickClockTrait { 495 struct CreateHighResTickClockTrait {
529 static TickClock* Create() { 496 static TickClock* Create() {
530 // Check if the installed hardware supports a high-resolution performance 497 // Check if the installed hardware supports a high-resolution performance
531 // counter, and if not fallback to the low-resolution tick clock. 498 // counter, and if not fallback to the low-resolution tick clock.
532 LARGE_INTEGER ticks_per_second; 499 LARGE_INTEGER ticks_per_second;
533 if (!QueryPerformanceFrequency(&ticks_per_second)) { 500 if (!QueryPerformanceFrequency(&ticks_per_second)) {
534 return tick_clock.Pointer(); 501 return tick_clock.Pointer();
535 } 502 }
(...skipping 24 matching lines...) Expand all
560 } 527 }
561 528
562 529
563 TimeTicks TimeTicks::HighResNow() { 530 TimeTicks TimeTicks::HighResNow() {
564 // Make sure we never return 0 here. 531 // Make sure we never return 0 here.
565 TimeTicks ticks(high_res_tick_clock.Pointer()->Now()); 532 TimeTicks ticks(high_res_tick_clock.Pointer()->Now());
566 ASSERT(!ticks.IsNull()); 533 ASSERT(!ticks.IsNull());
567 return ticks; 534 return ticks;
568 } 535 }
569 536
537
538 // static
539 bool TimeTicks::IsHighResClockWorking() {
540 return high_res_tick_clock.Pointer()->IsHighResolution();
541 }
542
570 #else // V8_OS_WIN 543 #else // V8_OS_WIN
571 544
572 TimeTicks TimeTicks::Now() { 545 TimeTicks TimeTicks::Now() {
573 return HighResNow(); 546 return HighResNow();
574 } 547 }
575 548
576 549
577 TimeTicks TimeTicks::HighResNow() { 550 TimeTicks TimeTicks::HighResNow() {
578 int64_t ticks; 551 int64_t ticks;
579 #if V8_OS_MACOSX 552 #if V8_OS_MACOSX
(...skipping 21 matching lines...) Expand all
601 int result = clock_gettime(CLOCK_MONOTONIC, &ts); 574 int result = clock_gettime(CLOCK_MONOTONIC, &ts);
602 ASSERT_EQ(0, result); 575 ASSERT_EQ(0, result);
603 USE(result); 576 USE(result);
604 ticks = (ts.tv_sec * Time::kMicrosecondsPerSecond + 577 ticks = (ts.tv_sec * Time::kMicrosecondsPerSecond +
605 ts.tv_nsec / Time::kNanosecondsPerMicrosecond); 578 ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
606 #endif // V8_OS_MACOSX 579 #endif // V8_OS_MACOSX
607 // Make sure we never return 0 here. 580 // Make sure we never return 0 here.
608 return TimeTicks(ticks + 1); 581 return TimeTicks(ticks + 1);
609 } 582 }
610 583
584
585 // static
586 bool TimeTicks::IsHighResClockWorking() {
587 return true;
588 }
589
611 #endif // V8_OS_WIN 590 #endif // V8_OS_WIN
612 591
613 } } // namespace v8::internal 592 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698