Memory Changes part 2 (ryubing/ryujinx!123)

See merge request ryubing/ryujinx!123
This commit is contained in:
LotP
2025-08-25 17:44:15 -05:00
parent d499449f57
commit 50ab108ee1
90 changed files with 2133 additions and 1159 deletions

View File

@@ -131,7 +131,6 @@ namespace Ryujinx.Common.Collections
if (parent.Predecessor != null)
{
newNode.Predecessor = parent.Predecessor;
parent.Predecessor = newNode;
newNode.Predecessor.Successor = newNode;
}

View File

@@ -1,3 +1,5 @@
using System;
namespace Ryujinx.Common.Memory
{
/// <summary>
@@ -17,5 +19,10 @@ namespace Ryujinx.Common.Memory
/// Number of elements on the array.
/// </summary>
int Length { get; }
/// <summary>
/// Number of elements on the array.
/// </summary>
public Span<T> AsSpan();
}
}

View File

@@ -1,6 +1,7 @@
#nullable enable
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -10,11 +11,126 @@ namespace Ryujinx.Common.Memory
{
/// <summary>
/// An <see cref="IMemoryOwner{T}"/> implementation with an embedded length and fast <see cref="Span{T}"/>
/// accessor, with memory allocated from <seealso cref="ArrayPool{T}.Shared"/>.
/// accessor, with memory allocated from <see cref="ArrayPooling"/>.
/// </summary>
/// <typeparam name="T">The type of item to store.</typeparam>
public sealed class MemoryOwner<T> : IMemoryOwner<T>
{
private static class ArrayPooling
{
public class Holder(T[]? array = null) : IComparable<Holder>, IComparable<int>
{
public int SkipCount;
public readonly T[]? Array = array;
public int CompareTo(Holder? other)
{
return Array!.Length.CompareTo(other!.Array!.Length);
}
public int CompareTo(int other)
{
int self = Array!.Length;
if (self < other)
{
SkipCount++;
return -1;
}
if (self > other * 4)
{
return 1;
}
return 0;
}
}
// ReSharper disable once StaticMemberInGenericType
private static int _maxCacheCount = 50;
private const int MaxSkipCount = 50;
static readonly List<Holder> _pool = new();
// ReSharper disable once StaticMemberInGenericType
static readonly Lock _lock = new();
private static int BinarySearch(List<Holder> list, int size)
{
int min = 0;
int max = list.Count-1;
while (min <= max)
{
int mid = (min + max) / 2;
int comparison = list[mid].CompareTo(size);
if (comparison == 0)
{
return mid;
}
if (comparison < 0)
{
min = mid+1;
}
else
{
max = mid-1;
}
}
return ~min;
}
public static T[] Get(int minimumSize)
{
lock (_lock)
{
int index = BinarySearch(_pool, minimumSize);
if (index >= 0)
{
Holder holder = _pool[index];
_pool.Remove(holder);
return holder.Array!;
}
return new T[minimumSize];
}
}
public static void Return(T[] array)
{
lock (_lock)
{
Holder holder = new(array);
int i = _pool.BinarySearch(holder);
if (i < 0)
{
_pool.Insert(~i, holder);
}
if (_pool.Count >= _maxCacheCount)
{
for (int index = 0; index < _pool.Count; index++)
{
Holder h = _pool[index];
if (h.SkipCount >= MaxSkipCount)
{
_pool.Remove(h);
index--;
}
}
_maxCacheCount = _pool.Count * 2;
}
}
}
}
private readonly int _length;
private T[]? _array;
@@ -25,7 +141,7 @@ namespace Ryujinx.Common.Memory
private MemoryOwner(int length)
{
_length = length;
_array = ArrayPool<T>.Shared.Rent(length);
_array = ArrayPooling.Get(length);
}
/// <summary>
@@ -124,7 +240,7 @@ namespace Ryujinx.Common.Memory
if (array is not null)
{
ArrayPool<T>.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
ArrayPooling.Return(array);
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Runtime.InteropServices;
using System.Threading;
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
@@ -42,10 +43,13 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
public int GetOrReserve(int threadId, T initial)
{
// Try get a match first.
Span<int> threadIdsSpan = ThreadIds.AsSpan();
Span<T> structsSpan = Structs.AsSpan();
for (int i = 0; i < MapSize; i++)
{
int compare = Interlocked.CompareExchange(ref ThreadIds[i], threadId, threadId);
int compare = Interlocked.CompareExchange(ref threadIdsSpan[i], threadId, threadId);
if (compare == threadId)
{
@@ -57,11 +61,11 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
for (int i = 0; i < MapSize; i++)
{
int compare = Interlocked.CompareExchange(ref ThreadIds[i], threadId, 0);
int compare = Interlocked.CompareExchange(ref threadIdsSpan[i], threadId, 0);
if (compare == 0)
{
Structs[i] = initial;
structsSpan[i] = initial;
return i;
}
}