FileDocCategorySizeDatePackage
SpeedManagerAlgorithmProviderV1.javaAPI DocAzureus 3.0.3.415290Wed Jul 25 09:03:48 BST 2007com.aelitis.azureus.core.speedmanager.impl.v1

SpeedManagerAlgorithmProviderV1

public class SpeedManagerAlgorithmProviderV1 extends Object implements com.aelitis.azureus.core.speedmanager.impl.SpeedManagerAlgorithmProvider

Fields Summary
private static final String
CONFIG_MIN_UP
private static final String
CONFIG_MAX_UP
private static final String
CONFIG_MAX_INC
private static final String
CONFIG_MAX_DEC
private static final String
CONFIG_CHOKE_PING
private static final String
CONFIG_DOWNADJ_ENABLE
private static final String
CONFIG_DOWNADJ_RATIO
private static final String
CONFIG_LATENCY_FACTOR
private static final String
CONFIG_FORCED_MIN
private static int
PING_CHOKE_TIME
private static int
MIN_UP
private static int
MAX_UP
private static boolean
ADJUST_DOWNLOAD_ENABLE
private static float
ADJUST_DOWNLOAD_RATIO
private static int
MAX_INCREMENT
private static int
MAX_DECREMENT
private static int
LATENCY_FACTOR
private static int
FORCED_MIN_SPEED
private static final String[]
CONFIG_PARAMS
private static final int
UNLIMITED
private static final int
MODE_RUNNING
private static final int
MODE_FORCED_MIN
private static final int
MODE_FORCED_MAX
private static final int
FORCED_MAX_TICKS
private static final int
FORCED_MIN_TICKS
private static final int
FORCED_MIN_AT_START_TICK_LIMIT
private static final int
PING_AVERAGE_HISTORY_COUNT
private static final int
IDLE_UPLOAD_SPEED
private static final int
INITIAL_IDLE_AVERAGE
private static final int
MIN_IDLE_AVERAGE
private static final int
INCREASING
private static final int
DECREASING
private com.aelitis.azureus.core.speedmanager.impl.SpeedManagerAlgorithmProviderAdapter
adapter
private com.aelitis.azureus.core.util.average.Average
upload_average
private com.aelitis.azureus.core.util.average.Average
upload_short_average
private com.aelitis.azureus.core.util.average.Average
upload_short_prot_average
private com.aelitis.azureus.core.util.average.Average
ping_average_history
private com.aelitis.azureus.core.util.average.Average
choke_speed_average
private Map
ping_sources
private volatile int
replacement_contacts
private int
mode
private volatile int
mode_ticks
private int
saved_limit
private int
direction
private int
ticks
private int
idle_ticks
private int
idle_average
private boolean
idle_average_set
private int
max_ping
private int
max_upload_average
Constructors Summary
public SpeedManagerAlgorithmProviderV1(com.aelitis.azureus.core.speedmanager.impl.SpeedManagerAlgorithmProviderAdapter _adapter)


	
	
			 
	
		adapter	= _adapter;
	
