]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/ceph_time.h
import ceph 16.2.7
[ceph.git] / ceph / src / common / ceph_time.h
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>
19 #include <iostream>
20 #include <string>
21 #include <optional>
22 #include <sys/time.h>
23
24 #if defined(__APPLE__)
25 #include <sys/_types/_timespec.h>
26
27 #define CLOCK_REALTIME_COARSE CLOCK_REALTIME
28 #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
29
30 int clock_gettime(int clk_id, struct timespec *tp);
31 #endif
32
33 #ifdef _WIN32
34 #define CLOCK_REALTIME_COARSE CLOCK_REALTIME
35 #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
36 // MINGW uses the QueryPerformanceCounter API behind the scenes.
37 #endif
38
39 struct ceph_timespec;
40
41 namespace ceph {
42 // Currently we use a 64-bit count of nanoseconds.
43
44 // We could, if we wished, use a struct holding a uint64_t count
45 // of seconds and a uint32_t count of nanoseconds.
46
47 // At least this way we can change it to something else if we
48 // want.
49 typedef uint64_t rep;
50
51
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
56 // APIs, however.
57 typedef std::chrono::duration<rep, std::nano> timespan;
58
59
60 // Like the above but signed.
61 typedef int64_t signed_rep;
62
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;
66
67 template<typename Duration>
68 struct timeval to_timeval(Duration d) {
69 struct timeval tv;
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();
74 return tv;
75 }
76
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
81 // resolution.)
82
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.
86
87 // High-resolution real-time clock
88 class real_clock {
89 public:
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
94 // type.
95 typedef std::chrono::time_point<real_clock> time_point;
96 static constexpr const bool is_steady = false;
97
98 static time_point now() noexcept {
99 struct timespec ts;
100 clock_gettime(CLOCK_REALTIME, &ts);
101 return from_timespec(ts);
102 }
103
104 static bool is_zero(const time_point& t) {
105 return (t == time_point::min());
106 }
107
108 static time_point zero() {
109 return time_point::min();
110 }
111
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)));
120 }
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)));
127 }
128
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();
131 }
132 static time_point from_time_t(const time_t& t) noexcept {
133 return time_point(std::chrono::seconds(t));
134 }
135
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();
139 }
140 static struct timespec to_timespec(const time_point& t) {
141 struct timespec ts;
142 to_timespec(t, ts);
143 return ts;
144 }
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));
148 }
149
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);
154
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();
159 }
160 static struct timeval to_timeval(const time_point& t) {
161 struct timeval tv;
162 to_timeval(t, tv);
163 return tv;
164 }
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));
168 }
169
170 static double to_double(const time_point& t) {
171 return std::chrono::duration<double>(t.time_since_epoch()).count();
172 }
173 static time_point from_double(const double d) {
174 return time_point(std::chrono::duration_cast<duration>(
175 std::chrono::duration<double>(d)));
176 }
177 };
178
179 // Low-resolution but preusmably faster real-time clock
180 class coarse_real_clock {
181 public:
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
186 // type.
187 typedef std::chrono::time_point<coarse_real_clock> time_point;
188 static constexpr const bool is_steady = false;
189
190 static time_point now() noexcept {
191 struct timespec ts;
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);
198 #else
199 // And if we find neither, you may wish to consult your system's
200 // documentation.
201 #warning Falling back to CLOCK_REALTIME, may be slow.
202 clock_gettime(CLOCK_REALTIME, &ts);
203 #endif
204 return from_timespec(ts);
205 }
206
207 static bool is_zero(const time_point& t) {
208 return (t == time_point::min());
209 }
210
211 static time_point zero() {
212 return time_point::min();
213 }
214
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();
218 }
219 static time_point from_time_t(const time_t t) noexcept {
220 return time_point(std::chrono::seconds(t));
221 }
222
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();
226 }
227 static struct timespec to_timespec(const time_point& t) {
228 struct timespec ts;
229 to_timespec(t, ts);
230 return ts;
231 }
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));
235 }
236
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);
241
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();
246 }
247 static struct timeval to_timeval(const time_point& t) {
248 struct timeval tv;
249 to_timeval(t, tv);
250 return tv;
251 }
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));
255 }
256
257 static double to_double(const time_point& t) {
258 return std::chrono::duration<double>(t.time_since_epoch()).count();
259 }
260 static time_point from_double(const double d) {
261 return time_point(std::chrono::duration_cast<duration>(
262 std::chrono::duration<double>(d)));
263 }
264 };
265
266 // High-resolution monotonic clock
267 class mono_clock {
268 public:
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;
274
275 static time_point now() noexcept {
276 struct timespec ts;
277 clock_gettime(CLOCK_MONOTONIC, &ts);
278 return time_point(std::chrono::seconds(ts.tv_sec) +
279 std::chrono::nanoseconds(ts.tv_nsec));
280 }
281
282 static bool is_zero(const time_point& t) {
283 return (t == time_point::min());
284 }
285
286 static time_point zero() {
287 return time_point::min();
288 }
289 };
290
291 // Low-resolution but, I would hope or there's no point, faster
292 // monotonic clock
293 class coarse_mono_clock {
294 public:
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;
300
301 static time_point now() noexcept {
302 struct timespec ts;
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);
309 #else
310 // And if we find neither, you may wish to consult your system's
311 // documentation.
312 #warning Falling back to CLOCK_MONOTONIC, may be slow.
313 clock_gettime(CLOCK_MONOTONIC, &ts);
314 #endif
315 return time_point(std::chrono::seconds(ts.tv_sec) +
316 std::chrono::nanoseconds(ts.tv_nsec));
317 }
318
319 static bool is_zero(const time_point& t) {
320 return (t == time_point::min());
321 }
322
323 static time_point zero() {
324 return time_point::min();
325 }
326 };
327
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,
332 typename Period2>
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,
337 Period1>,
338 std::chrono::duration<typename std::make_signed<Rep2>::type,
339 Period2> >::type {
340 // Foo.
341 using srep =
342 typename std::common_type<
343 std::chrono::duration<typename std::make_signed<Rep1>::type,
344 Period1>,
345 std::chrono::duration<typename std::make_signed<Rep2>::type,
346 Period2> >::type;
347 return srep(srep(minuend).count() - srep(subtrahend).count());
348 }
349
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());
363 }
364 }
365
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.
369
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.
374
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.
378
379
380 // Actual wall-clock times
381 typedef real_clock::time_point real_time;
382 typedef coarse_real_clock::time_point coarse_real_time;
383
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;
390
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);
397 }
398
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;
406 }
407
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>
414 >::type> {
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));
419 }
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<
425 Duration,
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));
431 }
432
433 inline timespan make_timespan(const double d) {
434 return std::chrono::duration_cast<timespan>(
435 std::chrono::duration<double>(d));
436 }
437 inline std::optional<timespan> maybe_timespan(const double d) {
438 return d ? std::make_optional(make_timespan(d)) : std::nullopt;
439 }
440
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);
449
450 // The way std::chrono handles the return type of subtraction is not
451 // wonderful. The difference of two unsigned types SHOULD be signed.
452
453 inline signedspan operator -(real_time minuend,
454 real_time subtrahend) {
455 return time_detail::difference(minuend, subtrahend);
456 }
457
458 inline signedspan operator -(coarse_real_time minuend,
459 coarse_real_time subtrahend) {
460 return time_detail::difference(minuend, subtrahend);
461 }
462
463 inline signedspan operator -(mono_time minuend,
464 mono_time subtrahend) {
465 return time_detail::difference(minuend, subtrahend);
466 }
467
468 inline signedspan operator -(coarse_mono_time minuend,
469 coarse_mono_time subtrahend) {
470 return time_detail::difference(minuend, subtrahend);
471 }
472
473 // We could add specializations of time_point - duration and
474 // time_point + duration to assert on overflow, but I don't think we
475 // should.
476 inline timespan abs(signedspan z) {
477 return z > signedspan::zero() ?
478 std::chrono::duration_cast<timespan>(z) :
479 timespan(-z.count());
480 }
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
485 // seen it in:
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
489 // ubuntu 18.04
490 // see bugs:
491 // https://tracker.ceph.com/issues/43365
492 // https://tracker.ceph.com/issues/44078
493 z = signedspan::zero();
494 }
495 return std::chrono::duration_cast<timespan>(z);
496 }
497
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);
501
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 {};
505
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 {};
511
512 template <typename Clock>
513 constexpr bool converts_to_timespec_v = converts_to_timespec<Clock>::value;
514
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();
519 }
520
521 template<typename Rep, typename T>
522 static Rep to_microseconds(T t) {
523 return std::chrono::duration_cast<
524 std::chrono::duration<
525 Rep,
526 std::micro>>(t).count();
527 }
528
529 } // namespace ceph
530
531 namespace std {
532 template<typename Rep, typename Period>
533 ostream& operator<<(ostream& m, const chrono::duration<Rep, Period>& t);
534 }
535
536 #endif // COMMON_CEPH_TIME_H