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