large array changes
This commit is contained in:
@@ -23,22 +23,35 @@
|
||||
#include "udpiiu.h"
|
||||
#undef epicsExportSharedSymbols
|
||||
|
||||
static const unsigned maxSearchTries = 100u; // max tries on unchanged net
|
||||
static const unsigned initialTriesPerFrame = 1u; // initial UDP frames per search try
|
||||
static const unsigned maxTriesPerFrame = 64u; // max UDP frames per search try
|
||||
|
||||
static const double initialRoundTripEstimate = 0.250; // seconds
|
||||
static const double minSearchPeriod = 0.030; // seconds
|
||||
static const double maxSearchPeriod = 5.0; // seconds
|
||||
|
||||
//
|
||||
// searchTimer::searchTimer ()
|
||||
//
|
||||
searchTimer::searchTimer ( udpiiu &iiuIn, epicsTimerQueue &queueIn, epicsMutex &mutexIn ) :
|
||||
timer ( queueIn.createTimer ( *this ) ),
|
||||
period ( initialRoundTripEstimate * 2.0 ),
|
||||
roundTripDelayEstimate ( initialRoundTripEstimate ),
|
||||
timer ( queueIn.createTimer () ),
|
||||
mutex ( mutexIn ),
|
||||
iiu ( iiuIn ),
|
||||
framesPerTry ( INITIALTRIESPERFRAME ),
|
||||
framesPerTry ( initialTriesPerFrame ),
|
||||
framesPerTryCongestThresh ( UINT_MAX ),
|
||||
minRetry ( UINT_MAX ),
|
||||
retry ( 0u ),
|
||||
searchTriesWithinThisPass ( 0u ),
|
||||
searchResponsesWithinThisPass ( 0u ),
|
||||
searchAttempts ( 0u ),
|
||||
searchResponses ( 0u ),
|
||||
searchAttemptsThisPass ( 0u ),
|
||||
searchResponsesThisPass ( 0u ),
|
||||
retrySeqNo ( 0u ),
|
||||
retrySeqAtPassBegin ( 0u ),
|
||||
period ( CA_RECAST_DELAY )
|
||||
active ( false ),
|
||||
noDelay ( false )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -52,59 +65,68 @@ searchTimer::~searchTimer ()
|
||||
//
|
||||
void searchTimer::resetPeriod ( double delayToNextTry )
|
||||
{
|
||||
bool reschedule;
|
||||
|
||||
if ( delayToNextTry < CA_RECAST_DELAY ) {
|
||||
delayToNextTry = CA_RECAST_DELAY;
|
||||
}
|
||||
|
||||
{
|
||||
epicsAutoMutex locker ( this->mutex );
|
||||
this->retry = 0;
|
||||
if ( this->period > delayToNextTry ) {
|
||||
reschedule = true;
|
||||
bool start;
|
||||
|
||||
delayToNextTry += initialRoundTripEstimate;
|
||||
|
||||
this->retry = 0;
|
||||
if ( this->iiu.channelCount () > 0 ) {
|
||||
if ( this->period > delayToNextTry || ! this->active ) {
|
||||
this->active = true;
|
||||
this->noDelay = delayToNextTry == 0.0;
|
||||
start = true;
|
||||
}
|
||||
else {
|
||||
reschedule = false;
|
||||
start = false;
|
||||
}
|
||||
this->period = CA_RECAST_DELAY;
|
||||
}
|
||||
|
||||
if ( reschedule ) {
|
||||
this->timer.start ( delayToNextTry );
|
||||
debugPrintf ( ("rescheduled search timer for completion in %f sec\n", delayToNextTry) );
|
||||
}
|
||||
else {
|
||||
this->timer.start ( delayToNextTry );
|
||||
debugPrintf ( ("if inactive, search timer started to completion in %f sec\n", delayToNextTry) );
|
||||
start = false;
|
||||
}
|
||||
// upper bound
|
||||
//this->period = initialRoundTripEstimate * 2.0;
|
||||
double newPeriod = this->roundTripDelayEstimate * 2.0;
|
||||
if ( newPeriod <= initialRoundTripEstimate * 2.0 ) {
|
||||
this->period = newPeriod;
|
||||
}
|
||||
else {
|
||||
this->period = initialRoundTripEstimate * 2.0;
|
||||
}
|
||||
// lower bound
|
||||
if ( this->period < minSearchPeriod ) {
|
||||
this->period = minSearchPeriod;
|
||||
}
|
||||
|
||||
if ( start ) {
|
||||
epicsAutoMutexRelease autoRelease ( this->mutex );
|
||||
this->timer.start ( *this, delayToNextTry );
|
||||
// debugPrintf ( ("rescheduled search timer for completion in %f sec\n", delayToNextTry) );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* searchTimer::setRetryInterval ()
|
||||
*/
|
||||
void searchTimer::setRetryInterval (unsigned retryNo)
|
||||
void searchTimer::setRetryInterval ( unsigned retryNo )
|
||||
{
|
||||
unsigned idelay;
|
||||
double delay;
|
||||
|
||||
epicsAutoMutex locker ( this->mutex );
|
||||
|
||||
/*
|
||||
* set the retry number
|
||||
*/
|
||||
this->retry = tsMin ( retryNo, MAXCONNTRIES + 1u );
|
||||
this->retry = tsMin ( retryNo, maxSearchTries + 1u );
|
||||
|
||||
/*
|
||||
* set the retry interval
|
||||
*/
|
||||
idelay = 1u << tsMin ( static_cast < size_t > ( this->retry ),
|
||||
CHAR_BIT * sizeof ( idelay ) - 1u );
|
||||
delay = idelay * CA_RECAST_DELAY; /* sec */
|
||||
/*
|
||||
* place upper limit on the retry delay
|
||||
*/
|
||||
this->period = tsMin ( CA_RECAST_PERIOD, delay );
|
||||
delay = idelay * this->roundTripDelayEstimate * 2.0; /* sec */
|
||||
//delay = idelay * initialRoundTripEstimate * 2.0; /* sec */
|
||||
|
||||
this->period = tsMin ( maxSearchPeriod, delay );
|
||||
this->period = tsMax ( minSearchPeriod, this->period );
|
||||
|
||||
debugPrintf ( ("new CA search period is %f sec\n", this->period) );
|
||||
}
|
||||
@@ -116,31 +138,55 @@ void searchTimer::setRetryInterval (unsigned retryNo)
|
||||
// at least one response. However, dont reset this delay if we
|
||||
// get a delayed response to an old search request.
|
||||
//
|
||||
void searchTimer::notifySearchResponse ( unsigned short retrySeqNoIn )
|
||||
void searchTimer::notifySearchResponse ( unsigned short retrySeqNoIn,
|
||||
const epicsTime & currentTime )
|
||||
{
|
||||
bool reschedualNeeded;
|
||||
|
||||
{
|
||||
epicsAutoMutex locker ( this->mutex );
|
||||
if ( this->retrySeqAtPassBegin <= retrySeqNoIn ) {
|
||||
if ( this->searchResponses < UINT_MAX ) {
|
||||
this->searchResponses++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( this->retrySeqAtPassBegin <= retrySeqNoIn ) {
|
||||
if ( this->searchResponsesWithinThisPass < UINT_MAX ) {
|
||||
this->searchResponsesWithinThisPass++;
|
||||
}
|
||||
}
|
||||
if ( retrySeqNoIn == this->retrySeqNo && ! this->noDelay ) {
|
||||
double curRTT = currentTime - this->timeAtLastRetry;
|
||||
this->roundTripDelayEstimate =
|
||||
( this->roundTripDelayEstimate + curRTT ) / 2.0;
|
||||
this->period = this->roundTripDelayEstimate * 2.0;
|
||||
this->period = tsMin ( maxSearchPeriod, this->period );
|
||||
this->period = tsMax ( minSearchPeriod, this->period );
|
||||
reschedualNeeded = true;
|
||||
this->active = true;
|
||||
this->noDelay = true;
|
||||
}
|
||||
|
||||
reschedualNeeded = ( retrySeqNoIn == this->retrySeqNo );
|
||||
if ( this->searchResponses == this->searchAttempts ) {
|
||||
reschedualNeeded = true;
|
||||
this->active = true;
|
||||
this->noDelay = true;
|
||||
}
|
||||
else {
|
||||
reschedualNeeded = false;
|
||||
}
|
||||
|
||||
if ( reschedualNeeded ) {
|
||||
this->timer.start ( 0.0 );
|
||||
epicsAutoMutexRelease autoRelease (this->mutex );
|
||||
# if defined(DEBUG) && 0
|
||||
char buf[64];
|
||||
epicsTime ts = epicsTime::getCurrent();
|
||||
ts.strftime ( buf, sizeof(buf), "%M:%S.%09f");
|
||||
# endif
|
||||
// debugPrintf ( ( "Response set timer delay to zero. ts=%s, RTT=%f sec\n",
|
||||
// buf, this->roundTripDelayEstimate ) );
|
||||
this->timer.start ( *this, currentTime );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// searchTimer::expire ()
|
||||
//
|
||||
epicsTimerNotify::expireStatus searchTimer::expire ()
|
||||
epicsTimerNotify::expireStatus searchTimer::expire ( const epicsTime & currentTime )
|
||||
{
|
||||
epicsAutoMutex locker ( this->mutex );
|
||||
unsigned nFrameSent = 0u;
|
||||
@@ -150,6 +196,9 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
|
||||
* check to see if there is nothing to do here
|
||||
*/
|
||||
if ( this->iiu.channelCount () == 0 ) {
|
||||
this->active = false;
|
||||
this->noDelay = false;
|
||||
debugPrintf ( ( "all channels located - search timer terminating\n" ) );
|
||||
return noRestart;
|
||||
}
|
||||
|
||||
@@ -157,6 +206,7 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
|
||||
* increment the retry sequence number
|
||||
*/
|
||||
this->retrySeqNo++; /* allowed to roll over */
|
||||
this->timeAtLastRetry = currentTime;
|
||||
|
||||
/*
|
||||
* dynamically adjust the number of UDP frames per
|
||||
@@ -185,12 +235,12 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
|
||||
* increase frames per try only if we see better than
|
||||
* a 93.75% success rate for one pass through the list
|
||||
*/
|
||||
if (this->searchResponsesWithinThisPass >
|
||||
(this->searchTriesWithinThisPass-(this->searchTriesWithinThisPass/16u)) ) {
|
||||
if ( this->searchResponses >
|
||||
( this->searchAttempts - (this->searchAttempts/16u) ) ) {
|
||||
/*
|
||||
* increase UDP frames per try if we have a good score
|
||||
*/
|
||||
if ( this->framesPerTry < MAXTRIESPERFRAME ) {
|
||||
if ( this->framesPerTry < maxTriesPerFrame ) {
|
||||
/*
|
||||
* a congestion avoidance threshold similar to TCP is now used
|
||||
*/
|
||||
@@ -201,24 +251,38 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
|
||||
this->framesPerTry += (this->framesPerTry/8) + 1;
|
||||
}
|
||||
debugPrintf ( ("Increasing frame count to %u t=%u r=%u\n",
|
||||
this->framesPerTry, this->searchTriesWithinThisPass, this->searchResponsesWithinThisPass) );
|
||||
this->framesPerTry, this->searchAttempts, this->searchResponses) );
|
||||
}
|
||||
}
|
||||
/*
|
||||
* if we detect congestion because we have less than a 87.5% success
|
||||
* rate then gradually reduce the frames per try
|
||||
*/
|
||||
else if ( this->searchResponsesWithinThisPass <
|
||||
(this->searchTriesWithinThisPass-(this->searchTriesWithinThisPass/8u)) ) {
|
||||
if (this->framesPerTry>1) {
|
||||
this->framesPerTry--;
|
||||
}
|
||||
this->framesPerTryCongestThresh = this->framesPerTry/2 + 1;
|
||||
debugPrintf ( ("Congestion detected - set frames per try to %u t=%u r=%u\n",
|
||||
this->framesPerTry, this->searchTriesWithinThisPass,
|
||||
this->searchResponsesWithinThisPass) );
|
||||
else if ( this->searchResponses <
|
||||
( this->searchAttempts - (this->searchAttempts/8u) ) ) {
|
||||
if (this->framesPerTry>1) {
|
||||
this->framesPerTry--;
|
||||
}
|
||||
this->framesPerTryCongestThresh = this->framesPerTry/2 + 1;
|
||||
debugPrintf ( ("Congestion detected - set frames per try to %u t=%u r=%u\n",
|
||||
this->framesPerTry, this->searchAttempts, this->searchResponses) );
|
||||
}
|
||||
|
||||
if ( this->searchAttemptsThisPass <= UINT_MAX - this->searchAttempts ) {
|
||||
this->searchAttemptsThisPass += this->searchAttempts;
|
||||
}
|
||||
else {
|
||||
this->searchAttemptsThisPass = UINT_MAX;
|
||||
}
|
||||
if ( this->searchResponsesThisPass <= UINT_MAX - this->searchResponses ) {
|
||||
this->searchResponsesThisPass += this->searchResponses;
|
||||
}
|
||||
else {
|
||||
this->searchResponsesThisPass = UINT_MAX;
|
||||
}
|
||||
this->searchAttempts = 0;
|
||||
this->searchResponses = 0;
|
||||
|
||||
while ( 1 ) {
|
||||
|
||||
/*
|
||||
@@ -228,8 +292,8 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
|
||||
* dont increase the delay between search
|
||||
* requests
|
||||
*/
|
||||
if ( this->searchTriesWithinThisPass >= this->iiu.channelCount () ) {
|
||||
if ( this->searchResponsesWithinThisPass == 0u ) {
|
||||
if ( this->searchAttemptsThisPass >= this->iiu.channelCount () ) {
|
||||
if ( this->searchResponsesThisPass == 0u ) {
|
||||
debugPrintf ( ("increasing search try interval\n") );
|
||||
this->setRetryInterval ( this->minRetry + 1u );
|
||||
}
|
||||
@@ -250,8 +314,8 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
|
||||
*/
|
||||
this->retrySeqAtPassBegin = this->retrySeqNo;
|
||||
|
||||
this->searchTriesWithinThisPass = 0;
|
||||
this->searchResponsesWithinThisPass = 0;
|
||||
this->searchAttemptsThisPass = 0;
|
||||
this->searchResponsesThisPass = 0;
|
||||
|
||||
debugPrintf ( ("saw end of list\n") );
|
||||
}
|
||||
@@ -275,8 +339,8 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
|
||||
this->minRetry = retryNoForThisChannel;
|
||||
}
|
||||
|
||||
if ( this->searchTriesWithinThisPass < UINT_MAX ) {
|
||||
this->searchTriesWithinThisPass++;
|
||||
if ( this->searchAttempts < UINT_MAX ) {
|
||||
this->searchAttempts++;
|
||||
}
|
||||
if ( nChanSent < UINT_MAX ) {
|
||||
nChanSent++;
|
||||
@@ -308,15 +372,29 @@ epicsTimerNotify::expireStatus searchTimer::expire ()
|
||||
// flush out the search request buffer
|
||||
this->iiu.datagramFlush ();
|
||||
|
||||
debugPrintf ( ("sent %u delay sec=%f\n", nFrameSent, this->period) );
|
||||
# ifdef DEBUG
|
||||
char buf[64];
|
||||
epicsTime ts = epicsTime::getCurrent();
|
||||
ts.strftime ( buf, sizeof(buf), "%M:%S.%09f");
|
||||
debugPrintf ( ("sent %u delay sec=%f RTT=%f ts=%s\n",
|
||||
nFrameSent, this->period,
|
||||
this->roundTripDelayEstimate, buf ) );
|
||||
# endif
|
||||
|
||||
if ( this->iiu.channelCount () == 0 ) {
|
||||
debugPrintf ( ( "all channels connected\n" ) );
|
||||
this->active = false;
|
||||
this->noDelay = false;
|
||||
return noRestart;
|
||||
}
|
||||
else if ( this->retry < MAXCONNTRIES ) {
|
||||
else if ( this->retry < maxSearchTries ) {
|
||||
this->noDelay = this->period == 0.0;
|
||||
return expireStatus ( restart, this->period );
|
||||
}
|
||||
else {
|
||||
debugPrintf ( ( "maximum search tries exceeded - giving up\n" ) );
|
||||
this->active = false;
|
||||
this->noDelay = false;
|
||||
return noRestart;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user