fix(performance): immediately render after a period of inactivity (#798)

The current code waits for 30ms after reading new data to refresh the
screen in order to batch input together. This reduces the number of
refreshes, but also adds perceptible latency as keystrokes will only get
visual feedback after a 30 ms delay.

Improve this by immediately refreshing if more than 30ms have already
passed since the last refresh. That way punctual events like keystrokes
get immediate feedback, while heavier input still gets batched together.
This commit is contained in:
Alexandre Courbot 2021-10-25 23:51:30 +09:00 committed by GitHub
parent 0c96347083
commit 21380c278e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -216,10 +216,13 @@ fn stream_terminal_bytes(
err_ctx.add_call(ContextType::AsyncTask);
// After a successful read, we keep on reading additional data up to a duration of
// `render_pause`. This is in order to batch up PtyBytes before rendering them.
// `RENDER_PAUSE`. This is in order to batch up PtyBytes before rendering them.
// Once `render_deadline` has elapsed, we send Render.
let render_pause = Duration::from_millis(30);
const RENDER_PAUSE: Duration = Duration::from_millis(30);
let mut render_deadline = None;
// Keep track of the last render time so we can render immediately if something shows
// up after a period of inactivity. This reduces input latency perception.
let mut last_render = Instant::now();
let mut buf = [0u8; 65536];
let mut async_reader = os_input.async_file_reader(pid);
@ -230,6 +233,7 @@ fn stream_terminal_bytes(
async_send_to_screen(senders.clone(), ScreenInstruction::Render).await;
// next read does not need a deadline as we just rendered everything
render_deadline = None;
last_render = Instant::now();
}
ReadResult::Ok(n_bytes) => {
let bytes = &buf[..n_bytes];
@ -242,8 +246,8 @@ fn stream_terminal_bytes(
)
.await;
// if we already have a render_deadline we keep it, otherwise we set it
// to the duration of `render_pause`.
render_deadline.get_or_insert(Instant::now() + render_pause);
// to RENDER_PAUSE since the last time we rendered.
render_deadline.get_or_insert(last_render + RENDER_PAUSE);
}
}
}