fix8  version 1.4.0
Open Source C++ FIX Framework
timer.hpp
Go to the documentation of this file.
1 //-------------------------------------------------------------------------------------------------
2 /*
3 
4 Fix8 is released under the GNU LESSER GENERAL PUBLIC LICENSE Version 3.
5 
6 Fix8 Open Source FIX Engine.
7 Copyright (C) 2010-16 David L. Dight <fix@fix8.org>
8 
9 Fix8 is free software: you can redistribute it and / or modify it under the terms of the
10 GNU Lesser General Public License as published by the Free Software Foundation, either
11 version 3 of the License, or (at your option) any later version.
12 
13 Fix8 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
14 even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 You should have received a copy of the GNU Lesser General Public License along with Fix8.
17 If not, see <http://www.gnu.org/licenses/>.
18 
19 BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO
20 THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE
21 COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY
22 KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO
24 THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
25 YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
26 
27 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT
28 HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED
29 ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
30 CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
31 NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR
32 THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH
33 HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
34 
35 */
36 //-------------------------------------------------------------------------------------------------
37 #ifndef FIX8_TIMER_HPP_
38 #define FIX8_TIMER_HPP_
39 
40 //-------------------------------------------------------------------------------------------------
41 #include <iomanip>
42 #include <queue>
43 #ifdef _MSC_VER
44 #include <time.h>
45 #else
46 #include <sys/time.h>
47 #endif
48 
49 //-------------------------------------------------------------------------------------------------
50 namespace FIX8
51 {
52 
53 //-------------------------------------------------------------------------------------------------
54 template<typename T>
55 class Timer;
56 
58 
59 template<typename T>
61 {
62  bool (T::*_callback)();
63  Tickval _t {};
64  unsigned _intervalMS = 0;
65  bool _repeat;
66 
67 public:
72  explicit TimerEvent(bool (T::*callback)(), bool repeat=false) : _callback(callback), _repeat(repeat) {}
73 
76 
79  void set(const Tickval& t) { _t = t; }
80 
84  bool operator<(const TimerEvent<T>& right) const { return _t > right._t; };
85 
86  friend class Timer<T>;
87 };
88 
89 //-------------------------------------------------------------------------------------------------
91 
92 template<typename T>
93 class Timer
94 {
98  unsigned _granularity;
99 
100  std::priority_queue<TimerEvent<T>> _event_queue;
102 
103 public:
107  explicit Timer(T& monitor, int granularity=10) : _monitor(monitor), _thread(std::ref(*this)), _granularity(granularity) {}
108 
110  virtual ~Timer()
111  {
112  stop();
113  join();
114  }
115 
120  bool schedule(TimerEvent<T> what, unsigned timeToWaitMS);
121 
124  size_t clear();
125 
127  void join() { _thread.join(); }
128 
130  void start() { _thread.start(); }
131 
133  void stop() { _thread.request_stop(); }
134 
137  int operator()();
138 
140 };
141 
142 //-------------------------------------------------------------------------------------------------
143 template<typename T>
145 {
146  unsigned elapsed(0);
147 
148  while(!_cancellation_token)
149  {
150  bool shouldsleep(false);
151  {
152  f8_scoped_spin_lock guard(_spin_lock);
153 
154  if (_event_queue.size())
155  {
156  TimerEvent<T> op(_event_queue.top());
157  if (!op._t) // ignore empty timeval
158  {
159  _event_queue.pop(); // remove from queue
160  continue;
161  }
162 
163  const Tickval now(Tickval::get_tickval());
164  if (op._t <= now) // has elapsed
165  {
166  TimerEvent<T> rop(_event_queue.top()); // take a copy
167  _event_queue.pop(); // remove from queue
168  ++elapsed;
169  const bool result((_monitor.*rop._callback)());
170  if (result && op._repeat) // don't repeat if callback returned false
171  {
172  op._t = now.get_ticks() + op._intervalMS * Tickval::million;
173  _event_queue.push(std::move(op)); // push back on queue
174  }
175  }
176  else
177  shouldsleep = true;
178  }
179  else
180  shouldsleep = true;
181  } // we want the lock to go out of scope before we sleep
182 
183  if (shouldsleep)
184  hypersleep<h_milliseconds>(_granularity);
185  }
186 
187  glout_info << "Terminating Timer thread (" << elapsed << " elapsed, " << _event_queue.size() << " queued).";
188  return 0;
189 }
190 
191 //-------------------------------------------------------------------------------------------------
192 template<typename T>
194 {
195  size_t result(0);
196  f8_scoped_spin_lock guard(_spin_lock);
197 
198  while (_event_queue.size())
199  {
200  ++result;
201  _event_queue.pop(); // remove from queue
202  }
203 
204  return result;
205 }
206 
207 //-------------------------------------------------------------------------------------------------
208 template<typename T>
209 bool Timer<T>::schedule(TimerEvent<T> what, unsigned timeToWait)
210 {
211  Tickval tofire;
212 
213  if (timeToWait)
214  {
215  // Calculate time to fire
216  Tickval::get_tickval(tofire);
217  tofire += timeToWait * Tickval::million;
218  what._intervalMS = timeToWait;
219  }
220 
221  what.set(tofire);
222  f8_scoped_spin_lock guard(_spin_lock);
223  _event_queue.push(std::move(what));
224 
225  return true;
226 }
227 
228 //---------------------------------------------------------------------------------------------------
229 #if defined __x86_64__ && (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__))
230 #define HAVE_RDTSC
231 inline Tickval::ticks rdtsc()
232 {
233  uint32_t high, low;
234  __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
235  return (static_cast<Tickval::ticks>(high) << 32) + static_cast<Tickval::ticks>(low);
236 }
237 #endif
238 
239 //---------------------------------------------------------------------------------------------------
242 {
243 #if defined FIX8_USE_RDTSC && defined FIX8_HAVE_RDTSC
245 #else
247 #endif
248 
249 public:
251 #if defined FIX8_USE_RDTSC && defined FIX8_HAVE_RDTSC
252  IntervalTimer() : startTime_(rdtsc()) {}
253 #else
254  IntervalTimer() : startTime_(true) {}
255 #endif
256 
258  virtual ~IntervalTimer() {}
259 
263  {
264 #if defined FIX8_USE_RDTSC && defined FIX8_HAVE_RDTSC
265  Tickval::ticks now(rdtsc());
266 #else
267  Tickval now(true);
268 #endif
269  delta_ = now - startTime_;
270  return *this;
271  }
272 
275 #if defined FIX8_USE_RDTSC && defined FIX8_HAVE_RDTSC
276  double AsDouble() const { return delta_; }
277 #else
278  double AsDouble() const { return delta_.todouble(); }
279 #endif
280 
283  double Reset()
284  {
285 #if defined FIX8_USE_RDTSC && defined FIX8_HAVE_RDTSC
286  const Tickval::ticks curr(delta_);
287  startTime_ = rdtsc();
288 #else
289  const double curr(AsDouble());
290  startTime_.now();
291 #endif
292  return curr;
293  }
294 
299  friend std::ostream& operator<<(std::ostream& os, const IntervalTimer& what)
300  {
301  std::ostringstream ostr;
302  ostr.setf(std::ios::showpoint);
303  ostr.setf(std::ios::fixed);
304 #if defined FIX8_USE_RDTSC && defined FIX8_HAVE_RDTSC
305  ostr << std::setprecision(9) << what;
306 #else
307  ostr << std::setprecision(9) << what.AsDouble();
308 #endif
309  return os << ostr.str();
310  }
311 };
312 
313 } // FIX8
314 
315 #endif // FIX8_TIMER_HPP_
const IntervalTimer & Calculate()
Definition: timer.hpp:262
virtual ~IntervalTimer()
Dtor.
Definition: timer.hpp:258
static const ticks million
Definition: tickval.hpp:76
static Tickval get_tickval()
Definition: tickval.hpp:191
TimerEvent(bool(T::*callback)(), bool repeat=false)
Definition: timer.hpp:72
f8_spin_lock _spin_lock
Definition: timer.hpp:97
friend std::ostream & operator<<(std::ostream &os, const IntervalTimer &what)
Definition: timer.hpp:299
int operator()()
Definition: timer.hpp:144
~TimerEvent()
Dtor.
Definition: timer.hpp:75
f8_thread_cancellation_token _cancellation_token
Definition: timer.hpp:101
High resolution timer.
Definition: timer.hpp:55
Thread wrapper. Ctor provides T instance and specifies ptr to member to call or defaults to operator(...
Definition: thread.hpp:245
f8_thread_cancellation_token & cancellation_token()
Definition: timer.hpp:139
Timer(T &monitor, int granularity=10)
Definition: timer.hpp:107
Thread cancellation token.
Definition: thread.hpp:206
double Reset()
Definition: timer.hpp:283
Tickval startTime_
Definition: timer.hpp:246
virtual int join(int timeoutInMs=0)
Definition: thread.hpp:126
IntervalTimer()
Ctor. RAII.
Definition: timer.hpp:254
int hypersleep< h_milliseconds >(unsigned amt)
Definition: hypersleep.hpp:105
size_t clear()
Definition: timer.hpp:193
void set(const Tickval &t)
Definition: timer.hpp:79
virtual ~Timer()
Dtor.
Definition: timer.hpp:110
void stop()
Stop the timer thread.
Definition: timer.hpp:133
Tickval & now()
Definition: tickval.hpp:133
#define glout_info
Definition: logger.hpp:601
Tickval _t
Definition: timer.hpp:63
void request_stop()
Definition: thread.hpp:293
decltype(f8_time_point::min().time_since_epoch().count()) ticks
Definition: tickval.hpp:66
generic spin_lock wrapper
Definition: thread.hpp:364
double AsDouble() const
Definition: timer.hpp:278
Timer event object to provide callback context with Timer.
Definition: timer.hpp:60
std::priority_queue< TimerEvent< T > > _event_queue
Definition: timer.hpp:100
bool schedule(TimerEvent< T > what, unsigned timeToWaitMS)
Definition: timer.hpp:209
void join()
Join timer thread. Wait till exits.
Definition: timer.hpp:127
unsigned _intervalMS
Definition: timer.hpp:64
unsigned _granularity
Definition: timer.hpp:98
bool(T::* _callback)()
Definition: timer.hpp:62
void start()
Start the timer thread.
Definition: timer.hpp:130
double todouble() const
Definition: tickval.hpp:166
ticks get_ticks() const
Definition: tickval.hpp:129
f8_thread< Timer > _thread
Definition: timer.hpp:96
T & _monitor
Definition: timer.hpp:95
High resolution interval timer.
Definition: timer.hpp:241