|
13 | 13 | #include <ctime>
|
14 | 14 |
|
15 | 15 | // CPU_TIME (Fortran 2018 16.9.57)
|
| 16 | +// SYSTEM_CLOCK (Fortran 2018 16.9.168) |
| 17 | +// |
16 | 18 | // We can use std::clock() from the <ctime> header as a fallback implementation
|
17 | 19 | // that should be available everywhere. This may not provide the best resolution
|
18 | 20 | // and is particularly troublesome on (some?) POSIX systems where CLOCKS_PER_SEC
|
@@ -68,11 +70,64 @@ double GetCpuTime(preferred_implementation,
|
68 | 70 | // Return some negative value to represent failure.
|
69 | 71 | return -1.0;
|
70 | 72 | }
|
| 73 | + |
| 74 | +using count_t = |
| 75 | + Fortran::runtime::CppTypeFor<Fortran::common::TypeCategory::Integer, 8>; |
| 76 | + |
| 77 | +// This is the fallback implementation, which should work everywhere. Note that |
| 78 | +// in general we can't recover after std::clock has reached its maximum value. |
| 79 | +template <typename Unused = void> |
| 80 | +count_t GetSystemClockCount(fallback_implementation) { |
| 81 | + std::clock_t timestamp{std::clock()}; |
| 82 | + if (timestamp == static_cast<std::clock_t>(-1)) { |
| 83 | + // Return -HUGE() to represent failure. |
| 84 | + return -std::numeric_limits<count_t>::max(); |
| 85 | + } |
| 86 | + |
| 87 | + // If our return type is large enough to hold any value returned by |
| 88 | + // std::clock, our work is done. Otherwise, we have to wrap around. |
| 89 | + static constexpr auto max{std::numeric_limits<count_t>::max()}; |
| 90 | + if constexpr (std::numeric_limits<std::clock_t>::max() <= max) { |
| 91 | + return static_cast<count_t>(timestamp); |
| 92 | + } else { |
| 93 | + // Since std::clock_t could be a floating point type, we can't just use the |
| 94 | + // % operator, so we have to wrap around manually. |
| 95 | + return static_cast<count_t>(timestamp - max * std::floor(timestamp / max)); |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +template <typename Unused = void> |
| 100 | +count_t GetSystemClockCountRate(fallback_implementation) { |
| 101 | + return CLOCKS_PER_SEC; |
| 102 | +} |
| 103 | + |
| 104 | +template <typename Unused = void> |
| 105 | +count_t GetSystemClockCountMax(fallback_implementation) { |
| 106 | + static constexpr auto max_clock_t = std::numeric_limits<std::clock_t>::max(); |
| 107 | + static constexpr auto max_count_t = std::numeric_limits<count_t>::max(); |
| 108 | + if constexpr (max_clock_t < max_count_t) { |
| 109 | + return static_cast<count_t>(max_clock_t); |
| 110 | + } else { |
| 111 | + return max_count_t; |
| 112 | + } |
| 113 | +} |
71 | 114 | } // anonymous namespace
|
72 | 115 |
|
73 | 116 | namespace Fortran::runtime {
|
74 | 117 | extern "C" {
|
75 | 118 |
|
76 | 119 | double RTNAME(CpuTime)() { return GetCpuTime(0); }
|
| 120 | + |
| 121 | +CppTypeFor<TypeCategory::Integer, 8> RTNAME(SystemClockCount)() { |
| 122 | + return GetSystemClockCount(0); |
| 123 | +} |
| 124 | + |
| 125 | +CppTypeFor<TypeCategory::Integer, 8> RTNAME(SystemClockCountRate)() { |
| 126 | + return GetSystemClockCountRate(0); |
| 127 | +} |
| 128 | + |
| 129 | +CppTypeFor<TypeCategory::Integer, 8> RTNAME(SystemClockCountMax)() { |
| 130 | + return GetSystemClockCountMax(0); |
| 131 | +} |
77 | 132 | } // extern "C"
|
78 | 133 | } // namespace Fortran::runtime
|
0 commit comments