1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #ifndef COMMON_CEPH_TIME_H
16 #define COMMON_CEPH_TIME_H
24 #if defined(__APPLE__)
25 #include <sys/_types/_timespec.h>
27 #define CLOCK_REALTIME_COARSE CLOCK_REALTIME
28 #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
30 int clock_gettime(int clk_id
, struct timespec
*tp
);
34 #define CLOCK_REALTIME_COARSE CLOCK_REALTIME
35 #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
36 // MINGW uses the QueryPerformanceCounter API behind the scenes.
42 // Currently we use a 64-bit count of nanoseconds.
44 // We could, if we wished, use a struct holding a uint64_t count
45 // of seconds and a uint32_t count of nanoseconds.
47 // At least this way we can change it to something else if we
52 // duration is the concrete time representation for our code in the
53 // case that we are only interested in durations between now and the
54 // future. Using it means we don't have to have EVERY function that
55 // deals with a duration be a template. We can do so for user-facing
57 typedef std::chrono::duration
<rep
, std::nano
> timespan
;
60 // Like the above but signed.
61 typedef int64_t signed_rep
;
63 // Similar to the above but for durations that can specify
64 // differences between now and a time point in the past.
65 typedef std::chrono::duration
<signed_rep
, std::nano
> signedspan
;
67 template<typename Duration
>
68 struct timeval
to_timeval(Duration d
) {
70 auto sec
= std::chrono::duration_cast
<std::chrono::seconds
>(d
);
71 tv
.tv_sec
= sec
.count();
72 auto usec
= std::chrono::duration_cast
<std::chrono::microseconds
>(d
-sec
);
73 tv
.tv_usec
= usec
.count();
77 // We define our own clocks so we can have our choice of all time
78 // sources supported by the operating system. With the standard
79 // library the resolution and cost are unspecified. (For example,
80 // the libc++ system_clock class gives only microsecond
83 // One potential issue is that we should accept system_clock
84 // timepoints in user-facing APIs alongside (or instead of)
85 // ceph::real_clock times.
87 // High-resolution real-time clock
90 typedef timespan duration
;
91 typedef duration::rep rep
;
92 typedef duration::period period
;
93 // The second template parameter defaults to the clock's duration
95 typedef std::chrono::time_point
<real_clock
> time_point
;
96 static constexpr const bool is_steady
= false;
98 static time_point
now() noexcept
{
100 clock_gettime(CLOCK_REALTIME
, &ts
);
101 return from_timespec(ts
);
104 static bool is_zero(const time_point
& t
) {
105 return (t
== time_point::min());
108 static time_point
zero() {
109 return time_point::min();
112 // Allow conversion to/from any clock with the same interface as
113 // std::chrono::system_clock)
114 template<typename Clock
, typename Duration
>
115 static time_point
to_system_time_point(
116 const std::chrono::time_point
<Clock
, Duration
>& t
) {
117 return time_point(seconds(Clock::to_time_t(t
)) +
118 std::chrono::duration_cast
<duration
>(t
.time_since_epoch() %
119 std::chrono::seconds(1)));
121 template<typename Clock
, typename Duration
>
122 static std::chrono::time_point
<Clock
, Duration
> to_system_time_point(
123 const time_point
& t
) {
124 return (Clock::from_time_t(to_time_t(t
)) +
125 std::chrono::duration_cast
<Duration
>(t
.time_since_epoch() %
126 std::chrono::seconds(1)));
129 static time_t to_time_t(const time_point
& t
) noexcept
{
130 return std::chrono::duration_cast
<std::chrono::seconds
>(t
.time_since_epoch()).count();
132 static time_point
from_time_t(const time_t& t
) noexcept
{
133 return time_point(std::chrono::seconds(t
));
136 static void to_timespec(const time_point
& t
, struct timespec
& ts
) {
137 ts
.tv_sec
= to_time_t(t
);
138 ts
.tv_nsec
= (t
.time_since_epoch() % std::chrono::seconds(1)).count();
140 static struct timespec
to_timespec(const time_point
& t
) {
145 static time_point
from_timespec(const struct timespec
& ts
) {
146 return time_point(std::chrono::seconds(ts
.tv_sec
) +
147 std::chrono::nanoseconds(ts
.tv_nsec
));
150 static void to_ceph_timespec(const time_point
& t
,
151 struct ceph_timespec
& ts
);
152 static struct ceph_timespec
to_ceph_timespec(const time_point
& t
);
153 static time_point
from_ceph_timespec(const struct ceph_timespec
& ts
);
155 static void to_timeval(const time_point
& t
, struct timeval
& tv
) {
156 tv
.tv_sec
= to_time_t(t
);
157 tv
.tv_usec
= std::chrono::duration_cast
<std::chrono::microseconds
>(
158 t
.time_since_epoch() % std::chrono::seconds(1)).count();
160 static struct timeval
to_timeval(const time_point
& t
) {
165 static time_point
from_timeval(const struct timeval
& tv
) {
166 return time_point(std::chrono::seconds(tv
.tv_sec
) +
167 std::chrono::microseconds(tv
.tv_usec
));
170 static double to_double(const time_point
& t
) {
171 return std::chrono::duration
<double>(t
.time_since_epoch()).count();
173 static time_point
from_double(const double d
) {
174 return time_point(std::chrono::duration_cast
<duration
>(
175 std::chrono::duration
<double>(d
)));
179 // Low-resolution but preusmably faster real-time clock
180 class coarse_real_clock
{
182 typedef timespan duration
;
183 typedef duration::rep rep
;
184 typedef duration::period period
;
185 // The second template parameter defaults to the clock's duration
187 typedef std::chrono::time_point
<coarse_real_clock
> time_point
;
188 static constexpr const bool is_steady
= false;
190 static time_point
now() noexcept
{
192 #if defined(CLOCK_REALTIME_COARSE)
193 // Linux systems have _COARSE clocks.
194 clock_gettime(CLOCK_REALTIME_COARSE
, &ts
);
195 #elif defined(CLOCK_REALTIME_FAST)
196 // BSD systems have _FAST clocks.
197 clock_gettime(CLOCK_REALTIME_FAST
, &ts
);
199 // And if we find neither, you may wish to consult your system's
201 #warning Falling back to CLOCK_REALTIME, may be slow.
202 clock_gettime(CLOCK_REALTIME
, &ts
);
204 return from_timespec(ts
);
207 static bool is_zero(const time_point
& t
) {
208 return (t
== time_point::min());
211 static time_point
zero() {
212 return time_point::min();
215 static time_t to_time_t(const time_point
& t
) noexcept
{
216 return std::chrono::duration_cast
<std::chrono::seconds
>(
217 t
.time_since_epoch()).count();
219 static time_point
from_time_t(const time_t t
) noexcept
{
220 return time_point(std::chrono::seconds(t
));
223 static void to_timespec(const time_point
& t
, struct timespec
& ts
) {
224 ts
.tv_sec
= to_time_t(t
);
225 ts
.tv_nsec
= (t
.time_since_epoch() % std::chrono::seconds(1)).count();
227 static struct timespec
to_timespec(const time_point
& t
) {
232 static time_point
from_timespec(const struct timespec
& ts
) {
233 return time_point(std::chrono::seconds(ts
.tv_sec
) +
234 std::chrono::nanoseconds(ts
.tv_nsec
));
237 static void to_ceph_timespec(const time_point
& t
,
238 struct ceph_timespec
& ts
);
239 static struct ceph_timespec
to_ceph_timespec(const time_point
& t
);
240 static time_point
from_ceph_timespec(const struct ceph_timespec
& ts
);
242 static void to_timeval(const time_point
& t
, struct timeval
& tv
) {
243 tv
.tv_sec
= to_time_t(t
);
244 tv
.tv_usec
= std::chrono::duration_cast
<std::chrono::microseconds
>(
245 t
.time_since_epoch() % std::chrono::seconds(1)).count();
247 static struct timeval
to_timeval(const time_point
& t
) {
252 static time_point
from_timeval(const struct timeval
& tv
) {
253 return time_point(std::chrono::seconds(tv
.tv_sec
) +
254 std::chrono::microseconds(tv
.tv_usec
));
257 static double to_double(const time_point
& t
) {
258 return std::chrono::duration
<double>(t
.time_since_epoch()).count();
260 static time_point
from_double(const double d
) {
261 return time_point(std::chrono::duration_cast
<duration
>(
262 std::chrono::duration
<double>(d
)));
266 // High-resolution monotonic clock
269 typedef timespan duration
;
270 typedef duration::rep rep
;
271 typedef duration::period period
;
272 typedef std::chrono::time_point
<mono_clock
> time_point
;
273 static constexpr const bool is_steady
= true;
275 static time_point
now() noexcept
{
277 clock_gettime(CLOCK_MONOTONIC
, &ts
);
278 return time_point(std::chrono::seconds(ts
.tv_sec
) +
279 std::chrono::nanoseconds(ts
.tv_nsec
));
282 static bool is_zero(const time_point
& t
) {
283 return (t
== time_point::min());
286 static time_point
zero() {
287 return time_point::min();
291 // Low-resolution but, I would hope or there's no point, faster
293 class coarse_mono_clock
{
295 typedef timespan duration
;
296 typedef duration::rep rep
;
297 typedef duration::period period
;
298 typedef std::chrono::time_point
<coarse_mono_clock
> time_point
;
299 static constexpr const bool is_steady
= true;
301 static time_point
now() noexcept
{
303 #if defined(CLOCK_MONOTONIC_COARSE)
304 // Linux systems have _COARSE clocks.
305 clock_gettime(CLOCK_MONOTONIC_COARSE
, &ts
);
306 #elif defined(CLOCK_MONOTONIC_FAST)
307 // BSD systems have _FAST clocks.
308 clock_gettime(CLOCK_MONOTONIC_FAST
, &ts
);
310 // And if we find neither, you may wish to consult your system's
312 #warning Falling back to CLOCK_MONOTONIC, may be slow.
313 clock_gettime(CLOCK_MONOTONIC
, &ts
);
315 return time_point(std::chrono::seconds(ts
.tv_sec
) +
316 std::chrono::nanoseconds(ts
.tv_nsec
));
319 static bool is_zero(const time_point
& t
) {
320 return (t
== time_point::min());
323 static time_point
zero() {
324 return time_point::min();
328 namespace time_detail
{
329 // So that our subtractions produce negative spans rather than
330 // arithmetic underflow.
331 template<typename Rep1
, typename Period1
, typename Rep2
,
333 inline auto difference(std::chrono::duration
<Rep1
, Period1
> minuend
,
334 std::chrono::duration
<Rep2
, Period2
> subtrahend
)
335 -> typename
std::common_type
<
336 std::chrono::duration
<typename
std::make_signed
<Rep1
>::type
,
338 std::chrono::duration
<typename
std::make_signed
<Rep2
>::type
,
342 typename
std::common_type
<
343 std::chrono::duration
<typename
std::make_signed
<Rep1
>::type
,
345 std::chrono::duration
<typename
std::make_signed
<Rep2
>::type
,
347 return srep(srep(minuend
).count() - srep(subtrahend
).count());
350 template<typename Clock
, typename Duration1
, typename Duration2
>
351 inline auto difference(
352 typename
std::chrono::time_point
<Clock
, Duration1
> minuend
,
353 typename
std::chrono::time_point
<Clock
, Duration2
> subtrahend
)
354 -> typename
std::common_type
<
355 std::chrono::duration
<typename
std::make_signed
<
356 typename
Duration1::rep
>::type
,
357 typename
Duration1::period
>,
358 std::chrono::duration
<typename
std::make_signed
<
359 typename
Duration2::rep
>::type
,
360 typename
Duration2::period
> >::type
{
361 return difference(minuend
.time_since_epoch(),
362 subtrahend
.time_since_epoch());
366 // Please note that the coarse clocks are disjoint. You cannot
367 // subtract a real_clock timepoint from a coarse_real_clock
368 // timepoint as, from C++'s perspective, they are disjoint types.
370 // This is not necessarily bad. If I sample a mono_clock and then a
371 // coarse_mono_clock, the coarse_mono_clock's time could potentially
372 // be previous to the mono_clock's time (just due to differing
373 // resolution) which would be Incorrect.
375 // This is not horrible, though, since you can use an idiom like
376 // mono_clock::timepoint(coarsepoint.time_since_epoch()) to unwrap
377 // and rewrap if you know what you're doing.
380 // Actual wall-clock times
381 typedef real_clock::time_point real_time
;
382 typedef coarse_real_clock::time_point coarse_real_time
;
384 // Monotonic times should never be serialized or communicated
385 // between machines, since they are incomparable. Thus we also don't
386 // make any provision for converting between
387 // std::chrono::steady_clock time and ceph::mono_clock time.
388 typedef mono_clock::time_point mono_time
;
389 typedef coarse_mono_clock::time_point coarse_mono_time
;
391 template<typename Rep1
, typename Ratio1
, typename Rep2
, typename Ratio2
>
392 auto floor(const std::chrono::duration
<Rep1
, Ratio1
>& duration
,
393 const std::chrono::duration
<Rep2
, Ratio2
>& precision
) ->
394 typename
std::common_type
<std::chrono::duration
<Rep1
, Ratio1
>,
395 std::chrono::duration
<Rep2
, Ratio2
> >::type
{
396 return duration
- (duration
% precision
);
399 template<typename Rep1
, typename Ratio1
, typename Rep2
, typename Ratio2
>
400 auto ceil(const std::chrono::duration
<Rep1
, Ratio1
>& duration
,
401 const std::chrono::duration
<Rep2
, Ratio2
>& precision
) ->
402 typename
std::common_type
<std::chrono::duration
<Rep1
, Ratio1
>,
403 std::chrono::duration
<Rep2
, Ratio2
> >::type
{
404 auto tmod
= duration
% precision
;
405 return duration
- tmod
+ (tmod
> tmod
.zero() ? 1 : 0) * precision
;
408 template<typename Clock
, typename Duration
, typename Rep
, typename Ratio
>
409 auto floor(const std::chrono::time_point
<Clock
, Duration
>& timepoint
,
410 const std::chrono::duration
<Rep
, Ratio
>& precision
) ->
411 std::chrono::time_point
<Clock
,
412 typename
std::common_type
<
413 Duration
, std::chrono::duration
<Rep
, Ratio
>
415 return std::chrono::time_point
<
416 Clock
, typename
std::common_type
<
417 Duration
, std::chrono::duration
<Rep
, Ratio
> >::type
>(
418 floor(timepoint
.time_since_epoch(), precision
));
420 template<typename Clock
, typename Duration
, typename Rep
, typename Ratio
>
421 auto ceil(const std::chrono::time_point
<Clock
, Duration
>& timepoint
,
422 const std::chrono::duration
<Rep
, Ratio
>& precision
) ->
423 std::chrono::time_point
<Clock
,
424 typename
std::common_type
<
426 std::chrono::duration
<Rep
, Ratio
> >::type
> {
427 return std::chrono::time_point
<
428 Clock
, typename
std::common_type
<
429 Duration
, std::chrono::duration
<Rep
, Ratio
> >::type
>(
430 ceil(timepoint
.time_since_epoch(), precision
));
433 inline timespan
make_timespan(const double d
) {
434 return std::chrono::duration_cast
<timespan
>(
435 std::chrono::duration
<double>(d
));
437 inline std::optional
<timespan
> maybe_timespan(const double d
) {
438 return d
? std::make_optional(make_timespan(d
)) : std::nullopt
;
441 template<typename Clock
,
442 typename
std::enable_if
<!Clock::is_steady
>::type
* = nullptr>
443 std::ostream
& operator<<(std::ostream
& m
,
444 const std::chrono::time_point
<Clock
>& t
);
445 template<typename Clock
,
446 typename
std::enable_if
<Clock::is_steady
>::type
* = nullptr>
447 std::ostream
& operator<<(std::ostream
& m
,
448 const std::chrono::time_point
<Clock
>& t
);
450 // The way std::chrono handles the return type of subtraction is not
451 // wonderful. The difference of two unsigned types SHOULD be signed.
453 inline signedspan
operator -(real_time minuend
,
454 real_time subtrahend
) {
455 return time_detail::difference(minuend
, subtrahend
);
458 inline signedspan
operator -(coarse_real_time minuend
,
459 coarse_real_time subtrahend
) {
460 return time_detail::difference(minuend
, subtrahend
);
463 inline signedspan
operator -(mono_time minuend
,
464 mono_time subtrahend
) {
465 return time_detail::difference(minuend
, subtrahend
);
468 inline signedspan
operator -(coarse_mono_time minuend
,
469 coarse_mono_time subtrahend
) {
470 return time_detail::difference(minuend
, subtrahend
);
473 // We could add specializations of time_point - duration and
474 // time_point + duration to assert on overflow, but I don't think we
476 inline timespan
abs(signedspan z
) {
477 return z
> signedspan::zero() ?
478 std::chrono::duration_cast
<timespan
>(z
) :
479 timespan(-z
.count());
481 inline timespan
to_timespan(signedspan z
) {
482 if (z
< signedspan::zero()) {
483 //ceph_assert(z >= signedspan::zero());
484 // There is a kernel bug that seems to be triggering this assert. We've
486 // centos 8.1: 4.18.0-147.el8.x86_64
487 // debian 10.3: 4.19.0-8-amd64
488 // debian 10.1: 4.19.67-2+deb10u1
491 // https://tracker.ceph.com/issues/43365
492 // https://tracker.ceph.com/issues/44078
493 z
= signedspan::zero();
495 return std::chrono::duration_cast
<timespan
>(z
);
498 std::string
timespan_str(timespan t
);
499 std::string
exact_timespan_str(timespan t
);
500 std::chrono::seconds
parse_timespan(const std::string
& s
);
502 // detects presence of Clock::to_timespec() and from_timespec()
503 template <typename Clock
, typename
= std::void_t
<>>
504 struct converts_to_timespec
: std::false_type
{};
506 template <typename Clock
>
507 struct converts_to_timespec
<Clock
, std::void_t
<decltype(
508 Clock::from_timespec(Clock::to_timespec(
509 std::declval
<typename
Clock::time_point
>()))
510 )>> : std::true_type
{};
512 template <typename Clock
>
513 constexpr bool converts_to_timespec_v
= converts_to_timespec
<Clock
>::value
;
515 template<typename Rep
, typename T
>
516 static Rep
to_seconds(T t
) {
517 return std::chrono::duration_cast
<
518 std::chrono::duration
<Rep
>>(t
).count();
521 template<typename Rep
, typename T
>
522 static Rep
to_microseconds(T t
) {
523 return std::chrono::duration_cast
<
524 std::chrono::duration
<
526 std::micro
>>(t
).count();
532 template<typename Rep
, typename Period
>
533 ostream
& operator<<(ostream
& m
, const chrono::duration
<Rep
, Period
>& t
);
536 #endif // COMMON_CEPH_TIME_H