perf #418: publish landblocks under the meter, not one per streaming tick

Phase-1 measurement (new [publish-timing]/[stream-tick] probe surfaces,
ACDREAM_PROBE_REVEAL_TIMING=1) refuted the ~31 ms-per-admission
hypothesis: the hold runs at ~64 fps with the streaming tick at ~32 Hz,
the whole 625-block window costs only ~500 ms of publication CPU (far
blocks ~0.17 ms, near 2-43 ms), and steady state showed ZERO meter
yields with ~0.22 ms of the 2 ms budget used - yet exactly one block
published per tick against a ~400-deep completion queue.

The real limiter: Runtime's collision-generation activation is a
deliberate two-poll transaction (the first
TryAcquireCollisionPrefixMutationPermission poll parks residents and
refuses by design), and LandblockPresentationPipeline.Advance's metered
arm returned Completed=false on ANY nonterminal commit, which
DrainAndApply treats as end-of-frame. One landblock per 32 Hz tick =
the flat 32/s, with the authored budget ~90% idle.

Fix: the metered arm now uses the same Runtime-owned gate the unmetered
arm and the synchronous CompletePublication API always used
(CanContinueMutationSynchronously). The second poll runs in the same
frame under the same meter, so the unchanged 2 ms elapsed-time ceiling
is now genuinely the authoritative per-frame bound; with any real debt
(live residents parked mid-game, pending withdrawals, dispatch backlog)
publication defers to the next frame exactly as before. No budget
values change, no reveal-gate/readiness change, and the streamed result
is byte-identical - only the frame scheduling of identical operations.

Measured A/B (this binary, two runs): totalMs 12689 / 12734 vs baseline
26728/27395/27503; loaded slope 32/s -> bursts of 100-360/s, 625/625 in
~6-7 s vs ~23 s. The remaining ~12.7 s floor is fully attributed in
docs/ISSUES.md: ~8 s of real budgeted readiness work plus retail's
authored tunnel exit (TunnelContinue 2-5 s + two 1 s fades, golden
constants), so the <12 s acceptance needs a lead decision on the
hold-time budget, not another hidden limiter.

New regression pin:
MeteredLoaded_NonterminalCommitWithoutDebt_CompletesInOneMeteredAdvance.
Gates: Release build 0 errors; App tests 5576/3 skips/0 failed;
Runtime tests 1756/0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-17 20:11:35 +02:00
parent 45f379560a
commit 11106c70e7
6 changed files with 408 additions and 5 deletions

View file

@ -171,6 +171,57 @@ public sealed class LandblockConcretePresentationPipelineTests
Assert.True(fixture.State.IsLoaded(LandblockId));
}
[Fact]
public void MeteredLoaded_NonterminalCommitWithoutDebt_CompletesInOneMeteredAdvance()
{
// #418: Runtime's collision-generation activation deliberately
// refuses its FIRST CommitCollisionGeneration poll (the quiescence
// boundary parks residents and returns nonterminal). The metered
// pipeline used to defer the second poll to the next frame
// unconditionally, which serialized the login completion drain to
// exactly one landblock per streaming tick (the flat 32 blocks/s
// hold). With no cross-cutting debt the second poll must now run in
// the SAME metered advance, so a whole publication completes in one
// frame when the budget allows it.
var calls = new List<string>();
ConcreteFixture fixture = Fixture(
calls,
commitEnvCells: _ => calls.Add("envcell"));
var pipeline = new LandblockPresentationPipeline(
fixture.Render,
fixture.Physics,
fixture.Static,
fixture.State,
fixture.RetirementOwner,
onLandblockLoaded: _ => calls.Add("live-recovery"));
LandblockStreamResult.Loaded result =
Result(Build(Entity(0x80A9B401u)));
LandblockStreamCostEstimate estimate =
LandblockStreamResultCost.Estimate(result);
var budget = new StreamingWorkBudget(
TimeSpan.FromSeconds(1),
maxCompletionAdmissions: 64,
maxAdoptedCpuBytes: 1_000_000,
maxEntityOperations: 4_096,
maxGpuUploadBytes: 1_000_000,
maxGlRetireOperations: 64,
destinationReserveFraction: 0.75f);
var meter = new StreamingWorkMeter(budget);
LandblockPublicationAdvance advance = pipeline.PublishLoaded(
result,
estimate,
meter,
ensureProgress: true);
meter.FinishFrame();
Assert.True(advance.Completed);
Assert.False(pipeline.HasPendingPublication(result));
Assert.True(fixture.State.IsNearTier(LandblockId));
Assert.Equal(1, fixture.Physics.Diagnostics.CompleteCount);
Assert.Equal(1, fixture.Static.Diagnostics.CompleteCount);
}
[Fact]
public void CrossOwnerValidationFailure_BlocksBeforeAnyPresentationMutation()
{