You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

timing.hpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. // timing.hpp
  2. //
  3. // Copyright (C) 2004-2020 MicroNeil Research Corporation.
  4. //
  5. // This software is released under the MIT license. See LICENSE.TXT.
  6. //
  7. // The purpose of this module is to abstract timing functions for
  8. // cross platform C++ development usning GNU compilers in *nix and
  9. // win32 environments (minGW). Timing resolution is in milliseconds
  10. // throughout to provide consistency and reasonable expectations.
  11. #pragma once
  12. namespace codedweller {
  13. ///////////////////////////////////////////////////////////////////////////////
  14. // class Sleeper - An object that remembers how long it is supposed to sleep.
  15. // This allows an application to create "standard" sleep timers that can be
  16. // established at the top of the code (easy to find) and reused.
  17. ///////////////////////////////////////////////////////////////////////////////
  18. static const int MinimumSleeperTime = 1; // Minimum msec allowed.
  19. static const int MaximumSleeperTime = 2000000000; // Maximum msec allowed.
  20. class Sleeper {
  21. private:
  22. int MillisecondsToSleep; // How long to sleep.
  23. void doRawSleep(int x); // Abstracted local sleep function.
  24. public:
  25. class BadSleeperValue {}; // Exception for bad values.
  26. Sleeper(); // Constructed empty - set to zero.
  27. Sleeper(int x); // Constructed with a value.
  28. int setMillisecondsToSleep(int x); // Safe way to set the vlaue.
  29. int getMillisecondsToSleep(); // Safe way to get the value.
  30. void sleep(); // Here's where we snooze if we can.
  31. void sleep(int x); // Shortcut - set the time and then sleep.
  32. void operator()();
  33. };
  34. /* Sleeper Documentation...
  35. **
  36. ** Sleeper.Sleeper()
  37. ** Constructs a Sleeper with a zero value.
  38. **
  39. ** Sleeper.Sleeper(int x)
  40. ** Constructs a Sleeper to "snooze" for x milliseconds.
  41. **
  42. ** Sleeper.setMillisecondsToSleep(int x)
  43. ** Sets the sleep time for the Sleeper and returns the time set.
  44. ** If the value is out of range then the Sleeper::BadSleeperValue will be thrown.
  45. **
  46. ** Sleeper.getMillisecondsToSleep()
  47. ** Returns the current MillisecondsToSleep.
  48. **
  49. ** Sleeper.sleep()
  50. ** Goes to sleep for MillisecondsToSleep. If MillisecondsToSleep has not been set
  51. ** then the function throws Sleeper::BadSleeperVlaue.
  52. **
  53. ** Sleeper.sleep(int x)
  54. ** First sets MillisecondsToSleep, then goes to sleep. If x is too big or too small
  55. ** then the method throws Sleeper::BadSleeperValue.
  56. */
  57. ///////////////////////////////////////////////////////////////////////////////
  58. // class PollTimer - An object to pause during polling processes where the
  59. // time between polls is expanded according to a Fibonacci sequence. This
  60. // allows self organizing automata to relax a bit when a particular process
  61. // is taking a long time so that the resources used in the polling process are
  62. // reduced if the system is under load - The idea is to prevent the polling
  63. // process from loading the system when there are many nodes poling, yet to
  64. // allow for a rapid response when there are few or when the answer we're
  65. // waiting for is ready quickly. We use a Fibonacci expansion because it is
  66. // a natural spiral.
  67. ///////////////////////////////////////////////////////////////////////////////
  68. class PollTimer {
  69. private:
  70. Sleeper mySleeper; // We need a sleeper to do this.
  71. int NominalPollTime; // Normal poll delay in msec.
  72. int MaximumPollTime; // Maximum poll delay in msec.
  73. bool LimitReached;
  74. // Why not use unsigned int everywhere? Because sometimes libraries use
  75. // int for their Sleep() functions... so we calculate with unsigned ints,
  76. // but we use ints for inputs to keep things sane. Wierd bugs show up if
  77. // signed ints overflow in clock_t values -- this learned by experience.
  78. unsigned int FibA; // One poll delay ago.
  79. unsigned int FibB; // Two poll delays ago.
  80. // FibA and FibB are used to generate the fibonacci expansion. The current
  81. // delay will always be the sum of the previous two delays assuming that
  82. // there was always a first delay of 1 x Nominal Poll time. This results
  83. // in an expansion like this: 1,2,3,5,8,13,21,34,...
  84. public:
  85. class BadPollTimerValue {}; // Exception for bad values.
  86. PollTimer(int Nom, int Max); // Construct with nominal and max delays.
  87. int setNominalPollTime(int Nom); // Set the Nominal Poll Time.
  88. int setMaximumPollTime(int Max); // Set the Maximum Poll Time.
  89. void reset(); // Reset the spiral.
  90. int pause(); // Pause between polls.
  91. };
  92. /* PollTimer Documentation...
  93. **
  94. ** PollTimer(nominal_delay, maximum_delay)
  95. ** Constructs a PollTimer and sets it's basic parameters. If the parameters are
  96. ** out of range then BadPollTimerValue will be thrown.
  97. **
  98. ** setNiminalPollTime(Nom)
  99. ** Sets the nominal (base unit) poll delay time. Throws BadPollTimerValue if
  100. ** the value is out of range.
  101. **
  102. ** setMaximumPollTime(Max)
  103. ** Sets the maximum (upper limit) poll delay. If the value is out of range then
  104. ** BadPollTimerValue is thrown.
  105. **
  106. ** reset()
  107. ** Resets the current poll delay to the nominal delay. The next call to pause()
  108. ** will sleep for the nominal delay. This method would normally be called when
  109. ** a poll cycle turns up some work to do so that subsequent poll delays will be
  110. ** short - leading to a responsive system.
  111. **
  112. ** pause()
  113. ** Calling this method will cause the current thread to sleep for the current
  114. ** poll delay time. Subsquent calls to pause will cause longer sleep times
  115. ** according to a natural spiral. An intervening call to reset() will shorten
  116. ** the delay times again. This method returns the number of milliseconds
  117. ** paused on this pass.
  118. */
  119. ///////////////////////////////////////////////////////////////////////////////
  120. // class Timer - This one acts much like a stop watch with millisecond
  121. // resolution. The time is based on wall-clock time using gettimeofday() or
  122. // GetSystemTimeAsFileTime depending on the OS.
  123. ///////////////////////////////////////////////////////////////////////////////
  124. typedef unsigned long long int msclock; // 64 bit int used for measuring time in ms.
  125. static msclock EPOCH_DELTA_IN_USEC = 11644473600000000ULL; // Microseconds difference between epochs.
  126. static msclock EPOCH_DELTA_IN_MSEC = EPOCH_DELTA_IN_USEC / 1000; // Milliseconds difference between epochs.
  127. class Timer {
  128. private:
  129. bool RunningFlag; // True if clock is running.
  130. msclock StartTime; // TimeOfDay at start.
  131. msclock StopTime; // TimeOfDay at stop or check.
  132. msclock getLocalRawClock() const; // Derives unix epoch ms from local clock.
  133. public:
  134. Timer(); // Construct and start the Timer.
  135. Timer(msclock startt); // Constructs and starts from a specific moment.
  136. void clear(); // Stop and set elapsed time to zero at now.
  137. msclock start(); // Re(set) the Start time to this moment.
  138. msclock start(msclock startt); // Re(set) the Start time to startt.
  139. msclock getStartClock(); // Return the unix epoch start clock.
  140. bool isRunning(); // Return true if the clock is running.
  141. msclock getElapsedTime() const; // get milliseconds since Timer start.
  142. msclock stop(); // Stop the Timer.
  143. msclock getStopClock(); // Return the unix epoch stop clock.
  144. double getElapsedSeconds()const; // Get floating point elapsed seconds.
  145. bool isUnixBased(); // True if base clock is unix/posix.
  146. msclock toWindowsEpoch(msclock unixt); // Converts unix t to windows t.
  147. msclock toUnixEpoch(msclock win32t); // Converts windows t to unix t.
  148. };
  149. /* Timer Documentation...
  150. **
  151. ** All raw clock values are returned as 64 bit unsigned integers using a special
  152. ** type - msclock. Conversions are done using microsecond accuracy.
  153. **
  154. ** Timer()
  155. ** Creates a new timer and starts the clock at this moment.
  156. **
  157. ** Timer(msclock startt)
  158. ** Creates a new timer and starts the clock at a specific moment. This can be
  159. ** used to start one clock precisely when another one ends as in:
  160. ** new Timer B(A.stop());
  161. **
  162. ** getLocalRawClock()
  163. ** This method uses slightly different code depending upon whether the system
  164. ** is a unix box or win32. In both cases the function determines the local time
  165. ** value as a 64bit integer with millisecond resolution using the unix epoch of
  166. ** Jan 1, 1970.
  167. **
  168. ** start()
  169. ** This method starts or restarts the Timer's clock at this moment.
  170. ** The msclock value for the start clock is returned.
  171. **
  172. ** start(msclock startt)
  173. ** This method starts or restarts the Timer's clock at the time specified
  174. ** int startt. This is used for chaining operations such as B.start(A.stop())
  175. **
  176. ** getStartClock()
  177. ** This method returns the start clock value.
  178. **
  179. ** isRunning()
  180. ** Returns true if the clock is running.
  181. **
  182. ** getElapsedTime()
  183. ** This method returns the elapsed time in milliseconds.
  184. ** If the clock is running this value will be different each time it is called.
  185. **
  186. ** stop()
  187. ** This method stops the clock and returns the stop clock value. If this method
  188. ** is called more than once then the stop clock is reset to the current time and
  189. ** that time is returned.
  190. **
  191. ** getStopClock()
  192. ** This method returns the stop clock value. If the Timer is still running
  193. ** then the result is the same as calling getElapsedTime(). If the clock is
  194. ** not running then the time the clock was last stopped is returned.
  195. **
  196. ** getElapsedSeconds()
  197. ** Returns the elapsed time as a floating point number with millisecond
  198. ** resolution.
  199. **
  200. ** isUnixBased()
  201. ** Returns true if the raw clock values are being derived from a unix/posix OS.
  202. **
  203. ** toWindowsEpoch(msclock unixt)
  204. ** Converts unixt to a windows value by adding the epoch delta.
  205. **
  206. ** toUnixEpoch(msclock win32t)
  207. ** Converts win32t to a unix value by subtracting the epoch delta.
  208. */
  209. ////////////////////////////////////////////////////////////////////////////////
  210. // class ScopeTimer - Runs a Timer while ScopeTimer is in scope.
  211. ////////////////////////////////////////////////////////////////////////////////
  212. class ScopeTimer { // Runs a timer when in scope.
  213. private:
  214. Timer& myTimer; // This is the timer to run.
  215. public:
  216. ScopeTimer(Timer& T) : myTimer(T) { myTimer.start(); } // The Timer starts at construction.
  217. ~ScopeTimer() { myTimer.stop(); } // The Timer stops at destruction.
  218. };
  219. ///////////////////////////////////////////////////////////////////////////////
  220. // class Timeout - This one uses a Timer to establish a timeout value.
  221. ///////////////////////////////////////////////////////////////////////////////
  222. class Timeout {
  223. private:
  224. Timer myTimer; // We need a timer to do this.
  225. msclock myDuration; // Milliseconds before timout expires.
  226. public:
  227. class BadTimeoutValue {}; // If the value is bad throw this.
  228. Timeout(msclock duration); // Create and set the duration.
  229. msclock setDuration(msclock duration); // Set/Change the duration in milliseconds.
  230. msclock getDuration(); // Return the current duration in milliseconds.
  231. msclock restart(); // Restart the timeout timer.
  232. msclock getElapsedTime(); // Get elapsed milliseconds.
  233. msclock getRemainingTime(); // Get remaining milliseconds.
  234. bool isExpired(); // Return true if time is up.
  235. };
  236. /* Timeout Documentation...
  237. **
  238. ** Timeout(int duration)
  239. ** Creates a Timout timer and sets the duration in milliseconds.
  240. **
  241. ** setDuration(int duration)
  242. ** Sets or changes the duration of the timeout timer.
  243. ** The Timout is NOT reset by this method. This allows you to change
  244. ** the timeout on the fly.
  245. **
  246. ** restart()
  247. ** Restarts the timeout timer.
  248. **
  249. ** getElapsedTime()
  250. ** Returns the number of milliseconds elapsed since the Timout was created
  251. ** or reset.
  252. **
  253. ** getRemainingTime()
  254. ** Returns the number of milliseconds remaining before time is up.
  255. **
  256. ** isExpired()
  257. ** Returns true if time is up.
  258. */
  259. } // End namespace codedweller