20#include <xrpl/beast/asio/io_latency_probe.h>
21#include <xrpl/beast/test/yield_to.h>
22#include <xrpl/beast/unit_test.h>
24#include <boost/asio/basic_waitable_timer.hpp>
25#include <boost/asio/deadline_timer.hpp>
26#include <boost/asio/io_service.hpp>
34using namespace std::chrono_literals;
40 boost::asio::basic_waitable_timer<std::chrono::steady_clock>;
42#ifdef RIPPLED_RUNNING_IN_CI
53 struct measure_asio_timers
55 using duration =
typename Clock::duration;
56 using rep =
typename MeasureClock::duration::rep;
60 measure_asio_timers(duration interval = 100ms,
size_t num_samples = 50)
63 boost::asio::io_service
ios;
66 boost::asio::basic_waitable_timer<Clock> timer{
ios};
67 elapsed_times_.
reserve(num_samples);
72 boost::system::error_code wait_err;
76 auto const start{MeasureClock::now()};
78 timer.expires_after(interval);
79 timer.async_wait([&](boost::system::error_code
const& ec) {
82 auto const end{MeasureClock::now()};
88 cv.
wait(mainlock, [&done] {
return done; });
93 boost::asio::detail::throw_error(wait_err,
"wait");
101 for (
auto const& v : elapsed_times_)
103 sum +=
static_cast<double>(
104 std::chrono::duration_cast<D>(v).count());
106 return sum / elapsed_times_.size();
113 return std::chrono::duration_cast<D>(
115 elapsed_times_.
begin(), elapsed_times_.
end()))
123 return std::chrono::duration_cast<D>(
125 elapsed_times_.
begin(), elapsed_times_.
end()))
138 boost::asio::io_service&
ios)
156 operator()(std::chrono::steady_clock::duration
const& elapsed)
166 boost::system::error_code ec;
168 io_probe.start_one();
170 timer.async_wait(yield[ec]);
171 if (!BEAST_EXPECTS(!ec, ec.message()))
173 BEAST_EXPECT(io_probe.durations_.size() == 1);
174 io_probe.probe_.cancel_async();
181 boost::system::error_code ec;
183 auto interval = 99ms;
184 auto probe_duration = 1s;
186 size_t expected_probe_count_max = (probe_duration / interval);
187 size_t expected_probe_count_min = expected_probe_count_max;
188#ifdef RIPPLED_RUNNING_IN_CI
191 measure_asio_timers<steady_clock> tt{interval};
196 expected_probe_count_min =
198 duration_cast<milliseconds>(probe_duration).count()) /
204 timer.async_wait(yield[ec]);
205 if (!BEAST_EXPECTS(!ec, ec.message()))
207 auto probes_seen = io_probe.durations_.size();
209 probes_seen >= (expected_probe_count_min - 1) &&
210 probes_seen <= (expected_probe_count_max + 1),
212 io_probe.probe_.cancel_async();
215 timer.expires_from_now(1s);
216 timer.async_wait(yield[ec]);
224 io_probe.probe_.cancel_async();
225 except<std::logic_error>([&io_probe]() { io_probe.start_one(); });
226 except<std::logic_error>([&io_probe]() { io_probe.start(); });
233 yield_to([&](boost::asio::yield_context& yield) {
241BEAST_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_