Measure actual echo timeout instead of network timeout to first hop

This commit is contained in:
Keith Winstein
2011-10-13 05:14:19 -04:00
parent 1f23219047
commit 460d4303c2
4 changed files with 50 additions and 14 deletions
-2
View File
@@ -77,8 +77,6 @@ namespace Network {
int fd( void ) { return connection.fd(); } int fd( void ) { return connection.fd(); }
void set_verbose( void ) { sender.set_verbose(); verbose = true; } void set_verbose( void ) { sender.set_verbose(); verbose = true; }
uint64_t timeout( void ) { return connection.timeout(); }
}; };
} }
+1 -2
View File
@@ -164,8 +164,7 @@ bool STMClient::process_user_input( int fd )
for ( int i = 0; i < bytes_read; i++ ) { for ( int i = 0; i < bytes_read; i++ ) {
char the_byte = buf[ i ]; char the_byte = buf[ i ];
overlays.get_prediction_engine().new_user_byte( the_byte, *local_framebuffer, overlays.get_prediction_engine().new_user_byte( the_byte, *local_framebuffer );
network->timeout() );
if ( quit_sequence_started ) { if ( quit_sequence_started ) {
if ( the_byte == '.' ) { /* Quit sequence is Ctrl-^ . */ if ( the_byte == '.' ) { /* Quit sequence is Ctrl-^ . */
+37 -5
View File
@@ -92,10 +92,29 @@ void OverlayEngine::apply( Framebuffer &fb ) const
[&fb]( OverlayElement *x ) { x->apply( fb ); } ); [&fb]( OverlayElement *x ) { x->apply( fb ); } );
} }
void OverlayEngine::cull( const Framebuffer &fb ) void PredictionEngine::cull( const Framebuffer &fb )
{ {
uint64_t now = timestamp();
auto i = elements.begin(); auto i = elements.begin();
while ( i != elements.end() ) { while ( i != elements.end() ) {
/* update echo timeout state */
if ( (*i)->get_validity( fb ) == Correct ) {
double R = now - (*i)->prediction_time;
if ( !RTT_hit ) { /* first measurement */
SRTT = R;
RTTVAR = R / 2;
RTT_hit = true;
} else {
const double alpha = 1.0 / 8.0;
const double beta = 1.0 / 4.0;
RTTVAR = (1 - beta) * RTTVAR + ( beta * fabs( SRTT - R ) );
SRTT = (1 - alpha) * SRTT + ( alpha * R );
}
}
/* eliminate predictions proven correct or incorrect */
if ( (*i)->get_validity( fb ) != Pending ) { if ( (*i)->get_validity( fb ) != Pending ) {
delete (*i); delete (*i);
i = elements.erase( i ); i = elements.erase( i );
@@ -263,6 +282,8 @@ void NotificationEngine::apply( Framebuffer &fb ) const
void OverlayManager::apply( Framebuffer &fb ) void OverlayManager::apply( Framebuffer &fb )
{ {
predictions.calculate_score( fb ); predictions.calculate_score( fb );
/* eliminate predictions proven correct or incorrect and update echo timers */
predictions.cull( fb ); predictions.cull( fb );
if ( predictions.get_score() > 3 ) { if ( predictions.get_score() > 3 ) {
@@ -289,14 +310,14 @@ void PredictionEngine::calculate_score( const Framebuffer &fb )
} }
} }
void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb, int prediction_len ) void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
{ {
uint64_t now = timestamp(); uint64_t now = timestamp();
if ( elements.empty() ) { if ( elements.empty() ) {
/* starting from scratch */ /* starting from scratch */
elements.push_front( new ConditionalCursorMove( now + prediction_len, elements.push_front( new ConditionalCursorMove( now + prediction_len(),
fb.ds.get_cursor_row(), fb.ds.get_cursor_row(),
fb.ds.get_cursor_col() ) ); fb.ds.get_cursor_col() ) );
} }
@@ -313,7 +334,7 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb, int
const Cell *existing_cell = fb.get_cell( ccm->new_row, ccm->new_col ); const Cell *existing_cell = fb.get_cell( ccm->new_row, ccm->new_col );
ConditionalOverlayCell *coc = new ConditionalOverlayCell( now + prediction_len, ConditionalOverlayCell *coc = new ConditionalOverlayCell( now + prediction_len(),
ccm->new_row, ccm->new_col, ccm->new_row, ccm->new_col,
existing_cell->renditions.background_color, existing_cell->renditions.background_color,
*existing_cell ); *existing_cell );
@@ -323,7 +344,7 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb, int
coc->replacement.contents.push_back( the_byte ); coc->replacement.contents.push_back( the_byte );
ccm->new_col++; ccm->new_col++;
ccm->expiration_time = now + prediction_len; ccm->expiration_time = now + prediction_len();
elements.push_back( coc ); elements.push_back( coc );
} else { } else {
@@ -357,3 +378,14 @@ int OverlayManager::wait_time( void )
return ret; return ret;
} }
} }
int PredictionEngine::prediction_len( void )
{
uint64_t RTO = lrint( ceil( SRTT + 4 * RTTVAR ) );
if ( RTO < 20 ) {
RTO = 20;
} else if ( RTO > 2000 ) {
RTO = 2000;
}
return RTO;
}
+12 -5
View File
@@ -20,12 +20,13 @@ namespace Overlay {
/* The individual elements of an overlay -- cursor movements and replaced cells */ /* The individual elements of an overlay -- cursor movements and replaced cells */
class OverlayElement { class OverlayElement {
public: public:
uint64_t expiration_time; uint64_t prediction_time, expiration_time;
virtual void apply( Framebuffer &fb ) const = 0; virtual void apply( Framebuffer &fb ) const = 0;
virtual Validity get_validity( const Framebuffer & ) const; virtual Validity get_validity( const Framebuffer & ) const;
OverlayElement( uint64_t s_expiration_time ) : expiration_time( s_expiration_time ) {} OverlayElement( uint64_t s_expiration_time ) : prediction_time( timestamp() ),
expiration_time( s_expiration_time ) {}
virtual ~OverlayElement() {} virtual ~OverlayElement() {}
}; };
@@ -75,7 +76,6 @@ namespace Overlay {
list<OverlayElement *> elements; list<OverlayElement *> elements;
public: public:
void cull( const Framebuffer &fb );
virtual void apply( Framebuffer &fb ) const; virtual void apply( Framebuffer &fb ) const;
void clear( void ); void clear( void );
@@ -109,11 +109,18 @@ namespace Overlay {
private: private:
int score; int score;
/* use the TCP timeout algorithm to measure appropriate echo prediction timeout */
bool RTT_hit;
double SRTT, RTTVAR;
int prediction_len( void );
public: public:
void new_user_byte( char the_byte, const Framebuffer &fb, int prediction_len ); void cull( const Framebuffer &fb );
void new_user_byte( char the_byte, const Framebuffer &fb );
void calculate_score( const Framebuffer &fb ); void calculate_score( const Framebuffer &fb );
PredictionEngine() : score( 0 ) {} PredictionEngine() : score( 0 ), RTT_hit( false ), SRTT( 1000 ), RTTVAR( 500 ) {}
int get_score( void ) { return score; } int get_score( void ) { return score; }
}; };