@@ -60,6 +60,18 @@ template <typename Unused = void> double GetCpuTime(fallback_implementation) {
60
60
return -1.0 ;
61
61
}
62
62
63
+ // struct timespec and timespec_get are not implemented in macOS 10.14. Using
64
+ // it here limits which version of MacOS we are compatible with. Unfortunately
65
+ // when building on newer MacOS for older MacOS it uses the new headers (with
66
+ // a definition of struct timespec) but just errors on API calls so we can't use
67
+ // overloading magic to trigger different implementations depending if struct
68
+ // timespec is defined.
69
+ #if defined __APPLE__
70
+ #define NO_TIMESPEC
71
+ #else
72
+ #undef NO_TIMESPEC
73
+ #endif
74
+
63
75
#if defined __MINGW32__
64
76
// clock_gettime is implemented in the pthread library for MinGW.
65
77
// Using it here would mean that all programs that link libflang_rt are
@@ -87,6 +99,7 @@ template <typename Unused = void> double GetCpuTime(fallback_implementation) {
87
99
#endif
88
100
89
101
#ifdef CLOCKID_CPU_TIME
102
+ #ifndef NO_TIMESPEC
90
103
// POSIX implementation using clock_gettime. This is only enabled where
91
104
// clock_gettime is available.
92
105
template <typename T = int , typename U = struct timespec >
@@ -101,6 +114,7 @@ double GetCpuTime(preferred_implementation,
101
114
// Return some negative value to represent failure.
102
115
return -1.0 ;
103
116
}
117
+ #endif // !NO_TIMESPEC
104
118
#endif // CLOCKID_CPU_TIME
105
119
106
120
using count_t = std::int64_t ;
@@ -113,6 +127,7 @@ using unsigned_count_t = std::uint64_t;
113
127
// - nanoseconds for kinds 8, 16
114
128
constexpr unsigned_count_t DS_PER_SEC{10u };
115
129
constexpr unsigned_count_t MS_PER_SEC{1'000u };
130
+ [[maybe_unused]] constexpr unsigned_count_t US_PER_SEC{1'000'000u };
116
131
constexpr unsigned_count_t NS_PER_SEC{1'000'000'000u };
117
132
118
133
// Computes HUGE(INT(0,kind)) as an unsigned integer value.
@@ -123,13 +138,9 @@ static constexpr inline unsigned_count_t GetHUGE(int kind) {
123
138
return (unsigned_count_t {1 } << ((8 * kind) - 1 )) - 1 ;
124
139
}
125
140
126
- // Function converts a std::timespec_t into the desired count to
127
- // be returned by the timing functions in accordance with the requested
128
- // kind at the call site.
129
- count_t ConvertTimeSpecToCount (int kind, const struct timespec &tspec) {
141
+ count_t ConvertSecondsNanosecondsToCount (
142
+ int kind, unsigned_count_t sec, unsigned_count_t nsec) {
130
143
const unsigned_count_t huge{GetHUGE (kind)};
131
- unsigned_count_t sec{static_cast <unsigned_count_t >(tspec.tv_sec )};
132
- unsigned_count_t nsec{static_cast <unsigned_count_t >(tspec.tv_nsec )};
133
144
if (kind >= 8 ) {
134
145
return (sec * NS_PER_SEC + nsec) % (huge + 1 );
135
146
} else if (kind >= 2 ) {
@@ -139,8 +150,45 @@ count_t ConvertTimeSpecToCount(int kind, const struct timespec &tspec) {
139
150
}
140
151
}
141
152
153
+ // Less accurate implementation only accurate to the nearest microsecond
154
+ // (instead of nanosecond) for systems where `struct timespec` is not available.
155
+ #if defined(NO_TIMESPEC) && !defined(_WIN32)
156
+ // Function converts a struct timeval into the desired count to
157
+ // be returned by the timing functions in accordance with the requested
158
+ // kind at the call site.
159
+ count_t ConvertTimevalToCount (int kind, const struct timeval &tval) {
160
+ unsigned_count_t sec{static_cast <unsigned_count_t >(tval.tv_sec )};
161
+ unsigned_count_t nsec{static_cast <unsigned_count_t >(tval.tv_usec ) * 1000 };
162
+ return ConvertSecondsNanosecondsToCount (kind, sec, nsec);
163
+ }
164
+
165
+ template <typename Unused = void >
166
+ count_t GetSystemClockCount (int kind, fallback_implementation) {
167
+ struct timeval tval;
168
+
169
+ if (gettimeofday (&tval, /* timezone=*/ nullptr ) != 0 ) {
170
+ // Return -HUGE(COUNT) to represent failure.
171
+ return -static_cast <count_t >(GetHUGE (kind));
172
+ }
173
+
174
+ // Compute the timestamp as seconds plus nanoseconds in accordance
175
+ // with the requested kind at the call site.
176
+ return ConvertTimevalToCount (kind, tval);
177
+ }
178
+
179
+ #else
180
+
181
+ // Function converts a std::timespec_t into the desired count to
182
+ // be returned by the timing functions in accordance with the requested
183
+ // kind at the call site.
184
+ count_t ConvertTimeSpecToCount (int kind, const struct timespec &tspec) {
185
+ unsigned_count_t sec{static_cast <unsigned_count_t >(tspec.tv_sec )};
186
+ unsigned_count_t nsec{static_cast <unsigned_count_t >(tspec.tv_nsec )};
187
+ return ConvertSecondsNanosecondsToCount (kind, sec, nsec);
188
+ }
189
+
142
190
#ifndef _AIX
143
- // This is the fallback implementation, which should work everywhere.
191
+ // More accurate version with nanosecond accuracy
144
192
template <typename Unused = void >
145
193
count_t GetSystemClockCount (int kind, fallback_implementation) {
146
194
struct timespec tspec;
@@ -154,11 +202,16 @@ count_t GetSystemClockCount(int kind, fallback_implementation) {
154
202
// with the requested kind at the call site.
155
203
return ConvertTimeSpecToCount (kind, tspec);
156
204
}
157
- #endif
205
+ #endif // !_AIX
206
+ #endif // !NO_TIMESPEC
158
207
159
208
template <typename Unused = void >
160
209
count_t GetSystemClockCountRate (int kind, fallback_implementation) {
210
+ #ifdef NO_TIMESPEC
211
+ return kind >= 8 ? US_PER_SEC : kind >= 2 ? MS_PER_SEC : DS_PER_SEC;
212
+ #else
161
213
return kind >= 8 ? NS_PER_SEC : kind >= 2 ? MS_PER_SEC : DS_PER_SEC;
214
+ #endif
162
215
}
163
216
164
217
template <typename Unused = void >
@@ -167,6 +220,7 @@ count_t GetSystemClockCountMax(int kind, fallback_implementation) {
167
220
return maxCount;
168
221
}
169
222
223
+ #ifndef NO_TIMESPEC
170
224
#ifdef CLOCKID_ELAPSED_TIME
171
225
template <typename T = int , typename U = struct timespec >
172
226
count_t GetSystemClockCount (int kind, preferred_implementation,
@@ -200,6 +254,7 @@ count_t GetSystemClockCountMax(int kind, preferred_implementation,
200
254
decltype (clock_gettime(ClockId, Timespec)) *Enabled = nullptr) {
201
255
return GetHUGE (kind);
202
256
}
257
+ #endif // !NO_TIMESPEC
203
258
204
259
// DATE_AND_TIME (Fortran 2018 16.9.59)
205
260
0 commit comments