/* * File : DownloadManagerStatsImpl.java * Created : 24-Oct-2003 * By : parg * * Azureus - a Java Bittorrent client * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details ( see the LICENSE file ). * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.gudy.azureus2.core3.download.impl; /** * @author parg */ import org.gudy.azureus2.core3.config.COConfigurationManager; import org.gudy.azureus2.core3.config.ParameterListener; import org.gudy.azureus2.core3.download.*; import org.gudy.azureus2.core3.peer.*; import org.gudy.azureus2.core3.torrent.TOTorrent; import org.gudy.azureus2.core3.util.Debug; import org.gudy.azureus2.core3.util.IndentWriter; import org.gudy.azureus2.core3.util.SystemTime; import org.gudy.azureus2.core3.disk.*; public class DownloadManagerStatsImpl implements DownloadManagerStats { private static int share_ratio_progress_interval; static{ COConfigurationManager.addAndFireParameterListener( "Share Ratio Progress Interval", new ParameterListener() { public void parameterChanged( String name ) { share_ratio_progress_interval = COConfigurationManager.getIntParameter( name ); } }); } private DownloadManagerImpl download_manager; //Completed (used for auto-starting purposes) private int completed; private int downloadCompleted; // saved downloaded and uploaded private long saved_data_bytes_downloaded; private long saved_protocol_bytes_downloaded; private long saved_data_bytes_uploaded; private long saved_protocol_bytes_uploaded; private long session_start_data_bytes_downloaded; private long session_start_data_bytes_uploaded; private long saved_discarded = 0; private long saved_hashfails = 0; private long saved_SecondsDownloading = 0; private long saved_SecondsOnlySeeding = 0; private int saved_SecondsSinceDownload = 0; private int saved_SecondsSinceUpload = 0; private long saved_peak_receive_rate = 0; private long saved_peak_send_rate = 0; private long saved_skipped_file_set_size; private long saved_skipped_but_downloaded; private int max_upload_rate_bps = 0; //0 for unlimited private int max_download_rate_bps = 0; //0 for unlimited private static final int HISTORY_MAX_SECS = 30*60; private volatile boolean history_retention_required; private long[] history; private int history_pos; private boolean history_wrapped; private int last_sr_progress = -1; protected DownloadManagerStatsImpl( DownloadManagerImpl dm ) { download_manager = dm; } public long getDataReceiveRate() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null){ return pm.getStats().getDataReceiveRate(); } return 0; } public long getProtocolReceiveRate() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null){ return pm.getStats().getProtocolReceiveRate(); } return 0; } public long getDataSendRate() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null){ return pm.getStats().getDataSendRate(); } return 0; } public long getProtocolSendRate() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null){ return pm.getStats().getProtocolSendRate(); } return 0; } public long getPeakDataReceiveRate() { PEPeerManager pm = download_manager.getPeerManager(); long result = saved_peak_receive_rate; if ( pm != null ){ result = Math.max( result, pm.getStats().getPeakDataReceiveRate()); } return( result ); } public long getPeakDataSendRate() { PEPeerManager pm = download_manager.getPeerManager(); long result = saved_peak_send_rate; if ( pm != null ){ result = Math.max( result, pm.getStats().getPeakDataSendRate()); } return( result ); } public long getSmoothedDataReceiveRate() { PEPeerManager pm = download_manager.getPeerManager(); if ( pm != null ){ return( pm.getStats().getSmoothedDataReceiveRate()); } return( 0 ); } public long getSmoothedDataSendRate() { PEPeerManager pm = download_manager.getPeerManager(); if ( pm != null ){ return( pm.getStats().getSmoothedDataSendRate()); } return( 0 ); } /* (non-Javadoc) * @see org.gudy.azureus2.core3.download.DownloadManagerStats#getETA() */ public long getETA() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null){ return pm.getETA( false ); } return -1; //return exactly -1 if ETA is unknown } public long getSmoothedETA() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null){ return pm.getETA( true ); } return -1; //return exactly -1 if ETA is unknown } /* (non-Javadoc) * @see org.gudy.azureus2.core3.download.DownloadManagerStats#getCompleted() */ public int getCompleted() { DiskManager dm = download_manager.getDiskManager(); if (dm == null) { int state = download_manager.getState(); if (state == DownloadManager.STATE_ALLOCATING || state == DownloadManager.STATE_CHECKING || state == DownloadManager.STATE_INITIALIZING) return completed; else return downloadCompleted; } if (dm.getState() == DiskManager.ALLOCATING || dm.getState() == DiskManager.CHECKING || dm.getState() == DiskManager.INITIALIZING) return dm.getPercentDone(); else { long total = dm.getTotalLength(); return total == 0 ? 0 : (int) ((1000 * (total - dm.getRemaining())) / total); } } public void setCompleted(int _completed) { completed = _completed; } public int getDownloadCompleted( boolean bLive ) { DiskManager dm = download_manager.getDiskManager(); // no disk manager -> not running -> use stored value if ( dm == null ){ return downloadCompleted; } int state = dm.getState(); boolean transient_state = state == DiskManager.INITIALIZING || state == DiskManager.ALLOCATING || state == DiskManager.CHECKING; long total = dm.getTotalLength(); int computed_completion = (total == 0) ? 0 : (int) ((1000 * (total - dm.getRemaining())) / total); // use non-transient values to update the record of download completion if ( !transient_state ){ downloadCompleted = computed_completion; } if ( bLive ){ // return the transient completion level return computed_completion; }else{ // return the non-transient one return( downloadCompleted ); } } public void setDownloadCompleted(int _completed) { downloadCompleted = _completed; } public String getElapsedTime() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null){ return pm.getElapsedTime(); } return ""; } public long getTimeStarted() { return( getTimeStarted( false )); } private long getTimeStarted( boolean mono ) { PEPeerManager pm = download_manager.getPeerManager(); if ( pm != null ){ return pm.getTimeStarted( mono ); } return -1; } public long getTimeStartedSeeding() { return( getTimeStartedSeeding( false )); } private long getTimeStartedSeeding( boolean mono ) { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null){ return( pm.getTimeStartedSeeding( mono )); } return -1; } public long getTotalDataBytesReceived() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null) { return saved_data_bytes_downloaded + pm.getStats().getTotalDataBytesReceived(); } return(saved_data_bytes_downloaded); } public long getSessionDataBytesReceived() { long total = getTotalDataBytesReceived(); long res = total - session_start_data_bytes_downloaded; if ( res < 0 ){ session_start_data_bytes_downloaded = total; res = 0; } return( res ); } public long getTotalGoodDataBytesReceived() { long downloaded = getTotalDataBytesReceived(); downloaded -= ( getHashFailBytes() + getDiscarded()); if ( downloaded < 0 ){ downloaded = 0; } return( downloaded ); } public long getTotalProtocolBytesReceived() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null) { return saved_protocol_bytes_downloaded + pm.getStats().getTotalProtocolBytesReceived(); } return(saved_protocol_bytes_downloaded); } public void resetTotalBytesSentReceived( long new_sent, long new_received ) { boolean running = download_manager.getPeerManager() != null; if ( running ){ download_manager.stopIt( DownloadManager.STATE_STOPPED, false, false ); } if ( new_sent >= 0 ){ saved_data_bytes_uploaded = new_sent; session_start_data_bytes_uploaded = new_sent; saved_protocol_bytes_uploaded = 0; } if ( new_received >= 0 ){ saved_data_bytes_downloaded = new_received; session_start_data_bytes_downloaded = new_received; saved_protocol_bytes_downloaded = 0; } saved_discarded = 0; saved_hashfails = 0; if ( running ){ download_manager.setStateWaiting(); } } public long getTotalDataBytesSent() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null) { return saved_data_bytes_uploaded + pm.getStats().getTotalDataBytesSent(); } return( saved_data_bytes_uploaded ); } public long getTotalProtocolBytesSent() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null) { return saved_protocol_bytes_uploaded + pm.getStats().getTotalProtocolBytesSent(); } return( saved_protocol_bytes_uploaded ); } public long getSessionDataBytesSent() { long total = getTotalDataBytesSent(); long res = total - session_start_data_bytes_uploaded; if ( res < 0 ){ session_start_data_bytes_uploaded = total; res = 0; } return( res ); } public void setRecentHistoryRetention( boolean required ) { synchronized( this ){ if ( required ){ if ( !history_retention_required ){ history = new long[HISTORY_MAX_SECS]; history_pos = 0; history_retention_required = true; } }else{ history = null; history_retention_required = false; } } } private static final int HISTORY_DIV = 64; public int[][] getRecentHistory() { synchronized( this ){ if ( history == null ){ return( new int[3][0] ); }else{ int entries = history_wrapped?HISTORY_MAX_SECS:history_pos; int start = history_wrapped?history_pos:0; int[][] result = new int[3][entries]; int pos = start; for ( int i=0;i<entries;i++){ if ( pos == HISTORY_MAX_SECS ){ pos = 0; } long entry = history[pos++]; int send_rate = (int)((entry>>42)&0x001fffffL); int recv_rate = (int)((entry>>21)&0x001fffffL); int swarm_rate = (int)((entry)&0x001fffffL); result[0][i] = send_rate*HISTORY_DIV; result[1][i] = recv_rate*HISTORY_DIV; result[2][i] = swarm_rate*HISTORY_DIV; } return( result ); } } } protected void timerTick( int tick_count ) { if ( tick_count % 15 == 0 ){ if ( last_sr_progress == -1 ){ long temp = download_manager.getDownloadState().getLongAttribute( DownloadManagerState.AT_SHARE_RATIO_PROGRESS ); last_sr_progress = (int)temp; } if ( share_ratio_progress_interval <= 0 ){ // reset if ( last_sr_progress != 0 ){ last_sr_progress = 0; download_manager.getDownloadState().setLongAttribute( DownloadManagerState.AT_SHARE_RATIO_PROGRESS, 0 ); } }else{ int current_sr = getShareRatio(); current_sr = ( current_sr / share_ratio_progress_interval) * share_ratio_progress_interval; if ( current_sr != last_sr_progress ){ last_sr_progress = current_sr; long data = ((SystemTime.getCurrentTime()/1000)<<32) + last_sr_progress; download_manager.getDownloadState().setLongAttribute( DownloadManagerState.AT_SHARE_RATIO_PROGRESS, data ); } } } if ( !history_retention_required ){ return; } PEPeerManager pm = download_manager.getPeerManager(); if ( pm == null ){ return; } PEPeerManagerStats stats = pm.getStats(); long send_rate = stats.getDataSendRate() + stats.getProtocolSendRate(); long receive_rate = stats.getDataReceiveRate() + stats.getProtocolReceiveRate(); long peer_swarm_average = getTotalAveragePerPeer(); long entry = ((((send_rate-1+HISTORY_DIV/2)/HISTORY_DIV)<<42) & 0x7ffffc0000000000L ) | ((((receive_rate-1+HISTORY_DIV/2)/HISTORY_DIV)<<21) & 0x000003ffffe00000L ) | ((((peer_swarm_average-1+HISTORY_DIV/2)/HISTORY_DIV))& 0x00000000001fffffL ); synchronized( this ){ if ( history != null ){ history[history_pos++] = entry; if ( history_pos == HISTORY_MAX_SECS ){ history_pos = 0; history_wrapped = true; } } } } public long getRemaining() { DiskManager disk_manager = download_manager.getDiskManager(); if ( disk_manager == null ){ return download_manager.getSize() - ((long)getDownloadCompleted(false) * download_manager.getSize() / 1000L); }else{ return disk_manager.getRemainingExcludingDND(); } } public long getDiscarded() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null){ return saved_discarded + pm.getStats().getTotalDiscarded(); } return( saved_discarded ); } public long getHashFailCount() { TOTorrent t = download_manager.getTorrent(); if ( t == null ){ return(0); } long total = getHashFailBytes(); long res = total / t.getPieceLength(); if ( res == 0 && total > 0 ){ res = 1; } return( res ); } public long getHashFailBytes() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null){ return saved_hashfails + pm.getStats().getTotalHashFailBytes(); } return( saved_hashfails ); } public long getTotalAverage() { PEPeerManager pm = download_manager.getPeerManager(); if (pm != null){ return pm.getStats().getTotalAverage(); } return( 0 ); } public long getTotalAveragePerPeer() { int div = download_manager.getNbPeers() + (download_manager.isDownloadComplete(false) ? 0 : 1); //since total speed includes our own speed when downloading long average = div < 1 ? 0 : getTotalAverage() / div; return( average ); } public int getShareRatio() { long downloaded = getTotalGoodDataBytesReceived(); long uploaded = getTotalDataBytesSent(); if ( downloaded <= 0 ){ return( -1 ); } return (int) ((1000 * uploaded) / downloaded); } public long getSecondsDownloading() { long lTimeStartedDL = getTimeStarted( true ); if (lTimeStartedDL >= 0) { long lTimeEndedDL = getTimeStartedSeeding( true ); if (lTimeEndedDL == -1) { lTimeEndedDL = SystemTime.getMonotonousTime(); } if (lTimeEndedDL > lTimeStartedDL) { return saved_SecondsDownloading + ((lTimeEndedDL - lTimeStartedDL) / 1000); } } return saved_SecondsDownloading; } public long getSecondsOnlySeeding() { long lTimeStarted = getTimeStartedSeeding( true ); if (lTimeStarted >= 0) { return saved_SecondsOnlySeeding + ((SystemTime.getMonotonousTime() - lTimeStarted) / 1000); } return saved_SecondsOnlySeeding; } public float getAvailability() { PEPeerManager pm = download_manager.getPeerManager(); if ( pm == null ){ return( -1 ); } return( pm.getMinAvailability()); } public long getBytesUnavailable() { PEPeerManager pm = download_manager.getPeerManager(); if ( pm == null ){ return( -1 ); } return( pm.getBytesUnavailable()); } public int getUploadRateLimitBytesPerSecond() { return max_upload_rate_bps; } public void setUploadRateLimitBytesPerSecond( int max_rate_bps ) { max_upload_rate_bps = max_rate_bps; } public int getDownloadRateLimitBytesPerSecond() { return max_download_rate_bps; } public void setDownloadRateLimitBytesPerSecond( int max_rate_bps ) { max_download_rate_bps = max_rate_bps; } public int getTimeSinceLastDataReceivedInSeconds() { PEPeerManager pm = download_manager.getPeerManager(); int res = saved_SecondsSinceDownload; if ( pm != null ){ int current = pm.getStats().getTimeSinceLastDataReceivedInSeconds(); if ( current >= 0 ){ // activity this session, use this value res = current; }else{ // no activity this session. If ever has been activity add in session // time if ( res >= 0 ){ long now = SystemTime.getCurrentTime(); long elapsed = now - pm.getTimeStarted( false ); if ( elapsed < 0 ){ elapsed = 0; } res += elapsed/1000; } } } return( res ); } public int getTimeSinceLastDataSentInSeconds() { PEPeerManager pm = download_manager.getPeerManager(); int res = saved_SecondsSinceUpload; if ( pm != null ){ int current = pm.getStats().getTimeSinceLastDataSentInSeconds(); if ( current >= 0 ){ // activity this session, use this value res = current; }else{ // no activity this session. If ever has been activity add in session // time if ( res >= 0 ){ long now = SystemTime.getCurrentTime(); long elapsed = now - pm.getTimeStarted( false ); if ( elapsed < 0 ){ elapsed = 0; } res += elapsed/1000; } } } return( res ); } public long getAvailWentBadTime() { PEPeerManager pm = download_manager.getPeerManager(); if ( pm != null ){ long bad_time = pm.getAvailWentBadTime(); if ( bad_time > 0 ){ // valid last bad time return( bad_time ); } if ( pm.getMinAvailability() >= 1.0 ){ // we can believe the fact that it isn't bad (we want to ignore 0 results from // downloads that never get to a 1.0 availbility) return( 0 ); } } DownloadManagerState state = download_manager.getDownloadState(); return( state.getLongAttribute( DownloadManagerState.AT_AVAIL_BAD_TIME )); } protected void saveSessionTotals() { // re-base the totals from current totals and session totals saved_data_bytes_downloaded = getTotalDataBytesReceived(); saved_data_bytes_uploaded = getTotalDataBytesSent(); saved_protocol_bytes_downloaded = getTotalProtocolBytesReceived(); saved_protocol_bytes_uploaded = getTotalProtocolBytesSent(); saved_discarded = getDiscarded(); saved_hashfails = getHashFailBytes(); saved_SecondsDownloading = getSecondsDownloading(); saved_SecondsOnlySeeding = getSecondsOnlySeeding(); saved_SecondsSinceDownload = getTimeSinceLastDataReceivedInSeconds(); saved_SecondsSinceUpload = getTimeSinceLastDataSentInSeconds(); saved_peak_receive_rate = getPeakDataReceiveRate(); saved_peak_send_rate = getPeakDataSendRate(); DownloadManagerState state = download_manager.getDownloadState(); state.setIntAttribute( DownloadManagerState.AT_TIME_SINCE_DOWNLOAD, saved_SecondsSinceDownload ); state.setIntAttribute( DownloadManagerState.AT_TIME_SINCE_UPLOAD, saved_SecondsSinceUpload ); state.setLongAttribute( DownloadManagerState.AT_AVAIL_BAD_TIME, getAvailWentBadTime()); state.setLongAttribute( DownloadManagerState.AT_PEAK_RECEIVE_RATE, saved_peak_receive_rate ); state.setLongAttribute( DownloadManagerState.AT_PEAK_SEND_RATE, saved_peak_send_rate ); } protected void setSavedDownloadedUploaded( long d, long u ) { saved_data_bytes_downloaded = d; saved_data_bytes_uploaded = u; } public void restoreSessionTotals( long _saved_data_bytes_downloaded, long _saved_data_bytes_uploaded, long _saved_discarded, long _saved_hashfails, long _saved_SecondsDownloading, long _saved_SecondsOnlySeeding ) { saved_data_bytes_downloaded = _saved_data_bytes_downloaded; saved_data_bytes_uploaded = _saved_data_bytes_uploaded; saved_discarded = _saved_discarded; saved_hashfails = _saved_hashfails; saved_SecondsDownloading = _saved_SecondsDownloading; saved_SecondsOnlySeeding = _saved_SecondsOnlySeeding; session_start_data_bytes_downloaded = saved_data_bytes_downloaded; session_start_data_bytes_uploaded = _saved_data_bytes_uploaded; DownloadManagerState state = download_manager.getDownloadState(); saved_SecondsSinceDownload = state.getIntAttribute( DownloadManagerState.AT_TIME_SINCE_DOWNLOAD ); saved_SecondsSinceUpload = state.getIntAttribute( DownloadManagerState.AT_TIME_SINCE_UPLOAD ); saved_peak_receive_rate = state.getLongAttribute( DownloadManagerState.AT_PEAK_RECEIVE_RATE ); saved_peak_send_rate = state.getLongAttribute( DownloadManagerState.AT_PEAK_SEND_RATE ); } public void setSkippedFileStats( long skipped_file_set_size, long skipped_but_downloaded ) { this.saved_skipped_file_set_size = skipped_file_set_size; this.saved_skipped_but_downloaded = skipped_but_downloaded; } public long getRemainingExcludingDND() { DiskManager dm = download_manager.getDiskManager(); if (dm != null) { return dm.getRemainingExcludingDND(); } long remaining = getRemaining(); long rem = ( remaining - ( saved_skipped_file_set_size - saved_skipped_but_downloaded )); if ( rem < 0 ){ rem = 0; } return( rem ); } public long getSizeExcludingDND() { DiskManager dm = download_manager.getDiskManager(); if (dm != null) { return dm.getSizeExcludingDND(); } long totalLength = download_manager.getSize(); return totalLength - saved_skipped_file_set_size; } public int getPercentDoneExcludingDND() { long sizeExcludingDND = getSizeExcludingDND(); if (sizeExcludingDND <= 0) { return 0; } float pct = (sizeExcludingDND - getRemainingExcludingDND()) / (float) sizeExcludingDND; return (int) (1000 * pct); } protected void generateEvidence( IndentWriter writer) { writer.println( "DownloadManagerStats" ); try{ writer.indent(); writer.println( "recv_d=" + getTotalDataBytesReceived() + ",recv_p=" + getTotalProtocolBytesReceived() + ",recv_g=" + getTotalGoodDataBytesReceived() + ",sent_d=" + getTotalDataBytesSent() + ",sent_p=" + getTotalProtocolBytesSent() + ",discard=" + getDiscarded() + ",hash_fails=" + getHashFailCount() + "/" + getHashFailBytes() + ",comp=" + getCompleted() + "[live:" + getDownloadCompleted(true) + "/" + getDownloadCompleted( false) + "],dl_comp=" + downloadCompleted + ",remaining=" + getRemaining()); writer.println( "down_lim=" + getDownloadRateLimitBytesPerSecond() + ",up_lim=" + getUploadRateLimitBytesPerSecond()); }finally{ writer.exdent(); } } }