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#include <boost/asio/basic_waitable_timer.hpp>
25#include <boost/asio/io_service.hpp>
26
27#include <chrono>
28#include <condition_variable>
29#include <mutex>
30#include <stdexcept>
31
32namespace beast {
33
35template <class Clock>
37{
38private:
39 using duration = typename Clock::duration;
40 using time_point = typename Clock::time_point;
41
46 boost::asio::io_service& m_ios;
47 boost::asio::basic_waitable_timer<std::chrono::steady_clock> m_timer;
49
50public:
51 io_latency_probe(duration const& period, boost::asio::io_service& ios)
52 : m_count(1)
53 , m_period(period)
54 , m_ios(ios)
55 , m_timer(m_ios)
56 , m_cancel(false)
57 {
58 }
59
61 {
62 std::unique_lock<decltype(m_mutex)> lock(m_mutex);
63 cancel(lock, true);
64 }
65
68 boost::asio::io_service&
70 {
71 return m_ios;
72 }
73
74 boost::asio::io_service const&
76 {
77 return m_ios;
78 }
85 void
87 {
88 std::unique_lock<decltype(m_mutex)> lock(m_mutex);
89 cancel(lock, true);
90 }
91
92 void
94 {
95 std::unique_lock<decltype(m_mutex)> lock(m_mutex);
96 cancel(lock, false);
97 }
104 template <class Handler>
105 void
106 sample_one(Handler&& handler)
107 {
109 if (m_cancel)
110 throw std::logic_error("io_latency_probe is canceled");
112 std::forward<Handler>(handler), Clock::now(), false, this));
113 }
114
119 template <class Handler>
120 void
121 sample(Handler&& handler)
122 {
124 if (m_cancel)
125 throw std::logic_error("io_latency_probe is canceled");
127 std::forward<Handler>(handler), Clock::now(), true, this));
128 }
129
130private:
131 void
132 cancel(std::unique_lock<decltype(m_mutex)>& lock, bool wait)
133 {
134 if (!m_cancel)
135 {
136 --m_count;
137 m_cancel = true;
138 }
139
140 if (wait)
141 m_cond.wait(lock, [this] { return this->m_count == 0; });
142 }
143
144 void
146 {
148 ++m_count;
149 }
150
151 void
153 {
155 if (--m_count == 0)
157 }
158
159 template <class Handler>
161 {
162 Handler m_handler;
166
168 Handler const& handler,
169 time_point const& start,
170 bool repeat,
171 io_latency_probe* probe)
172 : m_handler(handler)
173 , m_start(start)
174 , m_repeat(repeat)
175 , m_probe(probe)
176 {
177 XRPL_ASSERT(
178 m_probe,
179 "beast::io_latency_probe::sample_op::sample_op : non-null "
180 "probe input");
181 m_probe->addref();
182 }
183
184 sample_op(sample_op&& from) noexcept
185 : m_handler(std::move(from.m_handler))
186 , m_start(from.m_start)
187 , m_repeat(from.m_repeat)
188 , m_probe(from.m_probe)
189 {
190 XRPL_ASSERT(
191 m_probe,
192 "beast::io_latency_probe::sample_op::sample_op(sample_op&&) : "
193 "non-null probe input");
194 from.m_probe = nullptr;
195 }
196
197 sample_op(sample_op const&) = delete;
199 operator=(sample_op const&) = delete;
200 sample_op&
201 operator=(sample_op&&) = delete;
202
204 {
205 if (m_probe)
206 m_probe->release();
207 }
208
209 void
211 {
212 if (!m_probe)
213 return;
214 typename Clock::time_point const now(Clock::now());
215 typename Clock::duration const elapsed(now - m_start);
216
217 m_handler(elapsed);
218
219 {
221 if (m_probe->m_cancel)
222 return;
223 }
224
225 if (m_repeat)
226 {
227 // Calculate when we want to sample again, and
228 // adjust for the expected latency.
229 //
230 typename Clock::time_point const when(
231 now + m_probe->m_period - 2 * elapsed);
232
233 if (when <= now)
234 {
235 // The latency is too high to maintain the desired
236 // period so don't bother with a timer.
237 //
238 m_probe->m_ios.post(
240 }
241 else
242 {
243 m_probe->m_timer.expires_from_now(when - now);
244 m_probe->m_timer.async_wait(
246 }
247 }
248 }
249
250 void
251 operator()(boost::system::error_code const& ec)
252 {
253 if (!m_probe)
254 return;
255 typename Clock::time_point const now(Clock::now());
256 m_probe->m_ios.post(
258 }
259 };
260};
261
262} // namespace beast
263
264#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