Tweaks to local predictions -- better flagging and more responsiveness
This commit is contained in:
+49
-31
@@ -11,7 +11,7 @@ using namespace Overlay;
|
|||||||
bool ConditionalOverlay::start_clock( uint64_t local_frame_acked, uint64_t now )
|
bool ConditionalOverlay::start_clock( uint64_t local_frame_acked, uint64_t now )
|
||||||
{
|
{
|
||||||
if ( (local_frame_acked >= expiration_frame) && (expiration_time == uint64_t(-1)) ) {
|
if ( (local_frame_acked >= expiration_frame) && (expiration_time == uint64_t(-1)) ) {
|
||||||
expiration_time = now + 25;
|
expiration_time = now + 50;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -30,7 +30,7 @@ void ConditionalOverlayCell::apply( Framebuffer &fb, uint64_t confirmed_epoch, i
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( unknown ) {
|
if ( unknown ) {
|
||||||
fb.get_mutable_cell( row, col )->contents.clear();
|
// fb.get_mutable_cell( row, col )->contents.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ void ConditionalOverlayCell::apply( Framebuffer &fb, uint64_t confirmed_epoch, i
|
|||||||
if ( display_time >= now ) {
|
if ( display_time >= now ) {
|
||||||
display_time = now;
|
display_time = now;
|
||||||
}
|
}
|
||||||
if ( flag ) {
|
if ( flag && (!replacement.is_blank()) ) {
|
||||||
fb.get_mutable_cell( row, col )->renditions.underlined = true;
|
fb.get_mutable_cell( row, col )->renditions.underlined = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,12 +69,6 @@ Validity ConditionalOverlayCell::get_validity( const Framebuffer &fb, int row, u
|
|||||||
return Pending;
|
return Pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert( expiration_time != uint64_t(-1) );
|
|
||||||
|
|
||||||
if ( now < expiration_time ) {
|
|
||||||
return Pending;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* special case deletion */
|
/* special case deletion */
|
||||||
if ( current.is_blank() && replacement.is_blank() ) {
|
if ( current.is_blank() && replacement.is_blank() ) {
|
||||||
return CorrectNoCredit;
|
return CorrectNoCredit;
|
||||||
@@ -85,10 +79,22 @@ Validity ConditionalOverlayCell::get_validity( const Framebuffer &fb, int row, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( current.contents == replacement.contents ) {
|
if ( current.contents == replacement.contents ) {
|
||||||
return Correct;
|
auto it = find_if( original_contents.begin(), original_contents.end(),
|
||||||
} else {
|
[&]( const Cell &x ) { return replacement.contents == x.contents; } );
|
||||||
return IncorrectOrExpired;
|
if ( it == original_contents.end() ) {
|
||||||
|
return Correct;
|
||||||
|
} else {
|
||||||
|
return CorrectNoCredit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert( expiration_time != uint64_t(-1) );
|
||||||
|
|
||||||
|
if ( now < expiration_time ) {
|
||||||
|
return Pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IncorrectOrExpired;
|
||||||
}
|
}
|
||||||
|
|
||||||
Validity ConditionalCursorMove::get_validity( const Framebuffer &fb, uint64_t current_frame, uint64_t now ) const
|
Validity ConditionalCursorMove::get_validity( const Framebuffer &fb, uint64_t current_frame, uint64_t now ) const
|
||||||
@@ -351,8 +357,6 @@ void PredictionEngine::cull( const Framebuffer &fb )
|
|||||||
|
|
||||||
/* go through cell predictions */
|
/* go through cell predictions */
|
||||||
|
|
||||||
uint64_t max_delay = 0;
|
|
||||||
|
|
||||||
auto i = overlays.begin();
|
auto i = overlays.begin();
|
||||||
while ( i != overlays.end() ) {
|
while ( i != overlays.end() ) {
|
||||||
auto inext = i;
|
auto inext = i;
|
||||||
@@ -403,6 +407,8 @@ void PredictionEngine::cull( const Framebuffer &fb )
|
|||||||
i->row_num, j->col,
|
i->row_num, j->col,
|
||||||
j->replacement.debug_contents(),
|
j->replacement.debug_contents(),
|
||||||
fb.get_cell( i->row_num, j->col )->debug_contents() );
|
fb.get_cell( i->row_num, j->col )->debug_contents() );
|
||||||
|
*/
|
||||||
|
/*
|
||||||
if ( j->display_time != uint64_t(-1) ) {
|
if ( j->display_time != uint64_t(-1) ) {
|
||||||
fprintf( stderr, "TIMING %ld - %ld\n", time(NULL), now - j->display_time );
|
fprintf( stderr, "TIMING %ld - %ld\n", time(NULL), now - j->display_time );
|
||||||
}
|
}
|
||||||
@@ -421,10 +427,21 @@ void PredictionEngine::cull( const Framebuffer &fb )
|
|||||||
|
|
||||||
if ( j->tentative_until_epoch > confirmed_epoch ) {
|
if ( j->tentative_until_epoch > confirmed_epoch ) {
|
||||||
confirmed_epoch = j->tentative_until_epoch;
|
confirmed_epoch = j->tentative_until_epoch;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fprintf( stderr, "Confirmed epoch %lu (predicting in epoch %lu)\n",
|
fprintf( stderr, "%lc in (%d,%d) confirms epoch %lu (predicting in epoch %lu)\n",
|
||||||
|
j->replacement.debug_contents(), i->row_num, j->col,
|
||||||
confirmed_epoch, prediction_epoch );
|
confirmed_epoch, prediction_epoch );
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( j->display_time != uint64_t(-1) ) {
|
||||||
|
if ( now - j->display_time < 75 ) {
|
||||||
|
if ( flagging > 0 ) {
|
||||||
|
flagging--;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no break */
|
/* no break */
|
||||||
@@ -442,7 +459,9 @@ void PredictionEngine::cull( const Framebuffer &fb )
|
|||||||
break;
|
break;
|
||||||
case Pending:
|
case Pending:
|
||||||
if ( j->display_time != uint64_t(-1) ) {
|
if ( j->display_time != uint64_t(-1) ) {
|
||||||
max_delay = max( max_delay, now - j->display_time );
|
if ( now - j->display_time >= 150 ) {
|
||||||
|
flagging = 10;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -453,16 +472,11 @@ void PredictionEngine::cull( const Framebuffer &fb )
|
|||||||
i = inext;
|
i = inext;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( max_delay > 100 ) {
|
|
||||||
flagging = true;
|
|
||||||
} else if ( max_delay < 50 ) {
|
|
||||||
flagging = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* go through cursor predictions */
|
/* go through cursor predictions */
|
||||||
for ( auto it = cursors.begin(); it != cursors.end(); it++ ) {
|
for ( auto it = cursors.begin(); it != cursors.end(); it++ ) {
|
||||||
if ( it->start_clock( local_frame_acked, now ) ) {
|
if ( it->start_clock( local_frame_acked, now ) ) {
|
||||||
last_scheduled_timeout = max( last_scheduled_timeout, it->expiration_time ); }
|
last_scheduled_timeout = max( last_scheduled_timeout, it->expiration_time );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !cursors.empty() ) {
|
if ( !cursors.empty() ) {
|
||||||
@@ -508,10 +522,6 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
|
|||||||
{
|
{
|
||||||
cull( fb );
|
cull( fb );
|
||||||
|
|
||||||
init_cursor( fb );
|
|
||||||
|
|
||||||
assert( !cursors.empty() );
|
|
||||||
|
|
||||||
/* translate application-mode cursor control function to ANSI cursor control sequence */
|
/* translate application-mode cursor control function to ANSI cursor control sequence */
|
||||||
if ( (last_byte == 0x1b)
|
if ( (last_byte == 0x1b)
|
||||||
&& (the_byte == 'O') ) {
|
&& (the_byte == 'O') ) {
|
||||||
@@ -532,6 +542,8 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
|
|||||||
if ( typeid( *act ) == typeid( Parser::Print ) ) {
|
if ( typeid( *act ) == typeid( Parser::Print ) ) {
|
||||||
/* make new prediction */
|
/* make new prediction */
|
||||||
|
|
||||||
|
init_cursor( fb );
|
||||||
|
|
||||||
assert( act->char_present );
|
assert( act->char_present );
|
||||||
|
|
||||||
wchar_t ch = act->ch;
|
wchar_t ch = act->ch;
|
||||||
@@ -550,10 +562,12 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
|
|||||||
|
|
||||||
for ( int i = cursor().col; i < fb.ds.get_width(); i++ ) {
|
for ( int i = cursor().col; i < fb.ds.get_width(); i++ ) {
|
||||||
ConditionalOverlayCell &cell = the_row.overlay_cells[ i ];
|
ConditionalOverlayCell &cell = the_row.overlay_cells[ i ];
|
||||||
cell.reset();
|
|
||||||
|
cell.reset_with_orig();
|
||||||
cell.active = true;
|
cell.active = true;
|
||||||
cell.tentative_until_epoch = prediction_epoch;
|
cell.tentative_until_epoch = prediction_epoch;
|
||||||
cell.expire( local_frame_sent + 1 );
|
cell.expire( local_frame_sent + 1 );
|
||||||
|
cell.original_contents.push_back( *fb.get_cell( cursor().row, i ) );
|
||||||
|
|
||||||
if ( i + 2 < fb.ds.get_width() ) {
|
if ( i + 2 < fb.ds.get_width() ) {
|
||||||
ConditionalOverlayCell &next_cell = the_row.overlay_cells[ i + 1 ];
|
ConditionalOverlayCell &next_cell = the_row.overlay_cells[ i + 1 ];
|
||||||
@@ -596,10 +610,11 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
|
|||||||
/* do the insert */
|
/* do the insert */
|
||||||
for ( int i = fb.ds.get_width() - 1; i > cursor().col; i-- ) {
|
for ( int i = fb.ds.get_width() - 1; i > cursor().col; i-- ) {
|
||||||
ConditionalOverlayCell &cell = the_row.overlay_cells[ i ];
|
ConditionalOverlayCell &cell = the_row.overlay_cells[ i ];
|
||||||
cell.reset();
|
cell.reset_with_orig();
|
||||||
cell.active = true;
|
cell.active = true;
|
||||||
cell.tentative_until_epoch = prediction_epoch;
|
cell.tentative_until_epoch = prediction_epoch;
|
||||||
cell.expire( local_frame_sent + 1 );
|
cell.expire( local_frame_sent + 1 );
|
||||||
|
cell.original_contents.push_back( *fb.get_cell( cursor().row, i ) );
|
||||||
|
|
||||||
ConditionalOverlayCell &prev_cell = the_row.overlay_cells[ i - 1 ];
|
ConditionalOverlayCell &prev_cell = the_row.overlay_cells[ i - 1 ];
|
||||||
const Cell *prev_cell_actual = fb.get_cell( cursor().row, i - 1 );
|
const Cell *prev_cell_actual = fb.get_cell( cursor().row, i - 1 );
|
||||||
@@ -620,13 +635,14 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConditionalOverlayCell &cell = the_row.overlay_cells[ cursor().col ];
|
ConditionalOverlayCell &cell = the_row.overlay_cells[ cursor().col ];
|
||||||
cell.reset();
|
cell.reset_with_orig();
|
||||||
cell.active = true;
|
cell.active = true;
|
||||||
cell.tentative_until_epoch = prediction_epoch;
|
cell.tentative_until_epoch = prediction_epoch;
|
||||||
cell.expire( local_frame_sent + 1 );
|
cell.expire( local_frame_sent + 1 );
|
||||||
cell.replacement.renditions = fb.ds.get_renditions();
|
cell.replacement.renditions = fb.ds.get_renditions();
|
||||||
cell.replacement.contents.clear();
|
cell.replacement.contents.clear();
|
||||||
cell.replacement.contents.push_back( ch );
|
cell.replacement.contents.push_back( ch );
|
||||||
|
cell.original_contents.push_back( *fb.get_cell( cursor().row, cursor().col ) );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fprintf( stderr, "[%d=>%d] Predicting %lc in row %d, col %d [tue: %lu]\n",
|
fprintf( stderr, "[%d=>%d] Predicting %lc in row %d, col %d [tue: %lu]\n",
|
||||||
@@ -656,11 +672,13 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
|
|||||||
become_tentative();
|
become_tentative();
|
||||||
} else if ( typeid( *act ) == typeid( Parser::CSI_Dispatch ) ) {
|
} else if ( typeid( *act ) == typeid( Parser::CSI_Dispatch ) ) {
|
||||||
if ( act->char_present && (act->ch == L'C') ) { /* right arrow */
|
if ( act->char_present && (act->ch == L'C') ) { /* right arrow */
|
||||||
|
init_cursor( fb );
|
||||||
if ( cursor().col < fb.ds.get_width() - 1 ) {
|
if ( cursor().col < fb.ds.get_width() - 1 ) {
|
||||||
cursor().col++;
|
cursor().col++;
|
||||||
cursor().expire( local_frame_sent + 1 );
|
cursor().expire( local_frame_sent + 1 );
|
||||||
}
|
}
|
||||||
} else if ( act->char_present && (act->ch == L'D') ) { /* left arrow */
|
} else if ( act->char_present && (act->ch == L'D') ) { /* left arrow */
|
||||||
|
init_cursor( fb );
|
||||||
ConditionalOverlayRow &the_row = get_or_make_row( cursor().row, fb.ds.get_width() );
|
ConditionalOverlayRow &the_row = get_or_make_row( cursor().row, fb.ds.get_width() );
|
||||||
if ( cursor().col <= the_row.first_col ) {
|
if ( cursor().col <= the_row.first_col ) {
|
||||||
become_tentative();
|
become_tentative();
|
||||||
@@ -684,6 +702,7 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
|
|||||||
|
|
||||||
void PredictionEngine::newline_carriage_return( const Framebuffer &fb )
|
void PredictionEngine::newline_carriage_return( const Framebuffer &fb )
|
||||||
{
|
{
|
||||||
|
init_cursor( fb );
|
||||||
cursor().col = 0;
|
cursor().col = 0;
|
||||||
if ( cursor().row == fb.ds.get_height() - 1 ) {
|
if ( cursor().row == fb.ds.get_height() - 1 ) {
|
||||||
for ( auto i = overlays.begin(); i != overlays.end(); i++ ) {
|
for ( auto i = overlays.begin(); i != overlays.end(); i++ ) {
|
||||||
@@ -719,7 +738,6 @@ void PredictionEngine::become_tentative( void )
|
|||||||
prediction_epoch ) );
|
prediction_epoch ) );
|
||||||
cursor().active = true;
|
cursor().active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fprintf( stderr, "Now tentative in epoch %lu (confirmed=%lu)\n",
|
fprintf( stderr, "Now tentative in epoch %lu (confirmed=%lu)\n",
|
||||||
prediction_epoch, confirmed_epoch );
|
prediction_epoch, confirmed_epoch );
|
||||||
|
|||||||
+21
-6
@@ -62,6 +62,9 @@ namespace Overlay {
|
|||||||
|
|
||||||
mutable uint64_t display_time;
|
mutable uint64_t display_time;
|
||||||
|
|
||||||
|
vector<Cell> original_contents; /* we don't give credit for correct predictions
|
||||||
|
that match the original contents */
|
||||||
|
|
||||||
void apply( Framebuffer &fb, uint64_t confirmed_epoch, int row, bool flag ) const;
|
void apply( Framebuffer &fb, uint64_t confirmed_epoch, int row, bool flag ) const;
|
||||||
Validity get_validity( const Framebuffer &fb, int row, uint64_t current_frame, uint64_t now ) const;
|
Validity get_validity( const Framebuffer &fb, int row, uint64_t current_frame, uint64_t now ) const;
|
||||||
|
|
||||||
@@ -69,10 +72,22 @@ namespace Overlay {
|
|||||||
: ConditionalOverlay( s_exp, s_col, s_tentative ),
|
: ConditionalOverlay( s_exp, s_col, s_tentative ),
|
||||||
replacement( 0 ),
|
replacement( 0 ),
|
||||||
unknown( false ),
|
unknown( false ),
|
||||||
display_time( -1 )
|
display_time( uint64_t(-1) ),
|
||||||
|
original_contents()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void reset( void ) { unknown = false; display_time = -1; ConditionalOverlay::reset(); }
|
void reset( void ) { unknown = false; display_time = uint64_t(-1); original_contents.clear(); ConditionalOverlay::reset(); }
|
||||||
|
void reset_with_orig( void ) {
|
||||||
|
if ( (!active) || unknown ) {
|
||||||
|
reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<Cell> new_orig( original_contents );
|
||||||
|
new_orig.push_back( replacement );
|
||||||
|
reset();
|
||||||
|
original_contents = new_orig;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConditionalOverlayRow {
|
class ConditionalOverlayRow {
|
||||||
@@ -126,9 +141,9 @@ namespace Overlay {
|
|||||||
|
|
||||||
void newline_carriage_return( const Framebuffer &fb );
|
void newline_carriage_return( const Framebuffer &fb );
|
||||||
|
|
||||||
bool flagging;
|
int flagging;
|
||||||
|
|
||||||
ConditionalCursorMove & cursor( void ) { return cursors.back(); }
|
ConditionalCursorMove & cursor( void ) { assert( !cursors.empty() ); return cursors.back(); }
|
||||||
|
|
||||||
void kill_epoch( uint64_t epoch, const Framebuffer &fb );
|
void kill_epoch( uint64_t epoch, const Framebuffer &fb );
|
||||||
|
|
||||||
@@ -150,8 +165,8 @@ namespace Overlay {
|
|||||||
|
|
||||||
PredictionEngine( void ) : last_byte( 0 ), parser(), overlays(), cursors(),
|
PredictionEngine( void ) : last_byte( 0 ), parser(), overlays(), cursors(),
|
||||||
local_frame_sent( 0 ), local_frame_acked( 0 ),
|
local_frame_sent( 0 ), local_frame_acked( 0 ),
|
||||||
prediction_epoch( 0 ), confirmed_epoch( 0 ),
|
prediction_epoch( 1 ), confirmed_epoch( 0 ),
|
||||||
flagging( false ), last_scheduled_timeout( 0 )
|
flagging( 0 ), last_scheduled_timeout( 0 )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user