1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-03-03 18:25:35 +00:00

lots of performance improvements. fun!

* dynamically resize the request queue on a per-peer basis based on its speed
* fix a huge bug that sabotaged the `swift' performance
* on startup, unchoke peers much sooner
* bump MAX_PEERS and PERCENT_PEER_WANTED
* do a better job of estimating speed on torrents less than 30 seconds old.
* getting an unrecognized extension ID, ignore it instead of stopping the torrent.
This commit is contained in:
Charles Kerr 2007-06-29 05:45:17 +00:00
parent 6c7a16397e
commit f0950d7390
8 changed files with 94 additions and 37 deletions

View file

@ -200,7 +200,7 @@ void tr_chokingPulse( tr_choking_t * c )
}
else
{
if( tr_peerLastChoke( peer ) + 10000 < now )
if( !tr_peerTimesChoked(peer) || tr_peerLastChoke( peer ) + 10000 < now )
canUnchoke[canUnchokeCount++] = peer;
}
}

View file

@ -45,7 +45,7 @@ static const int SWIFT_ENABLED = 1;
* For every byte the peer uploads to us,
* allow them to download this many bytes from us
*/
static const double SWIFT_REPAYMENT_RATIO = 1.1;
static const double SWIFT_REPAYMENT_RATIO = 1.33;
/**
* Allow new peers to download this many bytes from
@ -70,7 +70,7 @@ static const int SWIFT_REFRESH_INTERVAL_SEC = 5;
******
*****/
#define PERCENT_PEER_WANTED 25 /* Percent before we start relax peers min activeness */
#define PERCENT_PEER_WANTED 75 /* Percent before we start relax peers min activeness */
#define MIN_UPLOAD_IDLE 60000 /* In high peer situations we wait only 1 min
until dropping peers for idling */
#define MAX_UPLOAD_IDLE 240000 /* In low peer situations we wait the
@ -83,9 +83,6 @@ static const int SWIFT_REFRESH_INTERVAL_SEC = 5;
during low peer situations */
#define MAX_CON_TIMEOUT 30000 /* Time to timeout connecting to peer,
during high peer situations */
#define MAX_REQUEST_COUNT 32
#define OUR_REQUEST_COUNT 12 /* TODO: we should detect if we are on a
high-speed network and adapt */
#define PEX_PEER_CUTOFF 50 /* only try to add new peers from pex if
we have fewer existing peers than this */
#define PEX_INTERVAL 60 /* don't send pex messages more frequently
@ -150,6 +147,7 @@ struct tr_peer_s
char peerInterested;
int optimistic;
int timesChoked;
uint64_t lastChoke;
uint8_t id[TR_ID_LEN];
@ -180,14 +178,18 @@ struct tr_peer_s
int outBlockSending;
int inRequestCount;
tr_request_t inRequests[OUR_REQUEST_COUNT];
int inRequestMax;
int inRequestAlloc;
tr_request_t * inRequests;
int inIndex;
int inBegin;
int inLength;
uint64_t inTotal;
int outRequestCount;
tr_request_t outRequests[MAX_REQUEST_COUNT];
int outRequestMax;
int outRequestAlloc;
tr_request_t * outRequests;
uint64_t outTotal;
uint64_t outDate;
@ -233,6 +235,12 @@ tr_peer_t * tr_peerInit( struct in_addr addr, in_port_t port, int s, int from )
assert( 0 <= from && TR_PEER_FROM__MAX > from );
peer->outRequestMax = peer->outRequestAlloc = 2;
peer->outRequests = tr_new0( tr_request_t, peer->outRequestAlloc );
peer->inRequestMax = peer->inRequestAlloc = 2;
peer->inRequests = tr_new0( tr_request_t, peer->inRequestAlloc );
peer->socket = s;
peer->addr = addr;
peer->port = port;
@ -354,10 +362,17 @@ int tr_peerRead( tr_peer_t * peer )
peer->size *= 2;
peer->buf = realloc( peer->buf, peer->size );
}
#if 0
/* Never read more than 1K each time, otherwise the rate
control is no use */
ret = tr_netRecv( peer->socket, &peer->buf[peer->pos],
MIN( 1024, peer->size - peer->pos ) );
MIN( 1024, peer->size - peer->pos ) );
#else
/* Hm, it doesn't *seem* to break rate control... */
ret = tr_netRecv( peer->socket, &peer->buf[peer->pos],
peer->size - peer->pos );
#endif
if( ret & TR_NET_CLOSE )
{
peer_dbg( "connection closed" );
@ -595,21 +610,13 @@ writeEnd:
if( peer->amInterested
&& !peer->peerChoking
&& !peer->banned
&& peer->inRequestCount < OUR_REQUEST_COUNT )
&& peer->inRequestCount < peer->inRequestMax )
{
int i;
int poolSize=0, endgame=0;
int * pool = getPreferredPieces ( tor, peer, &poolSize, &endgame );
/* TODO: add some asserts to see if this bitfield is really necessary */
tr_bitfield_t * requestedBlocks = tr_bitfieldNew( tor->blockCount );
for( i=0; i<peer->inRequestCount; ++i) {
const tr_request_t * r = &peer->inRequests[i];
const int block = tr_block( r->index, r->begin );
tr_bitfieldAdd( requestedBlocks, block );
}
for( i=0; i<poolSize && peer->inRequestCount<OUR_REQUEST_COUNT; )
for( i=0; i<poolSize && peer->inRequestCount<peer->inRequestMax; )
{
int unused;
const int piece = pool[i];
@ -617,15 +624,11 @@ writeEnd:
? tr_cpMostMissingBlockInPiece( tor->completion, piece, &unused)
: tr_cpMissingBlockInPiece ( tor->completion, piece );
if( block>=0 && (endgame || !tr_bitfieldHas( requestedBlocks, block ) ) )
{
tr_bitfieldAdd( requestedBlocks, block );
if( block>=0 )
sendRequest( tor, peer, block );
}
else ++i;
}
tr_bitfieldFree( requestedBlocks );
free( pool );
}
@ -684,10 +687,16 @@ float tr_peerUploadRate( const tr_peer_t * peer )
return tr_rcRate( peer->upload );
}
int tr_peerTimesChoked( const tr_peer_t * peer )
{
return peer->timesChoked;
}
void tr_peerChoke( tr_peer_t * peer )
{
sendChoke( peer, 1 );
peer->lastChoke = tr_date();
++peer->timesChoked;
}
void tr_peerUnchoke( tr_peer_t * peer )
@ -838,6 +847,44 @@ tr_torrentSwiftPulse ( tr_torrent_t * tor )
tr_torrentWriterLock( tor );
for( i=0; i<tor->peerCount; ++i )
{
/* preferred # of seconds for the request queue's turnaround time.
this is just an arbitrary number. */
const int queueTime = 5;
int j;
tr_peer_t * peer = tor->peers[ i ];
if( !tr_peerIsConnected( peer ) )
continue;
/* decide how deep the request queue should be */
peer->outRequestMax = queueTime * tr_rcRate(peer->download) / tor->blockSize;
peer->inRequestMax += 2; /* room to grow */
/* make room for new requests */
if( peer->outRequestAlloc < peer->outRequestMax ) {
peer->outRequestAlloc = peer->outRequestMax;
peer->outRequests = tr_renew( tr_request_t, peer->outRequests, peer->outRequestAlloc );
}
/* decide how deep the request queue should be */
peer->inRequestMax = queueTime * tr_rcRate(peer->download) / (tor->blockSize/1024);
peer->inRequestMax += 2; /* room to grow */
/* make room for new requests */
if( peer->inRequestAlloc < peer->inRequestMax ) {
peer->inRequestAlloc = peer->inRequestMax;
peer->inRequests = tr_renew( tr_request_t, peer->inRequests, peer->inRequestAlloc );
}
/* queue shrank... notify completion that we won't be sending those requests */
for( j=peer->inRequestMax; j<peer->inRequestCount; ++j ) {
tr_request_t * r = &peer->inRequests[j];
tr_cpDownloaderRem( tor->completion, tr_block(r->index,r->begin) );
}
}
deadbeats = tr_calloc( tor->peerCount, sizeof(tr_peer_t*) );
for( i=0; i<tor->peerCount; ++i ) {
tr_peer_t * peer = tor->peers[ i ];
@ -847,7 +894,7 @@ tr_torrentSwiftPulse ( tr_torrent_t * tor )
if( deadbeatCount )
{
const double ul_KiBsec = tr_rcRate( tor->upload );
const double ul_KiBsec = tr_rcRate( tor->download );
const double ul_KiB = ul_KiBsec * SWIFT_REFRESH_INTERVAL_SEC;
const double ul_bytes = ul_KiB * 1024;
const double freeCreditTotal = ul_bytes * SWIFT_LARGESSE;

View file

@ -45,6 +45,7 @@ int tr_peerIsFrom ( const tr_peer_t * );
int tr_peerAmChoking ( const tr_peer_t * );
int tr_peerAmInterested ( const tr_peer_t * );
int tr_peerIsChoking ( const tr_peer_t * );
int tr_peerTimesChoked ( const tr_peer_t * );
int tr_peerIsInterested ( const tr_peer_t * );
float tr_peerProgress ( const tr_peer_t * );
int tr_peerPort ( const tr_peer_t * );

View file

@ -237,7 +237,7 @@ static inline int parseRequest( tr_torrent_t * tor, tr_peer_t * peer,
return TR_ERROR;
}
if( peer->outRequestCount >= MAX_REQUEST_COUNT )
if( peer->outRequestCount >= peer->outRequestMax )
{
tr_err( "Too many requests" );
return TR_ERROR;
@ -523,7 +523,8 @@ static inline int parseMessage( tr_torrent_t * tor, tr_peer_t * peer,
}
peer_dbg( "GET unknown extended message '%hhu'", extid );
}
return 1;
/* ignore the unknown extension */
return 0;
case AZ_MSG_BT_KEEP_ALIVE:
return TR_OK;
case AZ_MSG_AZ_PEER_EXCHANGE:
@ -536,7 +537,7 @@ static inline int parseMessage( tr_torrent_t * tor, tr_peer_t * peer,
return 0;
}
peer_dbg( "GET unknown message '%d'", id );
tr_err( "GET unknown message '%d'", id );
return TR_ERROR;
}

View file

@ -165,18 +165,19 @@ void tr_rcClose( tr_ratecontrol_t * r )
static float rateForInterval( tr_ratecontrol_t * r, int interval )
{
tr_transfer_t * t = NULL;
uint64_t now, start;
int i, total;
uint64_t now, then, start;
float total = 0;
int i;
now = tr_date();
now = then = tr_date();
start = now - interval;
/* Browse the history back in time */
total = 0;
for( i = r->transferStop; i != r->transferStart; i-- )
{
t = &r->transfers[i];
if( t->date < start )
then = t->date;
if( then < start )
break;
total += t->size;
@ -184,6 +185,7 @@ static float rateForInterval( tr_ratecontrol_t * r, int interval )
if( !i )
i = HISTORY_SIZE; /* Loop */
}
#if 0
if( ( r->transferStop + 1 ) % HISTORY_SIZE == r->transferStart
&& i == r->transferStart )
{
@ -192,7 +194,10 @@ static float rateForInterval( tr_ratecontrol_t * r, int interval )
* interval so that we return the correct rate */
interval = now - t->date;
}
#endif
return ( 1000.0f / 1024.0f ) * total / interval;
if( now == then )
return 0.0;
return ( 1000.0f / 1024.0f ) * total / (now - then);
}

View file

@ -26,7 +26,8 @@
#include "peer.h"
/* Maximum number of peers that we keep in our local list */
#define MAX_PEER_COUNT 42
/* This is an arbitrary number, but it seems to work well */
#define MAX_PEER_COUNT 128
struct tr_shared_s
{

View file

@ -544,8 +544,8 @@ tr_stat_t * tr_torrentStat( tr_torrent_t * tor )
s->peersDownloading = 0;
for( i=0; i<tor->peerCount; ++i ) {
const tr_peer_t * peer = tor->peers[i];
if( tr_peerIsConnected( peer ) ) {
++s->peersTotal;
if( tr_peerIsConnected( peer ) ) {
++s->peersFrom[tr_peerIsFrom(peer)];
if( tr_peerAmInterested( peer ) && !tr_peerIsChoking( peer ) )
++s->peersUploading;
@ -953,7 +953,7 @@ torrentThreadLoop ( void * _tor )
cp_status_t cpStatus;
/* sleep a little while */
tr_wait( tor->runStatus == TR_RUN_STOPPED ? 1000 : 100 );
tr_wait( tor->runStatus == TR_RUN_STOPPED ? 1600 : 800 );
/* if we're stopping... */
if( tor->runStatus == TR_RUN_STOPPING )

View file

@ -180,6 +180,8 @@ static inline int _tr_block( const tr_torrent_t * tor, int index, int begin )
((struct_type *) tr_malloc (((size_t) sizeof (struct_type)) * ((size_t) (n_structs))))
#define tr_new0(struct_type, n_structs) \
((struct_type *) tr_malloc0 (((size_t) sizeof (struct_type)) * ((size_t) (n_structs))))
#define tr_renew(struct_type, mem, n_structs) \
((struct_type *) realloc ((mem), ((size_t) sizeof (struct_type)) * ((size_t) (n_structs))))
void* tr_malloc ( size_t );
void* tr_malloc0 ( size_t );