OMKClock.cpp

Go to the documentation of this file.
00001 /*
00002  * Software OpenMASK-3DVis © INRIA 1993-2002, thereinafter the Software
00003  * 
00004  * The software has been developed within the Siames Project. 
00005  * INRIA hold intellectual property rights
00006  * 
00007  * The Software has been registered with the Agence pour la Protection des
00008  * Programmes (APP) under registration number IDDN.FR.001.500027.00.S.P.2001.000.41200
00009  *
00010  * This file may be distributed under the terms of the Q Public License
00011  * version 1.0 as defined by Trolltech AS of Norway and appearing in the file
00012  * LICENSE.QPL included in the packaging of this file.
00013  *
00014  * Licensees holding valid specific licenses issued by INRIA for the software may use 
00015  * this file in accordance with that specific license         
00016  *
00017  */
00018 //-----------------------------------------------------------------------------
00019 #include "OMKClock.h"
00020 
00021 #include <OMKParametersAccessor.inl>
00022 
00023 #ifdef _MSC_VER // WINDOWS Time Management
00024 #include <time.h>
00025 //Includes for using std::transform and toupper under VC
00026 #include <cctype>
00027 #include <string>
00028 #include <algorithm>
00029 #else // POSIX Time Management
00030 #include <sys/time.h>
00031 #endif
00032 
00033 #include <math.h>
00034 
00035 #define NANOSLEEP_RESOLUTION  20000000
00036 using namespace OMK ;
00037 
00038 //===================================================================
00039 REGISTER_OBJECT_FACTORY( Clock, "Clock" ) ;
00040 //===================================================================
00041 Clock::Clock( Controller &ctrl,  const ObjectDescriptor &objectDescription ) 
00042 : ExtensibleSimulatedObject( ctrl,  objectDescription ), 
00043   _firstRealDate(0ul), 
00044   _timeToSpend( 0l ),
00045   _simulFrequency( 1ul ),
00046   _wantedMult( 1.0f ),  _realMult( 0.0f ), 
00047   _freeRun( false ),  _activeSleep( true ), _simulationStarted( false) 
00048 {  
00049 
00050 #ifdef _MSC_VER // WINDOWS Time Management
00051   QueryPerformanceCounter( &_startSimulationDate );
00052   QueryPerformanceCounter( &_lastCallDate );
00053   QueryPerformanceCounter( &_lastRealRefresh );
00054   QueryPerformanceFrequency( &_processorFrequency );
00055 #else // POSIX Time Management
00056   _lastCallDate = 0ul ;
00057   _lastRealRefresh = 0ul ;
00058 #endif
00059 
00060 }
00061 //===================================================================
00062 
00063 //===================================================================
00064 Clock::~Clock()
00065 {
00066 }
00067 //===================================================================
00068 
00069 //===================================================================
00070 void Clock::init()
00071 {
00072   const ConfigurationParameterDescriptor* prm = getConfigurationParameters();
00073   
00074   std::string str;
00075   if( ParametersAccessor::get( prm, "SleepProcedure", str ) )
00076   {  
00077     std::transform( str.begin(), str.end(), str.begin(), toupper );
00078     _activeSleep = !( str == "PASSIVE" );
00079   }
00080 
00081   ParametersAccessor::get( prm, "FreeRun"     , _freeRun      );
00082   ParametersAccessor::get( prm, "InitCoeff"   , _wantedMult   );
00083   setWantedMultiplier( _wantedMult ) ;
00084 
00085 #ifdef _MSC_VER
00086   QueryPerformanceCounter( &_startSimulationDate ) ;
00087   _lastRealRefresh = _startSimulationDate ;
00088   _lastCallDate = _startSimulationDate ;
00089 #else
00090   timeval currentTime;
00091   gettimeofday( &currentTime, NULL );
00092   _firstRealDate = currentTime.tv_sec;
00093   // The filter is used to avoid numeric overflow
00094   _lastRealRefresh = _lastCallDate = ( currentTime.tv_sec & 0xfff ) * 1000000 + currentTime.tv_usec;
00095 #endif
00096 
00097   _simulFrequency = getObjectDescriptor().getFrequency();
00098   return ExtensibleSimulatedObject::init();
00099 }
00100 //===================================================================
00101 
00102 //===================================================================
00103 bool Clock::processEvent( Event* event )
00104 {
00105   return ExtensibleSimulatedObject::processEvent( event ) ;
00106 }
00107 //===================================================================
00108 
00109 //===================================================================
00110 void Clock::compute()
00111 {
00112         if(!_simulationStarted){
00113           _simulationStarted = true ;
00114 #ifdef _MSC_VER
00115           // current time in micro-sec
00116           LARGE_INTEGER firstDate ;
00117           QueryPerformanceCounter( &firstDate ) ;
00118           _startSimulationDate = firstDate ;
00119           _lastCallDate = firstDate ;
00120 #else
00121           timeval firstTime;
00122           gettimeofday( &firstTime, NULL );
00123           // current time in micro-sec
00124           _lastCallDate = ( firstTime.tv_sec & 0xfff ) * 1000000 + firstTime.tv_usec;
00125 #endif
00126         }
00127 
00128 #ifdef _MSC_VER
00129   // current time in micro-sec
00130   LARGE_INTEGER newCallDate ;
00131   QueryPerformanceCounter( &newCallDate ) ;
00132   LARGE_INTEGER currentDate = newCallDate ;
00133   // ratio of step duration by elapsed time since last call
00134   _realMult = (float)( ( 1/ _simulFrequency ) * (_processorFrequency.QuadPart / (newCallDate.QuadPart - _lastCallDate.QuadPart) ) ) ;
00135 #else
00136   timeval currentTime;
00137   gettimeofday( &currentTime, NULL );
00138   // current time in micro-sec
00139   unsigned long newCallDate = ( currentTime.tv_sec & 0xfff ) * 1000000 + currentTime.tv_usec;
00140   // ratio of step duration by elapsed time since last call
00141   _realMult = ( 1000000.0f / _simulFrequency ) / ( newCallDate - _lastCallDate );
00142 #endif
00143 
00144   if( _freeRun )
00145   {
00146     _timeToSpend = 0;
00147   }
00148   else
00149   {  
00150     // Controled time, sleep if necessary
00151     // step duration in micro-sec
00152     long stepDuration = (long)( 1000000.0f / ( _simulFrequency * _wantedMult ) );
00153     // sleep duration is the wanted step duration minus the time needed for simulation
00154     // negative: time to catch up, positive: time to spend
00155 #ifdef _MSC_VER
00156         _timeToSpend += (long)( stepDuration + ((_lastCallDate.QuadPart - newCallDate.QuadPart)*1000000/_processorFrequency.QuadPart) ) ;
00157 #else
00158     _timeToSpend += _lastCallDate - newCallDate + stepDuration ;
00159 #endif
00160     // never sleep more than step duration (to avoid numeric overflow on signed long)
00161     _timeToSpend = (stepDuration < _timeToSpend) ? stepDuration : _timeToSpend ;
00162     
00163     if( 0 < _timeToSpend )
00164     { 
00165       // Some time to spend
00166       if( _activeSleep )
00167       { 
00168         // Active sleep => loop
00169 #ifdef _MSC_VER
00170 
00171                 long currentStep = 0 ;
00172                 while( currentStep < _timeToSpend){
00173                         QueryPerformanceCounter( &currentDate ) ;
00174                         currentStep = (long)(( currentDate.QuadPart - newCallDate.QuadPart )*1000000/_processorFrequency.QuadPart); // Get step in micro-sec
00175 
00176                 }
00177 #else
00178         // Compute the date to reach with the dummy loop
00179         timeval targetDate;
00180         targetDate.tv_sec = currentTime.tv_sec ;
00181         targetDate.tv_usec = currentTime.tv_usec + _timeToSpend ;
00182         for( targetDate.tv_usec = currentTime.tv_usec + _timeToSpend ; 
00183              1000000l < targetDate.tv_usec ; 
00184              targetDate.tv_usec -= 1000000l )
00185         { // Add a seconde until targetDate.tv_usec is in range (< 10000000usec)
00186           targetDate.tv_sec++ ;
00187         }
00188 
00189         while( currentTime.tv_sec < targetDate.tv_sec
00190             || ( currentTime.tv_sec == targetDate.tv_sec
00191                && currentTime.tv_usec < targetDate.tv_usec ) )
00192         { // The dummy loop until date is reached
00193             gettimeofday( &currentTime, NULL );
00194         }
00195 #endif
00196 
00197       } 
00198       else
00199       { 
00200         // Passive sleep => nanosleep call
00201 #ifdef _MSC_VER
00202         // TODO / FIX Windows "Sleep" is not precise enough (~10ms), and current method is :
00203             // 1. First, make PASSIVE SLEEP as much as possible (milli-second granularity)
00204         Sleep(_timeToSpend/1000);
00205                 // 2. Then, spend the rest of time with active sleep
00206                 long currentStep = (long)(( currentDate.QuadPart - newCallDate.QuadPart )*1000000/_processorFrequency.QuadPart ) ; // Get step in micro-sec
00207                 while( currentStep < _timeToSpend){
00208                         QueryPerformanceCounter( &currentDate ) ;
00209                         currentStep = (long)( ( currentDate.QuadPart - newCallDate.QuadPart )*1000000/_processorFrequency.QuadPart ) ; // Get step in micro-sec
00210                 }
00211 #else
00212                 timespec sleepNanoTime;
00213         sleepNanoTime.tv_sec = 0;
00214         sleepNanoTime.tv_nsec = _timeToSpend * 1000l ;
00215         nanosleep( &sleepNanoTime, NULL );
00216 #endif
00217       }
00218     }
00219   }
00220   // store the call date for next call
00221   _lastCallDate = newCallDate;
00222 
00223   ExtensibleSimulatedObject::compute();
00224 }
00225 //===================================================================

logo OpenMask

Documentation generated on Mon Jun 9 11:45:55 2008

Generated with doxygen by Dimitri van Heesch ,   1997-2007