rippled
Loading...
Searching...
No Matches
io_latency_probe.h
1#ifndef BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED
2#define BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED
3
4#include <xrpl/beast/utility/instrumentation.h>
5
6#include <boost/asio/basic_waitable_timer.hpp>
7#include <boost/asio/io_context.hpp>
8#include <boost/asio/post.hpp>
9
10#include <chrono>
11#include <condition_variable>
12#include <mutex>
13#include <stdexcept>
14
15namespace beast {
16
18template <class Clock>
20{
21private:
22 using duration = typename Clock::duration;
23 using time_point = typename Clock::time_point;
24
29 boost::asio::io_context& m_ios;
30 boost::asio::basic_waitable_timer<std::chrono::steady_clock> m_timer;
32
33public:
34 io_latency_probe(duration const& period, boost::asio::io_context& ios)
35 : m_count(1)
36 , m_period(period)
37 , m_ios(ios)
38 , m_timer(m_ios)
39 , m_cancel(false)
40 {
41 }
42
44 {
45 std::unique_lock<decltype(m_mutex)> lock(m_mutex);
46 cancel(lock, true);
47 }
48
51 boost::asio::io_context&
53 {
54 return m_ios;
55 }
56
57 boost::asio::io_context const&
59 {
60 return m_ios;
61 }
68 void
70 {
71 std::unique_lock<decltype(m_mutex)> lock(m_mutex);
72 cancel(lock, true);
73 }
74
75 void
77 {
78 std::unique_lock<decltype(m_mutex)> lock(m_mutex);
79 cancel(lock, false);
80 }
87 template <class Handler>
88 void
89 sample_one(Handler&& handler)
90 {
92 if (m_cancel)
93 throw std::logic_error("io_latency_probe is canceled");
94 boost::asio::post(
95 m_ios,
97 std::forward<Handler>(handler), Clock::now(), false, this));
98 }
99
104 template <class Handler>
105 void
106 sample(Handler&& handler)
107 {
109 if (m_cancel)
110 throw std::logic_error("io_latency_probe is canceled");
111 boost::asio::post(
112 m_ios,
114 std::forward<Handler>(handler), Clock::now(), true, this));
115 }
116
117private:
118 void
119 cancel(std::unique_lock<decltype(m_mutex)>& lock, bool wait)
120 {
121 if (!m_cancel)
122 {
123 --m_count;
124 m_cancel = true;
125 }
126
127 if (wait)
128 m_cond.wait(lock, [this] { return this->m_count == 0; });
129 }
130
131 void
133 {
135 ++m_count;
136 }
137
138 void
140 {
142 if (--m_count == 0)
144 }
145
146 template <class Handler>
148 {
149 Handler m_handler;
153
155 Handler const& handler,
156 time_point const& start,
157 bool repeat,
158 io_latency_probe* probe)
159 : m_handler(handler)
160 , m_start(start)
161 , m_repeat(repeat)
162 , m_probe(probe)
163 {
164 XRPL_ASSERT(
165 m_probe,
166 "beast::io_latency_probe::sample_op::sample_op : non-null "
167 "probe input");
168 m_probe->addref();
169 }
170
171 sample_op(sample_op&& from) noexcept
172 : m_handler(std::move(from.m_handler))
173 , m_start(from.m_start)
174 , m_repeat(from.m_repeat)
175 , m_probe(from.m_probe)
176 {
177 XRPL_ASSERT(
178 m_probe,
179 "beast::io_latency_probe::sample_op::sample_op(sample_op&&) : "
180 "non-null probe input");
181 from.m_probe = nullptr;
182 }
183
184 sample_op(sample_op const&) = delete;
186 operator=(sample_op const&) = delete;
187 sample_op&
188 operator=(sample_op&&) = delete;
189
191 {
192 if (m_probe)
193 m_probe->release();
194 }
195
196 void
198 {
199 if (!m_probe)
200 return;
201 typename Clock::time_point const now(Clock::now());
202 typename Clock::duration const elapsed(now - m_start);
203
204 m_handler(elapsed);
205
206 {
208 if (m_probe->m_cancel)
209 return;
210 }
211
212 if (m_repeat)
213 {
214 // Calculate when we want to sample again, and
215 // adjust for the expected latency.
216 //
217 typename Clock::time_point const when(
218 now + m_probe->m_period - 2 * elapsed);
219
220 if (when <= now)
221 {
222 // The latency is too high to maintain the desired
223 // period so don't bother with a timer.
224 //
225 boost::asio::post(
226 m_probe->m_ios,
228 }
229 else
230 {
231 m_probe->m_timer.expires_after(when - now);
232 m_probe->m_timer.async_wait(
234 }
235 }
236 }
237
238 void
239 operator()(boost::system::error_code const& ec)
240 {
241 if (!m_probe)
242 return;
243 typename Clock::time_point const now(Clock::now());
244 boost::asio::post(
245 m_probe->m_ios,
247 }
248 };
249};
250
251} // namespace beast
252
253#endif
Measures handler latency on an io_context queue.
void sample(Handler &&handler)
Initiate continuous i/o latency sampling.
std::recursive_mutex m_mutex
boost::asio::basic_waitable_timer< std::chrono::steady_clock > m_timer
void cancel()
Cancel all pending i/o.
boost::asio::io_context const & get_io_context() const
void sample_one(Handler &&handler)
Measure one sample of i/o latency.
typename Clock::duration duration
boost::asio::io_context & get_io_context()
Return the io_context associated with the latency probe.
boost::asio::io_context & m_ios
void cancel(std::unique_lock< decltype(m_mutex)> &lock, bool wait)
std::condition_variable_any m_cond
io_latency_probe(duration const &period, boost::asio::io_context &ios)
typename Clock::time_point time_point
T is_same_v
sample_op(Handler const &handler, time_point const &start, bool repeat, io_latency_probe *probe)
sample_op operator=(sample_op const &)=delete
sample_op & operator=(sample_op &&)=delete
sample_op(sample_op &&from) noexcept
void operator()(boost::system::error_code const &ec)
sample_op(sample_op const &)=delete