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,
51  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& get_io_service ()
69  {
70  return m_ios;
71  }
72 
73  boost::asio::io_service const& get_io_service () const
74  {
75  return m_ios;
76  }
83  void cancel ()
84  {
85  std::unique_lock <decltype(m_mutex)> lock (m_mutex);
86  cancel (lock, true);
87  }
88 
89  void cancel_async ()
90  {
91  std::unique_lock <decltype(m_mutex)> lock (m_mutex);
92  cancel (lock, false);
93  }
100  template <class Handler>
101  void sample_one (Handler&& handler)
102  {
103  std::lock_guard lock (m_mutex);
104  if (m_cancel)
105  throw std::logic_error ("io_latency_probe is canceled");
106  m_ios.post (sample_op <Handler> (
107  std::forward <Handler> (handler),
108  Clock::now(), false, this));
109  }
110 
115  template <class Handler>
116  void sample (Handler&& handler)
117  {
118  std::lock_guard lock (m_mutex);
119  if (m_cancel)
120  throw std::logic_error ("io_latency_probe is canceled");
121  m_ios.post (sample_op <Handler> (
122  std::forward <Handler> (handler),
123  Clock::now(), true, this));
124  }
125 
126 private:
127  void cancel (std::unique_lock <decltype (m_mutex)>& lock,
128  bool wait)
129  {
130  if (! m_cancel)
131  {
132  --m_count;
133  m_cancel = true;
134  }
135 
136  if (wait)
137 #ifdef BOOST_NO_CXX11_LAMBDAS
138  while (m_count != 0)
139  m_cond.wait (lock);
140 #else
141  m_cond.wait (lock, [this] {
142  return this->m_count == 0; });
143 #endif
144  }
145 
146  void addref ()
147  {
148  std::lock_guard lock (m_mutex);
149  ++m_count;
150  }
151 
152  void release ()
153  {
154  std::lock_guard lock (m_mutex);
155  if (--m_count == 0)
156  m_cond.notify_all ();
157  }
158 
159  template <class Handler>
160  struct sample_op
161  {
162  Handler m_handler;
164  bool m_repeat;
166 
167  sample_op (Handler const& handler, time_point const& start,
168  bool repeat, io_latency_probe* probe)
169  : m_handler (handler)
170  , m_start (start)
171  , m_repeat (repeat)
172  , m_probe (probe)
173  {
174  assert(m_probe);
175  m_probe->addref();
176  }
177 
178  sample_op (sample_op&& from) noexcept
179  : m_handler (std::move(from.m_handler))
180  , m_start (from.m_start)
181  , m_repeat (from.m_repeat)
182  , m_probe (from.m_probe)
183  {
184  assert(m_probe);
185  from.m_probe = nullptr;
186  }
187 
188  sample_op (sample_op const&) = delete;
189  sample_op operator= (sample_op const&) = delete;
190  sample_op& operator= (sample_op&&) = delete;
191 
193  {
194  if(m_probe)
195  m_probe->release();
196  }
197 
198  void operator() () const
199  {
200  if (!m_probe)
201  return;
202  typename Clock::time_point const now (Clock::now());
203  typename Clock::duration const elapsed (now - m_start);
204 
205  m_handler (elapsed);
206 
207  {
209  if (m_probe->m_cancel)
210  return;
211  }
212 
213  if (m_repeat)
214  {
215  // Calculate when we want to sample again, and
216  // adjust for the expected latency.
217  //
218  typename Clock::time_point const when (
219  now + m_probe->m_period - 2 * elapsed);
220 
221  if (when <= now)
222  {
223  // The latency is too high to maintain the desired
224  // period so don't bother with a timer.
225  //
227  m_handler, now, m_repeat, m_probe));
228  }
229  else
230  {
231  m_probe->m_timer.expires_from_now(when - now);
232  m_probe->m_timer.async_wait (sample_op <Handler> (
233  m_handler, now, m_repeat, m_probe));
234  }
235  }
236  }
237 
238  void operator () (boost::system::error_code const& ec)
239  {
240  if (!m_probe)
241  return;
242  typename Clock::time_point const now (Clock::now());
244  m_handler, now, m_repeat, m_probe));
245  }
246  };
247 };
248 
249 }
250 
251 #endif
beast::io_latency_probe::sample_op::~sample_op
~sample_op()
Definition: io_latency_probe.h:192
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:198
beast::io_latency_probe::sample_op::m_handler
Handler m_handler
Definition: io_latency_probe.h:162
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:165
beast::io_latency_probe::sample_op::m_start
time_point m_start
Definition: io_latency_probe.h:163
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:178
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: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:152
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:116
beast::io_latency_probe::cancel
void cancel(std::unique_lock< decltype(m_mutex)> &lock, bool wait)
Definition: io_latency_probe.h:127
beast::io_latency_probe::sample_one
void sample_one(Handler &&handler)
Measure one sample of i/o latency.
Definition: io_latency_probe.h:101
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:164
beast::io_latency_probe::cancel
void cancel()
Cancel all pending i/o.
Definition: io_latency_probe.h:83
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:60
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:167
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:146
beast::io_latency_probe::cancel_async
void cancel_async()
Definition: io_latency_probe.h:89
mutex
beast::io_latency_probe::sample_op
Definition: io_latency_probe.h:160
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:582