diff --git a/tests/AcDream.App.Tests/Diagnostics/ConnectedR6SoakContractTests.cs b/tests/AcDream.App.Tests/Diagnostics/ConnectedR6SoakContractTests.cs index 53ef5409..84061a32 100644 --- a/tests/AcDream.App.Tests/Diagnostics/ConnectedR6SoakContractTests.cs +++ b/tests/AcDream.App.Tests/Diagnostics/ConnectedR6SoakContractTests.cs @@ -236,15 +236,24 @@ public sealed class ConnectedR6SoakContractTests // records can masquerade as retained memory in the return gate. // The script previously slept only 12s despite the comment already // citing the 25s deadline. - string source = File.ReadAllText(Path.Combine( + string script = File.ReadAllText(Path.Combine( FindRepoRoot(), "tools", "run-connected-r6-soak.ps1")); + string route = File.ReadAllText(Path.Combine( + FindRepoRoot(), + "tools", + "connected-r6-soak.route.txt")); AssertAppearsInOrder( - source, - "LiveEntityLivenessController's authoritative absence deadline is 25", - "Start-Sleep -Seconds 26"); + script, + "LiveEntityLivenessController's 25-second authoritative absence", + "$checkpointPattern =", + "Wait-ForLogPattern $process $stdoutLog $checkpointPattern", + "$stationaryProfiles = Get-FrameProfiles $stdoutLog", + "Capture-Sample $process $destination.Name 'stationary'"); + Assert.Equal(9, CountOccurrences(route, "sleep 27000")); + Assert.Equal(9, CountOccurrences(route, "sleep 3000")); } [Fact] diff --git a/tools/connected-dense-town.route.txt b/tools/connected-dense-town.route.txt index bf143348..3cb30812 100644 --- a/tools/connected-dense-town.route.txt +++ b/tools/connected-dense-town.route.txt @@ -14,6 +14,7 @@ sleep 8000 input down MovementTurnRight sleep 6000 input up MovementTurnRight -sleep 26000 +sleep 27000 screenshot arwic-dense 10000 checkpoint arwic-dense +sleep 3000 diff --git a/tools/connected-r6-soak.route.txt b/tools/connected-r6-soak.route.txt index 8786fbc0..00a92552 100644 --- a/tools/connected-r6-soak.route.txt +++ b/tools/connected-r6-soak.route.txt @@ -45,9 +45,10 @@ sleep 500 input up MovementForward sleep 700 input press CombatToggleCombat -sleep 7400 +sleep 27000 screenshot caul-baseline 10000 checkpoint caul-baseline +sleep 3000 # Sawato baseline. command /teleloc 0x3032001C 83.3 89.2 133.005 1 0 0 0 @@ -56,9 +57,10 @@ sleep 8000 input down MovementTurnRight sleep 6000 input up MovementTurnRight -sleep 22000 +sleep 27000 screenshot sawato-baseline 10000 checkpoint sawato-baseline +sleep 3000 # Rynthid world-edge streaming. command /teleloc 0xF6820033 145.7 49.855 58.010 1 0 0 0 @@ -67,9 +69,10 @@ sleep 8000 input down MovementTurnRight sleep 6000 input up MovementTurnRight -sleep 22000 +sleep 27000 screenshot rynthid 10000 checkpoint rynthid +sleep 3000 # Aerlinthe dense island. command /teleloc 0x09040008 11.4 188.6 87.705 1 0 0 0 @@ -78,9 +81,10 @@ sleep 8000 input down MovementTurnRight sleep 6000 input up MovementTurnRight -sleep 22000 +sleep 27000 screenshot aerlinthe 10000 checkpoint aerlinthe +sleep 3000 # Same-location lifecycle revisit. command /teleloc 0x3032001C 83.3 89.2 133.005 1 0 0 0 @@ -89,9 +93,10 @@ sleep 8000 input down MovementTurnRight sleep 6000 input up MovementTurnRight -sleep 22000 +sleep 27000 screenshot sawato-return 10000 checkpoint sawato-return +sleep 3000 # Holtburg mixed-town workload + local exercise. command /teleloc 0xA9B40019 84.0 7.1 94.005 1 0 0 0 @@ -128,9 +133,10 @@ sleep 500 input up MovementForward sleep 700 input press CombatToggleCombat -sleep 7400 +sleep 27000 screenshot holtburg 10000 checkpoint holtburg +sleep 3000 # Caul return/leak oracle + final local exercise. command /teleloc 0xC95B0001 14.8 0.3 12.005 1 0 0 0 @@ -167,9 +173,10 @@ sleep 500 input up MovementForward sleep 700 input press CombatToggleCombat -sleep 15000 +sleep 27000 screenshot caul-return 10000 checkpoint caul-return +sleep 3000 # A second warm-cache Sawato/Caul revisit is the plateau oracle. The first # circuit intentionally warms bounded DAT/GPU caches, so comparing the cold @@ -181,9 +188,10 @@ sleep 8000 input down MovementTurnRight sleep 6000 input up MovementTurnRight -sleep 22000 +sleep 27000 screenshot sawato-plateau 10000 checkpoint sawato-plateau +sleep 3000 command /teleloc 0xC95B0001 14.8 0.3 12.005 1 0 0 0 wait materialized 9 60000 @@ -191,6 +199,7 @@ sleep 8000 input down MovementTurnRight sleep 6000 input up MovementTurnRight -sleep 22000 +sleep 27000 screenshot caul-plateau 10000 checkpoint caul-plateau +sleep 3000 diff --git a/tools/run-connected-r6-soak.ps1 b/tools/run-connected-r6-soak.ps1 index 22a44f39..2a010232 100644 --- a/tools/run-connected-r6-soak.ps1 +++ b/tools/run-connected-r6-soak.ps1 @@ -19,7 +19,12 @@ if ([string]::IsNullOrWhiteSpace($Password)) { $Password = 'testpassword' } if ($DenseTown) { [object[]]$destinations = @( - [pscustomobject]@{ Name = 'Arwic dense'; Occurrence = 1; Exercise = $false } + [pscustomobject]@{ + Name = 'Arwic dense' + Checkpoint = 'arwic-dense' + Occurrence = 1 + Exercise = $false + } ) [string[]]$expectedCheckpointNames = @('arwic-dense') $routeFileName = 'connected-dense-town.route.txt' @@ -27,15 +32,15 @@ if ($DenseTown) { } else { [object[]]$destinations = @( - [pscustomobject]@{ Name = 'Caul'; Occurrence = 1; Exercise = $true }, - [pscustomobject]@{ Name = 'Sawato'; Occurrence = 2; Exercise = $false }, - [pscustomobject]@{ Name = 'Rynthid'; Occurrence = 3; Exercise = $false }, - [pscustomobject]@{ Name = 'Aerlinthe'; Occurrence = 4; Exercise = $false }, - [pscustomobject]@{ Name = 'Sawato revisit'; Occurrence = 5; Exercise = $false }, - [pscustomobject]@{ Name = 'Holtburg'; Occurrence = 6; Exercise = $true }, - [pscustomobject]@{ Name = 'Caul return'; Occurrence = 7; Exercise = $true }, - [pscustomobject]@{ Name = 'Sawato plateau'; Occurrence = 8; Exercise = $false }, - [pscustomobject]@{ Name = 'Caul plateau'; Occurrence = 9; Exercise = $false } + [pscustomobject]@{ Name = 'Caul'; Checkpoint = 'caul-baseline'; Occurrence = 1; Exercise = $true }, + [pscustomobject]@{ Name = 'Sawato'; Checkpoint = 'sawato-baseline'; Occurrence = 2; Exercise = $false }, + [pscustomobject]@{ Name = 'Rynthid'; Checkpoint = 'rynthid'; Occurrence = 3; Exercise = $false }, + [pscustomobject]@{ Name = 'Aerlinthe'; Checkpoint = 'aerlinthe'; Occurrence = 4; Exercise = $false }, + [pscustomobject]@{ Name = 'Sawato revisit'; Checkpoint = 'sawato-return'; Occurrence = 5; Exercise = $false }, + [pscustomobject]@{ Name = 'Holtburg'; Checkpoint = 'holtburg'; Occurrence = 6; Exercise = $true }, + [pscustomobject]@{ Name = 'Caul return'; Checkpoint = 'caul-return'; Occurrence = 7; Exercise = $true }, + [pscustomobject]@{ Name = 'Sawato plateau'; Checkpoint = 'sawato-plateau'; Occurrence = 8; Exercise = $false }, + [pscustomobject]@{ Name = 'Caul plateau'; Checkpoint = 'caul-plateau'; Occurrence = 9; Exercise = $false } ) [string[]]$expectedCheckpointNames = @( 'caul-baseline', @@ -744,13 +749,20 @@ try { Write-Marker "turn-sample destination='$($destination.Name)' cpuP95=$($turnSample.CpuP95Ms) gpuP95=$($turnSample.GpuP95Ms)" $null = Wait-ForLogPattern $process $stdoutLog '[input] MovementTurnRight Release' $destination.Occurrence 12 - # LiveEntityLivenessController's authoritative absence deadline is 25 - # seconds. Sample only after that deadline so a previous destination's - # records cannot masquerade as retained memory in the return gate. - Start-Sleep -Seconds 26 - $stationaryProfileStart = (Get-FrameProfiles $stdoutLog).Count - $stationaryResult = Wait-ForNextFrameProfile $process $stdoutLog $stationaryProfileStart 12 - $stationarySample = Capture-Sample $process $destination.Name 'stationary' $stationaryResult.Line + # Each route block dwells 27 seconds after its final input (past + # LiveEntityLivenessController's 25-second authoritative absence + # deadline), then emits a named checkpoint and holds for three more + # seconds. Bind the process/title sample to that barrier rather than + # racing a free-running sleep against the next teleport. + $checkpointPattern = + "[world-gate] checkpoint name=$($destination.Checkpoint) sequence=$($destination.Occurrence)" + $null = Wait-ForLogPattern $process $stdoutLog $checkpointPattern 1 60 + $stationaryProfiles = Get-FrameProfiles $stdoutLog + if ($stationaryProfiles.Count -eq 0) { + throw "no frame-prof report exists at checkpoint '$($destination.Checkpoint)'" + } + $stationarySample = + Capture-Sample $process $destination.Name 'stationary' $stationaryProfiles[-1] Write-Marker "stationary-sample destination='$($destination.Name)' wsMiB=$($stationarySample.WorkingSetMiB) privateMiB=$($stationarySample.PrivateMiB) ent=$($stationarySample.EntityCount) anim=$($stationarySample.AnimationCount) updateP95=$($stationarySample.UpdateP95Ms)" if ($destination.Exercise) {