Skip to content

Commit

Permalink
JIT Sparse Function Table (#250)
Browse files Browse the repository at this point in the history
More up to date build of the JIT Sparse PR for continued development.
JIT Sparse Function Table was originally developed by riperiperi for the
original Ryujinx project, and decreased the amount of layers in the
Function Table structure, to decrease lookup times at the cost of
slightly higher RAM usage.
This PR rebalances the JIT Sparse Function Table to be a bit more RAM
intensive, but faster in workloads where the JIT Function Table is a
bottleneck. Faster RAM will see a bigger impact and slower RAM (DDR3 and
potentially slow DDR4) will see a slight performance decrease.
This PR also implements a base for a PPTC profile system that could
allow for PPTC with ExeFS mods enabled in the future.
This PR also potentially fixes a strange issue where Avalonia would time
out in some rare instances, e.g. when running ExeFS mods with TotK and a
strange controller configuration.

---------

Co-authored-by: Evan Husted <gr33m11@gmail.com>
  • Loading branch information
LotP1 and GreemDev authored Nov 22, 2024
1 parent 5534001 commit e653848
Show file tree
Hide file tree
Showing 27 changed files with 990 additions and 327 deletions.
252 changes: 0 additions & 252 deletions src/ARMeilleure/Common/AddressTable.cs

This file was deleted.

44 changes: 44 additions & 0 deletions src/ARMeilleure/Common/AddressTableLevel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
namespace ARMeilleure.Common
{
/// <summary>
/// Represents a level in an <see cref="IAddressTable{TEntry}"/>.
/// </summary>
public readonly struct AddressTableLevel
{
/// <summary>
/// Gets the index of the <see cref="Level"/> in the guest address.
/// </summary>
public int Index { get; }

/// <summary>
/// Gets the length of the <see cref="AddressTableLevel"/> in the guest address.
/// </summary>
public int Length { get; }

/// <summary>
/// Gets the mask which masks the bits used by the <see cref="AddressTableLevel"/>.
/// </summary>
public ulong Mask => ((1ul << Length) - 1) << Index;

/// <summary>
/// Initializes a new instance of the <see cref="AddressTableLevel"/> structure with the specified
/// <paramref name="index"/> and <paramref name="length"/>.
/// </summary>
/// <param name="index">Index of the <see cref="AddressTableLevel"/></param>
/// <param name="length">Length of the <see cref="AddressTableLevel"/></param>
public AddressTableLevel(int index, int length)
{
(Index, Length) = (index, length);
}

/// <summary>
/// Gets the value of the <see cref="AddressTableLevel"/> from the specified guest <paramref name="address"/>.
/// </summary>
/// <param name="address">Guest address</param>
/// <returns>Value of the <see cref="AddressTableLevel"/> from the specified guest <paramref name="address"/></returns>
public int GetValue(ulong address)
{
return (int)((address & Mask) >> Index);
}
}
}
75 changes: 75 additions & 0 deletions src/ARMeilleure/Common/AddressTablePresets.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
namespace ARMeilleure.Common
{
public static class AddressTablePresets
{
private static readonly AddressTableLevel[] _levels64Bit =
new AddressTableLevel[]
{
new(31, 17),
new(23, 8),
new(15, 8),
new( 7, 8),
new( 2, 5),
};

private static readonly AddressTableLevel[] _levels32Bit =
new AddressTableLevel[]
{
new(31, 17),
new(23, 8),
new(15, 8),
new( 7, 8),
new( 1, 6),
};

private static readonly AddressTableLevel[] _levels64BitSparseTiny =
new AddressTableLevel[]
{
new( 11, 28),
new( 2, 9),
};

private static readonly AddressTableLevel[] _levels32BitSparseTiny =
new AddressTableLevel[]
{
new( 10, 22),
new( 1, 9),
};

private static readonly AddressTableLevel[] _levels64BitSparseGiant =
new AddressTableLevel[]
{
new( 38, 1),
new( 2, 36),
};

private static readonly AddressTableLevel[] _levels32BitSparseGiant =
new AddressTableLevel[]
{
new( 31, 1),
new( 1, 30),
};

//high power will run worse on DDR3 systems and some DDR4 systems due to the higher ram utilization
//low power will never run worse than non-sparse, but for most systems it won't be necessary
//high power is always used, but I've left low power in here for future reference
public static AddressTableLevel[] GetArmPreset(bool for64Bits, bool sparse, bool lowPower = false)
{
if (sparse)
{
if (lowPower)
{
return for64Bits ? _levels64BitSparseTiny : _levels32BitSparseTiny;
}
else
{
return for64Bits ? _levels64BitSparseGiant : _levels32BitSparseGiant;
}
}
else
{
return for64Bits ? _levels64Bit : _levels32Bit;
}
}
}
}
2 changes: 1 addition & 1 deletion src/ARMeilleure/Common/Allocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace ARMeilleure.Common
{
unsafe abstract class Allocator : IDisposable
public unsafe abstract class Allocator : IDisposable
{
public T* Allocate<T>(ulong count = 1) where T : unmanaged
{
Expand Down
Loading

0 comments on commit e653848

Please sign in to comment.