using NUnit.Framework; using VMdemo.Core; using VMdemo.Simulation; namespace VMdemo.Tests.EditMode { public class Step6StatsCollectorTests { [Test] public void StatsCollector_Reset_ClearsAllCountersAndRates() { var stats = new StatsCollector(); stats.RecordAccess(tlbHit: true, pageTableHit: false, pageFault: false, cost: 1); stats.RecordAccess(tlbHit: false, pageTableHit: false, pageFault: true, cost: 104); stats.Reset(); Assert.That(stats.TotalAccess, Is.EqualTo(0)); Assert.That(stats.TlbHit, Is.EqualTo(0)); Assert.That(stats.PageTableHit, Is.EqualTo(0)); Assert.That(stats.PageFault, Is.EqualTo(0)); Assert.That(stats.TotalCost, Is.EqualTo(0L)); Assert.That(stats.TlbHitRate, Is.EqualTo(0.0)); Assert.That(stats.PageTableHitRate, Is.EqualTo(0.0)); Assert.That(stats.AvgCost, Is.EqualTo(0.0)); } [Test] public void StatsCollector_CalculateCost_FollowsMvpCostModel() { var stats = new StatsCollector(); Assert.That(stats.CalculateCost(tlbHit: true, pageTableHit: false, pageFault: false, pageFaultPenalty: 100), Is.EqualTo(1)); Assert.That(stats.CalculateCost(tlbHit: false, pageTableHit: true, pageFault: false, pageFaultPenalty: 100), Is.EqualTo(4)); Assert.That(stats.CalculateCost(tlbHit: false, pageTableHit: false, pageFault: true, pageFaultPenalty: 100), Is.EqualTo(104)); } [Test] public void StatsCollector_RecordAccess_AggregatesCountersRatesAndAverage() { var stats = new StatsCollector(); stats.RecordAccess(tlbHit: true, pageTableHit: false, pageFault: false, cost: 1); stats.RecordAccess(tlbHit: false, pageTableHit: true, pageFault: false, cost: 4); stats.RecordAccess(tlbHit: false, pageTableHit: false, pageFault: true, cost: 104); Assert.That(stats.TotalAccess, Is.EqualTo(3)); Assert.That(stats.TlbHit, Is.EqualTo(1)); Assert.That(stats.PageTableHit, Is.EqualTo(1)); Assert.That(stats.PageFault, Is.EqualTo(1)); Assert.That(stats.TotalCost, Is.EqualTo(109L)); Assert.That(stats.TlbHitRate, Is.EqualTo(1.0 / 3.0).Within(1e-12)); Assert.That(stats.PageTableHitRate, Is.EqualTo(1.0 / 3.0).Within(1e-12)); Assert.That(stats.AvgCost, Is.EqualTo(109.0 / 3.0).Within(1e-12)); } [Test] public void TranslatorEngine_StepOnce_ToFinalize_UpdatesStatsAndCurrentCost() { var engine = CreateEngine(pageFaultPenalty: 120, seed: 31); engine.SetNextVirtualAddress(0x0000_1234UL); while (!engine.StepOnce()) { } Assert.That(engine.State.CurrentRound, Is.EqualTo(1)); Assert.That(engine.State.IsPageFault, Is.True); Assert.That(engine.State.CurrentCost, Is.EqualTo(124)); Assert.That(engine.Stats.TotalAccess, Is.EqualTo(1)); Assert.That(engine.Stats.PageFault, Is.EqualTo(1)); Assert.That(engine.Stats.TotalCost, Is.EqualTo(124L)); Assert.That(engine.Stats.AvgCost, Is.EqualTo(124.0)); } [Test] public void TranslatorEngine_RunOneAccess_TracksBatchSummaryWithMixedPaths() { var engine = CreateEngine(pageFaultPenalty: 100, seed: 41); const ulong va = 0x0000_5678UL; var first = engine.RunOneAccess(va); // page fault var second = engine.RunOneAccess(va); // tlb hit engine.TlbCache.Clear(); var third = engine.RunOneAccess(va); // page table hit Assert.IsTrue(first.PageFault); Assert.IsTrue(second.TlbHit); Assert.IsTrue(third.PageTableHit); Assert.That(engine.Stats.TotalAccess, Is.EqualTo(3)); Assert.That(engine.Stats.TlbHit, Is.EqualTo(1)); Assert.That(engine.Stats.PageTableHit, Is.EqualTo(1)); Assert.That(engine.Stats.PageFault, Is.EqualTo(1)); Assert.That(engine.Stats.TotalCost, Is.EqualTo(109L)); Assert.That(engine.Stats.TlbHitRate, Is.EqualTo(1.0 / 3.0).Within(1e-12)); Assert.That(engine.Stats.PageTableHitRate, Is.EqualTo(1.0 / 3.0).Within(1e-12)); Assert.That(engine.Stats.AvgCost, Is.EqualTo(109.0 / 3.0).Within(1e-12)); } [Test] public void TranslatorEngine_Reset_ClearsStats() { var engine = CreateEngine(pageFaultPenalty: 100, seed: 51); engine.RunOneAccess(0x0000_9ABCUL); Assert.That(engine.Stats.TotalAccess, Is.EqualTo(1)); engine.Reset(); Assert.That(engine.Stats.TotalAccess, Is.EqualTo(0)); Assert.That(engine.Stats.TlbHit, Is.EqualTo(0)); Assert.That(engine.Stats.PageTableHit, Is.EqualTo(0)); Assert.That(engine.Stats.PageFault, Is.EqualTo(0)); Assert.That(engine.Stats.TotalCost, Is.EqualTo(0L)); Assert.That(engine.Stats.AvgCost, Is.EqualTo(0.0)); Assert.That(engine.State.CurrentCost, Is.EqualTo(0)); } private static TranslatorEngine CreateEngine(int pageFaultPenalty, int seed) { var config = new SimulationConfig { vaBits = 24, pageSizeKB = 4, physicalMemoryMB = 1, tlbEntries = 4, accessCount = 20, pageFaultPenalty = pageFaultPenalty }; return new TranslatorEngine(config, seed); } } }