Hmbown / Hmbown/Codewhale

v0.9.14: GPUI client perf — idle tick loop, per-frame decodes, transcript sync copies

Open
#6,215 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
41k
Forks
3.6k
Avg merge
13h 59m
Merged PRs (30d)
299

Description

Source: `codewhale-ops/PERF-OPPORTUNITIES-20260915.md` §4 — the GPUI half was never filed; the Core half is already tracked in #6208–#6214. Line numbers are anchors; function names are the stable reference.

## G1. The 30Hz tick loop never stops — even fully idle [verified]
`src/workspace/mod.rs:880` — `loop { Timer::after(33ms); tick() }` forever. Every tick iterates the whole `message_text` map, scans settings-field expiries, locks engine state. Constant idle CPU/battery drain scaling with conversation size.
Fix: exit when nothing is animating and no turn is active; re-arm from events (stream completion, pet frame due). Minimum: back off to 1s when idle. **Fix first — it multiplies every other per-tick cost below.**

## G2. Pet animation repaints the whole workspace + companion window at 30–60Hz
`src/workspace/pet.rs:63` polls the whale engine every 30ms and calls `cx.notify()` unconditionally; `render.rs:107` drives the main window via `request_animation_frame()`; `companion.rs` observes the workspace so each notify repaints the floating window too. One sprite rebuilds the 8k-line workspace element tree.
Fix: notify only on fresh frames; move pet state into an isolated overlay entity.

## G3. Transcript sync deep-copies and hashes all message text per sync
`src/workspace/render.rs:7027` — `SharedString::from(item.text().to_string())` per row per sync; `render.rs:139` hashes full text into the fingerprint. Runs 4×/s while streaming — O(transcript chars) memcpy+hash per sync.
Fix: carry text as refcounted `SharedString`/`Arc`; fingerprint by `(len, latest_seq)` or a rolling hash of appended deltas.

## G4. Expanded receipt details re-parse GFM markdown every frame
`render.rs:385` — `to_mdast(source, ParseOptions::gfm())` per frame per visible expanded row. Message rows already cache `TextViewState`; detail rows don't.
Fix: cache detail `TextViewState` keyed by item id; use `markdown::state_view`.

## G5. History drawer rebuilds all derived rows on every notify, then diffs
`src/workspace/history.rs:350` — `build_history_sections` (RFC3339 day parse, title scan, `format!` meta) on every workspace notify — 30Hz tick + every keystroke while open.
Fix: fingerprint inputs (`latest_seq`/count + prefs + flags) and skip the rebuild when unchanged. Related to the virtualized-drawer branch.

## G6. Unvirtualized "saved sessions" list with per-frame formatting
`render.rs:549` — Button per saved session per frame, `row_label(..., SystemTime::now())`, `format!` meta, no cap.
Fix: prepare rows on change; virtualize with the conversations-list delegate pattern.

## G7. Preview panel re-decodes images on the UI thread every frame
`render.rs:1421` — `Image::from_bytes(..., raw.clone())`: whole-buffer clone + decode per frame while open.
Fix: decode once into `Arc` cache keyed by `(path, mtime)`.

## G8. Tick-driven sync fs IO on the UI thread
`mod.rs:1150` + `deep_link.rs:452` — settings reload every 33ms while connected; deep-link inbox `File::open`/`read_to_string`/`remove_file` every 750ms — sync fs on the main thread.
Fix: background thread or FSEvent/kqueue watcher posting events; schedule settings refresh at its real deadline.

Contributor guide

Open the contributing guide

Research direction

Start with src/workspace/mod.rs around the 30Hz tick loop, then trace the function anchors in pet.rs, render.rs, history.rs, companion.rs, and deep_link.rs. Done means addressing the eight listed GPUI performance paths: idle scheduling, repaint isolation, transcript and markdown caching, history and session row preparation, image caching, and asynchronous or deadline-based filesystem refreshes.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
desktop-dev, performance
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.