Replace UptimeTimer with UptimeClock

* UptimeClock is a chrono-compatible seconds-precision clock.

* Like UptimeTimer, its purpose is to make it possible for clients
  to query the uptime thousands of times per second without a
  significant performance hit.

* UptimeClock decouples itself from LoadManager by managing its
  own once-per-second update loop.

* Clients now traffic in chrono time_points and durations instead
  of int.
This commit is contained in:
Howard Hinnant
2018-04-23 13:46:37 -04:00
committed by seelabs
parent 717f874767
commit 7d163a45dc
14 changed files with 159 additions and 186 deletions

View File

@@ -238,7 +238,7 @@ public:
std::weak_ptr<Peer> const& wPeer, std::weak_ptr<Peer> const& wPeer,
std::shared_ptr<protocol::TMGetObjectByHash> const& request, std::shared_ptr<protocol::TMGetObjectByHash> const& request,
uint256 haveLedgerHash, uint256 haveLedgerHash,
std::uint32_t uUptime); UptimeClock::time_point uptime);
std::size_t getFetchPackCacheSize () const; std::size_t getFetchPackCacheSize () const;

View File

@@ -36,7 +36,7 @@
#include <ripple/basics/contract.h> #include <ripple/basics/contract.h>
#include <ripple/basics/Log.h> #include <ripple/basics/Log.h>
#include <ripple/basics/TaggedCache.h> #include <ripple/basics/TaggedCache.h>
#include <ripple/basics/UptimeTimer.h> #include <ripple/basics/UptimeClock.h>
#include <ripple/core/TimeKeeper.h> #include <ripple/core/TimeKeeper.h>
#include <ripple/nodestore/DatabaseShard.h> #include <ripple/nodestore/DatabaseShard.h>
#include <ripple/overlay/Overlay.h> #include <ripple/overlay/Overlay.h>
@@ -1792,9 +1792,9 @@ LedgerMaster::makeFetchPack (
std::weak_ptr<Peer> const& wPeer, std::weak_ptr<Peer> const& wPeer,
std::shared_ptr<protocol::TMGetObjectByHash> const& request, std::shared_ptr<protocol::TMGetObjectByHash> const& request,
uint256 haveLedgerHash, uint256 haveLedgerHash,
std::uint32_t uUptime) UptimeClock::time_point uptime)
{ {
if (UptimeTimer::getInstance ().getElapsedSeconds () > (uUptime + 1)) if (UptimeClock::now() > uptime + 1s)
{ {
JLOG(m_journal.info()) << "Fetch pack request got stale"; JLOG(m_journal.info()) << "Fetch pack request got stale";
return; return;
@@ -1916,7 +1916,7 @@ LedgerMaster::makeFetchPack (
wantLedger = getLedgerByHash (haveLedger->info().parentHash); wantLedger = getLedgerByHash (haveLedger->info().parentHash);
} }
while (wantLedger && while (wantLedger &&
UptimeTimer::getInstance ().getElapsedSeconds () <= uUptime + 1); UptimeClock::now() <= uptime + 1s);
JLOG(m_journal.info()) JLOG(m_journal.info())
<< "Built fetch pack with " << reply.objects ().size () << " nodes"; << "Built fetch pack with " << reply.objects ().size () << " nodes";

View File

@@ -21,7 +21,7 @@
#include <ripple/app/main/Application.h> #include <ripple/app/main/Application.h>
#include <ripple/app/misc/LoadFeeTrack.h> #include <ripple/app/misc/LoadFeeTrack.h>
#include <ripple/app/misc/NetworkOPs.h> #include <ripple/app/misc/NetworkOPs.h>
#include <ripple/basics/UptimeTimer.h> #include <ripple/basics/UptimeClock.h>
#include <ripple/json/to_string.h> #include <ripple/json/to_string.h>
#include <ripple/beast/core/CurrentThreadName.h> #include <ripple/beast/core/CurrentThreadName.h>
#include <memory> #include <memory>
@@ -35,18 +35,16 @@ LoadManager::LoadManager (
: Stoppable ("LoadManager", parent) : Stoppable ("LoadManager", parent)
, app_ (app) , app_ (app)
, journal_ (journal) , journal_ (journal)
, deadLock_ (0) , deadLock_ ()
, armed_ (false) , armed_ (false)
, stop_ (false) , stop_ (false)
{ {
UptimeTimer::getInstance ().beginManualUpdates ();
} }
LoadManager::~LoadManager () LoadManager::~LoadManager ()
{ {
try try
{ {
UptimeTimer::getInstance ().endManualUpdates ();
onStop (); onStop ();
} }
catch (std::exception const& ex) catch (std::exception const& ex)
@@ -67,9 +65,7 @@ void LoadManager::activateDeadlockDetector ()
void LoadManager::resetDeadlockDetector () void LoadManager::resetDeadlockDetector ()
{ {
auto const elapsedSeconds = auto const elapsedSeconds = UptimeClock::now();
UptimeTimer::getInstance ().getElapsedSeconds ();
std::lock_guard<std::mutex> sl (mutex_); std::lock_guard<std::mutex> sl (mutex_);
deadLock_ = elapsedSeconds; deadLock_ = elapsedSeconds;
} }
@@ -108,24 +104,14 @@ void LoadManager::run ()
{ {
beast::setCurrentThreadName ("LoadManager"); beast::setCurrentThreadName ("LoadManager");
using clock_type = std::chrono::steady_clock; using clock_type = std::chrono::system_clock;
// Initialize the clock to the current time.
auto t = clock_type::now(); auto t = clock_type::now();
bool stop = false; bool stop = false;
while (! (stop || isStopping ())) while (! (stop || isStopping ()))
{ {
{ {
// VFALCO NOTE I think this is to reduce calls to the operating
// system for retrieving the current time.
//
// TODO Instead of incrementing can't we just retrieve the
// current time again?
//
// Manually update the timer.
UptimeTimer::getInstance ().incrementElapsedTime ();
// Copy out shared data under a lock. Use copies outside lock. // Copy out shared data under a lock. Use copies outside lock.
std::unique_lock<std::mutex> sl (mutex_); std::unique_lock<std::mutex> sl (mutex_);
auto const deadLock = deadLock_; auto const deadLock = deadLock_;
@@ -134,29 +120,24 @@ void LoadManager::run ()
sl.unlock(); sl.unlock();
// Measure the amount of time we have been deadlocked, in seconds. // Measure the amount of time we have been deadlocked, in seconds.
// auto const timeSpentDeadlocked = UptimeClock::now() - deadLock;
// VFALCO NOTE deadLock_ is a canary for detecting the condition.
int const timeSpentDeadlocked =
UptimeTimer::getInstance ().getElapsedSeconds () - deadLock;
// VFALCO NOTE I think that "armed" refers to the deadlock detector. auto const reportingIntervalSeconds = 10s;
//
int const reportingIntervalSeconds = 10;
if (armed && (timeSpentDeadlocked >= reportingIntervalSeconds)) if (armed && (timeSpentDeadlocked >= reportingIntervalSeconds))
{ {
// Report the deadlocked condition every 10 seconds // Report the deadlocked condition every 10 seconds
if ((timeSpentDeadlocked % reportingIntervalSeconds) == 0) if ((timeSpentDeadlocked % reportingIntervalSeconds) == 0s)
{ {
JLOG(journal_.warn()) JLOG(journal_.warn())
<< "Server stalled for " << "Server stalled for "
<< timeSpentDeadlocked << " seconds."; << timeSpentDeadlocked.count() << " seconds.";
} }
// If we go over 500 seconds spent deadlocked, it means that // If we go over 500 seconds spent deadlocked, it means that
// the deadlock resolution code has failed, which qualifies // the deadlock resolution code has failed, which qualifies
// as undefined behavior. // as undefined behavior.
// //
assert (timeSpentDeadlocked < 500); assert (timeSpentDeadlocked < 500s);
} }
} }
@@ -178,18 +159,17 @@ void LoadManager::run ()
app_.getOPs ().reportFeeChange (); app_.getOPs ().reportFeeChange ();
} }
t += std::chrono::seconds (1); t += 1s;
auto const duration = t - clock_type::now(); auto const duration = t - clock_type::now();
if ((duration < std::chrono::seconds (0)) || if ((duration < 0s) || (duration > 1s))
(duration > std::chrono::seconds (1)))
{ {
JLOG(journal_.warn()) << "time jump"; JLOG(journal_.warn()) << "time jump";
t = clock_type::now(); t = clock_type::now();
} }
else else
{ {
alertable_sleep_for(duration); alertable_sleep_until(t);
} }
} }
@@ -202,7 +182,7 @@ std::unique_ptr<LoadManager>
make_LoadManager (Application& app, make_LoadManager (Application& app,
Stoppable& parent, beast::Journal journal) Stoppable& parent, beast::Journal journal)
{ {
return std::make_unique<LoadManager>(app, parent, journal); return std::unique_ptr<LoadManager>{new LoadManager{app, parent, journal}};
} }
} // ripple } // ripple

View File

@@ -42,16 +42,6 @@ class Application;
*/ */
class LoadManager : public Stoppable class LoadManager : public Stoppable
{ {
public:
// It would be better if the LoadManager constructor could be private
// with std::make_unique as a friend. But Visual Studio can't currently
// swallow the following friend declaration (Microsoft (R) C/C++
// Optimizing Compiler Version 19.00.23026 for x64). So we make the
// constructor public.
// template<class T, class... Args>
// friend std::unique_ptr<T> std::make_unique (Args&&... args);
// Should only be constructible by std::make_unique.
LoadManager (Application& app, Stoppable& parent, beast::Journal journal); LoadManager (Application& app, Stoppable& parent, beast::Journal journal);
public: public:
@@ -105,9 +95,13 @@ private:
std::thread thread_; std::thread thread_;
std::mutex mutex_; // Guards deadLock_, armed_, and stop_. std::mutex mutex_; // Guards deadLock_, armed_, and stop_.
int deadLock_; // Detect server deadlocks. UptimeClock::time_point deadLock_; // Detect server deadlocks.
bool armed_; bool armed_;
bool stop_; bool stop_;
friend
std::unique_ptr<LoadManager>
make_LoadManager(Application& app, Stoppable& parent, beast::Journal journal);
}; };
std::unique_ptr<LoadManager> std::unique_ptr<LoadManager>

View File

@@ -41,7 +41,7 @@
#include <ripple/app/tx/apply.h> #include <ripple/app/tx/apply.h>
#include <ripple/basics/mulDiv.h> #include <ripple/basics/mulDiv.h>
#include <ripple/basics/PerfLog.h> #include <ripple/basics/PerfLog.h>
#include <ripple/basics/UptimeTimer.h> #include <ripple/basics/UptimeClock.h>
#include <ripple/core/ConfigSections.h> #include <ripple/core/ConfigSections.h>
#include <ripple/crypto/csprng.h> #include <ripple/crypto/csprng.h>
#include <ripple/crypto/RFC1751.h> #include <ripple/crypto/RFC1751.h>
@@ -2335,7 +2335,7 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin, bool counters)
} }
info[jss::state_accounting] = accounting_.json(); info[jss::state_accounting] = accounting_.json();
info[jss::uptime] = UptimeTimer::getInstance ().getElapsedSeconds (); info[jss::uptime] = UptimeClock::now().time_since_epoch().count();
info[jss::jq_trans_overflow] = std::to_string( info[jss::jq_trans_overflow] = std::to_string(
app_.overlay().getJqTransOverflow()); app_.overlay().getJqTransOverflow());
info[jss::peer_disconnects] = std::to_string( info[jss::peer_disconnects] = std::to_string(

View File

@@ -20,39 +20,47 @@
#ifndef RIPPLE_BASICS_UPTIMETIMER_H_INCLUDED #ifndef RIPPLE_BASICS_UPTIMETIMER_H_INCLUDED
#define RIPPLE_BASICS_UPTIMETIMER_H_INCLUDED #define RIPPLE_BASICS_UPTIMETIMER_H_INCLUDED
#include <ctime> #include <atomic>
#include <chrono>
#include <ratio>
#include <thread>
namespace ripple { namespace ripple {
/** Tracks program uptime. /** Tracks program uptime to seconds precision.
The timer can be switched to a manual system of updating, to reduce The timer caches the current time as a performance optimization.
system calls. (?) This allows clients to query the current time thousands of times
per second.
*/ */
// VFALCO TODO determine if the non-manual timing is actually needed
class UptimeTimer class UptimeClock
{ {
private:
UptimeTimer ();
~UptimeTimer ();
public: public:
int getElapsedSeconds () const; using rep = int;
using period = std::ratio<1>;
using duration = std::chrono::duration<rep, period>;
using time_point = std::chrono::time_point<UptimeClock>;
static constexpr bool is_steady = std::chrono::system_clock::is_steady;
void beginManualUpdates (); explicit UptimeClock() = default;
void endManualUpdates ();
void incrementElapsedTime (); static time_point now(); // seconds since rippled program start
static UptimeTimer& getInstance ();
private: private:
// VFALCO DEPRECATED, Use a memory barrier instead of forcing a cache line static std::atomic<rep> now_;
int volatile m_elapsedTime; static std::atomic<bool> stop_;
time_t m_startTime; struct update_thread
: private std::thread
{
~update_thread();
update_thread(update_thread&&) = default;
bool m_isUpdatingManually; using std::thread::thread;
};
static update_thread start_clock();
}; };
} // ripple } // ripple

View File

@@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/basics/UptimeClock.h>
namespace ripple {
std::atomic<UptimeClock::rep> UptimeClock::now_{0}; // seconds since start
std::atomic<bool> UptimeClock::stop_{false}; // stop update thread
// On rippled shutdown, cancel and wait for the update thread
UptimeClock::update_thread::~update_thread()
{
if (joinable())
{
stop_ = true;
// This join() may take up to a 1s, but happens only
// once at rippled shutdown.
join();
}
}
// Launch the update thread
UptimeClock::update_thread
UptimeClock::start_clock()
{
return update_thread{[]
{
using namespace std;
using namespace std::chrono;
// Wake up every second and update now_
auto next = system_clock::now() + 1s;
while (!stop_)
{
this_thread::sleep_until(next);
next += 1s;
++now_;
}
}};
}
// This actually measures time since first use, instead of since rippled start.
// However the difference between these two epochs is a small fraction of a second
// and unimportant.
UptimeClock::time_point
UptimeClock::now()
{
// start the update thread on first use
static const auto init = start_clock();
// Return the number of seconds since rippled start
return time_point{duration{now_}};
}
} // ripple

View File

@@ -1,82 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/basics/UptimeTimer.h>
#include <atomic>
namespace ripple {
UptimeTimer::UptimeTimer ()
: m_elapsedTime (0)
, m_startTime (::time (0))
, m_isUpdatingManually (false)
{
}
UptimeTimer::~UptimeTimer ()
{
}
int UptimeTimer::getElapsedSeconds () const
{
int result;
if (m_isUpdatingManually)
{
std::atomic_thread_fence (std::memory_order_seq_cst);
result = m_elapsedTime;
}
else
{
// VFALCO TODO use time_t instead of int return
result = static_cast <int> (::time (0) - m_startTime);
}
return result;
}
void UptimeTimer::beginManualUpdates ()
{
//assert (!m_isUpdatingManually);
m_isUpdatingManually = true;
}
void UptimeTimer::endManualUpdates ()
{
//assert (m_isUpdatingManually);
m_isUpdatingManually = false;
}
void UptimeTimer::incrementElapsedTime ()
{
//assert (m_isUpdatingManually);
++m_elapsedTime;
}
UptimeTimer& UptimeTimer::getInstance ()
{
static UptimeTimer instance;
return instance;
}
} // ripple

View File

@@ -20,6 +20,7 @@
#ifndef RIPPLE_CORE_LOADMONITOR_H_INCLUDED #ifndef RIPPLE_CORE_LOADMONITOR_H_INCLUDED
#define RIPPLE_CORE_LOADMONITOR_H_INCLUDED #define RIPPLE_CORE_LOADMONITOR_H_INCLUDED
#include <ripple/basics/UptimeClock.h>
#include <ripple/core/LoadEvent.h> #include <ripple/core/LoadEvent.h>
#include <ripple/beast/utility/Journal.h> #include <ripple/beast/utility/Journal.h>
#include <chrono> #include <chrono>
@@ -73,7 +74,7 @@ private:
std::chrono::milliseconds mLatencyMSPeak; std::chrono::milliseconds mLatencyMSPeak;
std::chrono::milliseconds mTargetLatencyAvg; std::chrono::milliseconds mTargetLatencyAvg;
std::chrono::milliseconds mTargetLatencyPk; std::chrono::milliseconds mTargetLatencyPk;
int mLastUpdate; UptimeClock::time_point mLastUpdate;
beast::Journal j_; beast::Journal j_;
}; };

View File

@@ -226,10 +226,9 @@ public:
@return `true` if we are stopping @return `true` if we are stopping
*/ */
template <class Rep, class Period>
bool bool
alertable_sleep_for( alertable_sleep_until(
std::chrono::duration<Rep, Period> const& d); std::chrono::system_clock::time_point const& t);
protected: protected:
/** Called by derived classes to indicate that the stoppable has stopped. */ /** Called by derived classes to indicate that the stoppable has stopped. */
@@ -373,10 +372,9 @@ public:
@return `true` if we are stopping @return `true` if we are stopping
*/ */
template <class Rep, class Period>
bool bool
alertable_sleep_for( alertable_sleep_until(
std::chrono::duration<Rep, Period> const& d); std::chrono::system_clock::time_point const& t);
private: private:
/* Notify a root stoppable and children to stop, without waiting. /* Notify a root stoppable and children to stop, without waiting.
@@ -407,23 +405,23 @@ JobCounter& Stoppable::jobCounter ()
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template <class Rep, class Period> inline
bool bool
RootStoppable::alertable_sleep_for( RootStoppable::alertable_sleep_until(
std::chrono::duration<Rep, Period> const& d) std::chrono::system_clock::time_point const& t)
{ {
std::unique_lock<std::mutex> lock(m_); std::unique_lock<std::mutex> lock(m_);
if (m_calledStop) if (m_calledStop)
return true; return true;
return c_.wait_for(lock, d, [this]{return m_calledStop.load();}); return c_.wait_until(lock, t, [this]{return m_calledStop.load();});
} }
template <class Rep, class Period> inline
bool bool
Stoppable::alertable_sleep_for( Stoppable::alertable_sleep_until(
std::chrono::duration<Rep, Period> const& d) std::chrono::system_clock::time_point const& t)
{ {
return m_root.alertable_sleep_for(d); return m_root.alertable_sleep_until(t);
} }
} // ripple } // ripple

View File

@@ -18,7 +18,7 @@
//============================================================================== //==============================================================================
#include <ripple/basics/Log.h> #include <ripple/basics/Log.h>
#include <ripple/basics/UptimeTimer.h> #include <ripple/basics/UptimeClock.h>
#include <ripple/basics/date.h> #include <ripple/basics/date.h>
#include <ripple/core/LoadMonitor.h> #include <ripple/core/LoadMonitor.h>
@@ -52,7 +52,7 @@ LoadMonitor::LoadMonitor (beast::Journal j)
, mLatencyMSPeak (0) , mLatencyMSPeak (0)
, mTargetLatencyAvg (0) , mTargetLatencyAvg (0)
, mTargetLatencyPk (0) , mTargetLatencyPk (0)
, mLastUpdate (UptimeTimer::getInstance ().getElapsedSeconds ()) , mLastUpdate (UptimeClock::now())
, j_ (j) , j_ (j)
{ {
} }
@@ -66,12 +66,12 @@ LoadMonitor::LoadMonitor (beast::Journal j)
void LoadMonitor::update () void LoadMonitor::update ()
{ {
using namespace std::chrono_literals; using namespace std::chrono_literals;
int now = UptimeTimer::getInstance ().getElapsedSeconds (); auto now = UptimeClock::now();
if (now == mLastUpdate) // current if (now == mLastUpdate) // current
return; return;
// VFALCO TODO Why 8? // VFALCO TODO Why 8?
if ((now < mLastUpdate) || (now > (mLastUpdate + 8))) if ((now < mLastUpdate) || (now > (mLastUpdate + 8s)))
{ {
// way out of date // way out of date
mCounts = 0; mCounts = 0;
@@ -93,7 +93,7 @@ void LoadMonitor::update ()
*/ */
do do
{ {
++mLastUpdate; mLastUpdate += 1s;
mCounts -= ((mCounts + 3) / 4); mCounts -= ((mCounts + 3) / 4);
mLatencyEvents -= ((mLatencyEvents + 3) / 4); mLatencyEvents -= ((mLatencyEvents + 3) / 4);
mLatencyMSAvg -= (mLatencyMSAvg / 4); mLatencyMSAvg -= (mLatencyMSAvg / 4);

View File

@@ -30,7 +30,7 @@
#include <ripple/app/misc/ValidatorList.h> #include <ripple/app/misc/ValidatorList.h>
#include <ripple/app/tx/apply.h> #include <ripple/app/tx/apply.h>
#include <ripple/basics/random.h> #include <ripple/basics/random.h>
#include <ripple/basics/UptimeTimer.h> #include <ripple/basics/UptimeClock.h>
#include <ripple/beast/core/LexicalCast.h> #include <ripple/beast/core/LexicalCast.h>
#include <ripple/beast/core/SemanticVersion.h> #include <ripple/beast/core/SemanticVersion.h>
#include <ripple/nodestore/DatabaseShard.h> #include <ripple/nodestore/DatabaseShard.h>
@@ -1864,7 +1864,7 @@ PeerImp::doFetchPack (const std::shared_ptr<protocol::TMGetObjectByHash>& packet
memcpy (hash.begin (), packet->ledgerhash ().data (), 32); memcpy (hash.begin (), packet->ledgerhash ().data (), 32);
std::weak_ptr<PeerImp> weak = shared_from_this(); std::weak_ptr<PeerImp> weak = shared_from_this();
auto elapsed = UptimeTimer::getInstance().getElapsedSeconds(); auto elapsed = UptimeClock::now();
auto const pap = &app_; auto const pap = &app_;
app_.getJobQueue ().addJob ( app_.getJobQueue ().addJob (
jtPACK, "MakeFetchPack", jtPACK, "MakeFetchPack",

View File

@@ -22,7 +22,7 @@
#include <ripple/app/ledger/LedgerMaster.h> #include <ripple/app/ledger/LedgerMaster.h>
#include <ripple/app/main/Application.h> #include <ripple/app/main/Application.h>
#include <ripple/app/misc/NetworkOPs.h> #include <ripple/app/misc/NetworkOPs.h>
#include <ripple/basics/UptimeTimer.h> #include <ripple/basics/UptimeClock.h>
#include <ripple/core/DatabaseCon.h> #include <ripple/core/DatabaseCon.h>
#include <ripple/json/json_value.h> #include <ripple/json/json_value.h>
#include <ripple/ledger/CachedSLEs.h> #include <ripple/ledger/CachedSLEs.h>
@@ -36,10 +36,11 @@
namespace ripple { namespace ripple {
static static
void textTime ( void
std::string& text, int& seconds, const char* unitName, int unitVal) textTime(std::string& text, UptimeClock::time_point& seconds,
const char* unitName, std::chrono::seconds unitVal)
{ {
int i = seconds / unitVal; auto i = seconds.time_since_epoch() / unitVal;
if (i == 0) if (i == 0)
return; return;
@@ -111,12 +112,12 @@ Json::Value doGetCounts (RPC::Context& context)
ret[jss::treenode_track_size] = context.app.family().treecache().getTrackSize(); ret[jss::treenode_track_size] = context.app.family().treecache().getTrackSize();
std::string uptime; std::string uptime;
int s = UptimeTimer::getInstance ().getElapsedSeconds (); auto s = UptimeClock::now();
textTime (uptime, s, "year", 365 * 24 * 60 * 60); textTime (uptime, s, "year", 365 * 24h);
textTime (uptime, s, "day", 24 * 60 * 60); textTime (uptime, s, "day", 24h);
textTime (uptime, s, "hour", 60 * 60); textTime (uptime, s, "hour", 1h);
textTime (uptime, s, "minute", 60); textTime (uptime, s, "minute", 1min);
textTime (uptime, s, "second", 1); textTime (uptime, s, "second", 1s);
ret[jss::uptime] = uptime; ret[jss::uptime] = uptime;
ret[jss::node_writes] = context.app.getNodeStore().getStoreCount(); ret[jss::node_writes] = context.app.getNodeStore().getStoreCount();

View File

@@ -30,7 +30,7 @@
#include <ripple/basics/impl/strHex.cpp> #include <ripple/basics/impl/strHex.cpp>
#include <ripple/basics/impl/StringUtilities.cpp> #include <ripple/basics/impl/StringUtilities.cpp>
#include <ripple/basics/impl/Sustain.cpp> #include <ripple/basics/impl/Sustain.cpp>
#include <ripple/basics/impl/UptimeTimer.cpp> #include <ripple/basics/impl/UptimeClock.cpp>
#if DOXYGEN #if DOXYGEN
#include <ripple/basics/README.md> #include <ripple/basics/README.md>