Skip to content

Commit

Permalink
perf(tui): only rerender if a non-tick event has been received (#9121)
Browse files Browse the repository at this point in the history
### 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">
  • Loading branch information
chris-olszewski authored Sep 6, 2024
1 parent 785682b commit c84638a
Showing 1 changed file with 8 additions and 1 deletion.
9 changes: 8 additions & 1 deletion crates/turborepo-ui/src/tui/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,13 @@ fn run_app_inner<B: Backend + std::io::Write>(
let mut last_render = Instant::now();
let mut resize_debouncer = Debouncer::new(RESIZE_DEBOUNCE_DELAY);
let mut callback = None;
let mut needs_rerender = true;
while let Some(event) = poll(app.input_options()?, &receiver, last_render + FRAMERATE) {
// If we only receive ticks, then there's been no state change so no update
// needed
if !matches!(event, Event::Tick) {
needs_rerender = true;
}
let mut event = Some(event);
let mut resize_event = None;
if matches!(event, Some(Event::Resize { .. })) {
Expand All @@ -606,9 +612,10 @@ fn run_app_inner<B: Backend + std::io::Write>(
if app.done {
break;
}
if FRAMERATE <= last_render.elapsed() {
if FRAMERATE <= last_render.elapsed() && needs_rerender {
terminal.draw(|f| view(app, f))?;
last_render = Instant::now();
needs_rerender = false;
}
}
}
Expand Down

0 comments on commit c84638a

Please sign in to comment.