Skip to content

feat(diags): time the host render path in video_render_probe - #278

Merged
kfox merged 1 commit into
mainfrom
perf/render-probe-cpu-timing
Aug 13, 2026
Merged

feat(diags): time the host render path in video_render_probe#278
kfox merged 1 commit into
mainfrom
perf/render-probe-cpu-timing

Conversation

@kfox

@kfox kfox commented Aug 13, 2026

Copy link
Copy Markdown
Owner

Why

video_render_probe.py modelled what a frame costs to put on the wire but measured nothing about what it costs to produce. That leaves it unable to answer whether a given machine is fast enough to drive c64cast at all — the question that decides whether the host can be a small single-board computer instead of a laptop.

What

  • Times decode and render separately and reports mean / median / p95 / max ms per frame alongside the existing per-region write cost.
  • A verdict line naming which side, if either, actually binds the source frame rate. It compares both ceilings against the source rate, so a clip both sides clear comfortably reports "neither side binds" rather than misreading headroom as a bottleneck.
  • --threads N pins decode and OpenCV to N threads, so two machines can be compared by single-core speed rather than by core count.
  • Two new per-frame CSV columns: decode_ms, render_ms.

The frame loop now steps the decode generator by hand instead of using a for ... in container.decode(v), so the generator advance — where the decoder actually runs — can be timed apart from the render path it feeds.

The measurement this makes visible

Compose cost tracks the source resolution, not the display mode, because every mode calls cv2.resize() down to its own small target and that resize reads every source pixel:

Source mhires hires mcm petscii
3840x2160 34.3 ms 33.4 30.4 29.8
1920x1080 11.2 ms 10.4 8.0 7.6
1280x720 6.7 ms 6.0 3.8 3.4
320x200 3.0 ms 2.1 0.4 0.1

So the media, not the renderer, is usually what decides whether the host or the link is the bottleneck — which is why the verdict names pre-scaling as the fix rather than just printing a ratio.

Verification

  • Run across three source resolutions (4K, 1080p, 320x200) confirming both verdict branches and the --threads pin.
  • make check (ruff, pyright, 3801 tests) and make site-check pass.
  • Offline only — no hardware involved.

Two pre-existing ruff format findings in docs/extending.md are untouched by this branch (they fail identically with these changes stashed).

The probe modelled what a frame costs to put on the wire but measured
nothing about what it costs to produce, so it could not answer whether a
given machine is fast enough to drive c64cast — the question that decides
whether the host can be a small single-board computer rather than a laptop.

Time the decode and render halves separately (the frame loop steps the
decode generator by hand so the decoder can be timed apart from the render
path it feeds) and report them against the existing per-region link cost,
with a verdict naming which side, if either, binds the source frame rate.
Add --threads N to pin decode and OpenCV so two machines compare by
single-core speed rather than core count, and two CSV columns.

The verdict names pre-scaling as the fix because compose cost tracks the
source resolution rather than the display mode: every mode resizes the
source down to its own small target and that resize reads every source
pixel, so one frame costs ~30 ms from 4K in any mode and ~3.4-6.7 ms from
720p. The media is usually what decides whether host or link binds.
@kfox
kfox merged commit 04dbe4b into main Aug 13, 2026
19 checks passed
@kfox
kfox deleted the perf/render-probe-cpu-timing branch August 13, 2026 18:26
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