void tr_bandwidthSetParent( tr_bandwidth * b, tr_bandwidth * parent ) { assert( tr_isBandwidth( b ) ); assert( b != parent ); if( b->parent ) { void * removed; assert( tr_isBandwidth( b->parent ) ); removed = tr_ptrArrayRemoveSorted( &b->parent->children, b, comparePointers ); assert( removed == b ); assert( tr_ptrArrayFindSorted( &b->parent->children, b, comparePointers ) == NULL ); b->parent = NULL; } if( parent ) { assert( tr_isBandwidth( parent ) ); assert( parent->parent != b ); tr_ptrArrayInsertSorted( &parent->children, b, comparePointers ); assert( tr_ptrArrayFindSorted( &parent->children, b, comparePointers ) == b ); b->parent = parent; } }
static void allocateBandwidth (tr_bandwidth * b, tr_priority_t parent_priority, tr_direction dir, unsigned int period_msec, tr_ptrArray * peer_pool) { const tr_priority_t priority = MAX (parent_priority, b->priority); assert (tr_isBandwidth (b)); assert (tr_isDirection (dir)); /* set the available bandwidth */ if (b->band[dir].isLimited) { const uint64_t nextPulseSpeed = b->band[dir].desiredSpeed_Bps; b->band[dir].bytesLeft = (unsigned int)(nextPulseSpeed * period_msec) / 1000u; } /* add this bandwidth's peer, if any, to the peer pool */ if (b->peer != NULL) { b->peer->priority = priority; tr_ptrArrayAppend (peer_pool, b->peer); } /* traverse & repeat for the subtree */ if (1) { int i; struct tr_bandwidth ** children = (struct tr_bandwidth**) tr_ptrArrayBase (&b->children); const int n = tr_ptrArraySize (&b->children); for (i=0; i<n; ++i) allocateBandwidth (children[i], priority, dir, period_msec, peer_pool); } }
void tr_bandwidthUsed( tr_bandwidth * b, tr_direction dir, size_t byteCount, tr_bool isPieceData, uint64_t now ) { struct tr_band * band; assert( tr_isBandwidth( b ) ); assert( tr_isDirection( dir ) ); band = &b->band[dir]; if( band->isLimited && isPieceData ) band->bytesLeft -= MIN( band->bytesLeft, byteCount ); #ifdef DEBUG_DIRECTION if( ( dir == DEBUG_DIRECTION ) && ( band->isLimited ) ) fprintf( stderr, "%p consumed %5zu bytes of %5s data... was %6zu, now %6zu left\n", b, byteCount, (isPieceData?"piece":"raw"), oldBytesLeft, band->bytesLeft ); #endif bytesUsed( now, &band->raw, byteCount ); if( isPieceData ) bytesUsed( now, &band->piece, byteCount ); if( b->parent != NULL ) tr_bandwidthUsed( b->parent, dir, byteCount, isPieceData, now ); }
double tr_bandwidthGetPieceSpeed( const tr_bandwidth * b, tr_direction dir ) { assert( tr_isBandwidth( b ) ); assert( tr_isDirection( dir ) ); return getSpeed( &b->band[dir].piece, HISTORY_MSEC ); }
unsigned int tr_bandwidthGetPieceSpeed_Bps( const tr_bandwidth * b, const uint64_t now, const tr_direction dir ) { assert( tr_isBandwidth( b ) ); assert( tr_isDirection( dir ) ); return getSpeed_Bps( &b->band[dir].piece, HISTORY_MSEC, now ); }
void tr_bandwidthSetPeer( tr_bandwidth * b, tr_peerIo * peer ) { assert( tr_isBandwidth( b ) ); assert( ( peer == NULL ) || tr_isPeerIo( peer ) ); b->peer = peer; }
tr_bool tr_isPeerIo( const tr_peerIo * io ) { return ( io != NULL ) && ( io->magicNumber == MAGIC_NUMBER ) && ( io->refCount >= 0 ) && ( tr_isBandwidth( &io->bandwidth ) ) && ( tr_isAddress( &io->addr ) ); }
void tr_bandwidthRemovePeer( tr_bandwidth * b, tr_peerIo * peerIo ) { assert( tr_isBandwidth( b ) ); assert( tr_isPeerIo( peerIo ) ); tr_ptrArrayRemoveSorted( b->peers, peerIo, comparePointers ); }
tr_bool tr_bandwidthIsLimited( const tr_bandwidth * b, tr_direction dir ) { assert( tr_isBandwidth( b ) ); assert( tr_isDirection( dir ) ); return b->band[dir].isLimited; }
double tr_bandwidthGetDesiredSpeed( const tr_bandwidth * b, tr_direction dir ) { assert( tr_isBandwidth( b ) ); assert( tr_isDirection( dir ) ); return b->band[dir].desiredSpeed; }
void tr_bandwidthHonorParentLimits( tr_bandwidth * b, tr_direction dir, tr_bool honorParentLimits ) { assert( tr_isBandwidth( b ) ); assert( tr_isDirection( dir ) ); b->band[dir].honorParentLimits = honorParentLimits; }
void tr_bandwidthDestruct (tr_bandwidth * b) { assert (tr_isBandwidth (b)); tr_bandwidthSetParent (b, NULL); tr_ptrArrayDestruct (&b->children, NULL); memset (b, ~0, sizeof (tr_bandwidth)); }
void tr_bandwidthSetDesiredSpeed( tr_bandwidth * b, tr_direction dir, double desiredSpeed ) { assert( tr_isBandwidth( b ) ); assert( tr_isDirection( dir ) ); b->band[dir].desiredSpeed = desiredSpeed; }
void tr_bandwidthSetLimited( tr_bandwidth * b, tr_direction dir, tr_bool isLimited ) { assert( tr_isBandwidth( b ) ); assert( tr_isDirection( dir ) ); b->band[dir].isLimited = isLimited; }
void tr_bandwidthFree( tr_bandwidth * b ) { assert( tr_isBandwidth( b ) ); tr_bandwidthSetParent( b, NULL ); tr_ptrArrayFree( b->peers, NULL ); tr_ptrArrayFree( b->children, NULL ); b->magicNumber = 0xDEAD; tr_free( b ); }
static void allocateBandwidth( tr_bandwidth * b, tr_priority_t parent_priority, tr_direction dir, unsigned int period_msec, tr_ptrArray * peer_pool ) { tr_priority_t priority; assert( tr_isBandwidth( b ) ); assert( tr_isDirection( dir ) ); /* set the available bandwidth */ if( b->band[dir].isLimited ) { const unsigned int nextPulseSpeed = b->band[dir].desiredSpeed_Bps; b->band[dir].bytesLeft = ( nextPulseSpeed * period_msec ) / 1000u; #ifdef DEBUG_DIRECTION if( dir == DEBUG_DIRECTION ) fprintf( stderr, "bandwidth %p currentPieceSpeed(%5.2f of %5.2f) desiredSpeed(%5.2f), allocating %d\n", b, currentSpeed, tr_bandwidthGetRawSpeed( b, dir ), desiredSpeed, b->band[dir].bytesLeft ); #endif } priority = MAX( parent_priority, b->priority ); /* add this bandwidth's peer, if any, to the peer pool */ if( b->peer != NULL ) { b->peer->priority = priority; tr_ptrArrayAppend( peer_pool, b->peer ); } #ifdef DEBUG_DIRECTION if( ( dir == DEBUG_DIRECTION ) && ( n > 1 ) ) fprintf( stderr, "bandwidth %p has %d peers\n", b, n ); #endif /* traverse & repeat for the subtree */ if( 1 ) { int i; struct tr_bandwidth ** children = (struct tr_bandwidth**) tr_ptrArrayBase( &b->children ); const int n = tr_ptrArraySize( &b->children ); for( i=0; i<n; ++i ) allocateBandwidth( children[i], priority, dir, period_msec, peer_pool ); } }
static void allocateBandwidth( tr_bandwidth * b, tr_direction dir, int period_msec, tr_ptrArray * peer_pool ) { assert( tr_isBandwidth( b ) ); assert( tr_isDirection( dir ) ); /* set the available bandwidth */ if( b->band[dir].isLimited ) { const double desiredSpeed = b->band[dir].desiredSpeed; const double nextPulseSpeed = desiredSpeed; b->band[dir].bytesLeft = MAX( 0.0, nextPulseSpeed * 1024.0 * period_msec / 1000.0 ); #ifdef DEBUG_DIRECTION if( dir == DEBUG_DIRECTION ) fprintf( stderr, "bandwidth %p currentPieceSpeed(%5.2f of %5.2f) desiredSpeed(%5.2f), allocating %5.2f\n", b, currentSpeed, tr_bandwidthGetRawSpeed( b, dir ), desiredSpeed, b->band[dir].bytesLeft/1024.0 ); #endif } /* traverse & repeat for the subtree */ { int i; const int n = tr_ptrArraySize( b->peers ); for( i=0; i<n; ++i ) tr_ptrArrayAppend( peer_pool, tr_ptrArrayNth( b->peers, i ) ); } #ifdef DEBUG_DIRECTION if( ( dir == DEBUG_DIRECTION ) && ( n > 1 ) ) fprintf( stderr, "bandwidth %p has %d peers\n", b, n ); #endif /* all children should reallocate too */ if( 1 ) { int i, n=0; struct tr_bandwidth ** children = (struct tr_bandwidth**) tr_ptrArrayPeek( b->children, &n ); for( i=0; i<n; ++i ) allocateBandwidth( children[i], dir, period_msec, peer_pool ); } }
unsigned int tr_bandwidthClamp( const tr_bandwidth * b, tr_direction dir, unsigned int byteCount ) { assert( tr_isBandwidth( b ) ); assert( tr_isDirection( dir ) ); if( b ) { if( b->band[dir].isLimited ) byteCount = MIN( byteCount, b->band[dir].bytesLeft ); if( b->parent && b->band[dir].honorParentLimits ) byteCount = tr_bandwidthClamp( b->parent, dir, byteCount ); } return byteCount; }
static unsigned int bandwidthClamp (const tr_bandwidth * b, uint64_t now, tr_direction dir, unsigned int byteCount) { assert (tr_isBandwidth (b)); assert (tr_isDirection (dir)); if (b) { if (b->band[dir].isLimited) { byteCount = MIN (byteCount, b->band[dir].bytesLeft); /* if we're getting close to exceeding the speed limit, * clamp down harder on the bytes available */ if (byteCount > 0) { double current; double desired; double r; if (now == 0) now = tr_time_msec (); current = tr_bandwidthGetRawSpeed_Bps (b, now, TR_DOWN); desired = tr_bandwidthGetDesiredSpeed_Bps (b, TR_DOWN); r = desired >= 1 ? current / desired : 0; if (r > 1.0) byteCount = 0; else if (r > 0.9) byteCount *= 0.8; else if (r > 0.8) byteCount *= 0.9; } } if (b->parent && b->band[dir].honorParentLimits && (byteCount > 0)) byteCount = bandwidthClamp (b->parent, now, dir, byteCount); } return byteCount; }