From 7b0168c5ddb054eb375266f473f8b757d7ca5e9e Mon Sep 17 00:00:00 2001 From: "Adam C. Emerson" Date: Thu, 5 Oct 2017 18:17:16 -0400 Subject: [PATCH] log: Create log_clock to replace use of utime_t We create a new time type to support using coarse timestamps (for performance) by default while still allowing the user to switch to fine timestamps. Signed-off-by: Adam C. Emerson --- src/common/ceph_time.cc | 23 +++++++ src/log/LogClock.h | 136 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 src/log/LogClock.h diff --git a/src/common/ceph_time.cc b/src/common/ceph_time.cc index cd41d0581ed..f5072b7923d 100644 --- a/src/common/ceph_time.cc +++ b/src/common/ceph_time.cc @@ -14,6 +14,7 @@ // For ceph_timespec #include "ceph_time.h" +#include "log/LogClock.h" #include "config.h" #if defined(__APPLE__) @@ -80,6 +81,26 @@ namespace ceph { const struct ceph_timespec& ts) { return time_point(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec)); } + + } + + namespace logging { + void log_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() %std::chrono::seconds(1)).count(); + } + struct ceph_timespec log_clock::to_ceph_timespec( + const time_point& t) { + struct ceph_timespec ts; + to_ceph_timespec(t, ts); + return ts; + } + log_clock::time_point log_clock::from_ceph_timespec( + const struct ceph_timespec& ts) { + return time_point(std::chrono::seconds(ts.tv_sec) + + std::chrono::nanoseconds(ts.tv_nsec)); + } } using std::chrono::duration_cast; @@ -132,4 +153,6 @@ namespace ceph { 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 logging::log_time& t); } diff --git a/src/log/LogClock.h b/src/log/LogClock.h new file mode 100644 index 00000000000..e790dbd2c8f --- /dev/null +++ b/src/log/LogClock.h @@ -0,0 +1,136 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_LOG_CLOCK_H +#define CEPH_LOG_CLOCK_H + +#include +#include +#include +#include + +#include "include/assert.h" +#include "common/ceph_time.h" + +namespace ceph { +namespace logging { +class log_clock { +public: + using duration = timespan; + using rep = duration::rep; + using period = duration::period; + // The second template parameter defaults to the clock's duration + // type. + using time_point = std::chrono::time_point; + static constexpr const bool is_steady = false; + + void coarsen() { + appropriate_now = coarse_now; + } + + void refine() { + appropriate_now = fine_now; + } + + time_point now() noexcept { + return appropriate_now(); + } + + 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)) + + 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))); + } +private: + static time_point coarse_now() { + return time_point(coarse_real_clock::now().time_since_epoch()); + } + static time_point fine_now() { + return time_point(real_clock::now().time_since_epoch()); + } + time_point(*appropriate_now)() = coarse_now; +}; +using log_time = log_clock::time_point; +inline int append_time(const log_time& t, char *out, int outlen) { + auto tv = log_clock::to_timeval(t); + std::tm bdt; + localtime_r(&tv.tv_sec, &bdt); + + auto r = std::snprintf(out, outlen, + "%04d-%02d-%02d %02d:%02d:%02d.%06ld", + bdt.tm_year + 1900, bdt.tm_mon + 1, bdt.tm_mday, + bdt.tm_hour, bdt.tm_min, bdt.tm_sec, tv.tv_usec); + // Since our caller just adds the return value to something without + // checking it… + ceph_assert(r >= 0); + return r; +} +} +} + +#endif -- 2.39.5