]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/ceph_time.h
update ceph source to reef 18.2.0
[ceph.git] / ceph / src / common / ceph_time.h
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
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.
12 *
13 */
14
15#ifndef COMMON_CEPH_TIME_H
16#define COMMON_CEPH_TIME_H
17
18#include <chrono>
11fdf7f2
TL
19#include <iostream>
20#include <string>
f67539c2 21#include <optional>
1e59de90
TL
22#if FMT_VERSION >= 90000
23#include <fmt/ostream.h>
24#endif
11fdf7f2 25#include <sys/time.h>
7c673cae 26
11fdf7f2 27#if defined(__APPLE__)
7c673cae 28#include <sys/_types/_timespec.h>
7c673cae 29
7c673cae
FG
30#define CLOCK_REALTIME_COARSE CLOCK_REALTIME
31#define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
32
33int clock_gettime(int clk_id, struct timespec *tp);
34#endif
35
f67539c2 36#ifdef _WIN32
1e59de90
TL
37// Clock precision:
38// mingw < 8.0.1:
39// * CLOCK_REALTIME: ~10-55ms (GetSystemTimeAsFileTime)
40// mingw >= 8.0.1:
41// * CLOCK_REALTIME: <1us (GetSystemTimePreciseAsFileTime)
42// * CLOCK_REALTIME_COARSE: ~10-55ms (GetSystemTimeAsFileTime)
43//
44// * CLOCK_MONOTONIC: <1us if TSC is usable, ~10-55ms otherwise
45// (QueryPerformanceCounter)
46// https://github.com/mirror/mingw-w64/commit/dcd990ed423381cf35702df9495d44f1979ebe50
47#ifndef CLOCK_REALTIME_COARSE
48 #define CLOCK_REALTIME_COARSE CLOCK_REALTIME
49#endif
50#ifndef CLOCK_MONOTONIC_COARSE
51 #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
52#endif
f67539c2
TL
53#endif
54
7c673cae
FG
55struct ceph_timespec;
56
57namespace ceph {
f67539c2
TL
58// Currently we use a 64-bit count of nanoseconds.
59
60// We could, if we wished, use a struct holding a uint64_t count
61// of seconds and a uint32_t count of nanoseconds.
62
63// At least this way we can change it to something else if we
64// want.
65typedef uint64_t rep;
66
67
68// duration is the concrete time representation for our code in the
69// case that we are only interested in durations between now and the
70// future. Using it means we don't have to have EVERY function that
71// deals with a duration be a template. We can do so for user-facing
72// APIs, however.
73typedef std::chrono::duration<rep, std::nano> timespan;
74
75
76// Like the above but signed.
77typedef int64_t signed_rep;
78
79// Similar to the above but for durations that can specify
80// differences between now and a time point in the past.
81typedef std::chrono::duration<signed_rep, std::nano> signedspan;
82
83template<typename Duration>
84struct timeval to_timeval(Duration d) {
85 struct timeval tv;
86 auto sec = std::chrono::duration_cast<std::chrono::seconds>(d);
87 tv.tv_sec = sec.count();
88 auto usec = std::chrono::duration_cast<std::chrono::microseconds>(d-sec);
89 tv.tv_usec = usec.count();
90 return tv;
91}
92
93// We define our own clocks so we can have our choice of all time
94// sources supported by the operating system. With the standard
95// library the resolution and cost are unspecified. (For example,
96// the libc++ system_clock class gives only microsecond
97// resolution.)
98
99// One potential issue is that we should accept system_clock
100// timepoints in user-facing APIs alongside (or instead of)
101// ceph::real_clock times.
102
103// High-resolution real-time clock
104class real_clock {
105public:
106 typedef timespan duration;
107 typedef duration::rep rep;
108 typedef duration::period period;
109 // The second template parameter defaults to the clock's duration
110 // type.
111 typedef std::chrono::time_point<real_clock> time_point;
112 static constexpr const bool is_steady = false;
113
114 static time_point now() noexcept {
115 struct timespec ts;
116 clock_gettime(CLOCK_REALTIME, &ts);
117 return from_timespec(ts);
118 }
119
120 static bool is_zero(const time_point& t) {
121 return (t == time_point::min());
122 }
123
124 static time_point zero() {
125 return time_point::min();
126 }
127
128 // Allow conversion to/from any clock with the same interface as
129 // std::chrono::system_clock)
130 template<typename Clock, typename Duration>
131 static time_point to_system_time_point(
132 const std::chrono::time_point<Clock, Duration>& t) {
133 return time_point(seconds(Clock::to_time_t(t)) +
134 std::chrono::duration_cast<duration>(t.time_since_epoch() %
135 std::chrono::seconds(1)));
136 }
137 template<typename Clock, typename Duration>
138 static std::chrono::time_point<Clock, Duration> to_system_time_point(
139 const time_point& t) {
140 return (Clock::from_time_t(to_time_t(t)) +
141 std::chrono::duration_cast<Duration>(t.time_since_epoch() %
142 std::chrono::seconds(1)));
143 }
144
145 static time_t to_time_t(const time_point& t) noexcept {
146 return std::chrono::duration_cast<std::chrono::seconds>(t.time_since_epoch()).count();
147 }
148 static time_point from_time_t(const time_t& t) noexcept {
149 return time_point(std::chrono::seconds(t));
150 }
151
152 static void to_timespec(const time_point& t, struct timespec& ts) {
153 ts.tv_sec = to_time_t(t);
154 ts.tv_nsec = (t.time_since_epoch() % std::chrono::seconds(1)).count();
155 }
156 static struct timespec to_timespec(const time_point& t) {
157 struct timespec ts;
158 to_timespec(t, ts);
159 return ts;
160 }
161 static time_point from_timespec(const struct timespec& ts) {
162 return time_point(std::chrono::seconds(ts.tv_sec) +
163 std::chrono::nanoseconds(ts.tv_nsec));
164 }
165
166 static void to_ceph_timespec(const time_point& t,
167 struct ceph_timespec& ts);
168 static struct ceph_timespec to_ceph_timespec(const time_point& t);
169 static time_point from_ceph_timespec(const struct ceph_timespec& ts);
170
171 static void to_timeval(const time_point& t, struct timeval& tv) {
172 tv.tv_sec = to_time_t(t);
173 tv.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
174 t.time_since_epoch() % std::chrono::seconds(1)).count();
175 }
176 static struct timeval to_timeval(const time_point& t) {
177 struct timeval tv;
178 to_timeval(t, tv);
179 return tv;
180 }
181 static time_point from_timeval(const struct timeval& tv) {
182 return time_point(std::chrono::seconds(tv.tv_sec) +
183 std::chrono::microseconds(tv.tv_usec));
184 }
185
186 static double to_double(const time_point& t) {
187 return std::chrono::duration<double>(t.time_since_epoch()).count();
188 }
189 static time_point from_double(const double d) {
190 return time_point(std::chrono::duration_cast<duration>(
191 std::chrono::duration<double>(d)));
192 }
193};
194
195// Low-resolution but preusmably faster real-time clock
196class coarse_real_clock {
197public:
198 typedef timespan duration;
199 typedef duration::rep rep;
200 typedef duration::period period;
201 // The second template parameter defaults to the clock's duration
202 // type.
203 typedef std::chrono::time_point<coarse_real_clock> time_point;
204 static constexpr const bool is_steady = false;
205
206 static time_point now() noexcept {
207 struct timespec ts;
7c673cae 208#if defined(CLOCK_REALTIME_COARSE)
f67539c2
TL
209 // Linux systems have _COARSE clocks.
210 clock_gettime(CLOCK_REALTIME_COARSE, &ts);
7c673cae 211#elif defined(CLOCK_REALTIME_FAST)
f67539c2
TL
212 // BSD systems have _FAST clocks.
213 clock_gettime(CLOCK_REALTIME_FAST, &ts);
7c673cae 214#else
f67539c2
TL
215 // And if we find neither, you may wish to consult your system's
216 // documentation.
7c673cae 217#warning Falling back to CLOCK_REALTIME, may be slow.
f67539c2 218 clock_gettime(CLOCK_REALTIME, &ts);
7c673cae 219#endif
f67539c2
TL
220 return from_timespec(ts);
221 }
222
223 static bool is_zero(const time_point& t) {
224 return (t == time_point::min());
225 }
226
227 static time_point zero() {
228 return time_point::min();
229 }
230
231 static time_t to_time_t(const time_point& t) noexcept {
232 return std::chrono::duration_cast<std::chrono::seconds>(
233 t.time_since_epoch()).count();
234 }
235 static time_point from_time_t(const time_t t) noexcept {
236 return time_point(std::chrono::seconds(t));
237 }
238
239 static void to_timespec(const time_point& t, struct timespec& ts) {
240 ts.tv_sec = to_time_t(t);
241 ts.tv_nsec = (t.time_since_epoch() % std::chrono::seconds(1)).count();
242 }
243 static struct timespec to_timespec(const time_point& t) {
244 struct timespec ts;
245 to_timespec(t, ts);
246 return ts;
247 }
248 static time_point from_timespec(const struct timespec& ts) {
249 return time_point(std::chrono::seconds(ts.tv_sec) +
250 std::chrono::nanoseconds(ts.tv_nsec));
251 }
252
253 static void to_ceph_timespec(const time_point& t,
254 struct ceph_timespec& ts);
255 static struct ceph_timespec to_ceph_timespec(const time_point& t);
256 static time_point from_ceph_timespec(const struct ceph_timespec& ts);
257
258 static void to_timeval(const time_point& t, struct timeval& tv) {
259 tv.tv_sec = to_time_t(t);
260 tv.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
261 t.time_since_epoch() % std::chrono::seconds(1)).count();
262 }
263 static struct timeval to_timeval(const time_point& t) {
264 struct timeval tv;
265 to_timeval(t, tv);
266 return tv;
267 }
268 static time_point from_timeval(const struct timeval& tv) {
269 return time_point(std::chrono::seconds(tv.tv_sec) +
270 std::chrono::microseconds(tv.tv_usec));
271 }
272
273 static double to_double(const time_point& t) {
274 return std::chrono::duration<double>(t.time_since_epoch()).count();
275 }
276 static time_point from_double(const double d) {
277 return time_point(std::chrono::duration_cast<duration>(
278 std::chrono::duration<double>(d)));
279 }
280};
281
282// High-resolution monotonic clock
283class mono_clock {
284public:
285 typedef timespan duration;
286 typedef duration::rep rep;
287 typedef duration::period period;
288 typedef std::chrono::time_point<mono_clock> time_point;
289 static constexpr const bool is_steady = true;
290
291 static time_point now() noexcept {
292 struct timespec ts;
293 clock_gettime(CLOCK_MONOTONIC, &ts);
294 return time_point(std::chrono::seconds(ts.tv_sec) +
295 std::chrono::nanoseconds(ts.tv_nsec));
296 }
297
298 static bool is_zero(const time_point& t) {
299 return (t == time_point::min());
300 }
301
302 static time_point zero() {
303 return time_point::min();
304 }
305};
306
307// Low-resolution but, I would hope or there's no point, faster
308// monotonic clock
309class coarse_mono_clock {
310public:
311 typedef timespan duration;
312 typedef duration::rep rep;
313 typedef duration::period period;
314 typedef std::chrono::time_point<coarse_mono_clock> time_point;
315 static constexpr const bool is_steady = true;
316
317 static time_point now() noexcept {
318 struct timespec ts;
7c673cae 319#if defined(CLOCK_MONOTONIC_COARSE)
f67539c2
TL
320 // Linux systems have _COARSE clocks.
321 clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
7c673cae 322#elif defined(CLOCK_MONOTONIC_FAST)
f67539c2
TL
323 // BSD systems have _FAST clocks.
324 clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
7c673cae 325#else
f67539c2
TL
326 // And if we find neither, you may wish to consult your system's
327 // documentation.
7c673cae 328#warning Falling back to CLOCK_MONOTONIC, may be slow.
f67539c2 329 clock_gettime(CLOCK_MONOTONIC, &ts);
7c673cae 330#endif
f67539c2
TL
331 return time_point(std::chrono::seconds(ts.tv_sec) +
332 std::chrono::nanoseconds(ts.tv_nsec));
333 }
7c673cae 334
f67539c2
TL
335 static bool is_zero(const time_point& t) {
336 return (t == time_point::min());
337 }
7c673cae 338
f67539c2
TL
339 static time_point zero() {
340 return time_point::min();
341 }
342};
343
344namespace time_detail {
345// So that our subtractions produce negative spans rather than
346// arithmetic underflow.
347template<typename Rep1, typename Period1, typename Rep2,
348 typename Period2>
349inline auto difference(std::chrono::duration<Rep1, Period1> minuend,
350 std::chrono::duration<Rep2, Period2> subtrahend)
351 -> typename std::common_type<
352 std::chrono::duration<typename std::make_signed<Rep1>::type,
353 Period1>,
354 std::chrono::duration<typename std::make_signed<Rep2>::type,
355 Period2> >::type {
356 // Foo.
357 using srep =
358 typename std::common_type<
359 std::chrono::duration<typename std::make_signed<Rep1>::type,
360 Period1>,
361 std::chrono::duration<typename std::make_signed<Rep2>::type,
362 Period2> >::type;
363 return srep(srep(minuend).count() - srep(subtrahend).count());
364}
365
366template<typename Clock, typename Duration1, typename Duration2>
367inline auto difference(
368 typename std::chrono::time_point<Clock, Duration1> minuend,
369 typename std::chrono::time_point<Clock, Duration2> subtrahend)
370 -> typename std::common_type<
371 std::chrono::duration<typename std::make_signed<
372 typename Duration1::rep>::type,
373 typename Duration1::period>,
374 std::chrono::duration<typename std::make_signed<
375 typename Duration2::rep>::type,
376 typename Duration2::period> >::type {
377 return difference(minuend.time_since_epoch(),
378 subtrahend.time_since_epoch());
379}
380}
381
382// Please note that the coarse clocks are disjoint. You cannot
383// subtract a real_clock timepoint from a coarse_real_clock
384// timepoint as, from C++'s perspective, they are disjoint types.
385
386// This is not necessarily bad. If I sample a mono_clock and then a
387// coarse_mono_clock, the coarse_mono_clock's time could potentially
388// be previous to the mono_clock's time (just due to differing
389// resolution) which would be Incorrect.
390
391// This is not horrible, though, since you can use an idiom like
392// mono_clock::timepoint(coarsepoint.time_since_epoch()) to unwrap
393// and rewrap if you know what you're doing.
394
395
396// Actual wall-clock times
397typedef real_clock::time_point real_time;
398typedef coarse_real_clock::time_point coarse_real_time;
399
400// Monotonic times should never be serialized or communicated
401// between machines, since they are incomparable. Thus we also don't
402// make any provision for converting between
403// std::chrono::steady_clock time and ceph::mono_clock time.
404typedef mono_clock::time_point mono_time;
405typedef coarse_mono_clock::time_point coarse_mono_time;
406
407template<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2>
408auto floor(const std::chrono::duration<Rep1, Ratio1>& duration,
409 const std::chrono::duration<Rep2, Ratio2>& precision) ->
410 typename std::common_type<std::chrono::duration<Rep1, Ratio1>,
411 std::chrono::duration<Rep2, Ratio2> >::type {
412 return duration - (duration % precision);
413}
414
415template<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2>
416auto ceil(const std::chrono::duration<Rep1, Ratio1>& duration,
417 const std::chrono::duration<Rep2, Ratio2>& precision) ->
418 typename std::common_type<std::chrono::duration<Rep1, Ratio1>,
419 std::chrono::duration<Rep2, Ratio2> >::type {
420 auto tmod = duration % precision;
421 return duration - tmod + (tmod > tmod.zero() ? 1 : 0) * precision;
422}
423
424template<typename Clock, typename Duration, typename Rep, typename Ratio>
425auto floor(const std::chrono::time_point<Clock, Duration>& timepoint,
426 const std::chrono::duration<Rep, Ratio>& precision) ->
427 std::chrono::time_point<Clock,
428 typename std::common_type<
429 Duration, std::chrono::duration<Rep, Ratio>
430 >::type> {
431 return std::chrono::time_point<
432 Clock, typename std::common_type<
433 Duration, std::chrono::duration<Rep, Ratio> >::type>(
434 floor(timepoint.time_since_epoch(), precision));
435}
436template<typename Clock, typename Duration, typename Rep, typename Ratio>
437auto ceil(const std::chrono::time_point<Clock, Duration>& timepoint,
438 const std::chrono::duration<Rep, Ratio>& precision) ->
439 std::chrono::time_point<Clock,
440 typename std::common_type<
441 Duration,
442 std::chrono::duration<Rep, Ratio> >::type> {
443 return std::chrono::time_point<
444 Clock, typename std::common_type<
445 Duration, std::chrono::duration<Rep, Ratio> >::type>(
446 ceil(timepoint.time_since_epoch(), precision));
447}
448
449inline timespan make_timespan(const double d) {
450 return std::chrono::duration_cast<timespan>(
451 std::chrono::duration<double>(d));
452}
453inline std::optional<timespan> maybe_timespan(const double d) {
454 return d ? std::make_optional(make_timespan(d)) : std::nullopt;
455}
456
457template<typename Clock,
458 typename std::enable_if<!Clock::is_steady>::type* = nullptr>
459std::ostream& operator<<(std::ostream& m,
460 const std::chrono::time_point<Clock>& t);
461template<typename Clock,
462 typename std::enable_if<Clock::is_steady>::type* = nullptr>
463std::ostream& operator<<(std::ostream& m,
464 const std::chrono::time_point<Clock>& t);
465
466// The way std::chrono handles the return type of subtraction is not
467// wonderful. The difference of two unsigned types SHOULD be signed.
468
469inline signedspan operator -(real_time minuend,
470 real_time subtrahend) {
471 return time_detail::difference(minuend, subtrahend);
472}
473
474inline signedspan operator -(coarse_real_time minuend,
475 coarse_real_time subtrahend) {
476 return time_detail::difference(minuend, subtrahend);
477}
478
479inline signedspan operator -(mono_time minuend,
480 mono_time subtrahend) {
481 return time_detail::difference(minuend, subtrahend);
482}
483
484inline signedspan operator -(coarse_mono_time minuend,
485 coarse_mono_time subtrahend) {
486 return time_detail::difference(minuend, subtrahend);
487}
488
489// We could add specializations of time_point - duration and
490// time_point + duration to assert on overflow, but I don't think we
491// should.
11fdf7f2
TL
492inline timespan abs(signedspan z) {
493 return z > signedspan::zero() ?
494 std::chrono::duration_cast<timespan>(z) :
495 timespan(-z.count());
7c673cae 496}
11fdf7f2 497inline timespan to_timespan(signedspan z) {
9f95a23c
TL
498 if (z < signedspan::zero()) {
499 //ceph_assert(z >= signedspan::zero());
500 // There is a kernel bug that seems to be triggering this assert. We've
501 // seen it in:
502 // centos 8.1: 4.18.0-147.el8.x86_64
503 // debian 10.3: 4.19.0-8-amd64
504 // debian 10.1: 4.19.67-2+deb10u1
505 // ubuntu 18.04
506 // see bugs:
507 // https://tracker.ceph.com/issues/43365
508 // https://tracker.ceph.com/issues/44078
509 z = signedspan::zero();
510 }
11fdf7f2 511 return std::chrono::duration_cast<timespan>(z);
7c673cae
FG
512}
513
11fdf7f2
TL
514std::string timespan_str(timespan t);
515std::string exact_timespan_str(timespan t);
516std::chrono::seconds parse_timespan(const std::string& s);
7c673cae 517
11fdf7f2
TL
518// detects presence of Clock::to_timespec() and from_timespec()
519template <typename Clock, typename = std::void_t<>>
520struct converts_to_timespec : std::false_type {};
7c673cae 521
11fdf7f2
TL
522template <typename Clock>
523struct converts_to_timespec<Clock, std::void_t<decltype(
f67539c2
TL
524 Clock::from_timespec(Clock::to_timespec(
525 std::declval<typename Clock::time_point>()))
11fdf7f2 526 )>> : std::true_type {};
7c673cae 527
11fdf7f2
TL
528template <typename Clock>
529constexpr bool converts_to_timespec_v = converts_to_timespec<Clock>::value;
530
9f95a23c
TL
531template<typename Rep, typename T>
532static Rep to_seconds(T t) {
533 return std::chrono::duration_cast<
534 std::chrono::duration<Rep>>(t).count();
535}
536
537template<typename Rep, typename T>
538static Rep to_microseconds(T t) {
539 return std::chrono::duration_cast<
540 std::chrono::duration<
541 Rep,
542 std::micro>>(t).count();
543}
544
11fdf7f2 545} // namespace ceph
7c673cae 546
f67539c2
TL
547namespace std {
548template<typename Rep, typename Period>
549ostream& operator<<(ostream& m, const chrono::duration<Rep, Period>& t);
550}
551
1e59de90
TL
552#if FMT_VERSION >= 90000
553template<typename Clock>
554struct fmt::formatter<std::chrono::time_point<Clock>> : fmt::ostream_formatter {};
555#endif
556
7c673cae 557#endif // COMMON_CEPH_TIME_H