This repository has been archived on 2026-04-18. You can view files and clone it, but cannot push or open issues or pull requests.
Virtual-Memory-Demo/Assets/Scripts/UI/SimulationUIFormatter.cs

325 lines
11 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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=falsePFN={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>";
}
}
}