X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Fcommon%2Fceph_time.h;fp=src%2Fceph%2Fsrc%2Fcommon%2Fceph_time.h;h=8479a0d5494c62beb7c9caa88ce4fafd7fd7a22b;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/common/ceph_time.h b/src/ceph/src/common/ceph_time.h new file mode 100644 index 0000000..8479a0d --- /dev/null +++ b/src/ceph/src/common/ceph_time.h @@ -0,0 +1,509 @@ +// -*- 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