5.1 KiB
P14: the post-P13 performance pass
P14 measured the record (push) arm against the dev pull monolith and cut its CPU cost. It ran on
feat/disaggregated from f8a9466b (start) to 781a7446 (close-out), on a Lenovo Y700 (Adreno
750) with pinned clocks.
- ESTIMATE.md: the code-based estimate, written before the first benchmark.
- BENCH.md: the final trace matrix, the layer split, CPU vs GPU binding, and what the remaining gap is made of.
- HANDOFF.md: harness commands, device state, open items.
- NEXT-draw-packet-cache.md: the design sketch for the next phase.
Headline numbers
Minecraft in FCL (the representative app check)
Setup:
- FCL Minecraft, in world.
- The library is swapped into FCL, which runs it as a plugin build without
MOBILEGL_PIPE_POISON. - Readings come from MobileGL's own fps log.
- Two launches × three steady windows of about 2 s each. Dev Espryt is three windows: its second launch died at start-up, twice.
- Clocks are pinned. Runs:
.trace-work/perf-p14/fcl-final/.
| backend | dev (pull) | feat monolith | feat inproc | feat monolith, presenting-thread CPU |
|---|---|---|---|---|
| Espryt | 228.6 | 198.3 (−13 %) | 241.5 (+6 %) | 2.43 ms/frame (dev 1.85) |
| Magma | 231.8 | 171.4 (−26 %) | 194.8 (−16 %) | 2.80 ms/frame (dev 1.64) |
Earlier in the pass, at 94705adc, the same measurement read:
- Espryt: monolith about 192, inproc about 233;
- Magma: monolith about 169, inproc about 179;
- dev: 209-245.
FCL Magma monolith did not follow the trace's improvement. Its presenting thread is busy only about 2.8 of the roughly 5.8 ms frame, so the rest is a wait. That is the first item for the next phase: an off-CPU profile of FCL Magma monolith, the same method that found the upload stall in the trace. Two attempts at it during close-out caught no game frames (FCL start-up).
Trace replay, rd12 (Minecraft 1.21.4 RD12, 1471 draws/frame), best of 3, fps
| backend | dev (pull) | monolith | inproc | shm | tcp |
|---|---|---|---|---|---|
| Espryt | 115.2 | 91.1 (start 69.8) | 111.9 (71.1) | 87.8 (62.8) | 68.7 (50.0) |
| Magma | 87.0 | 83.8 (start 45.4) | 110.0 (63.2) | 95.6 (58.6) | 69.9 (45.6) |
openra is in BENCH.md. On openra, Magma monolith now runs 2.5x faster than dev (747 vs 293), and inproc 3.6x (1052 vs 293).
Every arm is CPU-bound: GPU busy is 19-39 %, and the top thread sits at 94-99 % of a core (70-80 % on tcp).
What landed
The commits run from f8a9466b to 781a7446. Per-commit numbers are in the commit subjects.
- Magma wire draw:
- no per-draw SPIR-V rehash or allocation;
- unit sampler memo; unchanged pipeline, vertex and index binds skipped;
- direct-mapped texture and buffer fronts;
- descriptor-set rebind with fresh offsets;
- pass-continuation memo;
- vertex-input layout kept on its record;
- texture level uploads no longer wait for the GPU to drain (
553eb86d, the largest single gain of the pass: rd12 70 -> 83, openra 367 -> 745); - slices stamped from the owner's submit counter.
- Espryt:
- VAO twin re-points only the moved buffers;
- clean attachments skip resync;
- unchanged buffer sets are adopted;
- twin lookups without SharedPtr copies;
- one thread-local block;
- one UBO-ring lookup per draw.
- MG_Pipe client half:
- lifetime-id slot fronts;
- per-VAO memo;
- fill pins;
- kept VAO bindings on the server;
- uniform spans;
- context-values gate;
- inline process applier;
- precomputed residual walk, with split copy and stamp loops;
- memo-answered draw bindings.
- MG_Remote: fault-verdict polling restructured.
- It first went from every record to every 256 records (
549a34bb). - The drain now polls before any record the last poll could not have seen (
c24b3428). This fixes the regression where a guilty context ran one more record. - The apply loop hands its poll to the drain (
e058a450).
- It first went from every record to every 256 records (
- Magma hang watch: a marker slot is reused only once its submission's fence completes
(
ec973fba). - Tests and CI:
- TextureUploadBetweenDrawsScenario on every arm, plus inproc sync validation (
67f4f311,86ab2835); - submit-time synchronization validation in the run-ahead and cache gates (
781a7446); - ServerLoopEglLatchTest now holds the race window open.
- TextureUploadBetweenDrawsScenario on every arm, plus inproc sync validation (
- Tools:
- pinned-clock matrix with a per-thread CPU and GPU-busy sampler;
- layer-split and off-CPU profile helpers;
- FCL harness;
- opt-in fps log and transport override properties.
Measured and not landed
- Record-publish batching: publishing a validate's state records with the draw record. It came in within ±2 % on every arm, and it opens a deadlock class (a staging-retirement wait on a written but unpublished record).
- Native TLS (minSdk / ANDROID_PLATFORM 29): +1.7 % on Espryt, noise on Magma (rd12 monolith). This is the user's call.
- Tracker / residual mutation-epoch fast path: estimated at most 0.07 ms from the tracker alone, 0.15-0.25 ms with the residual copies. Each step is below the 2 % bar, and a missed epoch bump renders stale. It is folded into the draw-packet design.