[libc-commits] [libc] b8daa45 - [libc] Implement `timespec_get` (#116102)

via libc-commits libc-commits at lists.llvm.org
Mon Dec 2 14:29:52 PST 2024


Author: Petr Hosek
Date: 2024-12-02T14:29:49-08:00
New Revision: b8daa45a566b15d929a812d85f3f1ff8c868c889

URL: https://github.com/llvm/llvm-project/commit/b8daa45a566b15d929a812d85f3f1ff8c868c889
DIFF: https://github.com/llvm/llvm-project/commit/b8daa45a566b15d929a812d85f3f1ff8c868c889.diff

LOG: [libc] Implement `timespec_get` (#116102)

`timespec_get` is C standard counterpart to POSIX `clock_gettime`. On
Linux we simply use `clock_gettime`. On baremetal we introduce a new
external API `__llvm_libc_timespec_get_utc` that should be implemented
by the vendor.

Added: 
    libc/src/time/baremetal/CMakeLists.txt
    libc/src/time/baremetal/timespec_get.cpp
    libc/src/time/gpu/timespec_get.cpp
    libc/src/time/linux/timespec_get.cpp
    libc/src/time/timespec_get.h
    libc/test/src/time/timespec_get_test.cpp

Modified: 
    libc/config/baremetal/arm/entrypoints.txt
    libc/config/baremetal/riscv/entrypoints.txt
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/riscv/entrypoints.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/include/llvm-libc-macros/time-macros.h
    libc/newhdrgen/yaml/time.yaml
    libc/spec/stdc.td
    libc/src/time/CMakeLists.txt
    libc/src/time/gpu/CMakeLists.txt
    libc/src/time/linux/CMakeLists.txt
    libc/test/src/time/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index b85ae1119345dd..9027717acb4dae 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -209,6 +209,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.time.gmtime
     libc.src.time.gmtime_r
     libc.src.time.mktime
+    libc.src.time.timespec_get
 
     # internal entrypoints
     libc.startup.baremetal.init

diff  --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 199a030ee6371e..afae2b3e082be3 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -205,6 +205,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.time.gmtime
     libc.src.time.gmtime_r
     libc.src.time.mktime
+    libc.src.time.timespec_get
 
     # internal entrypoints
     libc.startup.baremetal.init

diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 08b5072499da69..aa0b8ba0490e98 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1000,6 +1000,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.time.mktime
     libc.src.time.nanosleep
     libc.src.time.time
+    libc.src.time.timespec_get
 
     # unistd.h entrypoints
     libc.src.unistd.__llvm_libc_syscall

diff  --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 3baf734d3d8197..fedc5002d8c246 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -939,6 +939,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.time.mktime
     libc.src.time.nanosleep
     libc.src.time.time
+    libc.src.time.timespec_get
 
     # unistd.h entrypoints
     libc.src.unistd.__llvm_libc_syscall

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index d0651c06b930ad..af7f429561fe05 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1083,6 +1083,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.time.mktime
     libc.src.time.nanosleep
     libc.src.time.time
+    libc.src.time.timespec_get
 
     # locale.h entrypoints
     libc.src.locale.localeconv

diff  --git a/libc/include/llvm-libc-macros/time-macros.h b/libc/include/llvm-libc-macros/time-macros.h
index 6d49ed484d5d48..445d8b3e837edc 100644
--- a/libc/include/llvm-libc-macros/time-macros.h
+++ b/libc/include/llvm-libc-macros/time-macros.h
@@ -7,4 +7,9 @@
 #include "linux/time-macros.h"
 #endif
 
+#define TIME_UTC 1
+#define TIME_MONOTONIC 2
+#define TIME_ACTIVE 3
+#define TIME_THREAD_ACTIVE 4
+
 #endif // LLVM_LIBC_MACROS_TIME_MACROS_H

diff  --git a/libc/newhdrgen/yaml/time.yaml b/libc/newhdrgen/yaml/time.yaml
index 69b40bef3160dd..3f745e5ee33868 100644
--- a/libc/newhdrgen/yaml/time.yaml
+++ b/libc/newhdrgen/yaml/time.yaml
@@ -96,3 +96,10 @@ functions:
     return_type: time_t
     arguments:
       - type: time_t *
+  - name: timespec_get
+    standard:
+      - stdc
+    return_type: int
+    arguments:
+      - type: struct timespec *
+      - type: int

diff  --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 4fa057da1cf133..493ca1a6440df4 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -1676,6 +1676,14 @@ def StdC : StandardSpec<"stdc"> {
               RetValSpec<TimeTType>,
               [ArgSpec<TimeTTypePtr>]
           >,
+          FunctionSpec<
+              "timespec_get",
+              RetValSpec<IntType>,
+              [
+                ArgSpec<StructTimeSpecPtr>,
+                ArgSpec<IntType>,
+              ]
+          >,
       ]
   >;
 

diff  --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt
index b3318e7ca87fa5..f18e74a15e6fc2 100644
--- a/libc/src/time/CMakeLists.txt
+++ b/libc/src/time/CMakeLists.txt
@@ -111,6 +111,13 @@ add_entrypoint_object(
     .${LIBC_TARGET_OS}.time
 )
 
+add_entrypoint_object(
+  timespec_get
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.timespec_get
+)
+
 add_entrypoint_object(
   clock
   ALIAS

diff  --git a/libc/src/time/baremetal/CMakeLists.txt b/libc/src/time/baremetal/CMakeLists.txt
new file mode 100644
index 00000000000000..bf0d42e265d6f6
--- /dev/null
+++ b/libc/src/time/baremetal/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_entrypoint_object(
+  timespec_get
+  SRCS
+    timespec_get.cpp
+  HDRS
+    ../timespec_get.h
+  DEPENDS
+    libc.hdr.time_macros
+    libc.hdr.types.struct_timespec
+)

diff  --git a/libc/src/time/baremetal/timespec_get.cpp b/libc/src/time/baremetal/timespec_get.cpp
new file mode 100644
index 00000000000000..173fe0e06e3a91
--- /dev/null
+++ b/libc/src/time/baremetal/timespec_get.cpp
@@ -0,0 +1,27 @@
+//===-- Implementation of timespec_get for baremetal ----------------------===//
+//
+// 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/timespec_get.h"
+#include "hdr/time_macros.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+extern "C" bool __llvm_libc_timespec_get_utc(struct timespec *ts);
+
+LLVM_LIBC_FUNCTION(int, timespec_get, (struct timespec * ts, int base)) {
+  if (base != TIME_UTC)
+    return 0;
+
+  if (!__llvm_libc_timespec_get_utc(ts))
+    return 0;
+  return base;
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/time/gpu/CMakeLists.txt b/libc/src/time/gpu/CMakeLists.txt
index c9b45628158012..8da5d3a22f5a09 100644
--- a/libc/src/time/gpu/CMakeLists.txt
+++ b/libc/src/time/gpu/CMakeLists.txt
@@ -44,3 +44,15 @@ add_entrypoint_object(
     libc.hdr.types.struct_timespec
     .time_utils
 )
+
+add_entrypoint_object(
+  timespec_get
+  SRCS
+    timespec_get.cpp
+  HDRS
+    ../timespec_get.h
+  DEPENDS
+    libc.hdr.time_macros
+    libc.hdr.types.struct_timespec
+    .time_utils
+)

diff  --git a/libc/src/time/gpu/timespec_get.cpp b/libc/src/time/gpu/timespec_get.cpp
new file mode 100644
index 00000000000000..f4ef328a83122c
--- /dev/null
+++ b/libc/src/time/gpu/timespec_get.cpp
@@ -0,0 +1,29 @@
+//===-- Implementation of timespec_get for gpu ----------------------------===//
+//
+// 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/timespec_get.h"
+#include "hdr/time_macros.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, timespec_get, (struct timespec * ts, int base)) {
+  if (base != TIME_MONOTONIC || !ts)
+    return 0;
+
+  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 base;
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/time/linux/CMakeLists.txt b/libc/src/time/linux/CMakeLists.txt
index c15fb44ad5d123..31fd7d1e64c85c 100644
--- a/libc/src/time/linux/CMakeLists.txt
+++ b/libc/src/time/linux/CMakeLists.txt
@@ -11,6 +11,19 @@ add_entrypoint_object(
     libc.src.errno.errno
 )
 
+add_entrypoint_object(
+  timespec_get
+  SRCS
+    timespec_get.cpp
+  HDRS
+    ../timespec_get.h
+  DEPENDS
+    libc.hdr.time_macros
+    libc.hdr.types.struct_timespec
+    libc.src.__support.time.linux.clock_gettime
+    libc.src.errno.errno
+)
+
 add_entrypoint_object(
   clock
   SRCS

diff  --git a/libc/src/time/linux/timespec_get.cpp b/libc/src/time/linux/timespec_get.cpp
new file mode 100644
index 00000000000000..ba9f8eb2e4426b
--- /dev/null
+++ b/libc/src/time/linux/timespec_get.cpp
@@ -0,0 +1,45 @@
+//===-- Implementation of timespec_get for Linux --------------------------===//
+//
+// 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/timespec_get.h"
+#include "hdr/time_macros.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/time/linux/clock_gettime.h"
+#include "src/errno/libc_errno.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, timespec_get, (struct timespec * ts, int base)) {
+  clockid_t clockid;
+  switch (base) {
+  case TIME_UTC:
+    clockid = CLOCK_REALTIME;
+    break;
+  case TIME_MONOTONIC:
+    clockid = CLOCK_MONOTONIC;
+    break;
+  case TIME_ACTIVE:
+    clockid = CLOCK_PROCESS_CPUTIME_ID;
+    break;
+  case TIME_THREAD_ACTIVE:
+    clockid = CLOCK_THREAD_CPUTIME_ID;
+    break;
+  default:
+    return 0;
+  }
+
+  auto result = internal::clock_gettime(clockid, ts);
+  if (!result.has_value()) {
+    libc_errno = result.error();
+    return 0;
+  }
+  return base;
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/time/timespec_get.h b/libc/src/time/timespec_get.h
new file mode 100644
index 00000000000000..2a176ff09ce4dd
--- /dev/null
+++ b/libc/src/time/timespec_get.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of timespec_get -------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_TIME_TIMESPEC_GET_H
+#define LLVM_LIBC_SRC_TIME_TIMESPEC_GET_H
+
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int timespec_get(struct timespec *ts, int base);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_TIME_TIMESPEC_GET_H

diff  --git a/libc/test/src/time/CMakeLists.txt b/libc/test/src/time/CMakeLists.txt
index bba01f063fed27..7151526b72b26d 100644
--- a/libc/test/src/time/CMakeLists.txt
+++ b/libc/test/src/time/CMakeLists.txt
@@ -162,6 +162,16 @@ add_libc_unittest(
     libc.src.errno.errno
 )
 
+add_libc_test(
+  timespec_get_test
+  SUITE
+    libc_time_unittests
+  SRCS
+    timespec_get_test.cpp
+  DEPENDS
+    libc.src.time.timespec_get
+)
+
 add_libc_test(
   clock_test
   SUITE

diff  --git a/libc/test/src/time/timespec_get_test.cpp b/libc/test/src/time/timespec_get_test.cpp
new file mode 100644
index 00000000000000..327bfefe934c15
--- /dev/null
+++ b/libc/test/src/time/timespec_get_test.cpp
@@ -0,0 +1,46 @@
+//===-- Unittests for timespec_get ----------------------------------------===//
+//
+// 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 "hdr/time_macros.h"
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/macros/properties/architectures.h"
+#include "src/time/timespec_get.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcTimespecGet, Utc) {
+  timespec ts;
+  int result;
+  result = LIBC_NAMESPACE::timespec_get(&ts, TIME_UTC);
+#ifdef LIBC_TARGET_ARCH_IS_GPU
+  ASSERT_EQ(result, 0);
+#else
+  ASSERT_EQ(result, TIME_UTC);
+  ASSERT_GT(ts.tv_sec, time_t(0));
+#endif
+}
+
+TEST(LlvmLibcTimespecGet, Monotonic) {
+  timespec ts1, ts2;
+  int result;
+  result = LIBC_NAMESPACE::timespec_get(&ts1, TIME_MONOTONIC);
+  ASSERT_EQ(result, TIME_MONOTONIC);
+  ASSERT_GT(ts1.tv_sec, time_t(0));
+  result = LIBC_NAMESPACE::timespec_get(&ts2, TIME_MONOTONIC);
+  ASSERT_EQ(result, TIME_MONOTONIC);
+  ASSERT_GE(ts2.tv_sec, ts1.tv_sec); // The monotonic time should increase.
+  if (ts2.tv_sec == ts1.tv_sec) {
+    ASSERT_GE(ts2.tv_nsec, ts1.tv_nsec);
+  }
+}
+
+TEST(LlvmLibcTimespecGet, Unknown) {
+  timespec ts;
+  int result;
+  result = LIBC_NAMESPACE::timespec_get(&ts, 0);
+  ASSERT_EQ(result, 0);
+}


        


More information about the libc-commits mailing list