Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

timing.hpp 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. // timing.hpp
  2. //
  3. // Copyright (C) 2004-2009 MicroNeil Research Corporation.
  4. // This program is part of the MicroNeil Research Open Library Project. For
  5. // more information go to http://www.microneil.com/OpenLibrary/index.html
  6. //
  7. // This program is free software; you can redistribute it and/or modify it
  8. // under the terms of the GNU General Public License as published by the
  9. // Free Software Foundation; either version 2 of the License, or (at your
  10. // option) any later version.
  11. //
  12. // This program is distributed in the hope that it will be useful, but WITHOUT
  13. // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  15. // more details.
  16. //
  17. // You should have received a copy of the GNU General Public License along with
  18. // this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  19. // Place, Suite 330, Boston, MA 02111-1307 USA
  20. // The purpose of this module is to abstract timing functions for
  21. // cross platform C++ development usning GNU compilers in *nix and
  22. // win32 environments (minGW). Timing resolution is in milliseconds
  23. // throughout to provide consistency and reasonable expectations.
  24. // 20060404 _M Added Timer::start(msclock startt) for chaining.
  25. // 20060403 _M This "timing" module has been completed and tested on
  26. // win32 (compiled using CodeBlocks and minGW) and on RHES3 (g++).
  27. //
  28. // The bottom line is that this code is perfect for most applications that
  29. // don't need real-time interaction on the win32 platform. That is, for
  30. // any application that can accept 15ms or so of "wiggle" in their timing
  31. // functions. On linux I was able to observe very consistent results with
  32. // variations measured in 1-2ms.
  33. //
  34. // Aynone seeking real-time accuracy on the win32 platform will need to contend
  35. // with all of the landmines in place against that and will need to write more
  36. // ellaborate versions of Timer::getLocalRawClock() and Sleeper::doRawSleep()
  37. // aa appropriate for their application. The existing code should work fine for
  38. // almost all other applications.
  39. //
  40. // This code was written with that in mind to some extent. That is why all of
  41. // the timing functions are measured in milliseconds rather than microseconds
  42. // or something smaller. Milliseconds are convenient for polling delays,
  43. // communications timeouts, measuring database application performance, and
  44. // other similar tasks. For that purpose - this timing module is just fine :-)
  45. // 20060323 _M Rewrote this module from a combination of previous
  46. // bits and pieces. This module will provide classes that abstract
  47. // timing functions for use in GNU projects on *nix and win32 systems.
  48. #ifndef MNR_timing
  49. #define MNR_timing
  50. // Introduce the standard namespace ///////////////////////////////////////////
  51. using namespace std;
  52. ///////////////////////////////////////////////////////////////////////////////
  53. // class Sleeper - An object that remembers how long it is supposed to sleep.
  54. // This allows an application to create "standard" sleep timers that can be
  55. // established at the top of the code (easy to find) and reused.
  56. ///////////////////////////////////////////////////////////////////////////////
  57. static const int MinimumSleeperTime = 1; // Minimum msec allowed.
  58. static const int MaximumSleeperTime = 2000000000; // Maximum msec allowed.
  59. class Sleeper {
  60. private:
  61. int MillisecondsToSleep; // How long to sleep.
  62. void doRawSleep(int x); // Abstracted local sleep function.
  63. public:
  64. class BadSleeperValue {}; // Exception for bad values.
  65. Sleeper(); // Constructed empty - set to zero.
  66. Sleeper(int x); // Constructed with a value.
  67. int setMillisecondsToSleep(int x); // Safe way to set the vlaue.
  68. int getMillisecondsToSleep(); // Safe way to get the value.
  69. void sleep(); // Here's where we snooze if we can.
  70. void sleep(int x); // Shortcut - set the time and then sleep.
  71. void operator()();
  72. };
  73. /* Sleeper Documentation...
  74. **
  75. ** Sleeper.Sleeper()
  76. ** Constructs a Sleeper with a zero value.
  77. **
  78. ** Sleeper.Sleeper(int x)
  79. ** Constructs a Sleeper to "snooze" for x milliseconds.
  80. **
  81. ** Sleeper.setMillisecondsToSleep(int x)
  82. ** Sets the sleep time for the Sleeper and returns the time set.
  83. ** If the value is out of range then the Sleeper::BadSleeperValue will be thrown.
  84. **
  85. ** Sleeper.getMillisecondsToSleep()
  86. ** Returns the current MillisecondsToSleep.
  87. **
  88. ** Sleeper.sleep()
  89. ** Goes to sleep for MillisecondsToSleep. If MillisecondsToSleep has not been set
  90. ** then the function throws Sleeper::BadSleeperVlaue.
  91. **
  92. ** Sleeper.sleep(int x)
  93. ** First sets MillisecondsToSleep, then goes to sleep. If x is too big or too small
  94. ** then the method throws Sleeper::BadSleeperValue.
  95. */
  96. ///////////////////////////////////////////////////////////////////////////////
  97. // class PollTimer - An object to pause during polling processes where the
  98. // time between polls is expanded according to a Fibonacci sequence. This
  99. // allows self organizing automata to relax a bit when a particular process
  100. // is taking a long time so that the resources used in the polling process are
  101. // reduced if the system is under load - The idea is to prevent the polling
  102. // process from loading the system when there are many nodes poling, yet to
  103. // allow for a rapid response when there are few or when the answer we're
  104. // waiting for is ready quickly. We use a Fibonacci expansion because it is
  105. // a natural spiral.
  106. ///////////////////////////////////////////////////////////////////////////////
  107. class PollTimer {
  108. private:
  109. Sleeper mySleeper; // We need a sleeper to do this.
  110. int NominalPollTime; // Normal poll delay in msec.
  111. int MaximumPollTime; // Maximum poll delay in msec.
  112. bool LimitReached;
  113. // Why not use unsigned int everywhere? Because sometimes libraries use
  114. // int for their Sleep() functions... so we calculate with unsigned ints,
  115. // but we use ints for inputs to keep things sane. Wierd bugs show up if
  116. // signed ints overflow in clock_t values -- this learned by experience.
  117. unsigned int FibA; // One poll delay ago.
  118. unsigned int FibB; // Two poll delays ago.
  119. // FibA and FibB are used to generate the fibonacci expansion. The current
  120. // delay will always be the sum of the previous two delays assuming that
  121. // there was always a first delay of 1 x Nominal Poll time. This results
  122. // in an expansion like this: 1,2,3,5,8,13,21,34,...
  123. public:
  124. class BadPollTimerValue {}; // Exception for bad values.
  125. PollTimer(int Nom, int Max); // Construct with nominal and max delays.
  126. int setNominalPollTime(int Nom); // Set the Nominal Poll Time.
  127. int setMaximumPollTime(int Max); // Set the Maximum Poll Time.
  128. void reset(); // Reset the spiral.
  129. int pause(); // Pause between polls.
  130. };
  131. /* PollTimer Documentation...
  132. **
  133. ** PollTimer(nominal_delay, maximum_delay)
  134. ** Constructs a PollTimer and sets it's basic parameters. If the parameters are
  135. ** out of range then BadPollTimerValue will be thrown.
  136. **
  137. ** setNiminalPollTime(Nom)
  138. ** Sets the nominal (base unit) poll delay time. Throws BadPollTimerValue if
  139. ** the value is out of range.
  140. **
  141. ** setMaximumPollTime(Max)
  142. ** Sets the maximum (upper limit) poll delay. If the value is out of range then
  143. ** BadPollTimerValue is thrown.
  144. **
  145. ** reset()
  146. ** Resets the current poll delay to the nominal delay. The next call to pause()
  147. ** will sleep for the nominal delay. This method would normally be called when
  148. ** a poll cycle turns up some work to do so that subsequent poll delays will be
  149. ** short - leading to a responsive system.
  150. **
  151. ** pause()
  152. ** Calling this method will cause the current thread to sleep for the current
  153. ** poll delay time. Subsquent calls to pause will cause longer sleep times
  154. ** according to a natural spiral. An intervening call to reset() will shorten
  155. ** the delay times again. This method returns the number of milliseconds
  156. ** paused on this pass.
  157. */
  158. ///////////////////////////////////////////////////////////////////////////////
  159. // class Timer - This one acts much like a stop watch with millisecond
  160. // resolution. The time is based on wall-clock time using gettimeofday() or
  161. // GetSystemTimeAsFileTime depending on the OS.
  162. ///////////////////////////////////////////////////////////////////////////////
  163. typedef unsigned long long int msclock; // 64 bit int used for measuring time in ms.
  164. static msclock EPOCH_DELTA_IN_USEC = 11644473600000000ULL; // Microseconds difference between epochs.
  165. static msclock EPOCH_DELTA_IN_MSEC = EPOCH_DELTA_IN_USEC / 1000; // Milliseconds difference between epochs.
  166. class Timer {
  167. private:
  168. msclock StartTime; // TimeOfDay at start.
  169. msclock StopTime; // TimeOfDay at stop or check.
  170. bool RunningFlag; // True if clock is running.
  171. msclock getLocalRawClock() const; // Derives unix epoch ms from local clock.
  172. public:
  173. Timer(); // Construct and start the Timer.
  174. Timer(msclock startt); // Constructs and starts from a specific moment.
  175. void clear(); // Stop and set elapsed time to zero at now.
  176. msclock start(); // Re(set) the Start time to this moment.
  177. msclock start(msclock startt); // Re(set) the Start time to startt.
  178. msclock getStartClock(); // Return the unix epoch start clock.
  179. bool isRunning(); // Return true if the clock is running.
  180. msclock getElapsedTime() const; // get milliseconds since Timer start.
  181. msclock stop(); // Stop the Timer.
  182. msclock getStopClock(); // Return the unix epoch stop clock.
  183. double getElapsedSeconds()const; // Get floating point elapsed seconds.
  184. bool isUnixBased(); // True if base clock is unix/posix.
  185. msclock toWindowsEpoch(msclock unixt); // Converts unix t to windows t.
  186. msclock toUnixEpoch(msclock win32t); // Converts windows t to unix t.
  187. };
  188. /* Timer Documentation...
  189. **
  190. ** All raw clock values are returned as 64 bit unsigned integers using a special
  191. ** type - msclock. Conversions are done using microsecond accuracy.
  192. **
  193. ** Timer()
  194. ** Creates a new timer and starts the clock at this moment.
  195. **
  196. ** Timer(msclock startt)
  197. ** Creates a new timer and starts the clock at a specific moment. This can be
  198. ** used to start one clock precisely when another one ends as in:
  199. ** new Timer B(A.stop());
  200. **
  201. ** getLocalRawClock()
  202. ** This method uses slightly different code depending upon whether the system
  203. ** is a unix box or win32. In both cases the function determines the local time
  204. ** value as a 64bit integer with millisecond resolution using the unix epoch of
  205. ** Jan 1, 1970.
  206. **
  207. ** start()
  208. ** This method starts or restarts the Timer's clock at this moment.
  209. ** The msclock value for the start clock is returned.
  210. **
  211. ** start(msclock startt)
  212. ** This method starts or restarts the Timer's clock at the time specified
  213. ** int startt. This is used for chaining operations such as B.start(A.stop())
  214. **
  215. ** getStartClock()
  216. ** This method returns the start clock value.
  217. **
  218. ** isRunning()
  219. ** Returns true if the clock is running.
  220. **
  221. ** getElapsedTime()
  222. ** This method returns the elapsed time in milliseconds.
  223. ** If the clock is running this value will be different each time it is called.
  224. **
  225. ** stop()
  226. ** This method stops the clock and returns the stop clock value. If this method
  227. ** is called more than once then the stop clock is reset to the current time and
  228. ** that time is returned.
  229. **
  230. ** getStopClock()
  231. ** This method returns the stop clock value. If the Timer is still running
  232. ** then the result is the same as calling getElapsedTime(). If the clock is
  233. ** not running then the time the clock was last stopped is returned.
  234. **
  235. ** getElapsedSeconds()
  236. ** Returns the elapsed time as a floating point number with millisecond
  237. ** resolution.
  238. **
  239. ** isUnixBased()
  240. ** Returns true if the raw clock values are being derived from a unix/posix OS.
  241. **
  242. ** toWindowsEpoch(msclock unixt)
  243. ** Converts unixt to a windows value by adding the epoch delta.
  244. **
  245. ** toUnixEpoch(msclock win32t)
  246. ** Converts win32t to a unix value by subtracting the epoch delta.
  247. */
  248. ////////////////////////////////////////////////////////////////////////////////
  249. // class ScopeTimer - Runs a Timer while ScopeTimer is in scope.
  250. ////////////////////////////////////////////////////////////////////////////////
  251. class ScopeTimer { // Runs a timer when in scope.
  252. private:
  253. Timer& myTimer; // This is the timer to run.
  254. public:
  255. ScopeTimer(Timer& T) : myTimer(T) { myTimer.start(); } // The Timer starts at construction.
  256. ~ScopeTimer() { myTimer.stop(); } // The Timer stops at destruction.
  257. };
  258. ///////////////////////////////////////////////////////////////////////////////
  259. // class Timeout - This one uses a Timer to establish a timeout value.
  260. ///////////////////////////////////////////////////////////////////////////////
  261. class Timeout {
  262. private:
  263. Timer myTimer; // We need a timer to do this.
  264. msclock myDuration; // Milliseconds before timout expires.
  265. public:
  266. class BadTimeoutValue {}; // If the value is bad throw this.
  267. Timeout(msclock duration); // Create and set the duration.
  268. msclock setDuration(msclock duration); // Set/Change the duration in milliseconds.
  269. msclock getDuration(); // Return the current duration in milliseconds.
  270. msclock restart(); // Restart the timeout timer.
  271. msclock getElapsedTime(); // Get elapsed milliseconds.
  272. msclock getRemainingTime(); // Get remaining milliseconds.
  273. bool isExpired(); // Return true if time is up.
  274. };
  275. /* Timeout Documentation...
  276. **
  277. ** Timeout(int duration)
  278. ** Creates a Timout timer and sets the duration in milliseconds.
  279. **
  280. ** setDuration(int duration)
  281. ** Sets or changes the duration of the timeout timer.
  282. ** The Timout is NOT reset by this method. This allows you to change
  283. ** the timeout on the fly.
  284. **
  285. ** restart()
  286. ** Restarts the timeout timer.
  287. **
  288. ** getElapsedTime()
  289. ** Returns the number of milliseconds elapsed since the Timout was created
  290. ** or reset.
  291. **
  292. ** getRemainingTime()
  293. ** Returns the number of milliseconds remaining before time is up.
  294. **
  295. ** isExpired()
  296. ** Returns true if time is up.
  297. */
  298. #endif // End MNR_timing once-only switch.