From 63ae8679a33c3010be6306de24b1acc7a30ec536 Mon Sep 17 00:00:00 2001 From: Roderick Sieben Date: Wed, 12 Dec 2018 02:48:54 +0100 Subject: [PATCH] Optimized memory modified check (#538) * Optimized memory modified check This was initially in some cases more expensive than plainly sending the data. Now it should have way better performance. * Small refactoring * renamed InvalidAccessEventArgs * Renamed PtPageBits * Removed ValueRange(set) They are currently unused and won't be likely to be used in the near future --- Events/InvalidAccessEventArgs.cs | 4 +- Memory/MemoryManager.cs | 73 ++++++++++---------------------- 2 files changed, 25 insertions(+), 52 deletions(-) diff --git a/Events/InvalidAccessEventArgs.cs b/Events/InvalidAccessEventArgs.cs index a8046d7..9c34975 100644 --- a/Events/InvalidAccessEventArgs.cs +++ b/Events/InvalidAccessEventArgs.cs @@ -2,11 +2,11 @@ using System; namespace ChocolArm64.Events { - public class InvalidAccessEventArgs : EventArgs + public class MemoryAccessEventArgs : EventArgs { public long Position { get; private set; } - public InvalidAccessEventArgs(long position) + public MemoryAccessEventArgs(long position) { Position = position; } diff --git a/Memory/MemoryManager.cs b/Memory/MemoryManager.cs index eacb533..1f21256 100644 --- a/Memory/MemoryManager.cs +++ b/Memory/MemoryManager.cs @@ -17,18 +17,18 @@ namespace ChocolArm64.Memory { private const int PtLvl0Bits = 13; private const int PtLvl1Bits = 14; - private const int PtPageBits = 12; + public const int PageBits = 12; private const int PtLvl0Size = 1 << PtLvl0Bits; private const int PtLvl1Size = 1 << PtLvl1Bits; - public const int PageSize = 1 << PtPageBits; + public const int PageSize = 1 << PageBits; private const int PtLvl0Mask = PtLvl0Size - 1; private const int PtLvl1Mask = PtLvl1Size - 1; public const int PageMask = PageSize - 1; - private const int PtLvl0Bit = PtPageBits + PtLvl1Bits; - private const int PtLvl1Bit = PtPageBits; + private const int PtLvl0Bit = PageBits + PtLvl1Bits; + private const int PtLvl1Bit = PageBits; private const long ErgMask = (4 << CpuThreadState.ErgSizeLog2) - 1; @@ -53,7 +53,9 @@ namespace ChocolArm64.Memory private byte*** _pageTable; - public event EventHandler InvalidAccess; + public event EventHandler InvalidAccess; + + public event EventHandler ObservedAccess; public MemoryManager(IntPtr ram) { @@ -632,7 +634,7 @@ namespace ChocolArm64.Memory return false; } - return _pageTable[l0][l1] != null || _observedPages.ContainsKey(position >> PtPageBits); + return _pageTable[l0][l1] != null || _observedPages.ContainsKey(position >> PageBits); } public long GetPhysicalAddress(long virtualAddress) @@ -678,14 +680,14 @@ Unmapped: private byte* HandleNullPte(long position) { - long key = position >> PtPageBits; + long key = position >> PageBits; if (_observedPages.TryGetValue(key, out IntPtr ptr)) { return (byte*)ptr + (position & PageMask); } - InvalidAccess?.Invoke(this, new InvalidAccessEventArgs(position)); + InvalidAccess?.Invoke(this, new MemoryAccessEventArgs(position)); throw new VmmPageFaultException(position); } @@ -726,16 +728,20 @@ Unmapped: private byte* HandleNullPteWrite(long position) { - long key = position >> PtPageBits; + long key = position >> PageBits; + + MemoryAccessEventArgs e = new MemoryAccessEventArgs(position); if (_observedPages.TryGetValue(key, out IntPtr ptr)) { SetPtEntry(position, (byte*)ptr); + ObservedAccess?.Invoke(this, e); + return (byte*)ptr + (position & PageMask); } - InvalidAccess?.Invoke(this, new InvalidAccessEventArgs(position)); + InvalidAccess?.Invoke(this, e); throw new VmmPageFaultException(position); } @@ -784,53 +790,20 @@ Unmapped: _pageTable[l0][l1] = ptr; } - public (bool[], int) IsRegionModified(long position, long size) + public void StartObservingRegion(long position, long size) { long endPosition = (position + size + PageMask) & ~PageMask; position &= ~PageMask; - size = endPosition - position; - - bool[] modified = new bool[size >> PtPageBits]; - - int count = 0; - - lock (_observedPages) + while ((ulong)position < (ulong)endPosition) { - for (int page = 0; page < modified.Length; page++) - { - byte* ptr = Translate(position); + _observedPages[position >> PageBits] = (IntPtr)Translate(position); - if (_observedPages.TryAdd(position >> PtPageBits, (IntPtr)ptr)) - { - modified[page] = true; + SetPtEntry(position, null); - count++; - } - else - { - long l0 = (position >> PtLvl0Bit) & PtLvl0Mask; - long l1 = (position >> PtLvl1Bit) & PtLvl1Mask; - - byte** lvl1 = _pageTable[l0]; - - if (lvl1 != null) - { - if (modified[page] = lvl1[l1] != null) - { - count++; - } - } - } - - SetPtEntry(position, null); - - position += PageSize; - } + position += PageSize; } - - return (modified, count); } public void StopObservingRegion(long position, long size) @@ -841,7 +814,7 @@ Unmapped: { lock (_observedPages) { - if (_observedPages.TryRemove(position >> PtPageBits, out IntPtr ptr)) + if (_observedPages.TryRemove(position >> PageBits, out IntPtr ptr)) { SetPtEntry(position, (byte*)ptr); } @@ -891,7 +864,7 @@ Unmapped: public bool IsValidPosition(long position) { - return position >> (PtLvl0Bits + PtLvl1Bits + PtPageBits) == 0; + return position >> (PtLvl0Bits + PtLvl1Bits + PageBits) == 0; } public void Dispose()