Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

<!-- cspell:ignore gshared -->

> **One-line summary**: Keep the measured physical-two handler-entry map and
> holder-local flat-dispatch count read; the targeted post-phase state bundle
> and other small-container, dispatch-switch, and private-pool candidates failed
> explicit timing or storage gates and were reverted.
> **One-line summary**: Keep the measured physical-two handler-entry map,
> holder-local flat-dispatch count read, and same-trial deregistration
> diagnostic; the targeted post-phase state bundle and other small-container,
> dispatch-switch, and private-pool candidates failed explicit timing or storage
> gates and were reverted.

## Decision rule

Expand Down Expand Up @@ -36,6 +37,31 @@ separately.
`DispatchSnapshot.entryCount` as lifecycle/topology telemetry, but do not route
the hot loop through the extra owner.

## Accepted measurement method

- Keep the joint deregistration palindrome. Its predecessor minimized four
independent seven-trial windows, so the reported H/B/B/H arms could come from
four different host phases. The corrected diagnostic prepares four fresh
populations per trial, measures them back-to-back, balances four forward and
four reverse preparation opportunities, and selects one complete trial. Its
marker retains every trial's direction and total so the floor is independently
auditable. The loaded Mono assembly passed 48
contract cases, including whole-sample selection and an enforced H/B/B/H
execution-order contract. Four
fresh-population invocations in one already-loaded Mono editor qualified only
two samples under the predeclared 3% gates; the two rejected samples measured
3.70% handler drift with 5.13% handler-excess spread and 3.03% bus drift. A
separate warmed raw distribution qualified all seven trials. The method stops
mixing arms from different host phases, but that intermittent invocation result
does not authorize the exact-`MessageBus` candidate. The final balanced
eight-trial marker independently rejected itself at 3.79% handler-excess spread.
Require repeated
interpretable Standalone IL2CPP Release brackets before making that runtime
edit. Four simultaneous populations deliberately increase diagnostic-only peak
memory: the existing 131072 cardinality keeps the shortest direct-bus arm near
10 ms, and preparing all arms first avoids allocation-heavy setup between their
timestamps.

## Rejected runtime candidates

