134 lines
3.9 KiB
C#
134 lines
3.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace VMdemo.Simulation
|
|
{
|
|
public readonly struct EvictionInfo
|
|
{
|
|
public EvictionInfo(bool hasEvicted, ulong evictedVpn, ulong evictedPfn)
|
|
{
|
|
HasEvicted = hasEvicted;
|
|
EvictedVpn = evictedVpn;
|
|
EvictedPfn = evictedPfn;
|
|
}
|
|
|
|
public bool HasEvicted { get; }
|
|
public ulong EvictedVpn { get; }
|
|
public ulong EvictedPfn { get; }
|
|
|
|
public static EvictionInfo None => new EvictionInfo(false, 0UL, 0UL);
|
|
}
|
|
|
|
public readonly struct AllocationResult
|
|
{
|
|
public AllocationResult(ulong assignedPfn, bool wasAlreadyResident, EvictionInfo eviction)
|
|
{
|
|
AssignedPfn = assignedPfn;
|
|
WasAlreadyResident = wasAlreadyResident;
|
|
Eviction = eviction;
|
|
}
|
|
|
|
public ulong AssignedPfn { get; }
|
|
public bool WasAlreadyResident { get; }
|
|
public EvictionInfo Eviction { get; }
|
|
}
|
|
|
|
public class PhysicalMemoryManager
|
|
{
|
|
private readonly Queue<ResidentPage> _fifoQueue = new Queue<ResidentPage>();
|
|
private readonly Dictionary<ulong, ulong> _residentByVpn = new Dictionary<ulong, ulong>();
|
|
private ulong _nextFreeFrame;
|
|
|
|
public PhysicalMemoryManager(ulong frameCount)
|
|
{
|
|
if (frameCount < 1UL)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(frameCount), "frameCount 必须 >= 1。");
|
|
}
|
|
|
|
FrameCount = frameCount;
|
|
_nextFreeFrame = 0UL;
|
|
}
|
|
|
|
public ulong FrameCount { get; }
|
|
public int ResidentCount => _residentByVpn.Count;
|
|
|
|
public bool TryGetResidentPfn(ulong vpn, out ulong pfn)
|
|
{
|
|
return _residentByVpn.TryGetValue(vpn, out pfn);
|
|
}
|
|
|
|
public AllocationResult AllocateForVpn(ulong vpn)
|
|
{
|
|
if (_residentByVpn.TryGetValue(vpn, out var existingPfn))
|
|
{
|
|
return new AllocationResult(existingPfn, true, EvictionInfo.None);
|
|
}
|
|
|
|
EvictionInfo evictionInfo;
|
|
ulong assignedPfn;
|
|
|
|
if (_nextFreeFrame < FrameCount)
|
|
{
|
|
assignedPfn = _nextFreeFrame;
|
|
_nextFreeFrame++;
|
|
evictionInfo = EvictionInfo.None;
|
|
}
|
|
else
|
|
{
|
|
if (_fifoQueue.Count == 0)
|
|
{
|
|
throw new InvalidOperationException("内存已满但 FIFO 队列为空,状态异常。");
|
|
}
|
|
|
|
var victim = _fifoQueue.Dequeue();
|
|
if (!_residentByVpn.Remove(victim.Vpn))
|
|
{
|
|
throw new InvalidOperationException("FIFO 淘汰项未出现在驻留映射中,状态异常。");
|
|
}
|
|
|
|
assignedPfn = victim.Pfn;
|
|
evictionInfo = new EvictionInfo(true, victim.Vpn, victim.Pfn);
|
|
}
|
|
|
|
_residentByVpn[vpn] = assignedPfn;
|
|
_fifoQueue.Enqueue(new ResidentPage(vpn, assignedPfn));
|
|
return new AllocationResult(assignedPfn, false, evictionInfo);
|
|
}
|
|
|
|
public IReadOnlyList<ulong> GetFifoVpnOrder()
|
|
{
|
|
var order = new List<ulong>(_fifoQueue.Count);
|
|
foreach (var page in _fifoQueue)
|
|
{
|
|
order.Add(page.Vpn);
|
|
}
|
|
|
|
return order;
|
|
}
|
|
|
|
public string FormatFifoQueue()
|
|
{
|
|
var order = GetFifoVpnOrder();
|
|
if (order.Count == 0)
|
|
{
|
|
return "FIFO=[]";
|
|
}
|
|
|
|
return $"FIFO=[{string.Join(",", order)}]";
|
|
}
|
|
|
|
private readonly struct ResidentPage
|
|
{
|
|
public ResidentPage(ulong vpn, ulong pfn)
|
|
{
|
|
Vpn = vpn;
|
|
Pfn = pfn;
|
|
}
|
|
|
|
public ulong Vpn { get; }
|
|
public ulong Pfn { get; }
|
|
}
|
|
}
|
|
}
|