Changeset 1426


Ignore:
Timestamp:
Jan 22, 2007, 10:58:51 PM (16 years ago)
Author:
titer
Message:

Removed the need for all the tiny mallocs in ratecontrol by using a fixed sized, circular history

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/ratecontrol.c

    r1372 r1426  
    2525#include "transmission.h"
    2626
    27 #define MAX_HISTORY 30
    28 
    29 typedef struct tr_transfer_s tr_transfer_t;
     27/* Maximum number of packets we keep track of. Since most packets are
     28 * 1 KB, it means we remember the last 2 MB transferred */
     29#define HISTORY_SIZE 2048
     30
     31/* How far back we go to calculate rates to be displayed in the
     32 * interface */
     33#define LONG_INTERVAL 30000 /* 30 secs */
     34
     35/* How far back we go to calculate pseudo-instantaneous transfer rates,
     36 * for the actual rate control */
     37#define SHORT_INTERVAL 1000 /* 1 sec */
     38
     39
     40/***********************************************************************
     41 * Structures
     42 **********************************************************************/
     43typedef struct tr_transfer_s
     44{
     45    uint64_t date;
     46    int      size;
     47}
     48tr_transfer_t;
     49
    3050struct tr_ratecontrol_s
    3151{
    32     tr_lock_t       lock;
    33     int             limit;
    34     tr_transfer_t * first;
    35     tr_transfer_t * last;
     52    tr_lock_t     lock;
     53    int           limit;
     54
     55    /* Circular history: it's empty if transferStop == transferStart,
     56     * full if ( transferStop + 1 ) % HISTORY_SIZE == transferStart */
     57    tr_transfer_t transfers[HISTORY_SIZE];
     58    int           transferStart;
     59    int           transferStop;
    3660};
    37 struct tr_transfer_s
    38 {
    39     uint64_t        date;
    40     int             size;
    41     tr_transfer_t * next;
    42     tr_transfer_t * prev;
    43 };
    44 
    45 /***********************************************************************
    46  * rateForInterval
    47  ***********************************************************************
    48  * Returns the transfer rate on the last 'interval' milliseconds
    49  **********************************************************************/
    50 static inline float rateForInterval( tr_ratecontrol_t * r, int interval )
    51 {
    52     tr_transfer_t * t;
    53     uint64_t        start = tr_date() - interval;
    54     int             total = 0;
    55 
    56     for( t = r->first; t && t->date > start; t = t->next )
    57     {
    58         total += t->size;
    59     }
    60 
    61     return ( 1000.0 / 1024.0 ) * total / interval;
    62 }
    63 
    64 static inline void cleanOldTransfers( tr_ratecontrol_t * r )
    65 {
    66     tr_transfer_t * t, * prev;
    67     uint64_t        old = tr_date() - MAX_HISTORY * 1000;
    68 
    69     for( t = r->last; t && t->date < old; )
    70     {
    71         prev = t->prev;
    72         if( prev )
    73             prev->next = NULL;
    74         else
    75             r->first = NULL;
    76         free( t );
    77         t       = prev;
    78         r->last = prev;
    79     }
    80 }
     61
     62
     63/***********************************************************************
     64 * Local prototypes
     65 **********************************************************************/
     66static float rateForInterval( tr_ratecontrol_t * r, int interval );
     67
     68
     69/***********************************************************************
     70 * Exported functions
     71 **********************************************************************/
    8172
    8273tr_ratecontrol_t * tr_rcInit()
     
    112103        r = isUpload ? tor->upload : tor->download;
    113104        tr_lockLock( &r->lock );
    114         rate += rateForInterval( r, 1000 );
     105        rate += rateForInterval( r, SHORT_INTERVAL );
    115106        tr_lockUnlock( &r->lock );
    116107       
     
    136127
    137128    tr_lockLock( &r->lock );
    138     ret = ( r->limit <= 0 ) ? ( r->limit < 0 ) : ( rateForInterval( r, 1000 ) < r->limit );
     129    ret = ( r->limit <= 0 ) ? ( r->limit < 0 ) :
     130            ( rateForInterval( r, SHORT_INTERVAL ) < r->limit );
    139131    tr_lockUnlock( &r->lock );
    140132
     
    148140    if( size < 100 )
    149141    {
     142        /* Don't count small messages */
    150143        return;
    151144    }
    152145   
    153146    tr_lockLock( &r->lock );
    154     t = malloc( sizeof( tr_transfer_t ) );
    155 
    156     if( r->first )
    157         r->first->prev = t;
    158     if( !r->last )
    159         r->last = t;
    160     t->next  = r->first;
    161     t->prev  = NULL;
    162     r->first = t;
    163 
    164     t->date  = tr_date();
    165     t->size  = size;
    166 
    167     cleanOldTransfers( r );
     147
     148    r->transferStop = ( r->transferStop + 1 ) % HISTORY_SIZE;
     149    if( r->transferStop == r->transferStart )
     150        /* History is full, forget about the first (oldest) item */
     151        r->transferStart = ( r->transferStart + 1 ) % HISTORY_SIZE;
     152
     153    t = &r->transfers[r->transferStop];
     154    t->date = tr_date();
     155    t->size = size;
     156
    168157    tr_lockUnlock( &r->lock );
    169158}
     
    174163
    175164    tr_lockLock( &r->lock );
    176     ret = rateForInterval( r, MAX_HISTORY * 1000 );
     165    ret = rateForInterval( r, LONG_INTERVAL );
    177166    tr_lockUnlock( &r->lock );
    178167
     
    182171void tr_rcReset( tr_ratecontrol_t * r )
    183172{
    184     tr_transfer_t * t, * next;
    185 
    186     tr_lockLock( &r->lock );
    187     for( t = r->first; t; )
    188     {
    189         next = t->next;
    190         free( t );
    191         t = next;
    192     }
    193     r->first = NULL;
    194     r->last  = NULL;
     173    tr_lockLock( &r->lock );
     174    r->transferStart = 0;
     175    r->transferStop = 0;
    195176    tr_lockUnlock( &r->lock );
    196177}
     
    202183    free( r );
    203184}
     185
     186
     187/***********************************************************************
     188 * Local functions
     189 **********************************************************************/
     190
     191/***********************************************************************
     192 * rateForInterval
     193 ***********************************************************************
     194 * Returns the transfer rate in KB/s on the last 'interval'
     195 * milliseconds
     196 **********************************************************************/
     197static float rateForInterval( tr_ratecontrol_t * r, int interval )
     198{
     199    tr_transfer_t * t = NULL;
     200    uint64_t now, start;
     201    int i, total;
     202
     203    now = tr_date();
     204    start = now - interval;
     205
     206    /* Browse the history back in time */
     207    total = 0;
     208    for( i = r->transferStop; i != r->transferStart; i-- )
     209    {
     210        t = &r->transfers[i];
     211        if( t->date < start )
     212            break;
     213
     214        total += t->size;
     215
     216        if( !i )
     217            i = HISTORY_SIZE; /* Loop */
     218    }
     219    if( ( r->transferStop + 1 ) % HISTORY_SIZE == r->transferStart
     220        && i == r->transferStart )
     221    {
     222        /* High bandwidth -> the history isn't big enough to remember
     223         * everything transferred since 'interval' ms ago. Correct the
     224         * interval so that we return the correct rate */
     225        interval = now - t->date;
     226    }
     227
     228    return ( 1000.0f / 1024.0f ) * total / interval;
     229}
     230
Note: See TracChangeset for help on using the changeset viewer.