Repository navigation
perf(gpui): stop vblank redraws of idle windows on Windows and X11 - #3104
Open
richiemcilroy wants to merge 5 commits into
Open
richiemcilroy wants to merge 5 commits into
richiemcilroy wants to merge 5 commits into
Conversation
Member
Author
|
@greptileai review |
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Member
Author
|
@greptileai review |
Member
Author
|
Real Cap app on Windows (GitHub-hosted windows-2022, WARP, main window with onboarding skipped via the
On main the 44 wakeups/s are vblank frame callbacks with no draws. The earlier "never idles" Windows reading was the first-run Welcome window, whose ambient animation is meant to run while it's active. |
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
zed-idle-frames.patchstops the frame source of an idle window only on macOS.frame_request_toggledefaults toNone(apps/desktop-gpui/patches/zed-idle-frames.patch:31), so on Windows and Linux the frame pacer does nothing and every visible window keeps waking the main thread once per vblank while it has nothing to draw:VSyncProviderthread callsRedrawWindow(RDW_INVALIDATE)on every window after every vblank (patched zedcrates/gpui_windows/src/platform.rs:342-346). Each one becomes aWM_PAINTthat runs gpui's frame callback.crates/gpui_linux/src/linux/x11/client.rs:2000-2036).Fix
Implement
frame_request_togglefor Windows and X11 inzed-idle-frames.patch. The gpui-side pacer is unchanged.RedrawWindow, and that is the only change to the loop. The thread still wakes every vblank, socheck_device_lost/handle_gpu_device_lostrun exactly as before. Device-lost recovery reaches paused windows because it sendsWM_GPUI_GPU_DEVICE_LOSTandWM_GPUI_FORCE_UPDATE_WINDOWto every window withSendMessageW. Once resumes the vsync redraws instead of drawing directly. The pacer stops them again after the frame, and until a frame arrives the window is redrawn every vblank as before, so a hidden or minimized window can't miss its frame. A new window clears any stale entry for its handle, and a dropped window removes its own.draw_windowis what pumps Direct Manipulation, which carries precision-touchpad two-finger scrolling and pinch.DM_POINTERHITTESTtakes the window off the paused list, and Stop is refused from a successfulSetContactuntil the viewport isREADYagain after the gesture and its inertia.force_render_after_recovery, or with an Expose still waiting to be presented, keeps its timer until that frame has run.can_drawdepend on the frame callbacks.Removed lines: the vsync loop's
for hwnd ... RedrawWindowblock (same call, now over the unpaused windows), the X11update_refresh_loopmatch head, the Expose loop's binding name, theSetContactcall (now also records the contact) and theDM_POINTERHITTESTdispatch (now passes the handle). All of them are upstream zed lines; none come fromzed-windows.patchorzed-linux.patch. The device-loss code,force_render_after_recovery,skip_draws/mark_drawable,invalidate_devicesand the #2472 display, DPI,fit_window_rectandIsWindowVisiblehunks are untouched.ci.yml: thegpui-patch-testsfilter now includesframe_pacer_tests(it ran onlystreambefore) and, on Windows, the newframe_request_testsanddirect_manipulationtests.Results
Same runner for base (main) and head, each idle window measured for 60 s, 3 rounds, alternating order, after an 8 s (probe) or 20 s (app) settle. Median (min to max). Main-thread wakeups are context switches of the process's first thread.
Real Cap app (
cap-gpuimain window, freshCAP_GPUI_APP_DATA_DIR, onboarding skipped), run 40100331504I couldn't measure the real app idle on the hosted Windows runner. There, both base and head redraw the main window continuously: about 38 main-thread wakeups/s and about 3.8 cores of CPU, almost all of it outside the main thread, with no difference between the two. A window that never goes idle never pauses, so this change can't affect it. The Windows numbers below come from the minimal window instead.
Minimal gpui window built against the same patched gpui (
idle_probe), run 40096753616The remaining ~42 process wakeups/s on Windows are the
VSyncProviderthread, which keeps ticking on purpose so device-loss checks still run every vblank. The "1 Hz clock" variant redraws once a second, like the recording bar timer.In absolute terms the CPU saved is small (the idle Windows window drops from about 7.5 to 1.7 Mcycles/s, roughly 0.3% to 0.07% of one core). The main win is that an idle Cap window no longer wakes the UI thread 44-62 times a second, which keeps the CPU out of deep idle states.
Repaint on demand.
idle_probe checkruns on both variants and both platforms. It waits past the pacer's idle delay before each step, then checks:on_next_frameandWindow::resizeon an idle window both draw.Repaint latency is unchanged or lower: Windows 15.5-31 ms on both (vblank-aligned), X11 2.0 ms head vs 4.1 ms base.
Tests.
frame_request_tests::a_paused_window_skips_vsync_redraws_but_still_gets_the_device_lost_forced_render(Windows, WARP device) pauses a window, checks the vsync loop skips it, runs the realhandle_gpu_device_lostand checks the paused window still receivesWM_GPUI_GPU_DEVICE_LOSTandWM_GPUI_FORCE_UPDATE_WINDOW, then checks a frame request resumes the redraws and the paused list empties.a_manipulation_lasts_through_its_inertia_until_the_viewport_is_readydrives the Direct Manipulation event handler throughRUNNING,INERTIAandREADY.How it was measured
Scratch branch
ci/idle-vblank-ab(runs linked above):windows-2022, because Blacksmith Windows runs jobs in session 0, which has no desktop.blacksmith-8vcpu-ubuntu-2404under Xvfb with Mesa lavapipe.../zed-capand rebuilds.NtQuerySystemInformationandQueryThreadCycleTimeon Windows, and from/proc/<pid>/task/*/statusandschedstaton Linux.

Confidence Score: 5/5
The PR appears safe to merge; no actionable new issues were found.Summary
Stops idle-window redraw requests on Windows and X11 while keeping on-demand redraws available.
Tests were not run during this review.
Reviews (3) · Last reviewed commit: "ci: run the Direct Manipulation test wit..." · Reviewed by Greptile