rippled
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 <boost/asio/basic_waitable_timer.hpp>
24 #include <boost/asio/io_service.hpp>
25 #include <boost/config.hpp>
26 #include <chrono>
27 #include <condition_variable>
28 #include <mutex>
29 #include <stdexcept>
30 
31 namespace beast {
32 
34 template <class Clock>
36 {
37 private:
38  using duration = typename Clock::duration;
39  using time_point = typename Clock::time_point;
40 
45  boost::asio::io_service& m_ios;
46  boost::asio::basic_waitable_timer<std::chrono::steady_clock> m_timer;
47  bool m_cancel;
48 
49 public:
50  io_latency_probe(duration const& period, boost::asio::io_service& ios)
51  : m_count(1)
52  , m_period(period)
53  , m_ios(ios)
54  , m_timer(m_ios)
55  , m_cancel(false)
56  {
57  }
58 
60  {
61  std::unique_lock<decltype(m_mutex)> lock(m_mutex);
62  cancel(lock, true);
63  }
64 
67  boost::asio::io_service&
69  {
70  return m_ios;
71  }
72 
73  boost::asio::io_service const&
75  {
76  return m_ios;
77  }
84  void
86  {
87  std::unique_lock<decltype(m_mutex)> lock(m_mutex);
88  cancel(lock, true);
89  }
90 
91  void
93  {
94  std::unique_lock<decltype(m_mutex)> lock(m_mutex);
95  cancel(lock, false);
96  }
103  template <class Handler>
104  void
105  sample_one(Handler&& handler)
106  {
107  std::lock_guard lock(m_mutex);
108  if (m_cancel)
109  throw std::logic_error("io_latency_probe is canceled");
110  m_ios.post(sample_op<Handler>(
111  std::forward<Handler>(handler), Clock::now(), false, this));
112  }
113 
118  template <class Handler>
119  void
120  sample(Handler&& handler)
121  {
122  std::lock_guard lock(m_mutex);
123  if (m_cancel)
124  throw std::logic_error("io_latency_probe is canceled");
125  m_ios.post(sample_op<Handler>(
126  std::forward<Handler>(handler), Clock::now(), true, this));
127  }
128 
129 private:
130  void
131  cancel(std::unique_lock<decltype(m_mutex)>& lock, bool wait)
132  {
133  if (!m_cancel)
134  {
135  --m_count;
136  m_cancel = true;
137  }
138 
139  if (wait)
140 #ifdef BOOST_NO_CXX11_LAMBDAS
141  while (m_count != 0)
142  m_cond.wait(lock);
143 #else
144  m_cond.wait(lock, [this] { return this->m_count == 0; });
145 #endif
146  }
147 
148  void
150  {
151  std::lock_guard lock(m_mutex);
152  ++m_count;
153  }
154 
155  void
157  {
158  std::lock_guard lock(m_mutex);
159  if (--m_count == 0)
160  m_cond.notify_all();
161  }
162 
163  template <class Handler>
164  struct sample_op
165  {
166  Handler m_handler;
168  bool m_repeat;
170 
172  Handler const& handler,
173  time_point const& start,
174  bool repeat,
175  io_latency_probe* probe)
176  : m_handler(handler)
177  , m_start(start)
178  , m_repeat(repeat)
179  , m_probe(probe)
180  {
181  assert(m_probe);
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  assert(m_probe);
192  from.m_probe = nullptr;
193  }
194 
195  sample_op(sample_op const&) = delete;
196  sample_op
197  operator=(sample_op const&) = delete;
198  sample_op&
199  operator=(sample_op&&) = delete;
200 
202  {
203  if (m_probe)
204  m_probe->release();
205  }
206 
207  void
208  operator()() const
209  {
210  if (!m_probe)
211  return;
212  typename Clock::time_point const now(Clock::now());
213  typename Clock::duration const elapsed(now - m_start);
214 
215  m_handler(elapsed);
216 
217  {
219  if (m_probe->m_cancel)
220  return;
221  }
222 
223  if (m_repeat)
224  {
225  // Calculate when we want to sample again, and
226  // adjust for the expected latency.
227  //
228  typename Clock::time_point const when(
229  now + m_probe->m_period - 2 * elapsed);
230 
231  if (when <= now)
232  {
233  // The latency is too high to maintain the desired
234  // period so don't bother with a timer.
235  //
236  m_probe->m_ios.post(
238  }
239  else
240  {
241  m_probe->m_timer.expires_from_now(when - now);
242  m_probe->m_timer.async_wait(
244  }
245  }
246  }
247 
248  void
249  operator()(boost::system::error_code const& ec)
250  {
251  if (!m_probe)
252  return;
253  typename Clock::time_point const now(Clock::now());
254  m_probe->m_ios.post(
256  }
257  };
258 };
259 
260 } // namespace beast
261 
262 #endif
beast::io_latency_probe::sample_op::~sample_op
~sample_op()
Definition: io_latency_probe.h:201
beast::io_latency_probe< std::chrono::steady_clock >::time_point
typename std::chrono::steady_clock ::time_point time_point
Definition: io_latency_probe.h:39
beast::io_latency_probe::sample_op::operator()
void operator()() const
Definition: io_latency_probe.h:208
beast::io_latency_probe::sample_op::m_handler
Handler m_handler
Definition: io_latency_probe.h:166
beast::io_latency_probe< std::chrono::steady_clock >::duration
typename std::chrono::steady_clock ::duration duration
Definition: io_latency_probe.h:38
beast::io_latency_probe::sample_op::m_probe
io_latency_probe * m_probe
Definition: io_latency_probe.h:169
beast::io_latency_probe::sample_op::m_start
time_point m_start
Definition: io_latency_probe.h:167
std::recursive_mutex
STL class.
std::lock_guard
STL class.
beast::io_latency_probe::get_io_service
boost::asio::io_service & get_io_service()
Return the io_service associated with the latency probe.
Definition: io_latency_probe.h:68
beast::io_latency_probe::sample_op::sample_op
sample_op(sample_op &&from) noexcept
Definition: io_latency_probe.h:185
beast::io_latency_probe::get_io_service
boost::asio::io_service const & get_io_service() const
Definition: io_latency_probe.h:74
beast::io_latency_probe::m_ios
boost::asio::io_service & m_ios
Definition: io_latency_probe.h:45
beast::io_latency_probe::m_cond
std::condition_variable_any m_cond
Definition: io_latency_probe.h:42
std::condition_variable_any
beast::io_latency_probe::m_period
const duration m_period
Definition: io_latency_probe.h:44
beast::io_latency_probe::m_cancel
bool m_cancel
Definition: io_latency_probe.h:47
stdexcept
beast::io_latency_probe::release
void release()
Definition: io_latency_probe.h:156
chrono
std::unique_lock
STL class.
beast::io_latency_probe::sample
void sample(Handler &&handler)
Initiate continuous i/o latency sampling.
Definition: io_latency_probe.h:120
beast::io_latency_probe::cancel
void cancel(std::unique_lock< decltype(m_mutex)> &lock, bool wait)
Definition: io_latency_probe.h:131
beast::io_latency_probe::sample_one
void sample_one(Handler &&handler)
Measure one sample of i/o latency.
Definition: io_latency_probe.h:105
std::logic_error
STL class.
std::condition_variable_any::wait
T wait(T... args)
beast::io_latency_probe
Measures handler latency on an io_service queue.
Definition: io_latency_probe.h:35
beast::io_latency_probe::sample_op::operator=
sample_op operator=(sample_op const &)=delete
beast::io_latency_probe::m_mutex
std::recursive_mutex m_mutex
Definition: io_latency_probe.h:41
beast::io_latency_probe::sample_op::m_repeat
bool m_repeat
Definition: io_latency_probe.h:168
beast::io_latency_probe::cancel
void cancel()
Cancel all pending i/o.
Definition: io_latency_probe.h:85
beast::io_latency_probe::sample_op::operator()
void operator()(boost::system::error_code const &ec)
Definition: io_latency_probe.h:249
beast::io_latency_probe::io_latency_probe
io_latency_probe(duration const &period, boost::asio::io_service &ios)
Definition: io_latency_probe.h:50
beast::io_latency_probe::~io_latency_probe
~io_latency_probe()
Definition: io_latency_probe.h:59
beast::io_latency_probe::sample_op::sample_op
sample_op(Handler const &handler, time_point const &start, bool repeat, io_latency_probe *probe)
Definition: io_latency_probe.h:171
beast::io_latency_probe::m_timer
boost::asio::basic_waitable_timer< std::chrono::steady_clock > m_timer
Definition: io_latency_probe.h:46
condition_variable
beast::io_latency_probe::addref
void addref()
Definition: io_latency_probe.h:149
beast::io_latency_probe::cancel_async
void cancel_async()
Definition: io_latency_probe.h:92
mutex
beast::io_latency_probe::sample_op
Definition: io_latency_probe.h:164
std::size_t
std::condition_variable_any::notify_all
T notify_all(T... args)
beast::io_latency_probe::m_count
std::size_t m_count
Definition: io_latency_probe.h:43
beast
Definition: base_uint.h:646