avoid allocations when doing address space lookup
Add missing improvement
This commit is contained in:
parent
1112d86882
commit
14c14e1896
4 changed files with 108 additions and 24 deletions
|
@ -5,10 +5,10 @@ namespace Ryujinx.Common.Collections
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class IntrusiveRedBlackTreeNode<T> where T : IntrusiveRedBlackTreeNode<T>
|
public class IntrusiveRedBlackTreeNode<T> where T : IntrusiveRedBlackTreeNode<T>
|
||||||
{
|
{
|
||||||
internal bool Color = true;
|
public bool Color = true;
|
||||||
internal T Left;
|
public T Left;
|
||||||
internal T Right;
|
public T Right;
|
||||||
internal T Parent;
|
public T Parent;
|
||||||
|
|
||||||
public T Predecessor => IntrusiveRedBlackTreeImpl<T>.PredecessorOf((T)this);
|
public T Predecessor => IntrusiveRedBlackTreeImpl<T>.PredecessorOf((T)this);
|
||||||
public T Successor => IntrusiveRedBlackTreeImpl<T>.SuccessorOf((T)this);
|
public T Successor => IntrusiveRedBlackTreeImpl<T>.SuccessorOf((T)this);
|
||||||
|
|
35
src/Ryujinx.Cpu/Jit/AddressIntrusiveRedBlackTree.cs
Normal file
35
src/Ryujinx.Cpu/Jit/AddressIntrusiveRedBlackTree.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
using Ryujinx.Common.Collections;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Cpu.Jit
|
||||||
|
{
|
||||||
|
internal class AddressIntrusiveRedBlackTree<T> : IntrusiveRedBlackTree<T> where T : IntrusiveRedBlackTreeNode<T>, IComparable<T>, IComparable<ulong>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve the node that is considered equal to the specified address by the comparator.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address">Address to compare with</param>
|
||||||
|
/// <returns>Node that is equal to <paramref name="address"/></returns>
|
||||||
|
public T GetNode(ulong address)
|
||||||
|
{
|
||||||
|
T node = Root;
|
||||||
|
while (node != null)
|
||||||
|
{
|
||||||
|
int cmp = node.CompareTo(address);
|
||||||
|
if (cmp < 0)
|
||||||
|
{
|
||||||
|
node = node.Left;
|
||||||
|
}
|
||||||
|
else if (cmp > 0)
|
||||||
|
{
|
||||||
|
node = node.Right;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
Private,
|
Private,
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Mapping : IntrusiveRedBlackTreeNode<Mapping>, IComparable<Mapping>
|
private class Mapping : IntrusiveRedBlackTreeNode<Mapping>, IComparable<Mapping>, IComparable<ulong>
|
||||||
{
|
{
|
||||||
public ulong Address { get; private set; }
|
public ulong Address { get; private set; }
|
||||||
public ulong Size { get; private set; }
|
public ulong Size { get; private set; }
|
||||||
|
@ -87,9 +87,25 @@ namespace Ryujinx.Cpu.Jit
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int CompareTo(ulong address)
|
||||||
|
{
|
||||||
|
if (address < Address)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (address <= EndAddress - 1UL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PrivateMapping : IntrusiveRedBlackTreeNode<PrivateMapping>, IComparable<PrivateMapping>
|
private class PrivateMapping : IntrusiveRedBlackTreeNode<PrivateMapping>, IComparable<PrivateMapping>, IComparable<ulong>
|
||||||
{
|
{
|
||||||
public ulong Address { get; private set; }
|
public ulong Address { get; private set; }
|
||||||
public ulong Size { get; private set; }
|
public ulong Size { get; private set; }
|
||||||
|
@ -158,13 +174,30 @@ namespace Ryujinx.Cpu.Jit
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int CompareTo(ulong address)
|
||||||
|
{
|
||||||
|
if (address < Address)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (address <= EndAddress - 1UL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly MemoryBlock _backingMemory;
|
private readonly MemoryBlock _backingMemory;
|
||||||
private readonly AddressSpacePartitionMultiAllocation _baseMemory;
|
private readonly AddressSpacePartitionMultiAllocation _baseMemory;
|
||||||
private readonly PrivateMemoryAllocator _privateMemoryAllocator;
|
private readonly PrivateMemoryAllocator _privateMemoryAllocator;
|
||||||
private readonly IntrusiveRedBlackTree<Mapping> _mappingTree;
|
|
||||||
private readonly IntrusiveRedBlackTree<PrivateMapping> _privateTree;
|
private readonly AddressIntrusiveRedBlackTree<Mapping> _mappingTree;
|
||||||
|
private readonly AddressIntrusiveRedBlackTree<PrivateMapping> _privateTree;
|
||||||
|
|
||||||
private readonly ReaderWriterLockSlim _treeLock;
|
private readonly ReaderWriterLockSlim _treeLock;
|
||||||
|
|
||||||
|
@ -186,8 +219,8 @@ namespace Ryujinx.Cpu.Jit
|
||||||
public AddressSpacePartition(AddressSpacePartitionAllocation baseMemory, MemoryBlock backingMemory, ulong address, ulong size)
|
public AddressSpacePartition(AddressSpacePartitionAllocation baseMemory, MemoryBlock backingMemory, ulong address, ulong size)
|
||||||
{
|
{
|
||||||
_privateMemoryAllocator = new PrivateMemoryAllocator(DefaultBlockAlignment, MemoryAllocationFlags.Mirrorable);
|
_privateMemoryAllocator = new PrivateMemoryAllocator(DefaultBlockAlignment, MemoryAllocationFlags.Mirrorable);
|
||||||
_mappingTree = new IntrusiveRedBlackTree<Mapping>();
|
_mappingTree = new AddressIntrusiveRedBlackTree<Mapping>();
|
||||||
_privateTree = new IntrusiveRedBlackTree<PrivateMapping>();
|
_privateTree = new AddressIntrusiveRedBlackTree<PrivateMapping>();
|
||||||
_treeLock = new ReaderWriterLockSlim();
|
_treeLock = new ReaderWriterLockSlim();
|
||||||
|
|
||||||
_mappingTree.Add(new Mapping(address, size, MappingType.None));
|
_mappingTree.Add(new Mapping(address, size, MappingType.None));
|
||||||
|
@ -212,7 +245,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Mapping map = _mappingTree.GetNode(new Mapping(Address, Size, MappingType.None));
|
Mapping map = _mappingTree.GetNode(Address);
|
||||||
|
|
||||||
return map != null && map.Address == Address && map.Size == Size && map.Type == MappingType.None;
|
return map != null && map.Address == Address && map.Size == Size && map.Type == MappingType.None;
|
||||||
}
|
}
|
||||||
|
@ -425,7 +458,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PrivateMapping map = _privateTree.GetNode(new PrivateMapping(Address, 1UL, default));
|
PrivateMapping map = _privateTree.GetNode(Address);
|
||||||
|
|
||||||
if (map != null && map.PrivateAllocation.IsValid)
|
if (map != null && map.PrivateAllocation.IsValid)
|
||||||
{
|
{
|
||||||
|
@ -448,7 +481,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
{
|
{
|
||||||
ulong pageAddress = EndAddress - _hostPageSize;
|
ulong pageAddress = EndAddress - _hostPageSize;
|
||||||
|
|
||||||
PrivateMapping map = _privateTree.GetNode(new PrivateMapping(pageAddress, 1UL, default));
|
PrivateMapping map = _privateTree.GetNode(pageAddress);
|
||||||
|
|
||||||
if (map != null && map.PrivateAllocation.IsValid)
|
if (map != null && map.PrivateAllocation.IsValid)
|
||||||
{
|
{
|
||||||
|
@ -469,7 +502,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, 1UL, default));
|
PrivateMapping map = _privateTree.GetNode(va);
|
||||||
|
|
||||||
if (map != null && map.PrivateAllocation.IsValid)
|
if (map != null && map.PrivateAllocation.IsValid)
|
||||||
{
|
{
|
||||||
|
@ -490,7 +523,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Mapping map = _mappingTree.GetNode(new Mapping(va, 1UL, MappingType.None));
|
Mapping map = _mappingTree.GetNode(va);
|
||||||
|
|
||||||
Update(map, va, pa, size, type);
|
Update(map, va, pa, size, type);
|
||||||
}
|
}
|
||||||
|
@ -584,7 +617,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
ulong vaAligned = BitUtils.AlignDown(va, alignment);
|
ulong vaAligned = BitUtils.AlignDown(va, alignment);
|
||||||
ulong endAddressAligned = BitUtils.AlignUp(endAddress, alignment);
|
ulong endAddressAligned = BitUtils.AlignUp(endAddress, alignment);
|
||||||
|
|
||||||
PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, 1UL, default));
|
PrivateMapping map = _privateTree.GetNode(va);
|
||||||
|
|
||||||
for (; map != null; map = map.Successor)
|
for (; map != null; map = map.Successor)
|
||||||
{
|
{
|
||||||
|
@ -628,7 +661,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrivateMapping map = _privateTree.GetNode(new PrivateMapping(vaAligned, 1UL, default));
|
PrivateMapping map = _privateTree.GetNode(vaAligned);
|
||||||
|
|
||||||
for (; map != null; map = map.Successor)
|
for (; map != null; map = map.Successor)
|
||||||
{
|
{
|
||||||
|
@ -688,7 +721,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
// Map all existing private allocations.
|
// Map all existing private allocations.
|
||||||
// This is necessary to ensure mirrors that are lazily created have the same mappings as the main one.
|
// This is necessary to ensure mirrors that are lazily created have the same mappings as the main one.
|
||||||
|
|
||||||
PrivateMapping map = _privateTree.GetNode(new PrivateMapping(Address, 1UL, default));
|
PrivateMapping map = _privateTree.GetNode(Address);
|
||||||
|
|
||||||
for (; map != null; map = map.Successor)
|
for (; map != null; map = map.Successor)
|
||||||
{
|
{
|
||||||
|
@ -705,7 +738,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, 1UL, default));
|
PrivateMapping map = _privateTree.GetNode(va);
|
||||||
|
|
||||||
nextVa = map.EndAddress;
|
nextVa = map.EndAddress;
|
||||||
|
|
||||||
|
@ -733,7 +766,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, size, default));
|
PrivateMapping map = _privateTree.GetNode(va);
|
||||||
|
|
||||||
if (map != null && map.PrivateAllocation.IsValid)
|
if (map != null && map.PrivateAllocation.IsValid)
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,7 +65,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
private readonly Func<ulong, ulong> _readPtCallback;
|
private readonly Func<ulong, ulong> _readPtCallback;
|
||||||
private readonly MemoryEhMeilleure _memoryEh;
|
private readonly MemoryEhMeilleure _memoryEh;
|
||||||
|
|
||||||
private class Mapping : IntrusiveRedBlackTreeNode<Mapping>, IComparable<Mapping>
|
private class Mapping : IntrusiveRedBlackTreeNode<Mapping>, IComparable<Mapping>, IComparable<ulong>
|
||||||
{
|
{
|
||||||
public ulong Address { get; }
|
public ulong Address { get; }
|
||||||
public ulong Size { get; }
|
public ulong Size { get; }
|
||||||
|
@ -98,9 +98,25 @@ namespace Ryujinx.Cpu.Jit
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int CompareTo(ulong address)
|
||||||
|
{
|
||||||
|
if (address < Address)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (address <= EndAddress - 1UL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly IntrusiveRedBlackTree<Mapping> _mappingTree;
|
private readonly AddressIntrusiveRedBlackTree<Mapping> _mappingTree;
|
||||||
private readonly object _lock;
|
private readonly object _lock;
|
||||||
|
|
||||||
public Block(MemoryTracking tracking, Func<ulong, ulong> readPtCallback, MemoryBlock memory, ulong size, object locker) : base(memory, size)
|
public Block(MemoryTracking tracking, Func<ulong, ulong> readPtCallback, MemoryBlock memory, ulong size, object locker) : base(memory, size)
|
||||||
|
@ -119,7 +135,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
|
|
||||||
public void RemoveMapping(ulong offset, ulong size)
|
public void RemoveMapping(ulong offset, ulong size)
|
||||||
{
|
{
|
||||||
_mappingTree.Remove(_mappingTree.GetNode(new Mapping(offset, size, 0, 0, 0)));
|
_mappingTree.Remove(_mappingTree.GetNode(offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ulong VirtualMemoryEvent(ulong address, ulong size, bool write)
|
private ulong VirtualMemoryEvent(ulong address, ulong size, bool write)
|
||||||
|
@ -128,7 +144,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
map = _mappingTree.GetNode(new Mapping(address, size, 0, 0, 0));
|
map = _mappingTree.GetNode(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (map == null)
|
if (map == null)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue