FileDocCategorySizeDatePackage
SpeedManagerAlgorithmProviderDHTPing.javaAPI DocAzureus 3.0.3.422020Mon Jul 30 21:09:18 BST 2007com.aelitis.azureus.core.speedmanager.impl.v2

SpeedManagerAlgorithmProviderDHTPing

public class SpeedManagerAlgorithmProviderDHTPing extends Object implements com.aelitis.azureus.core.speedmanager.impl.SpeedManagerAlgorithmProvider, org.gudy.azureus2.core3.config.COConfigurationListener
This class implements an Vivaldi strategy for adjusting the upload limit. It will every 30 seconds calculate the distance to the center of the Vivaldi structure and if it determines that it is going away from it will lower the limit. If it getting closer it will increase the upload limit.

Fields Summary
private com.aelitis.azureus.core.speedmanager.impl.SpeedManagerAlgorithmProviderAdapter
adapter
private org.gudy.azureus2.plugins.PluginInterface
dhtPlugin
private long
timeSinceLastUpdate
private static int
metricGoodResult
private static int
metricGoodTolerance
private static int
metricBadResult
private static int
metricBadTolerance
private int
consecutiveUpticks
private int
consecutiveDownticks
private SpeedLimitMonitor
limitMonitor
private int
lastMetricValue
private static int
numIntervalsBetweenCal
private static boolean
skipIntervalAfterAdjustment
private List
pingTimeList
private boolean
hadAdjustmentLastInterval
private int
intervalCount
PingSourceManager
pingSourceManager
int
sessionMaxUploadRate
Constructors Summary
SpeedManagerAlgorithmProviderDHTPing(com.aelitis.azureus.core.speedmanager.impl.SpeedManagerAlgorithmProviderAdapter _adapter)





     

        adapter = _adapter;

        limitMonitor = new SpeedLimitMonitor( adapter.getSpeedManager());
        
        COConfigurationManager.addListener( this );
 
        SMInstance.init( _adapter );

        try{
            dhtPlugin = AzureusCoreFactory.getSingleton().getPluginManager().getPluginInterfaceByClass( DHTPlugin.class );
        }catch(AzureusCoreException ace){
            log("Warning: AzureusCore was not initialized on startup.");
        }

        if( dhtPlugin==null ){
            //Need to log this condition if it ever happens!!
            log(" Error: failed to get DHT Plugin ");
        }//if

        limitMonitor.initPingSpaceMap(metricGoodResult+metricGoodTolerance,metricBadResult-metricBadTolerance);
    
Methods Summary
public voidcalculate(com.aelitis.azureus.core.speedmanager.SpeedManagerPingSource[] sources)
Called whenever a new set of ping values is available for processing

param
sources -


        
        limitMonitor.logPMDataEx();


        //Get new data to ping-source-manager.
        int len = sources.length;
        for(int i=0; i<len; i++){
            pingSourceManager.addPingTime( sources[i] );
            int pingTime = sources[i].getPingTime();

            //exclude ping-times of -1 which mess up the averages.
            if(pingTime>0){
                pingTimeList.add( new Integer( sources[i].getPingTime() ) );
                intervalCount++;
            }//if
        }//for

        //if we are in a limit finding mode then don't even bother with this calculation.
        if( limitMonitor.isConfTestingLimits() ){

            if( limitMonitor.isConfLimitTestFinished() ){
                endLimitTesting();
                return;
            }else{
                //will increase the limit each cycle.
                SMUpdate ramp = limitMonitor.rampTestingLimit(
                                    adapter.getCurrentUploadLimit(),
                                    adapter.getCurrentDownloadLimit()
                    );
                logNewLimits( ramp );
                setNewLimits( ramp );
            }
        }//if - isConfTestingLimits

        
        long currTime = SystemTime.getCurrentTime();

        if( timeSinceLastUpdate==0 ){
            timeSinceLastUpdate=currTime;
        }

        //use the DHT ping times instead.
        if ( calculateMediaDHTPingTime() ){
            return;
        }

        log("metric:"+ lastMetricValue);
        logLimitStatus();

        //update the metric data
        limitMonitor.addToPingMapData(lastMetricValue);

        float signalStrength = determineSignalStrength(lastMetricValue);

        //if are are NOT looking for limits and we have a signal then make an adjustment.
        if( signalStrength!=0.0f && !limitMonitor.isConfTestingLimits() ){
            hadAdjustmentLastInterval=true;

            float multiple = consectiveMultiplier();
            int currUpLimit = adapter.getCurrentUploadLimit();
            int currDownLimit = adapter.getCurrentDownloadLimit();

            limitMonitor.checkForUnpinningCondition();

            SMUpdate update = limitMonitor.modifyLimits(signalStrength,multiple,currUpLimit, currDownLimit);

            //log
            logNewLimits(update);

            //setting new
            setNewLimits( update );

        }else{
            hadAdjustmentLastInterval=false;

            //verify the limits. It is possible for the user to adjust the capacity down below the current limit, so check that condition here.
            int currUploadLimit = adapter.getCurrentUploadLimit();
            int currDownloadLimit = adapter.getCurrentDownloadLimit();
            if( !limitMonitor.areSettingsInSpec(currUploadLimit, currDownloadLimit) ){
                SMUpdate update = limitMonitor.adjustLimitsToSpec(currUploadLimit, currDownloadLimit);
                logNewLimits( update );
                setNewLimits( update );
            }

        }

        //determine if we need to drop a ping source.
        pingSourceManager.checkPingSources(sources);
    
private floatcalculateDownTickMultiple(int c)
Want to drop rate faster then increase.

param
c -
return
-


        float multiple=0.0f;
        if(c<0){
            return multiple;
        }

        switch(c){
            case 0:
            case 1:
                multiple=0.25f;
                break;
            case 2:
                multiple=0.5f;
                break;
            case 3:
                multiple=1.0f;
                break;
            case 4:
                multiple=2.0f;
                break;
            case 5:
                multiple=3.0f;
                break;
            case 6:
                multiple=4.0f;
                break;
            case 7:
                multiple=6.0f;
                break;
            case 8:
                multiple=9.0f;
                break;
            case 9:
                multiple=15.0f;
                break;
            default:
                multiple=20.0f;
        }//switch
        return multiple;
    
private booleancalculateMediaDHTPingTime()
DHT Ping data is one of the metrics used. Calculate it here.

return
- true if should exit early from the caluculate method.

        //Don't count this data point, if we skip the next ping times after an adjustment.
        if(skipIntervalAfterAdjustment && hadAdjustmentLastInterval){
            hadAdjustmentLastInterval=false;
            pingTimeList = new ArrayList();
            intervalCount=0;
            return true;
        }

        //have we accululated enough data to make an adjustment?
        if( intervalCount < numIntervalsBetweenCal ){
            //get more data before making another calculation.
            return true;
        }

        //we have enough data. find the median ping time.
        Collections.sort( pingTimeList );

        //if we don't have any pings, then either the connection is lost or very bad network congestion.
        //force an adjustment down.
        if( pingTimeList.size()==0 ){
            lastMetricValue =10000;  //This is a high value to force an adjusment down.
        }else{
            int medianIndex = pingTimeList.size()/2;

            Integer medianPingTime = (Integer) pingTimeList.get(medianIndex);
            lastMetricValue = medianPingTime.intValue();
        }

        //we have now consumed this data. reset the counters.
        intervalCount=0;
        pingTimeList = new ArrayList();
        return false;
    
private floatcalculateUpTickMultiple(int c)
Want to rise much slower then drop.

param
c - number of upsignals recieved in a row
return
- multiple factor.


        float multiple=0.0f;
        
        if(c<0){
            return multiple;
        }

        switch(c){
            case 0:
            case 1:
                multiple=0.25f;
                break;
            case 2:
                multiple=0.5f;
                break;
            case 3:
                multiple=1.0f;
                break;
            case 4:
                multiple=1.25f;
                break;
            case 5:
                multiple=1.5f;
                break;
            case 6:
                multiple=1.75f;
                break;
            case 7:
                multiple=2.0f;
                break;
            case 8:
                multiple=2.25f;
                break;
            case 9:
                multiple=2.5f;
                break;
            default:
                multiple=3.0f;
        }//switch

        //decrease the signal strength if bandwith usage is only in MED use.
        if( limitMonitor.bandwidthUsageMedium() ){
            multiple /= 2.0f;
        }

        return multiple;
    
public voidconfigurationSaved()


        try{

            limitMonitor.readFromPersistentMap();
            limitMonitor.updateFromCOConfigManager();

            metricGoodResult =COConfigurationManager.getIntParameter(
                    SpeedManagerAlgorithmProviderV2.SETTING_DHT_GOOD_SET_POINT);
            metricGoodTolerance =COConfigurationManager.getIntParameter(
                    SpeedManagerAlgorithmProviderV2.SETTING_DHT_GOOD_TOLERANCE);
            metricBadResult =COConfigurationManager.getIntParameter(
                    SpeedManagerAlgorithmProviderV2.SETTING_DHT_BAD_SET_POINT);
            metricBadTolerance =COConfigurationManager.getIntParameter(
                    SpeedManagerAlgorithmProviderV2.SETTING_DHT_BAD_TOLERANCE);

            skipIntervalAfterAdjustment=COConfigurationManager.getBooleanParameter(
                    SpeedManagerAlgorithmProviderV2.SETTING_WAIT_AFTER_ADJUST);
            numIntervalsBetweenCal=COConfigurationManager.getIntParameter(
                    SpeedManagerAlgorithmProviderV2.SETTING_INTERVALS_BETWEEN_ADJUST);

            limitMonitor.initPingSpaceMap(metricGoodResult+metricGoodTolerance,metricBadResult-metricBadTolerance);

            SpeedManagerLogger.trace("..DHTPing - configurationSaved called.");

        }catch( Throwable t ){
            SpeedManagerLogger.log(t.getMessage());
        }

    
