Skip to content

perf(pan): redraw at the rate rows arrive, not the display's (FR-PAN-13) - #198

Merged
dc0sk merged 2 commits into
mainfrom
perf/gpu-load
Sep 21, 2026
Merged

dc0sk merged 2 commits into
mainfrom
perf/gpu-load

Conversation

@dc0sk

@dc0sk dc0sk commented Sep 21, 2026

Copy link
Copy Markdown
Owner

Stacked on #197 (TLS) on #196 (POTA).

Why

The integrated GPU was ~40 % busy while data flowed. The window is redrawn as a whole, so GPU load follows how often it is redrawn. While rows arrived, every frame asked for the next vsync, so a ~30 rows/s stream redrew at the panel's refresh rate (60 Hz, more on a fast panel) although a frame between two rows shows nothing new.

What

Each redraw asks for the next one a smoothed row interval ahead, kept between 8 ms (~125 fps cap) and 100 ms (never slower than the UI tick), via RedrawRequest::At. The chain still ends 300 ms after the last row and restarts with the tick.

Simulated against a display: 30 rows/s → 30.3 frames/s (was 60+), 20 → 19.7, 25 → 24.7, 62.5 → 61.8, 500 → 124.9 (capped), 4 → 10.1.

This amends FR-PAN-13, which required the display rate. The cost: a row can appear up to one row interval (~33 ms) later than on the vsync chain. If that is noticeable, the fix is a shorter interval, not a revert.

K4_FPS=1 prints frames per second, for checking.

Not measured on screen — please read

The display was asleep (eDP-1 dpms=Off) when I built this, so the compositor presented no window. My first "baseline" recorded 0–1 frames a second and 0 % GPU; that measures a blanked screen, not the app, and I discarded it rather than report it. An XWayland run (~1 fps) and a native one (0 fps) both showed no real frames while the display was off, and I read the display state only afterwards, so the two could not be told apart; whether XWayland windows are presented on this compositor with the display on is untested. A measurement needs a lit display, and the display state should be checked first. What is proven here is the logic (simulation, 24 mutations); what is predicted is roughly half the GPU load.

Findings

  • The estimate was clamped twice, so removing either clamp was masked by the other; the redundant one is deleted.
  • My tolerances let an estimate with no smoothing pass; a test that one odd frame must not swing it now fails it.
  • The one line that matters (RedrawRequest::At(at)) is invisible to pure tests; a structural guard covers it (reading only the code above its own module, so it can't match itself).

Validation parked with DC0SK (not done here)

  • With the panel on: K4_FPS=1 k4remote --demo — expect ~30 FPS (the old build shows the panel's refresh rate). Read /sys/class/drm/card0/device/gpu_busy_percent beside it, before and after; the recorded earlier figure was ~55 redraws/s at 13 % of a core.
  • Look at the waterfall and trace: still smooth? Any visible stutter on a real K4 stream?

Not done

Cheaper frames (the whole window is still redrawn each frame); a user-set frame cap.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ma4bQKqGNFTYyVSEKPcXRk

While rows arrived, every frame asked for the next vsync, so a ~30 rows/s
stream redrew the whole window at the panel's refresh rate although a frame
between two rows shows nothing new. GPU load follows how often the window is
redrawn.

Each redraw now asks for the next one a smoothed row interval ahead, kept
between 8 ms and 100 ms, via RedrawRequest::At. The chain still ends 300 ms
after the last row and restarts with the UI tick. Simulated: 30 rows/s gives
30.3 frames/s, 500 rows/s is capped at 124.9, 4 rows/s runs at 10.1.

FR-PAN-13 is amended (it required the display rate); the cost is that a row
can show up to one row interval later. K4_FPS=1 prints frames per second.

Not measured on screen: the display was asleep when this was built.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ma4bQKqGNFTYyVSEKPcXRk
I wrote that this compositor does not present XWayland windows. The only
evidence was one XWayland run and one native run, both taken while the display
was off, with the display state read afterwards; they cannot distinguish the
two, and earlier sessions captured XWayland windows fine. Recorded as untested.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ma4bQKqGNFTYyVSEKPcXRk
@dc0sk
dc0sk changed the base branch from feat/spot-tls to main September 21, 2026 18:03
@dc0sk dc0sk closed this Sep 21, 2026
@dc0sk dc0sk reopened this Sep 21, 2026
@dc0sk
dc0sk merged commit 119b0c0 into main Sep 21, 2026
5 checks passed
@dc0sk
dc0sk deleted the perf/gpu-load branch September 22, 2026 08:22
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