Archived
Step 1 - 参数与核心数据模型
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1f0f89f24ab6334f87c91090393ab8b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace VMdemo.Core
|
||||
{
|
||||
[Serializable]
|
||||
public struct AddressParts
|
||||
{
|
||||
public AddressParts(ulong vpn, ulong offset, ulong l1Index, ulong l2Index)
|
||||
{
|
||||
Vpn = vpn;
|
||||
Offset = offset;
|
||||
L1Index = l1Index;
|
||||
L2Index = l2Index;
|
||||
}
|
||||
|
||||
public static AddressParts Empty => new AddressParts(0UL, 0UL, 0UL, 0UL);
|
||||
|
||||
public ulong Vpn;
|
||||
public ulong Offset;
|
||||
public ulong L1Index;
|
||||
public ulong L2Index;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"VPN={Vpn}, Offset={Offset}, L1={L1Index}, L2={L2Index}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2170a834280c39d40826bf87a50a20b4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
|
||||
namespace VMdemo.Core
|
||||
{
|
||||
public static class ConfigValidator
|
||||
{
|
||||
public readonly struct DerivedConfig
|
||||
{
|
||||
public DerivedConfig(ulong pageSizeBytes, ulong physicalMemoryBytes, int offsetBits, int vpnBits, ulong frameCount)
|
||||
{
|
||||
PageSizeBytes = pageSizeBytes;
|
||||
PhysicalMemoryBytes = physicalMemoryBytes;
|
||||
OffsetBits = offsetBits;
|
||||
VpnBits = vpnBits;
|
||||
FrameCount = frameCount;
|
||||
}
|
||||
|
||||
public ulong PageSizeBytes { get; }
|
||||
public ulong PhysicalMemoryBytes { get; }
|
||||
public int OffsetBits { get; }
|
||||
public int VpnBits { get; }
|
||||
public ulong FrameCount { get; }
|
||||
}
|
||||
|
||||
public static bool TryValidate(SimulationConfig config, out string errorMessage)
|
||||
{
|
||||
return TryValidateAndBuildDerived(config, out _, out errorMessage);
|
||||
}
|
||||
|
||||
public static bool TryValidateAndBuildDerived(
|
||||
SimulationConfig config,
|
||||
out DerivedConfig derived,
|
||||
out string errorMessage)
|
||||
{
|
||||
derived = default;
|
||||
|
||||
if (config == null)
|
||||
{
|
||||
errorMessage = "配置不能为空。";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config.vaBits != 32 && config.vaBits != 48 && config.vaBits != 64)
|
||||
{
|
||||
errorMessage = "vaBits 仅支持 32、48、64。";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config.pageSizeKB <= 0)
|
||||
{
|
||||
errorMessage = "pageSizeKB 必须是正整数。";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsPowerOfTwo((ulong)config.pageSizeKB))
|
||||
{
|
||||
errorMessage = "pageSizeKB 必须是 2 的幂(2^n KB)。";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config.physicalMemoryMB <= 0)
|
||||
{
|
||||
errorMessage = "physicalMemoryMB 必须是正整数。";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config.tlbEntries <= 0)
|
||||
{
|
||||
errorMessage = "tlbEntries 必须是正整数。";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config.accessCount <= 0)
|
||||
{
|
||||
errorMessage = "accessCount 必须是正整数。";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config.pageFaultPenalty <= 0)
|
||||
{
|
||||
errorMessage = "pageFaultPenalty 必须是正整数。";
|
||||
return false;
|
||||
}
|
||||
|
||||
var pageSizeBytes = config.PageSizeBytes;
|
||||
if (!TryGetLog2(pageSizeBytes, out var offsetBits))
|
||||
{
|
||||
errorMessage = "pageSizeKB 必须对应可计算的 2 的幂字节数。";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offsetBits >= config.vaBits)
|
||||
{
|
||||
errorMessage =
|
||||
$"offsetBits 必须小于 vaBits,当前 offsetBits={offsetBits},vaBits={config.vaBits}。";
|
||||
return false;
|
||||
}
|
||||
|
||||
var frameCount = config.FrameCount;
|
||||
if (frameCount < 1UL)
|
||||
{
|
||||
errorMessage =
|
||||
$"frameCount 必须 >= 1,当前 frameCount={frameCount}。请增大 physicalMemoryMB 或减小 pageSizeKB。";
|
||||
return false;
|
||||
}
|
||||
|
||||
derived = new DerivedConfig(
|
||||
pageSizeBytes,
|
||||
config.PhysicalMemoryBytes,
|
||||
offsetBits,
|
||||
config.vaBits - offsetBits,
|
||||
frameCount);
|
||||
|
||||
errorMessage = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsPowerOfTwo(ulong value)
|
||||
{
|
||||
return value != 0UL && (value & (value - 1UL)) == 0UL;
|
||||
}
|
||||
|
||||
private static bool TryGetLog2(ulong value, out int bits)
|
||||
{
|
||||
bits = -1;
|
||||
if (!IsPowerOfTwo(value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bits = 0;
|
||||
while (value > 1UL)
|
||||
{
|
||||
value >>= 1;
|
||||
bits++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 278803579202bf144ad186a403dbaed2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
|
||||
namespace VMdemo.Core
|
||||
{
|
||||
[Serializable]
|
||||
public class SimulationConfig
|
||||
{
|
||||
public int vaBits = 32;
|
||||
public int pageSizeKB = 4;
|
||||
public int physicalMemoryMB = 64;
|
||||
public int tlbEntries = 16;
|
||||
public int accessCount = 100;
|
||||
public int pageFaultPenalty = 100;
|
||||
|
||||
public ulong PageSizeBytes => pageSizeKB > 0 ? (ulong)pageSizeKB * 1024UL : 0UL;
|
||||
|
||||
public ulong PhysicalMemoryBytes => physicalMemoryMB > 0 ? (ulong)physicalMemoryMB * 1024UL * 1024UL : 0UL;
|
||||
|
||||
public int OffsetBits
|
||||
{
|
||||
get
|
||||
{
|
||||
return TryGetLog2(PageSizeBytes, out var bits) ? bits : -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int VpnBits
|
||||
{
|
||||
get
|
||||
{
|
||||
var offsetBits = OffsetBits;
|
||||
return offsetBits >= 0 ? vaBits - offsetBits : -1;
|
||||
}
|
||||
}
|
||||
|
||||
public ulong FrameCount
|
||||
{
|
||||
get
|
||||
{
|
||||
var pageSizeBytes = PageSizeBytes;
|
||||
if (pageSizeBytes == 0UL)
|
||||
{
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
return PhysicalMemoryBytes / pageSizeBytes;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetLog2(ulong value, out int bits)
|
||||
{
|
||||
bits = -1;
|
||||
if (value == 0UL || (value & (value - 1UL)) != 0UL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bits = 0;
|
||||
while (value > 1UL)
|
||||
{
|
||||
value >>= 1;
|
||||
bits++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 560da4f3bb13de24986a73b585c1ec1f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c143559c7269dd940b8cb1b43b2d07a5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using VMdemo.Core;
|
||||
|
||||
namespace VMdemo.Simulation
|
||||
{
|
||||
[Serializable]
|
||||
public class SimulationState
|
||||
{
|
||||
public int CurrentRound { get; set; }
|
||||
public ulong CurrentVirtualAddress { get; set; }
|
||||
public AddressParts CurrentAddressParts { get; set; }
|
||||
public bool IsPageFault { get; set; }
|
||||
public bool IsTlbHit { get; set; }
|
||||
public bool IsPageTableHit { get; set; }
|
||||
public int CurrentCost { get; set; }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
CurrentRound = 0;
|
||||
CurrentVirtualAddress = 0UL;
|
||||
CurrentAddressParts = AddressParts.Empty;
|
||||
IsPageFault = false;
|
||||
IsTlbHit = false;
|
||||
IsPageTableHit = false;
|
||||
CurrentCost = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ab511454f082cd4987e3388c3eee16a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a14121217fe28e64f9ddd4fc9f89c32a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"name": "VMdemo"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: baede126690de864e8b4ee808c6a2716
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34f7f3b70dfcb49478f58b5b5af22019
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 760fef5586fd36f4f9004a24632450a7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,137 @@
|
||||
using NUnit.Framework;
|
||||
using VMdemo.Core;
|
||||
using VMdemo.Simulation;
|
||||
|
||||
namespace VMdemo.Tests.EditMode
|
||||
{
|
||||
public class Step1CoreModelTests
|
||||
{
|
||||
[Test]
|
||||
public void TryValidateAndBuildDerived_ValidConfig_ReturnsExpectedDerivedValues()
|
||||
{
|
||||
var config = new SimulationConfig
|
||||
{
|
||||
vaBits = 48,
|
||||
pageSizeKB = 4,
|
||||
physicalMemoryMB = 64,
|
||||
tlbEntries = 16,
|
||||
accessCount = 1000,
|
||||
pageFaultPenalty = 100
|
||||
};
|
||||
|
||||
var ok = ConfigValidator.TryValidateAndBuildDerived(config, out var derived, out var error);
|
||||
|
||||
Assert.IsTrue(ok, error);
|
||||
Assert.That(error, Is.Empty);
|
||||
Assert.That(derived.PageSizeBytes, Is.EqualTo(4096UL));
|
||||
Assert.That(derived.PhysicalMemoryBytes, Is.EqualTo(67108864UL));
|
||||
Assert.That(derived.OffsetBits, Is.EqualTo(12));
|
||||
Assert.That(derived.VpnBits, Is.EqualTo(36));
|
||||
Assert.That(derived.FrameCount, Is.EqualTo(16384UL));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryValidate_InvalidVaBits_FailsWithReadableMessage()
|
||||
{
|
||||
var config = new SimulationConfig
|
||||
{
|
||||
vaBits = 40,
|
||||
pageSizeKB = 4,
|
||||
physicalMemoryMB = 64,
|
||||
tlbEntries = 16,
|
||||
accessCount = 10,
|
||||
pageFaultPenalty = 100
|
||||
};
|
||||
|
||||
var ok = ConfigValidator.TryValidate(config, out var error);
|
||||
|
||||
Assert.IsFalse(ok);
|
||||
Assert.That(error, Does.Contain("vaBits"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryValidate_PageSizeNotPowerOfTwo_FailsWithReadableMessage()
|
||||
{
|
||||
var config = new SimulationConfig
|
||||
{
|
||||
vaBits = 32,
|
||||
pageSizeKB = 6,
|
||||
physicalMemoryMB = 64,
|
||||
tlbEntries = 16,
|
||||
accessCount = 10,
|
||||
pageFaultPenalty = 100
|
||||
};
|
||||
|
||||
var ok = ConfigValidator.TryValidate(config, out var error);
|
||||
|
||||
Assert.IsFalse(ok);
|
||||
Assert.That(error, Does.Contain("pageSizeKB"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryValidate_OffsetBitsGreaterOrEqualVaBits_Fails()
|
||||
{
|
||||
var config = new SimulationConfig
|
||||
{
|
||||
vaBits = 32,
|
||||
pageSizeKB = 4 * 1024 * 1024,
|
||||
physicalMemoryMB = 8192,
|
||||
tlbEntries = 16,
|
||||
accessCount = 10,
|
||||
pageFaultPenalty = 100
|
||||
};
|
||||
|
||||
var ok = ConfigValidator.TryValidate(config, out var error);
|
||||
|
||||
Assert.IsFalse(ok);
|
||||
Assert.That(error, Does.Contain("offsetBits"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryValidate_FrameCountLessThanOne_Fails()
|
||||
{
|
||||
var config = new SimulationConfig
|
||||
{
|
||||
vaBits = 32,
|
||||
pageSizeKB = 2048,
|
||||
physicalMemoryMB = 1,
|
||||
tlbEntries = 16,
|
||||
accessCount = 10,
|
||||
pageFaultPenalty = 100
|
||||
};
|
||||
|
||||
var ok = ConfigValidator.TryValidate(config, out var error);
|
||||
|
||||
Assert.IsFalse(ok);
|
||||
Assert.That(error, Does.Contain("frameCount"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SimulationState_Reset_ClearsAllStepState()
|
||||
{
|
||||
var state = new SimulationState
|
||||
{
|
||||
CurrentRound = 7,
|
||||
CurrentVirtualAddress = 123456UL,
|
||||
CurrentAddressParts = new AddressParts(10UL, 20UL, 3UL, 7UL),
|
||||
IsPageFault = true,
|
||||
IsTlbHit = true,
|
||||
IsPageTableHit = true,
|
||||
CurrentCost = 999
|
||||
};
|
||||
|
||||
state.Reset();
|
||||
|
||||
Assert.That(state.CurrentRound, Is.EqualTo(0));
|
||||
Assert.That(state.CurrentVirtualAddress, Is.EqualTo(0UL));
|
||||
Assert.That(state.CurrentAddressParts.Vpn, Is.EqualTo(0UL));
|
||||
Assert.That(state.CurrentAddressParts.Offset, Is.EqualTo(0UL));
|
||||
Assert.That(state.CurrentAddressParts.L1Index, Is.EqualTo(0UL));
|
||||
Assert.That(state.CurrentAddressParts.L2Index, Is.EqualTo(0UL));
|
||||
Assert.IsFalse(state.IsPageFault);
|
||||
Assert.IsFalse(state.IsTlbHit);
|
||||
Assert.IsFalse(state.IsPageTableHit);
|
||||
Assert.That(state.CurrentCost, Is.EqualTo(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 52e57f0a987345340859c62fc16b1c90
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "VMdemo.EditModeTests",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"Assembly-CSharp",
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner",
|
||||
"VMdemo"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0e3ad2a355fe1d4e979eb4d2d33fc5a
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user