mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-03 16:56:48 +00:00
183 lines
4.2 KiB
C++
183 lines
4.2 KiB
C++
#include <xrpl/core/LoadMonitor.h>
|
|
|
|
#include <xrpl/basics/Log.h>
|
|
#include <xrpl/basics/UptimeClock.h>
|
|
#include <xrpl/beast/utility/Journal.h>
|
|
#include <xrpl/core/LoadEvent.h>
|
|
|
|
#include <chrono>
|
|
#include <mutex>
|
|
|
|
namespace xrpl {
|
|
|
|
/*
|
|
|
|
TODO
|
|
----
|
|
|
|
- Use Journal for logging
|
|
|
|
*/
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
LoadMonitor::Stats::Stats() : latencyAvg(0), latencyPeak(0)
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
LoadMonitor::LoadMonitor(beast::Journal j)
|
|
: mLatencyMSAvg(0)
|
|
, mLatencyMSPeak(0)
|
|
, mTargetLatencyAvg(0)
|
|
, mTargetLatencyPk(0)
|
|
, mLastUpdate(UptimeClock::now())
|
|
, j_(j)
|
|
{
|
|
}
|
|
|
|
// VFALCO NOTE WHY do we need "the mutex?" This dependence on
|
|
// a hidden global, especially a synchronization primitive,
|
|
// is a flawed design.
|
|
// It's not clear exactly which data needs to be protected.
|
|
//
|
|
// call with the mutex
|
|
void
|
|
LoadMonitor::update()
|
|
{
|
|
using namespace std::chrono_literals;
|
|
auto now = UptimeClock::now();
|
|
if (now == mLastUpdate) // current
|
|
return;
|
|
|
|
// VFALCO TODO Why 8?
|
|
if ((now < mLastUpdate) || (now > (mLastUpdate + 8s)))
|
|
{
|
|
// way out of date
|
|
mCounts = 0;
|
|
mLatencyEvents = 0;
|
|
mLatencyMSAvg = 0ms;
|
|
mLatencyMSPeak = 0ms;
|
|
mLastUpdate = now;
|
|
return;
|
|
}
|
|
|
|
// do exponential decay
|
|
/*
|
|
David:
|
|
|
|
"Imagine if you add 10 to something every second. And you
|
|
also reduce it by 1/4 every second. It will "idle" at 40,
|
|
corresponding to 10 counts per second."
|
|
*/
|
|
do
|
|
{
|
|
mLastUpdate += 1s;
|
|
mCounts -= ((mCounts + 3) / 4);
|
|
mLatencyEvents -= ((mLatencyEvents + 3) / 4);
|
|
mLatencyMSAvg -= (mLatencyMSAvg / 4);
|
|
mLatencyMSPeak -= (mLatencyMSPeak / 4);
|
|
} while (mLastUpdate < now);
|
|
}
|
|
|
|
void
|
|
LoadMonitor::addLoadSample(LoadEvent const& s)
|
|
{
|
|
using namespace std::chrono;
|
|
|
|
auto const total = s.runTime() + s.waitTime();
|
|
// Don't include "jitter" as part of the latency
|
|
auto const latency = total < 2ms ? 0ms : round<milliseconds>(total);
|
|
|
|
if (latency > 500ms)
|
|
{
|
|
auto mj = (latency > 1s) ? j_.warn() : j_.info();
|
|
JLOG(mj) << "Job: " << s.name() << " run: " << round<milliseconds>(s.runTime()).count()
|
|
<< "ms"
|
|
<< " wait: " << round<milliseconds>(s.waitTime()).count() << "ms";
|
|
}
|
|
|
|
addSamples(1, latency);
|
|
}
|
|
|
|
/* Add multiple samples
|
|
@param count The number of samples to add
|
|
@param latencyMS The total number of milliseconds
|
|
*/
|
|
void
|
|
LoadMonitor::addSamples(int count, std::chrono::milliseconds latency)
|
|
{
|
|
std::scoped_lock const sl(mutex_);
|
|
|
|
update();
|
|
mCounts += count;
|
|
mLatencyEvents += count;
|
|
mLatencyMSAvg += latency;
|
|
mLatencyMSPeak += latency;
|
|
|
|
auto const latencyPeak = mLatencyEvents * latency * 4 / count;
|
|
|
|
if (mLatencyMSPeak < latencyPeak)
|
|
mLatencyMSPeak = latencyPeak;
|
|
}
|
|
|
|
void
|
|
LoadMonitor::setTargetLatency(std::chrono::milliseconds avg, std::chrono::milliseconds pk)
|
|
{
|
|
mTargetLatencyAvg = avg;
|
|
mTargetLatencyPk = pk;
|
|
}
|
|
|
|
bool
|
|
LoadMonitor::isOverTarget(std::chrono::milliseconds avg, std::chrono::milliseconds peak)
|
|
{
|
|
using namespace std::chrono_literals;
|
|
return (mTargetLatencyPk > 0ms && (peak > mTargetLatencyPk)) ||
|
|
(mTargetLatencyAvg > 0ms && (avg > mTargetLatencyAvg));
|
|
}
|
|
|
|
bool
|
|
LoadMonitor::isOver()
|
|
{
|
|
std::scoped_lock const sl(mutex_);
|
|
|
|
update();
|
|
|
|
if (mLatencyEvents == 0)
|
|
return false;
|
|
|
|
return isOverTarget(
|
|
mLatencyMSAvg / (mLatencyEvents * 4), mLatencyMSPeak / (mLatencyEvents * 4));
|
|
}
|
|
|
|
LoadMonitor::Stats
|
|
LoadMonitor::getStats()
|
|
{
|
|
using namespace std::chrono_literals;
|
|
Stats stats;
|
|
|
|
std::scoped_lock const sl(mutex_);
|
|
|
|
update();
|
|
|
|
stats.count = mCounts / 4;
|
|
|
|
if (mLatencyEvents == 0)
|
|
{
|
|
stats.latencyAvg = 0ms;
|
|
stats.latencyPeak = 0ms;
|
|
}
|
|
else
|
|
{
|
|
stats.latencyAvg = mLatencyMSAvg / (mLatencyEvents * 4);
|
|
stats.latencyPeak = mLatencyMSPeak / (mLatencyEvents * 4);
|
|
}
|
|
|
|
stats.isOverloaded = isOverTarget(stats.latencyAvg, stats.latencyPeak);
|
|
|
|
return stats;
|
|
}
|
|
|
|
} // namespace xrpl
|