2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/portability/Time.h>
18 #include <folly/Likely.h>
24 template <typename _Rep, typename _Period>
25 static void duration_to_ts(
26 std::chrono::duration<_Rep, _Period> d,
27 struct timespec* ts) {
29 time_t(std::chrono::duration_cast<std::chrono::seconds>(d).count());
30 ts->tv_nsec = long(std::chrono::duration_cast<std::chrono::nanoseconds>(
31 d % std::chrono::seconds(1))
35 #if !FOLLY_HAVE_CLOCK_GETTIME || FOLLY_FORCE_CLOCK_GETTIME_DEFINITION
38 #include <mach/mach_init.h>
39 #include <mach/mach_port.h>
40 #include <mach/mach_time.h>
41 #include <mach/mach_types.h>
42 #include <mach/task.h>
43 #include <mach/thread_act.h>
44 #include <mach/vm_map.h>
47 namespace portability {
50 static std::chrono::nanoseconds time_value_to_ns(time_value_t t) {
51 return std::chrono::seconds(t.seconds) +
52 std::chrono::microseconds(t.microseconds);
55 static int clock_process_cputime(struct timespec* ts) {
56 // Get CPU usage for live threads.
57 task_thread_times_info thread_times_info;
58 mach_msg_type_number_t thread_times_info_count = TASK_THREAD_TIMES_INFO_COUNT;
59 kern_return_t kern_result = task_info(
61 TASK_THREAD_TIMES_INFO,
62 (thread_info_t)&thread_times_info,
63 &thread_times_info_count);
64 if (UNLIKELY(kern_result != KERN_SUCCESS)) {
68 // Get CPU usage for terminated threads.
69 mach_task_basic_info task_basic_info;
70 mach_msg_type_number_t task_basic_info_count = MACH_TASK_BASIC_INFO_COUNT;
71 kern_result = task_info(
74 (thread_info_t)&task_basic_info,
75 &task_basic_info_count);
76 if (UNLIKELY(kern_result != KERN_SUCCESS)) {
80 auto cputime = time_value_to_ns(thread_times_info.user_time) +
81 time_value_to_ns(thread_times_info.system_time) +
82 time_value_to_ns(task_basic_info.user_time) +
83 time_value_to_ns(task_basic_info.system_time);
84 duration_to_ts(cputime, ts);
88 static int clock_thread_cputime(struct timespec* ts) {
89 mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
90 thread_basic_info_data_t thread_info_data;
91 thread_act_t thread = mach_thread_self();
92 kern_return_t kern_result = thread_info(
93 thread, THREAD_BASIC_INFO, (thread_info_t)&thread_info_data, &count);
94 mach_port_deallocate(mach_task_self(), thread);
95 if (UNLIKELY(kern_result != KERN_SUCCESS)) {
98 auto cputime = time_value_to_ns(thread_info_data.system_time) +
99 time_value_to_ns(thread_info_data.user_time);
100 duration_to_ts(cputime, ts);
104 int clock_gettime(clockid_t clk_id, struct timespec* ts) {
106 case CLOCK_REALTIME: {
107 auto now = std::chrono::system_clock::now().time_since_epoch();
108 duration_to_ts(now, ts);
111 case CLOCK_MONOTONIC: {
112 auto now = std::chrono::steady_clock::now().time_since_epoch();
113 duration_to_ts(now, ts);
116 case CLOCK_PROCESS_CPUTIME_ID:
117 return clock_process_cputime(ts);
118 case CLOCK_THREAD_CPUTIME_ID:
119 return clock_thread_cputime(ts);
126 int clock_getres(clockid_t clk_id, struct timespec* ts) {
127 if (clk_id != CLOCK_MONOTONIC) {
131 static auto info = [] {
132 static mach_timebase_info_data_t info;
133 auto result = (mach_timebase_info(&info) == KERN_SUCCESS) ? &info : nullptr;
139 ts->tv_nsec = info->numer / info->denom;
145 } // namespace portability
147 #elif defined(_WIN32)
153 #include <folly/portability/Windows.h>
156 namespace portability {
159 using unsigned_nanos = std::chrono::duration<uint64_t, std::nano>;
161 static unsigned_nanos filetimeToUnsignedNanos(FILETIME ft) {
163 i.HighPart = ft.dwHighDateTime;
164 i.LowPart = ft.dwLowDateTime;
166 // FILETIMEs are in units of 100ns.
167 return unsigned_nanos(i.QuadPart * 100);
170 static LARGE_INTEGER performanceFrequency() {
171 static auto result = [] {
173 // On Windows XP or later, this will never fail.
174 BOOL res = QueryPerformanceFrequency(&freq);
181 extern "C" int clock_getres(clockid_t clock_id, struct timespec* res) {
187 static constexpr size_t kNsPerSec = 1000000000;
189 case CLOCK_REALTIME: {
190 constexpr auto perSec = double(std::chrono::system_clock::period::num) /
191 std::chrono::system_clock::period::den;
192 res->tv_sec = time_t(perSec);
193 res->tv_nsec = time_t(perSec * kNsPerSec);
196 case CLOCK_MONOTONIC: {
197 constexpr auto perSec = double(std::chrono::steady_clock::period::num) /
198 std::chrono::steady_clock::period::den;
199 res->tv_sec = time_t(perSec);
200 res->tv_nsec = time_t(perSec * kNsPerSec);
203 case CLOCK_PROCESS_CPUTIME_ID:
204 case CLOCK_THREAD_CPUTIME_ID: {
205 DWORD adj, timeIncrement;
207 if (!GetSystemTimeAdjustment(&adj, &timeIncrement, &adjDisabled)) {
213 res->tv_nsec = long(timeIncrement * 100);
223 extern "C" int clock_gettime(clockid_t clock_id, struct timespec* tp) {
229 const auto unanosToTimespec = [](timespec* tp, unsigned_nanos t) -> int {
230 static constexpr unsigned_nanos one_sec{std::chrono::seconds(1)};
232 time_t(std::chrono::duration_cast<std::chrono::seconds>(t).count());
233 tp->tv_nsec = long((t % one_sec).count());
237 FILETIME createTime, exitTime, kernalTime, userTime;
239 case CLOCK_REALTIME: {
240 auto now = std::chrono::system_clock::now().time_since_epoch();
241 duration_to_ts(now, tp);
244 case CLOCK_MONOTONIC: {
245 auto now = std::chrono::steady_clock::now().time_since_epoch();
246 duration_to_ts(now, tp);
249 case CLOCK_PROCESS_CPUTIME_ID: {
250 if (!GetProcessTimes(
260 return unanosToTimespec(
262 filetimeToUnsignedNanos(kernalTime) +
263 filetimeToUnsignedNanos(userTime));
265 case CLOCK_THREAD_CPUTIME_ID: {
276 return unanosToTimespec(
278 filetimeToUnsignedNanos(kernalTime) +
279 filetimeToUnsignedNanos(userTime));
289 } // namespace portability
292 #error No clock_gettime(3) compatibility wrapper available for this platform.
300 #include <folly/portability/Windows.h>
303 char* asctime_r(const tm* tm, char* buf) {
305 if (asctime_s(tmpBuf, tm)) {
308 // Nothing we can do if the buff is to small :(
309 return strcpy(buf, tmpBuf);
312 char* ctime_r(const time_t* t, char* buf) {
314 if (ctime_s(tmpBuf, 64, t)) {
317 // Nothing we can do if the buff is to small :(
318 return strcpy(buf, tmpBuf);
321 tm* gmtime_r(const time_t* t, tm* res) {
322 if (!gmtime_s(res, t)) {
328 tm* localtime_r(const time_t* t, tm* o) {
329 if (!localtime_s(o, t)) {
335 int nanosleep(const struct timespec* request, struct timespec* remain) {
336 Sleep((DWORD)((request->tv_sec * 1000) + (request->tv_nsec / 1000000)));
337 if (remain != nullptr) {
345 const char* __restrict s,
346 const char* __restrict f,
347 struct tm* __restrict tm) {
348 // Isn't the C++ standard lib nice? std::get_time is defined such that its
349 // format parameters are the exact same as strptime. Of course, we have to
350 // create a string stream first, and imbue it with the current C locale, and
351 // we also have to make sure we return the right things if it fails, or
352 // if it succeeds, but this is still far simpler an implementation than any
353 // of the versions in any of the C standard libraries.
354 std::istringstream input(s);
355 input.imbue(std::locale(setlocale(LC_ALL, nullptr)));
356 input >> std::get_time(tm, f);
360 return const_cast<char*>(s + input.tellg());