- Do not bundle `RunTargetedPostPhases<TMessage>`'s immutable arguments into a
Expand Down
47 changes: 29 additions & 18 deletions Tests/Runtime/Benchmarks/DispatchThroughputBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,29 +218,40 @@ public void DirectAndTokenDispatchTwinPalindromeDiagnostic()
[Test, Performance, Category("PerfBench"), Order(DeregistrationAttributionDiagnosticOrder)]
public void DirectHandlerAndBusDeregistrationPalindromeDiagnostic()
{
DispatchBenchmarkResult handlerA = DeregistrationAttributionBenchmarks.RunScenario(
DeregistrationAttributionOperation.DirectHandler
DeregistrationAttributionPalindromeDiagnostic diagnostic =
DeregistrationAttributionBenchmarks.RunPairedDiagnostic();
Assert.IsTrue(
diagnostic.JointTrialSelection,
"The measured diagnostic must select one complete trial."
);
DispatchBenchmarkResult busA = DeregistrationAttributionBenchmarks.RunScenario(
DeregistrationAttributionOperation.DirectBus
Assert.IsTrue(
diagnostic.SameTrialArms,
"The measured diagnostic must retain all four arms from one trial."
);
DispatchBenchmarkResult busB = DeregistrationAttributionBenchmarks.RunScenario(
DeregistrationAttributionOperation.DirectBus
Assert.IsTrue(
diagnostic.PreparationDirectionAlternated,
"The measured diagnostic must alternate preparation direction across trials."
);
DispatchBenchmarkResult handlerB = DeregistrationAttributionBenchmarks.RunScenario(
DeregistrationAttributionOperation.DirectHandler
Assert.AreEqual(
DeregistrationAttributionBenchmarks.PalindromeTimingTrials,
diagnostic.TimingTrials,
"The measured diagnostic must report its actual trial count."
);

// Each arm independently selects its minimum from seven fresh populations. That
// rejects interruptions but loses cross-path covariance: interpretable=true is
// necessary for a later candidate bracket, never sufficient acceptance evidence.
DeregistrationAttributionPalindromeDiagnostic diagnostic =
DeregistrationAttributionBenchmarks.AnalyzePalindrome(
handlerA.WallClockMs,
busA.WallClockMs,
busB.WallClockMs,
handlerB.WallClockMs
string[] trialRecords = diagnostic.TrialSequence.Split(',');
Assert.AreEqual(
DeregistrationAttributionBenchmarks.PalindromeTimingTrials,
trialRecords.Length,
"The measured diagnostic must retain every trial record."
);
for (int trial = 0; trial < trialRecords.Length; trial++)
{
string expectedPrefix = $"{trial}:{((trial & 1) == 0 ? 'F' : 'R')}:";
StringAssert.StartsWith(
expectedPrefix,
trialRecords[trial],
$"trial={trial}, expectedPrefix={expectedPrefix}: trial provenance changed."
);
}
string evidence = diagnostic.ToStructuredLog();
Debug.Log(evidence);
TestContext.Out.WriteLine(evidence);
Expand Down
183 changes: 163 additions & 20 deletions Tests/Runtime/Benchmarks/RegistrationLifecycleBenchmarkContractTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -284,13 +284,12 @@ public void DeregistrationPalindromeClassifiesEveryEvidenceBoundary(
int expectedClassification
)
{
DeregistrationAttributionPalindromeDiagnostic diagnostic =
DeregistrationAttributionBenchmarks.AnalyzePalindrome(
handlerA,
busA,
busB,
handlerB
);
DeregistrationAttributionPalindromeDiagnostic diagnostic = AnalyzePalindrome(
handlerA,
busA,
busB,
handlerB
);
int actualClassification =
(diagnostic.HandlerDriftWithinThreshold ? 1 : 0)
| (diagnostic.BusDriftWithinThreshold ? 2 : 0)
Expand All @@ -312,10 +311,18 @@ int expectedClassification
[Category("PerfBench")]
public void DeregistrationPalindromeIsArmSwapInvariant()
{
DeregistrationAttributionPalindromeDiagnostic first =
DeregistrationAttributionBenchmarks.AnalyzePalindrome(198.5d, 100d, 101d, 200.5d);
DeregistrationAttributionPalindromeDiagnostic swapped =
DeregistrationAttributionBenchmarks.AnalyzePalindrome(200.5d, 101d, 100d, 198.5d);
DeregistrationAttributionPalindromeDiagnostic first = AnalyzePalindrome(
198.5d,
100d,
101d,
200.5d
);
DeregistrationAttributionPalindromeDiagnostic swapped = AnalyzePalindrome(
200.5d,
101d,
100d,
198.5d
);

Assert.AreEqual(
first.HandlerDriftPercent,
Expand Down Expand Up @@ -343,8 +350,12 @@ public void DeregistrationPalindromeIsArmSwapInvariant()
[Category("PerfBench")]
public void DeregistrationPalindromeLogRejectsAcceptanceMeaning()
{
DeregistrationAttributionPalindromeDiagnostic diagnostic =
DeregistrationAttributionBenchmarks.AnalyzePalindrome(130d, 100d, 101d, 131d);
DeregistrationAttributionPalindromeDiagnostic diagnostic = AnalyzePalindrome(
130d,
100d,
101d,
131d
);
string evidence = diagnostic.ToStructuredLog();

Assert.AreEqual(
Expand Down Expand Up @@ -373,9 +384,9 @@ public void DeregistrationPalindromeLogRejectsAcceptanceMeaning()
"The log must retain each threshold decision."
);
StringAssert.Contains(
"independentMinima=true diagnosticOnly=true acceptanceEvidence=false candidateCompared=false interpretable=true",
"handlerFirstPairTotal_ms=230 busFirstPairTotal_ms=232 palindromeTotal_ms=462 selectedTrial=-1 prepareForward=false jointTrialSelection=false sameTrialArms=false preparationDirectionAlternated=false timingTrials=0 trialSequence=none diagnosticOnly=true acceptanceEvidence=false candidateCompared=false interpretable=true",
evidence,
"The log must reject acceptance meaning for independently selected minima."
"Arithmetic-only diagnostics must not claim measured selection provenance."
);
StringAssert.DoesNotContain(
" valid=",
Expand All @@ -388,11 +399,8 @@ public void DeregistrationPalindromeLogRejectsAcceptanceMeaning()
[Category("PerfBench")]
public void DeregistrationPalindromeLogDistinguishesExactAndJustOverThreshold()
{
string exact = DeregistrationAttributionBenchmarks
.AnalyzePalindrome(1100d, 100d, 103d, 1103d)
.ToStructuredLog();
string justOver = DeregistrationAttributionBenchmarks
.AnalyzePalindrome(1100d, 100d, 103.000001d, 1103.000001d)
string exact = AnalyzePalindrome(1100d, 100d, 103d, 1103d).ToStructuredLog();
string justOver = AnalyzePalindrome(1100d, 100d, 103.000001d, 1103.000001d)
.ToStructuredLog();

Assert.AreNotEqual(
Expand Down Expand Up @@ -422,6 +430,88 @@ public void DeregistrationPalindromeLogDistinguishesExactAndJustOverThreshold()
);
}

[Test]
[Category("PerfBench")]
[TestCase(false)]
[TestCase(true)]
public void DeregistrationPalindromeFloorKeepsAllArmsFromOneTrial(bool prepareForward)
{
DeregistrationAttributionPalindromeSample current = PalindromeSample(
120d,
10d,
9d,
121d,
trial: 2,
prepareForward
);
DeregistrationAttributionPalindromeSample mixedArmTrap = PalindromeSample(
100d,
40d,
50d,
90d,
trial: 3,
!prepareForward
);
DeregistrationAttributionPalindromeSample faster = PalindromeSample(
121d,
8d,
8d,
120d,
trial: 4,
!prepareForward
);

DeregistrationAttributionPalindromeSample kept =
DeregistrationAttributionBenchmarks.SelectPalindromeFloor(current, mixedArmTrap);
AssertPalindromeSample(
current,
kept,
$"prepareForward={prepareForward}: retained sample"
);

DeregistrationAttributionPalindromeSample replaced =
DeregistrationAttributionBenchmarks.SelectPalindromeFloor(current, faster);
AssertPalindromeSample(
faster,
replaced,
$"prepareForward={prepareForward}: replacement sample"
);
}

[Test]
[Category("PerfBench")]
[TestCase(0, DeregistrationAttributionOperation.DirectHandler)]
[TestCase(1, DeregistrationAttributionOperation.DirectBus)]
[TestCase(2, DeregistrationAttributionOperation.DirectBus)]
[TestCase(3, DeregistrationAttributionOperation.DirectHandler)]
public void DeregistrationPalindromeExecutionOrderIsSymmetric(
int armIndex,
DeregistrationAttributionOperation expectedOperation
)
{
Assert.AreEqual(
expectedOperation,
DeregistrationAttributionBenchmarks.PalindromeOperationAt(armIndex),
$"armIndex={armIndex}, expectedOperation={expectedOperation}: the timed execution sequence must remain H/B/B/H."
);
}

[Test]
[Category("PerfBench")]
[TestCase(-1)]
[TestCase(4)]
public void DeregistrationPalindromeRejectsUnknownArmIndex(int armIndex)
{
ArgumentOutOfRangeException exception = Assert.Throws<ArgumentOutOfRangeException>(() =>
DeregistrationAttributionBenchmarks.PalindromeOperationAt(armIndex)
);
Assert.AreEqual(
nameof(armIndex),
exception.ParamName,
$"armIndex={armIndex}: the diagnostic must reject an arm outside H/B/B/H."
);
}

[Test]
public void PublishedDispatchAndAttributionUseSameSupportedMethodOrderBoundary()
{
Expand Down Expand Up @@ -597,6 +687,59 @@ private static IEnumerable<TestCaseData> DeregistrationPalindromeCases()
);
}

private static DeregistrationAttributionPalindromeDiagnostic AnalyzePalindrome(
double handlerA,
double busA,
double busB,
double handlerB
)
{
return DeregistrationAttributionBenchmarks.AnalyzePalindrome(
handlerA,
busA,
busB,
handlerB
);
}

private static DeregistrationAttributionPalindromeSample PalindromeSample(
double handlerA,
double busA,
double busB,
double handlerB,
int trial,
bool prepareForward
)
{
return new DeregistrationAttributionPalindromeSample(
handlerA,
busA,
busB,
handlerB,
trial,
prepareForward
);
}

private static void AssertPalindromeSample(
DeregistrationAttributionPalindromeSample expected,
DeregistrationAttributionPalindromeSample actual,
string context
)
{
Assert.AreEqual(expected.HandlerA, actual.HandlerA, $"{context}: handler A changed.");
Assert.AreEqual(expected.BusA, actual.BusA, $"{context}: bus A changed.");
Assert.AreEqual(expected.BusB, actual.BusB, $"{context}: bus B changed.");
Assert.AreEqual(expected.HandlerB, actual.HandlerB, $"{context}: handler B changed.");
Assert.AreEqual(expected.Trial, actual.Trial, $"{context}: trial changed.");
Assert.AreEqual(
expected.PrepareForward,
actual.PrepareForward,
$"{context}: preparation direction changed."
);
Assert.AreEqual(expected.TotalMs, actual.TotalMs, $"{context}: total changed.");
}

private static TestCaseData PalindromeCase(
string name,
double handlerA,
Expand Down
Loading
Loading