]>
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> | |
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 | ||
32 | int clock_gettime(int clk_id, struct timespec *tp); | |
33 | #endif | |
34 | ||
35 | struct ceph_timespec; | |
36 | ||
37 | namespace 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 | ||
460 | template<typename Clock, typename Duration> | |
461 | void 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 | ||
471 | template<typename Clock, typename Duration> | |
472 | void 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 | ||
489 | namespace 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 |