summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Kernel.Tests
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-20 19:32:52 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-20 19:32:52 +0800
commit6f904d6f8528bd13941894af3db16d0bc3b0aeb3 (patch)
treeedb64713930b99d9e3e9daf2c7c9dcba411f60b9 /src/LivingVillage.Kernel.Tests
parent7a7f14a1a036801b6d27953f6edc4e4a2f7b2efb (diff)
downloadliving-village-6f904d6f8528bd13941894af3db16d0bc3b0aeb3.tar.gz
perf: add simulation baseline probe
Diffstat (limited to 'src/LivingVillage.Kernel.Tests')
-rw-r--r--src/LivingVillage.Kernel.Tests/LivingVillage.Kernel.Tests.fsproj2
-rw-r--r--src/LivingVillage.Kernel.Tests/PerformanceTests.fs51
2 files changed, 53 insertions, 0 deletions
diff --git a/src/LivingVillage.Kernel.Tests/LivingVillage.Kernel.Tests.fsproj b/src/LivingVillage.Kernel.Tests/LivingVillage.Kernel.Tests.fsproj
index b30fc8f..f618dc9 100644
--- a/src/LivingVillage.Kernel.Tests/LivingVillage.Kernel.Tests.fsproj
+++ b/src/LivingVillage.Kernel.Tests/LivingVillage.Kernel.Tests.fsproj
@@ -12,6 +12,7 @@
<Compile Include="TradeTests.fs" />
<Compile Include="M5Tests.fs" />
<Compile Include="M6aTests.fs" />
+ <Compile Include="PerformanceTests.fs" />
</ItemGroup>
<ItemGroup>
@@ -22,6 +23,7 @@
<ItemGroup>
<ProjectReference Include="..\LivingVillage.Kernel\LivingVillage.Kernel.fsproj" />
+ <ProjectReference Include="..\LivingVillage.Headless\LivingVillage.Headless.fsproj" />
</ItemGroup>
</Project>
diff --git a/src/LivingVillage.Kernel.Tests/PerformanceTests.fs b/src/LivingVillage.Kernel.Tests/PerformanceTests.fs
new file mode 100644
index 0000000..c7e65e4
--- /dev/null
+++ b/src/LivingVillage.Kernel.Tests/PerformanceTests.fs
@@ -0,0 +1,51 @@
+namespace LivingVillage.Kernel.Tests
+
+open System
+open System.Diagnostics
+open Microsoft.VisualStudio.TestTools.UnitTesting
+open LivingVillage.Headless
+
+[<TestClass>]
+type PerformanceTests () =
+
+ let testConfiguration =
+ { PerformanceProbe.defaultConfiguration with
+ WarmupTicks = 32
+ MeasureTicks = 256
+ Repetitions = 1 }
+
+ [<TestMethod>]
+ member _.FixedSeedAndInputSequenceProduceTheSameWorldDigest () =
+ let first = PerformanceProbe.runSteps testConfiguration
+ let second = PerformanceProbe.runSteps testConfiguration
+
+ Assert.AreEqual<int64>(
+ int64 (testConfiguration.WarmupTicks + testConfiguration.MeasureTicks),
+ first.Tick)
+ Assert.AreEqual<int>(testConfiguration.NpcCount, first.Npcs.Length)
+ Assert.AreEqual<string>(PerformanceProbe.worldDigest first, PerformanceProbe.worldDigest second)
+
+ [<TestMethod>]
+ member _.MeasurementReportsConfiguredTicksAndRuntimeCounters () =
+ let sample = PerformanceProbe.measure testConfiguration
+
+ Assert.AreEqual<int>(testConfiguration.MeasureTicks, sample.MeasureTicks)
+ Assert.AreEqual<int64>(int64 (testConfiguration.WarmupTicks + testConfiguration.MeasureTicks), sample.FinalTick)
+ Assert.AreEqual<int64>(Stopwatch.Frequency, sample.StopwatchFrequency)
+ Assert.IsTrue(sample.ElapsedStopwatchTicks > 0L)
+ Assert.IsTrue(sample.AllocatedBytes >= 0L)
+ Assert.IsTrue(sample.Gen0Collections >= 0L)
+ Assert.IsTrue(sample.Gen1Collections >= 0L)
+ Assert.IsTrue(sample.Gen2Collections >= 0L)
+ let formatted = PerformanceProbe.formatSample sample
+ Assert.IsTrue(formatted.Contains("ticks_per_second="))
+ Assert.IsTrue(formatted.Contains("allocated_bytes="))
+ Assert.IsTrue(formatted.Contains("gen0="))
+
+ [<TestMethod>]
+ member _.InvalidConfigurationReportsAUsefulFailure () =
+ let invalid = { testConfiguration with NpcCount = 0 }
+
+ match PerformanceProbe.validateConfiguration invalid with
+ | Ok () -> Assert.Fail("zero NPC configuration must be rejected")
+ | Error message -> Assert.IsTrue(message.Contains("NpcCount"))