private floatconsectiveMultiplier()
The longer were get the same signal the stronger it is. On upticks however we only increase the rates when if the upload or download is saturated.

return
-


        float multiple;

        if( consecutiveUpticks > consecutiveDownticks ){

            //Set the consecutive upticks back to zero if the bandwidth is not being used.
            if( limitMonitor.bandwidthUsageLow() ){
                consecutiveUpticks=0;
            }

            multiple = calculateUpTickMultiple(consecutiveUpticks);
        }else{
            multiple = calculateDownTickMultiple(consecutiveDownticks);
            limitMonitor.notifyOfDownSignal();
        }

        return multiple;
    
public voiddestroy()

    	COConfigurationManager.removeListener( this );
    
private floatdetermineSignalStrength(int currMetricValue)
Determined by the vivaldi value and the number of consecutive calculations with the same result.

param
currMetricValue -
return
-


        //determine if this is an up-tick (+1), down-tick (-1) or neutral (0).
        float signal=0.0f;
        if( currMetricValue< metricGoodResult){
            //strong up signal.
            signal=1.0f;
            consecutiveUpticks++;
            consecutiveDownticks=0;
        }
        else if( currMetricValue < (metricGoodResult + metricGoodTolerance)){
            //weak up signal.
            signal = (float)(currMetricValue- metricGoodResult)/ metricGoodTolerance;

            consecutiveUpticks++;
            consecutiveDownticks=0;
        }
        else if( currMetricValue > metricBadResult){
            //strong down signal
            signal = -1.0f;
            consecutiveUpticks=0;
            consecutiveDownticks++;
        }
        else if( currMetricValue > (metricBadResult - metricBadTolerance) ){
            //weak down signal
            consecutiveUpticks=0;
            consecutiveDownticks++;

            int lowerBound= metricBadResult - metricBadTolerance;
            signal = (currMetricValue-lowerBound) / metricBadTolerance;
            signal -= 1.0f;
        }
        else{
            //This is a neutral signal. 
        }

        log("consecutive:"+consecutiveUpticks+":"+consecutiveDownticks);

        return signal;
    
private voidendLimitTesting()

        int downLimitGuess = limitMonitor.guessDownloadLimit();
        int upLimitGuess = limitMonitor.guessUploadLimit();

        SMUpdate update = limitMonitor.endLimitTesting(downLimitGuess,
                upLimitGuess );

        //print out the PingMap data to compare.
        limitMonitor.logPingMapData();

        //reset Ping Space Map for next round.
        limitMonitor.resetPingSpace();

        //log
        logNewLimits(update);
        //setting new
        setNewLimits( update );
    
public booleangetAdjustsDownloadLimits()

    	// TODO Auto-generated method stub
    	return true;
    
public intgetCurrentChokeSpeed()
Returns the current view of when choking occurs

return
speed in bytes/sec

        return 0;
    
public intgetCurrentPingMillis()

        return 0;
    
public intgetIdlePingMillis()
Various getters for interesting info shown in stats view

return
-


        //return the vivaldi time.
        return lastMetricValue;
        
    
public intgetMaxPingMillis()

        return 912;  //Currently a fixed number to be sure of algorightm.
    
public intgetMaxUploadSpeed()

        return sessionMaxUploadRate;
    
protected voidlog(java.lang.String str)


        SpeedManagerLogger.log(str);
    
private voidlogCurrentData(int downRate, int currDownLimit, int upRate, int currUploadLimit)
log "curr-data" line to the AutoSpeed-Beta file.

param
downRate -
param
currDownLimit -
param
upRate -
param
currUploadLimit -

        StringBuffer sb = new StringBuffer("curr-data-v:"+downRate+":"+currDownLimit+":");
        sb.append( limitMonitor.getDownloadMaxLimit() ).append(":");
        sb.append(limitMonitor.getDownloadBandwidthMode()).append(":");
        sb.append(limitMonitor.getDownloadLimitSettingMode()).append(":");
        sb.append(upRate).append(":").append(currUploadLimit).append(":");
        sb.append( limitMonitor.getUploadMaxLimit() ).append(":");
        sb.append(limitMonitor.getUploadBandwidthMode()).append(":");
        sb.append(limitMonitor.getUploadLimitSettingMode()).append(":");
        sb.append(limitMonitor.getTransferModeAsString());

        SpeedManagerLogger.log( sb.toString() );
    
