Repository navigation
[M2-PROF-01] CPU/GPU render timing (RENDER-005) - #96
Merged
Merged
Conversation
…PU measurement) Per-pass CPU phase times (batch, sort, submit) from the render-thread timers; opt-in per-pass GPU time via one reused GL TIME_ELAPSED query object (one frame late, honest 'n/a' headless — never a fake number); stall detection for the CPU waiting on the GPU's implicit upload sync (one rate-limited Warn per stalled frame); the M1-PROF-01 profiler gains the primitive-typed render feeds (text/JSON/summary surfaces). Tests: ctest -R render_timing (8 tests: the stallThresholdUs validation + stopped state, the CPU phase times with exact totals, the GPU timing's one-frame-late semantics, the stall detection, and the slow-shader fixture with GPU time > CPU time on a hardware-GL runner, SKIPPED on software renderers) + the profiler counter-model render-timing tests. laige-api.json 1815 -> 1851 symbols; budgets.json unchanged (17). Local 4-tree Linux gate green (117/117, 117/117, 112/112, 112/112 minus the 10 GL-creating entries per the GPU policy); include-lint + determinism-lint green. Roadmap box checked; Progress Board M2 29/33 (total 75/194).
The GL test suites passed SpriteRenderer::Options{} defaults to
makeScene; the default maxInstances/maxAtlases are 0, outside the
documented domain [1, ...], so SpriteRenderer::create failed
invalid_argument on every P0 CI runner (first CI run 38303505479:
the render_timing + unfiltered laige-render_tests entries aborted on
all three Linux trees). The tests now set the per-scene budgets
explicitly (16 instances / 2 atlases, 8192 for the stall scene).
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.
[M2-PROF-01] CPU/GPU render timing (RENDER-005)
Implements the M2-PROF-01 step exactly per its Scope/Verify clauses in
roadmap/M2-rendering-2.5d.md: CPU and GPU measured independently — per-pass CPU phase times (batch, sort, submit) from the render-thread timers, per-pass GPU time via a GLTIME_ELAPSEDquery object (opt-in, one frame late, honest "n/a" headless), stall detection for the CPU waiting on the GPU's implicit upload sync (rate-limited), and the profiler feed of the render values.API
SpriteBatcher—SpriteBatchTiming(frameTiming():batchMs= the frame window,beginFrame()/create up tobuild()start;sortMs=build()itself) +SpriteBatchTimingTotals(timingTotals(), successful builds only). Twosteady_clockreads per frame (+ one at create), no allocation.SpriteRenderer::Options—gpuTiming(off by default; ONE reusedGL_TIME_ELAPSEDquery object created atcreate, a begin/end pair around the pass, one availability read per frame — no per-frame GL allocation, no CPU/GPU synchronization) +stallThresholdUs(documented defaultkSpriteRendererDefaultStallUs= 2000 us ≈ 12% of a 60 Hz frame; domain[1, 0xFFFFFFFF];createvalidation, first failure wins, theoptions_invalidwarn).SpriteDrawStats—submitMs,uploadWallUs,uploadStalled,gpuTimeUs/gpuTimeValid(one frame late: frame N reports frame N−1's pass;gpuTimeValidfalse = "n/a" — first frame, GPU more than one frame behind, or an environment without working timing queries; never a fake number; a failed submit poisons only its own in-flight measurement).SpriteDrawTotals— thesubmitMs,uploadStallUs/uploadStallFrames,gpuTimeUs/gpuTimeFramessums.glBufferSubDatainto the reused instance buffer; its CPU wall time above the threshold →uploadStalled+ one rate-limited Warnsprite_renderer/submit_stall(fieldsstall_us,upload_bytes). Observation, never an execution gate (the G-R2 precedent).laige-simcannot depend onlaige-rendertypes, ARCH-001):addRenderBatchMs/addRenderSortMs/addRenderSubmitMs/addRenderGpu/addRenderStall/setRenderTextureMemory; thelaige-profile render:text line, the JSON report's"render"object (gpu_usisnulluntil the first completed measurement), and the summary line's render fields (render_gpu_us=n/aon the same rule). The engine's render-thread wiring lands with the engine integration step (theaddDrawCallsfeed precedent).textureMemoryBytes()gauge now feeds the profiler.Tests
render_timing_tests.cpp(new CTest entryrender_timing= the step's Verify command; 8 tests / 5 suites):RenderTimingCreate(GL-free: thestallThresholdUsvalidation + first-failure-wins + the stopped state reads zero),RenderTimingCpu(GL: the CPU phase times, the EXACT totals accumulation, the empty frame records nothing, the profiler feed wiring),RenderTimingGpu(GL: off-by-default "n/a"; on: the one-frame-late semantics underglFinish-paced frames, exact totals),RenderTimingStall(GL: the 4096-sprite frame under a 1 us threshold stalls — one Warn per stalled frame with the pinned fields; the small frame under the default threshold does not),RenderTimingSlowShader(GL: the deliberately slow shader — a 16384-iteration dependent sin loop — with the GPU-side pass time EXCEEDING the CPU-side submit time on a hardware-GL runner; SKIPS on a software renderer, where the CPU is the GPU and the driver is synchronous).profiler_tests.cpp— the render-timing counter-model tests (the exact accumulation, the "n/a" GPU contract, the disabled no-op preserving state, the greppable text/JSON report surfaces, the zero-alloc record path now covering the 6 render feeds).GTEST_SKIPwhere no usable OpenGL 3.3) + the ASandetect_leaks=0/ TSan property entries;TIMEOUT 120.Docs / surface
docs/api/sprite_renderer.md(new "Render timing" section + the API/Performance/traps updates),docs/api/sprite_batcher.md(the timing fields),docs/api/profiler.md(the counter table, summary line, text line, JSON object), both module READMEs,tools/README.md(the report schema line).laige-api.jsonregenerated LAST (1815 → 1851 symbols, 48 headers).budgets.jsonunchanged (17 entries — the timing is O(1) bookkeeping; the composite 50k render-CPU budget is measured with M2-PERF-01).Verification
ctestminus the GL-creating entries (GPU local-execution policy; the CI lanes run them unfiltered) — results in the Change Log row.laige-include-lint+laige-determinism-lintgreen;api-real-tree/api-check-freshin the gate.ctest -R render_timingon every P0 OS job (Linux llvmpipe + Windows desktop runner — the slow-shader GPU>CPU observation is defined for the hardware-GL desktop runner; macOS runners skip all GL, documented).Size: beyond the ~250-line roadmap guidance (the documented contract spans renderer + batcher + profiler + five docs, per CORE-006/DOC-004) — noted in the Shipped entry.