@@ -64,29 +64,20 @@ template <typename Unused = void> double GetCpuTime(fallback_implementation) {
64
64
// clock_gettime is implemented in the pthread library for MinGW.
65
65
// Using it here would mean that all programs that link libFortranRuntime are
66
66
// required to also link to pthread. Instead, don't use the function.
67
- #undef CLOCKID_CPU_TIME
68
- #undef CLOCKID_ELAPSED_TIME
69
- #else
70
- // Determine what clock to use for CPU time.
71
- #if defined CLOCK_PROCESS_CPUTIME_ID
72
- #define CLOCKID_CPU_TIME CLOCK_PROCESS_CPUTIME_ID
67
+ #undef CLOCKID
68
+ #elif defined CLOCK_PROCESS_CPUTIME_ID
69
+ #define CLOCKID CLOCK_PROCESS_CPUTIME_ID
73
70
#elif defined CLOCK_THREAD_CPUTIME_ID
74
- #define CLOCKID_CPU_TIME CLOCK_THREAD_CPUTIME_ID
75
- #else
76
- #undef CLOCKID_CPU_TIME
77
- #endif
78
-
79
- // Determine what clock to use for elapsed time.
80
- #if defined CLOCK_MONOTONIC
81
- #define CLOCKID_ELAPSED_TIME CLOCK_MONOTONIC
71
+ #define CLOCKID CLOCK_THREAD_CPUTIME_ID
72
+ #elif defined CLOCK_MONOTONIC
73
+ #define CLOCKID CLOCK_MONOTONIC
82
74
#elif defined CLOCK_REALTIME
83
- #define CLOCKID_ELAPSED_TIME CLOCK_REALTIME
75
+ #define CLOCKID CLOCK_REALTIME
84
76
#else
85
- #undef CLOCKID_ELAPSED_TIME
86
- #endif
77
+ #undef CLOCKID
87
78
#endif
88
79
89
- #ifdef CLOCKID_CPU_TIME
80
+ #ifdef CLOCKID
90
81
// POSIX implementation using clock_gettime. This is only enabled where
91
82
// clock_gettime is available.
92
83
template <typename T = int , typename U = struct timespec >
@@ -95,26 +86,17 @@ double GetCpuTime(preferred_implementation,
95
86
T ClockId = 0 , U *Timespec = nullptr ,
96
87
decltype (clock_gettime(ClockId, Timespec)) *Enabled = nullptr) {
97
88
struct timespec tspec;
98
- if (clock_gettime (CLOCKID_CPU_TIME , &tspec) == 0 ) {
89
+ if (clock_gettime (CLOCKID , &tspec) == 0 ) {
99
90
return tspec.tv_nsec * 1.0e-9 + tspec.tv_sec ;
100
91
}
101
92
// Return some negative value to represent failure.
102
93
return -1.0 ;
103
94
}
104
- #endif // CLOCKID_CPU_TIME
95
+ #endif
105
96
106
97
using count_t = std::int64_t ;
107
98
using unsigned_count_t = std::uint64_t ;
108
99
109
- // POSIX implementation using clock_gettime where available. The clock_gettime
110
- // result is in nanoseconds, which is converted as necessary to
111
- // - deciseconds for kind 1
112
- // - milliseconds for kinds 2, 4
113
- // - nanoseconds for kinds 8, 16
114
- constexpr unsigned_count_t DS_PER_SEC{10u };
115
- constexpr unsigned_count_t MS_PER_SEC{1'000u };
116
- constexpr unsigned_count_t NS_PER_SEC{1'000'000'000u };
117
-
118
100
// Computes HUGE(INT(0,kind)) as an unsigned integer value.
119
101
static constexpr inline unsigned_count_t GetHUGE (int kind) {
120
102
if (kind > 8 ) {
@@ -123,65 +105,72 @@ static constexpr inline unsigned_count_t GetHUGE(int kind) {
123
105
return (unsigned_count_t {1 } << ((8 * kind) - 1 )) - 1 ;
124
106
}
125
107
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 std::timespec &tspec) {
130
- 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
- if (kind >= 8 ) {
134
- return (sec * NS_PER_SEC + nsec) % (huge + 1 );
135
- } else if (kind >= 2 ) {
136
- return (sec * MS_PER_SEC + (nsec / (NS_PER_SEC / MS_PER_SEC))) % (huge + 1 );
137
- } else { // kind == 1
138
- return (sec * DS_PER_SEC + (nsec / (NS_PER_SEC / DS_PER_SEC))) % (huge + 1 );
139
- }
140
- }
141
-
142
- // This is the fallback implementation, which should work everywhere.
108
+ // This is the fallback implementation, which should work everywhere. Note that
109
+ // in general we can't recover after std::clock has reached its maximum value.
143
110
template <typename Unused = void >
144
111
count_t GetSystemClockCount (int kind, fallback_implementation) {
145
- std::timespec tspec;
146
-
147
- if (std::timespec_get (&tspec, TIME_UTC) < 0 ) {
112
+ std::clock_t timestamp{std::clock ()};
113
+ if (timestamp == static_cast <std::clock_t >(-1 )) {
148
114
// Return -HUGE(COUNT) to represent failure.
149
115
return -static_cast <count_t >(GetHUGE (kind));
150
116
}
151
-
152
- // Compute the timestamp as seconds plus nanoseconds in accordance
153
- // with the requested kind at the call site.
154
- return ConvertTimeSpecToCount (kind, tspec);
117
+ // Convert the timestamp to std::uint64_t with wrap-around. The timestamp is
118
+ // most likely a floating-point value (since C'11), so compute the modulus
119
+ // carefully when one is required.
120
+ constexpr auto maxUnsignedCount{std::numeric_limits<unsigned_count_t >::max ()};
121
+ if constexpr (std::numeric_limits<std::clock_t >::max () > maxUnsignedCount) {
122
+ timestamp -= maxUnsignedCount * std::floor (timestamp / maxUnsignedCount);
123
+ }
124
+ unsigned_count_t unsignedCount{static_cast <unsigned_count_t >(timestamp)};
125
+ // Return the modulus of the unsigned integral count with HUGE(COUNT)+1.
126
+ // The result is a signed integer but never negative.
127
+ return static_cast <count_t >(unsignedCount % (GetHUGE (kind) + 1 ));
155
128
}
156
129
157
130
template <typename Unused = void >
158
131
count_t GetSystemClockCountRate (int kind, fallback_implementation) {
159
- return kind >= 8 ? NS_PER_SEC : kind >= 2 ? MS_PER_SEC : DS_PER_SEC ;
132
+ return CLOCKS_PER_SEC ;
160
133
}
161
134
162
135
template <typename Unused = void >
163
136
count_t GetSystemClockCountMax (int kind, fallback_implementation) {
137
+ constexpr auto max_clock_t {std::numeric_limits<std::clock_t >::max ()};
164
138
unsigned_count_t maxCount{GetHUGE (kind)};
165
- return maxCount;
139
+ return max_clock_t <= maxCount ? static_cast <count_t >(max_clock_t )
140
+ : static_cast <count_t >(maxCount);
166
141
}
167
142
168
- #ifdef CLOCKID_ELAPSED_TIME
143
+ // POSIX implementation using clock_gettime where available. The clock_gettime
144
+ // result is in nanoseconds, which is converted as necessary to
145
+ // - deciseconds for kind 1
146
+ // - milliseconds for kinds 2, 4
147
+ // - nanoseconds for kinds 8, 16
148
+ constexpr unsigned_count_t DS_PER_SEC{10u };
149
+ constexpr unsigned_count_t MS_PER_SEC{1'000u };
150
+ constexpr unsigned_count_t NS_PER_SEC{1'000'000'000u };
151
+
152
+ #ifdef CLOCKID
169
153
template <typename T = int , typename U = struct timespec >
170
154
count_t GetSystemClockCount (int kind, preferred_implementation,
171
155
// We need some dummy parameters to pass to decltype(clock_gettime).
172
156
T ClockId = 0 , U *Timespec = nullptr ,
173
157
decltype (clock_gettime(ClockId, Timespec)) *Enabled = nullptr) {
174
158
struct timespec tspec;
175
159
const unsigned_count_t huge{GetHUGE (kind)};
176
- if (clock_gettime (CLOCKID_ELAPSED_TIME , &tspec) != 0 ) {
160
+ if (clock_gettime (CLOCKID , &tspec) != 0 ) {
177
161
return -huge; // failure
178
162
}
179
-
180
- // Compute the timestamp as seconds plus nanoseconds in accordance
181
- // with the requested kind at the call site.
182
- return ConvertTimeSpecToCount (kind, tspec);
163
+ unsigned_count_t sec{static_cast <unsigned_count_t >(tspec.tv_sec )};
164
+ unsigned_count_t nsec{static_cast <unsigned_count_t >(tspec.tv_nsec )};
165
+ if (kind >= 8 ) {
166
+ return (sec * NS_PER_SEC + nsec) % (huge + 1 );
167
+ } else if (kind >= 2 ) {
168
+ return (sec * MS_PER_SEC + (nsec / (NS_PER_SEC / MS_PER_SEC))) % (huge + 1 );
169
+ } else { // kind == 1
170
+ return (sec * DS_PER_SEC + (nsec / (NS_PER_SEC / DS_PER_SEC))) % (huge + 1 );
171
+ }
183
172
}
184
- #endif // CLOCKID_ELAPSED_TIME
173
+ #endif
185
174
186
175
template <typename T = int , typename U = struct timespec >
187
176
count_t GetSystemClockCountRate (int kind, preferred_implementation,
0 commit comments