[flang-commits] [PATCH] D104020: [flang] Add POSIX implementation for CPU_TIME

Diana Picus via Phabricator via flang-commits flang-commits at lists.llvm.org
Thu Jun 10 03:55:50 PDT 2021


rovka created this revision.
rovka added reviewers: klausler, jeanPerier.
rovka added a project: Flang.
Herald added subscribers: jdoerfert, kristof.beyls.
rovka requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Add an implementation for CPU_TIME using the POSIX function
clock_gettime. I think on most POSIX systems this will be included for
free via <ctime>, which corresponds to "time.h" (YMMV, we can fix the
code if the need arises).

Detecting that clock_gettime is available is tricky. For instance, commit
827407a86aa07 <https://reviews.llvm.org/rG827407a86aa07f35ca31239c4f28cc2486170204> used the following incantation in f18-parse-demo.cpp:

      

#if _POSIX_C_SOURCE >= 199309L && _POSIX_TIMERS > 0 && _POSIX_CPUTIME && \

  defined CLOCK_PROCESS_CPUTIME_ID

This doesn't work on my AArch64 Ubuntu system, which provides
clock_gettime but doesn't define _POSIX_TIMERS. Since finding the right
combination of macros requires infinite time, patience and access to
sundry POSIX systems, we should probably try a different approach.

This patch attempts to use SFINAE instead of the preprocessor to choose
an implementation for CPU_TIME. We define a helper function template
which lets us check if clock_gettime is available (and has the
interface we expect). I hope the comments explain it well enough.

This approach has the advantage that it keeps the detection of
clock_gettime close to the code that uses it. An alternative would be to
use CMake to check for the symbol (not sure which approach is likely to
run into more quirks).

Looking forward to feedback!


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D104020

Files:
  flang/runtime/time-intrinsic.cpp


Index: flang/runtime/time-intrinsic.cpp
===================================================================
--- flang/runtime/time-intrinsic.cpp
+++ flang/runtime/time-intrinsic.cpp
@@ -12,14 +12,29 @@
 
 #include <ctime>
 
-namespace Fortran::runtime {
-extern "C" {
-
 // CPU_TIME (Fortran 2018 16.9.57)
-double RTNAME(CpuTime)() {
-  // This is part of the c++ standard, so it should at least exist everywhere.
-  // It probably does not have the best resolution, so we prefer other
-  // platform-specific alternatives if they exist.
+// 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
+// is defined as 10^6 regardless of the actual precision of std::clock().
+// Therefore, we will usually prefer platform-specific alternatives when they
+// are available.
+//
+// We can use SFINAE to choose a platform-specific alternative. To do so, we
+// introduce a helper function template, whose overload set will contain only
+// implementations relying on interfaces which are actually available. Each
+// overload will have a dummy parameter whose type indicates whether or not it
+// should be preferred. Any other parameters required for SFINAE should have
+// default values provided.
+namespace {
+// Types for the dummy parameter indicating the priority of a given overload.
+// We will invoke our helper with an integer literal argument, so the overload
+// with the highest priority should have the type int.
+using fallback_implementation = double;
+using preferred_implementation = int;
+
+// This is the fallback implementation, which should work everywhere.
+template <typename Unused = void> double getCpuTime(fallback_implementation) {
   std::clock_t timestamp{std::clock()};
   if (timestamp != std::clock_t{-1})
     return static_cast<double>(timestamp) / CLOCKS_PER_SEC;
@@ -27,5 +42,35 @@
   // Return some negative value to represent failure.
   return -1.0;
 }
+
+// POSIX implementation using clock_gettime. This is only enabled if
+// clock_gettime is available.
+template <typename T = int, typename U = struct timespec>
+double getCpuTime(preferred_implementation,
+    // We need some dummy parameters to pass to decltype(clock_gettime).
+    T ClockId = 0, U *Timespec = nullptr,
+    decltype(clock_gettime(ClockId, Timespec)) *Enabled = nullptr) {
+#if defined CLOCK_THREAD_CPUTIME_ID
+#define CLOCKID CLOCK_THREAD_CPUTIME_ID
+#elif defined CLOCK_PROCESS_CPUTIME_ID
+#define CLOCKID CLOCK_PROCESS_CPUTIME_ID
+#elif defined CLOCK_MONOTONIC
+#define CLOCKID CLOCK_MONOTONIC
+#else
+#define CLOCKID CLOCK_REALTIME
+#endif
+  struct timespec tspec;
+  if (clock_gettime(CLOCKID, &tspec) == 0)
+    return tspec.tv_nsec * 1.0e-9 + tspec.tv_sec;
+
+  // Return some negative value to represent failure.
+  return -1.0;
+}
+} // anonymous namespace
+
+namespace Fortran::runtime {
+extern "C" {
+
+double RTNAME(CpuTime)() { return getCpuTime(0); }
 } // extern "C"
 } // namespace Fortran::runtime


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D104020.351119.patch
Type: text/x-patch
Size: 3114 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/flang-commits/attachments/20210610/0694a382/attachment-0001.bin>


More information about the flang-commits mailing list