Changeset 7137


Ignore:
Timestamp:
Nov 23, 2008, 4:31:28 PM (12 years ago)
Author:
charles
Message:

(libT) #1468: speed display is very jumpy

Location:
trunk/libtransmission
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/peer-io.c

    r7133 r7137  
    3131#include "net.h"
    3232#include "peer-io.h"
    33 #include "ratecontrol.h"
    3433#include "trevent.h"
    3534#include "utils.h"
     
    7372struct tr_bandwidth
    7473{
    75     unsigned int    isUnlimited : 1;
    76     size_t          bytesUsed;
    77     size_t          bytesLeft;
     74    unsigned int  isUnlimited : 1;
     75    size_t        bytesLeft;
    7876};
    7977
     
    221219                struct tr_bandwidth * b = &io->bandwidth[TR_UP];
    222220                b->bytesLeft -= MIN( b->bytesLeft, n );
    223                 b->bytesUsed += n;
    224221            }
    225222
     
    257254        struct tr_bandwidth * b = io->bandwidth + TR_DOWN;
    258255        b->bytesLeft -= MIN( b->bytesLeft, (size_t)n );
    259         b->bytesUsed += n;
    260         dbgmsg( io, "%zu new input bytes. bytesUsed is %zu, bytesLeft is %zu", n, b->bytesUsed, b->bytesLeft );
     256        dbgmsg( io, "%zu new input bytes. bytesLeft is %zu", n, b->bytesLeft );
    261257
    262258        adjustInputBuffer( io );
     
    617613
    618614size_t
    619 tr_peerIoGetBandwidthUsed( const tr_peerIo * io,
    620                            tr_direction      direction )
    621 {
    622     assert( io );
    623     assert( direction == TR_UP || direction == TR_DOWN );
    624     return io->bandwidth[direction].bytesUsed;
    625 }
    626 
    627 size_t
    628615tr_peerIoGetWriteBufferSpace( const tr_peerIo * io )
    629616{
     
    650637
    651638void
    652 tr_peerIoSetBandwidth( tr_peerIo * io,
    653                        tr_direction direction,
    654                        size_t       bytesLeft )
     639tr_peerIoAllocateBandwidth( tr_peerIo     * io,
     640                            tr_direction    direction,
     641                            size_t          bytesLeft )
    655642{
    656643    struct tr_bandwidth * b;
     
    661648    b = io->bandwidth + direction;
    662649    b->isUnlimited = 0;
    663     b->bytesUsed = 0;
    664650    b->bytesLeft = bytesLeft;
    665651
     
    679665    b = io->bandwidth + direction;
    680666    b->isUnlimited = 1;
    681     b->bytesUsed = 0;
    682667    b->bytesLeft = 0;
    683668
     
    883868    return time( NULL ) - io->timeCreated;
    884869}
    885 
  • trunk/libtransmission/peer-io.h

    r7133 r7137  
    199199**/
    200200
    201 size_t            tr_peerIoGetBandwidthUsed( const tr_peerIo * io,
    202                                              tr_direction      direction );
    203 
    204201size_t            tr_peerIoGetWriteBufferSpace( const tr_peerIo * io );
    205202
    206 void              tr_peerIoSetBandwidth( tr_peerIo *  io,
    207                                          tr_direction direction,
    208                                          size_t       bytesLeft );
     203void              tr_peerIoAllocateBandwidth( tr_peerIo *  io,
     204                                              tr_direction direction,
     205                                              size_t       bytesLeft );
    209206
    210207void              tr_peerIoSetBandwidthUnlimited( tr_peerIo *  io,
  • trunk/libtransmission/peer-mgr.c

    r7132 r7137  
    6868    /* number of unchoked peers per torrent.
    6969     * FIXME: this probably ought to be configurable */
    70     MAX_UNCHOKED_PEERS = 12,
     70    MAX_UNCHOKED_PEERS = 14,
    7171
    7272    /* number of bad pieces a peer is allowed to send before we ban them */
     
    131131    tr_ptrArray     * incomingHandshakes; /* tr_handshake */
    132132    tr_timer        * bandwidthTimer;
    133     tr_ratecontrol  * globalPoolRawSpeed[2];
    134133};
    135134
     
    521520    m->torrents = tr_ptrArrayNew( );
    522521    m->incomingHandshakes = tr_ptrArrayNew( );
    523     m->globalPoolRawSpeed[TR_CLIENT_TO_PEER] = tr_rcInit( );
    524     m->globalPoolRawSpeed[TR_PEER_TO_CLIENT] = tr_rcInit( );
    525522    m->bandwidthTimer = tr_timerNew( session, bandwidthPulse, m, BANDWIDTH_PERIOD_MSEC );
    526523    return m;
     
    533530
    534531    tr_timerFree( &manager->bandwidthTimer );
    535     tr_rcClose( manager->globalPoolRawSpeed[TR_CLIENT_TO_PEER] );
    536     tr_rcClose( manager->globalPoolRawSpeed[TR_PEER_TO_CLIENT] );
    537532
    538533    /* free the handshakes.  Abort invokes handshakeDoneCB(), which removes
     
    23632358****/
    23642359
     2360#if 0
     2361#define DEBUG_DIRECTION TR_UP
     2362#endif
     2363
    23652364static double
    2366 allocateHowMuch( double                  desired_average_kb_per_sec,
    2367                  const tr_ratecontrol  * ratecontrol )
     2365bytesPerPulse( double KiB_per_second )
     2366{
     2367    return KiB_per_second * ( 1024.0 * BANDWIDTH_PERIOD_MSEC / 1000.0 );
     2368}
     2369
     2370/*
     2371 * @param currentSpeed current speed in KiB/s
     2372 * @param desiredSpeed desired speed in KiB/s
     2373 */
     2374static double
     2375allocateHowMuch( tr_direction dir UNUSED, double currentSpeed, double desiredSpeed )
    23682376{
    23692377    const int pulses_per_history = TR_RATECONTROL_HISTORY_MSEC / BANDWIDTH_PERIOD_MSEC;
    2370     const double seconds_per_pulse = BANDWIDTH_PERIOD_MSEC / 1000.0;
    2371     const double baseline_bytes_per_pulse = desired_average_kb_per_sec * 1024.0 * seconds_per_pulse;
    2372     const double min = baseline_bytes_per_pulse * 0.80;
    2373     const double max = baseline_bytes_per_pulse * 1.20;
    2374     const double current_bytes_per_pulse = tr_rcRate( ratecontrol ) * 1024.0 * seconds_per_pulse;
    2375     const double next_pulse_bytes = baseline_bytes_per_pulse * ( pulses_per_history + 1 )
     2378    const double current_bytes_per_pulse = bytesPerPulse( currentSpeed );
     2379    const double desired_bytes_per_pulse = bytesPerPulse( desiredSpeed );
     2380    const double min = desired_bytes_per_pulse * 0.90;
     2381    const double max = desired_bytes_per_pulse * 1.25;
     2382    const double next_pulse_bytes = desired_bytes_per_pulse * ( pulses_per_history + 1 )
    23762383                                  - ( current_bytes_per_pulse * pulses_per_history );
    23772384    double clamped;
     
    23822389    clamped = MIN( clamped, max );
    23832390
    2384 #if 0
    2385 fprintf( stderr, "desiredAvgKB is %5.2f, rate is %5.2f, allocating %5.2f (%5.2f)\n",
    2386          desired_average_kb_per_sec,
    2387          tr_rcRate( ratecontrol ),
     2391#ifdef DEBUG_DIRECTION
     2392if( dir == DEBUG_DIRECTION )
     2393fprintf( stderr, "currentSpeed(%5.2f) desiredSpeed(%5.2f), allocating %5.2f (%5.2f)\n",
     2394         currentSpeed,
     2395         desiredSpeed,
    23882396         clamped/1024.0,
    23892397         next_pulse_bytes/1024.0 );
     
    23922400    return clamped;
    23932401}
    2394 
    23952402/**
    23962403 * Distributes a fixed amount of bandwidth among a set of peers.
     
    23982405 * @param peerArray peers whose client-to-peer bandwidth will be set
    23992406 * @param direction whether to allocate upload or download bandwidth
    2400  * @param history recent bandwidth history for these peers
    2401  * @param desiredAvgKB overall bandwidth goal for this set of peers
     2407 * @param currentSpeed current speed in KiB/s for this set of peers
     2408 * @param desiredSpeed desired speed in KiB/s for this set of peers
    24022409 */
    24032410static void
    24042411setPeerBandwidth( tr_ptrArray          * peerArray,
    24052412                  const tr_direction     direction,
    2406                   const tr_ratecontrol * ratecontrol,
    2407                   double                 desiredAvgKB )
    2408 {
    2409     const int    peerCount = tr_ptrArraySize( peerArray );
    2410     const double bytes = allocateHowMuch( desiredAvgKB, ratecontrol );
    2411     const double welfareBytes = MIN( 2048, bytes * 0.2 );
    2412     const double meritBytes = MAX( 0, bytes - welfareBytes );
    2413     tr_peer **   peers = (tr_peer**) tr_ptrArrayBase( peerArray );
     2413                  double                 currentSpeed,
     2414                  double                 desiredSpeed )
     2415{
     2416    const int    MINIMUM_WELFARE_BYTES = bytesPerPulse( 5 );
    24142417    int          i;
    24152418    double       welfare;
    2416     size_t       bytesUsed;
    2417 
    2418     assert( meritBytes >= 0.0 );
    2419     assert( welfareBytes >= 0.0 );
    2420     assert( direction == TR_UP || direction == TR_DOWN );
    2421 
    2422     for( i=bytesUsed=0; i<peerCount; ++i )
    2423         bytesUsed += tr_peerIoGetBandwidthUsed( peers[i]->io, direction );
    2424 
    2425    welfare = welfareBytes / peerCount;
     2419    double       meritBytes;
     2420    double       meritMultiplier;
     2421    double       welfareBytes;
     2422    const int    peerCount      = tr_ptrArraySize( peerArray );
     2423    const double bytes          = allocateHowMuch( direction, currentSpeed, desiredSpeed );
     2424    tr_peer **   peers          = (tr_peer**) tr_ptrArrayBase( peerArray );
     2425
     2426    /* how many bytes we'll allocate based on merit.
     2427     *
     2428     * 1. When just getting started we want to give all the peers a lot
     2429     *    of `welfare' allocation because we don't know which ones will
     2430     *    turn out to be productive for us.
     2431     *
     2432     * 2. When we've reached steady state and are near our bandwidth limit,
     2433     *    the bandwidth spent on `welfare' is going to come from peers that
     2434     *    we already know are productive... which is probably a waste.
     2435     *
     2436     * 3. So we tie the merit/welfare allocations to the current speed.
     2437     *    the closer the current speed gets to the maximum speed, the less
     2438     *    welfare we allocate.
     2439     *
     2440     * 4. We always need to allocate /some/ welfare bytes, otherwise
     2441     *    the other peers will starve.
     2442     */
     2443    meritBytes = bytesPerPulse( MIN( currentSpeed * 1.2, desiredSpeed ) );
     2444    welfareBytes = bytes > meritBytes ?  bytes - meritBytes : 0;
     2445    if( welfareBytes < MINIMUM_WELFARE_BYTES )
     2446        welfareBytes = MINIMUM_WELFARE_BYTES;
     2447    meritBytes = bytes - welfareBytes;
     2448    meritMultiplier = currentSpeed > 0.01 ?  meritBytes / currentSpeed : 0.0;
     2449
     2450#ifdef DEBUG_DIRECTION
     2451if( direction == DEBUG_DIRECTION )
     2452fprintf( stderr, "currentSpeed(%5.2f) desiredSpeed(%5.2f) - k[%.1f] merit [%.1f] welfare [%.1f]\n", currentSpeed, desiredSpeed, bytes/1024.0, meritBytes/1024.0, welfareBytes/1024.0 );
     2453#endif
     2454
     2455    /* how much welfare each peer gets */
     2456    welfare = welfareBytes / peerCount;
    24262457
    24272458    for( i=0; i<peerCount; ++i )
    24282459    {
    24292460        tr_peer * peer = peers[i];
    2430         const double merit = bytesUsed
    2431                            ? ( meritBytes * tr_peerIoGetBandwidthUsed( peer->io, direction ) ) / bytesUsed
    2432                            : ( meritBytes / peerCount );
    2433         tr_peerIoSetBandwidth( peer->io, direction, merit + welfare );
    2434     }
    2435 }
    2436 
    2437 static size_t
    2438 countHandshakeBandwidth( tr_ptrArray * handshakes,
    2439                          tr_direction  direction )
    2440 {
    2441     const int n = tr_ptrArraySize( handshakes );
    2442     int       i;
    2443     size_t    total;
    2444 
    2445     for( i = total = 0; i < n; ++i )
    2446     {
    2447         tr_peerIo * io = tr_handshakeGetIO( tr_ptrArrayNth( handshakes, i ) );
    2448         total += tr_peerIoGetBandwidthUsed( io, direction );
    2449     }
    2450     return total;
    2451 }
    2452 
    2453 static size_t
    2454 countPeerBandwidth( tr_ptrArray * peers,
    2455                     tr_direction  direction )
    2456 {
    2457     const int n = tr_ptrArraySize( peers );
    2458     int       i;
    2459     size_t    total;
    2460 
    2461     for( i = total = 0; i < n; ++i )
    2462     {
    2463         tr_peer * peer = tr_ptrArrayNth( peers, i );
    2464         total += tr_peerIoGetBandwidthUsed( peer->io, direction );
    2465     }
    2466     return total;
     2461        const size_t merit = tr_rcRate( peers[i]->pieceSpeed[direction] ) * meritMultiplier;
     2462        tr_peerIoAllocateBandwidth( peer->io, direction, merit + welfare );
     2463    }
    24672464}
    24682465
     
    25002497static void
    25012498getBandwidthPeers( Torrent       * t,
    2502                    tr_direction    direction,
    2503                    tr_ptrArray   * appendme )
     2499                   tr_direction    dir,
     2500                   tr_ptrArray   * appendme,
     2501                   double        * speed )
    25042502{
    25052503    int i, peerCount;
    25062504    tr_peer ** peers;
    25072505
     2506    assert( t );
    25082507    assert( torrentIsLocked( t ) );
     2508    assert( dir == TR_UP || dir == TR_DOWN );
     2509    assert( appendme );
     2510    assert( speed );
    25092511
    25102512    peers = (tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
    25112513
    25122514    for( i=0; i<peerCount; ++i )
    2513         if( peers[i]->msgs )
    2514             if(    ( ( direction == TR_PEER_TO_CLIENT ) && clientIsDownloadingFrom( peers[i] ) )
    2515                 || ( ( direction == TR_CLIENT_TO_PEER ) && clientIsUploadingTo( peers[i] ) ) )
    2516                     tr_ptrArrayAppend( appendme, peers[i] );
     2515    {
     2516        tr_peer * p = peers[i];
     2517
     2518        if( p->msgs )
     2519        {
     2520            if( ( ( dir == TR_DOWN ) && clientIsDownloadingFrom( p ) ) || ( ( dir == TR_UP ) && clientIsUploadingTo( p ) ) )
     2521            {
     2522                tr_ptrArrayAppend( appendme, p );
     2523                *speed += tr_rcRate( p->pieceSpeed[dir] );
     2524            }
     2525        }
     2526    }
    25172527}
    25182528
     
    25242534 * @return the amount of directional bandwidth used since the last pulse.
    25252535 */
    2526 static double
     2536static void
    25272537allocateBandwidth( tr_peerMgr * mgr,
    25282538                   tr_direction direction )
     
    25322542    Torrent **    torrents = (Torrent **) tr_ptrArrayBase( mgr->torrents );
    25332543    tr_ptrArray * globalPool = tr_ptrArrayNew( );
    2534     double        allBytesUsed = 0;
    2535     size_t        poolBytesUsed = 0;
     2544    double        globalPoolSpeed = 0;
    25362545    int           i;
    25372546
     
    25452554    {
    25462555        Torrent * t = torrents[i];
    2547         size_t used;
    25482556        tr_speedlimit speedMode;
    25492557
     
    25512559        if( tr_torrentGetActivity( t->tor ) == TR_STATUS_STOPPED )
    25522560            continue;
    2553 
    2554         used = countPeerBandwidth( t->peers, direction );
    2555         countHandshakeBandwidth( t->outgoingHandshakes, direction );
    2556 
    2557         /* remember this torrent's bytes used */
    2558         tr_rcTransferred( t->tor->rawSpeed[direction], used );
    2559 
    2560         /* add this torrent's bandwidth use to allBytesUsed */
    2561         allBytesUsed += used;
    25622561
    25632562        /* if piece data is disallowed, don't bother limiting bandwidth --
     
    25752574                break;
    25762575
    2577             case TR_SPEEDLIMIT_SINGLE:
    2578             {
     2576            case TR_SPEEDLIMIT_SINGLE: {
    25792577                tr_ptrArray * peers = tr_ptrArrayNew( );
    2580                 getBandwidthPeers( t, direction, peers );
    2581                 setPeerBandwidth( peers, direction,
    2582                                   t->tor->rawSpeed[direction],
    2583                                   tr_torrentGetSpeedLimit( t->tor, direction ) );
     2578                double speed = 0;
     2579                getBandwidthPeers( t, direction, peers, &speed );
     2580                setPeerBandwidth( peers, direction, speed, tr_torrentGetSpeedLimit( t->tor, direction ) );
    25842581                tr_ptrArrayFree( peers, NULL );
    25852582                break;
     
    25872584
    25882585            case TR_SPEEDLIMIT_GLOBAL:
    2589                 getBandwidthPeers( t, direction, globalPool );
    2590                 poolBytesUsed += used;
     2586                getBandwidthPeers( t, direction, globalPool, &globalPoolSpeed );
    25912587                break;
    25922588        }
    25932589    }
    2594 
    2595     /* add incoming handshakes to the global pool */
    2596     i = countHandshakeBandwidth( mgr->incomingHandshakes, direction );
    2597     allBytesUsed += i;
    2598     poolBytesUsed += i;
    2599 
    2600     tr_rcTransferred( mgr->globalPoolRawSpeed[direction], poolBytesUsed );
    26012590
    26022591    /* handle the global pool's connections */
     
    26042593        givePeersUnlimitedBandwidth( globalPool, direction );
    26052594    else
    2606         setPeerBandwidth( globalPool, direction,
    2607                           mgr->globalPoolRawSpeed[direction],
     2595        setPeerBandwidth( globalPool, direction, globalPoolSpeed,
    26082596                          tr_sessionGetSpeedLimit( session, direction ) );
    26092597
     
    26132601    /* cleanup */
    26142602    tr_ptrArrayFree( globalPool, NULL );
    2615     return allBytesUsed;
    26162603}
    26172604
Note: See TracChangeset for help on using the changeset viewer.