1*71db0c75SAndroid Build Coastguard Worker //===-- GPU implementation of the nanosleep function ----------------------===// 2*71db0c75SAndroid Build Coastguard Worker // 3*71db0c75SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*71db0c75SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information. 5*71db0c75SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*71db0c75SAndroid Build Coastguard Worker // 7*71db0c75SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 8*71db0c75SAndroid Build Coastguard Worker 9*71db0c75SAndroid Build Coastguard Worker #include "src/time/nanosleep.h" 10*71db0c75SAndroid Build Coastguard Worker 11*71db0c75SAndroid Build Coastguard Worker #include "src/__support/macros/config.h" 12*71db0c75SAndroid Build Coastguard Worker #include "time_utils.h" 13*71db0c75SAndroid Build Coastguard Worker 14*71db0c75SAndroid Build Coastguard Worker namespace LIBC_NAMESPACE_DECL { 15*71db0c75SAndroid Build Coastguard Worker 16*71db0c75SAndroid Build Coastguard Worker constexpr uint64_t TICKS_PER_SEC = 1000000000UL; 17*71db0c75SAndroid Build Coastguard Worker 18*71db0c75SAndroid Build Coastguard Worker LLVM_LIBC_FUNCTION(int, nanosleep, 19*71db0c75SAndroid Build Coastguard Worker (const struct timespec *req, struct timespec *rem)) { 20*71db0c75SAndroid Build Coastguard Worker if (!GPU_CLOCKS_PER_SEC || !req) 21*71db0c75SAndroid Build Coastguard Worker return -1; 22*71db0c75SAndroid Build Coastguard Worker 23*71db0c75SAndroid Build Coastguard Worker uint64_t nsecs = req->tv_nsec + req->tv_sec * TICKS_PER_SEC; 24*71db0c75SAndroid Build Coastguard Worker uint64_t tick_rate = TICKS_PER_SEC / GPU_CLOCKS_PER_SEC; 25*71db0c75SAndroid Build Coastguard Worker 26*71db0c75SAndroid Build Coastguard Worker uint64_t start = gpu::fixed_frequency_clock(); 27*71db0c75SAndroid Build Coastguard Worker #if defined(LIBC_TARGET_ARCH_IS_NVPTX) 28*71db0c75SAndroid Build Coastguard Worker uint64_t end = start + (nsecs + tick_rate - 1) / tick_rate; 29*71db0c75SAndroid Build Coastguard Worker uint64_t cur = gpu::fixed_frequency_clock(); 30*71db0c75SAndroid Build Coastguard Worker // The NVPTX architecture supports sleeping and guaruntees the actual time 31*71db0c75SAndroid Build Coastguard Worker // slept will be somewhere between zero and twice the requested amount. Here 32*71db0c75SAndroid Build Coastguard Worker // we will sleep again if we undershot the time. 33*71db0c75SAndroid Build Coastguard Worker while (cur < end) { 34*71db0c75SAndroid Build Coastguard Worker if (__nvvm_reflect("__CUDA_ARCH") >= 700) 35*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE_ASM("nanosleep.u32 %0;" ::"r"(nsecs)); 36*71db0c75SAndroid Build Coastguard Worker cur = gpu::fixed_frequency_clock(); 37*71db0c75SAndroid Build Coastguard Worker nsecs -= nsecs > cur - start ? cur - start : 0; 38*71db0c75SAndroid Build Coastguard Worker } 39*71db0c75SAndroid Build Coastguard Worker #elif defined(LIBC_TARGET_ARCH_IS_AMDGPU) 40*71db0c75SAndroid Build Coastguard Worker uint64_t end = start + (nsecs + tick_rate - 1) / tick_rate; 41*71db0c75SAndroid Build Coastguard Worker uint64_t cur = gpu::fixed_frequency_clock(); 42*71db0c75SAndroid Build Coastguard Worker // The AMDGPU architecture does not provide a sleep implementation with a 43*71db0c75SAndroid Build Coastguard Worker // known delay so we simply repeatedly sleep with a large value of ~960 clock 44*71db0c75SAndroid Build Coastguard Worker // cycles and check until we've passed the time using the known frequency. 45*71db0c75SAndroid Build Coastguard Worker __builtin_amdgcn_s_sleep(2); 46*71db0c75SAndroid Build Coastguard Worker while (cur < end) { 47*71db0c75SAndroid Build Coastguard Worker __builtin_amdgcn_s_sleep(15); 48*71db0c75SAndroid Build Coastguard Worker cur = gpu::fixed_frequency_clock(); 49*71db0c75SAndroid Build Coastguard Worker } 50*71db0c75SAndroid Build Coastguard Worker #else 51*71db0c75SAndroid Build Coastguard Worker // Sleeping is not supported. 52*71db0c75SAndroid Build Coastguard Worker if (rem) { 53*71db0c75SAndroid Build Coastguard Worker rem->tv_sec = req->tv_sec; 54*71db0c75SAndroid Build Coastguard Worker rem->tv_nsec = req->tv_nsec; 55*71db0c75SAndroid Build Coastguard Worker } 56*71db0c75SAndroid Build Coastguard Worker return -1; 57*71db0c75SAndroid Build Coastguard Worker #endif 58*71db0c75SAndroid Build Coastguard Worker uint64_t stop = gpu::fixed_frequency_clock(); 59*71db0c75SAndroid Build Coastguard Worker 60*71db0c75SAndroid Build Coastguard Worker // Check to make sure we slept for at least the desired duration and set the 61*71db0c75SAndroid Build Coastguard Worker // remaining time if not. 62*71db0c75SAndroid Build Coastguard Worker uint64_t elapsed = (stop - start) * tick_rate; 63*71db0c75SAndroid Build Coastguard Worker if (elapsed < nsecs) { 64*71db0c75SAndroid Build Coastguard Worker if (rem) { 65*71db0c75SAndroid Build Coastguard Worker rem->tv_sec = (nsecs - elapsed) / TICKS_PER_SEC; 66*71db0c75SAndroid Build Coastguard Worker rem->tv_nsec = (nsecs - elapsed) % TICKS_PER_SEC; 67*71db0c75SAndroid Build Coastguard Worker } 68*71db0c75SAndroid Build Coastguard Worker return -1; 69*71db0c75SAndroid Build Coastguard Worker } 70*71db0c75SAndroid Build Coastguard Worker 71*71db0c75SAndroid Build Coastguard Worker return 0; 72*71db0c75SAndroid Build Coastguard Worker } 73*71db0c75SAndroid Build Coastguard Worker 74*71db0c75SAndroid Build Coastguard Worker } // namespace LIBC_NAMESPACE_DECL 75