diff options
| author | Aram Drevekenin <aram@poor.dev> | 2025-03-24 16:48:39 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-03-24 16:48:39 +0100 |
| commit | f3351f4f75dd1dc43f8808235553593bf87e68a0 (patch) | |
| tree | af9b7660baba92819e546cce138787dcd752ce25 /zellij-server/src/terminal_bytes.rs | |
| parent | build: Don't re-export foreign crates in utils (#4087) (diff) | |
| download | sl0ppij-f3351f4f75dd1dc43f8808235553593bf87e68a0.tar.gz sl0ppij-f3351f4f75dd1dc43f8808235553593bf87e68a0.tar.xz sl0ppij-f3351f4f75dd1dc43f8808235553593bf87e68a0.zip | |
performance(render): improve rendering performance by consolidating renders and introducing repaint_delay (#4100)
* initial draft
* style(comment): add explanation to async render
* remove timeouts from terminal_bytes
* some cleanups
* cleanups
* chore(docs): update pr
Diffstat (limited to 'zellij-server/src/terminal_bytes.rs')
| -rw-r--r-- | zellij-server/src/terminal_bytes.rs | 100 |
1 files changed, 5 insertions, 95 deletions
diff --git a/zellij-server/src/terminal_bytes.rs b/zellij-server/src/terminal_bytes.rs index c6d901c2..7eb19204 100644 --- a/zellij-server/src/terminal_bytes.rs +++ b/zellij-server/src/terminal_bytes.rs @@ -3,7 +3,7 @@ use crate::{ screen::ScreenInstruction, thread_bus::ThreadSenders, }; -use async_std::{future::timeout as async_timeout, task}; +use async_std::task; use std::{ os::unix::io::RawFd, time::{Duration, Instant}, @@ -13,32 +13,12 @@ use zellij_utils::{ logging::debug_to_file, }; -enum ReadResult { - Ok(usize), - Timeout, - Err(std::io::Error), -} - -impl From<std::io::Result<usize>> for ReadResult { - fn from(e: std::io::Result<usize>) -> ReadResult { - match e { - Err(e) => ReadResult::Err(e), - Ok(n) => ReadResult::Ok(n), - } - } -} - pub(crate) struct TerminalBytes { pid: RawFd, terminal_id: u32, senders: ThreadSenders, async_reader: Box<dyn AsyncReader>, debug: bool, - render_deadline: Option<Instant>, - backed_up: bool, - minimum_render_send_time: Option<Duration>, - buffering_pause: Duration, - last_render: Instant, } impl TerminalBytes { @@ -55,11 +35,6 @@ impl TerminalBytes { senders, debug, async_reader: os_input.async_file_reader(pid), - render_deadline: None, - backed_up: false, - minimum_render_send_time: None, - buffering_pause: Duration::from_millis(30), - last_render: Instant::now(), } } pub async fn listen(&mut self) -> Result<()> { @@ -80,25 +55,13 @@ impl TerminalBytes { err_ctx.add_call(ContextType::AsyncTask); let mut buf = [0u8; 65536]; loop { - match self.deadline_read(&mut buf).await { - // EOF - ReadResult::Ok(0) => break, - // Some error occured - ReadResult::Err(err) => { + match self.async_reader.read(&mut buf).await { + Ok(0) => break, // EOF + Err(err) => { log::error!("{}", err); break; }, - ReadResult::Timeout => { - let time_to_send_render = self - .async_send_to_screen(ScreenInstruction::Render) - .await - .with_context(err_context)?; - self.update_render_send_time(time_to_send_render); - // next read does not need a deadline as we just rendered everything - self.render_deadline = None; - self.last_render = Instant::now(); - }, - ReadResult::Ok(n_bytes) => { + Ok(n_bytes) => { let bytes = &buf[..n_bytes]; if self.debug { let _ = debug_to_file(bytes, self.pid); @@ -109,19 +72,6 @@ impl TerminalBytes { )) .await .with_context(err_context)?; - if !self.backed_up { - // we're not backed up, let's send an immediate render instruction - let time_to_send_render = self - .async_send_to_screen(ScreenInstruction::Render) - .await - .with_context(err_context)?; - self.update_render_send_time(time_to_send_render); - self.last_render = Instant::now(); - } - // if we already have a render_deadline we keep it, otherwise we set it - // to buffering_pause since the last time we rendered. - self.render_deadline - .get_or_insert(self.last_render + self.buffering_pause); }, } } @@ -156,44 +106,4 @@ impl TerminalBytes { .context("failed to async-send to screen")?; Ok(sent_at.elapsed()) } - fn update_render_send_time(&mut self, time_to_send_render: Duration) { - match self.minimum_render_send_time.as_mut() { - Some(minimum_render_time) => { - if time_to_send_render < *minimum_render_time { - *minimum_render_time = time_to_send_render; - } - if time_to_send_render > *minimum_render_time * 10 { - // sending the render instruction took an especially long time, we can safely - // assume the screen thread is backed up and we should only send render - // instructions sparingly - self.backed_up = true; - } else if time_to_send_render < *minimum_render_time * 5 { - // the screen thread is not backed up, we atomically unset the backed_up - // indication - self.backed_up = false; - } - }, - None => { - self.minimum_render_send_time = Some(time_to_send_render); - }, - } - } - async fn deadline_read(&mut self, buf: &mut [u8]) -> ReadResult { - if !self.backed_up { - self.async_reader.read(buf).await.into() - } else if let Some(deadline) = self.render_deadline { - let timeout = deadline.checked_duration_since(Instant::now()); - if let Some(timeout) = timeout { - match async_timeout(timeout, self.async_reader.read(buf)).await { - Ok(res) => res.into(), - _ => ReadResult::Timeout, - } - } else { - // deadline has already elapsed - ReadResult::Timeout - } - } else { - self.async_reader.read(buf).await.into() - } - } } |
