1#include <xrpl/beast/asio/io_latency_probe.h>
2#include <xrpl/beast/test/yield_to.h>
3#include <xrpl/beast/unit_test/suite.h>
5#include <boost/asio/basic_waitable_timer.hpp>
6#include <boost/asio/executor_work_guard.hpp>
7#include <boost/asio/io_context.hpp>
8#include <boost/asio/spawn.hpp>
9#include <boost/system/detail/error_code.hpp>
23using namespace std::chrono_literals;
27 using MyTimer = boost::asio::basic_waitable_timer<std::chrono::steady_clock>;
29#ifdef XRPL_RUNNING_IN_CI
37 template <
class Clock,
class MeasureClock = std::chrono::high_resolution_clock>
38 struct MeasureAsioTimers
40 using duration = Clock::duration;
41 using rep = MeasureClock::duration::rep;
45 MeasureAsioTimers(duration interval = 100ms,
size_t numSamples = 50)
48 boost::asio::io_context
ios;
50 work{boost::asio::make_work_guard(
ios)};
52 boost::asio::basic_waitable_timer<Clock> timer{
ios};
53 elapsedTimes.
reserve(numSamples);
58 boost::system::error_code waitErr;
60 while (--numSamples > 0u)
62 auto const start{MeasureClock::now()};
64 timer.expires_after(interval);
65 timer.async_wait([&](boost::system::error_code
const& ec) {
68 auto const end{MeasureClock::now()};
74 cv.
wait(mainlock, [&done] {
return done; });
79 boost::asio::detail::throw_error(waitErr,
"wait");
87 for (
auto const& v : elapsedTimes)
91 return sum / elapsedTimes.size();
133 operator()(std::chrono::steady_clock::duration
const& elapsed)
143 boost::system::error_code ec;
147 timer.async_wait(yield[ec]);
148 if (!BEAST_EXPECTS(!ec, ec.message()))
158 boost::system::error_code ec;
160 auto interval = 99ms;
161 auto probeDuration = 1s;
163 size_t const expectedProbeCountMax = (probeDuration / interval);
165 size_t expectedProbeCountMin = expectedProbeCountMax;
166#ifdef XRPL_RUNNING_IN_CI
169 MeasureAsioTimers<steady_clock> tt{interval};
170 log <<
"measured mean for timers: " << tt.getMean<
milliseconds>() <<
"ms\n";
171 log <<
"measured max for timers: " << tt.getMax<
milliseconds>() <<
"ms\n";
172 expectedProbeCountMin =
179 timer.async_wait(yield[ec]);
180 if (!BEAST_EXPECTS(!ec, ec.message()))
184 probesSeen >= (expectedProbeCountMin - 1) && probesSeen <= (expectedProbeCountMax + 1),
189 timer.expires_after(1s);
190 timer.async_wait(yield[ec]);
207 yieldTo([&](boost::asio::yield_context& yield) {
215BEAST_DEFINE_TESTSUITE(io_latency_probe,
beast,
beast);
Measures handler latency on an io_context queue.
Mix-in to support tests using asio coroutines.
boost::asio::io_context & getIoContext()
Return the io_context associated with the object.
void yieldTo(F0 &&f0, FN &&... fn)
Run one or more functions, each in a coroutine.
bool except(F &&f, String const &reason)
LogOs< char > log
Logging output stream.
TestcaseT testcase
Memberspace for declaring test cases.
boost::asio::basic_waitable_timer< std::chrono::steady_clock > MyTimer
void testCanceled(boost::asio::yield_context &yield)
void testSampleOngoing(boost::asio::yield_context &yield)
void run() override
Runs the suite.
void testSampleOne(boost::asio::yield_context &yield)
T duration_cast(T... args)
T emplace_back(T... args)
TestSampler(std::chrono::milliseconds interval, boost::asio::io_context &ios)
std::vector< std::chrono::steady_clock::duration > durations
void operator()(std::chrono::steady_clock::duration const &elapsed)
beast::IOLatencyProbe< std::chrono::steady_clock > probe