[flang-commits] [flang] 0104cc8 - [flang] Add default implementation for SYSTEM_CLOCK
Diana Picus via flang-commits
flang-commits at lists.llvm.org
Wed Aug 18 00:48:09 PDT 2021
Author: Diana Picus
Date: 2021-08-18T07:39:13Z
New Revision: 0104cc85b14aad7980360f58a1159463f8da5adb
URL: https://github.com/llvm/llvm-project/commit/0104cc85b14aad7980360f58a1159463f8da5adb
DIFF: https://github.com/llvm/llvm-project/commit/0104cc85b14aad7980360f58a1159463f8da5adb.diff
LOG: [flang] Add default implementation for SYSTEM_CLOCK
Add an implementation for the runtime functions related to SYSTEM_CLOCK.
As with CPU_TIME, this is based on std::clock(), which should be
available everywhere, but it is highly recommended to add
platform-specific implementations for systems where std::clock() behaves
poorly (e.g. POSIX).
The documentation for std::clock() doesn't specify a maximum value and
in fact wrap around behaviour is non-conforming. Therefore, this
implementation of SYSTEM_CLOCK is not guaranteed to wrap around either,
and after std::clock reaches its maximum value we will likely just
return failure rather than wrap around. If this happens often on your
system, please add a new platform-specific implementation.
We define COUNT_MAX as either the maximum value that can be stored in
a std::clock_t or in a 64-bit integer (whichever is smaller), and
COUNT_RATE as CLOCKS_PER_SEC. For POSIX systems, the value of
CLOCKS_PER_SEC is hardcoded to 10^6 and irrelevant for the values
returned by std::clock.
Differential Revision: https://reviews.llvm.org/D105969
Added:
Modified:
flang/runtime/time-intrinsic.cpp
flang/unittests/Runtime/Time.cpp
Removed:
################################################################################
diff --git a/flang/runtime/time-intrinsic.cpp b/flang/runtime/time-intrinsic.cpp
index d6b1c36bf9e0..3a377006667c 100644
--- a/flang/runtime/time-intrinsic.cpp
+++ b/flang/runtime/time-intrinsic.cpp
@@ -13,6 +13,8 @@
#include <ctime>
// CPU_TIME (Fortran 2018 16.9.57)
+// SYSTEM_CLOCK (Fortran 2018 16.9.168)
+//
// We can use std::clock() from the <ctime> header as a fallback implementation
// that should be available everywhere. This may not provide the best resolution
// and is particularly troublesome on (some?) POSIX systems where CLOCKS_PER_SEC
@@ -68,11 +70,64 @@ double GetCpuTime(preferred_implementation,
// Return some negative value to represent failure.
return -1.0;
}
+
+using count_t =
+ Fortran::runtime::CppTypeFor<Fortran::common::TypeCategory::Integer, 8>;
+
+// This is the fallback implementation, which should work everywhere. Note that
+// in general we can't recover after std::clock has reached its maximum value.
+template <typename Unused = void>
+count_t GetSystemClockCount(fallback_implementation) {
+ std::clock_t timestamp{std::clock()};
+ if (timestamp == static_cast<std::clock_t>(-1)) {
+ // Return -HUGE() to represent failure.
+ return -std::numeric_limits<count_t>::max();
+ }
+
+ // If our return type is large enough to hold any value returned by
+ // std::clock, our work is done. Otherwise, we have to wrap around.
+ static constexpr auto max{std::numeric_limits<count_t>::max()};
+ if constexpr (std::numeric_limits<std::clock_t>::max() <= max) {
+ return static_cast<count_t>(timestamp);
+ } else {
+ // Since std::clock_t could be a floating point type, we can't just use the
+ // % operator, so we have to wrap around manually.
+ return static_cast<count_t>(timestamp - max * std::floor(timestamp / max));
+ }
+}
+
+template <typename Unused = void>
+count_t GetSystemClockCountRate(fallback_implementation) {
+ return CLOCKS_PER_SEC;
+}
+
+template <typename Unused = void>
+count_t GetSystemClockCountMax(fallback_implementation) {
+ static constexpr auto max_clock_t = std::numeric_limits<std::clock_t>::max();
+ static constexpr auto max_count_t = std::numeric_limits<count_t>::max();
+ if constexpr (max_clock_t < max_count_t) {
+ return static_cast<count_t>(max_clock_t);
+ } else {
+ return max_count_t;
+ }
+}
} // anonymous namespace
namespace Fortran::runtime {
extern "C" {
double RTNAME(CpuTime)() { return GetCpuTime(0); }
+
+CppTypeFor<TypeCategory::Integer, 8> RTNAME(SystemClockCount)() {
+ return GetSystemClockCount(0);
+}
+
+CppTypeFor<TypeCategory::Integer, 8> RTNAME(SystemClockCountRate)() {
+ return GetSystemClockCountRate(0);
+}
+
+CppTypeFor<TypeCategory::Integer, 8> RTNAME(SystemClockCountMax)() {
+ return GetSystemClockCountMax(0);
+}
} // extern "C"
} // namespace Fortran::runtime
diff --git a/flang/unittests/Runtime/Time.cpp b/flang/unittests/Runtime/Time.cpp
index b2ca81f98c4e..3439a7caa05c 100644
--- a/flang/unittests/Runtime/Time.cpp
+++ b/flang/unittests/Runtime/Time.cpp
@@ -26,3 +26,33 @@ TEST(TimeIntrinsics, CpuTime) {
ASSERT_GE(end, start);
}
}
+
+using count_t = CppTypeFor<TypeCategory::Integer, 8>;
+
+TEST(TimeIntrinsics, SystemClock) {
+ // We can't really test that we get the "right" result for SYSTEM_CLOCK, but
+ // we can have a smoke test to see that we get something reasonable on the
+ // platforms where we expect to support it.
+
+ // The value of the count rate and max will vary by platform, but they should
+ // always be strictly positive if we have a working implementation of
+ // SYSTEM_CLOCK.
+ EXPECT_GT(RTNAME(SystemClockCountRate)(), 0);
+
+ count_t max{RTNAME(SystemClockCountMax)()};
+ EXPECT_GT(max, 0);
+
+ count_t start{RTNAME(SystemClockCount)()};
+ EXPECT_GE(start, 0);
+ EXPECT_LE(start, max);
+
+ // Loop until we get a
diff erent value from SystemClockCount. If we don't get
+ // one before we time out, then we should probably look into an implementation
+ // for SystemClokcCount with a better timer resolution on this platform.
+ for (count_t end = start; end == start; end = RTNAME(SystemClockCount)()) {
+ EXPECT_GE(end, 0);
+ EXPECT_LE(end, max);
+
+ EXPECT_GE(end, start);
+ }
+}
More information about the flang-commits
mailing list