19 #include <ripple/beast/asio/io_latency_probe.h>
20 #include <ripple/beast/unit_test.h>
21 #include <beast/test/yield_to.hpp>
22 #include <boost/asio/basic_waitable_timer.hpp>
23 #include <boost/asio/deadline_timer.hpp>
24 #include <boost/asio/io_service.hpp>
25 #include <boost/optional.hpp>
34 using namespace std::chrono_literals;
37 public beast::unit_test::suite,
public beast::test::enable_yield_to
39 using MyTimer = boost::asio::basic_waitable_timer<std::chrono::steady_clock>;
41 #ifdef RIPPLED_RUNNING_IN_CI
49 template <
class Clock,
class MeasureClock = std::chrono::high_resolution_clock>
50 struct measure_asio_timers
52 using duration =
typename Clock::duration;
53 using rep =
typename MeasureClock::duration::rep;
57 measure_asio_timers(duration interval = 100ms,
size_t num_samples = 50)
60 boost::asio::io_service ios;
61 boost::optional<boost::asio::io_service::work> work {ios};
63 boost::asio::basic_waitable_timer<Clock> timer {ios};
64 elapsed_times_.
reserve (num_samples);
69 boost::system::error_code wait_err;
73 auto const start {MeasureClock::now()};
75 timer.expires_after (interval);
76 timer.async_wait ( [&] (boost::system::error_code
const& ec) {
79 auto const end {MeasureClock::now()};
85 cv.
wait(mainlock, [&done]{
return done;});
90 boost::asio::detail::throw_error(wait_err,
"wait");
97 for (
auto const& v : elapsed_times_)
99 sum +=
static_cast<double>(
100 std::chrono::duration_cast<D>(v).count());
102 return sum / elapsed_times_.size();
109 elapsed_times_.
begin(),elapsed_times_.
end())).count();
116 elapsed_times_.
begin(),elapsed_times_.
end())).count();
128 boost::asio::io_service& ios)
129 : probe_ (interval, ios)
145 void operator() (std::chrono::steady_clock::duration
const& elapsed)
154 testcase <<
"sample one";
155 boost::system::error_code ec;
158 MyTimer timer {get_io_service(), 1s};
159 timer.async_wait(yield[ec]);
160 if(! BEAST_EXPECTS(! ec, ec.message()))
162 BEAST_EXPECT(io_probe.durations_.size() == 1);
163 io_probe.probe_.cancel_async();
169 testcase <<
"sample ongoing";
170 boost::system::error_code ec;
172 auto interval = 99ms;
173 auto probe_duration = 1s;
175 size_t expected_probe_count_max = (probe_duration/interval);
176 size_t expected_probe_count_min = expected_probe_count_max;
177 #ifdef RIPPLED_RUNNING_IN_CI
180 measure_asio_timers<steady_clock> tt {interval};
181 log <<
"measured mean for timers: "
183 log <<
"measured max for timers: "
185 expected_probe_count_min =
187 duration_cast<milliseconds>(probe_duration).count())
190 log <<
"expected_probe_count_min: " << expected_probe_count_min <<
"\n";
191 log <<
"expected_probe_count_max: " << expected_probe_count_max <<
"\n";
195 MyTimer timer {get_io_service(), probe_duration};
196 timer.async_wait(yield[ec]);
197 if(! BEAST_EXPECTS(! ec, ec.message()))
199 auto probes_seen = io_probe.durations_.size();
201 probes_seen >= (expected_probe_count_min - 1) &&
202 probes_seen <= (expected_probe_count_max + 1),
204 io_probe.probe_.cancel_async();
207 timer.expires_from_now(1s);
208 timer.async_wait(yield[ec]);
214 testcase <<
"canceled";
217 except<std::logic_error>( [&io_probe](){ io_probe.start_one(); });
218 except<std::logic_error>( [&io_probe](){ io_probe.start(); });
224 yield_to([&](boost::asio::yield_context& yield)
226 testSampleOne (yield);
227 testSampleOngoing (yield);
228 testCanceled (yield);