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 ); }
int tr_sessionGetSpeedLimit( const tr_session * session, tr_direction dir ) { assert( tr_isSession( session ) ); assert( tr_isDirection( dir ) ); return session->speedLimit[dir]; }
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 ); }
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 ); }
tr_bool tr_sessionIsSpeedLimitEnabled( const tr_session * session, tr_direction dir ) { assert( tr_isSession( session ) ); assert( tr_isDirection( dir ) ); return session->isSpeedLimited[dir]; }
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_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_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_sessionSetSpeedLimit( tr_session * session, tr_direction dir, int desiredSpeed ) { assert( tr_isSession( session ) ); assert( tr_isDirection( dir ) ); session->speedLimit[dir] = desiredSpeed; updateBandwidth( session, dir ); }
void tr_sessionSetSpeedLimitEnabled( tr_session * session, tr_direction dir, tr_bool isLimited ) { assert( tr_isSession( session ) ); assert( tr_isDirection( dir ) ); session->isSpeedLimited[dir] = isLimited; updateBandwidth( session, dir ); }
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 ); } }
void tr_peerIoSetEnabled( tr_peerIo * io, tr_direction dir, tr_bool isEnabled ) { const short event = dir == TR_UP ? EV_WRITE : EV_READ; assert( tr_isPeerIo( io ) ); assert( tr_isDirection( dir ) ); assert( tr_amInEventThread( io->session ) ); assert( io->session->events != NULL ); if( isEnabled ) event_enable( io, event ); else event_disable( io, event ); }
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; }
int tr_peerIoFlush( tr_peerIo * io, tr_direction dir, size_t limit ) { int bytesUsed = 0; assert( tr_isPeerIo( io ) ); assert( tr_isDirection( dir ) ); if( io->hasFinishedConnecting ) { if( dir == TR_DOWN ) bytesUsed = tr_peerIoTryRead( io, limit ); else bytesUsed = tr_peerIoTryWrite( io, limit ); } dbgmsg( io, "flushing peer-io, hasFinishedConnecting %d, direction %d, limit %zu, bytesUsed %d", (int)io->hasFinishedConnecting, (int)dir, limit, bytesUsed ); return bytesUsed; }
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; }