1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "platform/time.h" 29 30 #if V8_OS_POSIX 31 #include <sys/time.h> 32 #endif 33 #if V8_OS_MACOSX 34 #include <mach/mach_time.h> 35 #endif 36 37 #include <cstring> 38 39 #include "checks.h" 40 #include "cpu.h" 41 #include "platform.h" 42 #if V8_OS_WIN 43 #include "win32-headers.h" 44 #endif 45 46 namespace v8 { 47 namespace internal { 48 49 TimeDelta TimeDelta::FromDays(int days) { 50 return TimeDelta(days * Time::kMicrosecondsPerDay); 51 } 52 53 54 TimeDelta TimeDelta::FromHours(int hours) { 55 return TimeDelta(hours * Time::kMicrosecondsPerHour); 56 } 57 58 59 TimeDelta TimeDelta::FromMinutes(int minutes) { 60 return TimeDelta(minutes * Time::kMicrosecondsPerMinute); 61 } 62 63 64 TimeDelta TimeDelta::FromSeconds(int64_t seconds) { 65 return TimeDelta(seconds * Time::kMicrosecondsPerSecond); 66 } 67 68 69 TimeDelta TimeDelta::FromMilliseconds(int64_t milliseconds) { 70 return TimeDelta(milliseconds * Time::kMicrosecondsPerMillisecond); 71 } 72 73 74 TimeDelta TimeDelta::FromNanoseconds(int64_t nanoseconds) { 75 return TimeDelta(nanoseconds / Time::kNanosecondsPerMicrosecond); 76 } 77 78 79 int TimeDelta::InDays() const { 80 return static_cast<int>(delta_ / Time::kMicrosecondsPerDay); 81 } 82 83 84 int TimeDelta::InHours() const { 85 return static_cast<int>(delta_ / Time::kMicrosecondsPerHour); 86 } 87 88 89 int TimeDelta::InMinutes() const { 90 return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute); 91 } 92 93 94 double TimeDelta::InSecondsF() const { 95 return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond; 96 } 97 98 99 int64_t TimeDelta::InSeconds() const { 100 return delta_ / Time::kMicrosecondsPerSecond; 101 } 102 103 104 double TimeDelta::InMillisecondsF() const { 105 return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond; 106 } 107 108 109 int64_t TimeDelta::InMilliseconds() const { 110 return delta_ / Time::kMicrosecondsPerMillisecond; 111 } 112 113 114 int64_t TimeDelta::InNanoseconds() const { 115 return delta_ * Time::kNanosecondsPerMicrosecond; 116 } 117 118 119 #if V8_OS_MACOSX 120 121 TimeDelta TimeDelta::FromMachTimespec(struct mach_timespec ts) { 122 ASSERT_GE(ts.tv_nsec, 0); 123 ASSERT_LT(ts.tv_nsec, 124 static_cast<long>(Time::kNanosecondsPerSecond)); // NOLINT 125 return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond + 126 ts.tv_nsec / Time::kNanosecondsPerMicrosecond); 127 } 128 129 130 struct mach_timespec TimeDelta::ToMachTimespec() const { 131 struct mach_timespec ts; 132 ASSERT(delta_ >= 0); 133 ts.tv_sec = delta_ / Time::kMicrosecondsPerSecond; 134 ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) * 135 Time::kNanosecondsPerMicrosecond; 136 return ts; 137 } 138 139 #endif // V8_OS_MACOSX 140 141 142 #if V8_OS_POSIX 143 144 TimeDelta TimeDelta::FromTimespec(struct timespec ts) { 145 ASSERT_GE(ts.tv_nsec, 0); 146 ASSERT_LT(ts.tv_nsec, 147 static_cast<long>(Time::kNanosecondsPerSecond)); // NOLINT 148 return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond + 149 ts.tv_nsec / Time::kNanosecondsPerMicrosecond); 150 } 151 152 153 struct timespec TimeDelta::ToTimespec() const { 154 struct timespec ts; 155 ts.tv_sec = delta_ / Time::kMicrosecondsPerSecond; 156 ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) * 157 Time::kNanosecondsPerMicrosecond; 158 return ts; 159 } 160 161 #endif // V8_OS_POSIX 162 163 164 #if V8_OS_WIN 165 166 // We implement time using the high-resolution timers so that we can get 167 // timeouts which are smaller than 10-15ms. To avoid any drift, we 168 // periodically resync the internal clock to the system clock. 169 class Clock V8_FINAL { 170 public: 171 Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {} 172 173 Time Now() { 174 // Time between resampling the un-granular clock for this API (1 minute). 175 const TimeDelta kMaxElapsedTime = TimeDelta::FromMinutes(1); 176 177 LockGuard<Mutex> lock_guard(&mutex_); 178 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; 190 } 191 192 return initial_time_ + elapsed; 193 } 194 195 Time NowFromSystemTime() { 196 LockGuard<Mutex> lock_guard(&mutex_); 197 initial_ticks_ = GetSystemTicks(); 198 initial_time_ = GetSystemTime(); 199 return initial_time_; 200 } 201 202 private: 203 static TimeTicks GetSystemTicks() { 204 return TimeTicks::Now(); 205 } 206 207 static Time GetSystemTime() { 208 FILETIME ft; 209 ::GetSystemTimeAsFileTime(&ft); 210 return Time::FromFiletime(ft); 211 } 212 213 TimeTicks initial_ticks_; 214 Time initial_time_; 215 Mutex mutex_; 216 }; 217 218 219 static LazyStaticInstance<Clock, 220 DefaultConstructTrait<Clock>, 221 ThreadSafeInitOnceTrait>::type clock = LAZY_STATIC_INSTANCE_INITIALIZER; 222 223 224 Time Time::Now() { 225 return clock.Pointer()->Now(); 226 } 227 228 229 Time Time::NowFromSystemTime() { 230 return clock.Pointer()->NowFromSystemTime(); 231 } 232 233 234 // Time between windows epoch and standard epoch. 235 static const int64_t kTimeToEpochInMicroseconds = V8_INT64_C(11644473600000000); 236 237 238 Time Time::FromFiletime(FILETIME ft) { 239 if (ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0) { 240 return Time(); 241 } 242 if (ft.dwLowDateTime == std::numeric_limits<DWORD>::max() && 243 ft.dwHighDateTime == std::numeric_limits<DWORD>::max()) { 244 return Max(); 245 } 246 int64_t us = (static_cast<uint64_t>(ft.dwLowDateTime) + 247 (static_cast<uint64_t>(ft.dwHighDateTime) << 32)) / 10; 248 return Time(us - kTimeToEpochInMicroseconds); 249 } 250 251 252 FILETIME Time::ToFiletime() const { 253 ASSERT(us_ >= 0); 254 FILETIME ft; 255 if (IsNull()) { 256 ft.dwLowDateTime = 0; 257 ft.dwHighDateTime = 0; 258 return ft; 259 } 260 if (IsMax()) { 261 ft.dwLowDateTime = std::numeric_limits<DWORD>::max(); 262 ft.dwHighDateTime = std::numeric_limits<DWORD>::max(); 263 return ft; 264 } 265 uint64_t us = static_cast<uint64_t>(us_ + kTimeToEpochInMicroseconds) * 10; 266 ft.dwLowDateTime = static_cast<DWORD>(us); 267 ft.dwHighDateTime = static_cast<DWORD>(us >> 32); 268 return ft; 269 } 270 271 #elif V8_OS_POSIX 272 273 Time Time::Now() { 274 struct timeval tv; 275 int result = gettimeofday(&tv, NULL); 276 ASSERT_EQ(0, result); 277 USE(result); 278 return FromTimeval(tv); 279 } 280 281 282 Time Time::NowFromSystemTime() { 283 return Now(); 284 } 285 286 287 Time Time::FromTimespec(struct timespec ts) { 288 ASSERT(ts.tv_nsec >= 0); 289 ASSERT(ts.tv_nsec < static_cast<long>(kNanosecondsPerSecond)); // NOLINT 290 if (ts.tv_nsec == 0 && ts.tv_sec == 0) { 291 return Time(); 292 } 293 if (ts.tv_nsec == static_cast<long>(kNanosecondsPerSecond - 1) && // NOLINT 294 ts.tv_sec == std::numeric_limits<time_t>::max()) { 295 return Max(); 296 } 297 return Time(ts.tv_sec * kMicrosecondsPerSecond + 298 ts.tv_nsec / kNanosecondsPerMicrosecond); 299 } 300 301 302 struct timespec Time::ToTimespec() const { 303 struct timespec ts; 304 if (IsNull()) { 305 ts.tv_sec = 0; 306 ts.tv_nsec = 0; 307 return ts; 308 } 309 if (IsMax()) { 310 ts.tv_sec = std::numeric_limits<time_t>::max(); 311 ts.tv_nsec = static_cast<long>(kNanosecondsPerSecond - 1); // NOLINT 312 return ts; 313 } 314 ts.tv_sec = us_ / kMicrosecondsPerSecond; 315 ts.tv_nsec = (us_ % kMicrosecondsPerSecond) * kNanosecondsPerMicrosecond; 316 return ts; 317 } 318 319 320 Time Time::FromTimeval(struct timeval tv) { 321 ASSERT(tv.tv_usec >= 0); 322 ASSERT(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond)); 323 if (tv.tv_usec == 0 && tv.tv_sec == 0) { 324 return Time(); 325 } 326 if (tv.tv_usec == static_cast<suseconds_t>(kMicrosecondsPerSecond - 1) && 327 tv.tv_sec == std::numeric_limits<time_t>::max()) { 328 return Max(); 329 } 330 return Time(tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec); 331 } 332 333 334 struct timeval Time::ToTimeval() const { 335 struct timeval tv; 336 if (IsNull()) { 337 tv.tv_sec = 0; 338 tv.tv_usec = 0; 339 return tv; 340 } 341 if (IsMax()) { 342 tv.tv_sec = std::numeric_limits<time_t>::max(); 343 tv.tv_usec = static_cast<suseconds_t>(kMicrosecondsPerSecond - 1); 344 return tv; 345 } 346 tv.tv_sec = us_ / kMicrosecondsPerSecond; 347 tv.tv_usec = us_ % kMicrosecondsPerSecond; 348 return tv; 349 } 350 351 #endif // V8_OS_WIN 352 353 354 Time Time::FromJsTime(double ms_since_epoch) { 355 // The epoch is a valid time, so this constructor doesn't interpret 356 // 0 as the null time. 357 if (ms_since_epoch == std::numeric_limits<double>::max()) { 358 return Max(); 359 } 360 return Time( 361 static_cast<int64_t>(ms_since_epoch * kMicrosecondsPerMillisecond)); 362 } 363 364 365 double Time::ToJsTime() const { 366 if (IsNull()) { 367 // Preserve 0 so the invalid result doesn't depend on the platform. 368 return 0; 369 } 370 if (IsMax()) { 371 // Preserve max without offset to prevent overflow. 372 return std::numeric_limits<double>::max(); 373 } 374 return static_cast<double>(us_) / kMicrosecondsPerMillisecond; 375 } 376 377 378 #if V8_OS_WIN 379 380 class TickClock { 381 public: 382 virtual ~TickClock() {} 383 virtual int64_t Now() = 0; 384 virtual bool IsHighResolution() = 0; 385 }; 386 387 388 // Overview of time counters: 389 // (1) CPU cycle counter. (Retrieved via RDTSC) 390 // The CPU counter provides the highest resolution time stamp and is the least 391 // expensive to retrieve. However, the CPU counter is unreliable and should not 392 // be used in production. Its biggest issue is that it is per processor and it 393 // is not synchronized between processors. Also, on some computers, the counters 394 // will change frequency due to thermal and power changes, and stop in some 395 // states. 396 // 397 // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high- 398 // resolution (100 nanoseconds) time stamp but is comparatively more expensive 399 // to retrieve. What QueryPerformanceCounter actually does is up to the HAL. 400 // (with some help from ACPI). 401 // According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx 402 // in the worst case, it gets the counter from the rollover interrupt on the 403 // programmable interrupt timer. In best cases, the HAL may conclude that the 404 // RDTSC counter runs at a constant frequency, then it uses that instead. On 405 // multiprocessor machines, it will try to verify the values returned from 406 // RDTSC on each processor are consistent with each other, and apply a handful 407 // of workarounds for known buggy hardware. In other words, QPC is supposed to 408 // give consistent result on a multiprocessor computer, but it is unreliable in 409 // reality due to bugs in BIOS or HAL on some, especially old computers. 410 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but 411 // it should be used with caution. 412 // 413 // (3) System time. The system time provides a low-resolution (typically 10ms 414 // to 55 milliseconds) time stamp but is comparatively less expensive to 415 // retrieve and more reliable. 416 class HighResolutionTickClock V8_FINAL : public TickClock { 417 public: 418 explicit HighResolutionTickClock(int64_t ticks_per_second) 419 : ticks_per_second_(ticks_per_second) { 420 ASSERT_LT(0, ticks_per_second); 421 } 422 virtual ~HighResolutionTickClock() {} 423 424 virtual int64_t Now() V8_OVERRIDE { 425 LARGE_INTEGER now; 426 BOOL result = QueryPerformanceCounter(&now); 427 ASSERT(result); 428 USE(result); 429 430 // Intentionally calculate microseconds in a round about manner to avoid 431 // overflow and precision issues. Think twice before simplifying! 432 int64_t whole_seconds = now.QuadPart / ticks_per_second_; 433 int64_t leftover_ticks = now.QuadPart % ticks_per_second_; 434 int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) + 435 ((leftover_ticks * Time::kMicrosecondsPerSecond) / ticks_per_second_); 436 437 // Make sure we never return 0 here, so that TimeTicks::HighResolutionNow() 438 // will never return 0. 439 return ticks + 1; 440 } 441 442 virtual bool IsHighResolution() V8_OVERRIDE { 443 return true; 444 } 445 446 private: 447 int64_t ticks_per_second_; 448 }; 449 450 451 class RolloverProtectedTickClock V8_FINAL : public TickClock { 452 public: 453 // We initialize rollover_ms_ to 1 to ensure that we will never 454 // return 0 from TimeTicks::HighResolutionNow() and TimeTicks::Now() below. 455 RolloverProtectedTickClock() : last_seen_now_(0), rollover_ms_(1) {} 456 virtual ~RolloverProtectedTickClock() {} 457 458 virtual int64_t Now() V8_OVERRIDE { 459 LockGuard<Mutex> lock_guard(&mutex_); 460 // We use timeGetTime() to implement TimeTicks::Now(), which rolls over 461 // every ~49.7 days. We try to track rollover ourselves, which works if 462 // TimeTicks::Now() is called at least every 49 days. 463 // Note that we do not use GetTickCount() here, since timeGetTime() gives 464 // more predictable delta values, as described here: 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. 469 DWORD now = timeGetTime(); 470 if (now < last_seen_now_) { 471 rollover_ms_ += V8_INT64_C(0x100000000); // ~49.7 days. 472 } 473 last_seen_now_ = now; 474 return (now + rollover_ms_) * Time::kMicrosecondsPerMillisecond; 475 } 476 477 virtual bool IsHighResolution() V8_OVERRIDE { 478 return false; 479 } 480 481 private: 482 Mutex mutex_; 483 DWORD last_seen_now_; 484 int64_t rollover_ms_; 485 }; 486 487 488 static LazyStaticInstance<RolloverProtectedTickClock, 489 DefaultConstructTrait<RolloverProtectedTickClock>, 490 ThreadSafeInitOnceTrait>::type tick_clock = 491 LAZY_STATIC_INSTANCE_INITIALIZER; 492 493 494 struct CreateHighResTickClockTrait { 495 static TickClock* Create() { 496 // Check if the installed hardware supports a high-resolution performance 497 // counter, and if not fallback to the low-resolution tick clock. 498 LARGE_INTEGER ticks_per_second; 499 if (!QueryPerformanceFrequency(&ticks_per_second)) { 500 return tick_clock.Pointer(); 501 } 502 503 // On Athlon X2 CPUs (e.g. model 15) the QueryPerformanceCounter 504 // is unreliable, fallback to the low-resolution tick clock. 505 CPU cpu; 506 if (strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15) { 507 return tick_clock.Pointer(); 508 } 509 510 return new HighResolutionTickClock(ticks_per_second.QuadPart); 511 } 512 }; 513 514 515 static LazyDynamicInstance<TickClock, 516 CreateHighResTickClockTrait, 517 ThreadSafeInitOnceTrait>::type high_res_tick_clock = 518 LAZY_DYNAMIC_INSTANCE_INITIALIZER; 519 520 521 TimeTicks TimeTicks::Now() { 522 // Make sure we never return 0 here. 523 TimeTicks ticks(tick_clock.Pointer()->Now()); 524 ASSERT(!ticks.IsNull()); 525 return ticks; 526 } 527 528 529 TimeTicks TimeTicks::HighResolutionNow() { 530 // Make sure we never return 0 here. 531 TimeTicks ticks(high_res_tick_clock.Pointer()->Now()); 532 ASSERT(!ticks.IsNull()); 533 return ticks; 534 } 535 536 537 // static 538 bool TimeTicks::IsHighResolutionClockWorking() { 539 return high_res_tick_clock.Pointer()->IsHighResolution(); 540 } 541 542 #else // V8_OS_WIN 543 544 TimeTicks TimeTicks::Now() { 545 return HighResolutionNow(); 546 } 547 548 549 TimeTicks TimeTicks::HighResolutionNow() { 550 int64_t ticks; 551 #if V8_OS_MACOSX 552 static struct mach_timebase_info info; 553 if (info.denom == 0) { 554 kern_return_t result = mach_timebase_info(&info); 555 ASSERT_EQ(KERN_SUCCESS, result); 556 USE(result); 557 } 558 ticks = (mach_absolute_time() / Time::kNanosecondsPerMicrosecond * 559 info.numer / info.denom); 560 #elif V8_OS_SOLARIS 561 ticks = (gethrtime() / Time::kNanosecondsPerMicrosecond); 562 #elif V8_LIBRT_NOT_AVAILABLE 563 // TODO(bmeurer): This is a temporary hack to support cross-compiling 564 // Chrome for Android in AOSP. Remove this once AOSP is fixed, also 565 // cleanup the tools/gyp/v8.gyp file. 566 struct timeval tv; 567 int result = gettimeofday(&tv, NULL); 568 ASSERT_EQ(0, result); 569 USE(result); 570 ticks = (tv.tv_sec * Time::kMicrosecondsPerSecond + tv.tv_usec); 571 #elif V8_OS_POSIX 572 struct timespec ts; 573 int result = clock_gettime(CLOCK_MONOTONIC, &ts); 574 ASSERT_EQ(0, result); 575 USE(result); 576 ticks = (ts.tv_sec * Time::kMicrosecondsPerSecond + 577 ts.tv_nsec / Time::kNanosecondsPerMicrosecond); 578 #endif // V8_OS_MACOSX 579 // Make sure we never return 0 here. 580 return TimeTicks(ticks + 1); 581 } 582 583 584 // static 585 bool TimeTicks::IsHighResolutionClockWorking() { 586 return true; 587 } 588 589 #endif // V8_OS_WIN 590 591 } } // namespace v8::internal 592