// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef COMMON_CEPH_TIME_H #define COMMON_CEPH_TIME_H #include #include "include/encoding.h" #if defined(DARWIN) #include #include #include #define CLOCK_REALTIME CALENDAR_CLOCK #define CLOCK_MONOTONIC SYSTEM_CLOCK #define CLOCK_REALTIME_COARSE CLOCK_REALTIME #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC int clock_gettime(int clk_id, struct timespec *tp); #endif struct ceph_timespec; namespace ceph { namespace time_detail { using std::chrono::duration_cast; using std::chrono::seconds; using std::chrono::microseconds; using std::chrono::nanoseconds; // Currently we use a 64-bit count of nanoseconds. // We could, if we wished, use a struct holding a uint64_t count // of seconds and a uint32_t count of nanoseconds. // At least this way we can change it to something else if we // want. typedef uint64_t rep; // A concrete duration, unsigned. The timespan Ceph thinks in. typedef std::chrono::duration timespan; // Like the above but signed. typedef int64_t signed_rep; typedef std::chrono::duration signedspan; // We define our own clocks so we can have our choice of all time // sources supported by the operating system. With the standard // library the resolution and cost are unspecified. (For example, // the libc++ system_clock class gives only microsecond // resolution.) // One potential issue is that we should accept system_clock // timepoints in user-facing APIs alongside (or instead of) // ceph::real_clock times. class real_clock { public: typedef timespan duration; typedef duration::rep rep; typedef duration::period period; // The second template parameter defaults to the clock's duration // type. typedef std::chrono::time_point time_point; static constexpr const bool is_steady = false; static time_point now() noexcept { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); return from_timespec(ts); } static bool is_zero(const time_point& t) { return (t == time_point::min()); } // Allow conversion to/from any clock with the same interface as // std::chrono::system_clock) template static time_point to_system_time_point( const std::chrono::time_point& t) { return time_point(seconds(Clock::to_time_t(t)) + duration_cast(t.time_since_epoch() % seconds(1))); } template static std::chrono::time_point to_system_time_point( const time_point& t) { return (Clock::from_time_t(to_time_t(t)) + duration_cast(t.time_since_epoch() % seconds(1))); } static time_t to_time_t(const time_point& t) noexcept { return duration_cast(t.time_since_epoch()).count(); } static time_point from_time_t(const time_t& t) noexcept { return time_point(seconds(t)); } static void to_timespec(const time_point& t, struct timespec& ts) { ts.tv_sec = to_time_t(t); ts.tv_nsec = (t.time_since_epoch() % seconds(1)).count(); } static struct timespec to_timespec(const time_point& t) { struct timespec ts; to_timespec(t, ts); return ts; } static time_point from_timespec(const struct timespec& ts) { return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec)); } static void to_ceph_timespec(const time_point& t, struct ceph_timespec& ts); static struct ceph_timespec to_ceph_timespec(const time_point& t); static time_point from_ceph_timespec(const struct ceph_timespec& ts); static void to_timeval(const time_point& t, struct timeval& tv) { tv.tv_sec = to_time_t(t); tv.tv_usec = duration_cast(t.time_since_epoch() % seconds(1)).count(); } static struct timeval to_timeval(const time_point& t) { struct timeval tv; to_timeval(t, tv); return tv; } static time_point from_timeval(const struct timeval& tv) { return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec)); } static double to_double(const time_point& t) { return std::chrono::duration(t.time_since_epoch()).count(); } static time_point from_double(const double d) { return time_point(duration_cast( std::chrono::duration(d))); } }; class coarse_real_clock { public: typedef timespan duration; typedef duration::rep rep; typedef duration::period period; // The second template parameter defaults to the clock's duration // type. typedef std::chrono::time_point time_point; static constexpr const bool is_steady = false; static time_point now() noexcept { struct timespec ts; #if defined(CLOCK_REALTIME_COARSE) // Linux systems have _COARSE clocks. clock_gettime(CLOCK_REALTIME_COARSE, &ts); #elif defined(CLOCK_REALTIME_FAST) // BSD systems have _FAST clocks. clock_gettime(CLOCK_REALTIME_FAST, &ts); #else // And if we find neither, you may wish to consult your system's // documentation. #warning Falling back to CLOCK_REALTIME, may be slow. clock_gettime(CLOCK_REALTIME, &ts); #endif return from_timespec(ts); } static time_t to_time_t(const time_point& t) noexcept { return duration_cast(t.time_since_epoch()).count(); } static time_point from_time_t(const time_t t) noexcept { return time_point(seconds(t)); } static void to_timespec(const time_point& t, struct timespec& ts) { ts.tv_sec = to_time_t(t); ts.tv_nsec = (t.time_since_epoch() % seconds(1)).count(); } static struct timespec to_timespec(const time_point& t) { struct timespec ts; to_timespec(t, ts); return ts; } static time_point from_timespec(const struct timespec& ts) { return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec)); } static void to_ceph_timespec(const time_point& t, struct ceph_timespec& ts); static struct ceph_timespec to_ceph_timespec(const time_point& t); static time_point from_ceph_timespec(const struct ceph_timespec& ts); static void to_timeval(const time_point& t, struct timeval& tv) { tv.tv_sec = to_time_t(t); tv.tv_usec = duration_cast(t.time_since_epoch() % seconds(1)).count(); } static struct timeval to_timeval(const time_point& t) { struct timeval tv; to_timeval(t, tv); return tv; } static time_point from_timeval(const struct timeval& tv) { return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec)); } static double to_double(const time_point& t) { return std::chrono::duration(t.time_since_epoch()).count(); } static time_point from_double(const double d) { return time_point(duration_cast( std::chrono::duration(d))); } }; class mono_clock { public: typedef timespan duration; typedef duration::rep rep; typedef duration::period period; typedef std::chrono::time_point time_point; static constexpr const bool is_steady = true; static time_point now() noexcept { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec)); } // A monotonic clock's timepoints are only meaningful to the // computer on which they were generated. Thus having an // optional skew is meaningless. }; class coarse_mono_clock { public: typedef timespan duration; typedef duration::rep rep; typedef duration::period period; typedef std::chrono::time_point time_point; static constexpr const bool is_steady = true; static time_point now() noexcept { struct timespec ts; #if defined(CLOCK_MONOTONIC_COARSE) // Linux systems have _COARSE clocks. clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); #elif defined(CLOCK_MONOTONIC_FAST) // BSD systems have _FAST clocks. clock_gettime(CLOCK_MONOTONIC_FAST, &ts); #else // And if we find neither, you may wish to consult your system's // documentation. #warning Falling back to CLOCK_MONOTONIC, may be slow. clock_gettime(CLOCK_MONOTONIC, &ts); #endif return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec)); } }; // So that our subtractions produce negative spans rather than // arithmetic underflow. namespace { template inline auto difference(std::chrono::duration minuend, std::chrono::duration subtrahend) -> typename std::common_type< std::chrono::duration::type, Period1>, std::chrono::duration::type, Period2> >::type { // Foo. using srep = typename std::common_type< std::chrono::duration::type, Period1>, std::chrono::duration::type, Period2> >::type; return srep(srep(minuend).count() - srep(subtrahend).count()); } template inline auto difference( typename std::chrono::time_point minuend, typename std::chrono::time_point subtrahend) -> typename std::common_type< std::chrono::duration::type, typename Duration1::period>, std::chrono::duration::type, typename Duration2::period> >::type { return difference(minuend.time_since_epoch(), subtrahend.time_since_epoch()); } } } // namespace time_detail // duration is the concrete time representation for our code in the // case that we are only interested in durations between now and the // future. Using it means we don't have to have EVERY function that // deals with a duration be a template. We can do so for user-facing // APIs, however. using time_detail::timespan; // Similar to the above but for durations that can specify // differences between now and a time point in the past. using time_detail::signedspan; // High-resolution real-time clock using time_detail::real_clock; // Low-resolution but preusmably faster real-time clock using time_detail::coarse_real_clock; // High-resolution monotonic clock using time_detail::mono_clock; // Low-resolution but, I would hope or there's no point, faster // monotonic clock using time_detail::coarse_mono_clock; // Please note that the coarse clocks are disjoint. You cannot // subtract a real_clock timepoint from a coarse_real_clock // timepoint as, from C++'s perspective, they are disjoint types. // This is not necessarily bad. If I sample a mono_clock and then a // coarse_mono_clock, the coarse_mono_clock's time could potentially // be previous to the mono_clock's time (just due to differing // resolution) which would be Incorrect. // This is not horrible, though, since you can use an idiom like // mono_clock::timepoint(coarsepoint.time_since_epoch()) to unwrap // and rewrap if you know what you're doing. // Actual wall-clock times typedef real_clock::time_point real_time; typedef coarse_real_clock::time_point coarse_real_time; // Monotonic times should never be serialized or communicated // between machines, since they are incomparable. Thus we also don't // make any provision for converting between // std::chrono::steady_clock time and ceph::mono_clock time. typedef mono_clock::time_point mono_time; typedef coarse_mono_clock::time_point coarse_mono_time; template auto floor(const std::chrono::duration& duration, const std::chrono::duration& precision) -> typename std::common_type, std::chrono::duration >::type { return duration - (duration % precision); } template auto ceil(const std::chrono::duration& duration, const std::chrono::duration& precision) -> typename std::common_type, std::chrono::duration >::type { auto tmod = duration % precision; return duration - tmod + (tmod > tmod.zero() ? 1 : 0) * precision; } template auto floor(const std::chrono::time_point& timepoint, const std::chrono::duration& precision) -> std::chrono::time_point >::type> { return std::chrono::time_point< Clock, typename std::common_type< Duration, std::chrono::duration >::type>( floor(timepoint.time_since_epoch(), precision)); } template auto ceil(const std::chrono::time_point& timepoint, const std::chrono::duration& precision) -> std::chrono::time_point >::type> { return std::chrono::time_point< Clock, typename std::common_type< Duration, std::chrono::duration >::type>( ceil(timepoint.time_since_epoch(), precision)); } namespace { inline timespan make_timespan(const double d) { return std::chrono::duration_cast( std::chrono::duration(d)); } } std::ostream& operator<<(std::ostream& m, const timespan& t); template::type* = nullptr> std::ostream& operator<<(std::ostream& m, const std::chrono::time_point& t); template::type* = nullptr> std::ostream& operator<<(std::ostream& m, const std::chrono::time_point& t); // The way std::chrono handles the return type of subtraction is not // wonderful. The difference of two unsigned types SHOULD be signed. namespace { inline signedspan operator -(real_time minuend, real_time subtrahend) { return time_detail::difference(minuend, subtrahend); } inline signedspan operator -(coarse_real_time minuend, coarse_real_time subtrahend) { return time_detail::difference(minuend, subtrahend); } inline signedspan operator -(mono_time minuend, mono_time subtrahend) { return time_detail::difference(minuend, subtrahend); } inline signedspan operator -(coarse_mono_time minuend, coarse_mono_time subtrahend) { return time_detail::difference(minuend, subtrahend); } } // We could add specializations of time_point - duration and // time_point + duration to assert on overflow, but I don't think we // should. } // namespace ceph // We need these definitions to be able to hande ::encode/::decode on // time points. template void encode(const std::chrono::time_point& t, ceph::bufferlist &bl) { auto ts = Clock::to_timespec(t); // A 32 bit count of seconds causes me vast unhappiness. uint32_t s = ts.tv_sec; uint32_t ns = ts.tv_nsec; ::encode(s, bl); ::encode(ns, bl); } template void decode(std::chrono::time_point& t, bufferlist::iterator& p) { uint32_t s; uint32_t ns; ::decode(s, p); ::decode(ns, p); struct timespec ts = { static_cast(s), static_cast(ns)}; t = Clock::from_timespec(ts); } // C++ Overload Resolution requires that our encode/decode functions // be defined in the same namespace as the type. So we need this // to handle things like ::encode(std::vector >) namespace std { namespace chrono { template void encode(const time_point& t, ceph::bufferlist &bl) { ::encode(t, bl); } template void decode(time_point& t, bufferlist::iterator &p) { ::decode(t, p); } } // namespace chrono // An overload of our own namespace { inline timespan abs(signedspan z) { return z > signedspan::zero() ? std::chrono::duration_cast(z) : timespan(-z.count()); } } } // namespace std #endif // COMMON_CEPH_TIME_H