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