[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