From: Kefu Chai Date: Thu, 7 Jan 2021 07:17:45 +0000 (+0800) Subject: common/ceph_time: move operator<<(ostream&, timespan&) into std namespace X-Git-Tag: v15.2.17~64^2~4 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=8543e24f1c681627e3670ec884aa41efa319c3c1;p=ceph.git common/ceph_time: move operator<<(ostream&, timespan&) into std namespace otherwise compiler is not able to find it as the "timespan" here is actually a class defined in std namespace, even it has an alias defined in ceph namespace like: typedef std::chrono::duration timespan; but this does not make it a member of "ceph" namespace. for more details on the lookup rules, see https://en.cppreference.com/w/cpp/language/adl Signed-off-by: Kefu Chai (cherry picked from commit 75aafcba888a5753d2a4a8378637b4bb9fad5dd0) --- diff --git a/src/common/ceph_time.cc b/src/common/ceph_time.cc index bb708bb467564..9b85fc88224d3 100644 --- a/src/common/ceph_time.cc +++ b/src/common/ceph_time.cc @@ -14,6 +14,10 @@ // For ceph_timespec #include "ceph_time.h" + +#include +#include + #include "log/LogClock.h" #include "config.h" #include "strtol.h" @@ -52,277 +56,276 @@ int clock_gettime(int clk_id, struct timespec *tp) } #endif +using namespace std::literals; + namespace ceph { - namespace time_detail { - void real_clock::to_ceph_timespec(const time_point& t, - struct ceph_timespec& ts) { - ts.tv_sec = to_time_t(t); - ts.tv_nsec = (t.time_since_epoch() % seconds(1)).count(); - } - struct ceph_timespec real_clock::to_ceph_timespec(const time_point& t) { - struct ceph_timespec ts; - to_ceph_timespec(t, ts); - return ts; - } - real_clock::time_point real_clock::from_ceph_timespec( - const struct ceph_timespec& ts) { - return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec)); - } +using std::chrono::seconds; +using std::chrono::nanoseconds; +void real_clock::to_ceph_timespec(const time_point& t, + struct ceph_timespec& ts) { + ts.tv_sec = to_time_t(t); + ts.tv_nsec = (t.time_since_epoch() % 1s).count(); +} +struct ceph_timespec real_clock::to_ceph_timespec(const time_point& t) { + struct ceph_timespec ts; + to_ceph_timespec(t, ts); + return ts; +} +real_clock::time_point real_clock::from_ceph_timespec( + const struct ceph_timespec& ts) { + return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec)); +} - void coarse_real_clock::to_ceph_timespec(const time_point& t, - struct ceph_timespec& ts) { - ts.tv_sec = to_time_t(t); - ts.tv_nsec = (t.time_since_epoch() % seconds(1)).count(); - } - struct ceph_timespec coarse_real_clock::to_ceph_timespec( - const time_point& t) { - struct ceph_timespec ts; - to_ceph_timespec(t, ts); - return ts; - } - coarse_real_clock::time_point coarse_real_clock::from_ceph_timespec( - const struct ceph_timespec& ts) { - return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec)); - } +void coarse_real_clock::to_ceph_timespec(const time_point& t, + struct ceph_timespec& ts) { + ts.tv_sec = to_time_t(t); + ts.tv_nsec = (t.time_since_epoch() % seconds(1)).count(); +} +struct ceph_timespec coarse_real_clock::to_ceph_timespec( + const time_point& t) { + struct ceph_timespec ts; + to_ceph_timespec(t, ts); + return ts; +} +coarse_real_clock::time_point coarse_real_clock::from_ceph_timespec( + const struct ceph_timespec& ts) { + return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec)); +} - } - using std::chrono::duration_cast; - using std::chrono::seconds; - using std::chrono::microseconds; +using std::chrono::duration_cast; +using std::chrono::seconds; +using std::chrono::microseconds; - template::type*> - std::ostream& operator<<(std::ostream& m, - const std::chrono::time_point& t) { - return m << std::fixed << std::chrono::duration( - t.time_since_epoch()).count() - << 's'; - } +template::type*> +std::ostream& operator<<(std::ostream& m, + const std::chrono::time_point& t) { + return m << std::fixed << std::chrono::duration( + t.time_since_epoch()).count() + << 's'; +} - std::ostream& operator<<(std::ostream& m, const timespan& t) { - static_assert(std::is_unsigned_v); - m << std::chrono::duration_cast(t).count(); - if (auto ns = (t % 1s).count(); ns > 0) { - char oldfill = m.fill(); - m.fill('0'); - m << '.' << std::setw(9) << ns; - m.fill(oldfill); - } - return m << 's'; - } +template::type*> +std::ostream& operator<<(std::ostream& m, + const std::chrono::time_point& t) { + m.setf(std::ios::right); + char oldfill = m.fill(); + m.fill('0'); + // localtime. this looks like an absolute time. + // conform to http://en.wikipedia.org/wiki/ISO_8601 + struct tm bdt; + time_t tt = Clock::to_time_t(t); + localtime_r(&tt, &bdt); + char tz[32] = { 0 }; + strftime(tz, sizeof(tz), "%z", &bdt); + m << std::setw(4) << (bdt.tm_year+1900) // 2007 -> '07' + << '-' << std::setw(2) << (bdt.tm_mon+1) + << '-' << std::setw(2) << bdt.tm_mday + << 'T' + << std::setw(2) << bdt.tm_hour + << ':' << std::setw(2) << bdt.tm_min + << ':' << std::setw(2) << bdt.tm_sec + << "." << std::setw(6) << duration_cast( + t.time_since_epoch() % seconds(1)).count() + << tz; + m.fill(oldfill); + m.unsetf(std::ios::right); + return m; +} - template::type*> - std::ostream& operator<<(std::ostream& m, - const std::chrono::time_point& t) { - m.setf(std::ios::right); - char oldfill = m.fill(); - m.fill('0'); - // localtime. this looks like an absolute time. - // conform to http://en.wikipedia.org/wiki/ISO_8601 - struct tm bdt; - time_t tt = Clock::to_time_t(t); - localtime_r(&tt, &bdt); - char tz[32] = { 0 }; - strftime(tz, sizeof(tz), "%z", &bdt); - m << std::setw(4) << (bdt.tm_year+1900) // 2007 -> '07' - << '-' << std::setw(2) << (bdt.tm_mon+1) - << '-' << std::setw(2) << bdt.tm_mday - << 'T' - << std::setw(2) << bdt.tm_hour - << ':' << std::setw(2) << bdt.tm_min - << ':' << std::setw(2) << bdt.tm_sec - << "." << std::setw(6) << duration_cast( - t.time_since_epoch() % seconds(1)).count() - << tz; - m.fill(oldfill); - m.unsetf(std::ios::right); - return m; - } +template std::ostream& +operator<< (std::ostream& m, const mono_time& t); +template std::ostream& +operator<< (std::ostream& m, const real_time& t); +template std::ostream& +operator<< (std::ostream& m, const coarse_mono_time& t); +template std::ostream& +operator<< (std::ostream& m, const coarse_real_time& t); - template std::ostream& - operator<< (std::ostream& m, const mono_time& t); - template std::ostream& - operator<< (std::ostream& m, const real_time& t); - template std::ostream& - operator<< (std::ostream& m, const coarse_mono_time& t); - template std::ostream& - operator<< (std::ostream& m, const coarse_real_time& t); +std::string timespan_str(timespan t) +{ + // FIXME: somebody pretty please make a version of this function + // that isn't as lame as this one! + uint64_t nsec = std::chrono::nanoseconds(t).count(); + std::ostringstream ss; + if (nsec < 2000000000) { + ss << ((float)nsec / 1000000000) << "s"; + return ss.str(); + } + uint64_t sec = nsec / 1000000000; + if (sec < 120) { + ss << sec << "s"; + return ss.str(); + } + uint64_t min = sec / 60; + if (min < 120) { + ss << min << "m"; + return ss.str(); + } + uint64_t hr = min / 60; + if (hr < 48) { + ss << hr << "h"; + return ss.str(); + } + uint64_t day = hr / 24; + if (day < 14) { + ss << day << "d"; + return ss.str(); + } + uint64_t wk = day / 7; + if (wk < 12) { + ss << wk << "w"; + return ss.str(); + } + uint64_t mn = day / 30; + if (mn < 24) { + ss << mn << "M"; + return ss.str(); + } + uint64_t yr = day / 365; + ss << yr << "y"; + return ss.str(); +} - std::string timespan_str(timespan t) - { - // FIXME: somebody pretty please make a version of this function - // that isn't as lame as this one! - uint64_t nsec = std::chrono::nanoseconds(t).count(); - ostringstream ss; - if (nsec < 2000000000) { - ss << ((float)nsec / 1000000000) << "s"; - return ss.str(); - } - uint64_t sec = nsec / 1000000000; - if (sec < 120) { - ss << sec << "s"; - return ss.str(); - } - uint64_t min = sec / 60; - if (min < 120) { - ss << min << "m"; - return ss.str(); - } - uint64_t hr = min / 60; - if (hr < 48) { - ss << hr << "h"; - return ss.str(); - } - uint64_t day = hr / 24; - if (day < 14) { - ss << day << "d"; - return ss.str(); - } - uint64_t wk = day / 7; - if (wk < 12) { - ss << wk << "w"; - return ss.str(); - } - uint64_t mn = day / 30; - if (mn < 24) { - ss << mn << "M"; - return ss.str(); - } - uint64_t yr = day / 365; +std::string exact_timespan_str(timespan t) +{ + uint64_t nsec = std::chrono::nanoseconds(t).count(); + uint64_t sec = nsec / 1000000000; + nsec %= 1000000000; + uint64_t yr = sec / (60 * 60 * 24 * 365); + std::ostringstream ss; + if (yr) { ss << yr << "y"; - return ss.str(); + sec -= yr * (60 * 60 * 24 * 365); + } + uint64_t mn = sec / (60 * 60 * 24 * 30); + if (mn >= 3) { + ss << mn << "mo"; + sec -= mn * (60 * 60 * 24 * 30); + } + uint64_t wk = sec / (60 * 60 * 24 * 7); + if (wk >= 2) { + ss << wk << "w"; + sec -= wk * (60 * 60 * 24 * 7); + } + uint64_t day = sec / (60 * 60 * 24); + if (day >= 2) { + ss << day << "d"; + sec -= day * (60 * 60 * 24); } + uint64_t hr = sec / (60 * 60); + if (hr >= 2) { + ss << hr << "h"; + sec -= hr * (60 * 60); + } + uint64_t min = sec / 60; + if (min >= 2) { + ss << min << "m"; + sec -= min * 60; + } + if (sec) { + ss << sec; + } + if (nsec) { + ss << ((float)nsec / 1000000000); + } + if (sec || nsec) { + ss << "s"; + } + return ss.str(); +} - std::string exact_timespan_str(timespan t) - { - uint64_t nsec = std::chrono::nanoseconds(t).count(); - uint64_t sec = nsec / 1000000000; - nsec %= 1000000000; - uint64_t yr = sec / (60 * 60 * 24 * 365); - ostringstream ss; - if (yr) { - ss << yr << "y"; - sec -= yr * (60 * 60 * 24 * 365); - } - uint64_t mn = sec / (60 * 60 * 24 * 30); - if (mn >= 3) { - ss << mn << "mo"; - sec -= mn * (60 * 60 * 24 * 30); - } - uint64_t wk = sec / (60 * 60 * 24 * 7); - if (wk >= 2) { - ss << wk << "w"; - sec -= wk * (60 * 60 * 24 * 7); - } - uint64_t day = sec / (60 * 60 * 24); - if (day >= 2) { - ss << day << "d"; - sec -= day * (60 * 60 * 24); - } - uint64_t hr = sec / (60 * 60); - if (hr >= 2) { - ss << hr << "h"; - sec -= hr * (60 * 60); +std::chrono::seconds parse_timespan(const std::string& s) +{ + static std::map units = { + { "s", 1 }, + { "sec", 1 }, + { "second", 1 }, + { "seconds", 1 }, + { "m", 60 }, + { "min", 60 }, + { "minute", 60 }, + { "minutes", 60 }, + { "h", 60*60 }, + { "hr", 60*60 }, + { "hour", 60*60 }, + { "hours", 60*60 }, + { "d", 24*60*60 }, + { "day", 24*60*60 }, + { "days", 24*60*60 }, + { "w", 7*24*60*60 }, + { "wk", 7*24*60*60 }, + { "week", 7*24*60*60 }, + { "weeks", 7*24*60*60 }, + { "mo", 30*24*60*60 }, + { "month", 30*24*60*60 }, + { "months", 30*24*60*60 }, + { "y", 365*24*60*60 }, + { "yr", 365*24*60*60 }, + { "year", 365*24*60*60 }, + { "years", 365*24*60*60 }, + }; + + auto r = 0s; + auto pos = 0u; + while (pos < s.size()) { + // skip whitespace + while (std::isspace(s[pos])) { + ++pos; } - uint64_t min = sec / 60; - if (min >= 2) { - ss << min << "m"; - sec -= min * 60; + if (pos >= s.size()) { + break; } - if (sec) { - ss << sec; + + // consume any digits + auto val_start = pos; + while (std::isdigit(s[pos])) { + ++pos; } - if (nsec) { - ss << ((float)nsec / 1000000000); + if (val_start == pos) { + throw std::invalid_argument("expected digit"); } - if (sec || nsec) { - ss << "s"; + auto n = s.substr(val_start, pos - val_start); + std::string err; + auto val = strict_strtoll(n.c_str(), 10, &err); + if (err.size()) { + throw std::invalid_argument(err); } - return ss.str(); - } - - std::chrono::seconds parse_timespan(const std::string& s) - { - static std::map units = { - { "s", 1 }, - { "sec", 1 }, - { "second", 1 }, - { "seconds", 1 }, - { "m", 60 }, - { "min", 60 }, - { "minute", 60 }, - { "minutes", 60 }, - { "h", 60*60 }, - { "hr", 60*60 }, - { "hour", 60*60 }, - { "hours", 60*60 }, - { "d", 24*60*60 }, - { "day", 24*60*60 }, - { "days", 24*60*60 }, - { "w", 7*24*60*60 }, - { "wk", 7*24*60*60 }, - { "week", 7*24*60*60 }, - { "weeks", 7*24*60*60 }, - { "mo", 30*24*60*60 }, - { "month", 30*24*60*60 }, - { "months", 30*24*60*60 }, - { "y", 365*24*60*60 }, - { "yr", 365*24*60*60 }, - { "year", 365*24*60*60 }, - { "years", 365*24*60*60 }, - }; - - auto r = 0s; - auto pos = 0u; - while (pos < s.size()) { - // skip whitespace - while (std::isspace(s[pos])) { - ++pos; - } - if (pos >= s.size()) { - break; - } - - // consume any digits - auto val_start = pos; - while (std::isdigit(s[pos])) { - ++pos; - } - if (val_start == pos) { - throw invalid_argument("expected digit"); - } - string n = s.substr(val_start, pos - val_start); - string err; - auto val = strict_strtoll(n.c_str(), 10, &err); - if (err.size()) { - throw invalid_argument(err); - } - // skip whitespace - while (std::isspace(s[pos])) { - ++pos; - } + // skip whitespace + while (std::isspace(s[pos])) { + ++pos; + } - // consume unit - auto unit_start = pos; - while (std::isalpha(s[pos])) { - ++pos; - } - if (unit_start != pos) { - string unit = s.substr(unit_start, pos - unit_start); - auto p = units.find(unit); - if (p == units.end()) { - throw invalid_argument("unrecogized unit '"s + unit + "'"); - } - val *= p->second; - } else if (pos < s.size()) { - throw invalid_argument("unexpected trailing '"s + s.substr(pos) + "'"); + // consume unit + auto unit_start = pos; + while (std::isalpha(s[pos])) { + ++pos; + } + if (unit_start != pos) { + auto unit = s.substr(unit_start, pos - unit_start); + auto p = units.find(unit); + if (p == units.end()) { + throw std::invalid_argument("unrecogized unit '"s + unit + "'"); } - r += chrono::seconds(val); + val *= p->second; + } else if (pos < s.size()) { + throw std::invalid_argument("unexpected trailing '"s + s.substr(pos) + "'"); } - return r; + r += std::chrono::seconds(val); } + return r; +} + +} +namespace std { +ostream& operator<<(ostream& m, const ::ceph::timespan& t) { + static_assert(is_unsigned_v<::ceph::timespan::rep>); + using seconds_t = chrono::duration; + ::fmt::print(m, "{:.9}", chrono::duration_cast(t)); + return m; } +} // namespace std diff --git a/src/common/ceph_time.h b/src/common/ceph_time.h index f6185c8820063..663d05f8feb2b 100644 --- a/src/common/ceph_time.h +++ b/src/common/ceph_time.h @@ -18,10 +18,9 @@ #include #include #include +#include #include -#include "include/ceph_assert.h" - #if defined(__APPLE__) #include @@ -31,451 +30,439 @@ int clock_gettime(int clk_id, struct timespec *tp); #endif +#ifdef _WIN32 +#define CLOCK_REALTIME_COARSE CLOCK_REALTIME +#define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC +// MINGW uses the QueryPerformanceCounter API behind the scenes. +#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()); - } - - static time_point zero() { - return 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; +// 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; + + +// 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. +typedef std::chrono::duration timespan; + + +// Like the above but signed. +typedef int64_t signed_rep; + +// Similar to the above but for durations that can specify +// differences between now and a time point in the past. +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. + +// High-resolution real-time clock +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()); + } + + static time_point zero() { + return 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)) + + std::chrono::duration_cast(t.time_since_epoch() % + std::chrono::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)) + + std::chrono::duration_cast(t.time_since_epoch() % + std::chrono::seconds(1))); + } + + static time_t to_time_t(const time_point& t) noexcept { + return std::chrono::duration_cast(t.time_since_epoch()).count(); + } + static time_point from_time_t(const time_t& t) noexcept { + return time_point(std::chrono::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() % std::chrono::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(std::chrono::seconds(ts.tv_sec) + + std::chrono::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 = std::chrono::duration_cast( + t.time_since_epoch() % std::chrono::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(std::chrono::seconds(tv.tv_sec) + + std::chrono::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(std::chrono::duration_cast( + std::chrono::duration(d))); + } +}; + +// Low-resolution but preusmably faster real-time clock +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); + // 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); + // 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. + // 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); + clock_gettime(CLOCK_REALTIME, &ts); #endif - return from_timespec(ts); - } - - static bool is_zero(const time_point& t) { - return (t == time_point::min()); - } - - static time_point zero() { - return time_point::min(); - } - - 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)); - } - - static bool is_zero(const time_point& t) { - return (t == time_point::min()); - } - - static time_point zero() { - return time_point::min(); - } - - // 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; + return from_timespec(ts); + } + + static bool is_zero(const time_point& t) { + return (t == time_point::min()); + } + + static time_point zero() { + return time_point::min(); + } + + static time_t to_time_t(const time_point& t) noexcept { + return std::chrono::duration_cast( + t.time_since_epoch()).count(); + } + static time_point from_time_t(const time_t t) noexcept { + return time_point(std::chrono::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() % std::chrono::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(std::chrono::seconds(ts.tv_sec) + + std::chrono::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 = std::chrono::duration_cast( + t.time_since_epoch() % std::chrono::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(std::chrono::seconds(tv.tv_sec) + + std::chrono::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(std::chrono::duration_cast( + std::chrono::duration(d))); + } +}; + +// High-resolution monotonic clock +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(std::chrono::seconds(ts.tv_sec) + + std::chrono::nanoseconds(ts.tv_nsec)); + } + + static bool is_zero(const time_point& t) { + return (t == time_point::min()); + } + + static time_point zero() { + return time_point::min(); + } +}; + +// Low-resolution but, I would hope or there's no point, faster +// monotonic clock +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); + // 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); + // 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. + // 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); + clock_gettime(CLOCK_MONOTONIC, &ts); #endif - return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec)); - } - - static bool is_zero(const time_point& t) { - return (t == time_point::min()); - } - - static time_point zero() { - return time_point::min(); - } - }; - - // 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. + return time_point(std::chrono::seconds(ts.tv_sec) + + std::chrono::nanoseconds(ts.tv_nsec)); + } + + static bool is_zero(const time_point& t) { + return (t == time_point::min()); + } + + static time_point zero() { + return time_point::min(); + } +}; + +namespace time_detail { +// So that our subtractions produce negative spans rather than +// arithmetic underflow. +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()); +} +} + +// 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)); +} + +inline timespan make_timespan(const double d) { + return std::chrono::duration_cast( + std::chrono::duration(d)); +} +inline std::optional maybe_timespan(const double d) { + return d ? std::make_optional(make_timespan(d)) : std::nullopt; +} + +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. + +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. inline timespan abs(signedspan z) { return z > signedspan::zero() ? std::chrono::duration_cast(z) : @@ -508,8 +495,8 @@ struct converts_to_timespec : std::false_type {}; template struct converts_to_timespec())) + Clock::from_timespec(Clock::to_timespec( + std::declval())) )>> : std::true_type {}; template @@ -531,4 +518,8 @@ static Rep to_microseconds(T t) { } // namespace ceph +namespace std { +ostream& operator<<(ostream& m, const ::ceph::timespan& t); +} + #endif // COMMON_CEPH_TIME_H