]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/ceph_time.h
update sources to v12.1.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>
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
243 // A monotonic clock's timepoints are only meaningful to the
244 // computer on which they were generated. Thus having an
245 // optional skew is meaningless.
246 };
247
248 class coarse_mono_clock {
249 public:
250 typedef timespan duration;
251 typedef duration::rep rep;
252 typedef duration::period period;
253 typedef std::chrono::time_point<coarse_mono_clock> time_point;
254 static constexpr const bool is_steady = true;
255
256 static time_point now() noexcept {
257 struct timespec ts;
258#if defined(CLOCK_MONOTONIC_COARSE)
259 // Linux systems have _COARSE clocks.
260 clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
261#elif defined(CLOCK_MONOTONIC_FAST)
262 // BSD systems have _FAST clocks.
263 clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
264#else
265 // And if we find neither, you may wish to consult your system's
266 // documentation.
267#warning Falling back to CLOCK_MONOTONIC, may be slow.
268 clock_gettime(CLOCK_MONOTONIC, &ts);
269#endif
270 return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec));
271 }
272 };
273
274 // So that our subtractions produce negative spans rather than
275 // arithmetic underflow.
276 namespace {
277 template<typename Rep1, typename Period1, typename Rep2,
278 typename Period2>
279 inline auto difference(std::chrono::duration<Rep1, Period1> minuend,
280 std::chrono::duration<Rep2, Period2> subtrahend)
281 -> typename std::common_type<
282 std::chrono::duration<typename std::make_signed<Rep1>::type,
283 Period1>,
284 std::chrono::duration<typename std::make_signed<Rep2>::type,
285 Period2> >::type {
286 // Foo.
287 using srep =
288 typename std::common_type<
289 std::chrono::duration<typename std::make_signed<Rep1>::type,
290 Period1>,
291 std::chrono::duration<typename std::make_signed<Rep2>::type,
292 Period2> >::type;
293 return srep(srep(minuend).count() - srep(subtrahend).count());
294 }
295
296 template<typename Clock, typename Duration1, typename Duration2>
297 inline auto difference(
298 typename std::chrono::time_point<Clock, Duration1> minuend,
299 typename std::chrono::time_point<Clock, Duration2> subtrahend)
300 -> typename std::common_type<
301 std::chrono::duration<typename std::make_signed<
302 typename Duration1::rep>::type,
303 typename Duration1::period>,
304 std::chrono::duration<typename std::make_signed<
305 typename Duration2::rep>::type,
306 typename Duration2::period> >::type {
307 return difference(minuend.time_since_epoch(),
308 subtrahend.time_since_epoch());
309 }
310 }
311 } // namespace time_detail
312
313 // duration is the concrete time representation for our code in the
314 // case that we are only interested in durations between now and the
315 // future. Using it means we don't have to have EVERY function that
316 // deals with a duration be a template. We can do so for user-facing
317 // APIs, however.
318 using time_detail::timespan;
319
320 // Similar to the above but for durations that can specify
321 // differences between now and a time point in the past.
322 using time_detail::signedspan;
323
324 // High-resolution real-time clock
325 using time_detail::real_clock;
326
327 // Low-resolution but preusmably faster real-time clock
328 using time_detail::coarse_real_clock;
329
330
331 // High-resolution monotonic clock
332 using time_detail::mono_clock;
333
334 // Low-resolution but, I would hope or there's no point, faster
335 // monotonic clock
336 using time_detail::coarse_mono_clock;
337
338 // Please note that the coarse clocks are disjoint. You cannot
339 // subtract a real_clock timepoint from a coarse_real_clock
340 // timepoint as, from C++'s perspective, they are disjoint types.
341
342 // This is not necessarily bad. If I sample a mono_clock and then a
343 // coarse_mono_clock, the coarse_mono_clock's time could potentially
344 // be previous to the mono_clock's time (just due to differing
345 // resolution) which would be Incorrect.
346
347 // This is not horrible, though, since you can use an idiom like
348 // mono_clock::timepoint(coarsepoint.time_since_epoch()) to unwrap
349 // and rewrap if you know what you're doing.
350
351
352 // Actual wall-clock times
353 typedef real_clock::time_point real_time;
354 typedef coarse_real_clock::time_point coarse_real_time;
355
356 // Monotonic times should never be serialized or communicated
357 // between machines, since they are incomparable. Thus we also don't
358 // make any provision for converting between
359 // std::chrono::steady_clock time and ceph::mono_clock time.
360 typedef mono_clock::time_point mono_time;
361 typedef coarse_mono_clock::time_point coarse_mono_time;
362
363 template<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2>
364 auto floor(const std::chrono::duration<Rep1, Ratio1>& duration,
365 const std::chrono::duration<Rep2, Ratio2>& precision) ->
366 typename std::common_type<std::chrono::duration<Rep1, Ratio1>,
367 std::chrono::duration<Rep2, Ratio2> >::type {
368 return duration - (duration % precision);
369 }
370
371 template<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2>
372 auto ceil(const std::chrono::duration<Rep1, Ratio1>& duration,
373 const std::chrono::duration<Rep2, Ratio2>& precision) ->
374 typename std::common_type<std::chrono::duration<Rep1, Ratio1>,
375 std::chrono::duration<Rep2, Ratio2> >::type {
376 auto tmod = duration % precision;
377 return duration - tmod + (tmod > tmod.zero() ? 1 : 0) * precision;
378 }
379
380 template<typename Clock, typename Duration, typename Rep, typename Ratio>
381 auto floor(const std::chrono::time_point<Clock, Duration>& timepoint,
382 const std::chrono::duration<Rep, Ratio>& precision) ->
383 std::chrono::time_point<Clock,
384 typename std::common_type<
385 Duration, std::chrono::duration<Rep, Ratio>
386 >::type> {
387 return std::chrono::time_point<
388 Clock, typename std::common_type<
389 Duration, std::chrono::duration<Rep, Ratio> >::type>(
390 floor(timepoint.time_since_epoch(), precision));
391 }
392 template<typename Clock, typename Duration, typename Rep, typename Ratio>
393 auto ceil(const std::chrono::time_point<Clock, Duration>& timepoint,
394 const std::chrono::duration<Rep, Ratio>& precision) ->
395 std::chrono::time_point<Clock,
396 typename std::common_type<
397 Duration,
398 std::chrono::duration<Rep, Ratio> >::type> {
399 return std::chrono::time_point<
400 Clock, typename std::common_type<
401 Duration, std::chrono::duration<Rep, Ratio> >::type>(
402 ceil(timepoint.time_since_epoch(), precision));
403 }
404
405 namespace {
406 inline timespan make_timespan(const double d) {
407 return std::chrono::duration_cast<timespan>(
408 std::chrono::duration<double>(d));
409 }
410 }
411
412 std::ostream& operator<<(std::ostream& m, const timespan& t);
413 template<typename Clock,
414 typename std::enable_if<!Clock::is_steady>::type* = nullptr>
415 std::ostream& operator<<(std::ostream& m,
416 const std::chrono::time_point<Clock>& 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
422 // The way std::chrono handles the return type of subtraction is not
423 // wonderful. The difference of two unsigned types SHOULD be signed.
424
425 namespace {
426 inline signedspan operator -(real_time minuend,
427 real_time subtrahend) {
428 return time_detail::difference(minuend, subtrahend);
429 }
430
431 inline signedspan operator -(coarse_real_time minuend,
432 coarse_real_time subtrahend) {
433 return time_detail::difference(minuend, subtrahend);
434 }
435
436 inline signedspan operator -(mono_time minuend,
437 mono_time subtrahend) {
438 return time_detail::difference(minuend, subtrahend);
439 }
440
441 inline signedspan operator -(coarse_mono_time minuend,
442 coarse_mono_time subtrahend) {
443 return time_detail::difference(minuend, subtrahend);
444 }
445 }
446
447 // We could add specializations of time_point - duration and
448 // time_point + duration to assert on overflow, but I don't think we
449 // should.
450
451} // namespace ceph
452
453// We need these definitions to be able to hande ::encode/::decode on
454// time points.
455
456template<typename Clock, typename Duration>
457void encode(const std::chrono::time_point<Clock, Duration>& t,
458 ceph::bufferlist &bl) {
459 auto ts = Clock::to_timespec(t);
460 // A 32 bit count of seconds causes me vast unhappiness.
461 uint32_t s = ts.tv_sec;
462 uint32_t ns = ts.tv_nsec;
463 ::encode(s, bl);
464 ::encode(ns, bl);
465}
466
467template<typename Clock, typename Duration>
468void decode(std::chrono::time_point<Clock, Duration>& t,
469 bufferlist::iterator& p) {
470 uint32_t s;
471 uint32_t ns;
472 ::decode(s, p);
473 ::decode(ns, p);
474 struct timespec ts = {
475 static_cast<time_t>(s),
476 static_cast<long int>(ns)};
477
478 t = Clock::from_timespec(ts);
479}
480
481// C++ Overload Resolution requires that our encode/decode functions
482// be defined in the same namespace as the type. So we need this
483// to handle things like ::encode(std::vector<ceph::real_time // > >)
484
485namespace std {
486 namespace chrono {
487 template<typename Clock, typename Duration>
488 void encode(const time_point<Clock, Duration>& t,
489 ceph::bufferlist &bl) {
490 ::encode(t, bl);
491 }
492
493 template<typename Clock, typename Duration>
494 void decode(time_point<Clock, Duration>& t, bufferlist::iterator &p) {
495 ::decode(t, p);
496 }
497 } // namespace chrono
498
499 // An overload of our own
500 namespace {
501 inline timespan abs(signedspan z) {
502 return z > signedspan::zero() ?
503 std::chrono::duration_cast<timespan>(z) :
504 timespan(-z.count());
505 }
506 }
507} // namespace std
508
509#endif // COMMON_CEPH_TIME_H