(trunk libT) fix the much-hated "Assertion failed: (tr_isPeerIo( io ))". Also, repeated calls to tr_date() were taking up about 78% of the time in tr_stat(), so instead of calling multiple times, call it once in tr_stat() and pass that value around to the functions that need it.

This commit is contained in:
Charles Kerr 2009-01-05 04:27:54 +00:00
parent b68a3bb96c
commit 5ccd5a7700
14 changed files with 92 additions and 60 deletions

View File

@ -33,10 +33,10 @@
***/
static float
getSpeed( const struct bratecontrol * r, int interval_msec )
getSpeed( const struct bratecontrol * r, int interval_msec, uint64_t now )
{
uint64_t bytes = 0;
const uint64_t cutoff = tr_date ( ) - interval_msec;
const uint64_t cutoff = (now?now:tr_date()) - interval_msec;
int i = r->newest;
for( ;; )
@ -205,6 +205,9 @@ tr_bandwidthAllocate( tr_bandwidth * b,
peers = (struct tr_peerIo**) tr_ptrArrayBase( &tmp );
peerCount = tr_ptrArraySize( &tmp );
for( i=0; i<peerCount; ++i )
tr_peerIoRef( peers[i] );
/* Stop all peers from listening for the socket to be ready for IO.
* See "Second phase of IO" lower in this function for more info. */
for( i=0; i<peerCount; ++i )
@ -246,6 +249,9 @@ tr_bandwidthAllocate( tr_bandwidth * b,
if( tr_peerIoHasBandwidthLeft( peers[i], dir ) )
tr_peerIoSetEnabled( peers[i], dir, TRUE );
for( i=0; i<peerCount; ++i )
tr_peerIoUnref( peers[i] );
/* cleanup */
tr_ptrArrayDestruct( &tmp, NULL );
}
@ -284,21 +290,21 @@ tr_bandwidthClamp( const tr_bandwidth * b,
}
double
tr_bandwidthGetRawSpeed( const tr_bandwidth * b, tr_direction dir )
tr_bandwidthGetRawSpeed( const tr_bandwidth * b, const uint64_t now, const tr_direction dir )
{
assert( tr_isBandwidth( b ) );
assert( tr_isDirection( dir ) );
return getSpeed( &b->band[dir].raw, HISTORY_MSEC );
return getSpeed( &b->band[dir].raw, HISTORY_MSEC, now );
}
double
tr_bandwidthGetPieceSpeed( const tr_bandwidth * b, tr_direction dir )
tr_bandwidthGetPieceSpeed( const tr_bandwidth * b, const uint64_t now, const tr_direction dir )
{
assert( tr_isBandwidth( b ) );
assert( tr_isDirection( dir ) );
return getSpeed( &b->band[dir].piece, HISTORY_MSEC );
return getSpeed( &b->band[dir].piece, HISTORY_MSEC, now );
}
static void

View File

@ -202,11 +202,13 @@ size_t tr_bandwidthClamp ( const tr_bandwidth * bandwidth,
/** @brief Get the raw total of bytes read or sent by this bandwidth subtree. */
double tr_bandwidthGetRawSpeed( const tr_bandwidth * bandwidth,
tr_direction direction );
const uint64_t now,
const tr_direction direction );
/** @brief Get the number of piece data bytes read or sent by this bandwidth subtree. */
double tr_bandwidthGetPieceSpeed( const tr_bandwidth * bandwidth,
tr_direction direction );
const uint64_t now,
const tr_direction direction );
/**
* @brief Notify the bandwidth object that some of its allocated bandwidth has been consumed.

View File

@ -1095,7 +1095,7 @@ void
tr_handshakeFree( tr_handshake * handshake )
{
if( handshake->io )
tr_peerIoFree( handshake->io );
tr_peerIoUnref( handshake->io );
tr_free( handshake );
}

View File

@ -118,6 +118,8 @@ canReadWrapper( tr_peerIo * io )
dbgmsg( io, "canRead" );
tr_peerIoRef( io );
/* try to consume the input buffer */
if( io->canRead )
{
@ -159,6 +161,8 @@ canReadWrapper( tr_peerIo * io )
tr_globalUnlock( session );
}
tr_peerIoUnref( io );
}
tr_bool
@ -166,6 +170,7 @@ tr_isPeerIo( const tr_peerIo * io )
{
return ( io != NULL )
&& ( io->magicNumber == MAGIC_NUMBER )
&& ( io->refCount > 0 )
&& ( tr_isBandwidth( &io->bandwidth ) )
&& ( tr_isAddress( &io->addr ) )
&& ( tr_isBool( io->isEncrypted ) )
@ -344,6 +349,7 @@ tr_peerIoNew( tr_session * session,
io = tr_new0( tr_peerIo, 1 );
io->magicNumber = MAGIC_NUMBER;
io->refCount = 1;
io->crypto = tr_cryptoNew( torrentHash, isIncoming );
io->session = session;
io->addr = *addr;
@ -424,7 +430,7 @@ io_dtor( void * vio )
tr_free( io );
}
void
static void
tr_peerIoFree( tr_peerIo * io )
{
if( io )
@ -436,6 +442,23 @@ tr_peerIoFree( tr_peerIo * io )
}
}
void
tr_peerIoRef( tr_peerIo * io )
{
assert( tr_isPeerIo( io ) );
++io->refCount;
}
void
tr_peerIoUnref( tr_peerIo * io )
{
assert( tr_isPeerIo( io ) );
if( !--io->refCount )
tr_peerIoFree( io );
}
const tr_address*
tr_peerIoGetAddress( const tr_peerIo * io,
tr_port * port )
@ -569,23 +592,23 @@ tr_peerIoEnableLTEP( tr_peerIo * io,
**/
static size_t
getDesiredOutputBufferSize( const tr_peerIo * io )
getDesiredOutputBufferSize( const tr_peerIo * io, uint64_t now )
{
/* this is all kind of arbitrary, but what seems to work well is
* being large enough to hold the next 20 seconds' worth of input,
* or a few blocks, whichever is bigger.
* It's okay to tweak this as needed */
const double maxBlockSize = 16 * 1024; /* 16 KiB is from BT spec */
const double currentSpeed = tr_bandwidthGetPieceSpeed( &io->bandwidth, TR_UP );
const double currentSpeed = tr_bandwidthGetPieceSpeed( &io->bandwidth, now, TR_UP );
const double period = 20; /* arbitrary */
const double numBlocks = 5.5; /* the 5 is arbitrary; the .5 is to leave room for messages */
return MAX( maxBlockSize*numBlocks, currentSpeed*1024*period );
}
size_t
tr_peerIoGetWriteBufferSpace( const tr_peerIo * io )
tr_peerIoGetWriteBufferSpace( const tr_peerIo * io, uint64_t now )
{
const size_t desiredLen = getDesiredOutputBufferSize( io );
const size_t desiredLen = getDesiredOutputBufferSize( io, now );
const size_t currentLen = EVBUFFER_LENGTH( io->outbuf );
size_t freeSpace = 0;

View File

@ -67,9 +67,12 @@ typedef struct tr_peerIo
int magicNumber;
uint8_t encryptionMode;
tr_port port;
int socket;
ssize_t refCount;
uint8_t peerId[SHA_DIGEST_LENGTH];
time_t timeCreated;
@ -110,7 +113,9 @@ tr_peerIo* tr_peerIoNewIncoming( tr_session * session,
tr_port port,
int socket );
void tr_peerIoFree ( tr_peerIo * io );
void tr_peerIoRef ( tr_peerIo * io );
void tr_peerIoUnref ( tr_peerIo * io );
tr_bool tr_isPeerIo ( const tr_peerIo * io );
@ -309,7 +314,7 @@ void tr_peerIoDrain( tr_peerIo * io,
***
**/
size_t tr_peerIoGetWriteBufferSpace( const tr_peerIo * io );
size_t tr_peerIoGetWriteBufferSpace( const tr_peerIo * io, uint64_t now );
static inline void tr_peerIoSetParent( tr_peerIo * io,
struct tr_bandwidth * parent )
@ -332,12 +337,12 @@ static inline tr_bool tr_peerIoHasBandwidthLeft( const tr_peerIo * io,
return tr_bandwidthClamp( &io->bandwidth, dir, 1024 ) > 0;
}
static inline double tr_peerIoGetPieceSpeed( const tr_peerIo * io, tr_direction dir )
static inline double tr_peerIoGetPieceSpeed( const tr_peerIo * io, uint64_t now, tr_direction dir )
{
assert( tr_isPeerIo( io ) );
assert( tr_isDirection( dir ) );
return tr_bandwidthGetPieceSpeed( &io->bandwidth, dir );
return tr_bandwidthGetPieceSpeed( &io->bandwidth, now, dir );
}
/**

View File

@ -76,6 +76,7 @@ typedef struct tr_peer
tr_peer;
double tr_peerGetPieceSpeed( const tr_peer * peer,
uint64_t now,
tr_direction direction );
#endif

View File

@ -144,7 +144,6 @@ struct tr_peerMgr
tr_session * session;
tr_ptrArray torrents; /* Torrent */
tr_ptrArray incomingHandshakes; /* tr_handshake */
tr_ptrArray finishedHandshakes; /* tr_handshake */
tr_timer * bandwidthTimer;
};
@ -356,7 +355,7 @@ peerDestructor( tr_peer * peer )
tr_peerMsgsFree( peer->msgs );
}
tr_peerIoFree( peer->io );
tr_peerIoUnref( peer->io );
tr_bitfieldFree( peer->have );
tr_bitfieldFree( peer->blame );
@ -459,7 +458,6 @@ tr_peerMgrNew( tr_session * session )
m->session = session;
m->torrents = TR_PTR_ARRAY_INIT;
m->incomingHandshakes = TR_PTR_ARRAY_INIT;
m->finishedHandshakes = TR_PTR_ARRAY_INIT;
m->bandwidthTimer = tr_timerNew( session, bandwidthPulse, m, BANDWIDTH_PERIOD_MSEC );
return m;
}
@ -467,8 +465,6 @@ tr_peerMgrNew( tr_session * session )
void
tr_peerMgrFree( tr_peerMgr * manager )
{
tr_handshake * handshake;
managerLock( manager );
tr_timerFree( &manager->bandwidthTimer );
@ -480,11 +476,6 @@ tr_peerMgrFree( tr_peerMgr * manager )
tr_ptrArrayDestruct( &manager->incomingHandshakes, NULL );
while(( handshake = tr_ptrArrayPop( &manager->finishedHandshakes )))
tr_handshakeFree( handshake );
tr_ptrArrayDestruct( &manager->finishedHandshakes, NULL );
/* free the torrents. */
tr_ptrArrayDestruct( &manager->torrents, torrentDestructor );
@ -1276,7 +1267,7 @@ myHandshakeDoneCB( tr_handshake * handshake,
}
if( !success )
tr_ptrArrayAppend( &manager->finishedHandshakes, handshake );
tr_handshakeFree( handshake );
if( t )
torrentUnlock( t );
@ -1793,6 +1784,7 @@ tr_peerMgrWebSpeeds( const tr_peerMgr * manager,
int i;
int webseedCount;
float * ret;
uint64_t now;
assert( manager );
managerLock( manager );
@ -1802,9 +1794,10 @@ tr_peerMgrWebSpeeds( const tr_peerMgr * manager,
webseedCount = tr_ptrArraySize( &t->webseeds );
assert( webseedCount == t->tor->info.webseedCount );
ret = tr_new0( float, webseedCount );
now = tr_date( );
for( i=0; i<webseedCount; ++i )
if( !tr_webseedGetSpeed( webseeds[i], &ret[i] ) )
if( !tr_webseedGetSpeed( webseeds[i], now, &ret[i] ) )
ret[i] = -1.0;
managerUnlock( manager );
@ -1812,9 +1805,9 @@ tr_peerMgrWebSpeeds( const tr_peerMgr * manager,
}
double
tr_peerGetPieceSpeed( const tr_peer * peer, tr_direction direction )
tr_peerGetPieceSpeed( const tr_peer * peer, uint64_t now, tr_direction direction )
{
return peer->io ? tr_peerIoGetPieceSpeed( peer->io, direction ) : 0.0;
return peer->io ? tr_peerIoGetPieceSpeed( peer->io, now, direction ) : 0.0;
}
@ -1827,6 +1820,7 @@ tr_peerMgrPeerStats( const tr_peerMgr * manager,
const Torrent * t;
const tr_peer ** peers;
tr_peer_stat * ret;
uint64_t now;
assert( manager );
managerLock( manager );
@ -1835,6 +1829,7 @@ tr_peerMgrPeerStats( const tr_peerMgr * manager,
size = tr_ptrArraySize( &t->peers );
peers = (const tr_peer**) tr_ptrArrayBase( &t->peers );
ret = tr_new0( tr_peer_stat, size );
now = tr_date( );
for( i = 0; i < size; ++i )
{
@ -1853,8 +1848,8 @@ tr_peerMgrPeerStats( const tr_peerMgr * manager,
stat->from = atom->from;
stat->progress = peer->progress;
stat->isEncrypted = tr_peerIoIsEncrypted( peer->io ) ? 1 : 0;
stat->rateToPeer = tr_peerGetPieceSpeed( peer, TR_CLIENT_TO_PEER );
stat->rateToClient = tr_peerGetPieceSpeed( peer, TR_PEER_TO_CLIENT );
stat->rateToPeer = tr_peerGetPieceSpeed( peer, now, TR_CLIENT_TO_PEER );
stat->rateToClient = tr_peerGetPieceSpeed( peer, now, TR_PEER_TO_CLIENT );
stat->peerIsChoked = peer->peerIsChoked;
stat->peerIsInterested = peer->peerIsInterested;
stat->clientIsChoked = peer->clientIsChoked;
@ -1937,6 +1932,7 @@ rechoke( Torrent * t )
tr_peer ** peers = (tr_peer**) tr_ptrArrayBase( &t->peers );
struct ChokeData * choke = tr_new0( struct ChokeData, peerCount );
const int chokeAll = !tr_torrentIsPieceTransferAllowed( t->tor, TR_CLIENT_TO_PEER );
const uint64_t now = tr_date( );
assert( torrentIsLocked( t ) );
@ -1964,7 +1960,7 @@ rechoke( Torrent * t )
n->peer = peer;
n->isInterested = peer->peerIsInterested;
n->isChoked = peer->peerIsChoked;
n->rate = tr_peerGetPieceSpeed( peer, TR_CLIENT_TO_PEER ) * 1024;
n->rate = tr_peerGetPieceSpeed( peer, now, TR_CLIENT_TO_PEER ) * 1024;
}
}
@ -2373,7 +2369,6 @@ pumpAllPeers( tr_peerMgr * mgr )
static int
bandwidthPulse( void * vmgr )
{
tr_handshake * handshake;
tr_peerMgr * mgr = vmgr;
managerLock( mgr );
@ -2384,10 +2379,6 @@ bandwidthPulse( void * vmgr )
tr_bandwidthAllocate( mgr->session->bandwidth, TR_UP, BANDWIDTH_PERIOD_MSEC );
tr_bandwidthAllocate( mgr->session->bandwidth, TR_DOWN, BANDWIDTH_PERIOD_MSEC );
/* free all the finished handshakes */
while(( handshake = tr_ptrArrayPop( &mgr->finishedHandshakes )))
tr_handshakeFree( handshake );
managerUnlock( mgr );
return TRUE;
}

View File

@ -1638,10 +1638,9 @@ canRead( tr_peerIo * io, void * vmsgs, size_t * piece )
**/
static int
ratePulse( void * vmsgs )
ratePulse( tr_peermsgs * msgs, uint64_t now )
{
tr_peermsgs * msgs = vmsgs;
const double rateToClient = tr_peerGetPieceSpeed( msgs->peer, TR_PEER_TO_CLIENT );
const double rateToClient = tr_peerGetPieceSpeed( msgs->peer, now, TR_PEER_TO_CLIENT );
const int seconds = 10;
const int floor = 8;
const int estimatedBlocksInPeriod = ( rateToClient * seconds * 1024 ) / msgs->torrent->blockSize;
@ -1687,7 +1686,7 @@ fillOutputBuffer( tr_peermsgs * msgs, time_t now )
*** Blocks
**/
if( ( tr_peerIoGetWriteBufferSpace( msgs->peer->io ) >= msgs->torrent->blockSize )
if( ( tr_peerIoGetWriteBufferSpace( msgs->peer->io, now ) >= msgs->torrent->blockSize )
&& popNextRequest( msgs, &req ) )
{
if( requestIsValid( msgs, &req )
@ -1747,7 +1746,7 @@ peerPulse( void * vmsgs )
tr_peermsgs * msgs = vmsgs;
const time_t now = time( NULL );
ratePulse( msgs );
ratePulse( msgs, now );
pumpRequestQueue( msgs, now );
expireOldRequests( msgs, now );
@ -2123,7 +2122,7 @@ tr_peerMsgsNew( struct tr_torrent * torrent,
tellPeerWhatWeHave( m );
tr_peerIoSetIOFuncs( m->peer->io, canRead, didWrite, gotError, m );
ratePulse( m );
ratePulse( m, tr_date() );
return m;
}

View File

@ -32,10 +32,11 @@
/* return the xfer rate over the last `interval' seconds in KiB/sec */
static float
rateForInterval( const tr_ratecontrol * r,
int interval_msec )
int interval_msec,
uint64_t now )
{
uint64_t bytes = 0;
const uint64_t cutoff = tr_date ( ) - interval_msec;
const uint64_t cutoff = (now?now:tr_date()) - interval_msec;
int i = r->newest;
for( ; ; )
@ -57,12 +58,12 @@ rateForInterval( const tr_ratecontrol * r,
***/
float
tr_rcRate( const tr_ratecontrol * r )
tr_rcRate( const tr_ratecontrol * r, uint64_t now )
{
float ret = 0.0f;
if( r )
ret = rateForInterval( r, TR_RC_HISTORY_MSEC );
ret = rateForInterval( r, TR_RC_HISTORY_MSEC, now );
return ret;
}

View File

@ -70,7 +70,8 @@ static inline void tr_rcDestruct ( tr_ratecontrol * rc ) { memset( rc, 0xDEAD,
void tr_rcTransferred ( tr_ratecontrol * ratecontrol,
size_t byteCount );
float tr_rcRate ( const tr_ratecontrol * ratecontrol );
float tr_rcRate ( const tr_ratecontrol * ratecontrol,
uint64_t now );
#endif

View File

@ -735,13 +735,13 @@ tr_sessionGetPeerLimitPerTorrent( const tr_session * session )
double
tr_sessionGetPieceSpeed( const tr_session * session, tr_direction dir )
{
return session ? tr_bandwidthGetPieceSpeed( session->bandwidth, dir ) : 0.0;
return session ? tr_bandwidthGetPieceSpeed( session->bandwidth, 0, dir ) : 0.0;
}
double
tr_sessionGetRawSpeed( const tr_session * session, tr_direction dir )
{
return session ? tr_bandwidthGetPieceSpeed( session->bandwidth, dir ) : 0.0;
return session ? tr_bandwidthGetPieceSpeed( session->bandwidth, 0, dir ) : 0.0;
}
int

View File

@ -722,6 +722,7 @@ tr_torrentStat( tr_torrent * tor )
struct tr_tracker * tc;
const tr_tracker_info * ti;
int usableSeeds = 0;
uint64_t now;
if( !tor )
return NULL;
@ -758,10 +759,12 @@ tr_torrentStat( tr_torrent * tor )
&s->peersGettingFromUs,
s->peersFrom );
s->rawUploadSpeed = tr_bandwidthGetRawSpeed ( tor->bandwidth, TR_UP );
s->rawDownloadSpeed = tr_bandwidthGetRawSpeed ( tor->bandwidth, TR_DOWN );
s->pieceUploadSpeed = tr_bandwidthGetPieceSpeed( tor->bandwidth, TR_UP );
s->pieceDownloadSpeed = tr_bandwidthGetPieceSpeed( tor->bandwidth, TR_DOWN );
now = tr_date( );
s->swarmSpeed = tr_rcRate( &tor->swarmSpeed, now );
s->rawUploadSpeed = tr_bandwidthGetRawSpeed ( tor->bandwidth, now, TR_UP );
s->rawDownloadSpeed = tr_bandwidthGetRawSpeed ( tor->bandwidth, now, TR_DOWN );
s->pieceUploadSpeed = tr_bandwidthGetPieceSpeed( tor->bandwidth, now, TR_UP );
s->pieceDownloadSpeed = tr_bandwidthGetPieceSpeed( tor->bandwidth, now, TR_DOWN );
usableSeeds += tor->info.webseedCount;
@ -777,7 +780,6 @@ tr_torrentStat( tr_torrent * tor )
(double) tor->info.pieceCount )
: 0.0;
s->swarmSpeed = tr_rcRate( &tor->swarmSpeed );
s->activityDate = tor->activityDate;
s->addedDate = tor->addedDate;

View File

@ -252,11 +252,11 @@ tr_webseedIsActive( const tr_webseed * w )
}
int
tr_webseedGetSpeed( const tr_webseed * w, float * setme_KiBs )
tr_webseedGetSpeed( const tr_webseed * w, uint64_t now, float * setme_KiBs )
{
const int isActive = tr_webseedIsActive( w );
*setme_KiBs = isActive ? tr_rcRate( &w->rateDown ) : 0.0f;
*setme_KiBs = isActive ? tr_rcRate( &w->rateDown, now ) : 0.0f;
return isActive;
}

View File

@ -36,6 +36,7 @@ tr_addreq_t tr_webseedAddRequest( tr_webseed * w,
/** @return true if a request is being processed, or false if idle */
int tr_webseedGetSpeed( const tr_webseed * w,
uint64_t now,
float * setme_KiBs );
/** @return true if a request is being processed, or false if idle */