diff options
| author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
|---|---|---|
| committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
| commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
| tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /Ryujinx.Memory/Tracking/MultiRegionHandle.cs | |
| parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) | |
Move solution and projects to src
Diffstat (limited to 'Ryujinx.Memory/Tracking/MultiRegionHandle.cs')
| -rw-r--r-- | Ryujinx.Memory/Tracking/MultiRegionHandle.cs | 415 |
1 files changed, 0 insertions, 415 deletions
diff --git a/Ryujinx.Memory/Tracking/MultiRegionHandle.cs b/Ryujinx.Memory/Tracking/MultiRegionHandle.cs deleted file mode 100644 index 68fc5e75..00000000 --- a/Ryujinx.Memory/Tracking/MultiRegionHandle.cs +++ /dev/null @@ -1,415 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Threading; - -namespace Ryujinx.Memory.Tracking -{ - /// <summary> - /// A region handle that tracks a large region using many smaller handles, to provide - /// granular tracking that can be used to track partial updates. Backed by a bitmap - /// to improve performance when scanning large regions. - /// </summary> - public class MultiRegionHandle : IMultiRegionHandle - { - /// <summary> - /// A list of region handles for each granularity sized chunk of the whole region. - /// </summary> - private readonly RegionHandle[] _handles; - private readonly ulong Address; - private readonly ulong Granularity; - private readonly ulong Size; - - private ConcurrentBitmap _dirtyBitmap; - - private int _sequenceNumber; - private BitMap _sequenceNumberBitmap; - private BitMap _dirtyCheckedBitmap; - private int _uncheckedHandles; - - public bool Dirty { get; private set; } = true; - - internal MultiRegionHandle( - MemoryTracking tracking, - ulong address, - ulong size, - IEnumerable<IRegionHandle> handles, - ulong granularity, - int id) - { - _handles = new RegionHandle[(size + granularity - 1) / granularity]; - Granularity = granularity; - - _dirtyBitmap = new ConcurrentBitmap(_handles.Length, true); - _sequenceNumberBitmap = new BitMap(_handles.Length); - _dirtyCheckedBitmap = new BitMap(_handles.Length); - - int i = 0; - - if (handles != null) - { - // Inherit from the handles we were given. Any gaps must be filled with new handles, - // and old handles larger than our granularity must copy their state onto new granular handles and dispose. - // It is assumed that the provided handles do not overlap, in order, are on page boundaries, - // and don't extend past the requested range. - - foreach (RegionHandle handle in handles) - { - int startIndex = (int)((handle.RealAddress - address) / granularity); - - // Fill any gap left before this handle. - while (i < startIndex) - { - RegionHandle fillHandle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i, id); - fillHandle.Parent = this; - _handles[i++] = fillHandle; - } - - lock (tracking.TrackingLock) - { - if (handle is RegionHandle bitHandle && handle.Size == granularity) - { - handle.Parent = this; - - bitHandle.ReplaceBitmap(_dirtyBitmap, i); - - _handles[i++] = bitHandle; - } - else - { - int endIndex = (int)((handle.RealEndAddress - address) / granularity); - - while (i < endIndex) - { - RegionHandle splitHandle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i, id); - splitHandle.Parent = this; - - splitHandle.Reprotect(handle.Dirty); - - RegionSignal signal = handle.PreAction; - if (signal != null) - { - splitHandle.RegisterAction(signal); - } - - _handles[i++] = splitHandle; - } - - handle.Dispose(); - } - } - } - } - - // Fill any remaining space with new handles. - while (i < _handles.Length) - { - RegionHandle handle = tracking.BeginTrackingBitmap(address + (ulong)i * granularity, granularity, _dirtyBitmap, i, id); - handle.Parent = this; - _handles[i++] = handle; - } - - _uncheckedHandles = _handles.Length; - - Address = address; - Size = size; - } - - public void SignalWrite() - { - Dirty = true; - } - - public IEnumerable<RegionHandle> GetHandles() - { - return _handles; - } - - public void ForceDirty(ulong address, ulong size) - { - Dirty = true; - - int startHandle = (int)((address - Address) / Granularity); - int lastHandle = (int)((address + (size - 1) - Address) / Granularity); - - for (int i = startHandle; i <= lastHandle; i++) - { - if (_sequenceNumberBitmap.Clear(i)) - { - _uncheckedHandles++; - } - - _handles[i].ForceDirty(); - } - } - - public void QueryModified(Action<ulong, ulong> modifiedAction) - { - if (!Dirty) - { - return; - } - - Dirty = false; - - QueryModified(Address, Size, modifiedAction); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ParseDirtyBits(long dirtyBits, ref int baseBit, ref int prevHandle, ref ulong rgStart, ref ulong rgSize, Action<ulong, ulong> modifiedAction) - { - while (dirtyBits != 0) - { - int bit = BitOperations.TrailingZeroCount(dirtyBits); - - dirtyBits &= ~(1L << bit); - - int handleIndex = baseBit + bit; - - RegionHandle handle = _handles[handleIndex]; - - if (handleIndex != prevHandle + 1) - { - // Submit handles scanned until the gap as dirty - if (rgSize != 0) - { - modifiedAction(rgStart, rgSize); - rgSize = 0; - } - - rgStart = handle.RealAddress; - } - - if (handle.Dirty) - { - rgSize += handle.RealSize; - handle.Reprotect(); - } - - prevHandle = handleIndex; - } - - baseBit += ConcurrentBitmap.IntSize; - } - - public void QueryModified(ulong address, ulong size, Action<ulong, ulong> modifiedAction) - { - int startHandle = (int)((address - Address) / Granularity); - int lastHandle = (int)((address + (size - 1) - Address) / Granularity); - - ulong rgStart = Address + (ulong)startHandle * Granularity; - - if (startHandle == lastHandle) - { - RegionHandle handle = _handles[startHandle]; - - if (handle.Dirty) - { - handle.Reprotect(); - modifiedAction(rgStart, handle.RealSize); - } - - return; - } - - ulong rgSize = 0; - - long[] masks = _dirtyBitmap.Masks; - - int startIndex = startHandle >> ConcurrentBitmap.IntShift; - int startBit = startHandle & ConcurrentBitmap.IntMask; - long startMask = -1L << startBit; - - int endIndex = lastHandle >> ConcurrentBitmap.IntShift; - int endBit = lastHandle & ConcurrentBitmap.IntMask; - long endMask = (long)(ulong.MaxValue >> (ConcurrentBitmap.IntMask - endBit)); - - long startValue = Volatile.Read(ref masks[startIndex]); - - int baseBit = startIndex << ConcurrentBitmap.IntShift; - int prevHandle = startHandle - 1; - - if (startIndex == endIndex) - { - ParseDirtyBits(startValue & startMask & endMask, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction); - } - else - { - ParseDirtyBits(startValue & startMask, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction); - - for (int i = startIndex + 1; i < endIndex; i++) - { - ParseDirtyBits(Volatile.Read(ref masks[i]), ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction); - } - - long endValue = Volatile.Read(ref masks[endIndex]); - - ParseDirtyBits(endValue & endMask, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction); - } - - if (rgSize != 0) - { - modifiedAction(rgStart, rgSize); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ParseDirtyBits(long dirtyBits, long mask, int index, long[] seqMasks, long[] checkMasks, ref int baseBit, ref int prevHandle, ref ulong rgStart, ref ulong rgSize, Action<ulong, ulong> modifiedAction) - { - long seqMask = mask & ~seqMasks[index]; - long checkMask = (~dirtyBits) & seqMask; - dirtyBits &= seqMask; - - while (dirtyBits != 0) - { - int bit = BitOperations.TrailingZeroCount(dirtyBits); - long bitValue = 1L << bit; - - dirtyBits &= ~bitValue; - - int handleIndex = baseBit + bit; - - RegionHandle handle = _handles[handleIndex]; - - if (handleIndex != prevHandle + 1) - { - // Submit handles scanned until the gap as dirty - if (rgSize != 0) - { - modifiedAction(rgStart, rgSize); - rgSize = 0; - } - rgStart = handle.RealAddress; - } - - rgSize += handle.RealSize; - handle.Reprotect(false, (checkMasks[index] & bitValue) == 0); - - checkMasks[index] &= ~bitValue; - - prevHandle = handleIndex; - } - - checkMasks[index] |= checkMask; - seqMasks[index] |= mask; - _uncheckedHandles -= BitOperations.PopCount((ulong)seqMask); - - baseBit += ConcurrentBitmap.IntSize; - } - - public void QueryModified(ulong address, ulong size, Action<ulong, ulong> modifiedAction, int sequenceNumber) - { - int startHandle = (int)((address - Address) / Granularity); - int lastHandle = (int)((address + (size - 1) - Address) / Granularity); - - ulong rgStart = Address + (ulong)startHandle * Granularity; - - if (sequenceNumber != _sequenceNumber) - { - if (_uncheckedHandles != _handles.Length) - { - _sequenceNumberBitmap.Clear(); - _uncheckedHandles = _handles.Length; - } - - _sequenceNumber = sequenceNumber; - } - - if (startHandle == lastHandle) - { - var handle = _handles[startHandle]; - if (_sequenceNumberBitmap.Set(startHandle)) - { - _uncheckedHandles--; - - if (handle.DirtyOrVolatile()) - { - handle.Reprotect(); - - modifiedAction(rgStart, handle.RealSize); - } - } - - return; - } - - if (_uncheckedHandles == 0) - { - return; - } - - ulong rgSize = 0; - - long[] seqMasks = _sequenceNumberBitmap.Masks; - long[] checkedMasks = _dirtyCheckedBitmap.Masks; - long[] masks = _dirtyBitmap.Masks; - - int startIndex = startHandle >> ConcurrentBitmap.IntShift; - int startBit = startHandle & ConcurrentBitmap.IntMask; - long startMask = -1L << startBit; - - int endIndex = lastHandle >> ConcurrentBitmap.IntShift; - int endBit = lastHandle & ConcurrentBitmap.IntMask; - long endMask = (long)(ulong.MaxValue >> (ConcurrentBitmap.IntMask - endBit)); - - long startValue = Volatile.Read(ref masks[startIndex]); - - int baseBit = startIndex << ConcurrentBitmap.IntShift; - int prevHandle = startHandle - 1; - - if (startIndex == endIndex) - { - ParseDirtyBits(startValue, startMask & endMask, startIndex, seqMasks, checkedMasks, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction); - } - else - { - ParseDirtyBits(startValue, startMask, startIndex, seqMasks, checkedMasks, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction); - - for (int i = startIndex + 1; i < endIndex; i++) - { - ParseDirtyBits(Volatile.Read(ref masks[i]), -1L, i, seqMasks, checkedMasks, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction); - } - - long endValue = Volatile.Read(ref masks[endIndex]); - - ParseDirtyBits(endValue, endMask, endIndex, seqMasks, checkedMasks, ref baseBit, ref prevHandle, ref rgStart, ref rgSize, modifiedAction); - } - - if (rgSize != 0) - { - modifiedAction(rgStart, rgSize); - } - } - - public void RegisterAction(ulong address, ulong size, RegionSignal action) - { - int startHandle = (int)((address - Address) / Granularity); - int lastHandle = (int)((address + (size - 1) - Address) / Granularity); - - for (int i = startHandle; i <= lastHandle; i++) - { - _handles[i].RegisterAction(action); - } - } - - public void RegisterPreciseAction(ulong address, ulong size, PreciseRegionSignal action) - { - int startHandle = (int)((address - Address) / Granularity); - int lastHandle = (int)((address + (size - 1) - Address) / Granularity); - - for (int i = startHandle; i <= lastHandle; i++) - { - _handles[i].RegisterPreciseAction(action); - } - } - - public void Dispose() - { - foreach (var handle in _handles) - { - handle.Dispose(); - } - } - } -} |
