15#include <mach/mach_time.h>
21#include <zircon/syscalls.h>
22#include <zircon/threads.h>
48#include "starboard/common/time.h"
54int64_t ComputeThreadTicks() {
55 mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT;
56 thread_basic_info_data_t thread_info_data;
57 kern_return_t kr = thread_info(
58 pthread_mach_thread_np(pthread_self()),
60 reinterpret_cast<thread_info_t
>(&thread_info_data),
65 CHECK_LE(thread_info_data.user_time.seconds,
66 std::numeric_limits<int64_t>::max() -
67 thread_info_data.system_time.seconds);
69 thread_info_data.user_time.seconds + thread_info_data.system_time.seconds;
72 static constexpr int64_t kSecondsLimit =
73 (std::numeric_limits<int64_t>::max() /
78 micros += (thread_info_data.user_time.microseconds +
79 thread_info_data.system_time.microseconds);
83V8_INLINE int64_t GetFuchsiaThreadTicks() {
84 zx_info_thread_stats_t
info;
85 zx_status_t status = zx_object_get_info(thrd_get_zx_handle(thrd_current()),
86 ZX_INFO_THREAD_STATS, &info,
87 sizeof(info),
nullptr,
nullptr);
96V8_INLINE int64_t ClockNow(clockid_t clk_id) {
97#if (defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
98 defined(V8_OS_BSD) || defined(V8_OS_ANDROID) || defined(V8_OS_ZOS)
102 if (clk_id == CLOCK_THREAD_CPUTIME_ID) {
107 if (thread_cputime(-1, &tc) != 0) {
116 if (clock_gettime(clk_id, &ts) != 0) {
121 static constexpr int64_t kSecondsLimit =
122 (std::numeric_limits<int64_t>::max() /
136 clock_gettime(CLOCK_MONOTONIC, &ts);
141inline bool IsHighResolutionTimer(clockid_t clk_id) {
146 int64_t
previous = NanosecondsNow();
150 constexpr int kAttempts = 100;
151 for (
int i = 0;
i < kAttempts;
i++) {
152 int64_t next = NanosecondsNow();
154 if (delta == 0)
continue;
170 LARGE_INTEGER perf_counter_now = {};
174 BOOL result = ::QueryPerformanceCounter(&perf_counter_now);
177 return perf_counter_now.QuadPart;
189 return std::numeric_limits<int>::max();
197 return std::numeric_limits<int>::max();
205 return std::numeric_limits<int>::max();
213 return std::numeric_limits<double>::infinity();
221 return std::numeric_limits<int64_t>::max();
229 return std::numeric_limits<double>::infinity();
237 return std::numeric_limits<int64_t>::max();
245 return std::numeric_limits<int64_t>::max();
254 return std::numeric_limits<int64_t>::max();
262 return std::numeric_limits<int64_t>::max();
278struct mach_timespec TimeDelta::ToMachTimespec() const {
279 struct mach_timespec ts;
281 ts.tv_sec =
static_cast<unsigned>(delta_ / Time::kMicrosecondsPerSecond);
282 ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
283 Time::kNanosecondsPerMicrosecond;
300struct timespec TimeDelta::ToTimespec() const {
302 ts.tv_sec =
static_cast<time_t
>(delta_ / Time::kMicrosecondsPerSecond);
303 ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
304 Time::kNanosecondsPerMicrosecond;
318 Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {}
322 const TimeDelta kMaxElapsedTime = TimeDelta::FromMinutes(1);
327 TimeTicks ticks = GetSystemTicks();
328 Time time = GetSystemTime();
332 TimeDelta elapsed = ticks - initial_ticks_;
334 initial_ticks_ = ticks;
335 initial_time_ =
time;
339 return initial_time_ + elapsed;
342 Time NowFromSystemTime() {
344 initial_ticks_ = GetSystemTicks();
345 initial_time_ = GetSystemTime();
346 return initial_time_;
350 static TimeTicks GetSystemTicks() {
351 return TimeTicks::Now();
354 static Time GetSystemTime() {
356 ::GetSystemTimeAsFileTime(&ft);
357 return Time::FromFiletime(ft);
360 TimeTicks initial_ticks_;
374static const int64_t kTimeToEpochInMicroseconds = int64_t{11644473600000000};
377 if (ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0) {
380 if (ft.dwLowDateTime == std::numeric_limits<DWORD>::max() &&
381 ft.dwHighDateTime == std::numeric_limits<DWORD>::max()) {
384 int64_t us = (
static_cast<uint64_t
>(ft.dwLowDateTime) +
385 (
static_cast<uint64_t
>(ft.dwHighDateTime) << 32)) / 10;
386 return Time(us - kTimeToEpochInMicroseconds);
394 ft.dwLowDateTime = 0;
395 ft.dwHighDateTime = 0;
399 ft.dwLowDateTime = std::numeric_limits<DWORD>::max();
400 ft.dwHighDateTime = std::numeric_limits<DWORD>::max();
403 uint64_t us =
static_cast<uint64_t
>(
us_ + kTimeToEpochInMicroseconds) * 10;
404 ft.dwLowDateTime =
static_cast<DWORD>(us);
405 ft.dwHighDateTime =
static_cast<DWORD>(us >> 32);
409#elif V8_OS_POSIX || V8_OS_STARBOARD
413 int result = gettimeofday(&tv,
nullptr);
428 if (ts.tv_nsec == 0 && ts.tv_sec == 0) {
432 ts.tv_sec == std::numeric_limits<time_t>::max()) {
440struct timespec Time::ToTimespec() const {
448 ts.tv_sec = std::numeric_limits<time_t>::max();
449 ts.tv_nsec =
static_cast<long>(kNanosecondsPerSecond - 1);
452 ts.tv_sec =
static_cast<time_t
>(us_ / kMicrosecondsPerSecond);
453 ts.tv_nsec = (us_ % kMicrosecondsPerSecond) * kNanosecondsPerMicrosecond;
461 if (tv.tv_usec == 0 && tv.tv_sec == 0) {
465 tv.tv_sec == std::numeric_limits<time_t>::max()) {
472struct timeval Time::ToTimeval() const {
480 tv.tv_sec = std::numeric_limits<time_t>::max();
481 tv.tv_usec =
static_cast<suseconds_t
>(kMicrosecondsPerSecond - 1);
484 tv.tv_sec =
static_cast<time_t
>(us_ / kMicrosecondsPerSecond);
485 tv.tv_usec = us_ % kMicrosecondsPerSecond;
494 if (ms_since_epoch == std::numeric_limits<double>::max()) {
509 return std::numeric_limits<double>::max();
516 return os << time.ToJsTime();
527DWORD timeGetTimeWrapper() {
return timeGetTime(); }
529DWORD (*g_tick_function)(void) = &timeGetTimeWrapper;
533union LastTimeAndRolloversState {
535 int32_t as_opaque_32;
551std::atomic<int32_t> g_last_time_and_rollovers{0};
552static_assert(
sizeof(LastTimeAndRolloversState) <=
553 sizeof(g_last_time_and_rollovers),
554 "LastTimeAndRolloversState does not fit in a single atomic word");
561TimeTicks RolloverProtectedNow() {
562 LastTimeAndRolloversState
state;
569 int32_t original = g_last_time_and_rollovers.load(std::memory_order_acquire);
571 state.as_opaque_32 = original;
572 now = g_tick_function();
573 uint8_t now_8 =
static_cast<uint8_t
>(now >> 24);
574 if (now_8 < state.as_values.last_8) ++state.as_values.rollovers;
575 state.as_values.last_8 = now_8;
578 if (state.as_opaque_32 == original)
break;
582 if (g_last_time_and_rollovers.compare_exchange_weak(
583 original, state.as_opaque_32, std::memory_order_acq_rel)) {
592 TimeDelta::FromMilliseconds(
593 now + (
static_cast<uint64_t
>(state.as_values.rollovers) << 32));
631TimeTicks InitialTimeTicksNowFunction();
635using TimeTicksNowFunction =
decltype(&TimeTicks::Now);
636TimeTicksNowFunction g_time_ticks_now_function = &InitialTimeTicksNowFunction;
637int64_t g_qpc_ticks_per_second = 0;
639TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) {
642 std::atomic_thread_fence(std::memory_order_acquire);
648 if (qpc_value < TimeTicks::kQPCOverflowThreshold) {
649 return TimeDelta::FromMicroseconds(
650 qpc_value * TimeTicks::kMicrosecondsPerSecond / g_qpc_ticks_per_second);
654 int64_t whole_seconds = qpc_value / g_qpc_ticks_per_second;
655 int64_t leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second);
656 return TimeDelta::FromMicroseconds(
657 (whole_seconds * TimeTicks::kMicrosecondsPerSecond) +
658 ((leftover_ticks * TimeTicks::kMicrosecondsPerSecond) /
659 g_qpc_ticks_per_second));
662TimeTicks QPCNow() {
return TimeTicks() + QPCValueToTimeDelta(QPCNowRaw()); }
664void InitializeTimeTicksNowFunctionPointer() {
665 LARGE_INTEGER ticks_per_sec = {};
666 if (!QueryPerformanceFrequency(&ticks_per_sec)) ticks_per_sec.QuadPart = 0;
679 TimeTicksNowFunction now_function;
681 if (ticks_per_sec.QuadPart <= 0 || !cpu.has_non_stop_time_stamp_counter()) {
682 now_function = &RolloverProtectedNow;
684 now_function = &QPCNow;
696 g_qpc_ticks_per_second = ticks_per_sec.QuadPart;
697 std::atomic_thread_fence(std::memory_order_release);
698 g_time_ticks_now_function = now_function;
701TimeTicks InitialTimeTicksNowFunction() {
702 InitializeTimeTicksNowFunctionPointer();
703 return g_time_ticks_now_function();
706#if V8_HOST_ARCH_ARM64
709int64_t FileTimeToMicroseconds(
const FILETIME& ft) {
713 return bit_cast<int64_t, FILETIME>(ft) / 10;
722 TimeTicks ticks(g_time_ticks_now_function());
729 if (g_time_ticks_now_function == &InitialTimeTicksNowFunction)
730 InitializeTimeTicksNowFunctionPointer();
731 return g_time_ticks_now_function == &QPCNow;
739 static struct mach_timebase_info info;
740 if (info.denom == 0) {
741 kern_return_t
result = mach_timebase_info(&info);
746 info.numer / info.denom);
752 ticks = ClockNow(CLOCK_MONOTONIC);
754 ticks = starboard::CurrentMonotonicTime();
756#error platform does not implement TimeTicks::Now.
769 static const bool is_high_resolution = IsHighResolutionTimer(CLOCK_MONOTONIC);
770 return is_high_resolution;
781 return starboard::CurrentMonotonicThreadTime() != 0;
782#elif defined(__PASE__)
785#elif (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
786 defined(V8_OS_DARWIN) || defined(V8_OS_ANDROID) || \
787 defined(V8_OS_SOLARIS) || defined(V8_OS_ZOS)
789#elif defined(V8_OS_WIN)
790 return IsSupportedWin();
799 const int64_t now = starboard::CurrentMonotonicThreadTime();
807#elif (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
808 defined(V8_OS_ANDROID) || defined(V8_OS_ZOS)
809 return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID));
813 return ThreadTicks::GetForThread(::GetCurrentThread());
824#if V8_HOST_ARCH_ARM64
831 FILETIME creation_time, exit_time, kernel_time, user_time;
832 ::GetThreadTimes(thread_handle, &creation_time, &exit_time, &kernel_time,
835 int64_t us = FileTimeToMicroseconds(user_time);
839 ULONG64 thread_cycle_time = 0;
840 ::QueryThreadCycleTime(thread_handle, &thread_cycle_time);
843 double tsc_ticks_per_second = TSCTicksPerSecond();
844 if (tsc_ticks_per_second == 0)
848 double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second;
855bool ThreadTicks::IsSupportedWin() {
861void ThreadTicks::WaitUntilInitializedWin() {
862#ifndef V8_HOST_ARCH_ARM64
863 while (TSCTicksPerSecond() == 0) ::Sleep(10);
867#ifndef V8_HOST_ARCH_ARM64
868double ThreadTicks::TSCTicksPerSecond() {
877 static double tsc_ticks_per_second = 0;
878 if (tsc_ticks_per_second != 0)
879 return tsc_ticks_per_second;
883 int previous_priority = ::GetThreadPriority(::GetCurrentThread());
884 ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
888 static const uint64_t tsc_initial = __rdtsc();
889 static const uint64_t perf_counter_initial = QPCNowRaw();
893 uint64_t tsc_now = __rdtsc();
894 uint64_t perf_counter_now = QPCNowRaw();
897 ::SetThreadPriority(::GetCurrentThread(), previous_priority);
908 LARGE_INTEGER perf_counter_frequency = {};
909 ::QueryPerformanceFrequency(&perf_counter_frequency);
910 DCHECK_GE(perf_counter_now, perf_counter_initial);
911 uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
912 double elapsed_time_seconds =
913 perf_counter_ticks /
static_cast<double>(perf_counter_frequency.QuadPart);
915 const double kMinimumEvaluationPeriodSeconds = 0.05;
916 if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
921 uint64_t tsc_ticks = tsc_now - tsc_initial;
922 tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds;
924 return tsc_ticks_per_second;
bool has_non_stop_time_stamp_counter() const
static bool IsSupported()
static constexpr int64_t kMicrosecondsPerMinute
static constexpr int64_t kNanosecondsPerSecond
static constexpr int64_t kNanosecondsPerMicrosecond
static constexpr int64_t kMicrosecondsPerHour
static constexpr int64_t kMicrosecondsPerMillisecond
static constexpr int64_t kMicrosecondsPerSecond
static constexpr int64_t kMicrosecondsPerDay
int64_t InMillisecondsRoundedUp() const
int64_t InSeconds() const
double InMillisecondsF() const
static TimeDelta FromTimespec(struct timespec ts)
double InSecondsF() const
int64_t InMilliseconds() const
constexpr bool IsMax() const
static TimeDelta FromMachTimespec(struct mach_timespec ts)
int64_t InMicroseconds() const
int64_t InNanoseconds() const
static bool IsHighResolution()
static Time FromTimespec(struct timespec ts)
static Time NowFromSystemTime()
static Time FromJsTime(double ms_since_epoch)
static Time FromFiletime(struct _FILETIME ft)
struct _FILETIME ToFiletime() const
static Time FromTimeval(struct timeval tv)
constexpr bool IsMax() const
constexpr bool IsNull() const
Handle< SharedFunctionInfo > info
ZoneVector< RpoNumber > & result
#define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName,...)
LiftoffAssembler::CacheState state
LockGuard< Mutex > MutexGuard
std::ostream & operator<<(std::ostream &out, AddressRegion region)
kInstanceDescriptorsOffset kTransitionsOrPrototypeInfoOffset IsNull(value)||IsJSProxy(value)||IsWasmObject(value)||(IsJSObject(value) &&(HeapLayout
#define CHECK_GT(lhs, rhs)
#define CHECK_LE(lhs, rhs)
#define DCHECK_GE(v1, v2)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
#define DCHECK_GT(v1, v2)