19 #include <ripple/beast/asio/io_latency_probe.h>
20 #include <ripple/beast/unit_test.h>
21 #include <boost/asio/basic_waitable_timer.hpp>
22 #include <boost/asio/deadline_timer.hpp>
23 #include <boost/asio/io_service.hpp>
24 #include <boost/optional.hpp>
26 #include <beast/test/yield_to.hpp>
33 using namespace std::chrono_literals;
36 public beast::test::enable_yield_to
39 boost::asio::basic_waitable_timer<std::chrono::steady_clock>;
41 #ifdef RIPPLED_RUNNING_IN_CI
52 struct measure_asio_timers
54 using duration =
typename Clock::duration;
55 using rep =
typename MeasureClock::duration::rep;
59 measure_asio_timers(duration interval = 100ms,
size_t num_samples = 50)
62 boost::asio::io_service ios;
63 boost::optional<boost::asio::io_service::work> work{ios};
65 boost::asio::basic_waitable_timer<Clock> timer{ios};
66 elapsed_times_.
reserve(num_samples);
71 boost::system::error_code wait_err;
75 auto const start{MeasureClock::now()};
77 timer.expires_after(interval);
78 timer.async_wait([&](boost::system::error_code
const& ec) {
81 auto const end{MeasureClock::now()};
87 cv.
wait(mainlock, [&done] {
return done; });
92 boost::asio::detail::throw_error(wait_err,
"wait");
100 for (
auto const& v : elapsed_times_)
102 sum +=
static_cast<double>(
103 std::chrono::duration_cast<D>(v).count());
105 return sum / elapsed_times_.size();
112 return std::chrono::duration_cast<D>(
114 elapsed_times_.
begin(), elapsed_times_.
end()))
122 return std::chrono::duration_cast<D>(
124 elapsed_times_.
begin(), elapsed_times_.
end()))
137 boost::asio::io_service& ios)
138 : probe_(interval, ios)
155 operator()(std::chrono::steady_clock::duration
const& elapsed)
164 testcase <<
"sample one";
165 boost::system::error_code ec;
168 MyTimer timer{get_io_service(), 1s};
169 timer.async_wait(yield[ec]);
170 if (!BEAST_EXPECTS(!ec, ec.message()))
172 BEAST_EXPECT(io_probe.durations_.size() == 1);
173 io_probe.probe_.cancel_async();
179 testcase <<
"sample ongoing";
180 boost::system::error_code ec;
182 auto interval = 99ms;
183 auto probe_duration = 1s;
185 size_t expected_probe_count_max = (probe_duration / interval);
186 size_t expected_probe_count_min = expected_probe_count_max;
187 #ifdef RIPPLED_RUNNING_IN_CI
190 measure_asio_timers<steady_clock> tt{interval};
195 expected_probe_count_min =
197 duration_cast<milliseconds>(probe_duration).count()) /
200 log <<
"expected_probe_count_min: " << expected_probe_count_min <<
"\n";
201 log <<
"expected_probe_count_max: " << expected_probe_count_max <<
"\n";
205 MyTimer timer{get_io_service(), probe_duration};
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]);
224 testcase <<
"canceled";
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) {
236 testSampleOne(yield);
237 testSampleOngoing(yield);