Ignore:
Timestamp:
Jul 28, 2007, 3:43:34 PM (14 years ago)
Author:
charles
Message:

a nice patch that makes the three most CPU-hogging functions (as reported by Shark) essentially free and reduces memory overhead by 8 bytes per piece per torrent. Lots of asserts for extra testing fun.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/completion.c

    r2518 r2531  
    4141    /* a block is complete if and only if we have it */
    4242    uint16_t * completeBlocks;
     43
     44    uint8_t doneDirty;
     45    uint64_t doneHave;
     46    uint64_t doneTotal;
     47    uint64_t completeHave;
    4348};
    4449
     
    7681    tr_bitfieldClear( cp->pieceBitfield );
    7782    memset( cp->completeBlocks, 0, sizeof(uint16_t) * tor->info.pieceCount );
    78 }
    79 
    80 int tr_cpPieceHasAllBlocks( const tr_completion_t * cp, int piece )
    81 {
    82     return tr_cpPieceIsComplete( cp, piece );
    83 }
    84 
    85 int tr_cpPieceIsComplete( const tr_completion_t * cp, int piece )
    86 {
    87     return cp->completeBlocks[piece] >= TR_BLOCKS_IN_PIECE(cp->tor,piece);
    88 }
    89 
    90 const tr_bitfield_t * tr_cpPieceBitfield( const tr_completion_t * cp )
    91 {
    92     return cp->pieceBitfield;
    93 }
    94 
    95 void tr_cpPieceAdd( tr_completion_t * cp, int piece )
    96 {
    97     const tr_torrent_t * tor = cp->tor;
    98     const int n_blocks = TR_BLOCKS_IN_PIECE(tor,piece);
    99     const int startBlock = TOR_PIECE_FIRST_BLOCK(tor,piece);
    100     const int endBlock   = startBlock + n_blocks;
    101 
    102     cp->completeBlocks[piece] = n_blocks;
    103     tr_bitfieldAddRange( cp->blockBitfield, startBlock, endBlock );
    104     tr_bitfieldAdd( cp->pieceBitfield, piece );
    105 }
    106 
    107 void tr_cpPieceRem( tr_completion_t * cp, int piece )
    108 {
    109     const tr_torrent_t * tor = cp->tor;
    110     const int n_blocks = TR_BLOCKS_IN_PIECE(tor,piece);
    111     const int startBlock = TOR_PIECE_FIRST_BLOCK(tor,piece);
    112     const int endBlock   = startBlock + n_blocks;
    113 
    114     assert( cp != NULL );
    115     assert( 0 <= piece );
    116     assert( piece < tor->info.pieceCount );
    117     assert( 0 <= startBlock );
    118     assert( startBlock < tor->blockCount );
    119     assert( startBlock <= endBlock );
    120     assert( endBlock <= tor->blockCount );
    121 
    122     cp->completeBlocks[piece] = 0;
    123     tr_bitfieldRemRange ( cp->blockBitfield, startBlock, endBlock );
    124     tr_bitfieldRem( cp->pieceBitfield, piece );
    125 }
    126 
    127 /* Blocks */
    128 void tr_cpDownloaderAdd( tr_completion_t * cp, int block )
    129 {
    130     ++cp->blockDownloaders[block];
    131 }
    132 
    133 void tr_cpDownloaderRem( tr_completion_t * cp, int block )
    134 {
    135     --cp->blockDownloaders[block];
    136 }
    137 
    138 int tr_cpBlockIsComplete( const tr_completion_t * cp, int block )
    139 {
    140     return tr_bitfieldHas( cp->blockBitfield, block );
    141 }
    142 
    143 void tr_cpBlockAdd( tr_completion_t * cp, int block )
    144 {
    145     const tr_torrent_t * tor = cp->tor;
    146 
    147     if( !tr_cpBlockIsComplete( cp, block ) )
    148     {
    149         const int piece = TOR_BLOCK_PIECE(tor, block);
    150 
    151         ++cp->completeBlocks[piece];
    152 
    153         if( cp->completeBlocks[piece] == TR_BLOCKS_IN_PIECE(tor,piece) )
    154             tr_bitfieldAdd( cp->pieceBitfield, piece );
    155 
    156         tr_bitfieldAdd( cp->blockBitfield, block );
    157     }
    158 }
    159 
    160 const tr_bitfield_t * tr_cpBlockBitfield( const tr_completion_t * cp )
    161 {
    162     assert( cp != NULL );
    163 
    164     return cp->blockBitfield;
    165 }
    166 
    167 void
    168 tr_cpBlockBitfieldSet( tr_completion_t * cp, tr_bitfield_t * bitfield )
    169 {
    170     int i;
    171 
    172     assert( cp != NULL );
    173     assert( bitfield != NULL );
    174 
    175     tr_cpReset( cp );
    176 
    177     for( i=0; i < cp->tor->blockCount; ++i )
    178         if( tr_bitfieldHas( bitfield, i ) )
    179             tr_cpBlockAdd( cp, i );
    180 }
    181 
    182 float tr_cpPercentBlocksInPiece( const tr_completion_t * cp, int piece )
    183 {
    184     assert( cp != NULL );
    185 
    186     return cp->completeBlocks[piece] / (double)TR_BLOCKS_IN_PIECE(cp->tor,piece);
    187 }
    188 
    189 int
    190 tr_cpMissingBlocksForPiece( const tr_completion_t * cp, int piece )
    191 {
    192     int i;
    193     int n;
    194     const tr_torrent_t * tor = cp->tor;
    195     const int start = TOR_PIECE_FIRST_BLOCK(tor,piece);
    196     const int end   = start + TR_BLOCKS_IN_PIECE(tor,piece);
    197 
    198     n = 0;
    199     for( i = start; i < end; ++i )
    200         if( !tr_cpBlockIsComplete( cp, i ) && !cp->blockDownloaders[i] )
    201             ++n;
    202 
    203     return n;
    204 }
    205 
    206 int tr_cpMissingBlockInPiece( const tr_completion_t * cp, int piece )
    207 {
    208     int i;
    209     const tr_torrent_t * tor = cp->tor;
    210     const int start = TOR_PIECE_FIRST_BLOCK(tor,piece);
    211     const int end   = start + TR_BLOCKS_IN_PIECE(tor,piece);
    212 
    213     for( i = start; i < end; ++i )
    214         if( !tr_cpBlockIsComplete( cp, i ) && !cp->blockDownloaders[i] )
    215             return i;
    216 
    217     return -1;
    218 }
    219 
    220 /***
    221 ****
    222 ***/
    223 
    224 cp_status_t
    225 tr_cpGetStatus ( const tr_completion_t * cp )
    226 {
    227     int i;
    228     int ret = TR_CP_COMPLETE;
    229     const tr_info_t * info;
    230 
    231     assert( cp != NULL );
    232     assert( cp->tor != NULL );
    233 
    234     info = &cp->tor->info;
    235     for( i=0; i<info->pieceCount; ++i ) {
    236         if( tr_cpPieceIsComplete( cp, i ) )
    237             continue;
    238         if( !info->pieces[i].dnd )
    239             return TR_CP_INCOMPLETE;
    240         ret = TR_CP_DONE;
    241     }
    242 
    243     return ret;
    244 }
    245 
    246 uint64_t
    247 tr_cpLeftUntilComplete ( const tr_completion_t * cp )
    248 {
    249     int i;
    250     uint64_t b=0;
    251     const tr_torrent_t * tor;
    252     const tr_info_t * info;
    253 
    254     assert( cp != NULL );
    255     assert( cp->tor != NULL );
    256 
    257     tor = cp->tor;
    258     info = &tor->info;
    259     for( i=0; i<info->pieceCount; ++i )
    260         if( !tr_cpPieceIsComplete( cp, i ) )
    261             b += ( TR_BLOCKS_IN_PIECE(tor,i) - cp->completeBlocks[ i ] );
    262 
    263     b *= tor->blockSize;
    264 
    265     if( tor->blockCount && !tr_cpBlockIsComplete( cp, tor->blockCount - 1 ) )
    266           b -= (tor->blockSize - (tor->info.totalSize % tor->blockSize));
    267 
    268     return b;
    269 }
    270 
    271 void
    272 tr_cpDoneStats( const tr_completion_t  * cp ,
    273                 uint64_t               * setmeHaveBytes,
    274                 uint64_t               * setmeTotalBytes )
    275 {
    276     const tr_torrent_t * tor = cp->tor;
     83
     84    cp->doneDirty = TRUE;
     85    cp->doneHave = 0;
     86    cp->doneTotal = 0;
     87    cp->completeHave = 0;
     88}
     89
     90/**
     91***
     92**/
     93
     94static void
     95tr_cpEnsureDoneValid( const tr_completion_t * ccp )
     96{
     97    const tr_torrent_t * tor = ccp->tor;
    27798    const tr_info_t * info = &tor->info;
    27899    uint64_t have=0, total=0;
    279100    int i;
     101    tr_completion_t * cp ;
     102
     103    if( !ccp->doneDirty )
     104        return;
     105
     106    /* too bad C doesn't have 'mutable' */
     107    cp = (tr_completion_t*) ccp;
     108    cp->doneDirty = FALSE;
    280109
    281110    for( i=0; i<info->pieceCount; ++i ) {
     
    298127    assert( total <= info->totalSize );
    299128
    300     *setmeHaveBytes = have;
    301     *setmeTotalBytes = total;
    302 }
     129    cp->doneHave = have;
     130    cp->doneTotal = total;
     131}
     132
     133void
     134tr_cpInvalidateDND ( tr_completion_t * cp )
     135{
     136    cp->doneDirty = TRUE;
     137}
     138
     139int tr_cpPieceHasAllBlocks( const tr_completion_t * cp, int piece )
     140{
     141    return tr_cpPieceIsComplete( cp, piece );
     142}
     143
     144int tr_cpPieceIsComplete( const tr_completion_t * cp, int piece )
     145{
     146    return cp->completeBlocks[piece] >= tr_torPieceCountBlocks(cp->tor,piece);
     147}
     148
     149const tr_bitfield_t * tr_cpPieceBitfield( const tr_completion_t * cp )
     150{
     151    return cp->pieceBitfield;
     152}
     153
     154void tr_cpPieceAdd( tr_completion_t * cp, int piece )
     155{
     156    const tr_torrent_t * tor = cp->tor;
     157    const int start = tr_torPieceFirstBlock(tor,piece);
     158    const int end = start + tr_torPieceCountBlocks(tor,piece);
     159    int i;
     160
     161    for( i=start; i<end; ++i )
     162        tr_cpBlockAdd( cp, i );
     163}
     164
     165void tr_cpPieceRem( tr_completion_t * cp, int piece )
     166{
     167    const tr_torrent_t * tor = cp->tor;
     168    const int start = tr_torPieceFirstBlock(tor,piece);
     169    const int end = start + tr_torPieceCountBlocks(tor,piece);
     170    int block;
     171
     172    assert( cp != NULL );
     173    assert( 0 <= piece );
     174    assert( piece < tor->info.pieceCount );
     175    assert( 0 <= start );
     176    assert( start < tor->blockCount );
     177    assert( start <= end );
     178    assert( end <= tor->blockCount );
     179
     180    for( block=start; block<end; ++block ) {
     181        if( tr_cpBlockIsComplete( cp, block ) ) {
     182            const int blockSize = tr_torBlockCountBytes( tor, block );
     183            cp->completeHave -= blockSize;
     184            if( !tor->info.pieces[piece].dnd )
     185                cp->doneHave -= blockSize;
     186        }
     187    }
     188
     189    cp->completeBlocks[piece] = 0;
     190    tr_bitfieldRemRange ( cp->blockBitfield, start, end );
     191    tr_bitfieldRem( cp->pieceBitfield, piece );
     192}
     193
     194/* Blocks */
     195void tr_cpDownloaderAdd( tr_completion_t * cp, int block )
     196{
     197    ++cp->blockDownloaders[block];
     198}
     199
     200void tr_cpDownloaderRem( tr_completion_t * cp, int block )
     201{
     202    --cp->blockDownloaders[block];
     203}
     204
     205int tr_cpBlockIsComplete( const tr_completion_t * cp, int block )
     206{
     207    return tr_bitfieldHas( cp->blockBitfield, block );
     208}
     209
     210void
     211tr_cpBlockAdd( tr_completion_t * cp, int block )
     212{
     213    const tr_torrent_t * tor = cp->tor;
     214
     215    if( !tr_cpBlockIsComplete( cp, block ) )
     216    {
     217        const int piece = tr_torBlockPiece( tor, block );
     218        const int blockSize = tr_torBlockCountBytes( tor, block );
     219
     220        ++cp->completeBlocks[piece];
     221
     222        if( cp->completeBlocks[piece] == tr_torPieceCountBlocks( tor, piece ) )
     223            tr_bitfieldAdd( cp->pieceBitfield, piece );
     224
     225        tr_bitfieldAdd( cp->blockBitfield, block );
     226
     227        cp->completeHave += blockSize;
     228
     229        if( !tor->info.pieces[piece].dnd )
     230            cp->doneHave += blockSize;
     231    }
     232}
     233
     234const tr_bitfield_t * tr_cpBlockBitfield( const tr_completion_t * cp )
     235{
     236    assert( cp != NULL );
     237
     238    return cp->blockBitfield;
     239}
     240
     241void
     242tr_cpBlockBitfieldSet( tr_completion_t * cp, tr_bitfield_t * bitfield )
     243{
     244    int i;
     245
     246    assert( cp != NULL );
     247    assert( bitfield != NULL );
     248
     249    tr_cpReset( cp );
     250
     251    for( i=0; i < cp->tor->blockCount; ++i )
     252        if( tr_bitfieldHas( bitfield, i ) )
     253            tr_cpBlockAdd( cp, i );
     254}
     255
     256float tr_cpPercentBlocksInPiece( const tr_completion_t * cp, int piece )
     257{
     258    assert( cp != NULL );
     259
     260    return (double)cp->completeBlocks[piece] / tr_torPieceCountBlocks(cp->tor,piece);
     261}
     262
     263int
     264tr_cpMissingBlocksForPiece( const tr_completion_t * cp, int piece )
     265{
     266    int i;
     267    int n;
     268    const tr_torrent_t * tor = cp->tor;
     269    const int start = tr_torPieceFirstBlock(tor,piece);
     270    const int end   = start + tr_torPieceCountBlocks(tor,piece);
     271
     272    n = 0;
     273    for( i = start; i < end; ++i )
     274        if( !tr_cpBlockIsComplete( cp, i ) && !cp->blockDownloaders[i] )
     275            ++n;
     276
     277    return n;
     278}
     279
     280int tr_cpMissingBlockInPiece( const tr_completion_t * cp, int piece )
     281{
     282    int i;
     283    const tr_torrent_t * tor = cp->tor;
     284    const int start = tr_torPieceFirstBlock(tor,piece);
     285    const int end   = start + tr_torPieceCountBlocks(tor,piece);
     286
     287    for( i = start; i < end; ++i )
     288        if( !tr_cpBlockIsComplete( cp, i ) && !cp->blockDownloaders[i] )
     289            return i;
     290
     291    return -1;
     292}
     293
     294/***
     295****
     296***/
    303297
    304298float
    305299tr_cpPercentComplete ( const tr_completion_t * cp )
    306300{
    307     const uint64_t tilComplete = tr_cpLeftUntilComplete( cp );
    308     const uint64_t total = cp->tor->info.totalSize;
    309     const float f = 1.0 - (double)tilComplete / total;
    310     return MAX(0.0, f);
     301    return (double)cp->completeHave / cp->tor->info.totalSize;
     302}
     303
     304uint64_t
     305tr_cpLeftUntilComplete ( const tr_completion_t * cp )
     306{
     307    return cp->tor->info.totalSize - cp->completeHave;
     308}
     309
     310float
     311tr_cpPercentDone( const tr_completion_t * cp )
     312{
     313    tr_cpEnsureDoneValid( cp );
     314
     315    return (double)cp->doneHave / cp->doneTotal;
     316}
     317
     318uint64_t
     319tr_cpLeftUntilDone ( const tr_completion_t * cp )
     320{
     321    tr_cpEnsureDoneValid( cp );
     322
     323    return cp->doneTotal - cp->doneHave;
     324}
     325
     326cp_status_t
     327tr_cpGetStatus ( const tr_completion_t * cp )
     328{
     329    if( cp->completeHave >= cp->tor->info.totalSize )
     330        return TR_CP_COMPLETE;
     331
     332    tr_cpEnsureDoneValid( cp );
     333
     334    if( cp->doneHave >= cp->doneTotal )
     335        return TR_CP_DONE;
     336
     337    return TR_CP_INCOMPLETE;
    311338}
    312339
Note: See TracChangeset for help on using the changeset viewer.