Methods Summary
public voidcalculate(com.aelitis.azureus.core.speedmanager.SpeedManagerPingSource[] sources)

		int	min_rtt	= UNLIMITED;
		
		for (int i=0;i<sources.length;i++){
			
			int	rtt =  sources[i].getPingTime();

			if ( rtt > 0 && rtt < min_rtt ){
				
				min_rtt	= rtt;
			}
		}
		
		String	str = "";
		
		int	ping_total		= 0;
		int	ping_count		= 0;
		
		for (int i=0;i<sources.length;i++){
			
			pingSource	ps;
			
			synchronized( ping_sources ){
			
				ps = (pingSource)ping_sources.get( sources[i] );
			}
						
			int	rtt =  sources[i].getPingTime();
			
			str += (i==0?"":",") + rtt;

				// discount anything 5*min reported unless min is really small, in which case round
				// up as we're only trying to catch badly behaved ones
			
			if ( ps != null ){
			
				boolean	good_ping =  rtt < 5 * Math.max( min_rtt, 75 );
				
				ps.pingReceived( rtt, good_ping );
				
				if ( !good_ping ){
					
					rtt = -1;
				}
			}

			if ( rtt != -1 ){
			
				ping_total += rtt;
				
				ping_count++;
			}
		}
		
		if ( ping_count == 0 ){
		
				// all failed
			
			return;
		}
		
		int	ping_average = ping_total/ping_count;
				
		int	running_average = (int)ping_average_history.update( ping_average );
		
		if ( ping_average > max_ping ){
			
			max_ping	= ping_average;
		}
		
		int	up_average = (int)upload_average.getAverage();
		
			// if we're uploading slowly or the current ping rate is better than our current idle average
			// then we count this towards establishing the baseline
		
		if ( up_average <= IDLE_UPLOAD_SPEED || ( running_average < idle_average && !idle_average_set )){
			
			idle_ticks++;
			
			if ( idle_ticks >= PING_AVERAGE_HISTORY_COUNT ){
				
				idle_average	= Math.max( running_average, MIN_IDLE_AVERAGE );

				log( "New idle average: " + idle_average );
				
				idle_average_set	= true;
			}
		}else{
			
			if ( up_average > max_upload_average ){
				
				max_upload_average	= up_average;
				
				log( "New max upload:" +  max_upload_average );
			}
			
			idle_ticks	= 0;
			
		}
		
		if ( idle_average_set && running_average < idle_average ){
			
				// bump down if we happen to come across lower idle values
			
			idle_average	= Math.max( running_average, MIN_IDLE_AVERAGE );
		}
		
		int	current_speed 	= adapter.getCurrentDataUploadSpeed() + adapter.getCurrentProtocolUploadSpeed();
		int	current_limit	= adapter.getCurrentUploadLimit();

		int	new_limit	= current_limit;

		log( 
				"Pings: " + str + ", average=" + ping_average +", running_average=" + running_average +
				",idle_average=" + idle_average + ", speed=" + current_speed + ",limit=" + current_limit +
				",choke = " + (int)choke_speed_average.getAverage());



		if ( mode == MODE_FORCED_MAX ){
			
			if ( mode_ticks > FORCED_MAX_TICKS ){
				
				mode		= MODE_RUNNING;
				
				current_limit = new_limit	= saved_limit;
			}
			
		}else if ( mode == MODE_FORCED_MIN ){
			
			if ( idle_average_set || mode_ticks > FORCED_MIN_TICKS ){
				
				log( "Mode -> running" );

				if ( !idle_average_set ){
					
					idle_average	= Math.max( running_average, MIN_IDLE_AVERAGE );
				
					idle_average_set	= true;
				}
				
				mode		= MODE_RUNNING;
				mode_ticks	= 0;
				
				current_limit = new_limit	= saved_limit;
				
			}else if ( mode_ticks == 5 ){
				
					// we've had 5 secs of min up speed, clear out the ping average now
					// to get accurate times
				
				ping_average_history.reset();
			}
		}
		
		if ( mode == MODE_RUNNING ){
			
			if (	( ticks > FORCED_MIN_AT_START_TICK_LIMIT && !idle_average_set ) ||
					( replacement_contacts >= 2 && idle_average_set )){
				
					// we've been running a while but no min set, or we've got some new untested 
					// contacts - force it
				
				log( "Mode -> forced min" );
				
				mode		= MODE_FORCED_MIN;
				mode_ticks	= 0;
				saved_limit	= current_limit;
				
				idle_average_set	= false;
				idle_ticks			= 0;
				replacement_contacts= 0;
				
				new_limit	= FORCED_MIN_SPEED;
				
			}else{
							
				int	short_up = (int)upload_short_average.getAverage();

				int	choke_speed = (int)choke_speed_average.getAverage();
			
				int choke_time 		= PING_CHOKE_TIME;
				int	latency_factor	= LATENCY_FACTOR;
				
				
				if ( running_average < 2* idle_average && ping_average < choke_time ){
					
					direction = INCREASING;
					
					int	diff = running_average - idle_average;
					
					if ( diff < 100 ){
						
						diff = 100;
					}
					
					int	increment = 1024 * ( diff / latency_factor );
										
						// if we're close to the last choke-speed then decrease increments

					int	max_inc	= MAX_INCREMENT;
					
					if ( new_limit + 2*1024 > choke_speed ){
						
						max_inc = 1024;
						
					}else if ( new_limit + 5*1024 > choke_speed ){
						
						max_inc += 3*1024;
					}
							
					new_limit += Math.min( increment, max_inc );					
					
				}else if ( ping_average > 4*idle_average || ping_average > choke_time ){
					
					if ( direction == INCREASING ){
						
						if ( idle_average_set ){
							
							choke_speed_average.update( short_up );
						}
					}
					
					direction = DECREASING;
					
					int decrement = 1024 * (( ping_average - (3*idle_average )) / latency_factor );
					
					new_limit -= Math.min( decrement, MAX_DECREMENT );
					
						// don't drop below the current protocol upload speed. This is to address
						// the situation whereby it is downloading that is choking the line - killing
						// protocol upspeed kills the downspeed
					
					if ( new_limit < upload_short_prot_average.getAverage() + 1024 ){
						
						new_limit = (int)upload_short_prot_average.getAverage() + 1024;
					}
				}			
				
				if ( new_limit < 1024 ){
					
					new_limit	= 1024;
				}
			}
		
				// final tidy up
			
			int	min_up	= MIN_UP;
			int	max_up	= MAX_UP;
			
			if ( min_up > 0 && new_limit < min_up && mode != MODE_FORCED_MIN  ){
				
				new_limit = min_up;
				
			}else if ( max_up > 0 &&  new_limit > max_up && mode != MODE_FORCED_MAX ){
				
				new_limit = max_up;
			}
			
				// if we're not achieving the current limit and the advice is to increase it, don't
				// bother
			
			if ( new_limit > current_limit && current_speed < ( current_limit - 10*1024 )){
			
				new_limit = current_limit;
			}
		}
		
		
			// round limit up to nearest K
		
		new_limit = (( new_limit + 1023 )/1024) * 1024;
		
		adapter.setCurrentUploadLimit( new_limit );
		
		if ( ADJUST_DOWNLOAD_ENABLE && !( Float.isInfinite( ADJUST_DOWNLOAD_RATIO ) || Float.isNaN( ADJUST_DOWNLOAD_RATIO ))){
			
			int	dl_limit = (int)(new_limit * ADJUST_DOWNLOAD_RATIO);
			
			adapter.setCurrentDownloadLimit( dl_limit );
		}
	
