added sleep quantum correction using epicsThreadSleepQuantum()
This commit is contained in:
@@ -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()
|
||||
//
|
||||
|
||||
@@ -100,6 +100,7 @@ private:
|
||||
//
|
||||
fdReg *pCBReg;
|
||||
void reschedule ();
|
||||
double quantum ();
|
||||
epicsShareFunc void installReg (fdReg ®);
|
||||
epicsShareFunc void removeReg (fdReg ®);
|
||||
void lazyInitTimerQueue ();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -22,8 +22,9 @@
|
||||
epicsTimerQueue::~epicsTimerQueue () {}
|
||||
|
||||
timerQueue::timerQueue ( epicsTimerQueueNotify ¬ifyIn ) :
|
||||
sleepQuantumOverTwo ( notifyIn.quantum () / 2.0 ),
|
||||
notify ( notifyIn ), pExpireTmr ( 0 ),
|
||||
processThread ( 0 ), cancelPending ( false )
|
||||
processThread ( 0 ), cancelPending ( false )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user