private voidlogLimitStatus()
Log the limit status. Max, Min and Conf. log("limits:down-max:down-min:down-conf:up-max:up-min:up-conf");


        StringBuffer msg = new StringBuffer();
        msg.append("limits:");
        msg.append(limitMonitor.getUploadMaxLimit()).append(":");
        msg.append(limitMonitor.getUploadMinLimit()).append(":");
        msg.append(limitMonitor.getUploadConfidence()).append(":");
        msg.append(limitMonitor.getDownloadMaxLimit()).append(":");
        msg.append(limitMonitor.getDownloadMinLimit()).append(":");
        msg.append(limitMonitor.getDownloadConfidence());

        SpeedManagerLogger.log( msg.toString() );
    
private voidlogNewLimits(SMUpdate update)

        if( update.hasNewUploadLimit ){
            int kbpsUpoadLimit = update.newUploadLimit/1024;
            log(" new up limit  : "+ kbpsUpoadLimit +" kb/s");
        }

        if( update.hasNewDownloadLimit ){
            int kpbsDownloadLimit = update.newDownloadLimit/1024;
            log(" new down limit: "+kpbsDownloadLimit+" kb/s");
        }
    
public voidpingSourceFailed(com.aelitis.azureus.core.speedmanager.SpeedManagerPingSource source)
Ping source has failed

param
source -

        //Where does the vivaldi data for the chart come from.
        log("pingSourceFailed");

        pingSourceManager.pingSourceFailed(source);
    
public voidpingSourceFound(com.aelitis.azureus.core.speedmanager.SpeedManagerPingSource source, boolean is_replacement)
Called when a new source of ping times has been found

param
source -
param
is_replacement One of the initial sources or a replacement for a failed one

        //We might not use ping source if the vivaldi data is available.
        log("pingSourceFound");
        //add a new ping source to the list.
        pingSourceManager.pingSourceFound(source, is_replacement);
    
public voidreset()
Reset any state to start of day values

        log("reset");

        log("curr-data: curr-down-rate : curr-down-limit : down-capacity : down-bandwith-mode : down-limit-mode : curr-up-rate : curr-up-limit : up-capacity : upload-bandwidth-mode : upload-limit-mode : transfer-mode");

        log("new-limit:newLimit:currStep:signalStrength:multiple:currUpLimit:maxStep:uploadLimitMax:uploadLimitMin:transferMode" );

        log("consecutive:up:down");

        log("metric:value:type");

        log("user-comment:log");

        log("pin:upload-status,download-status,upload-unpin-timer,download-unpin-timer");

        log("limits:down-max:down-min:down-conf:up-max:up-min:up-conf");
        
        limitMonitor.resetPingSpace();
    
private voidsetNewLimits(SMUpdate update)
Just update the limits.

param
update - SMUpdate


        adapter.setCurrentUploadLimit( update.newUploadLimit );
        adapter.setCurrentDownloadLimit( update.newDownloadLimit );

    
public voidupdateStats()
Called periodically (see period above) to allow stats to be updated.


        //update some stats used in the UI.

        int currUploadLimit = adapter.getCurrentUploadLimit();
        int currDataUploadSpeed = adapter.getCurrentDataUploadSpeed();
        int currProtoUploadSpeed = adapter.getCurrentProtocolUploadSpeed();
        int upRateBitsPerSec = currDataUploadSpeed + currProtoUploadSpeed;

        int currDownLimit = adapter.getCurrentDownloadLimit();
        int downDataRate = adapter.getCurrentDataDownloadSpeed();
        int downProtoRate = adapter.getCurrentProtocolDownloadSpeed();
        int downRateBitsPerSec = downDataRate+downProtoRate;

        //update the bandwidth status
        limitMonitor.setDownloadBandwidthMode(downRateBitsPerSec,currDownLimit);
        limitMonitor.setUploadBandwidthMode(upRateBitsPerSec,currUploadLimit);

        //update the limts status.  (is it near a forced max or min?)
        limitMonitor.setDownloadLimitSettingMode(currDownLimit);
        limitMonitor.setUploadLimitSettingMode(currUploadLimit);

        limitMonitor.updateTransferMode();

        if( limitMonitor.isConfTestingLimits() ){
            limitMonitor.updateLimitTestingData(downRateBitsPerSec,upRateBitsPerSec);
        }

        //update ping maps
        limitMonitor.setCurrentTransferRates(downRateBitsPerSec,upRateBitsPerSec);

        //only for the UI.
        if( upRateBitsPerSec > sessionMaxUploadRate ){
            sessionMaxUploadRate = upRateBitsPerSec;
        }

        

        //"curr-data" ....
        logCurrentData(downRateBitsPerSec, currDownLimit, upRateBitsPerSec, currUploadLimit);