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( ¤tTime, 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( ¤tTime, 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( ¤tDate ) ; 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( ¤tTime, 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( ¤tDate ) ; 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 //===================================================================
Documentation generated on Mon Jun 9 11:45:55 2008 |
Generated with doxygen by Dimitri van Heesch , 1997-2007 |