public voiddestroy()

    
public booleangetAdjustsDownloadLimits()

		return( ADJUST_DOWNLOAD_ENABLE );
	
public intgetCurrentChokeSpeed()
Returns the current view of when choking occurs

return
speed in bytes/sec

		return((int)choke_speed_average.getAverage());
	
public intgetCurrentPingMillis()

		return( (int)ping_average_history.getAverage());
	
public intgetIdlePingMillis()

		return( idle_average );
	
public intgetMaxPingMillis()

		return( max_ping );
	
public intgetMaxUploadSpeed()

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

		adapter.log( str );
	
public voidpingSourceFailed(com.aelitis.azureus.core.speedmanager.SpeedManagerPingSource source)

		synchronized( ping_sources ){
			
			ping_sources.remove( source );
		}
	
public voidpingSourceFound(com.aelitis.azureus.core.speedmanager.SpeedManagerPingSource source, boolean is_replacement)

		if ( is_replacement ){
			
			replacement_contacts++;
		}

		synchronized( ping_sources ){
			
			ping_sources.put( source, new pingSource( source ));
		}
	
public voidreset()

		ticks					= 0;
		mode					= MODE_RUNNING;
		mode_ticks				= 0;
		idle_ticks				= 0;
		idle_average			= INITIAL_IDLE_AVERAGE;
		idle_average_set		= false;
		max_upload_average		= 0;
		direction				= INCREASING;
		max_ping				= 0;
		replacement_contacts	= 0;
		
		ping_sources			= new HashMap();
		
		choke_speed_average.reset();
		upload_average.reset();
		upload_short_average.reset();
		upload_short_prot_average.reset();
		ping_average_history.reset();
	
public voidupdateStats()

		int	current_protocol_speed 	= adapter.getCurrentProtocolUploadSpeed();
		int	current_data_speed		= adapter.getCurrentDataUploadSpeed();

		int	current_speed = current_protocol_speed + current_data_speed;
		
		upload_average.update( current_speed );
		
		upload_short_average.update( current_speed );
		
		upload_short_prot_average.update( current_protocol_speed );
		
		mode_ticks++;
		
		ticks++;