aboutsummaryrefslogtreecommitdiffstats
path: root/zellij-server/src/terminal_bytes.rs
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2025-03-24 16:48:39 +0100
committerGitHub <noreply@github.com>2025-03-24 16:48:39 +0100
commitf3351f4f75dd1dc43f8808235553593bf87e68a0 (patch)
treeaf9b7660baba92819e546cce138787dcd752ce25 /zellij-server/src/terminal_bytes.rs
parentbuild: Don't re-export foreign crates in utils (#4087) (diff)
downloadsl0ppij-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.rs100
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()
- }
- }
}