@@ -60,6 +60,18 @@ template <typename Unused = void> double GetCpuTime(fallback_implementation) {
6060 return -1.0 ;
6161}
6262
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+
6375#if defined __MINGW32__
6476// clock_gettime is implemented in the pthread library for MinGW.
6577// 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) {
8799#endif
88100
89101#ifdef CLOCKID_CPU_TIME
102+ #ifndef NO_TIMESPEC
90103// POSIX implementation using clock_gettime. This is only enabled where
91104// clock_gettime is available.
92105template <typename T = int , typename U = struct timespec >
@@ -101,6 +114,7 @@ double GetCpuTime(preferred_implementation,
101114 // Return some negative value to represent failure.
102115 return -1.0 ;
103116}
117+ #endif // !NO_TIMESPEC
104118#endif // CLOCKID_CPU_TIME
105119
106120using count_t = std::int64_t ;
@@ -113,6 +127,7 @@ using unsigned_count_t = std::uint64_t;
113127// - nanoseconds for kinds 8, 16
114128constexpr unsigned_count_t DS_PER_SEC{10u };
115129constexpr unsigned_count_t MS_PER_SEC{1'000u };
130+ [[maybe_unused]] constexpr unsigned_count_t US_PER_SEC{1'000'000u };
116131constexpr unsigned_count_t NS_PER_SEC{1'000'000'000u };
117132
118133// Computes HUGE(INT(0,kind)) as an unsigned integer value.
@@ -123,13 +138,9 @@ static constexpr inline unsigned_count_t GetHUGE(int kind) {
123138 return (unsigned_count_t {1 } << ((8 * kind) - 1 )) - 1 ;
124139}
125140
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) {
130143 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 )};
133144 if (kind >= 8 ) {
134145 return (sec * NS_PER_SEC + nsec) % (huge + 1 );
135146 } else if (kind >= 2 ) {
@@ -139,8 +150,45 @@ count_t ConvertTimeSpecToCount(int kind, const struct timespec &tspec) {
139150 }
140151}
141152
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+
142190#ifndef _AIX
143- // This is the fallback implementation, which should work everywhere.
191+ // More accurate version with nanosecond accuracy
144192template <typename Unused = void >
145193count_t GetSystemClockCount (int kind, fallback_implementation) {
146194 struct timespec tspec;
@@ -154,11 +202,16 @@ count_t GetSystemClockCount(int kind, fallback_implementation) {
154202 // with the requested kind at the call site.
155203 return ConvertTimeSpecToCount (kind, tspec);
156204}
157- #endif
205+ #endif // !_AIX
206+ #endif // !NO_TIMESPEC
158207
159208template <typename Unused = void >
160209count_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
161213 return kind >= 8 ? NS_PER_SEC : kind >= 2 ? MS_PER_SEC : DS_PER_SEC;
214+ #endif
162215}
163216
164217template <typename Unused = void >
@@ -167,6 +220,7 @@ count_t GetSystemClockCountMax(int kind, fallback_implementation) {
167220 return maxCount;
168221}
169222
223+ #ifndef NO_TIMESPEC
170224#ifdef CLOCKID_ELAPSED_TIME
171225template <typename T = int , typename U = struct timespec >
172226count_t GetSystemClockCount (int kind, preferred_implementation,
@@ -200,6 +254,7 @@ count_t GetSystemClockCountMax(int kind, preferred_implementation,
200254 decltype (clock_gettime(ClockId, Timespec)) *Enabled = nullptr) {
201255 return GetHUGE (kind);
202256}
257+ #endif // !NO_TIMESPEC
203258
204259// DATE_AND_TIME (Fortran 2018 16.9.59)
205260
0 commit comments