mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-09-29 20:07:55 +02:00
Memory changes 2.2
A few more internal changes to the RangeList systems. * No longer using a QuickAccess dictionary. * The performance of the dictionary wasn't much faster than just doing binary searches. * Using just binary searches allows us to take advantage of span and array returns as they're are faster than linked lists when iterating or copying the overlaps. Small code optimizations. Fixes a few leftover crashes.
This commit is contained in:
@@ -12,8 +12,8 @@ namespace Ryujinx.Memory.Range
|
||||
/// <typeparam name="T">Type of the range.</typeparam>
|
||||
public unsafe class NonOverlappingRangeList<T> : RangeListBase<T> where T : class, INonOverlappingRange
|
||||
{
|
||||
private readonly Dictionary<ulong, RangeItem<T>> _quickAccess = new(AddressEqualityComparer.Comparer);
|
||||
private readonly Dictionary<ulong, RangeItem<T>> _fastQuickAccess = new(AddressEqualityComparer.Comparer);
|
||||
// private readonly Dictionary<ulong, RangeItem<T>> _quickAccess = new(AddressEqualityComparer.Comparer);
|
||||
// private readonly Dictionary<ulong, RangeItem<T>> _fastQuickAccess = new(AddressEqualityComparer.Comparer);
|
||||
|
||||
public readonly ReaderWriterLockSlim Lock = new();
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Ryujinx.Memory.Range
|
||||
|
||||
Insert(index, rangeItem);
|
||||
|
||||
_quickAccess.Add(item.Address, rangeItem);
|
||||
// _quickAccess.Add(item.Address, rangeItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,15 +71,15 @@ namespace Ryujinx.Memory.Range
|
||||
Items[index + 1].Previous = rangeItem;
|
||||
}
|
||||
|
||||
foreach (ulong addr in Items[index].QuickAccessAddresses)
|
||||
{
|
||||
_quickAccess.Remove(addr);
|
||||
_fastQuickAccess.Remove(addr);
|
||||
}
|
||||
// foreach (ulong addr in Items[index].QuickAccessAddresses)
|
||||
// {
|
||||
// _quickAccess.Remove(addr);
|
||||
// _fastQuickAccess.Remove(addr);
|
||||
// }
|
||||
|
||||
Items[index] = rangeItem;
|
||||
|
||||
_quickAccess[item.Address] = rangeItem;
|
||||
// _quickAccess[item.Address] = rangeItem;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -108,18 +108,18 @@ namespace Ryujinx.Memory.Range
|
||||
Items[index + 1].Previous = rangeItem;
|
||||
}
|
||||
|
||||
foreach (ulong addr in item.QuickAccessAddresses)
|
||||
{
|
||||
_quickAccess.Remove(addr);
|
||||
_fastQuickAccess.Remove(addr);
|
||||
}
|
||||
// foreach (ulong addr in item.QuickAccessAddresses)
|
||||
// {
|
||||
// _quickAccess.Remove(addr);
|
||||
// _fastQuickAccess.Remove(addr);
|
||||
// }
|
||||
|
||||
Items[index] = rangeItem;
|
||||
|
||||
if (item.Address != rangeItem.Address)
|
||||
_quickAccess.Remove(item.Address);
|
||||
|
||||
_quickAccess[rangeItem.Address] = rangeItem;
|
||||
// if (item.Address != rangeItem.Address)
|
||||
// _quickAccess.Remove(item.Address);
|
||||
//
|
||||
// _quickAccess[rangeItem.Address] = rangeItem;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -196,13 +196,13 @@ namespace Ryujinx.Memory.Range
|
||||
|
||||
if (index >= 0 && Items[index].Value.Equals(item))
|
||||
{
|
||||
_quickAccess.Remove(item.Address);
|
||||
|
||||
foreach (ulong addr in Items[index].QuickAccessAddresses)
|
||||
{
|
||||
_quickAccess.Remove(addr);
|
||||
_fastQuickAccess.Remove(addr);
|
||||
}
|
||||
// _quickAccess.Remove(item.Address);
|
||||
//
|
||||
// foreach (ulong addr in Items[index].QuickAccessAddresses)
|
||||
// {
|
||||
// _quickAccess.Remove(addr);
|
||||
// _fastQuickAccess.Remove(addr);
|
||||
// }
|
||||
|
||||
RemoveAt(index);
|
||||
|
||||
@@ -232,15 +232,15 @@ namespace Ryujinx.Memory.Range
|
||||
|
||||
(int startIndex, int endIndex) = BinarySearchEdges(startItem.Address, endItem.EndAddress);
|
||||
|
||||
for (int i = startIndex; i < endIndex; i++)
|
||||
{
|
||||
_quickAccess.Remove(Items[i].Address);
|
||||
foreach (ulong addr in Items[i].QuickAccessAddresses)
|
||||
{
|
||||
_quickAccess.Remove(addr);
|
||||
_fastQuickAccess.Remove(addr);
|
||||
}
|
||||
}
|
||||
// for (int i = startIndex; i < endIndex; i++)
|
||||
// {
|
||||
// _quickAccess.Remove(Items[i].Address);
|
||||
// foreach (ulong addr in Items[i].QuickAccessAddresses)
|
||||
// {
|
||||
// _quickAccess.Remove(addr);
|
||||
// _fastQuickAccess.Remove(addr);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (endIndex < Count)
|
||||
{
|
||||
@@ -279,12 +279,12 @@ namespace Ryujinx.Memory.Range
|
||||
|
||||
while (Items[endIndex] is not null && Items[endIndex].Address < address + size)
|
||||
{
|
||||
_quickAccess.Remove(Items[endIndex].Address);
|
||||
foreach (ulong addr in Items[endIndex].QuickAccessAddresses)
|
||||
{
|
||||
_quickAccess.Remove(addr);
|
||||
_fastQuickAccess.Remove(addr);
|
||||
}
|
||||
// _quickAccess.Remove(Items[endIndex].Address);
|
||||
// foreach (ulong addr in Items[endIndex].QuickAccessAddresses)
|
||||
// {
|
||||
// _quickAccess.Remove(addr);
|
||||
// _fastQuickAccess.Remove(addr);
|
||||
// }
|
||||
|
||||
if (endIndex == Count - 1)
|
||||
{
|
||||
@@ -321,9 +321,9 @@ namespace Ryujinx.Memory.Range
|
||||
{
|
||||
Lock.EnterWriteLock();
|
||||
Count = 0;
|
||||
_quickAccess.Clear();
|
||||
_fastQuickAccess.Clear();
|
||||
Lock.ExitWriteLock();
|
||||
// _quickAccess.Clear();
|
||||
// _fastQuickAccess.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -344,7 +344,7 @@ namespace Ryujinx.Memory.Range
|
||||
// So we need to return both the split 0-1 and 1-2 ranges.
|
||||
|
||||
Lock.EnterWriteLock();
|
||||
(RangeItem<T> first, RangeItem<T> last) = FindOverlaps(address, size);
|
||||
(RangeItem<T> first, RangeItem<T> last) = FindOverlapsAsNodes(address, size);
|
||||
list = new List<T>();
|
||||
|
||||
if (first is null)
|
||||
@@ -436,10 +436,10 @@ namespace Ryujinx.Memory.Range
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override RangeItem<T> FindOverlap(ulong address, ulong size)
|
||||
{
|
||||
if (_quickAccess.TryGetValue(address, out RangeItem<T> overlap))
|
||||
{
|
||||
return overlap;
|
||||
}
|
||||
// if (_quickAccess.TryGetValue(address, out RangeItem<T> overlap))
|
||||
// {
|
||||
// return overlap;
|
||||
// }
|
||||
|
||||
int index = BinarySearchLeftEdge(address, address + size);
|
||||
|
||||
@@ -448,11 +448,11 @@ namespace Ryujinx.Memory.Range
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Items[index].Address < address)
|
||||
{
|
||||
_quickAccess.TryAdd(address, Items[index]);
|
||||
Items[index].QuickAccessAddresses.Add(address);
|
||||
}
|
||||
// if (Items[index].Address < address)
|
||||
// {
|
||||
// _quickAccess.TryAdd(address, Items[index]);
|
||||
// Items[index].QuickAccessAddresses.Add(address);
|
||||
// }
|
||||
|
||||
return Items[index];
|
||||
}
|
||||
@@ -466,10 +466,10 @@ namespace Ryujinx.Memory.Range
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override RangeItem<T> FindOverlapFast(ulong address, ulong size)
|
||||
{
|
||||
if (_quickAccess.TryGetValue(address, out RangeItem<T> overlap) || _fastQuickAccess.TryGetValue(address, out overlap))
|
||||
{
|
||||
return overlap;
|
||||
}
|
||||
// if (_quickAccess.TryGetValue(address, out RangeItem<T> overlap) || _fastQuickAccess.TryGetValue(address, out overlap))
|
||||
// {
|
||||
// return overlap;
|
||||
// }
|
||||
|
||||
int index = BinarySearch(address, address + size);
|
||||
|
||||
@@ -478,16 +478,16 @@ namespace Ryujinx.Memory.Range
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Items[index].Address < address)
|
||||
{
|
||||
_quickAccess.TryAdd(address, Items[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
_fastQuickAccess.TryAdd(address, Items[index]);
|
||||
}
|
||||
|
||||
Items[index].QuickAccessAddresses.Add(address);
|
||||
// if (Items[index].Address < address)
|
||||
// {
|
||||
// _quickAccess.TryAdd(address, Items[index]);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// _fastQuickAccess.TryAdd(address, Items[index]);
|
||||
// }
|
||||
//
|
||||
// Items[index].QuickAccessAddresses.Add(address);
|
||||
|
||||
return Items[index];
|
||||
}
|
||||
@@ -499,18 +499,8 @@ namespace Ryujinx.Memory.Range
|
||||
/// <param name="size">Size in bytes of the range</param>
|
||||
/// <returns>The first and last overlapping items, or null if none are found</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public (RangeItem<T>, RangeItem<T>) FindOverlaps(ulong address, ulong size)
|
||||
public (RangeItem<T>, RangeItem<T>) FindOverlapsAsNodes(ulong address, ulong size)
|
||||
{
|
||||
if (_quickAccess.TryGetValue(address, out RangeItem<T> overlap))
|
||||
{
|
||||
if (overlap.Next is null || overlap.Next.Address >= address + size)
|
||||
{
|
||||
return (overlap, overlap);
|
||||
}
|
||||
|
||||
return (overlap, Items[BinarySearchRightEdge(address, address + size)]);
|
||||
}
|
||||
|
||||
(int index, int endIndex) = BinarySearchEdges(address, address + size);
|
||||
|
||||
if (index < 0)
|
||||
@@ -518,13 +508,45 @@ namespace Ryujinx.Memory.Range
|
||||
return (null, null);
|
||||
}
|
||||
|
||||
if (Items[index].Address < address)
|
||||
return (Items[index], Items[endIndex - 1]);
|
||||
}
|
||||
|
||||
public RangeItem<T>[] FindOverlapsAsArray(ulong address, ulong size)
|
||||
{
|
||||
(int index, int endIndex) = BinarySearchEdges(address, address + size);
|
||||
|
||||
RangeItem<T>[] result;
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
_quickAccess.TryAdd(address, Items[index]);
|
||||
Items[index].QuickAccessAddresses.Add(address);
|
||||
result = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
result = new RangeItem<T>[endIndex - index];
|
||||
|
||||
Array.Copy(Items, index, result, 0, endIndex - index);
|
||||
}
|
||||
|
||||
return (Items[index], Items[endIndex - 1]);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Span<RangeItem<T>> FindOverlapsAsSpan(ulong address, ulong size)
|
||||
{
|
||||
(int index, int endIndex) = BinarySearchEdges(address, address + size);
|
||||
|
||||
Span<RangeItem<T>> result;
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
result = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Items.AsSpan().Slice(index, endIndex - index);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override IEnumerator<T> GetEnumerator()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Memory.Range;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Memory.Tracking
|
||||
@@ -79,12 +80,10 @@ namespace Ryujinx.Memory.Tracking
|
||||
{
|
||||
NonOverlappingRangeList<VirtualRegion> regions = type == 0 ? _virtualRegions : _guestVirtualRegions;
|
||||
regions.Lock.EnterReadLock();
|
||||
(RangeItem<VirtualRegion> first, RangeItem<VirtualRegion> last) = regions.FindOverlaps(va, size);
|
||||
|
||||
RangeItem<VirtualRegion> current = first;
|
||||
while (last != null && current != last.Next)
|
||||
Span<RangeItem<VirtualRegion>> overlaps = regions.FindOverlapsAsSpan(va, size);
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
VirtualRegion region = current.Value;
|
||||
VirtualRegion region = overlaps[i].Value;
|
||||
|
||||
// If the region has been fully remapped, signal that it has been mapped again.
|
||||
bool remapped = _memoryManager.IsRangeMapped(region.Address, region.Size);
|
||||
@@ -94,7 +93,6 @@ namespace Ryujinx.Memory.Tracking
|
||||
}
|
||||
|
||||
region.UpdateProtection();
|
||||
current = current.Next;
|
||||
}
|
||||
regions.Lock.ExitReadLock();
|
||||
}
|
||||
@@ -118,15 +116,11 @@ namespace Ryujinx.Memory.Tracking
|
||||
{
|
||||
NonOverlappingRangeList<VirtualRegion> regions = type == 0 ? _virtualRegions : _guestVirtualRegions;
|
||||
regions.Lock.EnterReadLock();
|
||||
(RangeItem<VirtualRegion> first, RangeItem<VirtualRegion> last) = regions.FindOverlaps(va, size);
|
||||
Span<RangeItem<VirtualRegion>> overlaps = regions.FindOverlapsAsSpan(va, size);
|
||||
|
||||
RangeItem<VirtualRegion> current = first;
|
||||
while (last != null && current != last.Next)
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
VirtualRegion region = current.Value;
|
||||
|
||||
region.SignalMappingChanged(false);
|
||||
current = current.Next;
|
||||
overlaps[i].Value.SignalMappingChanged(false);
|
||||
}
|
||||
regions.Lock.ExitReadLock();
|
||||
}
|
||||
@@ -303,21 +297,13 @@ namespace Ryujinx.Memory.Tracking
|
||||
lock (TrackingLock)
|
||||
{
|
||||
NonOverlappingRangeList<VirtualRegion> regions = guest ? _guestVirtualRegions : _virtualRegions;
|
||||
List<RangeItem<VirtualRegion>> overlaps = [];
|
||||
|
||||
// We use the non-span method here because keeping the lock will cause a deadlock.
|
||||
regions.Lock.EnterReadLock();
|
||||
(RangeItem<VirtualRegion> first, RangeItem<VirtualRegion> last) = regions.FindOverlaps(address, size);
|
||||
|
||||
RangeItem<VirtualRegion> current = first;
|
||||
while (last != null && current != last.Next)
|
||||
{
|
||||
overlaps.Add(current);
|
||||
current = current.Next;
|
||||
}
|
||||
RangeItem<VirtualRegion>[] overlaps = regions.FindOverlapsAsArray(address, size);
|
||||
regions.Lock.ExitReadLock();
|
||||
|
||||
if (first is null && !precise)
|
||||
if (overlaps.Length == 0 && !precise)
|
||||
{
|
||||
if (_memoryManager.IsRangeMapped(address, size))
|
||||
{
|
||||
@@ -338,7 +324,7 @@ namespace Ryujinx.Memory.Tracking
|
||||
size += (ulong)_pageSize;
|
||||
}
|
||||
|
||||
for (int i = 0; i < overlaps.Count; i++)
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
VirtualRegion region = overlaps[i].Value;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user