xref: /aosp_15_r20/external/llvm-libc/src/time/gpu/nanosleep.cpp (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
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