]>
Commit | Line | Data |
---|---|---|
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 | ||
33 | int 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 |
55 | struct ceph_timespec; |
56 | ||
57 | namespace 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. | |
65 | typedef 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. | |
73 | typedef std::chrono::duration<rep, std::nano> timespan; | |
74 | ||
75 | ||
76 | // Like the above but signed. | |
77 | typedef 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. | |
81 | typedef std::chrono::duration<signed_rep, std::nano> signedspan; | |
82 | ||
83 | template<typename Duration> | |
84 | struct 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 | |
104 | class real_clock { | |
105 | public: | |
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 | |
196 | class coarse_real_clock { | |
197 | public: | |
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 | |
283 | class mono_clock { | |
284 | public: | |
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 | |
309 | class coarse_mono_clock { | |
310 | public: | |
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 | ||
344 | namespace time_detail { | |
345 | // So that our subtractions produce negative spans rather than | |
346 | // arithmetic underflow. | |
347 | template<typename Rep1, typename Period1, typename Rep2, | |
348 | typename Period2> | |
349 | inline 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 | ||
366 | template<typename Clock, typename Duration1, typename Duration2> | |
367 | inline 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 | |
397 | typedef real_clock::time_point real_time; | |
398 | typedef 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. | |
404 | typedef mono_clock::time_point mono_time; | |
405 | typedef coarse_mono_clock::time_point coarse_mono_time; | |
406 | ||
407 | template<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2> | |
408 | auto 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 | ||
415 | template<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2> | |
416 | auto 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 | ||
424 | template<typename Clock, typename Duration, typename Rep, typename Ratio> | |
425 | auto 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 | } | |
436 | template<typename Clock, typename Duration, typename Rep, typename Ratio> | |
437 | auto 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 | ||
449 | inline timespan make_timespan(const double d) { | |
450 | return std::chrono::duration_cast<timespan>( | |
451 | std::chrono::duration<double>(d)); | |
452 | } | |
453 | inline std::optional<timespan> maybe_timespan(const double d) { | |
454 | return d ? std::make_optional(make_timespan(d)) : std::nullopt; | |
455 | } | |
456 | ||
457 | template<typename Clock, | |
458 | typename std::enable_if<!Clock::is_steady>::type* = nullptr> | |
459 | std::ostream& operator<<(std::ostream& m, | |
460 | const std::chrono::time_point<Clock>& t); | |
461 | template<typename Clock, | |
462 | typename std::enable_if<Clock::is_steady>::type* = nullptr> | |
463 | std::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 | ||
469 | inline signedspan operator -(real_time minuend, | |
470 | real_time subtrahend) { | |
471 | return time_detail::difference(minuend, subtrahend); | |
472 | } | |
473 | ||
474 | inline signedspan operator -(coarse_real_time minuend, | |
475 | coarse_real_time subtrahend) { | |
476 | return time_detail::difference(minuend, subtrahend); | |
477 | } | |
478 | ||
479 | inline signedspan operator -(mono_time minuend, | |
480 | mono_time subtrahend) { | |
481 | return time_detail::difference(minuend, subtrahend); | |
482 | } | |
483 | ||
484 | inline 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 |
492 | inline timespan abs(signedspan z) { |
493 | return z > signedspan::zero() ? | |
494 | std::chrono::duration_cast<timespan>(z) : | |
495 | timespan(-z.count()); | |
7c673cae | 496 | } |
11fdf7f2 | 497 | inline 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 |
514 | std::string timespan_str(timespan t); |
515 | std::string exact_timespan_str(timespan t); | |
516 | std::chrono::seconds parse_timespan(const std::string& s); | |
7c673cae | 517 | |
11fdf7f2 TL |
518 | // detects presence of Clock::to_timespec() and from_timespec() |
519 | template <typename Clock, typename = std::void_t<>> | |
520 | struct converts_to_timespec : std::false_type {}; | |
7c673cae | 521 | |
11fdf7f2 TL |
522 | template <typename Clock> |
523 | struct 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 |
528 | template <typename Clock> |
529 | constexpr bool converts_to_timespec_v = converts_to_timespec<Clock>::value; | |
530 | ||
9f95a23c TL |
531 | template<typename Rep, typename T> |
532 | static Rep to_seconds(T t) { | |
533 | return std::chrono::duration_cast< | |
534 | std::chrono::duration<Rep>>(t).count(); | |
535 | } | |
536 | ||
537 | template<typename Rep, typename T> | |
538 | static 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 |
547 | namespace std { |
548 | template<typename Rep, typename Period> | |
549 | ostream& operator<<(ostream& m, const chrono::duration<Rep, Period>& t); | |
550 | } | |
551 | ||
1e59de90 TL |
552 | #if FMT_VERSION >= 90000 |
553 | template<typename Clock> | |
554 | struct fmt::formatter<std::chrono::time_point<Clock>> : fmt::ostream_formatter {}; | |
555 | #endif | |
556 | ||
7c673cae | 557 | #endif // COMMON_CEPH_TIME_H |