aboutsummaryrefslogtreecommitdiffziptar.gz
path: root/src/Godosa.Core.Tests/Diagnostics/FrameTimeStatsTests.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Godosa.Core.Tests/Diagnostics/FrameTimeStatsTests.cs')
-rw-r--r--src/Godosa.Core.Tests/Diagnostics/FrameTimeStatsTests.cs97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/Godosa.Core.Tests/Diagnostics/FrameTimeStatsTests.cs b/src/Godosa.Core.Tests/Diagnostics/FrameTimeStatsTests.cs
new file mode 100644
index 0000000..44b6758
--- /dev/null
+++ b/src/Godosa.Core.Tests/Diagnostics/FrameTimeStatsTests.cs
@@ -0,0 +1,97 @@
+using System;
+using Godosa.Core.Diagnostics;
+using Xunit;
+
+namespace Godosa.Core.Tests.Diagnostics;
+
+public class FrameTimeStatsTests
+{
+ /// <summary>99 smooth 10 ms frames plus one 100 ms hitch.</summary>
+ private static FrameTimeStats OneHitch()
+ {
+ var stats = new FrameTimeStats(capacity: 100);
+ for (int i = 0; i < 99; i++)
+ stats.Record(0.010, workSeconds: 0.002, simTicks: 0, simSeconds: 0);
+ stats.Record(0.100, workSeconds: 0.002, simTicks: 0, simSeconds: 0);
+ return stats;
+ }
+
+ [Fact]
+ public void Fps_IsFramesOverTotalTime_NotMeanOfInstantaneousFps()
+ {
+ var s = OneHitch().Summarize();
+
+ Assert.Equal(100, s.Frames);
+ // 100 frames / 1.09 s. (Mean of per-frame FPS would be (99*100 + 10)/100 = 99.1.)
+ Assert.Equal(91.743, s.Fps, 3);
+ Assert.Equal(10.9, s.AvgMs, 6);
+ }
+
+ [Fact]
+ public void Percentiles_UseNearestRank_AndMaxCatchesTheHitch()
+ {
+ var s = OneHitch().Summarize();
+
+ Assert.Equal(10.0, s.P50Ms, 6);
+ Assert.Equal(10.0, s.P95Ms, 6);
+ Assert.Equal(10.0, s.P99Ms, 6); // rank ceil(0.99*100) = 99th of 100
+ Assert.Equal(100.0, s.MaxMs, 6);
+ }
+
+ [Fact]
+ public void OnePercentLow_AveragesTheSlowestOnePercentOfFrames()
+ {
+ var s = OneHitch().Summarize();
+
+ Assert.Equal(10.0, s.OnePercentLowFps, 6); // worst 1 of 100 frames = 100 ms
+ }
+
+ [Fact]
+ public void Hitches_CountFramesOverTwiceTheMedian()
+ {
+ var stats = new FrameTimeStats(capacity: 10);
+ foreach (var ms in new[] { 10, 10, 10, 10, 10, 20, 21, 35 })
+ stats.Record(ms / 1000.0, 0, 0, 0);
+
+ Assert.Equal(2, stats.Summarize().Hitches); // median 10 → 21 and 35 (20 is not > 20)
+ }
+
+ [Fact]
+ public void Window_DropsOldestFrames()
+ {
+ var stats = new FrameTimeStats(capacity: 4);
+ foreach (var ms in new[] { 100, 100, 3, 4, 5, 6 })
+ stats.Record(ms / 1000.0, 0, 0, 0);
+
+ Span<float> intervals = stackalloc float[4];
+ int n = stats.CopyIntervalsMs(intervals);
+
+ Assert.Equal(4, n);
+ Assert.Equal(new float[] { 3, 4, 5, 6 }, intervals.ToArray());
+ Assert.Equal(6.0, stats.Summarize().MaxMs, 4);
+ }
+
+ [Fact]
+ public void Sim_ReportsAchievedTickRateAndCostPerTick()
+ {
+ var stats = new FrameTimeStats(capacity: 60);
+ for (int i = 0; i < 60; i++) // 1 s at 60 fps; a tick every other frame, 1 ms each
+ stats.Record(1.0 / 60.0, workSeconds: 0.004, simTicks: i % 2, simSeconds: (i % 2) * 0.001);
+
+ var s = stats.Summarize();
+
+ Assert.Equal(30.0, s.SimTickRate, 3);
+ Assert.Equal(1.0, s.AvgTickMs, 6);
+ Assert.Equal(4.0, s.AvgWorkMs, 6);
+ }
+
+ [Fact]
+ public void Empty_SummarizesToZerosWithoutDividingByZero()
+ {
+ var s = new FrameTimeStats().Summarize();
+
+ Assert.Equal(0, s.Frames);
+ Assert.Equal(0.0, s.Fps);
+ Assert.Equal(0.0, s.AvgTickMs);
+ }
+}