From 8393ea5d1dd8e8b56a87a6edbca31fb8722cee48 Mon Sep 17 00:00:00 2001 From: Joseph Huber Date: Tue, 16 Jul 2024 16:17:34 -0500 Subject: [PATCH] [libc] Implement `clock_gettime` for the monotonic clock on the GPU (#99067) Summary: This patch implements `clock_gettime` using the monotonic clock. This allows users to get time elapsed at nanosecond resolution. This is primarily to facilitate compiling the `chrono` library from `libc++`. For this reason we provide both `CLOCK_MONOTONIC`, which we can implement with the GPU's global fixed-frequency clock, and `CLOCK_REALTIME` which we cannot. The latter is provided just to make people who use this header happy and it will always return failure. --- libc/config/gpu/entrypoints.txt | 1 + libc/docs/gpu/support.rst | 1 + .../llvm-libc-macros/gpu/time-macros.h | 3 ++ libc/include/time.h.def | 2 ++ libc/src/time/gpu/CMakeLists.txt | 12 +++++++ libc/src/time/gpu/clock_gettime.cpp | 32 +++++++++++++++++++ libc/test/src/time/CMakeLists.txt | 2 +- libc/test/src/time/clock_gettime_test.cpp | 11 +++++-- 8 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 libc/src/time/gpu/clock_gettime.cpp diff --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt index 36c5b8c8085286..b0c4652c6b8eeb 100644 --- a/libc/config/gpu/entrypoints.txt +++ b/libc/config/gpu/entrypoints.txt @@ -218,6 +218,7 @@ set(TARGET_LIBC_ENTRYPOINTS # time.h entrypoints libc.src.time.clock + libc.src.time.clock_gettime libc.src.time.nanosleep # wchar.h entrypoints diff --git a/libc/docs/gpu/support.rst b/libc/docs/gpu/support.rst index 6e2c8c7e93987c..89ea4d588a16f1 100644 --- a/libc/docs/gpu/support.rst +++ b/libc/docs/gpu/support.rst @@ -242,6 +242,7 @@ time.h Function Name Available RPC Required ============= ========= ============ clock |check| +clock_gettime |check| nanosleep |check| ============= ========= ============ diff --git a/libc/include/llvm-libc-macros/gpu/time-macros.h b/libc/include/llvm-libc-macros/gpu/time-macros.h index c3dc812f90a3be..7142a3e1b27641 100644 --- a/libc/include/llvm-libc-macros/gpu/time-macros.h +++ b/libc/include/llvm-libc-macros/gpu/time-macros.h @@ -9,6 +9,9 @@ #ifndef LLVM_LIBC_MACROS_GPU_TIME_MACROS_H #define LLVM_LIBC_MACROS_GPU_TIME_MACROS_H +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 + #define CLOCKS_PER_SEC 1000000 #endif // LLVM_LIBC_MACROS_GPU_TIME_MACROS_H diff --git a/libc/include/time.h.def b/libc/include/time.h.def index 2355e8822fad7a..3776dfcadad28e 100644 --- a/libc/include/time.h.def +++ b/libc/include/time.h.def @@ -11,6 +11,8 @@ #include "__llvm-libc-common.h" #include "llvm-libc-macros/time-macros.h" +#include "llvm-libc-types/clock_t.h" +#include "llvm-libc-types/clockid_t.h" %%public_api() diff --git a/libc/src/time/gpu/CMakeLists.txt b/libc/src/time/gpu/CMakeLists.txt index 088271d881911a..c9b45628158012 100644 --- a/libc/src/time/gpu/CMakeLists.txt +++ b/libc/src/time/gpu/CMakeLists.txt @@ -32,3 +32,15 @@ add_entrypoint_object( libc.src.__support.GPU.utils .time_utils ) + +add_entrypoint_object( + clock_gettime + SRCS + clock_gettime.cpp + HDRS + ../clock_gettime.h + DEPENDS + libc.hdr.types.clockid_t + libc.hdr.types.struct_timespec + .time_utils +) diff --git a/libc/src/time/gpu/clock_gettime.cpp b/libc/src/time/gpu/clock_gettime.cpp new file mode 100644 index 00000000000000..de7899a2a17cc0 --- /dev/null +++ b/libc/src/time/gpu/clock_gettime.cpp @@ -0,0 +1,32 @@ +//===---------- GPU implementation of the POSIX clock_gettime function ----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/time/clock_gettime.h" + +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "time_utils.h" + +namespace LIBC_NAMESPACE_DECL { + +constexpr uint64_t TICKS_PER_SEC = 1000000000UL; + +LLVM_LIBC_FUNCTION(int, clock_gettime, (clockid_t clockid, timespec *ts)) { + if (clockid != CLOCK_MONOTONIC || !ts) + return -1; + + uint64_t ns_per_tick = TICKS_PER_SEC / GPU_CLOCKS_PER_SEC; + uint64_t ticks = gpu::fixed_frequency_clock(); + + ts->tv_nsec = (ticks * ns_per_tick) % TICKS_PER_SEC; + ts->tv_sec = (ticks * ns_per_tick) / TICKS_PER_SEC; + + return 0; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt index 51cacef0a62fe8..78cfe8f301615f 100644 --- a/libc/test/src/time/CMakeLists.txt +++ b/libc/test/src/time/CMakeLists.txt @@ -30,7 +30,7 @@ add_libc_unittest( libc.src.time.asctime_r ) -add_libc_unittest( +add_libc_test( clock_gettime_test SUITE libc_time_unittests diff --git a/libc/test/src/time/clock_gettime_test.cpp b/libc/test/src/time/clock_gettime_test.cpp index 6367ae7145a47d..43715c0265f1f8 100644 --- a/libc/test/src/time/clock_gettime_test.cpp +++ b/libc/test/src/time/clock_gettime_test.cpp @@ -6,22 +6,29 @@ // //===----------------------------------------------------------------------===// +#include "src/__support/macros/properties/architectures.h" #include "src/time/clock_gettime.h" #include "test/UnitTest/Test.h" #include TEST(LlvmLibcClockGetTime, RealTime) { - struct timespec tp; + timespec tp; int result; result = LIBC_NAMESPACE::clock_gettime(CLOCK_REALTIME, &tp); + // The GPU does not implement CLOCK_REALTIME but provides it so programs will + // compile. +#ifdef LIBC_TARGET_ARCH_IS_GPU + ASSERT_EQ(result, -1); +#else ASSERT_EQ(result, 0); ASSERT_GT(tp.tv_sec, time_t(0)); +#endif } #ifdef CLOCK_MONOTONIC TEST(LlvmLibcClockGetTime, MonotonicTime) { - struct timespec tp1, tp2; + timespec tp1, tp2; int result; result = LIBC_NAMESPACE::clock_gettime(CLOCK_MONOTONIC, &tp1); ASSERT_EQ(result, 0);