source: trunk/libtransmission/ratecontrol.c @ 2231

Last change on this file since 2231 was 2231, checked in by charles, 15 years ago

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.
  • Property svn:keywords set to Date Rev Author Id
File size: 5.7 KB
Line 
1/******************************************************************************
2 * $Id: ratecontrol.c 2231 2007-06-29 05:45:17Z charles $
3 *
4 * Copyright (c) 2006 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include "transmission.h"
26#include "shared.h"
27
28/* Maximum number of packets we keep track of. Since most packets are
29 * 1 KB, it means we remember the last 2 MB transferred */
30#define HISTORY_SIZE 2048
31
32/* How far back we go to calculate rates to be displayed in the
33 * interface */
34#define LONG_INTERVAL 30000 /* 30 secs */
35
36/* How far back we go to calculate pseudo-instantaneous transfer rates,
37 * for the actual rate control */
38#define SHORT_INTERVAL 1000 /* 1 sec */
39
40
41/***********************************************************************
42 * Structures
43 **********************************************************************/
44typedef struct tr_transfer_s
45{
46    uint64_t date;
47    int      size;
48}
49tr_transfer_t;
50
51struct tr_ratecontrol_s
52{
53    tr_lock_t     lock;
54    int           limit;
55
56    /* Circular history: it's empty if transferStop == transferStart,
57     * full if ( transferStop + 1 ) % HISTORY_SIZE == transferStart */
58    tr_transfer_t transfers[HISTORY_SIZE];
59    int           transferStart;
60    int           transferStop;
61};
62
63
64/***********************************************************************
65 * Local prototypes
66 **********************************************************************/
67static float rateForInterval( tr_ratecontrol_t * r, int interval );
68
69
70/***********************************************************************
71 * Exported functions
72 **********************************************************************/
73
74tr_ratecontrol_t * tr_rcInit()
75{
76    tr_ratecontrol_t * r;
77
78    r        = calloc( 1, sizeof( tr_ratecontrol_t ) );
79    r->limit = -1;
80    tr_lockInit( &r->lock );
81
82    return r;
83}
84
85void tr_rcSetLimit( tr_ratecontrol_t * r, int limit )
86{
87    tr_lockLock( &r->lock );
88    r->limit = limit;
89    tr_lockUnlock( &r->lock );
90}
91
92int tr_rcCanTransfer( tr_ratecontrol_t * r )
93{
94    int ret;
95
96    tr_lockLock( &r->lock );
97    ret = ( r->limit <= 0 ) ? ( r->limit < 0 ) :
98            ( rateForInterval( r, SHORT_INTERVAL ) < r->limit );
99    tr_lockUnlock( &r->lock );
100
101    return ret;
102}
103
104void tr_rcTransferred( tr_ratecontrol_t * r, int size )
105{
106    tr_transfer_t * t;
107
108    if( size < 100 )
109    {
110        /* Don't count small messages */
111        return;
112    }
113   
114    tr_lockLock( &r->lock );
115
116    r->transferStop = ( r->transferStop + 1 ) % HISTORY_SIZE;
117    if( r->transferStop == r->transferStart )
118        /* History is full, forget about the first (oldest) item */
119        r->transferStart = ( r->transferStart + 1 ) % HISTORY_SIZE;
120
121    t = &r->transfers[r->transferStop];
122    t->date = tr_date();
123    t->size = size;
124
125    tr_lockUnlock( &r->lock );
126}
127
128float tr_rcRate( tr_ratecontrol_t * r )
129{
130    float ret;
131
132    tr_lockLock( &r->lock );
133    ret = rateForInterval( r, LONG_INTERVAL );
134    tr_lockUnlock( &r->lock );
135
136    return ret;
137}
138
139void tr_rcReset( tr_ratecontrol_t * r )
140{
141    tr_lockLock( &r->lock );
142    r->transferStart = 0;
143    r->transferStop = 0;
144    tr_lockUnlock( &r->lock );
145}
146
147void tr_rcClose( tr_ratecontrol_t * r )
148{
149    tr_rcReset( r );
150    tr_lockClose( &r->lock );
151    free( r );
152}
153
154
155/***********************************************************************
156 * Local functions
157 **********************************************************************/
158
159/***********************************************************************
160 * rateForInterval
161 ***********************************************************************
162 * Returns the transfer rate in KB/s on the last 'interval'
163 * milliseconds
164 **********************************************************************/
165static float rateForInterval( tr_ratecontrol_t * r, int interval )
166{
167    tr_transfer_t * t = NULL;
168    uint64_t now, then, start;
169    float total = 0;
170    int i;
171
172    now = then = tr_date();
173    start = now - interval;
174
175    /* Browse the history back in time */
176    for( i = r->transferStop; i != r->transferStart; i-- )
177    {
178        t = &r->transfers[i];
179        then = t->date;
180        if( then < start )
181            break;
182
183        total += t->size;
184
185        if( !i )
186            i = HISTORY_SIZE; /* Loop */
187    }
188#if 0
189    if( ( r->transferStop + 1 ) % HISTORY_SIZE == r->transferStart
190        && i == r->transferStart )
191    {
192        /* High bandwidth -> the history isn't big enough to remember
193         * everything transferred since 'interval' ms ago. Correct the
194         * interval so that we return the correct rate */
195        interval = now - t->date;
196    }
197#endif
198
199    if( now == then )
200        return 0.0;
201    return ( 1000.0f / 1024.0f ) * total / (now - then);
202}
203
Note: See TracBrowser for help on using the repository browser.