Return the correct resolution for clock_getres
[folly.git] / folly / portability / Time.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/portability/Time.h>
18 #include <folly/Likely.h>
19
20 #include <assert.h>
21
22 #include <chrono>
23
24 template <typename _Rep, typename _Period>
25 static void duration_to_ts(
26     std::chrono::duration<_Rep, _Period> d,
27     struct timespec* ts) {
28   ts->tv_sec = std::chrono::duration_cast<std::chrono::seconds>(d).count();
29   ts->tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(
30                     d % std::chrono::seconds(1))
31                     .count();
32 }
33
34 #if !FOLLY_HAVE_CLOCK_GETTIME
35 #if __MACH__
36 #include <errno.h>
37 #include <mach/mach_init.h>
38 #include <mach/mach_port.h>
39 #include <mach/mach_time.h>
40 #include <mach/mach_types.h>
41 #include <mach/task.h>
42 #include <mach/thread_act.h>
43 #include <mach/vm_map.h>
44
45 static std::chrono::nanoseconds time_value_to_ns(time_value_t t) {
46   return std::chrono::seconds(t.seconds) +
47       std::chrono::microseconds(t.microseconds);
48 }
49
50 static int clock_process_cputime(struct timespec* ts) {
51   // Get CPU usage for live threads.
52   task_thread_times_info thread_times_info;
53   mach_msg_type_number_t thread_times_info_count = TASK_THREAD_TIMES_INFO_COUNT;
54   kern_return_t kern_result = task_info(
55       mach_task_self(),
56       TASK_THREAD_TIMES_INFO,
57       (thread_info_t)&thread_times_info,
58       &thread_times_info_count);
59   if (UNLIKELY(kern_result != KERN_SUCCESS)) {
60     return -1;
61   }
62
63   // Get CPU usage for terminated threads.
64   mach_task_basic_info task_basic_info;
65   mach_msg_type_number_t task_basic_info_count = MACH_TASK_BASIC_INFO_COUNT;
66   kern_result = task_info(
67       mach_task_self(),
68       MACH_TASK_BASIC_INFO,
69       (thread_info_t)&task_basic_info,
70       &task_basic_info_count);
71   if (UNLIKELY(kern_result != KERN_SUCCESS)) {
72     return -1;
73   }
74
75   auto cputime = time_value_to_ns(thread_times_info.user_time) +
76       time_value_to_ns(thread_times_info.system_time) +
77       time_value_to_ns(task_basic_info.user_time) +
78       time_value_to_ns(task_basic_info.system_time);
79   duration_to_ts(cputime, ts);
80   return 0;
81 }
82
83 static int clock_thread_cputime(struct timespec* ts) {
84   mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
85   thread_basic_info_data_t thread_info_data;
86   thread_act_t thread = mach_thread_self();
87   kern_return_t kern_result = thread_info(
88       thread, THREAD_BASIC_INFO, (thread_info_t)&thread_info_data, &count);
89   mach_port_deallocate(mach_task_self(), thread);
90   if (UNLIKELY(kern_result != KERN_SUCCESS)) {
91     return -1;
92   }
93   auto cputime = time_value_to_ns(thread_info_data.system_time) +
94       time_value_to_ns(thread_info_data.user_time);
95   duration_to_ts(cputime, ts);
96   return 0;
97 }
98
99 int clock_gettime(clockid_t clk_id, struct timespec* ts) {
100   switch (clk_id) {
101     case CLOCK_REALTIME: {
102       auto now = std::chrono::system_clock::now().time_since_epoch();
103       duration_to_ts(now, ts);
104       return 0;
105     }
106     case CLOCK_MONOTONIC: {
107       auto now = std::chrono::steady_clock::now().time_since_epoch();
108       duration_to_ts(now, ts);
109       return 0;
110     }
111     case CLOCK_PROCESS_CPUTIME_ID:
112       return clock_process_cputime(ts);
113     case CLOCK_THREAD_CPUTIME_ID:
114       return clock_thread_cputime(ts);
115     default:
116       errno = EINVAL;
117       return -1;
118   }
119 }
120
121 int clock_getres(clockid_t clk_id, struct timespec* ts) {
122   if (clk_id != CLOCK_MONOTONIC) {
123     return -1;
124   }
125
126   static auto info = [] {
127     static mach_timebase_info_data_t info;
128     auto result = (mach_timebase_info(&info) == KERN_SUCCESS) ? &info : nullptr;
129     assert(result);
130     return result;
131   }();
132
133   ts->tv_sec = 0;
134   ts->tv_nsec = info->numer / info->denom;
135
136   return 0;
137 }
138 #elif defined(_WIN32)
139 #include <errno.h>
140 #include <locale.h>
141 #include <stdint.h>
142 #include <stdlib.h>
143
144 #include <folly/portability/Windows.h>
145
146 using unsigned_nanos = std::chrono::duration<uint64_t, std::nano>;
147
148 static unsigned_nanos filetimeToUnsignedNanos(FILETIME ft) {
149   ULARGE_INTEGER i;
150   i.HighPart = ft.dwHighDateTime;
151   i.LowPart = ft.dwLowDateTime;
152
153   // FILETIMEs are in units of 100ns.
154   return unsigned_nanos(i.QuadPart * 100);
155 };
156
157 static LARGE_INTEGER performanceFrequency() {
158   static auto result = [] {
159     LARGE_INTEGER freq;
160     // On Windows XP or later, this will never fail.
161     BOOL res = QueryPerformanceFrequency(&freq);
162     assert(res);
163     return freq;
164   }();
165   return result;
166 }
167
168 extern "C" int clock_getres(clockid_t clock_id, struct timespec* res) {
169   if (!res) {
170     errno = EFAULT;
171     return -1;
172   }
173
174   static constexpr size_t kNsPerSec = 1000000000;
175   switch (clock_id) {
176     case CLOCK_REALTIME: {
177       constexpr auto perSec = double(std::chrono::system_clock::period::num) /
178           std::chrono::system_clock::period::den;
179       res->tv_sec = time_t(perSec);
180       res->tv_nsec = time_t(perSec * kNsPerSec);
181       return 0;
182     }
183     case CLOCK_MONOTONIC: {
184       constexpr auto perSec = double(std::chrono::steady_clock::period::num) /
185           std::chrono::steady_clock::period::den;
186       res->tv_sec = time_t(perSec);
187       res->tv_nsec = time_t(perSec * kNsPerSec);
188       return 0;
189     }
190     case CLOCK_PROCESS_CPUTIME_ID:
191     case CLOCK_THREAD_CPUTIME_ID: {
192       DWORD adj, timeIncrement;
193       BOOL adjDisabled;
194       if (!GetSystemTimeAdjustment(&adj, &timeIncrement, &adjDisabled)) {
195         errno = EINVAL;
196         return -1;
197       }
198
199       res->tv_sec = 0;
200       res->tv_nsec = timeIncrement * 100;
201       return 0;
202     }
203
204     default:
205       errno = EINVAL;
206       return -1;
207   }
208 }
209
210 extern "C" int clock_gettime(clockid_t clock_id, struct timespec* tp) {
211   if (!tp) {
212     errno = EFAULT;
213     return -1;
214   }
215
216   const auto unanosToTimespec = [](timespec* tp, unsigned_nanos t) -> int {
217     static constexpr unsigned_nanos one_sec(std::chrono::seconds(1));
218     tp->tv_sec = std::chrono::duration_cast<std::chrono::seconds>(t).count();
219     tp->tv_nsec = (t % one_sec).count();
220     return 0;
221   };
222
223   FILETIME createTime, exitTime, kernalTime, userTime;
224   switch (clock_id) {
225     case CLOCK_REALTIME: {
226       auto now = std::chrono::system_clock::now().time_since_epoch();
227       duration_to_ts(now, tp);
228       return 0;
229     }
230     case CLOCK_MONOTONIC: {
231       auto now = std::chrono::steady_clock::now().time_since_epoch();
232       duration_to_ts(now, tp);
233       return 0;
234     }
235     case CLOCK_PROCESS_CPUTIME_ID: {
236       if (!GetProcessTimes(
237               GetCurrentProcess(),
238               &createTime,
239               &exitTime,
240               &kernalTime,
241               &userTime)) {
242         errno = EINVAL;
243         return -1;
244       }
245
246       return unanosToTimespec(
247           tp,
248           filetimeToUnsignedNanos(kernalTime) +
249               filetimeToUnsignedNanos(userTime));
250     }
251     case CLOCK_THREAD_CPUTIME_ID: {
252       if (!GetThreadTimes(
253               GetCurrentThread(),
254               &createTime,
255               &exitTime,
256               &kernalTime,
257               &userTime)) {
258         errno = EINVAL;
259         return -1;
260       }
261
262       return unanosToTimespec(
263           tp,
264           filetimeToUnsignedNanos(kernalTime) +
265               filetimeToUnsignedNanos(userTime));
266     }
267
268     default:
269       errno = EINVAL;
270       return -1;
271   }
272 }
273 #else
274 #error No clock_gettime(3) compatibility wrapper available for this platform.
275 #endif
276 #endif
277
278 #ifdef _WIN32
279 #include <iomanip>
280 #include <sstream>
281
282 #include <folly/portability/Windows.h>
283
284 extern "C" {
285 char* asctime_r(const tm* tm, char* buf) {
286   char tmpBuf[64];
287   if (asctime_s(tmpBuf, tm)) {
288     return nullptr;
289   }
290   // Nothing we can do if the buff is to small :(
291   return strcpy(buf, tmpBuf);
292 }
293
294 char* ctime_r(const time_t* t, char* buf) {
295   char tmpBuf[64];
296   if (ctime_s(tmpBuf, 64, t)) {
297     return nullptr;
298   }
299   // Nothing we can do if the buff is to small :(
300   return strcpy(buf, tmpBuf);
301 }
302
303 tm* gmtime_r(const time_t* t, tm* res) {
304   if (!gmtime_s(res, t)) {
305     return res;
306   }
307   return nullptr;
308 }
309
310 tm* localtime_r(const time_t* t, tm* o) {
311   if (!localtime_s(o, t)) {
312     return o;
313   }
314   return nullptr;
315 }
316
317 int nanosleep(const struct timespec* request, struct timespec* remain) {
318   Sleep((DWORD)((request->tv_sec * 1000) + (request->tv_nsec / 1000000)));
319   if (remain != nullptr) {
320     remain->tv_nsec = 0;
321     remain->tv_sec = 0;
322   }
323   return 0;
324 }
325
326 char* strptime(const char* __restrict s,
327                const char* __restrict f,
328                struct tm* __restrict tm) {
329   // Isn't the C++ standard lib nice? std::get_time is defined such that its
330   // format parameters are the exact same as strptime. Of course, we have to
331   // create a string stream first, and imbue it with the current C locale, and
332   // we also have to make sure we return the right things if it fails, or
333   // if it succeeds, but this is still far simpler an implementation than any
334   // of the versions in any of the C standard libraries.
335   std::istringstream input(s);
336   input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
337   input >> std::get_time(tm, f);
338   if (input.fail()) {
339     return nullptr;
340   }
341   return const_cast<char*>(s + input.tellg());
342 }
343 }
344 #endif