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_service.hpp>
27
28#include <chrono>
29#include <condition_variable>
30#include <mutex>
31#include <stdexcept>
32
33namespace beast {
34
36template <class Clock>
38{
39private:
40 using duration = typename Clock::duration;
41 using time_point = typename Clock::time_point;
42
47 boost::asio::io_service& m_ios;
48 boost::asio::basic_waitable_timer<std::chrono::steady_clock> m_timer;
50
51public:
52 io_latency_probe(duration const& period, boost::asio::io_service& ios)
53 : m_count(1)
54 , m_period(period)
55 , m_ios(ios)
56 , m_timer(m_ios)
57 , m_cancel(false)
58 {
59 }
60
62 {
63 std::unique_lock<decltype(m_mutex)> lock(m_mutex);
64 cancel(lock, true);
65 }
66
69 boost::asio::io_service&
71 {
72 return m_ios;
73 }
74
75 boost::asio::io_service const&
77 {
78 return m_ios;
79 }
86 void
88 {
89 std::unique_lock<decltype(m_mutex)> lock(m_mutex);
90 cancel(lock, true);
91 }
92
93 void
95 {
96 std::unique_lock<decltype(m_mutex)> lock(m_mutex);
97 cancel(lock, false);
98 }
105 template <class Handler>
106 void
107 sample_one(Handler&& handler)
108 {
110 if (m_cancel)
111 throw std::logic_error("io_latency_probe is canceled");
113 std::forward<Handler>(handler), Clock::now(), false, this));
114 }
115
120 template <class Handler>
121 void
122 sample(Handler&& handler)
123 {
125 if (m_cancel)
126 throw std::logic_error("io_latency_probe is canceled");
128 std::forward<Handler>(handler), Clock::now(), true, this));
129 }
130
131private:
132 void
133 cancel(std::unique_lock<decltype(m_mutex)>& lock, bool wait)
134 {
135 if (!m_cancel)
136 {
137 --m_count;
138 m_cancel = true;
139 }
140
141 if (wait)
142 m_cond.wait(lock, [this] { return this->m_count == 0; });
143 }
144
145 void
147 {
149 ++m_count;
150 }
151
152 void
154 {
156 if (--m_count == 0)
158 }
159
160 template <class Handler>
162 {
163 Handler m_handler;
167
169 Handler const& handler,
170 time_point const& start,
171 bool repeat,
172 io_latency_probe* probe)
173 : m_handler(handler)
174 , m_start(start)
175 , m_repeat(repeat)
176 , m_probe(probe)
177 {
178 XRPL_ASSERT(
179 m_probe,
180 "beast::io_latency_probe::sample_op::sample_op : non-null "
181 "probe input");
182 m_probe->addref();
183 }
184
185 sample_op(sample_op&& from) noexcept
186 : m_handler(std::move(from.m_handler))
187 , m_start(from.m_start)
188 , m_repeat(from.m_repeat)
189 , m_probe(from.m_probe)
190 {
191 XRPL_ASSERT(
192 m_probe,
193 "beast::io_latency_probe::sample_op::sample_op(sample_op&&) : "
194 "non-null probe input");
195 from.m_probe = nullptr;
196 }
197
198 sample_op(sample_op const&) = delete;
200 operator=(sample_op const&) = delete;
201 sample_op&
202 operator=(sample_op&&) = delete;
203
205 {
206 if (m_probe)
207 m_probe->release();
208 }
209
210 void
212 {
213 if (!m_probe)
214 return;
215 typename Clock::time_point const now(Clock::now());
216 typename Clock::duration const elapsed(now - m_start);
217
218 m_handler(elapsed);
219
220 {
222 if (m_probe->m_cancel)
223 return;
224 }
225
226 if (m_repeat)
227 {
228 // Calculate when we want to sample again, and
229 // adjust for the expected latency.
230 //
231 typename Clock::time_point const when(
232 now + m_probe->m_period - 2 * elapsed);
233
234 if (when <= now)
235 {
236 // The latency is too high to maintain the desired
237 // period so don't bother with a timer.
238 //
239 m_probe->m_ios.post(
241 }
242 else
243 {
244 m_probe->m_timer.expires_from_now(when - now);
245 m_probe->m_timer.async_wait(
247 }
248 }
249 }
250
251 void
252 operator()(boost::system::error_code const& ec)
253 {
254 if (!m_probe)
255 return;
256 typename Clock::time_point const now(Clock::now());
257 m_probe->m_ios.post(
259 }
260 };
261};
262
263} // namespace beast
264
265#endif
Measures handler latency on an io_service 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.
void sample_one(Handler &&handler)
Measure one sample of i/o latency.
typename Clock::duration duration
boost::asio::io_service & m_ios
void cancel(std::unique_lock< decltype(m_mutex)> &lock, bool wait)
std::condition_variable_any m_cond
boost::asio::io_service const & get_io_service() const
boost::asio::io_service & get_io_service()
Return the io_service associated with the latency probe.
typename Clock::time_point time_point
io_latency_probe(duration const &period, boost::asio::io_service &ios)
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