142 lines
4.1 KiB
C#
142 lines
4.1 KiB
C#
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;
|
||
}
|
||
}
|
||
}
|