[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.
This commit is contained in:
parent
0c98776159
commit
b8daa45a56
@ -209,6 +209,7 @@ set(TARGET_LIBC_ENTRYPOINTS
|
|||||||
libc.src.time.gmtime
|
libc.src.time.gmtime
|
||||||
libc.src.time.gmtime_r
|
libc.src.time.gmtime_r
|
||||||
libc.src.time.mktime
|
libc.src.time.mktime
|
||||||
|
libc.src.time.timespec_get
|
||||||
|
|
||||||
# internal entrypoints
|
# internal entrypoints
|
||||||
libc.startup.baremetal.init
|
libc.startup.baremetal.init
|
||||||
|
@ -205,6 +205,7 @@ set(TARGET_LIBC_ENTRYPOINTS
|
|||||||
libc.src.time.gmtime
|
libc.src.time.gmtime
|
||||||
libc.src.time.gmtime_r
|
libc.src.time.gmtime_r
|
||||||
libc.src.time.mktime
|
libc.src.time.mktime
|
||||||
|
libc.src.time.timespec_get
|
||||||
|
|
||||||
# internal entrypoints
|
# internal entrypoints
|
||||||
libc.startup.baremetal.init
|
libc.startup.baremetal.init
|
||||||
|
@ -1000,6 +1000,7 @@ if(LLVM_LIBC_FULL_BUILD)
|
|||||||
libc.src.time.mktime
|
libc.src.time.mktime
|
||||||
libc.src.time.nanosleep
|
libc.src.time.nanosleep
|
||||||
libc.src.time.time
|
libc.src.time.time
|
||||||
|
libc.src.time.timespec_get
|
||||||
|
|
||||||
# unistd.h entrypoints
|
# unistd.h entrypoints
|
||||||
libc.src.unistd.__llvm_libc_syscall
|
libc.src.unistd.__llvm_libc_syscall
|
||||||
|
@ -939,6 +939,7 @@ if(LLVM_LIBC_FULL_BUILD)
|
|||||||
libc.src.time.mktime
|
libc.src.time.mktime
|
||||||
libc.src.time.nanosleep
|
libc.src.time.nanosleep
|
||||||
libc.src.time.time
|
libc.src.time.time
|
||||||
|
libc.src.time.timespec_get
|
||||||
|
|
||||||
# unistd.h entrypoints
|
# unistd.h entrypoints
|
||||||
libc.src.unistd.__llvm_libc_syscall
|
libc.src.unistd.__llvm_libc_syscall
|
||||||
|
@ -1083,6 +1083,7 @@ if(LLVM_LIBC_FULL_BUILD)
|
|||||||
libc.src.time.mktime
|
libc.src.time.mktime
|
||||||
libc.src.time.nanosleep
|
libc.src.time.nanosleep
|
||||||
libc.src.time.time
|
libc.src.time.time
|
||||||
|
libc.src.time.timespec_get
|
||||||
|
|
||||||
# locale.h entrypoints
|
# locale.h entrypoints
|
||||||
libc.src.locale.localeconv
|
libc.src.locale.localeconv
|
||||||
|
@ -7,4 +7,9 @@
|
|||||||
#include "linux/time-macros.h"
|
#include "linux/time-macros.h"
|
||||||
#endif
|
#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
|
#endif // LLVM_LIBC_MACROS_TIME_MACROS_H
|
||||||
|
@ -96,3 +96,10 @@ functions:
|
|||||||
return_type: time_t
|
return_type: time_t
|
||||||
arguments:
|
arguments:
|
||||||
- type: time_t *
|
- type: time_t *
|
||||||
|
- name: timespec_get
|
||||||
|
standard:
|
||||||
|
- stdc
|
||||||
|
return_type: int
|
||||||
|
arguments:
|
||||||
|
- type: struct timespec *
|
||||||
|
- type: int
|
||||||
|
@ -1676,6 +1676,14 @@ def StdC : StandardSpec<"stdc"> {
|
|||||||
RetValSpec<TimeTType>,
|
RetValSpec<TimeTType>,
|
||||||
[ArgSpec<TimeTTypePtr>]
|
[ArgSpec<TimeTTypePtr>]
|
||||||
>,
|
>,
|
||||||
|
FunctionSpec<
|
||||||
|
"timespec_get",
|
||||||
|
RetValSpec<IntType>,
|
||||||
|
[
|
||||||
|
ArgSpec<StructTimeSpecPtr>,
|
||||||
|
ArgSpec<IntType>,
|
||||||
|
]
|
||||||
|
>,
|
||||||
]
|
]
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
@ -111,6 +111,13 @@ add_entrypoint_object(
|
|||||||
.${LIBC_TARGET_OS}.time
|
.${LIBC_TARGET_OS}.time
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_entrypoint_object(
|
||||||
|
timespec_get
|
||||||
|
ALIAS
|
||||||
|
DEPENDS
|
||||||
|
.${LIBC_TARGET_OS}.timespec_get
|
||||||
|
)
|
||||||
|
|
||||||
add_entrypoint_object(
|
add_entrypoint_object(
|
||||||
clock
|
clock
|
||||||
ALIAS
|
ALIAS
|
||||||
|
10
libc/src/time/baremetal/CMakeLists.txt
Normal file
10
libc/src/time/baremetal/CMakeLists.txt
Normal file
@ -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
|
||||||
|
)
|
27
libc/src/time/baremetal/timespec_get.cpp
Normal file
27
libc/src/time/baremetal/timespec_get.cpp
Normal file
@ -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
|
@ -44,3 +44,15 @@ add_entrypoint_object(
|
|||||||
libc.hdr.types.struct_timespec
|
libc.hdr.types.struct_timespec
|
||||||
.time_utils
|
.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
|
||||||
|
)
|
||||||
|
29
libc/src/time/gpu/timespec_get.cpp
Normal file
29
libc/src/time/gpu/timespec_get.cpp
Normal file
@ -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
|
@ -11,6 +11,19 @@ add_entrypoint_object(
|
|||||||
libc.src.errno.errno
|
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(
|
add_entrypoint_object(
|
||||||
clock
|
clock
|
||||||
SRCS
|
SRCS
|
||||||
|
45
libc/src/time/linux/timespec_get.cpp
Normal file
45
libc/src/time/linux/timespec_get.cpp
Normal file
@ -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
|
21
libc/src/time/timespec_get.h
Normal file
21
libc/src/time/timespec_get.h
Normal file
@ -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
|
@ -162,6 +162,16 @@ add_libc_unittest(
|
|||||||
libc.src.errno.errno
|
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(
|
add_libc_test(
|
||||||
clock_test
|
clock_test
|
||||||
SUITE
|
SUITE
|
||||||
|
46
libc/test/src/time/timespec_get_test.cpp
Normal file
46
libc/test/src/time/timespec_get_test.cpp
Normal file
@ -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);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user