Skip to content

Commit c84638a

Browse files
perf(tui): only rerender if a non-tick event has been received (#9121)
### Description `ratatui` does a great job of only updating cells that are different between render, but constructing the `vt100` screen can be intensive. This PR avoid constructing the screen if there are no updates to the the app state meaning there's no reason to re-render the TUI. There are some additional changes we can also make to lower CPU usage more: - We're currently spending a lot of time polling for terminal events see if there's a less resource intensive alternative. - Patch vt100 so constructing `Screen` is less resource intensive e.g. doy/vt100-rust#14 ### Testing Instructions Using TUI in [next.js](https://github.com/vercel/next.js) ``` pnpm dev -F next ``` Before <img width="302" alt="Screenshot 2024-09-06 at 12 40 07 PM" src="https://github.com/user-attachments/assets/698595a0-f02e-4ef0-8880-ab39a6ecf32c"> After Ran via `cargo build -p turbo --release` and `turbo_dev --skip-infer dev -F next` <img width="292" alt="Screenshot 2024-09-06 at 12 31 00 PM" src="https://github.com/user-attachments/assets/66859912-7cea-4180-8c5e-10ea32312c52">
1 parent 785682b commit c84638a

File tree

1 file changed

+8
-1
lines changed
  • crates/turborepo-ui/src/tui

1 file changed

+8
-1
lines changed

crates/turborepo-ui/src/tui/app.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,13 @@ fn run_app_inner<B: Backend + std::io::Write>(
586586
let mut last_render = Instant::now();
587587
let mut resize_debouncer = Debouncer::new(RESIZE_DEBOUNCE_DELAY);
588588
let mut callback = None;
589+
let mut needs_rerender = true;
589590
while let Some(event) = poll(app.input_options()?, &receiver, last_render + FRAMERATE) {
591+
// If we only receive ticks, then there's been no state change so no update
592+
// needed
593+
if !matches!(event, Event::Tick) {
594+
needs_rerender = true;
595+
}
590596
let mut event = Some(event);
591597
let mut resize_event = None;
592598
if matches!(event, Some(Event::Resize { .. })) {
@@ -606,9 +612,10 @@ fn run_app_inner<B: Backend + std::io::Write>(
606612
if app.done {
607613
break;
608614
}
609-
if FRAMERATE <= last_render.elapsed() {
615+
if FRAMERATE <= last_render.elapsed() && needs_rerender {
610616
terminal.draw(|f| view(app, f))?;
611617
last_render = Instant::now();
618+
needs_rerender = false;
612619
}
613620
}
614621
}

0 commit comments

Comments
 (0)