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