test(teleport): tp-probe AIM/ENQ/BUILD/APPLY/PLACED instrumentation (REMOVABLE)

Acceptance apparatus for the teleport-residency fix. ACDREAM_PROBE_TELEPORT=1
gates 5 log points with cross-thread TickCount64 timestamps + the _datLock
waited/held measurement. Stripped (or promoted) at verification (plan T6).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-22 13:45:15 +02:00
parent 02f4be72c0
commit 9ac719424c
3 changed files with 52 additions and 0 deletions

View file

@ -5472,6 +5472,9 @@ public sealed class GameWindow : IDisposable
EnsureTeleportArrivalController(); EnsureTeleportArrivalController();
_pendingTeleportRot = rot; _pendingTeleportRot = rot;
_teleportArrival!.BeginArrival(newWorldPos, p.LandblockId); _teleportArrival!.BeginArrival(newWorldPos, p.LandblockId);
AcDream.Core.Physics.PhysicsDiagnostics.LogTeleport(
"AIM", p.LandblockId,
$"lb={lbX},{lbY} indoor={((p.LandblockId & 0xFFFFu) >= 0x0100u)} diffLb={differentLandblock}");
} }
} }
@ -5561,6 +5564,8 @@ public sealed class GameWindow : IDisposable
dt: 1f / 60f); dt: 1f / 60f);
_playerController.State = AcDream.App.Input.PlayerState.InWorld; _playerController.State = AcDream.App.Input.PlayerState.InWorld;
AcDream.Core.Physics.PhysicsDiagnostics.LogTeleport(
"PLACED", resolved.CellId, $"forced={forced}");
Console.WriteLine($"live: teleport complete — snapped to {snappedPos} cell=0x{resolved.CellId:X8}"); Console.WriteLine($"live: teleport complete — snapped to {snappedPos} cell=0x{resolved.CellId:X8}");
// Tell the server the client finished loading the new landblock (holtburger // Tell the server the client finished loading the new landblock (holtburger
@ -5813,6 +5818,25 @@ public sealed class GameWindow : IDisposable
// case), which blocks the render thread for at most that duration. // case), which blocks the render thread for at most that duration.
// This is the minimum correct behavior; a future pass can reduce // This is the minimum correct behavior; a future pass can reduce
// contention by pre-building render-thread work on the worker. // contention by pre-building render-thread work on the worker.
// tp-probe (2026-06-22, REMOVABLE): measure lock-WAIT (the _datLock
// contention signal — large only when the render thread is hammering the
// lock during a CreateObject flood) AND lock-HOLD (the intrinsic build
// cost). Identical work in both branches; the probe branch only adds the
// stopwatch + log. No behavior change when ProbeTeleportEnabled is false.
if (AcDream.Core.Physics.PhysicsDiagnostics.ProbeTeleportEnabled)
{
var sw = System.Diagnostics.Stopwatch.StartNew();
lock (_datLock)
{
long waitedMs = sw.ElapsedMilliseconds;
sw.Restart();
var built = BuildLandblockForStreamingLocked(landblockId, kind);
AcDream.Core.Physics.PhysicsDiagnostics.LogTeleport(
"BUILD", landblockId,
$"waited={waitedMs}ms held={sw.ElapsedMilliseconds}ms kind={kind}");
return built;
}
}
lock (_datLock) lock (_datLock)
{ {
return BuildLandblockForStreamingLocked(landblockId, kind); return BuildLandblockForStreamingLocked(landblockId, kind);
@ -6414,6 +6438,7 @@ public sealed class GameWindow : IDisposable
AcDream.Core.Terrain.LandblockMeshData meshData) AcDream.Core.Terrain.LandblockMeshData meshData)
{ {
if (_terrain is null || _dats is null) return; if (_terrain is null || _dats is null) return;
AcDream.Core.Physics.PhysicsDiagnostics.LogTeleport("APPLY", lb.LandblockId);
// Phase A.1 hotfix: render-thread path also takes the dat lock so it // Phase A.1 hotfix: render-thread path also takes the dat lock so it
// doesn't race with BuildLandblockForStreaming on the worker thread. // doesn't race with BuildLandblockForStreaming on the worker thread.

View file

@ -127,6 +127,7 @@ public sealed class LandblockStreamer : IDisposable
{ {
if (System.Threading.Volatile.Read(ref _disposed) != 0) if (System.Threading.Volatile.Read(ref _disposed) != 0)
throw new ObjectDisposedException(nameof(LandblockStreamer)); throw new ObjectDisposedException(nameof(LandblockStreamer));
AcDream.Core.Physics.PhysicsDiagnostics.LogTeleport("ENQ", landblockId, $"kind={kind}");
_inbox.Writer.TryWrite(new LandblockStreamJob.Load(landblockId, kind)); _inbox.Writer.TryWrite(new LandblockStreamJob.Load(landblockId, kind));
} }

View file

@ -423,6 +423,31 @@ public static class PhysicsDiagnostics
public static bool ProbeSweptEnabled { get; set; } = public static bool ProbeSweptEnabled { get; set; } =
Environment.GetEnvironmentVariable("ACDREAM_PROBE_SWEPT") == "1"; Environment.GetEnvironmentVariable("ACDREAM_PROBE_SWEPT") == "1";
/// <summary>
/// Teleport-foundation timing probe (2026-06-22 — REMOVABLE diagnostic).
/// Emits one <c>[tp-probe]</c> line per teleport-pipeline event with a
/// cross-thread monotonic timestamp (<see cref="Environment.TickCount64"/>)
/// so the offline reader can order AIM / ENQ / BUILD / APPLY / PLACED across
/// the render thread and the streamer worker. Disambiguates the three
/// candidate roots for "destination not resident fast": apply-THROTTLE
/// (APPLY lands before PLACED), <c>_datLock</c> CONTENTION (BUILD waited=
/// large), and a streaming-command GATE (ENQ never fires for the dest).
/// Initial state from <c>ACDREAM_PROBE_TELEPORT=1</c>. Strip after capture.
/// </summary>
public static bool ProbeTeleportEnabled { get; set; } =
Environment.GetEnvironmentVariable("ACDREAM_PROBE_TELEPORT") == "1";
/// <summary>
/// One <c>[tp-probe]</c> line. Self-guards on <see cref="ProbeTeleportEnabled"/>,
/// so callers need not pre-check (the cost when off is a single bool read).
/// </summary>
public static void LogTeleport(string point, uint id, string extra = "")
{
if (!ProbeTeleportEnabled) return;
Console.WriteLine(System.FormattableString.Invariant(
$"[tp-probe] {point,-6} id=0x{id:X8} t={Environment.TickCount64} {extra}"));
}
/// <summary> /// <summary>
/// A6.P3 issue #98 step-walk investigation (2026-05-23). When true, /// A6.P3 issue #98 step-walk investigation (2026-05-23). When true,
/// emits one <c>[step-walk]</c> line at selected points in the transition /// emits one <c>[step-walk]</c> line at selected points in the transition
@ -549,6 +574,7 @@ public static class PhysicsDiagnostics
ProbePlacementFailEnabled = false; ProbePlacementFailEnabled = false;
ProbeSweptEnabled = false; ProbeSweptEnabled = false;
ProbeStepWalkEnabled = false; ProbeStepWalkEnabled = false;
ProbeTeleportEnabled = false;
// Side-channel fields // Side-channel fields
LastBspHitPoly = null; LastBspHitPoly = null;