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