Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

timing.cpp 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // timing.cpp
  2. //
  3. // Copyright (C) 2006 - 2009 MicroNeil Research Corporation.
  4. //
  5. // See the corresponding .hpp file for descriptions and history.
  6. //
  7. // This program is part of the MicroNeil Research Open Library Project. For
  8. // more information go to http://www.microneil.com/OpenLibrary/index.html
  9. //
  10. // This program is free software; you can redistribute it and/or modify it
  11. // under the terms of the GNU General Public License as published by the
  12. // Free Software Foundation; either version 2 of the License, or (at your
  13. // option) any later version.
  14. //
  15. // This program is distributed in the hope that it will be useful, but WITHOUT
  16. // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  17. // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  18. // more details.
  19. //
  20. // You should have received a copy of the GNU General Public License along with
  21. // this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  22. // Place, Suite 330, Boston, MA 02111-1307 USA
  23. #include <ctime>
  24. #include <sys/time.h>
  25. #include <cerrno>
  26. // Platform Specific Includes //////////////////////////////////////////////////
  27. #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
  28. #include <windows.h>
  29. #endif
  30. #include "timing.hpp"
  31. // Introduce the standard namespace ////////////////////////////////////////////
  32. using namespace std;
  33. namespace CodeDweller {
  34. ///////////////////////////////////////////////////////////////////////////////
  35. // class Sleeper - An object that remembers how long it is supposed to sleep.
  36. // This allows an application to create "standard" sleep timers. This also
  37. // helps keep sleeper values within range to avoid weird timing problems.
  38. ///////////////////////////////////////////////////////////////////////////////
  39. // Abstracted doRawSleep() function ////////////////////////////////////////////
  40. #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
  41. // In a WIN32 environment Sleep() is defined and it works in milliseconds so
  42. // we will use that for doRawSleep(). It's important to note that under normal
  43. // circumstances win32 Sleep() may be off by quite a bit (15ms or so) due to
  44. // how timing is done in the OS. There are ways around this, but they are
  45. // sometimes complex - so here I've left things basic. If more precise win32
  46. // timing is needed then this method can be recoded using a workaround that is
  47. // appropriate to the application.
  48. void Sleeper::doRawSleep(int x) {
  49. Sleep(x); // Use windows Sleep()
  50. }
  51. #else
  52. // If we are not in a win32 environment then we're likely on a posix/unix system
  53. // or at least we have the standard posix/unix time functions so we'll redefine
  54. // absSleep to use nanosleep();
  55. void Sleeper::doRawSleep(int x) {
  56. struct timespec sleeptime; // How much sleeping to do.
  57. struct timespec remaining; // How much sleeping remains.
  58. int result; // The latest result.
  59. remaining.tv_sec = x/1000; // Divide ms by 1000 to get secs.
  60. remaining.tv_nsec = (x%1000)*1000000; // Multiply the remaining msecs to get nsecs.
  61. do { // Just in case we get interruped...
  62. sleeptime.tv_sec = remaining.tv_sec; // Get our sleep time from the
  63. sleeptime.tv_nsec = remaining.tv_nsec; // remaining time.
  64. result = nanosleep(&sleeptime,&remaining); // Call nanosleep and get the remaining time.
  65. } while(0>result && EINTR==errno); // If we were interrupted sleep some more.
  66. }
  67. #endif
  68. Sleeper::Sleeper() // Constructed empty we set our
  69. :MillisecondsToSleep(0) { // sleep time to zero.
  70. }
  71. Sleeper::Sleeper(int x) { // Constructed with a value we
  72. setMillisecondsToSleep(x); // set the sleep time or throw.
  73. }
  74. int Sleeper::setMillisecondsToSleep(int x) { // Safe way to set the vlaue.
  75. if(x < MinimumSleeperTime ||
  76. x > MaximumSleeperTime) // If it's not a good time value
  77. throw BadSleeperValue(); // then throw the exception.
  78. MillisecondsToSleep = x; // If it is good - set it.
  79. return MillisecondsToSleep; // Return the set value.
  80. }
  81. int Sleeper::getMillisecondsToSleep() { // Safe way to get the value.
  82. return MillisecondsToSleep; // Send back the value.
  83. }
  84. void Sleeper::sleep() { // Here's where we snooze.
  85. if(MillisecondsToSleep > 0) { // If we have a good snooze
  86. doRawSleep(MillisecondsToSleep); // value then go to Sleep().
  87. } else { // If the value is not good
  88. throw BadSleeperValue(); // throw an exception.
  89. }
  90. }
  91. void Sleeper::sleep(int x) { // Reset the sleep time then sleep.
  92. setMillisecondsToSleep(x); // Set the sleep time.
  93. sleep(); // Sleep.
  94. }
  95. void Sleeper::operator()() { // Syntactic sugar - operator() on
  96. sleep(); // a sleeper calls sleep().
  97. }
  98. ///////////////////////////////////////////////////////////////////////////////
  99. // class PollTimer - An object to pause during polling processes where the
  100. // time between polls is expanded according to a Fibonacci sequence. This
  101. // allows self organizing automata to relax a bit when a particular process
  102. // is taking a long time so that the resources used in the polling process are
  103. // reduced if the system is under load - The idea is to prevent the polling
  104. // process from loading the system when there are many nodes poling, yet to
  105. // allow for a rapid response when there are few or when the answer we're
  106. // waiting for is ready quickly. We use a Fibonacci expansion because it is
  107. // a natural spiral.
  108. ///////////////////////////////////////////////////////////////////////////////
  109. PollTimer::PollTimer(int Nom, int Max) :
  110. NominalPollTime(MinimumSleeperTime),
  111. MaximumPollTime(MinimumSleeperTime) { // Construction requires a
  112. setNominalPollTime(Nom); // nominal delay to use and
  113. setMaximumPollTime(Max); // a maximum delay to allow.
  114. }
  115. int PollTimer::setNominalPollTime(int Nom) { // Set the Nominal Poll Time.
  116. if(Nom < MinimumSleeperTime || // Check the low and high
  117. Nom > MaximumSleeperTime) // limits and throw an
  118. throw BadPollTimerValue(); // exception if we need to.
  119. // If the value is good then
  120. NominalPollTime = Nom; // remember it.
  121. if(MaximumPollTime < NominalPollTime) // Make sure the Maximum poll
  122. MaximumPollTime = NominalPollTime; // time is >= the Nominal time.
  123. reset(); // Reset due to the change.
  124. return NominalPollTime; // Return the new value.
  125. }
  126. int PollTimer::setMaximumPollTime(int Max) { // Set the Maximum Poll Time.
  127. if(Max < MinimumSleeperTime || // Check the low and high
  128. Max > MaximumSleeperTime) // limits and throw an
  129. throw BadPollTimerValue(); // exception if we need to.
  130. // If the value is good then
  131. MaximumPollTime = Max; // remember it.
  132. if(MaximumPollTime < NominalPollTime) // Make sure the Maximum poll
  133. MaximumPollTime = NominalPollTime; // time is >= the Nominal time.
  134. reset(); // Reset due to the change.
  135. return MaximumPollTime; // Return the new value.
  136. }
  137. void PollTimer::reset() { // Reset the spiral.
  138. FibA = NominalPollTime; // Assume our starting event.
  139. FibB = 0; // Assume no other events.
  140. LimitReached=false; // Reset our limit watcher.
  141. }
  142. int PollTimer::pause() { // Pause between polls.
  143. int SleepThisTime = MaximumPollTime; // Assume we're at out limit for now.
  144. if(LimitReached) { // If actually are at our limit then
  145. mySleeper.sleep(SleepThisTime); // use the current value.
  146. } else { // If we are still expanding then
  147. SleepThisTime = FibA+FibB; // Calculate the time to use and
  148. if(SleepThisTime >= MaximumPollTime) { // check it against the limit. If
  149. SleepThisTime = MaximumPollTime; // we reached the limit, us that value
  150. LimitReached = true; // and set the flag.
  151. } else { // If we haven't reached the limit yet
  152. FibB=FibA; // then shift our events and remember
  153. FibA=SleepThisTime; // this one to build our spiral.
  154. }
  155. mySleeper.sleep(SleepThisTime); // Take a nap.
  156. } // Then FIRE THE MISSILES!
  157. return SleepThisTime; // Tell the caller how long we slept.
  158. }
  159. ///////////////////////////////////////////////////////////////////////////////
  160. // class Timer - This one acts much like a stop watch with millisecond
  161. // resolution. The time is based on wall-clock time using gettimeofday().
  162. ///////////////////////////////////////////////////////////////////////////////
  163. #ifdef WIN32
  164. // Here is the win32 version of getLocalRawClock()
  165. #define TimerIsUnixBased (false)
  166. msclock Timer::getLocalRawClock() const {
  167. FILETIME t; // We need a FILETIME structure.
  168. msclock c; // We need a place to calculate our value.
  169. GetSystemTimeAsFileTime(&t); // Grab the system time.
  170. c = (unsigned long long int) t.dwHighDateTime << 32LL; // Put full seconds into the high order bits.
  171. c |= t.dwLowDateTime; // Put 100ns ticks into the low order bits.
  172. c /= 10000; // Divide 100ns ticks by 10K to get ms.
  173. c -= EPOCH_DELTA_IN_MSEC; // Correct for the epoch difference.
  174. return c; // Return the result.
  175. }
  176. #else
  177. // Here is the unix/posix version of getLocalRawClock()
  178. #define TimerIsUnixBased (true)
  179. msclock Timer::getLocalRawClock() const {
  180. struct timeval t; // We need a timval structure.
  181. msclock c; // We need a place to calculate our value.
  182. gettimeofday(&t,NULL); // Grab the system time.
  183. c = t.tv_sec * 1000; // Put the full seconds in as milliseconds.
  184. c += t.tv_usec / 1000; // Add the microseconds as milliseconds.
  185. return c; // Return the milliseconds.
  186. }
  187. #endif
  188. Timer::Timer() { // Construct by resetting the
  189. start(); // clocks by using start();
  190. }
  191. Timer::Timer(msclock startt): // Construct a timer from a specific time.
  192. RunningFlag(true), // Set the running flag,
  193. StartTime(startt), // the start time and
  194. StopTime(startt) { // the stop time clock to startt.
  195. }
  196. void Timer::clear() { // Stop, zero elapsed, now.
  197. StartTime = StopTime = getLocalRawClock(); // Set the start and stop time
  198. RunningFlag = false; // to now. We are NOT running.
  199. }
  200. msclock Timer::start() { // (re) Start the timer at this moment.
  201. return start(getLocalRawClock()); // start() using the current raw clock.
  202. }
  203. msclock Timer::start(msclock startt) { // (re) Start a timer at startt.
  204. StartTime = StopTime = startt; // Set the start and end clocks.
  205. RunningFlag = true; // Set the running flag to true.
  206. return StartTime; // Return the start clock.
  207. }
  208. msclock Timer::getStartClock() { return StartTime; } // Return the start clock value.
  209. bool Timer::isRunning() { return RunningFlag; } // Return the running state.
  210. msclock Timer::getElapsedTime() const { // Return the elapsed timeofday -
  211. msclock AssumedStopTime; // We need to use a StopTime simulation.
  212. if(RunningFlag) { // If we are running we must get
  213. AssumedStopTime = getLocalRawClock(); // the current time (as if it were stop).
  214. } else { // If we are not running we use
  215. AssumedStopTime = StopTime; // the actual stop time.
  216. }
  217. msclock delta = AssumedStopTime - StartTime; // Calculate the difference.
  218. return delta; // That's our result.
  219. }
  220. msclock Timer::stop() { // Stop the timer.
  221. StopTime = getLocalRawClock(); // Grab the time and then stop
  222. RunningFlag=false; // the clock.
  223. return StopTime; // Return the time we stopped.
  224. }
  225. msclock Timer::getStopClock() { return StopTime; } // Return the stop clock value.
  226. double Timer::getElapsedSeconds() const { // Calculate the elapsed seconds.
  227. msclock e = getElapsedTime(); // Get the elapsed time in msecs.
  228. double secs = (double) e / 1000.0; // Calculate seconds from msecs.
  229. return secs;
  230. }
  231. bool Timer::isUnixBased() { return TimerIsUnixBased; } // Is this timer unix based?
  232. msclock Timer::toWindowsEpoch(msclock unixt) { // Convert a unix based msclock to win32 based.
  233. return (unixt + EPOCH_DELTA_IN_MSEC); // Going this way we add the epoch delta.
  234. }
  235. msclock Timer::toUnixEpoch(msclock win32t) { // Convert a win32 based msclock to a unix based.
  236. return (win32t - EPOCH_DELTA_IN_MSEC); // Going this way we subtract the epoch delta.
  237. }
  238. ///////////////////////////////////////////////////////////////////////////////
  239. // class Timeout - This one uses a Timer to establish a timeout value.
  240. ///////////////////////////////////////////////////////////////////////////////
  241. Timeout::Timeout(msclock duration):myDuration(duration) { } // Create, set the duration, start.
  242. msclock Timeout::setDuration(msclock duration) { // Set/Change the duration in milliseconds.
  243. myDuration = duration; // (re) Set the duration.
  244. return myDuration; // Return the current (new) duration.
  245. }
  246. msclock Timeout::getDuration() { // Return the current duration.
  247. return myDuration;
  248. }
  249. msclock Timeout::restart() { // Restart the timeout timer.
  250. return myTimer.start(); // Restart the clock and return the time.
  251. }
  252. msclock Timeout::getElapsedTime() { // Get elapsed milliseconds.
  253. return myTimer.getElapsedTime(); // Return the elapsed time.
  254. }
  255. msclock Timeout::getRemainingTime() { // Get remaining milliseconds.
  256. msclock remaining = 0ULL; // Assume we're expired to start.
  257. msclock elapsed = myTimer.getElapsedTime(); // Get the elapsed time.
  258. if(elapsed < myDuration) { // If there is still time then
  259. remaining = myDuration - elapsed; // calculate what is left.
  260. }
  261. return remaining; // Return what we found.
  262. }
  263. bool Timeout::isExpired() { // Return true if time is up.
  264. return (!(myTimer.getElapsedTime() < myDuration)); // Check the elapsed time against myDuration.
  265. }
  266. }