1 package com.aelitis.azureus.core.speedmanager.impl.v2; 2 3 import org.gudy.azureus2.core3.config.COConfigurationManager; 4 import org.gudy.azureus2.core3.util.SystemTime; 5 import org.gudy.azureus2.core3.util.RealTimeInfo; 6 import com.aelitis.azureus.core.speedmanager.SpeedManagerLimitEstimate; 7 import com.aelitis.azureus.core.speedmanager.SpeedManagerPingMapper; 8 import com.aelitis.azureus.core.speedmanager.SpeedManager; 9 import com.aelitis.azureus.core.speedmanager.impl.SpeedManagerAlgorithmProviderAdapter; 10 import com.aelitis.azureus.core.AzureusCoreFactory; 11 12 /** 13 * Created on May 23, 2007 14 * Created by Alan Snyder 15 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 16 * <p/> 17 * This program is free software; you can redistribute it and/or 18 * modify it under the terms of the GNU General Public License 19 * as published by the Free Software Foundation; either version 2 20 * of the License, or (at your option) any later version. 21 * This program is distributed in the hope that it will be useful, 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * GNU General Public License for more details. 25 * You should have received a copy of the GNU General Public License 26 * along with this program; if not, write to the Free Software 27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 28 */ 29 30 /** 31 * This class is responsible for re-adjusting the limits used by AutoSpeedV2. 32 * 33 * This class will keep track of the "status" (i.e. seeding, downloading)of the 34 * application. It will then re-adjust the MAX limits when it thinks limits 35 * are being reached. 36 * 37 * Here are the rules it will use. 38 * 39 * #1) When seeding. If the upload is AT_LIMIT for a period of time it will allow 40 * that to adjust upward. 41 * #2) When downloading. If the download is AT_LIMIT for a period of time it will 42 * allow that to adjust upward. 43 * 44 * #3) When downloading, if a down-tick is detected and the upload is near a limit, 45 * it will drop the upload limit to 80% of MAX_UPLOAD. 46 * 47 * #4) Once that limit is reached it will drop both the upload and download limits together. 48 * 49 * #5) Seeding mode is triggered when - download bandwidth at LOW - compared to CAPACITY for 5 minutes continously. 50 * 51 * #6) Download mode is triggered when - download bandwidth reaches MEDIUM - compared to CURRENT_LIMIT for the first time. 52 * 53 * Rules #5 and #6 favor downloading over seeding. 54 * 55 */ 56 57 public class SpeedLimitMonitor implements PSMonitorListener 58 { 59 60 //use for home network. 61 private int uploadLimitMax = SMConst.START_UPLOAD_RATE_MAX; 62 private int uploadLimitMin = SMConst.calculateMinUpload( uploadLimitMax ); 63 private int downloadLimitMax = SMConst.START_DOWNLOAD_RATE_MAX; 64 private int downloadLimitMin = SMConst.calculateMinDownload( downloadLimitMax ); 65 66 private TransferMode transferMode = new TransferMode(); 67 68 //Upload and Download bandwidth usage modes. Compare usage to current limit. 69 private SaturatedMode uploadBandwidthStatus =SaturatedMode.NONE; 70 private SaturatedMode downloadBandwidthStatus =SaturatedMode.NONE; 71 72 //Compare current limit to max limit. 73 private SaturatedMode uploadLimitSettingStatus=SaturatedMode.AT_LIMIT; 74 private SaturatedMode downloadLimitSettingStatus=SaturatedMode.AT_LIMIT; 75 76 //How much confidence to we have in the current limits? 77 private SpeedLimitConfidence uploadLimitConf = SpeedLimitConfidence.NONE; 78 private SpeedLimitConfidence downloadLimitConf = SpeedLimitConfidence.NONE; 79 80 private long clLastIncreaseTime =-1; 81 private long clFirstBadPingTime=-1; 82 83 private boolean currTestDone; 84 private boolean beginLimitTest; 85 private int highestUploadRate=0; 86 private int highestDownloadRate=0; 87 private int preTestUploadCapacity=5042; 88 private int preTestUploadLimit=5142; 89 private int preTestDownloadCapacity=5042; 90 private int preTestDownloadLimit=5142; 91 92 public static final String UPLOAD_CONF_LIMIT_SETTING="SpeedLimitMonitor.setting.upload.limit.conf"; 93 public static final String DOWNLOAD_CONF_LIMIT_SETTING="SpeedLimitMonitor.setting.download.limit.conf"; 94 public static final String UPLOAD_CHOKE_PING_COUNT="SpeedLimitMonitor.setting.choke.ping.count"; 95 private static final long CONF_LIMIT_TEST_LENGTH=1000*30; 96 97 //these methods are used to see how high limits can go. 98 private boolean isUploadMaxPinned=true; 99 private boolean isDownloadMaxPinned=true; 100 private long uploadAtLimitStartTime =SystemTime.getCurrentTime(); 101 private long downloadAtLimitStartTime = SystemTime.getCurrentTime(); 102 private int uploadChokePingCount = 1; 103 private int uploadPinCounter = 0; 104 105 private static final long TIME_AT_LIMIT_BEFORE_UNPINNING = 30 * 1000; //30 seconds. 106 107 //which percent of the measured upload capacity to use in download and seeding mode. 108 public static final String USED_UPLOAD_CAPACITY_DOWNLOAD_MODE = "SpeedLimitMonitor.setting.upload.used.download.mode"; 109 public static final String USED_UPLOAD_CAPACITY_SEEDING_MODE = "SpeedLimitMonitor.setting.upload.used.seeding.mode"; 110 private float percentUploadCapacityDownloadMode = 0.6f; 111 112 //PingSpaceMaps for the entire session. 113 PingSpaceMapper pingMapOfDownloadMode; 114 PingSpaceMapper pingMapOfSeedingMode; 115 116 117 boolean useVariancePingMap = false; 118 SpeedManagerPingMapper transientPingMap; 119 120 PingSpaceMon longTermMonitor = new PingSpaceMon(); 121 122 LimitControl slider = new LimitControlDropUploadFirst(); 123 124 SpeedLimitListener persistentMapListener; 125 SpeedLimitMonitor(SpeedManager sm)126 public SpeedLimitMonitor(SpeedManager sm){ 127 128 // 129 longTermMonitor.addListener( this ); 130 131 persistentMapListener = new SpeedLimitListener( this ); 132 133 sm.addListener( persistentMapListener ); 134 } 135 136 137 /** 138 * Splitting the limits our from other setting for SpeedManagerAlgorithmTI. 139 */ updateSettingsFromCOConfigManager()140 public void updateSettingsFromCOConfigManager(){ 141 percentUploadCapacityDownloadMode = (float) 142 COConfigurationManager.getIntParameter(SpeedLimitMonitor.USED_UPLOAD_CAPACITY_DOWNLOAD_MODE, 60)/100.0f; 143 144 slider.updateSeedSettings(percentUploadCapacityDownloadMode); 145 } 146 updateFromCOConfigManager()147 public void updateFromCOConfigManager(){ 148 149 uploadLimitMax = COConfigurationManager.getIntParameter(SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT); 150 uploadLimitMin = SMConst.calculateMinUpload( uploadLimitMax ); 151 152 downloadLimitMax =COConfigurationManager.getIntParameter(SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT); 153 downloadLimitMin=SMConst.calculateMinDownload( downloadLimitMax ); 154 155 uploadLimitConf = SpeedLimitConfidence.parseString( 156 COConfigurationManager.getStringParameter( SpeedLimitMonitor.UPLOAD_CONF_LIMIT_SETTING )); 157 downloadLimitConf = SpeedLimitConfidence.parseString( 158 COConfigurationManager.getStringParameter( SpeedLimitMonitor.DOWNLOAD_CONF_LIMIT_SETTING)); 159 160 percentUploadCapacityDownloadMode = (float) 161 COConfigurationManager.getIntParameter(SpeedLimitMonitor.USED_UPLOAD_CAPACITY_DOWNLOAD_MODE, 60)/100.0f; 162 163 uploadChokePingCount = Math.min( 164 COConfigurationManager.getIntParameter(SpeedLimitMonitor.UPLOAD_CHOKE_PING_COUNT), 165 30 ); 166 167 slider.updateLimits(uploadLimitMax,uploadLimitMin,downloadLimitMax,downloadLimitMin); 168 slider.updateSeedSettings(percentUploadCapacityDownloadMode); 169 170 171 if( isSettingDownloadUnlimited() ){ 172 slider.setDownloadUnlimitedMode( true ); 173 } 174 175 }//updateFromCOConfigManager 176 177 /** 178 * replaces - updateFromCOConfigManager() 179 */ readFromPersistentMap()180 public void readFromPersistentMap(){ 181 //get persistent mapper. 182 SpeedManager sm = AzureusCoreFactory.getSingleton().getSpeedManager(); 183 184 //get upload estimate. 185 SpeedManagerLimitEstimate uEst = SMConst.filterEstimate( 186 sm.getEstimatedUploadCapacityBytesPerSec(), 187 SMConst.START_UPLOAD_RATE_MAX ); 188 189 int upPingMapLimit = uEst.getBytesPerSec(); 190 if(upPingMapLimit<SMConst.START_UPLOAD_RATE_MAX){ 191 //will find upload limit via slow search. 192 uploadLimitMax = SMConst.START_UPLOAD_RATE_MAX; 193 }else{ 194 uploadLimitMax = upPingMapLimit; 195 } 196 uploadLimitMin = SMConst.calculateMinUpload( uploadLimitMax ); 197 198 199 //get download estimate. 200 SpeedManagerLimitEstimate dEst = SMConst.filterEstimate( 201 sm.getEstimatedDownloadCapacityBytesPerSec(), 202 SMConst.START_DOWNLOAD_RATE_MAX ); 203 204 205 int downPingMapLimit = dEst.getBytesPerSec(); 206 if( isSettingDownloadUnlimited() ){ 207 slider.setDownloadUnlimitedMode(true); 208 }else{ 209 slider.setDownloadUnlimitedMode(false); 210 } 211 212 if(downPingMapLimit<SMConst.START_DOWNLOAD_RATE_MAX){ 213 downloadLimitMax = SMConst.START_DOWNLOAD_RATE_MAX; 214 }else{ 215 downloadLimitMax = downPingMapLimit; 216 } 217 downloadLimitMin = SMConst.calculateMinDownload( downloadLimitMax ); 218 219 uploadLimitConf = SpeedLimitConfidence.convertType( uEst.getEstimateType() ); 220 downloadLimitConf = SpeedLimitConfidence.convertType( dEst.getEstimateType() ); 221 222 percentUploadCapacityDownloadMode = (float) 223 COConfigurationManager.getIntParameter(SpeedLimitMonitor.USED_UPLOAD_CAPACITY_DOWNLOAD_MODE, 60)/100.0f; 224 225 saveToCOConfiguration(); 226 } 227 228 saveToCOConfiguration()229 public void saveToCOConfiguration(){ 230 COConfigurationManager.setParameter(SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT,uploadLimitMax); 231 COConfigurationManager.setParameter(SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT,downloadLimitMax); 232 COConfigurationManager.setParameter(SpeedLimitMonitor.UPLOAD_CONF_LIMIT_SETTING, uploadLimitConf.getString() ); 233 COConfigurationManager.setParameter(SpeedLimitMonitor.DOWNLOAD_CONF_LIMIT_SETTING, downloadLimitConf.getString() ); 234 COConfigurationManager.setParameter(SpeedLimitMonitor.UPLOAD_CHOKE_PING_COUNT,uploadChokePingCount); 235 } 236 logPMData(int oRate, SpeedLimitConfidence oConf, int nRate, float nConf, String type)237 private void logPMData(int oRate, SpeedLimitConfidence oConf, int nRate, float nConf, String type){ 238 239 // SpeedManagerLogger.log("speed-limit-conf: "+type+" rate="+oRate+" conf="+oConf.getString()+"("+oConf.asEstimateType() 240 // +") pm-rate="+nRate+" pm-conf="+nConf); 241 242 }//logPMData 243 logPMDataEx()244 public void logPMDataEx(){ 245 246 int tuploadLimitMax = COConfigurationManager.getIntParameter(SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT); 247 int tdownloadLimitMax =COConfigurationManager.getIntParameter(SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT); 248 249 //for testing. 250 SpeedManager sm = AzureusCoreFactory.getSingleton().getSpeedManager(); 251 SpeedManagerLimitEstimate dEst = sm.getEstimatedDownloadCapacityBytesPerSec(); 252 253 int tmpDMax = dEst.getBytesPerSec(); 254 float tmpDMaxConf = dEst.getEstimateType(); 255 256 257 // for testing. 258 SpeedManagerLimitEstimate uEst = sm.getEstimatedUploadCapacityBytesPerSec(); 259 int tmpUMax = uEst.getBytesPerSec(); 260 float tmpUMaxConf = uEst.getEstimateType(); 261 262 SpeedLimitConfidence tuploadLimitConf = SpeedLimitConfidence.parseString( 263 COConfigurationManager.getStringParameter( SpeedLimitMonitor.UPLOAD_CONF_LIMIT_SETTING )); 264 SpeedLimitConfidence tdownloadLimitConf = SpeedLimitConfidence.parseString( 265 COConfigurationManager.getStringParameter( SpeedLimitMonitor.DOWNLOAD_CONF_LIMIT_SETTING)); 266 267 // 268 logPMData(tuploadLimitMax, tuploadLimitConf, tmpUMax, tmpUMaxConf, "check-upload" ); 269 logPMData(tdownloadLimitMax, tdownloadLimitConf, tmpDMax, tmpDMaxConf, "check-download" ); 270 271 }//logPMDataEx 272 273 274 /** 275 * The criteria for download being unlimited is if the ConfigPanel has the 276 * "download == 0 " && "type==fixed" 277 * @return - true 278 */ isSettingDownloadUnlimited()279 private boolean isSettingDownloadUnlimited(){ 280 281 SpeedManagerAlgorithmProviderAdapter adpter = SMInstance.getInstance().getAdapter(); 282 283 SpeedManager sm = adpter.getSpeedManager(); 284 SpeedManagerLimitEstimate dEst = sm.getEstimatedDownloadCapacityBytesPerSec(); 285 286 int rate = dEst.getBytesPerSec(); 287 float type = dEst.getEstimateType(); 288 289 //user or plug-in want the download rate unlimited. 290 if( rate==0 && type==SpeedManagerLimitEstimate.TYPE_MANUAL ){ 291 return true; 292 } 293 294 //start the search in unlimited mode. 295 if( rate==0 && type==SpeedManagerLimitEstimate.TYPE_UNKNOWN){ 296 return true; 297 } 298 299 return false; 300 } 301 302 //SpeedLimitMonitorStatus setDownloadBandwidthMode(int rate, int limit)303 public void setDownloadBandwidthMode(int rate, int limit){ 304 downloadBandwidthStatus = SaturatedMode.getSaturatedMode(rate,limit); 305 } 306 setUploadBandwidthMode(int rate, int limit)307 public void setUploadBandwidthMode(int rate, int limit){ 308 uploadBandwidthStatus = SaturatedMode.getSaturatedMode(rate,limit); 309 } 310 setDownloadLimitSettingMode(int currLimit)311 public void setDownloadLimitSettingMode(int currLimit){ 312 downloadLimitSettingStatus = SaturatedMode.getSaturatedMode(currLimit, downloadLimitMax); 313 } 314 setUploadLimitSettingMode(int currLimit)315 public void setUploadLimitSettingMode(int currLimit){ 316 if( !transferMode.isDownloadMode() ){ 317 uploadLimitSettingStatus = SaturatedMode.getSaturatedMode(currLimit, uploadLimitMax); 318 }else{ 319 uploadLimitSettingStatus = SaturatedMode.getSaturatedMode(currLimit, uploadLimitMax); 320 } 321 } 322 getUploadMaxLimit()323 public int getUploadMaxLimit(){ 324 return uploadLimitMax; 325 } 326 getDownloadMaxLimit()327 public int getDownloadMaxLimit(){ 328 return downloadLimitMax; 329 } 330 getUploadMinLimit()331 public int getUploadMinLimit(){ 332 return uploadLimitMin; 333 } 334 getDownloadMinLimit()335 public int getDownloadMinLimit(){ 336 return downloadLimitMin; 337 } 338 getUploadConfidence()339 public String getUploadConfidence(){ 340 return uploadLimitConf.getString(); 341 } 342 getDownloadConfidence()343 public String getDownloadConfidence(){ 344 return downloadLimitConf.getString(); 345 } 346 getDownloadBandwidthMode()347 public SaturatedMode getDownloadBandwidthMode(){ 348 return downloadBandwidthStatus; 349 } 350 getUploadBandwidthMode()351 public SaturatedMode getUploadBandwidthMode(){ 352 return uploadBandwidthStatus; 353 } 354 getDownloadLimitSettingMode()355 public SaturatedMode getDownloadLimitSettingMode(){ 356 return downloadLimitSettingStatus; 357 } 358 getUploadLimitSettingMode()359 public SaturatedMode getUploadLimitSettingMode(){ 360 return uploadLimitSettingStatus; 361 } 362 updateTransferMode()363 public void updateTransferMode(){ 364 365 transferMode.updateStatus( downloadBandwidthStatus ); 366 } 367 getTransferModeAsString()368 public String getTransferModeAsString(){ 369 return transferMode.getString(); 370 } 371 getTransferMode()372 public TransferMode getTransferMode(){ 373 return transferMode; 374 } 375 376 377 /** 378 * Are both the upload and download bandwidths usages is low? 379 * Otherwise false. 380 * @return - 381 */ bandwidthUsageLow()382 public boolean bandwidthUsageLow(){ 383 384 if( uploadBandwidthStatus.compareTo(SaturatedMode.LOW)<=0 && 385 downloadBandwidthStatus.compareTo(SaturatedMode.LOW)<=0){ 386 387 return true; 388 389 } 390 391 //Either upload or download is at MEDIUM or above. 392 return false; 393 } 394 395 /** 396 * 397 * @return - 398 */ bandwidthUsageMedium()399 public boolean bandwidthUsageMedium(){ 400 if( uploadBandwidthStatus.compareTo(SaturatedMode.MED)<=0 && 401 downloadBandwidthStatus.compareTo(SaturatedMode.MED)<=0){ 402 return true; 403 } 404 405 //Either upload or download is at MEDIUM or above. 406 return false; 407 } 408 409 /** 410 * True if both are at limits. 411 * @return - true only if both the upload and download usages are at the limits. 412 */ bandwidthUsageAtLimit()413 public boolean bandwidthUsageAtLimit(){ 414 if( uploadBandwidthStatus.compareTo(SaturatedMode.AT_LIMIT)==0 && 415 downloadBandwidthStatus.compareTo(SaturatedMode.AT_LIMIT)==0){ 416 return true; 417 } 418 return false; 419 } 420 421 /** 422 * True if the upload bandwidth usage is HIGH or AT_LIMIT. 423 * @return - 424 */ isUploadBandwidthUsageHigh()425 public boolean isUploadBandwidthUsageHigh(){ 426 if( uploadBandwidthStatus.compareTo(SaturatedMode.AT_LIMIT)==0 || 427 uploadBandwidthStatus.compareTo(SaturatedMode.HIGH)==0){ 428 return true; 429 } 430 return false; 431 } 432 isEitherLimitUnpinned()433 public boolean isEitherLimitUnpinned(){ 434 return ( !isUploadMaxPinned || !isDownloadMaxPinned ); 435 } 436 437 /** 438 * Does the same as createNewLimit except it drops the upload rate first when in download mode. 439 * @param signalStrength - 440 * @param multiple - 441 * @param currUpLimit - 442 * @param currDownLimit - 443 * @return - 444 */ modifyLimits(float signalStrength, float multiple, int currUpLimit, int currDownLimit)445 public SMUpdate modifyLimits(float signalStrength, float multiple, int currUpLimit, int currDownLimit){ 446 447 //this flag is set in a previous method. 448 if( isStartLimitTestFlagSet() ){ 449 SpeedManagerLogger.trace("modifyLimits - startLimitTesting."); 450 SMUpdate update = startLimitTesting(currUpLimit, currDownLimit); 451 return checkActiveProgressiveDownloadLimit( update ); 452 } 453 454 455 if( isEitherLimitUnpinned() ){ 456 SpeedManagerLogger.trace("modifyLimits - calculateNewUnpinnedLimits"); 457 SMUpdate update = calculateNewUnpinnedLimits(signalStrength); 458 return checkActiveProgressiveDownloadLimit( update ); 459 } 460 461 slider.updateLimits(uploadLimitMax,uploadLimitMin, 462 downloadLimitMax,downloadLimitMin); 463 464 slider.updateStatus(currUpLimit,uploadBandwidthStatus, 465 currDownLimit, downloadBandwidthStatus,transferMode); 466 467 SMUpdate update = slider.adjust( signalStrength*multiple ); 468 return checkActiveProgressiveDownloadLimit( update ); 469 }//modifyLimits 470 471 /** 472 * If a progressive download is currently active. Then the download limit should 473 * not be allowed to go below that limit, regardless of anything else. 474 * @param update - 475 * @return - 476 */ checkActiveProgressiveDownloadLimit( SMUpdate update )477 private SMUpdate checkActiveProgressiveDownloadLimit( SMUpdate update ){ 478 479 //Do we have an active download limit? 480 long prgDownLimit = RealTimeInfo.getProgressiveActiveBytesPerSec(); 481 482 //If the value is zero, then the no progressive download is currently active. 483 if( prgDownLimit==0 ){ 484 return update; 485 } 486 487 //We seem to have an active progressive download. Make sure the limit does not 488 //drop below that limit. 489 final int MULTIPLE = 2; 490 if( prgDownLimit*MULTIPLE > update.newDownloadLimit && update.newDownloadLimit!=0 ) 491 { 492 log( "Active Progressive download in progress. Overriding limit. curr="+update.newDownloadLimit 493 +" progDownloadLimit="+prgDownLimit*MULTIPLE ); 494 495 update.newDownloadLimit = (int)prgDownLimit*MULTIPLE; 496 }//if 497 498 return update; 499 }//checkActiveProgressiveDownloadLimit 500 501 /** 502 * Log debug info needed during beta period. 503 */ logPinningInfo()504 private void logPinningInfo() { 505 StringBuffer sb = new StringBuffer("pin: "); 506 if(isUploadMaxPinned){ 507 sb.append("ul-pinned:"); 508 }else{ 509 sb.append("ul-unpinned:"); 510 } 511 if(isDownloadMaxPinned){ 512 sb.append("dl-pinned:"); 513 }else{ 514 sb.append("dl-unpinned:"); 515 } 516 long currTime = SystemTime.getCurrentTime(); 517 long upWait = currTime - uploadAtLimitStartTime; 518 long downWait = currTime - downloadAtLimitStartTime; 519 sb.append(upWait).append(":").append(downWait); 520 log( sb.toString() ); 521 } 522 523 /** 524 * 525 * @param signalStrength - 526 * @return - 527 */ calculateNewUnpinnedLimits(float signalStrength)528 public SMUpdate calculateNewUnpinnedLimits(float signalStrength){ 529 530 //first verify that is this is an up signal. 531 if(signalStrength<0.0f){ 532 //down-tick is a signal to stop moving the files up. 533 isUploadMaxPinned=true; 534 isDownloadMaxPinned=true; 535 }//if 536 537 //just verify settings to make sure everything is sane before updating. 538 boolean updateUpload=false; 539 boolean updateDownload=false; 540 541 if( uploadBandwidthStatus.compareTo(SaturatedMode.AT_LIMIT)==0 && 542 uploadLimitSettingStatus.compareTo(SaturatedMode.AT_LIMIT)==0 ){ 543 updateUpload=true; 544 } 545 546 if( downloadBandwidthStatus.compareTo(SaturatedMode.AT_LIMIT)==0 && 547 downloadLimitSettingStatus.compareTo(SaturatedMode.AT_LIMIT)==0 ){ 548 updateDownload=true; 549 } 550 551 boolean uploadChanged=false; 552 boolean downloadChanged=false; 553 554 555 if(updateUpload && !transferMode.isDownloadMode() ){ 556 //slow the upload rate the more. 557 uploadPinCounter++; 558 if( uploadPinCounter%(Math.ceil(Math.sqrt(uploadChokePingCount)))==0 ){ 559 //increase limit by calculated amount, but only if not in downloading mode. 560 uploadLimitMax += calculateUnpinnedStepSize(uploadLimitMax); 561 uploadChanged=true; 562 COConfigurationManager.setParameter( 563 SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT, uploadLimitMax); 564 COConfigurationManager.setParameter( 565 SpeedLimitMonitor.UPLOAD_CHOKE_PING_COUNT,uploadChokePingCount); 566 }//if 567 } 568 if(updateDownload && !slider.isDownloadUnlimitedMode() ){ 569 //increase limit by calculated amount. 570 downloadLimitMax += calculateUnpinnedStepSize(downloadLimitMax); 571 downloadChanged=true; 572 COConfigurationManager.setParameter( 573 SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT, downloadLimitMax); 574 } 575 576 //apply any rules that need applied. 577 //The download limit can never be less then the upload limit. (Unless zero. UNLIMITED) 578 if( uploadLimitMax > downloadLimitMax){ 579 downloadLimitMax = uploadLimitMax; 580 downloadChanged=true; 581 COConfigurationManager.setParameter( 582 SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT, downloadLimitMax); 583 } 584 585 uploadLimitMin = SMConst.calculateMinUpload( uploadLimitMax ); 586 downloadLimitMin = SMConst.calculateMinDownload( downloadLimitMax ); 587 588 if( slider.isDownloadUnlimitedMode() ){ 589 SpeedManagerLogger.trace("upload unpinned while download is unlimited."); 590 return new SMUpdate(uploadLimitMax,uploadChanged, 0,false); 591 } 592 593 return new SMUpdate(uploadLimitMax,uploadChanged, downloadLimitMax,downloadChanged); 594 }//calculateNewUnpinnedLimits 595 596 /** 597 * If setting is less then 100kBytes take 1 kByte steps. 598 * If setting is less then 500kBytes take 5 kByte steps. 599 * if setting is larger take 10 kBytes steps. 600 * @param currLimitMax - current limit setting. 601 * @return - set size for next change. 602 */ calculateUnpinnedStepSize(int currLimitMax)603 private int calculateUnpinnedStepSize(int currLimitMax){ 604 if(currLimitMax<102400){ 605 return 1024; 606 }else if(currLimitMax<409600){ 607 return 1024*5; 608 }else{ 609 return 1024*10; 610 } 611 }// 612 613 /** 614 * Make a decision about unpinning either the upload or download limit. This is based on the 615 * time we are saturating the limit without a down-tick signal. 616 */ checkForUnpinningCondition()617 public void checkForUnpinningCondition(){ 618 619 long currTime = SystemTime.getCurrentTime(); 620 621 //verify the download is not unlimited. 622 slider.setDownloadUnlimitedMode( isSettingDownloadUnlimited() ); 623 624 //upload useage must be at limits for a set period of time before unpinning. 625 if( !uploadBandwidthStatus.equals(SaturatedMode.AT_LIMIT) || 626 !uploadLimitSettingStatus.equals(SaturatedMode.AT_LIMIT) ) 627 { 628 //start the clock over. 629 uploadAtLimitStartTime = currTime; 630 }else{ 631 //check to see if we have been here for the time limit. 632 if( uploadAtLimitStartTime+(TIME_AT_LIMIT_BEFORE_UNPINNING* uploadChokePingCount) < currTime ){ 633 634 if( isUploadConfidenceLow() ){ 635 if( !transferMode.isDownloadMode() ){ 636 //alway slow search the upload limit. 637 isUploadMaxPinned = false; 638 } 639 }else{ 640 //Don't unpin the limit is we have absolute confidence in it. 641 if( !isUploadConfidenceAbsolute() ){ 642 //we have been AT_LIMIT long enough. Time to un-pin the limit see if we can go higher. 643 isUploadMaxPinned = false; 644 SpeedManagerLogger.trace("unpinning the upload max limit!! #choke-pings="+uploadChokePingCount+ 645 ", pin-counter="+uploadPinCounter); 646 } 647 } 648 } 649 } 650 651 //download usage must be at limits for a set period of time before unpinning. 652 if( !downloadBandwidthStatus.equals(SaturatedMode.AT_LIMIT) || 653 !downloadLimitSettingStatus.equals(SaturatedMode.AT_LIMIT) ) 654 { 655 //start the clock over. 656 downloadAtLimitStartTime = currTime; 657 }else{ 658 //check to see if we have been here for the time limit. 659 if( downloadAtLimitStartTime+TIME_AT_LIMIT_BEFORE_UNPINNING < currTime ){ 660 661 if( isDownloadConfidenceLow() ){ 662 if( transferMode.isDownloadMode() ){ 663 triggerLimitTestingFlag(); 664 } 665 }else{ 666 if( !isDownloadConfidenceAbsolute() ){ 667 //we have been AT_LIMIT long enough. Time to un-pin the limit see if we can go higher. 668 isDownloadMaxPinned = false; 669 SpeedManagerLogger.trace("unpinning the download max limit!!"); 670 } 671 } 672 } 673 } 674 675 logPinningInfo(); 676 } 677 678 /** 679 * If we have a down-tick signal then resetTimer all the counters for increasing the limits. 680 */ notifyOfDownSignal()681 public void notifyOfDownSignal(){ 682 683 if( !isUploadMaxPinned ){ 684 uploadChokePingCount++; 685 String msg = "pinning the upload max limit, due to downtick signal. #downtick="+ uploadChokePingCount; 686 SpeedManagerLogger.trace(msg); 687 SMSearchLogger.log(msg); 688 } 689 690 if( !isDownloadMaxPinned ){ 691 String msg = "pinning the download max limit, due to downtick signal."; 692 SpeedManagerLogger.trace(msg); 693 SMSearchLogger.log(msg); 694 } 695 696 resetPinSearch(); 697 } 698 resetPinSearch()699 void resetPinSearch(){ 700 long currTime = SystemTime.getCurrentTime(); 701 702 uploadAtLimitStartTime = currTime; 703 downloadAtLimitStartTime = currTime; 704 isUploadMaxPinned = true; 705 isDownloadMaxPinned = true; 706 } 707 resetPinSearch(SpeedManagerLimitEstimate estimate)708 void resetPinSearch(SpeedManagerLimitEstimate estimate){ 709 //chocking ping needs higher limit. 710 float type = estimate.getEstimateType(); 711 if(type>=SpeedManagerLimitEstimate.TYPE_CHOKE_ESTIMATED){ 712 uploadChokePingCount++; 713 } 714 resetPinSearch(); 715 } 716 717 /** 718 * Return true if we are confidence testing the limits. 719 * @return - SMUpdate 720 */ isConfTestingLimits()721 public boolean isConfTestingLimits(){ 722 return transferMode.isConfTestingLimits(); 723 }// 724 725 /** 726 * Determine if we have low confidence in this limit. 727 * @return - true if the confidence setting is LOW or NONE. Otherwise return true. 728 */ isDownloadConfidenceLow()729 public boolean isDownloadConfidenceLow(){ 730 return ( downloadLimitConf.compareTo(SpeedLimitConfidence.MED) < 0 ); 731 } 732 isUploadConfidenceLow()733 public boolean isUploadConfidenceLow(){ 734 return ( uploadLimitConf.compareTo(SpeedLimitConfidence.MED) < 0 ); 735 } 736 isDownloadConfidenceAbsolute()737 public boolean isDownloadConfidenceAbsolute(){ 738 return ( downloadLimitConf.compareTo(SpeedLimitConfidence.ABSOLUTE)==0 ); 739 } 740 isUploadConfidenceAbsolute()741 public boolean isUploadConfidenceAbsolute(){ 742 return ( uploadLimitConf.compareTo(SpeedLimitConfidence.ABSOLUTE)==0 ); 743 } 744 745 746 /** 747 * 748 * @param downloadRate - currentUploadRate in bytes/sec 749 * @param uploadRate - currentUploadRate in bytes/sec 750 */ updateLimitTestingData( int downloadRate, int uploadRate )751 public synchronized void updateLimitTestingData( int downloadRate, int uploadRate ){ 752 if( downloadRate>highestDownloadRate ){ 753 highestDownloadRate=downloadRate; 754 } 755 if( uploadRate>highestUploadRate){ 756 highestUploadRate=uploadRate; 757 } 758 759 //The exit criteria for this test is 30 seconds without an increase in the limits. 760 long currTime = SystemTime.getCurrentTime(); 761 if( currTime > clLastIncreaseTime+CONF_LIMIT_TEST_LENGTH){ 762 //set the test done flag. 763 currTestDone=true; 764 } 765 // or 30 seconds after its first bad ping. 766 if( clFirstBadPingTime!=-1){ 767 if( currTime > clFirstBadPingTime+CONF_LIMIT_TEST_LENGTH){ 768 //set the test done flag. 769 currTestDone=true; 770 } 771 } 772 773 }//updateLimitTestingData. 774 775 776 /** 777 * Convert raw ping value to new metric. 778 * @param lastMetric - 779 */ updateLimitTestingPing(int lastMetric)780 public void updateLimitTestingPing(int lastMetric){ 781 //Convert raw - pings into a rating. 782 if(lastMetric>500){ 783 updateLimitTestingPing(-1.0f); 784 } 785 } 786 787 /** 788 * New metric from the PingMapper is value between -1.0 and +1.0f. 789 * @param lastMetric - 790 */ updateLimitTestingPing(float lastMetric)791 public void updateLimitTestingPing(float lastMetric){ 792 if( lastMetric<-0.3f){ 793 //Setting this time is a signal to end soon. 794 clFirstBadPingTime = SystemTime.getCurrentTime(); 795 } 796 } 797 798 799 /** 800 * Call this method to start the limit testing. 801 * @param currUploadLimit - 802 * @param currDownloadLimit - 803 * @return - SMUpdate 804 */ startLimitTesting(int currUploadLimit, int currDownloadLimit)805 public SMUpdate startLimitTesting(int currUploadLimit, int currDownloadLimit){ 806 807 clLastIncreaseTime =SystemTime.getCurrentTime(); 808 clFirstBadPingTime =-1; 809 810 highestUploadRate=0; 811 highestDownloadRate=0; 812 currTestDone=false; 813 814 //reset the flag. 815 beginLimitTest=false; 816 817 //get the limits before the test, we are restoring them after the test. 818 preTestUploadLimit = currUploadLimit; 819 preTestDownloadLimit = currDownloadLimit; 820 821 //configure the limits for this test. One will be at min and the other unlimited. 822 SMUpdate retVal; 823 if( transferMode.isDownloadMode() ){ 824 //test the download limit. 825 retVal = new SMUpdate(uploadLimitMin,true, 826 Math.round(downloadLimitMax *1.2f),true); 827 preTestDownloadCapacity = downloadLimitMax; 828 transferMode.setMode( TransferMode.State.DOWNLOAD_LIMIT_SEARCH ); 829 }else{ 830 //test the upload limit. 831 retVal = new SMUpdate( Math.round(uploadLimitMax *1.2f),true, 832 downloadLimitMin,true); 833 preTestUploadCapacity = uploadLimitMax; 834 transferMode.setMode( TransferMode.State.UPLOAD_LIMIT_SEARCH ); 835 } 836 837 return retVal; 838 } 839 840 /** 841 * Ramp the upload and download rates higher, so ping-times are relevant. 842 * @param uploadLimit - 843 * @param downloadLimit - 844 * @return - 845 */ rampTestingLimit(int uploadLimit, int downloadLimit)846 public SMUpdate rampTestingLimit(int uploadLimit, int downloadLimit){ 847 SMUpdate retVal; 848 if( transferMode.getMode() == TransferMode.State.DOWNLOAD_LIMIT_SEARCH 849 && downloadBandwidthStatus.isGreater( SaturatedMode.MED ) ) 850 { 851 downloadLimit *= 1.1f; 852 clLastIncreaseTime = SystemTime.getCurrentTime(); 853 retVal = new SMUpdate(uploadLimit,false,downloadLimit,true); 854 855 }else if( transferMode.getMode() == TransferMode.State.UPLOAD_LIMIT_SEARCH 856 && uploadBandwidthStatus.isGreater( SaturatedMode.MED )) 857 { 858 uploadLimit *= 1.1f; 859 clLastIncreaseTime = SystemTime.getCurrentTime(); 860 retVal = new SMUpdate(uploadLimit,true,downloadLimit,false); 861 862 }else{ 863 retVal = new SMUpdate(uploadLimit,false,downloadLimit,false); 864 SpeedManagerLogger.trace("ERROR: rampTestLimit should only be called during limit testing. "); 865 } 866 867 return retVal; 868 }//rampTestingLimit 869 triggerLimitTestingFlag()870 public void triggerLimitTestingFlag(){ 871 SpeedManagerLogger.trace("triggerd fast limit test."); 872 beginLimitTest=true; 873 874 //if we are using a persistent PingSource then get that here. 875 if( useVariancePingMap ){ 876 SMInstance pm = SMInstance.getInstance(); 877 SpeedManagerAlgorithmProviderAdapter adapter = pm.getAdapter(); 878 879 //start a new transientPingMap; 880 if(transientPingMap!=null){ 881 transientPingMap.destroy(); 882 } 883 transientPingMap = adapter.createTransientPingMapper(); 884 } 885 886 } 887 isStartLimitTestFlagSet()888 public synchronized boolean isStartLimitTestFlagSet(){ 889 return beginLimitTest; 890 } 891 isConfLimitTestFinished()892 public synchronized boolean isConfLimitTestFinished(){ 893 return currTestDone; 894 } 895 endLimitTesting(int downloadCapacityGuess, int uploadCapacityGuess)896 public synchronized SMUpdate endLimitTesting(int downloadCapacityGuess, int uploadCapacityGuess){ 897 898 SpeedManagerLogger.trace(" repalce highestDownloadRate: "+highestDownloadRate+" with "+downloadCapacityGuess); 899 SpeedManagerLogger.trace(" replace highestUploadRate: "+highestUploadRate+" with "+uploadCapacityGuess); 900 901 highestDownloadRate = downloadCapacityGuess; 902 highestUploadRate = uploadCapacityGuess; 903 904 return endLimitTesting(); 905 } 906 907 /** 908 * Call this method to end the limit testing. 909 * @return - SMUpdate 910 */ endLimitTesting()911 public synchronized SMUpdate endLimitTesting(){ 912 913 SMUpdate retVal; 914 //determine if the new setting is different then the old setting. 915 if( transferMode.getMode()==TransferMode.State.DOWNLOAD_LIMIT_SEARCH ){ 916 917 downloadLimitConf = determineConfidenceLevel(); 918 919 //set that value. 920 SpeedManagerLogger.trace("pre-upload-setting="+ preTestUploadCapacity +" up-capacity"+ uploadLimitMax 921 +" pre-download-setting="+ preTestDownloadCapacity +" down-capacity="+ downloadLimitMax); 922 923 retVal = new SMUpdate(preTestUploadLimit,true, downloadLimitMax,true); 924 //change back to original mode. 925 transferMode.setMode( TransferMode.State.DOWNLOADING ); 926 927 }else if( transferMode.getMode()==TransferMode.State.UPLOAD_LIMIT_SEARCH){ 928 929 uploadLimitConf = determineConfidenceLevel(); 930 931 //set that value. 932 retVal = new SMUpdate(uploadLimitMax,true, downloadLimitMax,true); 933 //change back to original mode. 934 transferMode.setMode( TransferMode.State.SEEDING ); 935 936 }else{ 937 //This is an "illegal state" make it in the logs, but try to recover by setting back to original state. 938 SpeedManagerLogger.log("SpeedLimitMonitor had IllegalState during endLimitTesting."); 939 retVal = new SMUpdate(preTestUploadLimit,true, preTestDownloadLimit,true); 940 } 941 942 currTestDone=true; 943 944 //reset the counter 945 uploadAtLimitStartTime = SystemTime.getCurrentTime(); 946 downloadAtLimitStartTime = SystemTime.getCurrentTime(); 947 948 return retVal; 949 } 950 951 /** 952 * After a test is complete determine how condifent the client should be in it 953 * based on how different it is from the previous result. If the new result is within 954 * 20% of the old result then give it a MED. If it is great then give it a LOW. 955 * @return - what the new confidence interval should be. 956 */ determineConfidenceLevel()957 public SpeedLimitConfidence determineConfidenceLevel(){ 958 SpeedLimitConfidence retVal=SpeedLimitConfidence.NONE; 959 String settingMaxLimitName; 960 //String settingMinLimitName; 961 boolean isDownload; 962 String settingConfidenceName; 963 int preTestValue; 964 int highestValue; 965 if(transferMode.getMode()==TransferMode.State.DOWNLOAD_LIMIT_SEARCH){ 966 967 settingConfidenceName = DOWNLOAD_CONF_LIMIT_SETTING; 968 settingMaxLimitName = SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT; 969 isDownload=true; 970 preTestValue = preTestDownloadCapacity; 971 highestValue = highestDownloadRate; 972 }else if(transferMode.getMode()==TransferMode.State.UPLOAD_LIMIT_SEARCH){ 973 974 settingConfidenceName = UPLOAD_CONF_LIMIT_SETTING; 975 settingMaxLimitName = SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT; 976 isDownload=false; 977 preTestValue = preTestUploadCapacity; 978 highestValue = highestUploadRate; 979 }else{ 980 // 981 SpeedManagerLogger.log("IllegalState in determineConfidenceLevel(). Setting level to NONE."); 982 return SpeedLimitConfidence.NONE; 983 } 984 985 boolean hadChockingPing = hadChockingPing(); 986 float percentDiff = (float)Math.abs( highestValue-preTestValue )/(float)(Math.max(highestValue,preTestValue)); 987 if( percentDiff<0.15f && hadChockingPing ){ 988 //Only set to medium if had both a chocking ping and two tests with similar results. 989 retVal = SpeedLimitConfidence.MED; 990 }else{ 991 retVal = SpeedLimitConfidence.LOW; 992 } 993 994 //update the values. 995 COConfigurationManager.setParameter(settingConfidenceName, retVal.getString() ); 996 int newMaxLimitSetting = highestValue; 997 COConfigurationManager.setParameter(settingMaxLimitName, newMaxLimitSetting); 998 int newMinLimitSetting; 999 if( isDownload ){ 1000 newMinLimitSetting = SMConst.calculateMinDownload( newMaxLimitSetting ); 1001 }else{ 1002 newMinLimitSetting = SMConst.calculateMinUpload( newMaxLimitSetting ); 1003 } 1004 1005 StringBuffer sb = new StringBuffer(); 1006 if( transferMode.getMode()==TransferMode.State.UPLOAD_LIMIT_SEARCH ){ 1007 sb.append("new upload limits: "); 1008 uploadLimitMax =newMaxLimitSetting; 1009 uploadLimitMin=newMinLimitSetting; 1010 //downloadCapacity can never be less then upload capacity. 1011 if( downloadLimitMax < uploadLimitMax){ 1012 downloadLimitMax = uploadLimitMax; 1013 COConfigurationManager.setParameter( 1014 SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT, downloadLimitMax); 1015 } 1016 sb.append(uploadLimitMax); 1017 }else{ 1018 sb.append("new download limits: "); 1019 downloadLimitMax =newMaxLimitSetting; 1020 downloadLimitMin=newMinLimitSetting; 1021 //upload capacity should never be 40x less then download. 1022 if( uploadLimitMax * 40 < downloadLimitMax){ 1023 uploadLimitMax = downloadLimitMax /40; 1024 COConfigurationManager.setParameter( 1025 SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT, uploadLimitMax); 1026 1027 uploadLimitMin = SMConst.calculateMinUpload( uploadLimitMax ); 1028 }//if 1029 sb.append(downloadLimitMax); 1030 } 1031 1032 slider.updateLimits(uploadLimitMax,uploadLimitMin,downloadLimitMax,downloadLimitMin); 1033 1034 SpeedManagerLogger.trace( sb.toString() ); 1035 1036 return retVal; 1037 } 1038 1039 /** 1040 * If the user changes the line capacity settings on the configuration panel and adjustment 1041 * needs to occur even if the signal is NO-CHANGE-NEEDED. Test for that condition here. 1042 * @param currUploadLimit - reported upload capacity from the adapter 1043 * @param currDownloadLimit - reported download capacity from the adapter. 1044 * @return - true if the "capacity" is lower then the current limit. 1045 */ areSettingsInSpec(int currUploadLimit, int currDownloadLimit)1046 public boolean areSettingsInSpec(int currUploadLimit, int currDownloadLimit){ 1047 1048 //during a confidence level test, anything goes. 1049 if( isConfTestingLimits() ){ 1050 return true; 1051 } 1052 1053 boolean retVal = true; 1054 if( currUploadLimit> uploadLimitMax){ 1055 retVal = false; 1056 } 1057 if( currDownloadLimit> downloadLimitMax && slider.isDownloadUnlimitedMode() ){ 1058 retVal = false; 1059 } 1060 return retVal; 1061 } 1062 choseBestLimit(SpeedManagerLimitEstimate estimate, int currMaxLimit, SpeedLimitConfidence currConf)1063 private int choseBestLimit(SpeedManagerLimitEstimate estimate, int currMaxLimit, SpeedLimitConfidence currConf) { 1064 float type = estimate.getEstimateType(); 1065 int estBytesPerSec = estimate.getBytesPerSec(); 1066 int chosenLimit; 1067 1068 //no estimate less then 20k accepted. 1069 if( (estBytesPerSec<currMaxLimit) && estBytesPerSec<20480 ){ 1070 return currMaxLimit; 1071 } 1072 1073 String reason=""; 1074 if( type==SpeedManagerLimitEstimate.TYPE_MANUAL){ 1075 chosenLimit = estBytesPerSec; 1076 reason="manual"; 1077 }else if( type==SpeedManagerLimitEstimate.TYPE_UNKNOWN){ 1078 chosenLimit = Math.max( estBytesPerSec, currMaxLimit ); 1079 reason="unknown"; 1080 }else if (type==SpeedManagerLimitEstimate.TYPE_ESTIMATED ){ 1081 1082 if ( estimate.getMetricRating() >= 0.0 ){ 1083 1084 // things looking good, this is just a new limit estimate and shouldn't 1085 // affect the actual limit in force 1086 1087 return( currMaxLimit ); 1088 1089 }else{ 1090 1091 chosenLimit = estBytesPerSec; 1092 reason = "estimate and bad metric"; 1093 } 1094 1095 }else{ 1096 //chose ping mapper. 1097 chosenLimit = estBytesPerSec; 1098 } 1099 1100 SpeedManagerLogger.trace("bestChosenLimit: reason="+reason+",chosenLimit="+chosenLimit); 1101 1102 return chosenLimit; 1103 } 1104 1105 /** 1106 * Make some choices about how usable the limits are before passing them on. 1107 * @param estUp - 1108 * @param estDown - 1109 */ setRefLimits(SpeedManagerLimitEstimate estUp,SpeedManagerLimitEstimate estDown)1110 public void setRefLimits(SpeedManagerLimitEstimate estUp,SpeedManagerLimitEstimate estDown){ 1111 1112 SpeedManagerLimitEstimate up = SMConst.filterEstimate(estUp,SMConst.MIN_UPLOAD_BYTES_PER_SEC); 1113 int upMax = choseBestLimit(up, uploadLimitMax, uploadLimitConf); 1114 1115 SpeedManagerLimitEstimate down = SMConst.filterEstimate(estDown, SMConst.MIN_DOWNLOAD_BYTES_PER_SEC); 1116 int downMax = choseBestLimit(down, downloadLimitMax, downloadLimitConf); 1117 1118 if(downMax<upMax){ 1119 SpeedManagerLogger.trace("down max-limit was less then up-max limit. increasing down max-limit. upMax=" 1120 +upMax+" downMax="+downMax); 1121 downMax = upMax; 1122 } 1123 1124 setRefLimits(upMax,downMax); 1125 } 1126 setRefLimits(int uploadMax, int downloadMax)1127 public void setRefLimits(int uploadMax, int downloadMax){ 1128 1129 if( (uploadLimitMax!=uploadMax) && (uploadMax>0) ){ 1130 uploadLimitMax=uploadMax; 1131 COConfigurationManager.setParameter( 1132 SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT, uploadLimitMax); 1133 } 1134 1135 uploadLimitMin = SMConst.calculateMinUpload( uploadMax ); 1136 1137 if( (downloadLimitMax!=downloadMax) && (downloadMax>0) ){ 1138 downloadLimitMax = downloadMax; 1139 COConfigurationManager.setParameter( 1140 SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT, downloadLimitMax); 1141 } 1142 1143 downloadLimitMin = SMConst.calculateMinDownload(downloadMax); 1144 1145 SpeedManagerLogger.trace("setRefLimits uploadMax="+uploadMax+" uploadLimitMax="+uploadLimitMax+", downloadMax="+downloadMax+" downloadLimitMax="+downloadLimitMax); 1146 1147 slider.updateLimits(uploadLimitMax,uploadLimitMin,downloadLimitMax,downloadLimitMin); 1148 } 1149 1150 /** 1151 * It is likely the user adjusted the "line speed capacity" on the configuration panel. 1152 * We need to adjust the current limits down to adjust. 1153 * @param currUploadLimit - 1154 * @param currDownloadLimit - 1155 * @return - Updates as needed. 1156 */ adjustLimitsToSpec(int currUploadLimit, int currDownloadLimit)1157 public SMUpdate adjustLimitsToSpec(int currUploadLimit, int currDownloadLimit){ 1158 1159 int newUploadLimit = currUploadLimit; 1160 boolean uploadChanged = false; 1161 int newDownloadLimit = currDownloadLimit; 1162 boolean downloadChanged = false; 1163 1164 StringBuffer reason = new StringBuffer(); 1165 1166 //check for the case when the line-speed capacity is below the current limit. 1167 if( currUploadLimit> uploadLimitMax && uploadLimitMax!=0){ 1168 1169 newUploadLimit = uploadLimitMax; 1170 uploadChanged = true; 1171 1172 reason.append(" (a) upload line-speed cap below current limit. "); 1173 } 1174 1175 if(uploadLimitMax==0){ 1176 reason.append("** uploadLimitMax=0 (Unlimited)! ** "); 1177 } 1178 1179 //check for the case when the min setting has been moved above the current limit. 1180 if( currDownloadLimit> downloadLimitMax && !slider.isDownloadUnlimitedMode() ){ 1181 newDownloadLimit = downloadLimitMax; 1182 downloadChanged = true; 1183 1184 reason.append(" (b) download line-speed cap below current limit. "); 1185 } 1186 1187 //Another possibility is the min limits have been raised. 1188 if( currUploadLimit<uploadLimitMin ){ 1189 newUploadLimit = uploadLimitMin; 1190 uploadChanged = true; 1191 1192 reason.append(" (c) min upload limit raised. "); 1193 } 1194 1195 if( currDownloadLimit<downloadLimitMin ){ 1196 newDownloadLimit = downloadLimitMin; 1197 downloadChanged = true; 1198 1199 reason.append(" (d) min download limit raised. "); 1200 } 1201 1202 SpeedManagerLogger.trace("Adjusting limits due to out of spec: new-up="+newUploadLimit 1203 +" new-down="+newDownloadLimit+" reasons: "+reason.toString()); 1204 1205 return new SMUpdate(newUploadLimit,uploadChanged,newDownloadLimit,downloadChanged); 1206 } 1207 1208 log(String str)1209 protected void log(String str){ 1210 1211 SpeedManagerLogger.log(str); 1212 }//log 1213 1214 1215 initPingSpaceMap(int maxGoodPing, int minBadPing)1216 public void initPingSpaceMap(int maxGoodPing, int minBadPing){ 1217 pingMapOfDownloadMode = new PingSpaceMapper(maxGoodPing,minBadPing); 1218 pingMapOfSeedingMode = new PingSpaceMapper(maxGoodPing,minBadPing); 1219 1220 //pingMonitor = new PingSpaceMonitor(maxGoodPing,minBadPing,transferMode); 1221 1222 useVariancePingMap = false; 1223 } 1224 initPingSpaceMap()1225 public void initPingSpaceMap(){ 1226 useVariancePingMap = true; 1227 1228 1229 //ToDo: remove after beta-testing - just to characterize the different methods. 1230 // pingMapOfDownloadMode = new PingSpaceMapper(150,500); 1231 // pingMapOfSeedingMode = new PingSpaceMapper(150,500); 1232 1233 } 1234 1235 /** 1236 * This is a lot of data, but is important debug info. 1237 * @param name - 1238 * @param transEst - 1239 * @param hadChockPing - 1240 * @param permEst - 1241 * @param downMode - 1242 * @param seedMode - 1243 */ betaLogPingMapperEstimates(String name, SpeedManagerLimitEstimate transEst, boolean hadChockPing, SpeedManagerLimitEstimate permEst, PingSpaceMapper downMode, PingSpaceMapper seedMode)1244 public void betaLogPingMapperEstimates(String name, 1245 SpeedManagerLimitEstimate transEst, 1246 boolean hadChockPing, 1247 SpeedManagerLimitEstimate permEst, 1248 PingSpaceMapper downMode, 1249 PingSpaceMapper seedMode) 1250 { 1251 StringBuffer sb = new StringBuffer("beta-ping-maps-").append(name).append(": "); 1252 1253 if(transEst!=null){ 1254 int rate = transEst.getBytesPerSec(); 1255 float conf = transEst.getMetricRating(); 1256 sb.append("transient-").append(rate).append("(").append(conf).append(")"); 1257 } 1258 sb.append(" chockPing=").append(hadChockPing); 1259 1260 1261 if(permEst!=null){ 1262 int rate = permEst.getBytesPerSec(); 1263 float conf = permEst.getMetricRating(); 1264 sb.append("; perm-").append(rate).append("(").append(conf).append(")"); 1265 } 1266 1267 if(downMode!=null){ 1268 int rateDown = downMode.guessDownloadLimit(); 1269 int rateUp = downMode.guessUploadLimit(); 1270 boolean downChockPing = downMode.hadChockingPing(true); 1271 boolean upChockPing = downMode.hadChockingPing(false); 1272 1273 sb.append("; downMode- "); 1274 sb.append("rateDown=").append(rateDown).append(" "); 1275 sb.append("rateUp=").append(rateUp).append(" "); 1276 sb.append("downChockPing=").append(downChockPing).append(" "); 1277 sb.append("upChockPing=").append(upChockPing).append(" "); 1278 } 1279 1280 if(seedMode!=null){ 1281 int rateDown = seedMode.guessDownloadLimit(); 1282 int rateUp = seedMode.guessUploadLimit(); 1283 boolean downChockPing = seedMode.hadChockingPing(true); 1284 boolean upChockPing = seedMode.hadChockingPing(false); 1285 1286 sb.append("; seedMode- "); 1287 sb.append("rateDown=").append(rateDown).append(" "); 1288 sb.append("rateUp=").append(rateUp).append(" "); 1289 sb.append("downChockPing=").append(downChockPing).append(" "); 1290 sb.append("upChockPing=").append(upChockPing).append(" "); 1291 } 1292 SpeedManagerLogger.log( sb.toString() ); 1293 }//betaLogPingMapperEstimates 1294 guessDownloadLimit()1295 public int guessDownloadLimit(){ 1296 1297 if( !useVariancePingMap){ 1298 return pingMapOfDownloadMode.guessDownloadLimit(); 1299 }else{ 1300 1301 boolean wasChocked=true; 1302 SpeedManagerLimitEstimate transientEst=null; 1303 if(transientPingMap!=null){ 1304 transientEst = transientPingMap.getLastBadDownloadLimit(); 1305 if(transientEst==null){ 1306 wasChocked=false; 1307 transientEst = transientPingMap.getEstimatedDownloadLimit(false); 1308 } 1309 } 1310 1311 //NOTE: Currently just getting the persistentMap for temp logging purposes. 1312 SMInstance pm = SMInstance.getInstance(); 1313 SpeedManagerAlgorithmProviderAdapter adapter = pm.getAdapter(); 1314 SpeedManagerPingMapper persistentMap = adapter.getPingMapper(); 1315 SpeedManagerLimitEstimate persistentEst = persistentMap.getEstimatedDownloadLimit(false); 1316 1317 //log the different ping-mappers for beta. 1318 betaLogPingMapperEstimates("down",transientEst,wasChocked,persistentEst,pingMapOfDownloadMode,pingMapOfSeedingMode); 1319 1320 if( transientEst!=null ) 1321 { 1322 return choseBestLimit(transientEst,downloadLimitMax,downloadLimitConf); 1323 }else{ 1324 return downloadLimitMax; 1325 } 1326 1327 } 1328 }//guessDownloadLimit 1329 guessUploadLimit()1330 public int guessUploadLimit(){ 1331 1332 if( !useVariancePingMap){ 1333 1334 int dmUpLimitGuess = pingMapOfDownloadMode.guessUploadLimit(); 1335 int smUpLimitGuess = pingMapOfSeedingMode.guessUploadLimit(); 1336 1337 return Math.max(dmUpLimitGuess,smUpLimitGuess); 1338 1339 }else{ 1340 1341 boolean wasChocked=true; 1342 SpeedManagerLimitEstimate transientEst=null; 1343 if(transientPingMap!=null){ 1344 transientEst = transientPingMap.getLastBadUploadLimit(); 1345 if(transientEst==null){ 1346 wasChocked=false; 1347 transientEst = transientPingMap.getEstimatedUploadLimit(false); 1348 } 1349 } 1350 1351 //NOTE: Currently just getting the persistentMap for temp logging purposes. 1352 SMInstance pm = SMInstance.getInstance(); 1353 SpeedManagerAlgorithmProviderAdapter adapter = pm.getAdapter(); 1354 SpeedManagerPingMapper persistentMap = adapter.getPingMapper(); 1355 SpeedManagerLimitEstimate persistentEst = persistentMap.getEstimatedUploadLimit(false); 1356 1357 //log the different ping-mappers for beta. 1358 betaLogPingMapperEstimates("up",transientEst,wasChocked,persistentEst,pingMapOfDownloadMode,pingMapOfSeedingMode); 1359 1360 if( transientEst!=null ) 1361 { 1362 return choseBestLimit(transientEst,uploadLimitMax,uploadLimitConf); 1363 }else{ 1364 return uploadLimitMax; 1365 } 1366 } 1367 1368 }//guessUploadLimit 1369 1370 1371 /** 1372 * Should return true if had a recent chocking ping. 1373 * @return - true if 1374 */ hadChockingPing()1375 public boolean hadChockingPing(){ 1376 if( !useVariancePingMap){ 1377 1378 return pingMapOfDownloadMode.hadChockingPing(true); 1379 1380 }else{ 1381 SpeedManagerPingMapper pm = SMInstance.getInstance().getAdapter().getPingMapper(); 1382 1383 //if either had a choking ping. 1384 SpeedManagerLimitEstimate dEst = pm.getEstimatedDownloadLimit(true); 1385 SpeedManagerLimitEstimate uEst = pm.getEstimatedUploadLimit(true); 1386 1387 boolean hadChokePingUp = (uEst.getEstimateType()==SpeedManagerLimitEstimate.TYPE_CHOKE_ESTIMATED); 1388 boolean hadChokePingDown = (dEst.getEstimateType()==SpeedManagerLimitEstimate.TYPE_CHOKE_ESTIMATED); 1389 1390 return ( hadChokePingUp || hadChokePingDown ); 1391 } 1392 }//hadChockingPing 1393 1394 /** 1395 * Just log this data until we decide if it is useful. 1396 */ logPingMapData()1397 public void logPingMapData() { 1398 1399 if( !useVariancePingMap){ 1400 int downLimGuess = pingMapOfDownloadMode.guessDownloadLimit(); 1401 int upLimGuess = pingMapOfDownloadMode.guessUploadLimit(); 1402 int seedingUpLimGuess = pingMapOfSeedingMode.guessUploadLimit(); 1403 1404 StringBuffer sb = new StringBuffer("ping-map: "); 1405 sb.append(":down=").append(downLimGuess); 1406 sb.append(":up=").append(upLimGuess); 1407 sb.append(":(seed)up=").append(seedingUpLimGuess); 1408 1409 SpeedManagerLogger.log( sb.toString() ); 1410 }else{ 1411 SMInstance pm = SMInstance.getInstance(); 1412 SpeedManagerAlgorithmProviderAdapter adapter = pm.getAdapter(); 1413 SpeedManagerPingMapper persistentMap = adapter.getPingMapper(); 1414 1415 SpeedManagerLimitEstimate estUp = persistentMap.getEstimatedUploadLimit(false); 1416 SpeedManagerLimitEstimate estDown = persistentMap.getEstimatedDownloadLimit(false); 1417 1418 int downLimGuess = estDown.getBytesPerSec(); 1419 float downConf = estDown.getMetricRating(); 1420 int upLimGuess = estUp.getBytesPerSec(); 1421 float upConf = estUp.getMetricRating(); 1422 1423 String name = persistentMap.getName(); 1424 1425 StringBuffer sb = new StringBuffer("new-ping-map: "); 1426 sb.append(" name=").append(name); 1427 sb.append(", down=").append(downLimGuess); 1428 sb.append(", down-conf=").append(downConf); 1429 sb.append(", up=").append(upLimGuess); 1430 sb.append(", up-conf=").append(upConf); 1431 1432 SpeedManagerLogger.log( sb.toString() ); 1433 } 1434 }//logPingMapData 1435 setCurrentTransferRates(int downRate, int upRate)1436 public void setCurrentTransferRates(int downRate, int upRate){ 1437 1438 if( pingMapOfDownloadMode!=null && pingMapOfSeedingMode!=null){ 1439 pingMapOfDownloadMode.setCurrentTransferRates(downRate,upRate); 1440 pingMapOfSeedingMode.setCurrentTransferRates(downRate,upRate); 1441 } 1442 1443 } 1444 resetPingSpace()1445 public void resetPingSpace(){ 1446 1447 if( pingMapOfDownloadMode!=null && pingMapOfSeedingMode!=null){ 1448 pingMapOfDownloadMode.reset(); 1449 pingMapOfSeedingMode.reset(); 1450 } 1451 1452 if(transientPingMap!=null){ 1453 transientPingMap.destroy(); 1454 } 1455 } 1456 addToPingMapData(int lastMetricValue)1457 public void addToPingMapData(int lastMetricValue){ 1458 String modeStr = getTransferModeAsString(); 1459 1460 if( modeStr.equalsIgnoreCase(TransferMode.State.DOWNLOADING.getString()) 1461 || modeStr.equalsIgnoreCase(TransferMode.State.DOWNLOAD_LIMIT_SEARCH.getString()) ) 1462 { 1463 //add point to map for download mode 1464 pingMapOfDownloadMode.addMetricToMap(lastMetricValue); 1465 1466 } 1467 else if( modeStr.equalsIgnoreCase(TransferMode.State.SEEDING.getString()) 1468 || modeStr.equalsIgnoreCase(TransferMode.State.UPLOAD_LIMIT_SEARCH.getString()) ) 1469 { 1470 //add point to map for seeding mode. 1471 pingMapOfSeedingMode.addMetricToMap(lastMetricValue); 1472 1473 } 1474 1475 1476 //if confidence limit testing, inform of bad ping. 1477 updateLimitTestingPing(lastMetricValue); 1478 1479 longTermMonitor.updateStatus(transferMode); 1480 1481 }//addToPingMapData 1482 1483 notifyUpload(SpeedManagerLimitEstimate estimate)1484 public void notifyUpload(SpeedManagerLimitEstimate estimate) { 1485 int bestLimit = choseBestLimit(estimate,uploadLimitMax,uploadLimitConf); 1486 1487 SpeedManagerLogger.trace("notifyUpload uploadLimitMax="+uploadLimitMax); 1488 tempLogEstimate(estimate); 1489 1490 if(bestLimit!=uploadLimitMax){ 1491 //update COConfiguration 1492 SpeedManagerLogger.log("persistent PingMap changed upload limit to "+bestLimit); 1493 1494 resetPinSearch(estimate); 1495 1496 uploadLimitMax = bestLimit; 1497 COConfigurationManager.setParameter( 1498 SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT, uploadLimitMax); 1499 } 1500 1501 uploadLimitMin = SMConst.calculateMinUpload(uploadLimitMax); 1502 slider.updateLimits(uploadLimitMax,uploadLimitMin,downloadLimitMax,downloadLimitMin); 1503 1504 SMSearchLogger.log("new upload rate: "+uploadLimitMax); 1505 } 1506 notifyDownload(SpeedManagerLimitEstimate estimate)1507 public void notifyDownload(SpeedManagerLimitEstimate estimate) { 1508 int bestLimit = choseBestLimit(estimate,downloadLimitMax,downloadLimitConf); 1509 1510 SpeedManagerLogger.trace("notifyDownload downloadLimitMax="+downloadLimitMax 1511 +" conf="+downloadLimitConf.getString()+" ("+downloadLimitConf.asEstimateType()+")"); 1512 tempLogEstimate(estimate); 1513 1514 if(downloadLimitMax!=bestLimit){ 1515 //update COConfiguration 1516 SpeedManagerLogger.log( "persistent PingMap changed download limit to "+bestLimit ); 1517 downloadLimitMax = bestLimit; 1518 COConfigurationManager.setParameter( 1519 SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT, bestLimit); 1520 } 1521 1522 downloadLimitMin = SMConst.calculateMinDownload(downloadLimitMax); 1523 slider.updateLimits(uploadLimitMax,uploadLimitMin,downloadLimitMax,downloadLimitMin); 1524 1525 1526 if(estimate.getBytesPerSec()!=0){ 1527 slider.setDownloadUnlimitedMode(false); 1528 }else{ 1529 slider.setDownloadUnlimitedMode(true); 1530 } 1531 1532 SMSearchLogger.log("download "+downloadLimitMax ); 1533 } 1534 tempLogEstimate(SpeedManagerLimitEstimate est)1535 private void tempLogEstimate(SpeedManagerLimitEstimate est){ 1536 1537 if(est==null){ 1538 SpeedManagerLogger.trace( "notify log: SpeedManagerLimitEstimate was null" ); 1539 return; 1540 } 1541 1542 StringBuffer sb = new StringBuffer(); 1543 float metric = est.getMetricRating(); 1544 float type = est.getEstimateType(); 1545 int rate = est.getBytesPerSec(); 1546 1547 String str = est.getString(); 1548 1549 sb.append("notify log: ").append(str); 1550 sb.append(" metricRating=").append(metric); 1551 sb.append(" rate=").append(rate); 1552 sb.append(" type=").append(type); 1553 1554 SpeedManagerLogger.trace( sb.toString() ); 1555 1556 }//tempLogEstimate 1557 1558 }//SpeedLimitMonitor 1559