// For ceph_timespec
#include "ceph_time.h"
+
+#include <fmt/chrono.h>
+#include <fmt/ostream.h>
+
#include "log/LogClock.h"
#include "config.h"
#include "strtol.h"
}
#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<typename Clock,
- typename std::enable_if<Clock::is_steady>::type*>
- std::ostream& operator<<(std::ostream& m,
- const std::chrono::time_point<Clock>& t) {
- return m << std::fixed << std::chrono::duration<double>(
- t.time_since_epoch()).count()
- << 's';
- }
+template<typename Clock,
+ typename std::enable_if<Clock::is_steady>::type*>
+std::ostream& operator<<(std::ostream& m,
+ const std::chrono::time_point<Clock>& t) {
+ return m << std::fixed << std::chrono::duration<double>(
+ t.time_since_epoch()).count()
+ << 's';
+}
- std::ostream& operator<<(std::ostream& m, const timespan& t) {
- static_assert(std::is_unsigned_v<timespan::rep>);
- m << std::chrono::duration_cast<std::chrono::seconds>(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<typename Clock,
+ typename std::enable_if<!Clock::is_steady>::type*>
+std::ostream& operator<<(std::ostream& m,
+ const std::chrono::time_point<Clock>& 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<microseconds>(
+ t.time_since_epoch() % seconds(1)).count()
+ << tz;
+ m.fill(oldfill);
+ m.unsetf(std::ios::right);
+ return m;
+}
- template<typename Clock,
- typename std::enable_if<!Clock::is_steady>::type*>
- std::ostream& operator<<(std::ostream& m,
- const std::chrono::time_point<Clock>& 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<microseconds>(
- t.time_since_epoch() % seconds(1)).count()
- << tz;
- m.fill(oldfill);
- m.unsetf(std::ios::right);
- return m;
- }
+template std::ostream&
+operator<< <mono_clock>(std::ostream& m, const mono_time& t);
+template std::ostream&
+operator<< <real_clock>(std::ostream& m, const real_time& t);
+template std::ostream&
+operator<< <coarse_mono_clock>(std::ostream& m, const coarse_mono_time& t);
+template std::ostream&
+operator<< <coarse_real_clock>(std::ostream& m, const coarse_real_time& t);
- template std::ostream&
- operator<< <mono_clock>(std::ostream& m, const mono_time& t);
- template std::ostream&
- operator<< <real_clock>(std::ostream& m, const real_time& t);
- template std::ostream&
- operator<< <coarse_mono_clock>(std::ostream& m, const coarse_mono_time& t);
- template std::ostream&
- operator<< <coarse_real_clock>(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<std::string,int> 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<string,int> 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<float>;
+ ::fmt::print(m, "{:.9}", chrono::duration_cast<seconds_t>(t));
+ return m;
}
+} // namespace std
#include <chrono>
#include <iostream>
#include <string>
+#include <optional>
#include <sys/time.h>
-#include "include/ceph_assert.h"
-
#if defined(__APPLE__)
#include <sys/_types/_timespec.h>
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<rep, std::nano> timespan;
-
-
- // Like the above but signed.
- typedef int64_t signed_rep;
-
- typedef std::chrono::duration<signed_rep, std::nano> 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<real_clock> 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<typename Clock, typename Duration>
- static time_point to_system_time_point(
- const std::chrono::time_point<Clock, Duration>& t) {
- return time_point(seconds(Clock::to_time_t(t)) +
- duration_cast<duration>(t.time_since_epoch() %
- seconds(1)));
- }
- template<typename Clock, typename Duration>
- static std::chrono::time_point<Clock, Duration> to_system_time_point(
- const time_point& t) {
- return (Clock::from_time_t(to_time_t(t)) +
- duration_cast<Duration>(t.time_since_epoch() % seconds(1)));
- }
-
- static time_t to_time_t(const time_point& t) noexcept {
- return duration_cast<seconds>(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<microseconds>(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<double>(t.time_since_epoch()).count();
- }
- static time_point from_double(const double d) {
- return time_point(duration_cast<duration>(
- std::chrono::duration<double>(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<coarse_real_clock> 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<rep, std::nano> 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<signed_rep, std::nano> 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<real_clock> 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<typename Clock, typename Duration>
+ static time_point to_system_time_point(
+ const std::chrono::time_point<Clock, Duration>& t) {
+ return time_point(seconds(Clock::to_time_t(t)) +
+ std::chrono::duration_cast<duration>(t.time_since_epoch() %
+ std::chrono::seconds(1)));
+ }
+ template<typename Clock, typename Duration>
+ static std::chrono::time_point<Clock, Duration> to_system_time_point(
+ const time_point& t) {
+ return (Clock::from_time_t(to_time_t(t)) +
+ std::chrono::duration_cast<Duration>(t.time_since_epoch() %
+ std::chrono::seconds(1)));
+ }
+
+ static time_t to_time_t(const time_point& t) noexcept {
+ return std::chrono::duration_cast<std::chrono::seconds>(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<std::chrono::microseconds>(
+ 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<double>(t.time_since_epoch()).count();
+ }
+ static time_point from_double(const double d) {
+ return time_point(std::chrono::duration_cast<duration>(
+ std::chrono::duration<double>(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<coarse_real_clock> 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<seconds>(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<microseconds>(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<double>(t.time_since_epoch()).count();
- }
- static time_point from_double(const double d) {
- return time_point(duration_cast<duration>(
- std::chrono::duration<double>(d)));
- }
- };
-
- class mono_clock {
- public:
- typedef timespan duration;
- typedef duration::rep rep;
- typedef duration::period period;
- typedef std::chrono::time_point<mono_clock> 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<coarse_mono_clock> 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<std::chrono::seconds>(
+ 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<std::chrono::microseconds>(
+ 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<double>(t.time_since_epoch()).count();
+ }
+ static time_point from_double(const double d) {
+ return time_point(std::chrono::duration_cast<duration>(
+ std::chrono::duration<double>(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<mono_clock> 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<coarse_mono_clock> 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<typename Rep1, typename Period1, typename Rep2,
- typename Period2>
- inline auto difference(std::chrono::duration<Rep1, Period1> minuend,
- std::chrono::duration<Rep2, Period2> subtrahend)
- -> typename std::common_type<
- std::chrono::duration<typename std::make_signed<Rep1>::type,
- Period1>,
- std::chrono::duration<typename std::make_signed<Rep2>::type,
- Period2> >::type {
- // Foo.
- using srep =
- typename std::common_type<
- std::chrono::duration<typename std::make_signed<Rep1>::type,
- Period1>,
- std::chrono::duration<typename std::make_signed<Rep2>::type,
- Period2> >::type;
- return srep(srep(minuend).count() - srep(subtrahend).count());
- }
-
- template<typename Clock, typename Duration1, typename Duration2>
- inline auto difference(
- typename std::chrono::time_point<Clock, Duration1> minuend,
- typename std::chrono::time_point<Clock, Duration2> subtrahend)
- -> typename std::common_type<
- std::chrono::duration<typename std::make_signed<
- typename Duration1::rep>::type,
- typename Duration1::period>,
- std::chrono::duration<typename std::make_signed<
- typename Duration2::rep>::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<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2>
- auto floor(const std::chrono::duration<Rep1, Ratio1>& duration,
- const std::chrono::duration<Rep2, Ratio2>& precision) ->
- typename std::common_type<std::chrono::duration<Rep1, Ratio1>,
- std::chrono::duration<Rep2, Ratio2> >::type {
- return duration - (duration % precision);
- }
-
- template<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2>
- auto ceil(const std::chrono::duration<Rep1, Ratio1>& duration,
- const std::chrono::duration<Rep2, Ratio2>& precision) ->
- typename std::common_type<std::chrono::duration<Rep1, Ratio1>,
- std::chrono::duration<Rep2, Ratio2> >::type {
- auto tmod = duration % precision;
- return duration - tmod + (tmod > tmod.zero() ? 1 : 0) * precision;
- }
-
- template<typename Clock, typename Duration, typename Rep, typename Ratio>
- auto floor(const std::chrono::time_point<Clock, Duration>& timepoint,
- const std::chrono::duration<Rep, Ratio>& precision) ->
- std::chrono::time_point<Clock,
- typename std::common_type<
- Duration, std::chrono::duration<Rep, Ratio>
- >::type> {
- return std::chrono::time_point<
- Clock, typename std::common_type<
- Duration, std::chrono::duration<Rep, Ratio> >::type>(
- floor(timepoint.time_since_epoch(), precision));
- }
- template<typename Clock, typename Duration, typename Rep, typename Ratio>
- auto ceil(const std::chrono::time_point<Clock, Duration>& timepoint,
- const std::chrono::duration<Rep, Ratio>& precision) ->
- std::chrono::time_point<Clock,
- typename std::common_type<
- Duration,
- std::chrono::duration<Rep, Ratio> >::type> {
- return std::chrono::time_point<
- Clock, typename std::common_type<
- Duration, std::chrono::duration<Rep, Ratio> >::type>(
- ceil(timepoint.time_since_epoch(), precision));
- }
-
- namespace {
- inline timespan make_timespan(const double d) {
- return std::chrono::duration_cast<timespan>(
- std::chrono::duration<double>(d));
- }
- }
-
- std::ostream& operator<<(std::ostream& m, const timespan& t);
- template<typename Clock,
- typename std::enable_if<!Clock::is_steady>::type* = nullptr>
- std::ostream& operator<<(std::ostream& m,
- const std::chrono::time_point<Clock>& t);
- template<typename Clock,
- typename std::enable_if<Clock::is_steady>::type* = nullptr>
- std::ostream& operator<<(std::ostream& m,
- const std::chrono::time_point<Clock>& 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<typename Rep1, typename Period1, typename Rep2,
+ typename Period2>
+inline auto difference(std::chrono::duration<Rep1, Period1> minuend,
+ std::chrono::duration<Rep2, Period2> subtrahend)
+ -> typename std::common_type<
+ std::chrono::duration<typename std::make_signed<Rep1>::type,
+ Period1>,
+ std::chrono::duration<typename std::make_signed<Rep2>::type,
+ Period2> >::type {
+ // Foo.
+ using srep =
+ typename std::common_type<
+ std::chrono::duration<typename std::make_signed<Rep1>::type,
+ Period1>,
+ std::chrono::duration<typename std::make_signed<Rep2>::type,
+ Period2> >::type;
+ return srep(srep(minuend).count() - srep(subtrahend).count());
+}
+
+template<typename Clock, typename Duration1, typename Duration2>
+inline auto difference(
+ typename std::chrono::time_point<Clock, Duration1> minuend,
+ typename std::chrono::time_point<Clock, Duration2> subtrahend)
+ -> typename std::common_type<
+ std::chrono::duration<typename std::make_signed<
+ typename Duration1::rep>::type,
+ typename Duration1::period>,
+ std::chrono::duration<typename std::make_signed<
+ typename Duration2::rep>::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<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2>
+auto floor(const std::chrono::duration<Rep1, Ratio1>& duration,
+ const std::chrono::duration<Rep2, Ratio2>& precision) ->
+ typename std::common_type<std::chrono::duration<Rep1, Ratio1>,
+ std::chrono::duration<Rep2, Ratio2> >::type {
+ return duration - (duration % precision);
+}
+
+template<typename Rep1, typename Ratio1, typename Rep2, typename Ratio2>
+auto ceil(const std::chrono::duration<Rep1, Ratio1>& duration,
+ const std::chrono::duration<Rep2, Ratio2>& precision) ->
+ typename std::common_type<std::chrono::duration<Rep1, Ratio1>,
+ std::chrono::duration<Rep2, Ratio2> >::type {
+ auto tmod = duration % precision;
+ return duration - tmod + (tmod > tmod.zero() ? 1 : 0) * precision;
+}
+
+template<typename Clock, typename Duration, typename Rep, typename Ratio>
+auto floor(const std::chrono::time_point<Clock, Duration>& timepoint,
+ const std::chrono::duration<Rep, Ratio>& precision) ->
+ std::chrono::time_point<Clock,
+ typename std::common_type<
+ Duration, std::chrono::duration<Rep, Ratio>
+ >::type> {
+ return std::chrono::time_point<
+ Clock, typename std::common_type<
+ Duration, std::chrono::duration<Rep, Ratio> >::type>(
+ floor(timepoint.time_since_epoch(), precision));
+}
+template<typename Clock, typename Duration, typename Rep, typename Ratio>
+auto ceil(const std::chrono::time_point<Clock, Duration>& timepoint,
+ const std::chrono::duration<Rep, Ratio>& precision) ->
+ std::chrono::time_point<Clock,
+ typename std::common_type<
+ Duration,
+ std::chrono::duration<Rep, Ratio> >::type> {
+ return std::chrono::time_point<
+ Clock, typename std::common_type<
+ Duration, std::chrono::duration<Rep, Ratio> >::type>(
+ ceil(timepoint.time_since_epoch(), precision));
+}
+
+inline timespan make_timespan(const double d) {
+ return std::chrono::duration_cast<timespan>(
+ std::chrono::duration<double>(d));
+}
+inline std::optional<timespan> maybe_timespan(const double d) {
+ return d ? std::make_optional(make_timespan(d)) : std::nullopt;
+}
+
+template<typename Clock,
+ typename std::enable_if<!Clock::is_steady>::type* = nullptr>
+std::ostream& operator<<(std::ostream& m,
+ const std::chrono::time_point<Clock>& t);
+template<typename Clock,
+ typename std::enable_if<Clock::is_steady>::type* = nullptr>
+std::ostream& operator<<(std::ostream& m,
+ const std::chrono::time_point<Clock>& 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<timespan>(z) :
template <typename Clock>
struct converts_to_timespec<Clock, std::void_t<decltype(
- Clock::from_timespec(Clock::to_timespec(
- std::declval<typename Clock::time_point>()))
+ Clock::from_timespec(Clock::to_timespec(
+ std::declval<typename Clock::time_point>()))
)>> : std::true_type {};
template <typename Clock>
} // namespace ceph
+namespace std {
+ostream& operator<<(ostream& m, const ::ceph::timespan& t);
+}
+
#endif // COMMON_CEPH_TIME_H