1e6cf5d28SSchrodinger ZHU Yifan //===--- clock_gettime windows implementation -------------------*- C++ -*-===// 2e6cf5d28SSchrodinger ZHU Yifan // 3e6cf5d28SSchrodinger ZHU Yifan // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e6cf5d28SSchrodinger ZHU Yifan // See https://llvm.org/LICENSE.txt for license information. 5e6cf5d28SSchrodinger ZHU Yifan // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e6cf5d28SSchrodinger ZHU Yifan // 7e6cf5d28SSchrodinger ZHU Yifan //===----------------------------------------------------------------------===// 8e6cf5d28SSchrodinger ZHU Yifan 9e6cf5d28SSchrodinger ZHU Yifan #include "hdr/time_macros.h" 10e6cf5d28SSchrodinger ZHU Yifan 11e6cf5d28SSchrodinger ZHU Yifan #include "src/__support/CPP/atomic.h" 12e6cf5d28SSchrodinger ZHU Yifan #include "src/__support/CPP/bit.h" 13e6cf5d28SSchrodinger ZHU Yifan #include "src/__support/CPP/limits.h" 14e6cf5d28SSchrodinger ZHU Yifan #include "src/__support/macros/optimization.h" 15e6cf5d28SSchrodinger ZHU Yifan #include "src/__support/time/clock_gettime.h" 16e6cf5d28SSchrodinger ZHU Yifan #include "src/__support/time/units.h" 17*9a06fb7eSSchrodinger ZHU Yifan #include "src/__support/time/windows/performance_counter.h" 18e6cf5d28SSchrodinger ZHU Yifan 19e6cf5d28SSchrodinger ZHU Yifan #define WIN32_LEAN_AND_MEAN 20e6cf5d28SSchrodinger ZHU Yifan #define NOMINMAX 21e6cf5d28SSchrodinger ZHU Yifan #include <Windows.h> 22e6cf5d28SSchrodinger ZHU Yifan 23e6cf5d28SSchrodinger ZHU Yifan namespace LIBC_NAMESPACE_DECL { 24e6cf5d28SSchrodinger ZHU Yifan namespace internal { 25e6cf5d28SSchrodinger ZHU Yifan ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts) { 26e6cf5d28SSchrodinger ZHU Yifan using namespace time_units; 27e6cf5d28SSchrodinger ZHU Yifan constexpr unsigned long long HNS_PER_SEC = 1_s_ns / 100ULL; 28e6cf5d28SSchrodinger ZHU Yifan constexpr long long SEC_LIMIT = 29e6cf5d28SSchrodinger ZHU Yifan cpp::numeric_limits<decltype(ts->tv_sec)>::max(); 30e6cf5d28SSchrodinger ZHU Yifan ErrorOr<int> ret = 0; 31e6cf5d28SSchrodinger ZHU Yifan switch (clockid) { 32e6cf5d28SSchrodinger ZHU Yifan default: 33e6cf5d28SSchrodinger ZHU Yifan ret = cpp::unexpected(EINVAL); 34e6cf5d28SSchrodinger ZHU Yifan break; 35e6cf5d28SSchrodinger ZHU Yifan 36e6cf5d28SSchrodinger ZHU Yifan case CLOCK_MONOTONIC: { 37e6cf5d28SSchrodinger ZHU Yifan // see 38e6cf5d28SSchrodinger ZHU Yifan // https://learn.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps 39e6cf5d28SSchrodinger ZHU Yifan // Is the performance counter monotonic (non-decreasing)? 40*9a06fb7eSSchrodinger ZHU Yifan // Yes. performance_counter does not go backward. 41e6cf5d28SSchrodinger ZHU Yifan [[clang::uninitialized]] LARGE_INTEGER buffer; 42e6cf5d28SSchrodinger ZHU Yifan // On systems that run Windows XP or later, the function will always 43e6cf5d28SSchrodinger ZHU Yifan // succeed and will thus never return zero. 44e6cf5d28SSchrodinger ZHU Yifan ::QueryPerformanceCounter(&buffer); 45*9a06fb7eSSchrodinger ZHU Yifan long long freq = performance_counter::get_ticks_per_second(); 46e6cf5d28SSchrodinger ZHU Yifan long long ticks = buffer.QuadPart; 47e6cf5d28SSchrodinger ZHU Yifan long long tv_sec = ticks / freq; 48e6cf5d28SSchrodinger ZHU Yifan long long tv_nsec = (ticks % freq) * 1_s_ns / freq; 49e6cf5d28SSchrodinger ZHU Yifan if (LIBC_UNLIKELY(tv_sec > SEC_LIMIT)) { 50e6cf5d28SSchrodinger ZHU Yifan ret = cpp::unexpected(EOVERFLOW); 51e6cf5d28SSchrodinger ZHU Yifan break; 52e6cf5d28SSchrodinger ZHU Yifan } 53e6cf5d28SSchrodinger ZHU Yifan ts->tv_sec = static_cast<decltype(ts->tv_sec)>(tv_sec); 54e6cf5d28SSchrodinger ZHU Yifan ts->tv_nsec = static_cast<decltype(ts->tv_nsec)>(tv_nsec); 55e6cf5d28SSchrodinger ZHU Yifan break; 56e6cf5d28SSchrodinger ZHU Yifan } 57e6cf5d28SSchrodinger ZHU Yifan case CLOCK_REALTIME: { 58e6cf5d28SSchrodinger ZHU Yifan // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime 59e6cf5d28SSchrodinger ZHU Yifan // GetSystemTimePreciseAsFileTime 60e6cf5d28SSchrodinger ZHU Yifan // This function is best suited for high-resolution time-of-day 61e6cf5d28SSchrodinger ZHU Yifan // measurements, or time stamps that are synchronized to UTC 62e6cf5d28SSchrodinger ZHU Yifan [[clang::uninitialized]] FILETIME file_time; 63e6cf5d28SSchrodinger ZHU Yifan [[clang::uninitialized]] ULARGE_INTEGER time; 64e6cf5d28SSchrodinger ZHU Yifan ::GetSystemTimePreciseAsFileTime(&file_time); 65e6cf5d28SSchrodinger ZHU Yifan time.LowPart = file_time.dwLowDateTime; 66e6cf5d28SSchrodinger ZHU Yifan time.HighPart = file_time.dwHighDateTime; 67e6cf5d28SSchrodinger ZHU Yifan 68e6cf5d28SSchrodinger ZHU Yifan // adjust to POSIX epoch (from Jan 1, 1601 to Jan 1, 1970) 69e6cf5d28SSchrodinger ZHU Yifan constexpr unsigned long long POSIX_TIME_SHIFT = 70e6cf5d28SSchrodinger ZHU Yifan (11644473600ULL * HNS_PER_SEC); 71e6cf5d28SSchrodinger ZHU Yifan if (LIBC_UNLIKELY(POSIX_TIME_SHIFT > time.QuadPart)) { 72e6cf5d28SSchrodinger ZHU Yifan ret = cpp::unexpected(EOVERFLOW); 73e6cf5d28SSchrodinger ZHU Yifan break; 74e6cf5d28SSchrodinger ZHU Yifan } 75e6cf5d28SSchrodinger ZHU Yifan time.QuadPart -= (11644473600ULL * HNS_PER_SEC); 76e6cf5d28SSchrodinger ZHU Yifan unsigned long long tv_sec = time.QuadPart / HNS_PER_SEC; 77e6cf5d28SSchrodinger ZHU Yifan unsigned long long tv_nsec = (time.QuadPart % HNS_PER_SEC) * 100ULL; 78e6cf5d28SSchrodinger ZHU Yifan if (LIBC_UNLIKELY(tv_sec > SEC_LIMIT)) { 79e6cf5d28SSchrodinger ZHU Yifan ret = cpp::unexpected(EOVERFLOW); 80e6cf5d28SSchrodinger ZHU Yifan break; 81e6cf5d28SSchrodinger ZHU Yifan } 82e6cf5d28SSchrodinger ZHU Yifan ts->tv_sec = static_cast<decltype(ts->tv_sec)>(tv_sec); 83e6cf5d28SSchrodinger ZHU Yifan ts->tv_nsec = static_cast<decltype(ts->tv_nsec)>(tv_nsec); 84e6cf5d28SSchrodinger ZHU Yifan break; 85e6cf5d28SSchrodinger ZHU Yifan } 86e6cf5d28SSchrodinger ZHU Yifan case CLOCK_PROCESS_CPUTIME_ID: 87e6cf5d28SSchrodinger ZHU Yifan case CLOCK_THREAD_CPUTIME_ID: { 88e6cf5d28SSchrodinger ZHU Yifan [[clang::uninitialized]] FILETIME creation_time; 89e6cf5d28SSchrodinger ZHU Yifan [[clang::uninitialized]] FILETIME exit_time; 90e6cf5d28SSchrodinger ZHU Yifan [[clang::uninitialized]] FILETIME kernel_time; 91e6cf5d28SSchrodinger ZHU Yifan [[clang::uninitialized]] FILETIME user_time; 92e6cf5d28SSchrodinger ZHU Yifan bool success; 93e6cf5d28SSchrodinger ZHU Yifan if (clockid == CLOCK_PROCESS_CPUTIME_ID) { 94e6cf5d28SSchrodinger ZHU Yifan // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocesstimes 95e6cf5d28SSchrodinger ZHU Yifan success = ::GetProcessTimes(::GetCurrentProcess(), &creation_time, 96e6cf5d28SSchrodinger ZHU Yifan &exit_time, &kernel_time, &user_time); 97e6cf5d28SSchrodinger ZHU Yifan } else { 98e6cf5d28SSchrodinger ZHU Yifan // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadtimes 99e6cf5d28SSchrodinger ZHU Yifan success = ::GetThreadTimes(::GetCurrentThread(), &creation_time, 100e6cf5d28SSchrodinger ZHU Yifan &exit_time, &kernel_time, &user_time); 101e6cf5d28SSchrodinger ZHU Yifan } 102e6cf5d28SSchrodinger ZHU Yifan if (!success) { 103e6cf5d28SSchrodinger ZHU Yifan ret = cpp::unexpected(EINVAL); 104e6cf5d28SSchrodinger ZHU Yifan break; 105e6cf5d28SSchrodinger ZHU Yifan } 106e6cf5d28SSchrodinger ZHU Yifan // https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime 107e6cf5d28SSchrodinger ZHU Yifan // It is not recommended that you add and subtract values from the FILETIME 108e6cf5d28SSchrodinger ZHU Yifan // structure to obtain relative times. Instead, you should copy the low- and 109e6cf5d28SSchrodinger ZHU Yifan // high-order parts of the file time to a ULARGE_INTEGER structure, perform 110e6cf5d28SSchrodinger ZHU Yifan // 64-bit arithmetic on the QuadPart member, and copy the LowPart and 111e6cf5d28SSchrodinger ZHU Yifan // HighPart members into the FILETIME structure. 112e6cf5d28SSchrodinger ZHU Yifan auto kernel_time_hns = cpp::bit_cast<ULARGE_INTEGER>(kernel_time); 113e6cf5d28SSchrodinger ZHU Yifan auto user_time_hns = cpp::bit_cast<ULARGE_INTEGER>(user_time); 114e6cf5d28SSchrodinger ZHU Yifan unsigned long long total_time_hns = 115e6cf5d28SSchrodinger ZHU Yifan kernel_time_hns.QuadPart + user_time_hns.QuadPart; 116e6cf5d28SSchrodinger ZHU Yifan 117e6cf5d28SSchrodinger ZHU Yifan unsigned long long tv_sec = total_time_hns / HNS_PER_SEC; 118e6cf5d28SSchrodinger ZHU Yifan unsigned long long tv_nsec = (total_time_hns % HNS_PER_SEC) * 100ULL; 119e6cf5d28SSchrodinger ZHU Yifan 120e6cf5d28SSchrodinger ZHU Yifan if (LIBC_UNLIKELY(tv_sec > SEC_LIMIT)) { 121e6cf5d28SSchrodinger ZHU Yifan ret = cpp::unexpected(EOVERFLOW); 122e6cf5d28SSchrodinger ZHU Yifan break; 123e6cf5d28SSchrodinger ZHU Yifan } 124e6cf5d28SSchrodinger ZHU Yifan 125e6cf5d28SSchrodinger ZHU Yifan ts->tv_sec = static_cast<decltype(ts->tv_sec)>(tv_sec); 126e6cf5d28SSchrodinger ZHU Yifan ts->tv_nsec = static_cast<decltype(ts->tv_nsec)>(tv_nsec); 127e6cf5d28SSchrodinger ZHU Yifan 128e6cf5d28SSchrodinger ZHU Yifan break; 129e6cf5d28SSchrodinger ZHU Yifan } 130e6cf5d28SSchrodinger ZHU Yifan } 131e6cf5d28SSchrodinger ZHU Yifan return ret; 132e6cf5d28SSchrodinger ZHU Yifan } 133e6cf5d28SSchrodinger ZHU Yifan } // namespace internal 134e6cf5d28SSchrodinger ZHU Yifan } // namespace LIBC_NAMESPACE_DECL 135