rippled
Loading...
Searching...
No Matches
io_latency_probe.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of Beast: https://github.com/vinniefalco/Beast
4 Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#ifndef BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED
21#define BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED
22
23#include <xrpl/beast/utility/instrumentation.h>
24
25#include <boost/asio/basic_waitable_timer.hpp>
26#include <boost/asio/io_context.hpp>
27#include <boost/asio/post.hpp>
28
29#include <chrono>
30#include <condition_variable>
31#include <mutex>
32#include <stdexcept>
33
34namespace beast {
35
37template <class Clock>
39{
40private:
41 using duration = typename Clock::duration;
42 using time_point = typename Clock::time_point;
43
48 boost::asio::io_context& m_ios;
49 boost::asio::basic_waitable_timer<std::chrono::steady_clock> m_timer;
51
52public:
53 io_latency_probe(duration const& period, boost::asio::io_context& ios)
54 : m_count(1)
55 , m_period(period)
56 , m_ios(ios)
57 , m_timer(m_ios)
58 , m_cancel(false)
59 {
60 }
61
63 {
64 std::unique_lock<decltype(m_mutex)> lock(m_mutex);
65 cancel(lock, true);
66 }
67
70 boost::asio::io_context&
72 {
73 return m_ios;
74 }
75
76 boost::asio::io_context const&
78 {
79 return m_ios;
80 }
87 void
89 {
90 std::unique_lock<decltype(m_mutex)> lock(m_mutex);
91 cancel(lock, true);
92 }
93
94 void
96 {
97 std::unique_lock<decltype(m_mutex)> lock(m_mutex);
98 cancel(lock, false);
99 }
106 template <class Handler>
107 void
108 sample_one(Handler&& handler)
109 {
111 if (m_cancel)
112 throw std::logic_error("io_latency_probe is canceled");
113 boost::asio::post(
114 m_ios,
116 std::forward<Handler>(handler), Clock::now(), false, this));
117 }
118
123 template <class Handler>
124 void
125 sample(Handler&& handler)
126 {
128 if (m_cancel)
129 throw std::logic_error("io_latency_probe is canceled");
130 boost::asio::post(
131 m_ios,
133 std::forward<Handler>(handler), Clock::now(), true, this));
134 }
135
136private:
137 void
138 cancel(std::unique_lock<decltype(m_mutex)>& lock, bool wait)
139 {
140 if (!m_cancel)
141 {
142 --m_count;
143 m_cancel = true;
144 }
145
146 if (wait)
147 m_cond.wait(lock, [this] { return this->m_count == 0; });
148 }
149
150 void
152 {
154 ++m_count;
155 }
156
157 void
159 {
161 if (--m_count == 0)
163 }
164
165 template <class Handler>
167 {
168 Handler m_handler;
172
174 Handler const& handler,
175 time_point const& start,
176 bool repeat,
177 io_latency_probe* probe)
178 : m_handler(handler)
179 , m_start(start)
180 , m_repeat(repeat)
181 , m_probe(probe)
182 {
183 XRPL_ASSERT(
184 m_probe,
185 "beast::io_latency_probe::sample_op::sample_op : non-null "
186 "probe input");
187 m_probe->addref();
188 }
189
190 sample_op(sample_op&& from) noexcept
191 : m_handler(std::move(from.m_handler))
192 , m_start(from.m_start)
193 , m_repeat(from.m_repeat)
194 , m_probe(from.m_probe)
195 {
196 XRPL_ASSERT(
197 m_probe,
198 "beast::io_latency_probe::sample_op::sample_op(sample_op&&) : "
199 "non-null probe input");
200 from.m_probe = nullptr;
201 }
202
203 sample_op(sample_op const&) = delete;
205 operator=(sample_op const&) = delete;
206 sample_op&
207 operator=(sample_op&&) = delete;
208
210 {
211 if (m_probe)
212 m_probe->release();
213 }
214
215 void
217 {
218 if (!m_probe)
219 return;
220 typename Clock::time_point const now(Clock::now());
221 typename Clock::duration const elapsed(now - m_start);
222
223 m_handler(elapsed);
224
225 {
227 if (m_probe->m_cancel)
228 return;
229 }
230
231 if (m_repeat)
232 {
233 // Calculate when we want to sample again, and
234 // adjust for the expected latency.
235 //
236 typename Clock::time_point const when(
237 now + m_probe->m_period - 2 * elapsed);
238
239 if (when <= now)
240 {
241 // The latency is too high to maintain the desired
242 // period so don't bother with a timer.
243 //
244 boost::asio::post(
245 m_probe->m_ios,
247 }
248 else
249 {
250 m_probe->m_timer.expires_after(when - now);
251 m_probe->m_timer.async_wait(
253 }
254 }
255 }
256
257 void
258 operator()(boost::system::error_code const& ec)
259 {
260 if (!m_probe)
261 return;
262 typename Clock::time_point const now(Clock::now());
263 boost::asio::post(
264 m_probe->m_ios,
266 }
267 };
268};
269
270} // namespace beast
271
272#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