325 lines
11 KiB
C#
325 lines
11 KiB
C#
using System.Collections.Generic;
|
||
using System.Text;
|
||
using VMdemo.Simulation;
|
||
|
||
namespace VMdemo.UI
|
||
{
|
||
public static class SimulationUIFormatter
|
||
{
|
||
private const string ColorVpn = "#4FC3F7";
|
||
private const string ColorL1 = "#FFB74D";
|
||
private const string ColorL2 = "#81C784";
|
||
private const string ColorOffset = "#B0BEC5";
|
||
|
||
public static string FormatStateSummary(
|
||
SimulationState state,
|
||
int machineBits,
|
||
int vaBits,
|
||
int pageSizeKB,
|
||
int physicalMemoryMB,
|
||
int tlbEntries)
|
||
{
|
||
var va = FormatAddressHex(state.CurrentVirtualAddress, vaBits);
|
||
var pa = FormatAddressHex(state.CurrentPhysicalAddress, vaBits);
|
||
var stepText = TranslationStepDisplay.ToChinese(state.CurrentStep);
|
||
return
|
||
$"系统规格:{machineBits}位机\n" +
|
||
$"虚拟地址有效位:{vaBits}位\n" +
|
||
$"页大小:{pageSizeKB}KB\n" +
|
||
$"物理内存:{physicalMemoryMB}MB\n" +
|
||
$"TLB:{tlbEntries}条全相联\n";
|
||
}
|
||
|
||
public static string FormatStats(StatsCollector stats)
|
||
{
|
||
return
|
||
$"总访问={stats.TotalAccess}\n" +
|
||
$"TLB命中率={stats.TlbHitRate:P2}\n" +
|
||
$"页表命中率={stats.PageTableHitRate:P2}\n" +
|
||
$"缺页次数={stats.PageFault}\n" +
|
||
$"平均开销={stats.AvgCost:F2}";
|
||
}
|
||
|
||
public static string FormatTlbTable(
|
||
IReadOnlyList<TlbEntry> entries,
|
||
int vpnBits,
|
||
int pfnBits)
|
||
{
|
||
if (entries == null || entries.Count == 0)
|
||
{
|
||
return "TLB:空";
|
||
}
|
||
|
||
var sb = new StringBuilder();
|
||
sb.AppendLine("TLB(最近使用 -> 最久未用)");
|
||
for (var i = 0; i < entries.Count; i++)
|
||
{
|
||
var entry = entries[i];
|
||
sb.Append("#").Append(i + 1)
|
||
.Append("VPN=").Append(FormatBitWidthHex(entry.Vpn, vpnBits))
|
||
.Append(" -> PFN=").Append(FormatBitWidthHex(entry.Pfn, pfnBits))
|
||
.AppendLine();
|
||
}
|
||
|
||
return sb.ToString().TrimEnd();
|
||
}
|
||
|
||
public static string FormatCurrentPageTableEntry(
|
||
SimulationState state,
|
||
TwoLevelPageTable pageTable,
|
||
EvictionInfo eviction)
|
||
{
|
||
if (state == null || pageTable == null)
|
||
{
|
||
return "页表:N/A";
|
||
}
|
||
|
||
var sb = new StringBuilder();
|
||
sb.Append("当前页表项:");
|
||
if (pageTable.TryGetEntry(state.CurrentAddressParts.L1Index, state.CurrentAddressParts.L2Index,
|
||
out var entry))
|
||
{
|
||
sb.Append("存在=").Append(entry.Present)
|
||
.Append(" 物理帧号PFN=").Append(FormatHex(entry.Pfn))
|
||
.Append(" 脏位=").Append(entry.Dirty);
|
||
}
|
||
else
|
||
{
|
||
sb.Append("(缺失)");
|
||
}
|
||
|
||
sb.AppendLine();
|
||
if (eviction.HasEvicted)
|
||
{
|
||
sb.Append("最近淘汰:虚拟页号VPN=").Append(FormatHex(eviction.EvictedVpn))
|
||
.Append(" 物理帧号PFN=").Append(FormatHex(eviction.EvictedPfn));
|
||
}
|
||
else
|
||
{
|
||
sb.Append("最近淘汰:无");
|
||
}
|
||
|
||
return sb.ToString();
|
||
}
|
||
|
||
public static string FormatFifoQueue(IReadOnlyList<ulong> fifoOrder)
|
||
{
|
||
if (fifoOrder == null || fifoOrder.Count == 0)
|
||
{
|
||
return "FIFO:空";
|
||
}
|
||
|
||
var sb = new StringBuilder("FIFO(最早进入 -> 最新进入):");
|
||
for (var i = 0; i < fifoOrder.Count; i++)
|
||
{
|
||
if (i > 0)
|
||
{
|
||
sb.Append(" -> ");
|
||
}
|
||
|
||
sb.Append(FormatHex(fifoOrder[i]));
|
||
}
|
||
|
||
return sb.ToString();
|
||
}
|
||
|
||
public static string FormatAddressHex(ulong value, int vaBits)
|
||
{
|
||
return FormatBitWidthHex(value, vaBits);
|
||
}
|
||
|
||
private static string FormatHex(ulong value)
|
||
{
|
||
return $"0x{value:X}";
|
||
}
|
||
|
||
public static string FormatBitWidthHex(ulong value, int bits)
|
||
{
|
||
var digits = bits switch
|
||
{
|
||
8 => 2,
|
||
16 => 4,
|
||
24 => 6,
|
||
32 => 8,
|
||
48 => 12,
|
||
64 => 16,
|
||
_ => bits > 0 ? (bits + 3) / 4 : 1
|
||
};
|
||
|
||
return $"0x{value.ToString($"X{digits}")}";
|
||
}
|
||
|
||
public static int ComputeBitsForCount(ulong count)
|
||
{
|
||
if (count <= 1UL)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
var maxValue = count - 1UL;
|
||
var bits = 0;
|
||
while (maxValue > 0UL)
|
||
{
|
||
bits++;
|
||
maxValue >>= 1;
|
||
}
|
||
|
||
return bits;
|
||
}
|
||
|
||
public static string FormatAddressSplitTrace(
|
||
SimulationState state,
|
||
int vaBits,
|
||
int offsetBits,
|
||
int l1Bits,
|
||
int l2Bits)
|
||
{
|
||
if (state == null)
|
||
{
|
||
return "地址拆分可视化:N/A";
|
||
}
|
||
|
||
var vpnBits = vaBits - offsetBits;
|
||
var vaHex = FormatAddressHex(state.CurrentVirtualAddress, vaBits);
|
||
var vaBin = FormatBinary(state.CurrentVirtualAddress, vaBits);
|
||
var vaBinColored = FormatVaBinaryWithFieldColors(state.CurrentVirtualAddress, vaBits, l1Bits, l2Bits, offsetBits);
|
||
var vpnBin = FormatBinary(state.CurrentAddressParts.Vpn, vpnBits);
|
||
var l1Bin = FormatBinary(state.CurrentAddressParts.L1Index, l1Bits);
|
||
var l2Bin = FormatBinary(state.CurrentAddressParts.L2Index, l2Bits);
|
||
var offBin = FormatBinary(state.CurrentAddressParts.Offset, offsetBits);
|
||
|
||
var sb = new StringBuilder();
|
||
sb.AppendLine("地址拆分可视化");
|
||
sb.AppendLine($"{vaHex})");
|
||
sb.AppendLine($"{vaBinColored}");
|
||
sb.AppendLine(
|
||
$"{WrapColor("VPN", ColorVpn)} = {WrapColor("L1+L2", ColorVpn)}," +
|
||
$"{WrapColor("L1", ColorL1)},{WrapColor("L2", ColorL2)},{WrapColor("Offset", ColorOffset)}");
|
||
sb.AppendLine($"VPN({vpnBits}) = L1({l1Bits}) + L2({l2Bits}) | Offset({offsetBits})");
|
||
sb.AppendLine($"VPN:{FormatBitWidthHex(state.CurrentAddressParts.Vpn, vpnBits)} ({WrapColor(vpnBin, ColorVpn)})");
|
||
sb.AppendLine($"L1 索引:{FormatBitWidthHex(state.CurrentAddressParts.L1Index, l1Bits)} ({WrapColor(l1Bin, ColorL1)})");
|
||
sb.AppendLine($"L2 索引:{FormatBitWidthHex(state.CurrentAddressParts.L2Index, l2Bits)} ({WrapColor(l2Bin, ColorL2)})");
|
||
sb.Append($"Offset:{FormatBitWidthHex(state.CurrentAddressParts.Offset, offsetBits)} ({WrapColor(offBin, ColorOffset)})");
|
||
return sb.ToString();
|
||
}
|
||
|
||
public static string FormatPageTableWalkTrace(SimulationState state, TwoLevelPageTable pageTable)
|
||
{
|
||
if (state == null || pageTable == null)
|
||
{
|
||
return "页表访问路径:N/A";
|
||
}
|
||
|
||
var probe = pageTable.Probe(state.CurrentAddressParts.L1Index, state.CurrentAddressParts.L2Index);
|
||
var sb = new StringBuilder();
|
||
sb.AppendLine("多级页表查询可视化");
|
||
sb.AppendLine(
|
||
$"1) 先按 VPN 拆分:L1={state.CurrentAddressParts.L1Index}, L2={state.CurrentAddressParts.L2Index}");
|
||
switch (probe.Status)
|
||
{
|
||
case PageTableProbeStatus.MissingL1Table:
|
||
sb.Append("2) L1 未命中:对应二级页表不存在。");
|
||
break;
|
||
case PageTableProbeStatus.MissingL2Entry:
|
||
sb.Append("2) L1 命中,L2 未命中:页表项不存在。");
|
||
break;
|
||
case PageTableProbeStatus.NotPresentEntry:
|
||
sb.Append($"2) L1/L2 命中,但 present=false(PFN={FormatHex(probe.Entry.Pfn)})。");
|
||
break;
|
||
case PageTableProbeStatus.PresentEntry:
|
||
sb.Append($"2) L1/L2 命中,present=true,得到 PFN={FormatHex(probe.Entry.Pfn)}。");
|
||
break;
|
||
}
|
||
|
||
return sb.ToString();
|
||
}
|
||
|
||
private static string FormatBinary(ulong value, int bits)
|
||
{
|
||
if (bits <= 0)
|
||
{
|
||
return "0";
|
||
}
|
||
|
||
var sb = new StringBuilder(bits + (bits / 4));
|
||
for (var i = bits - 1; i >= 0; i--)
|
||
{
|
||
var bit = (value >> i) & 1UL;
|
||
sb.Append(bit == 1UL ? '1' : '0');
|
||
if (i > 0 && i % 4 == 0)
|
||
{
|
||
sb.Append('_');
|
||
}
|
||
}
|
||
|
||
return sb.ToString();
|
||
}
|
||
|
||
private static string FormatVaBinaryWithFieldColors(
|
||
ulong value,
|
||
int vaBits,
|
||
int l1Bits,
|
||
int l2Bits,
|
||
int offsetBits)
|
||
{
|
||
if (vaBits <= 0)
|
||
{
|
||
return "0";
|
||
}
|
||
|
||
var sb = new StringBuilder(vaBits * 10);
|
||
string currentColor = null;
|
||
|
||
for (var i = vaBits - 1; i >= 0; i--)
|
||
{
|
||
var bitColor = ResolveBitColor(i, l1Bits, l2Bits, offsetBits);
|
||
if (currentColor != bitColor)
|
||
{
|
||
if (currentColor != null)
|
||
{
|
||
sb.Append("</color>");
|
||
}
|
||
|
||
sb.Append("<color=").Append(bitColor).Append(">");
|
||
currentColor = bitColor;
|
||
}
|
||
|
||
var bit = (value >> i) & 1UL;
|
||
sb.Append(bit == 1UL ? '1' : '0');
|
||
if (i > 0 && i % 4 == 0)
|
||
{
|
||
sb.Append('_');
|
||
}
|
||
}
|
||
|
||
if (currentColor != null)
|
||
{
|
||
sb.Append("</color>");
|
||
}
|
||
|
||
return sb.ToString();
|
||
}
|
||
|
||
private static string ResolveBitColor(int bitIndex, int l1Bits, int l2Bits, int offsetBits)
|
||
{
|
||
var l1Start = offsetBits + l2Bits;
|
||
if (bitIndex >= l1Start)
|
||
{
|
||
return ColorL1;
|
||
}
|
||
|
||
if (bitIndex >= offsetBits)
|
||
{
|
||
return ColorL2;
|
||
}
|
||
|
||
return ColorOffset;
|
||
}
|
||
|
||
private static string WrapColor(string text, string colorHex)
|
||
{
|
||
return $"<color={colorHex}>{text}</color>";
|
||
}
|
||
}
|
||
}
|