Skip to content

Back off idle background work in the GPUI app - #17

Merged
snekxs merged 1 commit into
gpuifrom
gpui-idle-power
Oct 20, 2026
Merged

snekxs merged 1 commit into
gpuifrom
gpui-idle-power

Conversation

@snekxs

@snekxs snekxs commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

What

The native app polled at a fixed rate whether or not anyone was looking at it. This cuts that without delaying anything a user can see.

1. HID reader idle backoff (crates/openmouse-hid)

Held-open interfaces keep a reader thread each, looping on a 10 ms read plus a 5 ms gap (about 66 wakeups/s per interface) for the life of the process.

  • New opt-in set_idle_backoff(bool). After 2 s with no report and no request, a reader adds a 100 ms park_timeout after its usual gap, outside the device lock.
  • Every request goes through with_open_group, which marks activity and unparks the readers before writing, so replies are still read at the normal cadence. Only an unsolicited report arriving while idle can be delayed (at most 100 ms; the OS queues it).
  • Off by default. Only HidService::start (GPUI) turns it on, so the Tauri app's reader behavior is unchanged.

2. Wallpaper watcher only runs for Dynamic (gpui/src/theme.rs)

Each check spawns osascript on macOS. It now skips the check unless the theme is Dynamic (re-checking the theme every 30 s). Switching to Dynamic already resamples on its own in AppView::set_theme.

3. Window-activity flag (gpui/src/activity.rs)

A shared flag set from the main window's activation events (the game overlay is not observed). While the window is not active:

Loop Active Inactive
Game process scan 2 s 10 s
Install scan 10 s 60 s
Wallpaper check (Dynamic) 2 s 30 s

They slow rather than stop, so a game launching behind the window still applies its profile (up to about 10 s later), and regaining focus wakes them immediately. A window launched minimized at login is marked inactive explicitly.

Measurements

Linux sandbox, release build, mirroring the reader loop shape with poll(2) on a pipe (no HID device available):

5 interfaces wakeups/s CPU
Current loop 655 2.05% of a core
With 100 ms idle park 134 0.46% of a core

Process scan cost is about 1 ms per tick with ~100 processes and about 7 ms with ~500. Install scan is under 2 ms per tick on a warm cache. The macOS osascript cost was not measured.

Testing

  • cargo test in crates/openmouse-hid and gpui pass (new unit tests for the idle rule and the activity waiters).
  • cargo check --all-targets for gpui passes on Linux.
  • Not tested: the reader backoff against a real mouse, and macOS/Windows window activation. Please check on hardware that status walks (connect, DPI change) are not slower after the mouse has sat idle, and that a minimized window still applies a game profile within about 10 s of launch.
  • The Tauri app was not built here; its code path is unchanged because the backoff is opt-in.

The native app polled at a fixed rate whether or not anyone was looking at
it. Three changes cut that without delaying anything a user can see:

- HID readers (openmouse-hid): an opt-in idle backoff. After two quiet
  seconds a reader adds a 100 ms wait, outside the device lock, so five open
  interfaces drop from about 650 wakeups a second to about 130. Every request
  marks activity and unparks the readers first, so replies are still read at
  the normal cadence. Off unless a host calls set_idle_backoff; only the GPUI
  app does, so the Tauri app behaves exactly as before.
- Wallpaper watcher: only runs its checks while the Dynamic theme is
  selected (each check spawns osascript on macOS). Switching to Dynamic
  already resamples on its own.
- Window activity: a shared flag set from the main window's activation
  events. While the window is not active the game process scan goes from 2 s
  to 10 s, the install scan from 10 s to 60 s and the wallpaper check from 2 s
  to 30 s. They slow rather than stop, so a game launching behind the window
  still applies its profile, and regaining focus wakes them immediately.
@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7176bda1-5c06-4b64-9c42-e9cc85e04ef7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Autofix is active · Waiting for CI/review

Waiting for complete CI and CodeRabbit review evidence.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Oct 16, 2026

Copy link
Copy Markdown

Autofix was enabled. Check current status in the Coding task.

@snekxs
snekxs merged commit c90056e into gpui Oct 20, 2026
4 checks passed
@snekxs
snekxs deleted the gpui-idle-power branch October 20, 2026 21:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant