1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/base/platform/time.h" 6 7 #if V8_OS_POSIX 8 #include <fcntl.h> // for O_RDONLY 9 #include <sys/time.h> 10 #include <unistd.h> 11 #endif 12 #if V8_OS_MACOSX 13 #include <mach/mach.h> 14 #include <mach/mach_time.h> 15 #include <pthread.h> 16 #endif 17 18 #include <cstring> 19 #include <ostream> 20 21 #if V8_OS_WIN 22 #include "src/base/atomicops.h" 23 #include "src/base/lazy-instance.h" 24 #include "src/base/win32-headers.h" 25 #endif 26 #include "src/base/cpu.h" 27 #include "src/base/logging.h" 28 #include "src/base/platform/platform.h" 29 30 namespace { 31 32 #if V8_OS_MACOSX 33 int64_t ComputeThreadTicks() { 34 mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT; 35 thread_basic_info_data_t thread_info_data; 36 kern_return_t kr = thread_info( 37 pthread_mach_thread_np(pthread_self()), 38 THREAD_BASIC_INFO, 39 reinterpret_cast<thread_info_t>(&thread_info_data), 40 &thread_info_count); 41 CHECK(kr == KERN_SUCCESS); 42 43 v8::base::CheckedNumeric<int64_t> absolute_micros( 44 thread_info_data.user_time.seconds + 45 thread_info_data.system_time.seconds); 46 absolute_micros *= v8::base::Time::kMicrosecondsPerSecond; 47 absolute_micros += (thread_info_data.user_time.microseconds + 48 thread_info_data.system_time.microseconds); 49 return absolute_micros.ValueOrDie(); 50 } 51 #elif V8_OS_POSIX 52 // Helper function to get results from clock_gettime() and convert to a 53 // microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported 54 // on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines 55 // _POSIX_MONOTONIC_CLOCK to -1. 56 V8_INLINE int64_t ClockNow(clockid_t clk_id) { 57 #if (defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \ 58 defined(V8_OS_BSD) || defined(V8_OS_ANDROID) 59 // On AIX clock_gettime for CLOCK_THREAD_CPUTIME_ID outputs time with 60 // resolution of 10ms. thread_cputime API provides the time in ns 61 #if defined(V8_OS_AIX) 62 thread_cputime_t tc; 63 if (clk_id == CLOCK_THREAD_CPUTIME_ID) { 64 if (thread_cputime(-1, &tc) != 0) { 65 UNREACHABLE(); 66 return 0; 67 } 68 } 69 #endif 70 struct timespec ts; 71 if (clock_gettime(clk_id, &ts) != 0) { 72 UNREACHABLE(); 73 return 0; 74 } 75 v8::base::internal::CheckedNumeric<int64_t> result(ts.tv_sec); 76 result *= v8::base::Time::kMicrosecondsPerSecond; 77 #if defined(V8_OS_AIX) 78 if (clk_id == CLOCK_THREAD_CPUTIME_ID) { 79 result += (tc.stime / v8::base::Time::kNanosecondsPerMicrosecond); 80 } else { 81 result += (ts.tv_nsec / v8::base::Time::kNanosecondsPerMicrosecond); 82 } 83 #else 84 result += (ts.tv_nsec / v8::base::Time::kNanosecondsPerMicrosecond); 85 #endif 86 return result.ValueOrDie(); 87 #else // Monotonic clock not supported. 88 return 0; 89 #endif 90 } 91 #elif V8_OS_WIN 92 V8_INLINE bool IsQPCReliable() { 93 v8::base::CPU cpu; 94 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. 95 return strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15; 96 } 97 98 // Returns the current value of the performance counter. 99 V8_INLINE uint64_t QPCNowRaw() { 100 LARGE_INTEGER perf_counter_now = {}; 101 // According to the MSDN documentation for QueryPerformanceCounter(), this 102 // will never fail on systems that run XP or later. 103 // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx 104 BOOL result = ::QueryPerformanceCounter(&perf_counter_now); 105 DCHECK(result); 106 USE(result); 107 return perf_counter_now.QuadPart; 108 } 109 #endif // V8_OS_MACOSX 110 111 112 } // namespace 113 114 namespace v8 { 115 namespace base { 116 117 TimeDelta TimeDelta::FromDays(int days) { 118 return TimeDelta(days * Time::kMicrosecondsPerDay); 119 } 120 121 122 TimeDelta TimeDelta::FromHours(int hours) { 123 return TimeDelta(hours * Time::kMicrosecondsPerHour); 124 } 125 126 127 TimeDelta TimeDelta::FromMinutes(int minutes) { 128 return TimeDelta(minutes * Time::kMicrosecondsPerMinute); 129 } 130 131 132 TimeDelta TimeDelta::FromSeconds(int64_t seconds) { 133 return TimeDelta(seconds * Time::kMicrosecondsPerSecond); 134 } 135 136 137 TimeDelta TimeDelta::FromMilliseconds(int64_t milliseconds) { 138 return TimeDelta(milliseconds * Time::kMicrosecondsPerMillisecond); 139 } 140 141 142 TimeDelta TimeDelta::FromNanoseconds(int64_t nanoseconds) { 143 return TimeDelta(nanoseconds / Time::kNanosecondsPerMicrosecond); 144 } 145 146 147 int TimeDelta::InDays() const { 148 return static_cast<int>(delta_ / Time::kMicrosecondsPerDay); 149 } 150 151 152 int TimeDelta::InHours() const { 153 return static_cast<int>(delta_ / Time::kMicrosecondsPerHour); 154 } 155 156 157 int TimeDelta::InMinutes() const { 158 return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute); 159 } 160 161 162 double TimeDelta::InSecondsF() const { 163 return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond; 164 } 165 166 167 int64_t TimeDelta::InSeconds() const { 168 return delta_ / Time::kMicrosecondsPerSecond; 169 } 170 171 172 double TimeDelta::InMillisecondsF() const { 173 return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond; 174 } 175 176 177 int64_t TimeDelta::InMilliseconds() const { 178 return delta_ / Time::kMicrosecondsPerMillisecond; 179 } 180 181 182 int64_t TimeDelta::InNanoseconds() const { 183 return delta_ * Time::kNanosecondsPerMicrosecond; 184 } 185 186 187 #if V8_OS_MACOSX 188 189 TimeDelta TimeDelta::FromMachTimespec(struct mach_timespec ts) { 190 DCHECK_GE(ts.tv_nsec, 0); 191 DCHECK_LT(ts.tv_nsec, 192 static_cast<long>(Time::kNanosecondsPerSecond)); // NOLINT 193 return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond + 194 ts.tv_nsec / Time::kNanosecondsPerMicrosecond); 195 } 196 197 198 struct mach_timespec TimeDelta::ToMachTimespec() const { 199 struct mach_timespec ts; 200 DCHECK(delta_ >= 0); 201 ts.tv_sec = static_cast<unsigned>(delta_ / Time::kMicrosecondsPerSecond); 202 ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) * 203 Time::kNanosecondsPerMicrosecond; 204 return ts; 205 } 206 207 #endif // V8_OS_MACOSX 208 209 210 #if V8_OS_POSIX 211 212 TimeDelta TimeDelta::FromTimespec(struct timespec ts) { 213 DCHECK_GE(ts.tv_nsec, 0); 214 DCHECK_LT(ts.tv_nsec, 215 static_cast<long>(Time::kNanosecondsPerSecond)); // NOLINT 216 return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond + 217 ts.tv_nsec / Time::kNanosecondsPerMicrosecond); 218 } 219 220 221 struct timespec TimeDelta::ToTimespec() const { 222 struct timespec ts; 223 ts.tv_sec = static_cast<time_t>(delta_ / Time::kMicrosecondsPerSecond); 224 ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) * 225 Time::kNanosecondsPerMicrosecond; 226 return ts; 227 } 228 229 #endif // V8_OS_POSIX 230 231 232 #if V8_OS_WIN 233 234 // We implement time using the high-resolution timers so that we can get 235 // timeouts which are smaller than 10-15ms. To avoid any drift, we 236 // periodically resync the internal clock to the system clock. 237 class Clock final { 238 public: 239 Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {} 240 241 Time Now() { 242 // Time between resampling the un-granular clock for this API (1 minute). 243 const TimeDelta kMaxElapsedTime = TimeDelta::FromMinutes(1); 244 245 LockGuard<Mutex> lock_guard(&mutex_); 246 247 // Determine current time and ticks. 248 TimeTicks ticks = GetSystemTicks(); 249 Time time = GetSystemTime(); 250 251 // Check if we need to synchronize with the system clock due to a backwards 252 // time change or the amount of time elapsed. 253 TimeDelta elapsed = ticks - initial_ticks_; 254 if (time < initial_time_ || elapsed > kMaxElapsedTime) { 255 initial_ticks_ = ticks; 256 initial_time_ = time; 257 return time; 258 } 259 260 return initial_time_ + elapsed; 261 } 262 263 Time NowFromSystemTime() { 264 LockGuard<Mutex> lock_guard(&mutex_); 265 initial_ticks_ = GetSystemTicks(); 266 initial_time_ = GetSystemTime(); 267 return initial_time_; 268 } 269 270 private: 271 static TimeTicks GetSystemTicks() { 272 return TimeTicks::Now(); 273 } 274 275 static Time GetSystemTime() { 276 FILETIME ft; 277 ::GetSystemTimeAsFileTime(&ft); 278 return Time::FromFiletime(ft); 279 } 280 281 TimeTicks initial_ticks_; 282 Time initial_time_; 283 Mutex mutex_; 284 }; 285 286 287 static LazyStaticInstance<Clock, DefaultConstructTrait<Clock>, 288 ThreadSafeInitOnceTrait>::type clock = 289 LAZY_STATIC_INSTANCE_INITIALIZER; 290 291 292 Time Time::Now() { 293 return clock.Pointer()->Now(); 294 } 295 296 297 Time Time::NowFromSystemTime() { 298 return clock.Pointer()->NowFromSystemTime(); 299 } 300 301 302 // Time between windows epoch and standard epoch. 303 static const int64_t kTimeToEpochInMicroseconds = V8_INT64_C(11644473600000000); 304 305 306 Time Time::FromFiletime(FILETIME ft) { 307 if (ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0) { 308 return Time(); 309 } 310 if (ft.dwLowDateTime == std::numeric_limits<DWORD>::max() && 311 ft.dwHighDateTime == std::numeric_limits<DWORD>::max()) { 312 return Max(); 313 } 314 int64_t us = (static_cast<uint64_t>(ft.dwLowDateTime) + 315 (static_cast<uint64_t>(ft.dwHighDateTime) << 32)) / 10; 316 return Time(us - kTimeToEpochInMicroseconds); 317 } 318 319 320 FILETIME Time::ToFiletime() const { 321 DCHECK(us_ >= 0); 322 FILETIME ft; 323 if (IsNull()) { 324 ft.dwLowDateTime = 0; 325 ft.dwHighDateTime = 0; 326 return ft; 327 } 328 if (IsMax()) { 329 ft.dwLowDateTime = std::numeric_limits<DWORD>::max(); 330 ft.dwHighDateTime = std::numeric_limits<DWORD>::max(); 331 return ft; 332 } 333 uint64_t us = static_cast<uint64_t>(us_ + kTimeToEpochInMicroseconds) * 10; 334 ft.dwLowDateTime = static_cast<DWORD>(us); 335 ft.dwHighDateTime = static_cast<DWORD>(us >> 32); 336 return ft; 337 } 338 339 #elif V8_OS_POSIX 340 341 Time Time::Now() { 342 struct timeval tv; 343 int result = gettimeofday(&tv, NULL); 344 DCHECK_EQ(0, result); 345 USE(result); 346 return FromTimeval(tv); 347 } 348 349 350 Time Time::NowFromSystemTime() { 351 return Now(); 352 } 353 354 355 Time Time::FromTimespec(struct timespec ts) { 356 DCHECK(ts.tv_nsec >= 0); 357 DCHECK(ts.tv_nsec < static_cast<long>(kNanosecondsPerSecond)); // NOLINT 358 if (ts.tv_nsec == 0 && ts.tv_sec == 0) { 359 return Time(); 360 } 361 if (ts.tv_nsec == static_cast<long>(kNanosecondsPerSecond - 1) && // NOLINT 362 ts.tv_sec == std::numeric_limits<time_t>::max()) { 363 return Max(); 364 } 365 return Time(ts.tv_sec * kMicrosecondsPerSecond + 366 ts.tv_nsec / kNanosecondsPerMicrosecond); 367 } 368 369 370 struct timespec Time::ToTimespec() const { 371 struct timespec ts; 372 if (IsNull()) { 373 ts.tv_sec = 0; 374 ts.tv_nsec = 0; 375 return ts; 376 } 377 if (IsMax()) { 378 ts.tv_sec = std::numeric_limits<time_t>::max(); 379 ts.tv_nsec = static_cast<long>(kNanosecondsPerSecond - 1); // NOLINT 380 return ts; 381 } 382 ts.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond); 383 ts.tv_nsec = (us_ % kMicrosecondsPerSecond) * kNanosecondsPerMicrosecond; 384 return ts; 385 } 386 387 388 Time Time::FromTimeval(struct timeval tv) { 389 DCHECK(tv.tv_usec >= 0); 390 DCHECK(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond)); 391 if (tv.tv_usec == 0 && tv.tv_sec == 0) { 392 return Time(); 393 } 394 if (tv.tv_usec == static_cast<suseconds_t>(kMicrosecondsPerSecond - 1) && 395 tv.tv_sec == std::numeric_limits<time_t>::max()) { 396 return Max(); 397 } 398 return Time(tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec); 399 } 400 401 402 struct timeval Time::ToTimeval() const { 403 struct timeval tv; 404 if (IsNull()) { 405 tv.tv_sec = 0; 406 tv.tv_usec = 0; 407 return tv; 408 } 409 if (IsMax()) { 410 tv.tv_sec = std::numeric_limits<time_t>::max(); 411 tv.tv_usec = static_cast<suseconds_t>(kMicrosecondsPerSecond - 1); 412 return tv; 413 } 414 tv.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond); 415 tv.tv_usec = us_ % kMicrosecondsPerSecond; 416 return tv; 417 } 418 419 #endif // V8_OS_WIN 420 421 422 Time Time::FromJsTime(double ms_since_epoch) { 423 // The epoch is a valid time, so this constructor doesn't interpret 424 // 0 as the null time. 425 if (ms_since_epoch == std::numeric_limits<double>::max()) { 426 return Max(); 427 } 428 return Time( 429 static_cast<int64_t>(ms_since_epoch * kMicrosecondsPerMillisecond)); 430 } 431 432 433 double Time::ToJsTime() const { 434 if (IsNull()) { 435 // Preserve 0 so the invalid result doesn't depend on the platform. 436 return 0; 437 } 438 if (IsMax()) { 439 // Preserve max without offset to prevent overflow. 440 return std::numeric_limits<double>::max(); 441 } 442 return static_cast<double>(us_) / kMicrosecondsPerMillisecond; 443 } 444 445 446 std::ostream& operator<<(std::ostream& os, const Time& time) { 447 return os << time.ToJsTime(); 448 } 449 450 451 #if V8_OS_WIN 452 453 class TickClock { 454 public: 455 virtual ~TickClock() {} 456 virtual int64_t Now() = 0; 457 virtual bool IsHighResolution() = 0; 458 }; 459 460 461 // Overview of time counters: 462 // (1) CPU cycle counter. (Retrieved via RDTSC) 463 // The CPU counter provides the highest resolution time stamp and is the least 464 // expensive to retrieve. However, the CPU counter is unreliable and should not 465 // be used in production. Its biggest issue is that it is per processor and it 466 // is not synchronized between processors. Also, on some computers, the counters 467 // will change frequency due to thermal and power changes, and stop in some 468 // states. 469 // 470 // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high- 471 // resolution (100 nanoseconds) time stamp but is comparatively more expensive 472 // to retrieve. What QueryPerformanceCounter actually does is up to the HAL. 473 // (with some help from ACPI). 474 // According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx 475 // in the worst case, it gets the counter from the rollover interrupt on the 476 // programmable interrupt timer. In best cases, the HAL may conclude that the 477 // RDTSC counter runs at a constant frequency, then it uses that instead. On 478 // multiprocessor machines, it will try to verify the values returned from 479 // RDTSC on each processor are consistent with each other, and apply a handful 480 // of workarounds for known buggy hardware. In other words, QPC is supposed to 481 // give consistent result on a multiprocessor computer, but it is unreliable in 482 // reality due to bugs in BIOS or HAL on some, especially old computers. 483 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but 484 // it should be used with caution. 485 // 486 // (3) System time. The system time provides a low-resolution (typically 10ms 487 // to 55 milliseconds) time stamp but is comparatively less expensive to 488 // retrieve and more reliable. 489 class HighResolutionTickClock final : public TickClock { 490 public: 491 explicit HighResolutionTickClock(int64_t ticks_per_second) 492 : ticks_per_second_(ticks_per_second) { 493 DCHECK_LT(0, ticks_per_second); 494 } 495 virtual ~HighResolutionTickClock() {} 496 497 int64_t Now() override { 498 uint64_t now = QPCNowRaw(); 499 500 // Intentionally calculate microseconds in a round about manner to avoid 501 // overflow and precision issues. Think twice before simplifying! 502 int64_t whole_seconds = now / ticks_per_second_; 503 int64_t leftover_ticks = now % ticks_per_second_; 504 int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) + 505 ((leftover_ticks * Time::kMicrosecondsPerSecond) / ticks_per_second_); 506 507 // Make sure we never return 0 here, so that TimeTicks::HighResolutionNow() 508 // will never return 0. 509 return ticks + 1; 510 } 511 512 bool IsHighResolution() override { return true; } 513 514 private: 515 int64_t ticks_per_second_; 516 }; 517 518 519 class RolloverProtectedTickClock final : public TickClock { 520 public: 521 RolloverProtectedTickClock() : rollover_(0) {} 522 virtual ~RolloverProtectedTickClock() {} 523 524 int64_t Now() override { 525 // We use timeGetTime() to implement TimeTicks::Now(), which rolls over 526 // every ~49.7 days. We try to track rollover ourselves, which works if 527 // TimeTicks::Now() is called at least every 24 days. 528 // Note that we do not use GetTickCount() here, since timeGetTime() gives 529 // more predictable delta values, as described here: 530 // http://blogs.msdn.com/b/larryosterman/archive/2009/09/02/what-s-the-difference-between-gettickcount-and-timegettime.aspx 531 // timeGetTime() provides 1ms granularity when combined with 532 // timeBeginPeriod(). If the host application for V8 wants fast timers, it 533 // can use timeBeginPeriod() to increase the resolution. 534 // We use a lock-free version because the sampler thread calls it 535 // while having the rest of the world stopped, that could cause a deadlock. 536 base::Atomic32 rollover = base::Acquire_Load(&rollover_); 537 uint32_t now = static_cast<uint32_t>(timeGetTime()); 538 if ((now >> 31) != static_cast<uint32_t>(rollover & 1)) { 539 base::Release_CompareAndSwap(&rollover_, rollover, rollover + 1); 540 ++rollover; 541 } 542 uint64_t ms = (static_cast<uint64_t>(rollover) << 31) | now; 543 return static_cast<int64_t>(ms * Time::kMicrosecondsPerMillisecond); 544 } 545 546 bool IsHighResolution() override { return false; } 547 548 private: 549 base::Atomic32 rollover_; 550 }; 551 552 553 static LazyStaticInstance<RolloverProtectedTickClock, 554 DefaultConstructTrait<RolloverProtectedTickClock>, 555 ThreadSafeInitOnceTrait>::type tick_clock = 556 LAZY_STATIC_INSTANCE_INITIALIZER; 557 558 559 struct CreateHighResTickClockTrait { 560 static TickClock* Create() { 561 // Check if the installed hardware supports a high-resolution performance 562 // counter, and if not fallback to the low-resolution tick clock. 563 LARGE_INTEGER ticks_per_second; 564 if (!QueryPerformanceFrequency(&ticks_per_second)) { 565 return tick_clock.Pointer(); 566 } 567 568 // If QPC not reliable, fallback to low-resolution tick clock. 569 if (IsQPCReliable()) { 570 return tick_clock.Pointer(); 571 } 572 573 return new HighResolutionTickClock(ticks_per_second.QuadPart); 574 } 575 }; 576 577 578 static LazyDynamicInstance<TickClock, CreateHighResTickClockTrait, 579 ThreadSafeInitOnceTrait>::type high_res_tick_clock = 580 LAZY_DYNAMIC_INSTANCE_INITIALIZER; 581 582 583 TimeTicks TimeTicks::Now() { 584 // Make sure we never return 0 here. 585 TimeTicks ticks(tick_clock.Pointer()->Now()); 586 DCHECK(!ticks.IsNull()); 587 return ticks; 588 } 589 590 591 TimeTicks TimeTicks::HighResolutionNow() { 592 // Make sure we never return 0 here. 593 TimeTicks ticks(high_res_tick_clock.Pointer()->Now()); 594 DCHECK(!ticks.IsNull()); 595 return ticks; 596 } 597 598 599 // static 600 bool TimeTicks::IsHighResolutionClockWorking() { 601 return high_res_tick_clock.Pointer()->IsHighResolution(); 602 } 603 604 #else // V8_OS_WIN 605 606 TimeTicks TimeTicks::Now() { 607 return HighResolutionNow(); 608 } 609 610 611 TimeTicks TimeTicks::HighResolutionNow() { 612 int64_t ticks; 613 #if V8_OS_MACOSX 614 static struct mach_timebase_info info; 615 if (info.denom == 0) { 616 kern_return_t result = mach_timebase_info(&info); 617 DCHECK_EQ(KERN_SUCCESS, result); 618 USE(result); 619 } 620 ticks = (mach_absolute_time() / Time::kNanosecondsPerMicrosecond * 621 info.numer / info.denom); 622 #elif V8_OS_SOLARIS 623 ticks = (gethrtime() / Time::kNanosecondsPerMicrosecond); 624 #elif V8_OS_POSIX 625 ticks = ClockNow(CLOCK_MONOTONIC); 626 #endif // V8_OS_MACOSX 627 // Make sure we never return 0 here. 628 return TimeTicks(ticks + 1); 629 } 630 631 632 // static 633 bool TimeTicks::IsHighResolutionClockWorking() { 634 return true; 635 } 636 637 #endif // V8_OS_WIN 638 639 640 bool ThreadTicks::IsSupported() { 641 #if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ 642 defined(V8_OS_MACOSX) || defined(V8_OS_ANDROID) || defined(V8_OS_SOLARIS) 643 return true; 644 #elif defined(V8_OS_WIN) 645 return IsSupportedWin(); 646 #else 647 return false; 648 #endif 649 } 650 651 652 ThreadTicks ThreadTicks::Now() { 653 #if V8_OS_MACOSX 654 return ThreadTicks(ComputeThreadTicks()); 655 #elif(defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ 656 defined(V8_OS_ANDROID) 657 return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID)); 658 #elif V8_OS_SOLARIS 659 return ThreadTicks(gethrvtime() / Time::kNanosecondsPerMicrosecond); 660 #elif V8_OS_WIN 661 return ThreadTicks::GetForThread(::GetCurrentThread()); 662 #else 663 UNREACHABLE(); 664 return ThreadTicks(); 665 #endif 666 } 667 668 669 #if V8_OS_WIN 670 ThreadTicks ThreadTicks::GetForThread(const HANDLE& thread_handle) { 671 DCHECK(IsSupported()); 672 673 // Get the number of TSC ticks used by the current thread. 674 ULONG64 thread_cycle_time = 0; 675 ::QueryThreadCycleTime(thread_handle, &thread_cycle_time); 676 677 // Get the frequency of the TSC. 678 double tsc_ticks_per_second = TSCTicksPerSecond(); 679 if (tsc_ticks_per_second == 0) 680 return ThreadTicks(); 681 682 // Return the CPU time of the current thread. 683 double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second; 684 return ThreadTicks( 685 static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond)); 686 } 687 688 // static 689 bool ThreadTicks::IsSupportedWin() { 690 static bool is_supported = base::CPU().has_non_stop_time_stamp_counter() && 691 !IsQPCReliable(); 692 return is_supported; 693 } 694 695 // static 696 void ThreadTicks::WaitUntilInitializedWin() { 697 while (TSCTicksPerSecond() == 0) 698 ::Sleep(10); 699 } 700 701 double ThreadTicks::TSCTicksPerSecond() { 702 DCHECK(IsSupported()); 703 704 // The value returned by QueryPerformanceFrequency() cannot be used as the TSC 705 // frequency, because there is no guarantee that the TSC frequency is equal to 706 // the performance counter frequency. 707 708 // The TSC frequency is cached in a static variable because it takes some time 709 // to compute it. 710 static double tsc_ticks_per_second = 0; 711 if (tsc_ticks_per_second != 0) 712 return tsc_ticks_per_second; 713 714 // Increase the thread priority to reduces the chances of having a context 715 // switch during a reading of the TSC and the performance counter. 716 int previous_priority = ::GetThreadPriority(::GetCurrentThread()); 717 ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST); 718 719 // The first time that this function is called, make an initial reading of the 720 // TSC and the performance counter. 721 static const uint64_t tsc_initial = __rdtsc(); 722 static const uint64_t perf_counter_initial = QPCNowRaw(); 723 724 // Make a another reading of the TSC and the performance counter every time 725 // that this function is called. 726 uint64_t tsc_now = __rdtsc(); 727 uint64_t perf_counter_now = QPCNowRaw(); 728 729 // Reset the thread priority. 730 ::SetThreadPriority(::GetCurrentThread(), previous_priority); 731 732 // Make sure that at least 50 ms elapsed between the 2 readings. The first 733 // time that this function is called, we don't expect this to be the case. 734 // Note: The longer the elapsed time between the 2 readings is, the more 735 // accurate the computed TSC frequency will be. The 50 ms value was 736 // chosen because local benchmarks show that it allows us to get a 737 // stddev of less than 1 tick/us between multiple runs. 738 // Note: According to the MSDN documentation for QueryPerformanceFrequency(), 739 // this will never fail on systems that run XP or later. 740 // https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx 741 LARGE_INTEGER perf_counter_frequency = {}; 742 ::QueryPerformanceFrequency(&perf_counter_frequency); 743 DCHECK_GE(perf_counter_now, perf_counter_initial); 744 uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial; 745 double elapsed_time_seconds = 746 perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart); 747 748 const double kMinimumEvaluationPeriodSeconds = 0.05; 749 if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds) 750 return 0; 751 752 // Compute the frequency of the TSC. 753 DCHECK_GE(tsc_now, tsc_initial); 754 uint64_t tsc_ticks = tsc_now - tsc_initial; 755 tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds; 756 757 return tsc_ticks_per_second; 758 } 759 #endif // V8_OS_WIN 760 761 } // namespace base 762 } // namespace v8 763