Revision f230a1cf deps/v8/src/platform/time.cc
deps/v8/src/platform/time.cc | ||
---|---|---|
43 | 43 |
#include "win32-headers.h" |
44 | 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 | 46 |
namespace v8 { |
54 | 47 |
namespace internal { |
55 | 48 |
|
... | ... | |
175 | 168 |
// periodically resync the internal clock to the system clock. |
176 | 169 |
class Clock V8_FINAL { |
177 | 170 |
public: |
178 |
Clock() : initial_time_(CurrentWallclockTime()), |
|
179 |
initial_ticks_(TimeTicks::Now()) {} |
|
171 |
Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {} |
|
180 | 172 |
|
181 | 173 |
Time Now() { |
182 |
// This must be executed under lock.
|
|
183 |
LockGuard<Mutex> lock_guard(&mutex_);
|
|
174 |
// Time between resampling the un-granular clock for this API (1 minute).
|
|
175 |
const TimeDelta kMaxElapsedTime = TimeDelta::FromMinutes(1);
|
|
184 | 176 |
|
185 |
// Calculate the time elapsed since we started our timer. |
|
186 |
TimeDelta elapsed = TimeTicks::Now() - initial_ticks_; |
|
177 |
LockGuard<Mutex> lock_guard(&mutex_); |
|
187 | 178 |
|
188 |
// Check if we don't need to synchronize with the wallclock yet. |
|
189 |
if (elapsed.InMicroseconds() <= kMaxMicrosecondsToAvoidDrift) { |
|
190 |
return initial_time_ + elapsed; |
|
179 |
// Determine current time and ticks. |
|
180 |
TimeTicks ticks = GetSystemTicks(); |
|
181 |
Time time = GetSystemTime(); |
|
182 |
|
|
183 |
// Check if we need to synchronize with the system clock due to a backwards |
|
184 |
// time change or the amount of 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. |
|
194 |
initial_ticks_ = TimeTicks::Now(); |
|
195 |
initial_time_ = CurrentWallclockTime(); |
|
196 |
return initial_time_; |
|
192 |
return initial_time_ + elapsed; |
|
197 | 193 |
} |
198 | 194 |
|
199 | 195 |
Time NowFromSystemTime() { |
200 |
// This must be executed under lock. |
|
201 | 196 |
LockGuard<Mutex> lock_guard(&mutex_); |
202 |
|
|
203 |
// Resynchronize with the wallclock. |
|
204 |
initial_ticks_ = TimeTicks::Now(); |
|
205 |
initial_time_ = CurrentWallclockTime(); |
|
197 |
initial_ticks_ = GetSystemTicks(); |
|
198 |
initial_time_ = GetSystemTime(); |
|
206 | 199 |
return initial_time_; |
207 | 200 |
} |
208 | 201 |
|
209 | 202 |
private: |
210 |
// Time between resampling the un-granular clock for this API (1 minute).
|
|
211 |
static const int64_t kMaxMicrosecondsToAvoidDrift =
|
|
212 |
Time::kMicrosecondsPerMinute;
|
|
203 |
static TimeTicks GetSystemTicks() {
|
|
204 |
return TimeTicks::Now();
|
|
205 |
}
|
|
213 | 206 |
|
214 |
static Time CurrentWallclockTime() {
|
|
207 |
static Time GetSystemTime() {
|
|
215 | 208 |
FILETIME ft; |
216 | 209 |
::GetSystemTimeAsFileTime(&ft); |
217 | 210 |
return Time::FromFiletime(ft); |
... | ... | |
223 | 216 |
}; |
224 | 217 |
|
225 | 218 |
|
226 |
static LazyDynamicInstance<Clock,
|
|
227 |
DefaultCreateTrait<Clock>,
|
|
228 |
ThreadSafeInitOnceTrait>::type clock = LAZY_DYNAMIC_INSTANCE_INITIALIZER;
|
|
219 |
static LazyStaticInstance<Clock,
|
|
220 |
DefaultConstructTrait<Clock>,
|
|
221 |
ThreadSafeInitOnceTrait>::type clock = LAZY_STATIC_INSTANCE_INITIALIZER;
|
|
229 | 222 |
|
230 | 223 |
|
231 | 224 |
Time Time::Now() { |
... | ... | |
388 | 381 |
public: |
389 | 382 |
virtual ~TickClock() {} |
390 | 383 |
virtual int64_t Now() = 0; |
384 |
virtual bool IsHighResolution() = 0; |
|
391 | 385 |
}; |
392 | 386 |
|
393 | 387 |
|
... | ... | |
440 | 434 |
int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) + |
441 | 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 | 438 |
// will never return 0. |
445 | 439 |
return ticks + 1; |
446 | 440 |
} |
447 | 441 |
|
448 |
private: |
|
449 |
int64_t ticks_per_second_; |
|
450 |
}; |
|
451 |
|
|
452 |
|
|
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; |
|
442 |
virtual bool IsHighResolution() V8_OVERRIDE { |
|
443 |
return true; |
|
468 | 444 |
} |
469 | 445 |
|
470 | 446 |
private: |
471 |
GETTICKCOUNT64PROC func_;
|
|
447 |
int64_t ticks_per_second_;
|
|
472 | 448 |
}; |
473 | 449 |
|
474 | 450 |
|
475 | 451 |
class RolloverProtectedTickClock V8_FINAL : public TickClock { |
476 | 452 |
public: |
477 | 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 | 455 |
RolloverProtectedTickClock() : last_seen_now_(0), rollover_ms_(1) {} |
480 | 456 |
virtual ~RolloverProtectedTickClock() {} |
481 | 457 |
|
... | ... | |
487 | 463 |
// Note that we do not use GetTickCount() here, since timeGetTime() gives |
488 | 464 |
// more predictable delta values, as described here: |
489 | 465 |
// http://blogs.msdn.com/b/larryosterman/archive/2009/09/02/what-s-the-difference-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 | 469 |
DWORD now = timeGetTime(); |
491 | 470 |
if (now < last_seen_now_) { |
492 | 471 |
rollover_ms_ += V8_INT64_C(0x100000000); // ~49.7 days. |
... | ... | |
495 | 474 |
return (now + rollover_ms_) * Time::kMicrosecondsPerMillisecond; |
496 | 475 |
} |
497 | 476 |
|
477 |
virtual bool IsHighResolution() V8_OVERRIDE { |
|
478 |
return false; |
|
479 |
} |
|
480 |
|
|
498 | 481 |
private: |
499 | 482 |
Mutex mutex_; |
500 | 483 |
DWORD last_seen_now_; |
... | ... | |
502 | 485 |
}; |
503 | 486 |
|
504 | 487 |
|
505 |
struct CreateTickClockTrait { |
|
506 |
static TickClock* Create() { |
|
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, |
|
488 |
static LazyStaticInstance<RolloverProtectedTickClock, |
|
489 |
DefaultConstructTrait<RolloverProtectedTickClock>, |
|
524 | 490 |
ThreadSafeInitOnceTrait>::type tick_clock = |
525 |
LAZY_DYNAMIC_INSTANCE_INITIALIZER;
|
|
491 |
LAZY_STATIC_INSTANCE_INITIALIZER;
|
|
526 | 492 |
|
527 | 493 |
|
528 | 494 |
struct CreateHighResTickClockTrait { |
... | ... | |
560 | 526 |
} |
561 | 527 |
|
562 | 528 |
|
563 |
TimeTicks TimeTicks::HighResNow() { |
|
529 |
TimeTicks TimeTicks::HighResolutionNow() {
|
|
564 | 530 |
// Make sure we never return 0 here. |
565 | 531 |
TimeTicks ticks(high_res_tick_clock.Pointer()->Now()); |
566 | 532 |
ASSERT(!ticks.IsNull()); |
567 | 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 | 542 |
#else // V8_OS_WIN |
571 | 543 |
|
572 | 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 | 550 |
int64_t ticks; |
579 | 551 |
#if V8_OS_MACOSX |
580 | 552 |
static struct mach_timebase_info info; |
... | ... | |
608 | 580 |
return TimeTicks(ticks + 1); |
609 | 581 |
} |
610 | 582 |
|
583 |
|
|
584 |
// static |
|
585 |
bool TimeTicks::IsHighResolutionClockWorking() { |
|
586 |
return true; |
|
587 |
} |
|
588 |
|
|
611 | 589 |
#endif // V8_OS_WIN |
612 | 590 |
|
613 | 591 |
} } // namespace v8::internal |
Also available in: Unified diff