📄 rate.cpp
字号:
#include "rate.h" // def.h#include <sys/time.h>#include "btconfig.h"#include "bufio.h" // for BUF_DEF_SIZ#include "bttime.h"#include "console.h"#ifndef HAVE_CLOCK_GETTIME#include "compat.h"#endif#define RATE_INTERVAL 20#define SHORT_INTERVAL 5Rate::Rate(){ m_last_timestamp = m_total_timeused = m_nom_time = (time_t)0; m_count_bytes = 0; m_history = m_history_last = (BWSAMPLE *)0; m_last_realtime = m_recent_realtime = m_prev_realtime = 0; m_last_size = m_recent_size = m_prev_size = 0; m_selfrate = (Rate *)0; m_late = 0; m_ontime = m_update_nominal = 0; m_lastrate.lasttime = (time_t)0; m_nominal = DEFAULT_SLICE_SIZE / 8; // minimum "acceptable" rate}void Rate::Reset(){ m_last_timestamp = m_total_timeused = (time_t)0; ClearHistory(); m_last_realtime = 0; m_last_size = 0;}void Rate::StartTimer(){ if( !m_last_timestamp ) m_last_timestamp = now;}void Rate::StopTimer(){ if( m_last_timestamp ){ m_total_timeused += (now - m_last_timestamp); if( m_history ){ if( m_history == m_history_last ) m_nominal = (size_t)(m_history->bytes / (m_history->timestamp - m_last_timestamp)); else (void)RateMeasure(); // updates nominal } m_last_timestamp = 0; ClearHistory(); } m_update_nominal = 0;}BWSAMPLE *Rate::NewSample(){ BWSAMPLE *sample = new BWSAMPLE; if( sample ){ sample->timestamp = 0; sample->bytes = 0; sample->next = (BWSAMPLE *)0; }else CONSOLE.Warning(2, "warn, failed to allocate memory for bandwidth sample."); return sample;}void Rate::ClearHistory(){ if( m_history ){ BWSAMPLE *pnext; for( BWSAMPLE *p=m_history; p; p=pnext ){ pnext = p->next; delete p; } m_history = m_history_last = (BWSAMPLE *)0; }}void Rate::Cleanup(){ BWSAMPLE *p = m_history; while( p && RATE_INTERVAL <= now - (time_t)(p->timestamp) ){ int nzero = 0; if( !p->next ){ if( BWSAMPLE *q = NewSample() ){ q->timestamp = (double)now - 1; p->next = q; m_history_last = q; nzero++; }else{ p->bytes = p->bytes * RATE_INTERVAL / (now - (time_t)(p->timestamp)); p->timestamp = (double)(now - RATE_INTERVAL + 1); } } if( p->next ){ if( RATE_INTERVAL > now - (time_t)(p->next->timestamp) ){ time_t reftime = nzero ? now : (time_t)(p->next->timestamp); while( (time_t)(p->next->timestamp) > (time_t)(p->timestamp) + 1 ){ // fill holes if( BWSAMPLE *q = NewSample() ){ q->timestamp = (double)((time_t)(p->next->timestamp) - 1); q->next = p->next; p->next = q; nzero++; }else break; } if( nzero ){ size_t bytes = (size_t)( p->bytes / (reftime - p->timestamp) ); BWSAMPLE *q = p->next; for( ; nzero; nzero-- ){ q->bytes += bytes; // distribute over the following empty samples q = q->next; } } } m_history = p->next; delete p; p = m_history; } }}void Rate::CountAdd(size_t nbytes){ m_count_bytes += nbytes; if( m_selfrate ) m_selfrate->CountAdd(nbytes);}void Rate::UnCount(size_t nbytes){ m_count_bytes -= nbytes; if( m_selfrate ) m_selfrate->UnCount(nbytes);}void Rate::RateAdd(size_t nbytes, size_t bwlimit){ struct timespec nowspec; clock_gettime(CLOCK_REALTIME, &nowspec); RateAdd(nbytes, bwlimit, nowspec.tv_sec + (double)(nowspec.tv_nsec)/1000000000);}void Rate::RateAdd(size_t nbytes, size_t bwlimit, double timestamp){ int update_nominal = 0; if( m_history_last && timestamp < m_history_last->timestamp ){ // time went backward ClearHistory(); }else Cleanup(); if( timestamp <= m_last_realtime ){ // time went backward m_ontime = 0; m_last_size = 0; m_last_realtime = 0; } if( m_history_last && (time_t)timestamp == (time_t)(m_history_last->timestamp) ) m_history_last->bytes += nbytes; else{ if( BWSAMPLE *p = NewSample() ){ p->timestamp = timestamp; p->bytes = nbytes; if( m_history_last ){ m_history_last->next = p; update_nominal = 1; } else m_history = p; m_history_last = p; } } if( !m_selfrate && m_ontime ){ double late=timestamp - (m_last_realtime + (double)m_last_size / bwlimit);// double tmplate = late; // keep the change under control in case the system gets weird on us if( late < 0 ) late /= 2; else if( m_late && late > m_late ) late = m_late / 2; m_late += late;// CONSOLE.Debug("%p late %f->%f: %f", this, tmplate, late, m_late); m_ontime = 0; } if( m_selfrate && bwlimit && m_last_realtime && m_selfrate->LastSize() / (timestamp - m_selfrate->LastRealtime()) > bwlimit ) m_last_size += nbytes; else if( !m_selfrate && bwlimit && m_last_realtime && m_last_size / (timestamp - m_last_realtime) > bwlimit ) m_last_size += nbytes; else{ m_last_realtime = timestamp; m_last_size = nbytes; } if( nbytes > BUF_DEF_SIZ ){ m_prev_realtime = m_recent_realtime; m_prev_size = m_recent_size; m_recent_realtime = timestamp; m_recent_size = nbytes; }else m_recent_size += nbytes; if( m_selfrate ){ if( update_nominal ){ m_update_nominal = 1; (void)RateMeasure(); // updates nominal } m_selfrate->RateAdd(nbytes, bwlimit, timestamp); }//if(!m_selfrate) CONSOLE.Debug("%p RateAdd %u @ %f next=%f", this,// nbytes, timestamp, m_last_realtime + (double)m_last_size / bwlimit);}void Rate::operator=(const Rate &ra){ m_last_timestamp = now; m_count_bytes = ra.m_count_bytes;}size_t Rate::CurrentRate(){ // We can't make up for past slowness by overloading the line now/future. // Look at only the most recent data sent/received. if( !m_last_timestamp || !m_history ) return 0; // no current rate struct timespec timestamp; clock_gettime(CLOCK_REALTIME, ×tamp); double timeused = timestamp.tv_sec + (double)(timestamp.tv_nsec)/1000000000 - m_last_realtime; if( timeused <= 0 ) return 0; return (size_t)( m_last_size / timeused );}size_t Rate::NominalRate(){ if( !m_history && m_last_timestamp && TimeUsed() > 10 ){ // sent a request over 10 sec ago but have received nothing if( !m_nom_time || now >= m_nom_time + 10 ){ m_nominal /= 10; m_nom_time = now; } } return m_nominal;}size_t Rate::RateMeasure(){ // calculate rate based on bandwidth history data time_t timestamp = now; unsigned long countbytes = 0; double timeused = 0; BWSAMPLE *p; if( m_history && now == m_lastrate.lasttime && m_recent_realtime == m_lastrate.recent ){ if( m_update_nominal ) m_nominal = m_lastrate.value; return m_lastrate.value; } m_lastrate.lasttime = now; if( !m_last_timestamp || !m_history ){ m_lastrate.value = 0; return 0; // no current rate } Cleanup(); for( p=m_history; p; p=p->next ){ countbytes += p->bytes; } timeused = (double)(now - (time_t)(m_history->timestamp)); if( timeused == 0 ) timeused = 1; else if( timeused < 0 ) ClearHistory(); // time went backward else m_update_nominal = 1; if( now < (time_t)m_recent_realtime ){ if( m_history ){ m_recent_realtime = (double)now; m_prev_realtime = (double)(now - 1); m_recent_size = m_prev_size = 0; }else{ m_recent_realtime = m_prev_realtime = 0; m_recent_size = m_prev_size = 0; } } if( !m_history ){ m_lastrate.value = 0; return 0; } // Don't let the most recent addition inflate the rate measurement. if( now == (time_t)m_recent_realtime ){ // don't count the most recent addition countbytes -= m_recent_size; timeused = m_recent_realtime - m_history->timestamp; }else if( m_recent_realtime && RATE_INTERVAL > now - (time_t)m_recent_realtime && m_recent_size / (now - (time_t)m_recent_realtime) > m_prev_size / (m_recent_realtime - m_prev_realtime) ){ // "tone down" the most recent to match the previous addition's rate countbytes -= m_recent_size; countbytes += (unsigned long)( m_prev_size / (m_recent_realtime - m_prev_realtime) * (now - (time_t)m_recent_realtime) ); } m_lastrate.value = (size_t)(countbytes / timeused); m_lastrate.recent = m_recent_realtime; if( m_update_nominal ) m_nominal = m_lastrate.value; return m_lastrate.value;}size_t Rate::RateMeasure(const Rate &ra_to){ time_t timeused = TimeUsed(); int tmp = ra_to.m_count_bytes - m_count_bytes; return (size_t)( (tmp>0) ? (tmp/(timeused ? timeused : 1)) : 0 );}time_t Rate::TimeUsed(){ if( now < m_last_timestamp ) m_last_timestamp = now; return now - m_last_timestamp;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -