added sleep quantum correction using epicsThreadSleepQuantum()

This commit is contained in:
Jeff Hill
2003-03-21 19:26:00 +00:00
parent 4c142e759c
commit 0792aebf95
10 changed files with 115 additions and 28 deletions
+7
View File
@@ -315,6 +315,13 @@ void fdManager::reschedule ()
{
}
double fdManager::quantum ()
{
// hopefully its a reasonable guess that select() and epicsThreadSleep()
// will have the same sleep quantum
return epicsThreadSleepQuantum ();
}
//
// lookUpFD()
//
+1
View File
@@ -100,6 +100,7 @@ private:
//
fdReg *pCBReg;
void reschedule ();
double quantum ();
epicsShareFunc void installReg (fdReg &reg);
epicsShareFunc void removeReg (fdReg &reg);
void lazyInitTimerQueue ();
+51 -11
View File
@@ -10,7 +10,7 @@
/* epicsThreadTest.cpp */
/* Author: Marty Kraimer Date: 26JAN2000 */
/* sleep accuracy tests by Jeff Hill */
/* sleep accuracy and sleep quantum tests by Jeff Hill */
/* epicsThreadGetIdSelf performance by Jeff Hill */
#include <stddef.h>
@@ -59,28 +59,67 @@ void myThread::run()
errlogPrintf("threadFunc %d stopping argvalue %p\n",myPrivate,argvalue);
}
static double threadSleepMeasureDelayError( const double & delay )
static double threadSleepMeasureDelayError ( const double & delay )
{
epicsTime beg = epicsTime::getCurrent();
epicsThreadSleep ( delay );
epicsTime end = epicsTime::getCurrent();
double meas = end - beg;
double error = fabs ( delay - meas );
printf ( "epicsThreadSleep ( %10f ) delay err %10f sec\n",
delay, error );
return error;
}
static void threadSleepTest()
static void threadSleepQuantumTest ()
{
static const unsigned iterations = 100u;
const double quantum = epicsThreadSleepQuantum ();
double errorSum = 0.0;
int i;
for ( i = 0u; i < 20; i++ ) {
double delay = ldexp ( 1.0 , -i );
errorSum += threadSleepMeasureDelayError ( delay );
for ( unsigned i = 0u; i < iterations; i++ ) {
errorSum +=
threadSleepMeasureDelayError ( 1e-15 );
}
double quantumEstimate = errorSum / iterations;
double quantumError = fabs ( quantumEstimate - quantum ) / quantum;
const char * pTol = 0;
if ( quantumError > 0.1 ) {
pTol = "10%";
}
else if ( quantumError > 0.01 ) {
pTol = "1%";
}
else if ( quantumError > 0.001 ) {
pTol = ".1%";
}
if ( pTol ) {
printf (
"The epicsThreadSleepQuantum() call returns %f sec.\n",
quantum );
printf (
"This doesnt match the quantum estimate "
"of %f sec within %s.\n",
quantumEstimate, pTol );
}
}
static void threadSleepTest ()
{
static const int iterations = 20;
const double quantum = epicsThreadSleepQuantum ();
double errorSum = threadSleepMeasureDelayError ( 0.0 );
for ( int i = 0u; i < iterations; i++ ) {
double delay = ldexp ( 1.0 , -i );
double error =
threadSleepMeasureDelayError ( delay );
errorSum += error;
if ( error > quantum + quantum / 8.0 ) {
printf ( "epicsThreadSleep ( %10f ) delay err %10f sec\n",
delay, error );
}
}
double averageError = errorSum / ( iterations + 1 );
if ( averageError > quantum ) {
printf ( "Average sleep delay error was %f sec\n", averageError );
}
errorSum += threadSleepMeasureDelayError ( 0.0 );
printf ( "Average error %f sec\n", errorSum / ( i + 1 ) );
}
static void epicsThreadGetIdSelfPerfTest ()
@@ -117,6 +156,7 @@ extern "C" void threadTest(int ntasks,int verbose)
epicsThreadGetIdSelfPerfTest ();
threadSleepTest();
threadSleepQuantumTest();
errVerbose = verbose;
errlogInit(4096);
+8 -3
View File
@@ -32,7 +32,7 @@ public:
void start ( const epicsTime &expireTime );
void setBegin ( const epicsTime & );
double delay () const;
void checkError () const;
double checkError () const;
protected:
virtual ~delayVerify ();
private:
@@ -67,7 +67,7 @@ inline double delayVerify::delay () const
return delayVerifyOffset + this->expectedDelay;
}
void delayVerify::checkError () const
double delayVerify::checkError () const
{
const double messageThresh = 0.5; // percent
double actualDelay = this->expireStamp - this->beginStamp;
@@ -78,6 +78,7 @@ void delayVerify::checkError () const
printf ( "delay error > %g %%, delay = %g sec, error = %g mSec (%f %%)\n",
messageThresh, this->expectedDelay, measuredError * 1000.0, percentError );
}
return measuredError;
}
inline void delayVerify::start ( const epicsTime &expireTime )
@@ -119,9 +120,13 @@ void testAccuracy ()
while ( expireCount != 0u ) {
expireEvent.wait ();
}
double averageMeasuredError;
for ( i = 0u; i < nTimers; i++ ) {
pTimers[i]->checkError ();
averageMeasuredError += pTimers[i]->checkError ();
}
averageMeasuredError /= nTimers;
printf ("average timer delay error %f mS\n",
averageMeasuredError * 1000 );
queue.release ();
}
+21 -6
View File
@@ -79,10 +79,14 @@ void epicsTimerQueueActiveForC::release ()
pMgr->release ( *this );
}
epicsTimerQueuePassiveForC::epicsTimerQueuePassiveForC
( epicsTimerQueueRescheduleCallback pCallbackIn, void * pPrivateIn ) :
epicsTimerQueuePassiveForC::epicsTimerQueuePassiveForC (
epicsTimerQueueNotifyReschedule pRescheduleCallbackIn,
epicsTimerQueueNotifyQuantum pSleepQuantumCallbackIn,
void * pPrivateIn ) :
timerQueuePassive ( * static_cast < epicsTimerQueueNotify * > ( this ) ),
pCallback ( pCallbackIn ), pPrivate ( pPrivateIn )
pRescheduleCallback ( pRescheduleCallbackIn ),
pSleepQuantumCallback ( pSleepQuantumCallbackIn ),
pPrivate ( pPrivateIn )
{
}
@@ -92,7 +96,12 @@ epicsTimerQueuePassiveForC::~epicsTimerQueuePassiveForC ()
void epicsTimerQueuePassiveForC::reschedule ()
{
(*this->pCallback) ( this->pPrivate );
(*this->pRescheduleCallback) ( this->pPrivate );
}
double epicsTimerQueuePassiveForC::quantum ()
{
return (*this->pSleepQuantumCallback) ( this->pPrivate );
}
void epicsTimerQueuePassiveForC::destroy ()
@@ -138,10 +147,16 @@ epicsShareFunc double epicsTimerNotify::expireStatus::expirationDelay () const
}
extern "C" epicsTimerQueuePassiveId epicsShareAPI
epicsTimerQueuePassiveCreate ( epicsTimerQueueRescheduleCallback pCallbackIn, void *pPrivateIn )
epicsTimerQueuePassiveCreate (
epicsTimerQueueNotifyReschedule pRescheduleCallbackIn,
epicsTimerQueueNotifyQuantum pSleepQuantumCallbackIn,
void * pPrivateIn )
{
try {
return new epicsTimerQueuePassiveForC ( pCallbackIn, pPrivateIn );
return new epicsTimerQueuePassiveForC (
pRescheduleCallbackIn,
pSleepQuantumCallbackIn,
pPrivateIn );
}
catch ( ... ) {
return 0;
+7 -2
View File
@@ -89,6 +89,9 @@ public:
// called when a new timer is inserted into the queue and the
// delay to the next expire has changed
virtual void reschedule () = 0;
// if there is a quantum in the scheduling of timer intervals
// return this quantum in seconds. If unknown then return zero.
virtual double quantum () = 0;
protected:
virtual ~epicsTimerQueueNotify () = 0;
};
@@ -142,9 +145,11 @@ epicsShareFunc void epicsShareAPI
/* passive timer queue */
typedef struct epicsTimerQueuePassiveForC * epicsTimerQueuePassiveId;
typedef void ( *epicsTimerQueueRescheduleCallback ) ( void *pPrivate );
typedef void ( * epicsTimerQueueNotifyReschedule ) ( void * pPrivate );
typedef double ( * epicsTimerQueueNotifyQuantum ) ( void * pPrivate );
epicsShareFunc epicsTimerQueuePassiveId epicsShareAPI
epicsTimerQueuePassiveCreate ( epicsTimerQueueRescheduleCallback, void *pPrivate );
epicsTimerQueuePassiveCreate ( epicsTimerQueueNotifyReschedule,
epicsTimerQueueNotifyQuantum, void *pPrivate );
epicsShareFunc void epicsShareAPI
epicsTimerQueuePassiveDestroy ( epicsTimerQueuePassiveId );
epicsShareFunc epicsTimerId epicsShareAPI
+1 -1
View File
@@ -66,7 +66,7 @@ void timer::start ( epicsTimerNotify & notify, const epicsTime & expire )
void timer::privateStart ( epicsTimerNotify & notify, const epicsTime & expire )
{
this->pNotify = & notify;
this->exp = expire;
this->exp = expire - this->queue.sleepQuantumOverTwo;
bool reschedualNeeded = false;
if ( this->curState == stateActive ) {
+12 -4
View File
@@ -100,6 +100,7 @@ private:
mutable epicsMutex mutex;
epicsEvent cancelBlockingEvent;
tsDLList < timer > timerList;
const double sleepQuantumOverTwo;
epicsTimerQueueNotify & notify;
timer * pExpireTmr;
epicsThreadId processThread;
@@ -142,6 +143,7 @@ private:
bool terminateFlag;
void run ();
void reschedule ();
double quantum ();
epicsTimerQueue & getEpicsTimerQueue ();
timerQueueActive ( const timerQueueActive & );
timerQueueActive & operator = ( const timerQueueActive & );
@@ -178,17 +180,23 @@ protected:
timerQueuePassive & operator = ( const timerQueuePassive & );
};
struct epicsTimerQueuePassiveForC : public epicsTimerQueueNotify, public timerQueuePassive {
struct epicsTimerQueuePassiveForC :
public epicsTimerQueueNotify, public timerQueuePassive {
public:
epicsTimerQueuePassiveForC ( epicsTimerQueueRescheduleCallback pCallback, void *pPrivate );
epicsTimerQueuePassiveForC (
epicsTimerQueueNotifyReschedule,
epicsTimerQueueNotifyQuantum,
void * pPrivate );
void destroy ();
protected:
~epicsTimerQueuePassiveForC ();
private:
epicsTimerQueueRescheduleCallback pCallback;
void *pPrivate;
epicsTimerQueueNotifyReschedule pRescheduleCallback;
epicsTimerQueueNotifyQuantum pSleepQuantumCallback;
void * pPrivate;
static epicsSingleton < tsFreeList < epicsTimerQueuePassiveForC, 0x10 > > pFreeList;
void reschedule ();
double quantum ();
};
struct epicsTimerQueueActiveForC : public timerQueueActive,
+2 -1
View File
@@ -22,8 +22,9 @@
epicsTimerQueue::~epicsTimerQueue () {}
timerQueue::timerQueue ( epicsTimerQueueNotify &notifyIn ) :
sleepQuantumOverTwo ( notifyIn.quantum () / 2.0 ),
notify ( notifyIn ), pExpireTmr ( 0 ),
processThread ( 0 ), cancelPending ( false )
processThread ( 0 ), cancelPending ( false )
{
}
+5
View File
@@ -86,6 +86,11 @@ void timerQueueActive::reschedule ()
this->rescheduleEvent.signal ();
}
double timerQueueActive::quantum ()
{
return epicsThreadSleepQuantum ();
}
void timerQueueActive::show ( unsigned int level ) const
{
printf ( "EPICS threaded timer queue at %p\n",