19#include <xrpl/beast/asio/io_latency_probe.h>
20#include <xrpl/beast/unit_test.h>
22#include <xrpl/beast/test/yield_to.h>
24#include <boost/asio/basic_waitable_timer.hpp>
25#include <boost/asio/deadline_timer.hpp>
26#include <boost/asio/io_service.hpp>
36using namespace std::chrono_literals;
42 boost::asio::basic_waitable_timer<std::chrono::steady_clock>;
44#ifdef RIPPLED_RUNNING_IN_CI
55 struct measure_asio_timers
57 using duration =
typename Clock::duration;
58 using rep =
typename MeasureClock::duration::rep;
62 measure_asio_timers(duration interval = 100ms,
size_t num_samples = 50)
65 boost::asio::io_service ios;
68 boost::asio::basic_waitable_timer<Clock> timer{ios};
69 elapsed_times_.
reserve(num_samples);
74 boost::system::error_code wait_err;
78 auto const start{MeasureClock::now()};
80 timer.expires_after(interval);
81 timer.async_wait([&](boost::system::error_code
const& ec) {
84 auto const end{MeasureClock::now()};
90 cv.
wait(mainlock, [&done] {
return done; });
95 boost::asio::detail::throw_error(wait_err,
"wait");
103 for (
auto const& v : elapsed_times_)
105 sum +=
static_cast<double>(
106 std::chrono::duration_cast<D>(v).count());
108 return sum / elapsed_times_.size();
115 return std::chrono::duration_cast<D>(
117 elapsed_times_.
begin(), elapsed_times_.
end()))
125 return std::chrono::duration_cast<D>(
127 elapsed_times_.
begin(), elapsed_times_.
end()))
140 boost::asio::io_service& ios)
158 operator()(std::chrono::steady_clock::duration
const& elapsed)
168 boost::system::error_code ec;
170 io_probe.start_one();
172 timer.async_wait(yield[ec]);
173 if (!BEAST_EXPECTS(!ec, ec.message()))
175 BEAST_EXPECT(io_probe.durations_.size() == 1);
176 io_probe.probe_.cancel_async();
183 boost::system::error_code ec;
185 auto interval = 99ms;
186 auto probe_duration = 1s;
188 size_t expected_probe_count_max = (probe_duration / interval);
189 size_t expected_probe_count_min = expected_probe_count_max;
190#ifdef RIPPLED_RUNNING_IN_CI
193 measure_asio_timers<steady_clock> tt{interval};
198 expected_probe_count_min =
200 duration_cast<milliseconds>(probe_duration).count()) /
206 timer.async_wait(yield[ec]);
207 if (!BEAST_EXPECTS(!ec, ec.message()))
209 auto probes_seen = io_probe.durations_.size();
211 probes_seen >= (expected_probe_count_min - 1) &&
212 probes_seen <= (expected_probe_count_max + 1),
214 io_probe.probe_.cancel_async();
217 timer.expires_from_now(1s);
218 timer.async_wait(yield[ec]);
226 io_probe.probe_.cancel_async();
227 except<std::logic_error>([&io_probe]() { io_probe.start_one(); });
228 except<std::logic_error>([&io_probe]() { io_probe.start(); });
235 yield_to([&](boost::asio::yield_context& yield) {
243BEAST_DEFINE_TESTSUITE(io_latency_probe, asio,
beast);
Measures handler latency on an io_service queue.
void sample(Handler &&handler)
Initiate continuous i/o latency sampling.
void sample_one(Handler &&handler)
Measure one sample of i/o latency.
Mix-in to support tests using asio coroutines.
void yield_to(F0 &&f0, FN &&... fn)
Run one or more functions, each in a coroutine.
boost::asio::io_service & get_io_service()
Return the io_service associated with the object.
log_os< char > log
Logging output stream.
testcase_t 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 emplace_back(T... args)
void operator()(std::chrono::steady_clock::duration const &elapsed)
test_sampler(std::chrono::milliseconds interval, boost::asio::io_service &ios)
beast::io_latency_probe< std::chrono::steady_clock > probe_
std::vector< std::chrono::steady_clock::duration > durations_