From e352d56925111823395777d91bf5683739438da5 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 24 Jul 2007 18:59:37 +0000 Subject: [PATCH] fix the high CPU load during endgame. --- libtransmission/peer.c | 69 ++++++++++++++++++++++++++----------- libtransmission/peerutils.h | 31 ++++++++--------- 2 files changed, 64 insertions(+), 36 deletions(-) diff --git a/libtransmission/peer.c b/libtransmission/peer.c index 589bbf30d..4950b049a 100644 --- a/libtransmission/peer.c +++ b/libtransmission/peer.c @@ -645,34 +645,63 @@ writeEnd: && !peer->banned && peer->inRequestCount < peer->inRequestMax ) { - int i; int poolSize = 0; - int * pool = getPreferredPieces ( tor, peer, &poolSize ); - const int endgame = !poolSize; + int endgame = FALSE; + int openSlots = peer->inRequestMax - peer->inRequestCount; + int * pool = getPreferredPieces ( tor, peer, &poolSize, &endgame ); - if( endgame ) /* endgame -- request everything we don't already have */ + if( !endgame ) { - for( i=0; iblockCount && peer->inRequestCountinRequestMax; ++i ) + /* pool is sorted from most to least desirable pieces, + so work our way through starting at beginning */ + int p; + for( p=0; p0; ) { - if( !isBlockInteresting( tor, peer, i ) ) - continue; - if( tr_bitfieldHas( peer->reqfield, i ) ) /* we've already asked them for it */ - continue; - if( !peer->reqfield ) - peer->reqfield = tr_bitfieldNew( tor->blockCount ); - tr_bitfieldAdd( peer->reqfield, i ); - sendRequest( tor, peer, i ); + const int piece = pool[p]; + const int block = tr_cpMissingBlockInPiece ( tor->completion, piece ); + if( block < 0 ) + ++p; + else { + sendRequest( tor, peer, block ); + --openSlots; + } } } - else for( i=0; iinRequestCountinRequestMax; ) + else { - int unused; - const int piece = pool[i]; - const int block = tr_cpMissingBlockInPiece ( tor->completion, piece ); + /* During endgame we remove the constraint of not asking for + pieces we've already requested from a different peer. + So if we follow the non-endgame approach of walking through + [0..poolCount) we'll bog down asking all peers for 1, then + all peers for 2, and so on. Randomize our starting point + into "pool" to reduce such overlap */ + int piecesLeft = poolSize; + int p = tr_rand( poolSize ); + for( ; openSlots>0 && piecesLeft>0; --piecesLeft, p=(p+1)%poolSize ) + { + const int piece = pool[p]; + const int firstBlock = tr_pieceStartBlock( piece ); + const int n = tr_pieceCountBlocks( piece ); + const int end = firstBlock + n; + int block; + for( block=firstBlock; blockcompletion, block )) + continue; - if( block>=0 ) - sendRequest( tor, peer, block ); - else ++i; + /* don't ask for it twice from the same peer */ + if( tr_bitfieldHas( peer->reqfield, block ) ) + continue; + + /* ask peer for the piece */ + if( !peer->reqfield ) + peer->reqfield = tr_bitfieldNew( tor->blockCount ); + tr_bitfieldAdd( peer->reqfield, block ); + sendRequest( tor, peer, block ); + --openSlots; + } + } } tr_free( pool ); diff --git a/libtransmission/peerutils.h b/libtransmission/peerutils.h index 67f757f9e..90014c502 100644 --- a/libtransmission/peerutils.h +++ b/libtransmission/peerutils.h @@ -181,19 +181,6 @@ static int isPieceInteresting( const tr_torrent_t * tor, return 1; } -static int isBlockInteresting( const tr_torrent_t * tor, - const tr_peer_t * peer, - int block ) -{ - if( tr_cpBlockIsComplete( tor->completion, block )) /* we already have it */ - return 0; - - if( !isPieceInteresting( tor, peer, tr_blockPiece( block ))) /* is piece interesting? */ - return 0; - - return 1; -} - /*********************************************************************** * isInteresting *********************************************************************** @@ -263,12 +250,14 @@ int comparePieces (const void * aIn, const void * bIn) static int* getPreferredPieces( const tr_torrent_t * tor, const tr_peer_t * peer, - int * pieceCount ) + int * pieceCount, + int * isEndgame ) { const tr_info_t * inf = &tor->info; int i; int poolSize = 0; + int endgame = FALSE; int * pool = tr_new( int, inf->pieceCount ); for( i=0; ipieceCount; ++i ) @@ -276,14 +265,23 @@ static int* getPreferredPieces( const tr_torrent_t * tor, if( tr_cpMissingBlocksForPiece( tor->completion, i ) ) pool[poolSize++] = i; + if( !poolSize ) { + endgame = TRUE; + for( i=0; ipieceCount; ++i ) + if( isPieceInteresting( tor, peer, i ) ) + pool[poolSize++] = i; + } + #if 0 fprintf (stderr, "old pool: "); for (i=0; i<15 && i 1 ) + /* sort the rest from most interesting to least... + but not in endgame, because it asks for pieces in a + scattershot manner anyway and doesn't need them sorted */ + if( !endgame && ( poolSize > 1 ) ) { PieceCompareData * p = tr_new( PieceCompareData, poolSize ); @@ -316,6 +314,7 @@ for (i=0; i<15 && i