forked from Mirror/Ryujinx
PPTC vs. giant ExeFS. (#2168)
* PPTC vs. giant ExeFS. * InternalVersion = 2168 * Add new heuristic algorithm for calculating the number of threads for parallel translations that also takes into account the user's free physical memory and not just the number of CPU cores. * Nit. * Add an outer Header structure and add the hashes for both this new structure and the existing "inner" Header structure. * InternalVersion = 2169
This commit is contained in:
parent
7344dee475
commit
90163087a0
9 changed files with 367 additions and 197 deletions
50
ARMeilleure/Translation/PTC/DegreeOfParallelism.cs
Normal file
50
ARMeilleure/Translation/PTC/DegreeOfParallelism.cs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Translation.PTC
|
||||||
|
{
|
||||||
|
class DegreeOfParallelism
|
||||||
|
{
|
||||||
|
public double GiBRef { get; } // GiB.
|
||||||
|
public double WeightRef { get; } // %.
|
||||||
|
public double IncrementByGiB { get; } // %.
|
||||||
|
private double _coefficient;
|
||||||
|
|
||||||
|
public DegreeOfParallelism(double gibRef, double weightRef, double incrementByGiB)
|
||||||
|
{
|
||||||
|
GiBRef = gibRef;
|
||||||
|
WeightRef = weightRef;
|
||||||
|
IncrementByGiB = incrementByGiB;
|
||||||
|
|
||||||
|
_coefficient = weightRef - (incrementByGiB * gibRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetDegreeOfParallelism(int min, int max)
|
||||||
|
{
|
||||||
|
double degreeOfParallelism = (GetProcessorCount() * GetWeight(GetAvailableMemoryGiB())) / 100d;
|
||||||
|
|
||||||
|
return Math.Clamp((int)Math.Round(degreeOfParallelism), min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double GetProcessorCount()
|
||||||
|
{
|
||||||
|
return (double)Environment.ProcessorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double GetWeight(double gib)
|
||||||
|
{
|
||||||
|
return (IncrementByGiB * gib) + _coefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double GetAvailableMemoryGiB()
|
||||||
|
{
|
||||||
|
GCMemoryInfo gcMemoryInfo = GC.GetGCMemoryInfo();
|
||||||
|
|
||||||
|
return FromBytesToGiB(gcMemoryInfo.TotalAvailableMemoryBytes - gcMemoryInfo.MemoryLoadBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double FromBytesToGiB(long bytes)
|
||||||
|
{
|
||||||
|
return Math.ScaleB((double)bytes, -30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,8 +2,8 @@ using System.Text;
|
||||||
|
|
||||||
namespace ARMeilleure.Translation.PTC
|
namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
internal static class EncodingCache
|
static class EncodingCache
|
||||||
{
|
{
|
||||||
internal static readonly Encoding UTF8NoBOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
|
public static readonly Encoding UTF8NoBOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,9 +24,10 @@ namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
public static class Ptc
|
public static class Ptc
|
||||||
{
|
{
|
||||||
private const string HeaderMagicString = "PTChd\0\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 2155; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 2169; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
@ -41,14 +42,16 @@ namespace ARMeilleure.Translation.PTC
|
||||||
private const byte FillingByte = 0x00;
|
private const byte FillingByte = 0x00;
|
||||||
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
|
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
|
||||||
|
|
||||||
|
// Carriers.
|
||||||
private static MemoryStream _infosStream;
|
private static MemoryStream _infosStream;
|
||||||
private static MemoryStream _codesStream;
|
private static List<byte[]> _codesList;
|
||||||
private static MemoryStream _relocsStream;
|
private static MemoryStream _relocsStream;
|
||||||
private static MemoryStream _unwindInfosStream;
|
private static MemoryStream _unwindInfosStream;
|
||||||
|
|
||||||
private static BinaryWriter _infosWriter;
|
private static BinaryWriter _infosWriter;
|
||||||
|
|
||||||
private static readonly ulong _headerMagic;
|
private static readonly ulong _outerHeaderMagic;
|
||||||
|
private static readonly ulong _innerHeaderMagic;
|
||||||
|
|
||||||
private static readonly ManualResetEvent _waitEvent;
|
private static readonly ManualResetEvent _waitEvent;
|
||||||
|
|
||||||
|
@ -66,16 +69,17 @@ namespace ARMeilleure.Translation.PTC
|
||||||
|
|
||||||
internal static PtcState State { get; private set; }
|
internal static PtcState State { get; private set; }
|
||||||
|
|
||||||
// Progress reporting helpers
|
// Progress reporting helpers.
|
||||||
private static volatile int _translateCount;
|
private static volatile int _translateCount;
|
||||||
private static volatile int _translateTotalCount;
|
private static volatile int _translateTotalCount;
|
||||||
public static event Action<PtcLoadingState, int, int> PtcStateChanged;
|
public static event Action<PtcLoadingState, int, int> PtcStateChanged;
|
||||||
|
|
||||||
static Ptc()
|
static Ptc()
|
||||||
{
|
{
|
||||||
InitializeMemoryStreams();
|
InitializeCarriers();
|
||||||
|
|
||||||
_headerMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(HeaderMagicString).AsSpan());
|
_outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
|
||||||
|
_innerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(InnerHeaderMagicString).AsSpan());
|
||||||
|
|
||||||
_waitEvent = new ManualResetEvent(true);
|
_waitEvent = new ManualResetEvent(true);
|
||||||
|
|
||||||
|
@ -141,41 +145,41 @@ namespace ARMeilleure.Translation.PTC
|
||||||
Enable();
|
Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void InitializeMemoryStreams()
|
private static void InitializeCarriers()
|
||||||
{
|
{
|
||||||
_infosStream = new MemoryStream();
|
_infosStream = new MemoryStream();
|
||||||
_codesStream = new MemoryStream();
|
_codesList = new List<byte[]>();
|
||||||
_relocsStream = new MemoryStream();
|
_relocsStream = new MemoryStream();
|
||||||
_unwindInfosStream = new MemoryStream();
|
_unwindInfosStream = new MemoryStream();
|
||||||
|
|
||||||
_infosWriter = new BinaryWriter(_infosStream, EncodingCache.UTF8NoBOM, true);
|
_infosWriter = new BinaryWriter(_infosStream, EncodingCache.UTF8NoBOM, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DisposeMemoryStreams()
|
private static void DisposeCarriers()
|
||||||
{
|
{
|
||||||
_infosWriter.Dispose();
|
_infosWriter.Dispose();
|
||||||
|
|
||||||
_infosStream.Dispose();
|
_infosStream.Dispose();
|
||||||
_codesStream.Dispose();
|
_codesList.Clear();
|
||||||
_relocsStream.Dispose();
|
_relocsStream.Dispose();
|
||||||
_unwindInfosStream.Dispose();
|
_unwindInfosStream.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool AreMemoryStreamsEmpty()
|
private static bool AreCarriersEmpty()
|
||||||
{
|
{
|
||||||
return _infosStream.Length == 0L && _codesStream.Length == 0L && _relocsStream.Length == 0L && _unwindInfosStream.Length == 0L;
|
return _infosStream.Length == 0L && _codesList.Count == 0 && _relocsStream.Length == 0L && _unwindInfosStream.Length == 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ResetMemoryStreamsIfNeeded()
|
private static void ResetCarriersIfNeeded()
|
||||||
{
|
{
|
||||||
if (AreMemoryStreamsEmpty())
|
if (AreCarriersEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DisposeMemoryStreams();
|
DisposeCarriers();
|
||||||
|
|
||||||
InitializeMemoryStreams();
|
InitializeCarriers();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PreLoad()
|
private static void PreLoad()
|
||||||
|
@ -207,28 +211,57 @@ namespace ARMeilleure.Translation.PTC
|
||||||
using (FileStream compressedStream = new(fileName, FileMode.Open))
|
using (FileStream compressedStream = new(fileName, FileMode.Open))
|
||||||
using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true))
|
using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true))
|
||||||
{
|
{
|
||||||
Hash128 currentSizeHash = DeserializeStructure<Hash128>(compressedStream);
|
OuterHeader outerHeader = DeserializeStructure<OuterHeader>(compressedStream);
|
||||||
|
|
||||||
Span<byte> sizeBytes = new byte[sizeof(int)];
|
if (!outerHeader.IsHeaderValid())
|
||||||
compressedStream.Read(sizeBytes);
|
|
||||||
Hash128 expectedSizeHash = XXHash128.ComputeHash(sizeBytes);
|
|
||||||
|
|
||||||
if (currentSizeHash != expectedSizeHash)
|
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int size = BinaryPrimitives.ReadInt32LittleEndian(sizeBytes);
|
if (outerHeader.Magic != _outerHeaderMagic)
|
||||||
|
{
|
||||||
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outerHeader.CacheFileVersion != InternalVersion)
|
||||||
|
{
|
||||||
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outerHeader.Endianness != GetEndianness())
|
||||||
|
{
|
||||||
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outerHeader.FeatureInfo != GetFeatureInfo())
|
||||||
|
{
|
||||||
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outerHeader.OSPlatform != GetOSPlatform())
|
||||||
|
{
|
||||||
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
IntPtr intPtr = IntPtr.Zero;
|
IntPtr intPtr = IntPtr.Zero;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
intPtr = Marshal.AllocHGlobal(size);
|
intPtr = Marshal.AllocHGlobal(new IntPtr(outerHeader.UncompressedStreamSize));
|
||||||
|
|
||||||
using (UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), size, size, FileAccess.ReadWrite))
|
using (UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), outerHeader.UncompressedStreamSize, outerHeader.UncompressedStreamSize, FileAccess.ReadWrite))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -241,96 +274,104 @@ namespace ARMeilleure.Translation.PTC
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hashSize = Unsafe.SizeOf<Hash128>();
|
Debug.Assert(stream.Position == stream.Length);
|
||||||
|
|
||||||
stream.Seek(0L, SeekOrigin.Begin);
|
stream.Seek(0L, SeekOrigin.Begin);
|
||||||
Hash128 currentHash = DeserializeStructure<Hash128>(stream);
|
|
||||||
|
|
||||||
ReadOnlySpan<byte> streamBytes = new(stream.PositionPointer, (int)(stream.Length - stream.Position));
|
InnerHeader innerHeader = DeserializeStructure<InnerHeader>(stream);
|
||||||
Hash128 expectedHash = XXHash128.ComputeHash(streamBytes);
|
|
||||||
|
|
||||||
if (currentHash != expectedHash)
|
if (!innerHeader.IsHeaderValid())
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.Seek((long)hashSize, SeekOrigin.Begin);
|
if (innerHeader.Magic != _innerHeaderMagic)
|
||||||
|
|
||||||
Header header = ReadHeader(stream);
|
|
||||||
|
|
||||||
if (header.Magic != _headerMagic)
|
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.CacheFileVersion != InternalVersion)
|
ReadOnlySpan<byte> infosBytes = new(stream.PositionPointer, innerHeader.InfosLength);
|
||||||
|
stream.Seek(innerHeader.InfosLength, SeekOrigin.Current);
|
||||||
|
|
||||||
|
Hash128 infosHash = XXHash128.ComputeHash(infosBytes);
|
||||||
|
|
||||||
|
if (innerHeader.InfosHash != infosHash)
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.Endianness != GetEndianness())
|
ReadOnlySpan<byte> codesBytes = (int)innerHeader.CodesLength > 0 ? new(stream.PositionPointer, (int)innerHeader.CodesLength) : ReadOnlySpan<byte>.Empty;
|
||||||
|
stream.Seek(innerHeader.CodesLength, SeekOrigin.Current);
|
||||||
|
|
||||||
|
Hash128 codesHash = XXHash128.ComputeHash(codesBytes);
|
||||||
|
|
||||||
|
if (innerHeader.CodesHash != codesHash)
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.FeatureInfo != GetFeatureInfo())
|
ReadOnlySpan<byte> relocsBytes = new(stream.PositionPointer, innerHeader.RelocsLength);
|
||||||
|
stream.Seek(innerHeader.RelocsLength, SeekOrigin.Current);
|
||||||
|
|
||||||
|
Hash128 relocsHash = XXHash128.ComputeHash(relocsBytes);
|
||||||
|
|
||||||
|
if (innerHeader.RelocsHash != relocsHash)
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.OSPlatform != GetOSPlatform())
|
ReadOnlySpan<byte> unwindInfosBytes = new(stream.PositionPointer, innerHeader.UnwindInfosLength);
|
||||||
|
stream.Seek(innerHeader.UnwindInfosLength, SeekOrigin.Current);
|
||||||
|
|
||||||
|
Hash128 unwindInfosHash = XXHash128.ComputeHash(unwindInfosBytes);
|
||||||
|
|
||||||
|
if (innerHeader.UnwindInfosHash != unwindInfosHash)
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.InfosLen % InfoEntry.Stride != 0)
|
ReadOnlySpan<byte> ptcJumpTableBytes = new(stream.PositionPointer, innerHeader.PtcJumpTableLength);
|
||||||
|
stream.Seek(innerHeader.PtcJumpTableLength, SeekOrigin.Current);
|
||||||
|
|
||||||
|
Debug.Assert(stream.Position == stream.Length);
|
||||||
|
|
||||||
|
Hash128 ptcJumpTableHash = XXHash128.ComputeHash(ptcJumpTableBytes);
|
||||||
|
|
||||||
|
if (innerHeader.PtcJumpTableHash != ptcJumpTableHash)
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadOnlySpan<byte> infosBuf = new(stream.PositionPointer, header.InfosLen);
|
stream.Seek((long)Unsafe.SizeOf<InnerHeader>(), SeekOrigin.Begin);
|
||||||
stream.Seek(header.InfosLen, SeekOrigin.Current);
|
|
||||||
|
|
||||||
ReadOnlySpan<byte> codesBuf = new(stream.PositionPointer, header.CodesLen);
|
_infosStream.Write(infosBytes);
|
||||||
stream.Seek(header.CodesLen, SeekOrigin.Current);
|
stream.Seek(innerHeader.InfosLength, SeekOrigin.Current);
|
||||||
|
|
||||||
ReadOnlySpan<byte> relocsBuf = new(stream.PositionPointer, header.RelocsLen);
|
_codesList.ReadFrom(stream);
|
||||||
stream.Seek(header.RelocsLen, SeekOrigin.Current);
|
|
||||||
|
|
||||||
ReadOnlySpan<byte> unwindInfosBuf = new(stream.PositionPointer, header.UnwindInfosLen);
|
_relocsStream.Write(relocsBytes);
|
||||||
stream.Seek(header.UnwindInfosLen, SeekOrigin.Current);
|
stream.Seek(innerHeader.RelocsLength, SeekOrigin.Current);
|
||||||
|
|
||||||
try
|
_unwindInfosStream.Write(unwindInfosBytes);
|
||||||
{
|
stream.Seek(innerHeader.UnwindInfosLength, SeekOrigin.Current);
|
||||||
PtcJumpTable = PtcJumpTable.Deserialize(stream);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
PtcJumpTable = new PtcJumpTable();
|
|
||||||
|
|
||||||
InvalidateCompressedStream(compressedStream);
|
PtcJumpTable = PtcJumpTable.Deserialize(stream);
|
||||||
|
|
||||||
return false;
|
Debug.Assert(stream.Position == stream.Length);
|
||||||
}
|
|
||||||
|
|
||||||
_infosStream.Write(infosBuf);
|
|
||||||
_codesStream.Write(codesBuf);
|
|
||||||
_relocsStream.Write(relocsBuf);
|
|
||||||
_unwindInfosStream.Write(unwindInfosBuf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
@ -344,33 +385,11 @@ namespace ARMeilleure.Translation.PTC
|
||||||
|
|
||||||
long fileSize = new FileInfo(fileName).Length;
|
long fileSize = new FileInfo(fileName).Length;
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Translation Cache" : "Loaded Translation Cache")} (size: {fileSize} bytes, translated functions: {GetInfosEntriesCount()}).");
|
Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Translation Cache" : "Loaded Translation Cache")} (size: {fileSize} bytes, translated functions: {GetEntriesCount()}).");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Header ReadHeader(Stream stream)
|
|
||||||
{
|
|
||||||
using (BinaryReader headerReader = new(stream, EncodingCache.UTF8NoBOM, true))
|
|
||||||
{
|
|
||||||
Header header = new Header();
|
|
||||||
|
|
||||||
header.Magic = headerReader.ReadUInt64();
|
|
||||||
|
|
||||||
header.CacheFileVersion = headerReader.ReadUInt32();
|
|
||||||
header.Endianness = headerReader.ReadBoolean();
|
|
||||||
header.FeatureInfo = headerReader.ReadUInt64();
|
|
||||||
header.OSPlatform = headerReader.ReadUInt32();
|
|
||||||
|
|
||||||
header.InfosLen = headerReader.ReadInt32();
|
|
||||||
header.CodesLen = headerReader.ReadInt32();
|
|
||||||
header.RelocsLen = headerReader.ReadInt32();
|
|
||||||
header.UnwindInfosLen = headerReader.ReadInt32();
|
|
||||||
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void InvalidateCompressedStream(FileStream compressedStream)
|
private static void InvalidateCompressedStream(FileStream compressedStream)
|
||||||
{
|
{
|
||||||
compressedStream.SetLength(0L);
|
compressedStream.SetLength(0L);
|
||||||
|
@ -396,7 +415,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
ResetMemoryStreamsIfNeeded();
|
ResetCarriersIfNeeded();
|
||||||
PtcJumpTable.ClearIfNeeded();
|
PtcJumpTable.ClearIfNeeded();
|
||||||
|
|
||||||
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
|
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
|
||||||
|
@ -409,46 +428,76 @@ namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
int translatedFuncsCount;
|
int translatedFuncsCount;
|
||||||
|
|
||||||
int hashSize = Unsafe.SizeOf<Hash128>();
|
InnerHeader innerHeader = new InnerHeader();
|
||||||
|
|
||||||
int size = hashSize + Header.Size + GetMemoryStreamsLength() + PtcJumpTable.GetSerializeSize(PtcJumpTable);
|
innerHeader.Magic = _innerHeaderMagic;
|
||||||
|
|
||||||
Span<byte> sizeBytes = new byte[sizeof(int)];
|
innerHeader.InfosLength = (int)_infosStream.Length;
|
||||||
BinaryPrimitives.WriteInt32LittleEndian(sizeBytes, size);
|
innerHeader.CodesLength = _codesList.Length();
|
||||||
Hash128 sizeHash = XXHash128.ComputeHash(sizeBytes);
|
innerHeader.RelocsLength = (int)_relocsStream.Length;
|
||||||
|
innerHeader.UnwindInfosLength = (int)_unwindInfosStream.Length;
|
||||||
|
innerHeader.PtcJumpTableLength = PtcJumpTable.GetSerializeSize(PtcJumpTable);
|
||||||
|
|
||||||
Span<byte> sizeHashBytes = new byte[hashSize];
|
OuterHeader outerHeader = new OuterHeader();
|
||||||
MemoryMarshal.Write<Hash128>(sizeHashBytes, ref sizeHash);
|
|
||||||
|
outerHeader.Magic = _outerHeaderMagic;
|
||||||
|
|
||||||
|
outerHeader.CacheFileVersion = InternalVersion;
|
||||||
|
outerHeader.Endianness = GetEndianness();
|
||||||
|
outerHeader.FeatureInfo = GetFeatureInfo();
|
||||||
|
outerHeader.OSPlatform = GetOSPlatform();
|
||||||
|
|
||||||
|
outerHeader.UncompressedStreamSize =
|
||||||
|
(long)Unsafe.SizeOf<InnerHeader>() +
|
||||||
|
innerHeader.InfosLength +
|
||||||
|
innerHeader.CodesLength +
|
||||||
|
innerHeader.RelocsLength +
|
||||||
|
innerHeader.UnwindInfosLength +
|
||||||
|
innerHeader.PtcJumpTableLength;
|
||||||
|
|
||||||
|
outerHeader.SetHeaderHash();
|
||||||
|
|
||||||
IntPtr intPtr = IntPtr.Zero;
|
IntPtr intPtr = IntPtr.Zero;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
intPtr = Marshal.AllocHGlobal(size);
|
intPtr = Marshal.AllocHGlobal(new IntPtr(outerHeader.UncompressedStreamSize));
|
||||||
|
|
||||||
using (UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), size, size, FileAccess.ReadWrite))
|
using (UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), outerHeader.UncompressedStreamSize, outerHeader.UncompressedStreamSize, FileAccess.ReadWrite))
|
||||||
{
|
{
|
||||||
stream.Seek((long)hashSize, SeekOrigin.Begin);
|
stream.Seek((long)Unsafe.SizeOf<InnerHeader>(), SeekOrigin.Begin);
|
||||||
|
|
||||||
WriteHeader(stream);
|
|
||||||
|
|
||||||
|
ReadOnlySpan<byte> infosBytes = new(stream.PositionPointer, innerHeader.InfosLength);
|
||||||
_infosStream.WriteTo(stream);
|
_infosStream.WriteTo(stream);
|
||||||
_codesStream.WriteTo(stream);
|
|
||||||
|
ReadOnlySpan<byte> codesBytes = (int)innerHeader.CodesLength > 0 ? new(stream.PositionPointer, (int)innerHeader.CodesLength) : ReadOnlySpan<byte>.Empty;
|
||||||
|
_codesList.WriteTo(stream);
|
||||||
|
|
||||||
|
ReadOnlySpan<byte> relocsBytes = new(stream.PositionPointer, innerHeader.RelocsLength);
|
||||||
_relocsStream.WriteTo(stream);
|
_relocsStream.WriteTo(stream);
|
||||||
|
|
||||||
|
ReadOnlySpan<byte> unwindInfosBytes = new(stream.PositionPointer, innerHeader.UnwindInfosLength);
|
||||||
_unwindInfosStream.WriteTo(stream);
|
_unwindInfosStream.WriteTo(stream);
|
||||||
|
|
||||||
|
ReadOnlySpan<byte> ptcJumpTableBytes = new(stream.PositionPointer, innerHeader.PtcJumpTableLength);
|
||||||
PtcJumpTable.Serialize(stream, PtcJumpTable);
|
PtcJumpTable.Serialize(stream, PtcJumpTable);
|
||||||
|
|
||||||
stream.Seek((long)hashSize, SeekOrigin.Begin);
|
Debug.Assert(stream.Position == stream.Length);
|
||||||
ReadOnlySpan<byte> streamBytes = new(stream.PositionPointer, (int)(stream.Length - stream.Position));
|
|
||||||
Hash128 hash = XXHash128.ComputeHash(streamBytes);
|
innerHeader.InfosHash = XXHash128.ComputeHash(infosBytes);
|
||||||
|
innerHeader.CodesHash = XXHash128.ComputeHash(codesBytes);
|
||||||
|
innerHeader.RelocsHash = XXHash128.ComputeHash(relocsBytes);
|
||||||
|
innerHeader.UnwindInfosHash = XXHash128.ComputeHash(unwindInfosBytes);
|
||||||
|
innerHeader.PtcJumpTableHash = XXHash128.ComputeHash(ptcJumpTableBytes);
|
||||||
|
|
||||||
|
innerHeader.SetHeaderHash();
|
||||||
|
|
||||||
stream.Seek(0L, SeekOrigin.Begin);
|
stream.Seek(0L, SeekOrigin.Begin);
|
||||||
SerializeStructure(stream, hash);
|
SerializeStructure(stream, innerHeader);
|
||||||
|
|
||||||
translatedFuncsCount = GetInfosEntriesCount();
|
translatedFuncsCount = GetEntriesCount();
|
||||||
|
|
||||||
ResetMemoryStreamsIfNeeded();
|
ResetCarriersIfNeeded();
|
||||||
PtcJumpTable.ClearIfNeeded();
|
PtcJumpTable.ClearIfNeeded();
|
||||||
|
|
||||||
using (FileStream compressedStream = new(fileName, FileMode.OpenOrCreate))
|
using (FileStream compressedStream = new(fileName, FileMode.OpenOrCreate))
|
||||||
|
@ -456,8 +505,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
compressedStream.Write(sizeHashBytes);
|
SerializeStructure(compressedStream, outerHeader);
|
||||||
compressedStream.Write(sizeBytes);
|
|
||||||
|
|
||||||
stream.Seek(0L, SeekOrigin.Begin);
|
stream.Seek(0L, SeekOrigin.Begin);
|
||||||
stream.CopyTo(deflateStream);
|
stream.CopyTo(deflateStream);
|
||||||
|
@ -490,67 +538,40 @@ namespace ARMeilleure.Translation.PTC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetMemoryStreamsLength()
|
|
||||||
{
|
|
||||||
return (int)_infosStream.Length + (int)_codesStream.Length + (int)_relocsStream.Length + (int)_unwindInfosStream.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void WriteHeader(Stream stream)
|
|
||||||
{
|
|
||||||
using (BinaryWriter headerWriter = new(stream, EncodingCache.UTF8NoBOM, true))
|
|
||||||
{
|
|
||||||
headerWriter.Write((ulong)_headerMagic); // Header.Magic
|
|
||||||
|
|
||||||
headerWriter.Write((uint)InternalVersion); // Header.CacheFileVersion
|
|
||||||
headerWriter.Write((bool)GetEndianness()); // Header.Endianness
|
|
||||||
headerWriter.Write((ulong)GetFeatureInfo()); // Header.FeatureInfo
|
|
||||||
headerWriter.Write((uint)GetOSPlatform()); // Header.OSPlatform
|
|
||||||
|
|
||||||
headerWriter.Write((int)_infosStream.Length); // Header.InfosLen
|
|
||||||
headerWriter.Write((int)_codesStream.Length); // Header.CodesLen
|
|
||||||
headerWriter.Write((int)_relocsStream.Length); // Header.RelocsLen
|
|
||||||
headerWriter.Write((int)_unwindInfosStream.Length); // Header.UnwindInfosLen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void LoadTranslations(ConcurrentDictionary<ulong, TranslatedFunction> funcs, IMemoryManager memory, JumpTable jumpTable)
|
internal static void LoadTranslations(ConcurrentDictionary<ulong, TranslatedFunction> funcs, IMemoryManager memory, JumpTable jumpTable)
|
||||||
{
|
{
|
||||||
if (AreMemoryStreamsEmpty())
|
if (AreCarriersEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Assert(funcs.Count == 0);
|
|
||||||
|
|
||||||
_infosStream.Seek(0L, SeekOrigin.Begin);
|
_infosStream.Seek(0L, SeekOrigin.Begin);
|
||||||
_codesStream.Seek(0L, SeekOrigin.Begin);
|
|
||||||
_relocsStream.Seek(0L, SeekOrigin.Begin);
|
_relocsStream.Seek(0L, SeekOrigin.Begin);
|
||||||
_unwindInfosStream.Seek(0L, SeekOrigin.Begin);
|
_unwindInfosStream.Seek(0L, SeekOrigin.Begin);
|
||||||
|
|
||||||
using (BinaryReader infosReader = new(_infosStream, EncodingCache.UTF8NoBOM, true))
|
using (BinaryReader infosReader = new(_infosStream, EncodingCache.UTF8NoBOM, true))
|
||||||
using (BinaryReader codesReader = new(_codesStream, EncodingCache.UTF8NoBOM, true))
|
|
||||||
using (BinaryReader relocsReader = new(_relocsStream, EncodingCache.UTF8NoBOM, true))
|
using (BinaryReader relocsReader = new(_relocsStream, EncodingCache.UTF8NoBOM, true))
|
||||||
using (BinaryReader unwindInfosReader = new(_unwindInfosStream, EncodingCache.UTF8NoBOM, true))
|
using (BinaryReader unwindInfosReader = new(_unwindInfosStream, EncodingCache.UTF8NoBOM, true))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < GetInfosEntriesCount(); i++)
|
for (int index = 0; index < GetEntriesCount(); index++)
|
||||||
{
|
{
|
||||||
InfoEntry infoEntry = ReadInfo(infosReader);
|
InfoEntry infoEntry = ReadInfo(infosReader);
|
||||||
|
|
||||||
if (infoEntry.Stubbed)
|
if (infoEntry.Stubbed)
|
||||||
{
|
{
|
||||||
SkipCode(infoEntry.CodeLen);
|
SkipCode(index, infoEntry.CodeLength);
|
||||||
SkipReloc(infoEntry.RelocEntriesCount);
|
SkipReloc(infoEntry.RelocEntriesCount);
|
||||||
SkipUnwindInfo(unwindInfosReader);
|
SkipUnwindInfo(unwindInfosReader);
|
||||||
}
|
}
|
||||||
else if (infoEntry.HighCq || !PtcProfiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) || !value.HighCq)
|
else if (infoEntry.HighCq || !PtcProfiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) || !value.HighCq)
|
||||||
{
|
{
|
||||||
Span<byte> code = ReadCode(codesReader, infoEntry.CodeLen);
|
byte[] code = ReadCode(index, infoEntry.CodeLength);
|
||||||
|
|
||||||
if (infoEntry.RelocEntriesCount != 0)
|
if (infoEntry.RelocEntriesCount != 0)
|
||||||
{
|
{
|
||||||
RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount);
|
RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount);
|
||||||
|
|
||||||
PatchCode(code, relocEntries, memory.PageTablePointer, jumpTable);
|
PatchCode(code.AsSpan(), relocEntries, memory.PageTablePointer, jumpTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader);
|
UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader);
|
||||||
|
@ -564,9 +585,10 @@ namespace ARMeilleure.Translation.PTC
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
infoEntry.Stubbed = true;
|
infoEntry.Stubbed = true;
|
||||||
|
infoEntry.CodeLength = 0;
|
||||||
UpdateInfo(infoEntry);
|
UpdateInfo(infoEntry);
|
||||||
|
|
||||||
StubCode(infoEntry.CodeLen);
|
StubCode(index);
|
||||||
StubReloc(infoEntry.RelocEntriesCount);
|
StubReloc(infoEntry.RelocEntriesCount);
|
||||||
StubUnwindInfo(unwindInfosReader);
|
StubUnwindInfo(unwindInfosReader);
|
||||||
}
|
}
|
||||||
|
@ -574,7 +596,6 @@ namespace ARMeilleure.Translation.PTC
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_infosStream.Position < _infosStream.Length ||
|
if (_infosStream.Position < _infosStream.Length ||
|
||||||
_codesStream.Position < _codesStream.Length ||
|
|
||||||
_relocsStream.Position < _relocsStream.Length ||
|
_relocsStream.Position < _relocsStream.Length ||
|
||||||
_unwindInfosStream.Position < _unwindInfosStream.Length)
|
_unwindInfosStream.Position < _unwindInfosStream.Length)
|
||||||
{
|
{
|
||||||
|
@ -589,9 +610,9 @@ namespace ARMeilleure.Translation.PTC
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"{funcs.Count} translated functions loaded");
|
Logger.Info?.Print(LogClass.Ptc, $"{funcs.Count} translated functions loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetInfosEntriesCount()
|
private static int GetEntriesCount()
|
||||||
{
|
{
|
||||||
return (int)_infosStream.Length / InfoEntry.Stride;
|
return _codesList.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InfoEntry ReadInfo(BinaryReader infosReader)
|
private static InfoEntry ReadInfo(BinaryReader infosReader)
|
||||||
|
@ -602,15 +623,17 @@ namespace ARMeilleure.Translation.PTC
|
||||||
infoEntry.GuestSize = infosReader.ReadUInt64();
|
infoEntry.GuestSize = infosReader.ReadUInt64();
|
||||||
infoEntry.HighCq = infosReader.ReadBoolean();
|
infoEntry.HighCq = infosReader.ReadBoolean();
|
||||||
infoEntry.Stubbed = infosReader.ReadBoolean();
|
infoEntry.Stubbed = infosReader.ReadBoolean();
|
||||||
infoEntry.CodeLen = infosReader.ReadInt32();
|
infoEntry.CodeLength = infosReader.ReadInt32();
|
||||||
infoEntry.RelocEntriesCount = infosReader.ReadInt32();
|
infoEntry.RelocEntriesCount = infosReader.ReadInt32();
|
||||||
|
|
||||||
return infoEntry;
|
return infoEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SkipCode(int codeLen)
|
[Conditional("DEBUG")]
|
||||||
|
private static void SkipCode(int index, int codeLength)
|
||||||
{
|
{
|
||||||
_codesStream.Seek(codeLen, SeekOrigin.Current);
|
Debug.Assert(_codesList[index].Length == 0);
|
||||||
|
Debug.Assert(codeLength == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SkipReloc(int relocEntriesCount)
|
private static void SkipReloc(int relocEntriesCount)
|
||||||
|
@ -625,13 +648,11 @@ namespace ARMeilleure.Translation.PTC
|
||||||
_unwindInfosStream.Seek(pushEntriesLength * UnwindPushEntry.Stride + UnwindInfo.Stride, SeekOrigin.Current);
|
_unwindInfosStream.Seek(pushEntriesLength * UnwindPushEntry.Stride + UnwindInfo.Stride, SeekOrigin.Current);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Span<byte> ReadCode(BinaryReader codesReader, int codeLen)
|
private static byte[] ReadCode(int index, int codeLength)
|
||||||
{
|
{
|
||||||
Span<byte> codeBuf = new byte[codeLen];
|
Debug.Assert(_codesList[index].Length == codeLength);
|
||||||
|
|
||||||
codesReader.Read(codeBuf);
|
return _codesList[index];
|
||||||
|
|
||||||
return codeBuf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RelocEntry[] GetRelocEntries(BinaryReader relocsReader, int relocEntriesCount)
|
private static RelocEntry[] GetRelocEntries(BinaryReader relocsReader, int relocEntriesCount)
|
||||||
|
@ -701,9 +722,9 @@ namespace ARMeilleure.Translation.PTC
|
||||||
return new UnwindInfo(pushEntries, prologueSize);
|
return new UnwindInfo(pushEntries, prologueSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TranslatedFunction FastTranslate(ReadOnlySpan<byte> code, ulong guestSize, UnwindInfo unwindInfo, bool highCq)
|
private static TranslatedFunction FastTranslate(byte[] code, ulong guestSize, UnwindInfo unwindInfo, bool highCq)
|
||||||
{
|
{
|
||||||
CompiledFunction cFunc = new CompiledFunction(code.ToArray(), unwindInfo);
|
CompiledFunction cFunc = new CompiledFunction(code, unwindInfo);
|
||||||
|
|
||||||
IntPtr codePtr = JitCache.Map(cFunc);
|
IntPtr codePtr = JitCache.Map(cFunc);
|
||||||
|
|
||||||
|
@ -723,16 +744,13 @@ namespace ARMeilleure.Translation.PTC
|
||||||
_infosWriter.Write((ulong)infoEntry.GuestSize);
|
_infosWriter.Write((ulong)infoEntry.GuestSize);
|
||||||
_infosWriter.Write((bool)infoEntry.HighCq);
|
_infosWriter.Write((bool)infoEntry.HighCq);
|
||||||
_infosWriter.Write((bool)infoEntry.Stubbed);
|
_infosWriter.Write((bool)infoEntry.Stubbed);
|
||||||
_infosWriter.Write((int)infoEntry.CodeLen);
|
_infosWriter.Write((int)infoEntry.CodeLength);
|
||||||
_infosWriter.Write((int)infoEntry.RelocEntriesCount);
|
_infosWriter.Write((int)infoEntry.RelocEntriesCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void StubCode(int codeLen)
|
private static void StubCode(int index)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < codeLen; i++)
|
_codesList[index] = Array.Empty<byte>();
|
||||||
{
|
|
||||||
_codesStream.WriteByte(FillingByte);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void StubReloc(int relocEntriesCount)
|
private static void StubReloc(int relocEntriesCount)
|
||||||
|
@ -757,9 +775,14 @@ namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
var profiledFuncsToTranslate = PtcProfiler.GetProfiledFuncsToTranslate(funcs);
|
var profiledFuncsToTranslate = PtcProfiler.GetProfiledFuncsToTranslate(funcs);
|
||||||
|
|
||||||
if (profiledFuncsToTranslate.Count == 0)
|
_translateCount = 0;
|
||||||
|
_translateTotalCount = profiledFuncsToTranslate.Count;
|
||||||
|
|
||||||
|
int degreeOfParallelism = new DegreeOfParallelism(4d, 75d, 12.5d).GetDegreeOfParallelism(0, 32);
|
||||||
|
|
||||||
|
if (_translateTotalCount == 0 || degreeOfParallelism == 0)
|
||||||
{
|
{
|
||||||
ResetMemoryStreamsIfNeeded();
|
ResetCarriersIfNeeded();
|
||||||
PtcJumpTable.ClearIfNeeded();
|
PtcJumpTable.ClearIfNeeded();
|
||||||
|
|
||||||
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
|
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
|
||||||
|
@ -767,8 +790,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_translateCount = 0;
|
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism}");
|
||||||
_translateTotalCount = profiledFuncsToTranslate.Count;
|
|
||||||
|
|
||||||
PtcStateChanged?.Invoke(PtcLoadingState.Start, _translateCount, _translateTotalCount);
|
PtcStateChanged?.Invoke(PtcLoadingState.Start, _translateCount, _translateTotalCount);
|
||||||
|
|
||||||
|
@ -813,11 +835,9 @@ namespace ARMeilleure.Translation.PTC
|
||||||
Translator.DisposePools();
|
Translator.DisposePools();
|
||||||
}
|
}
|
||||||
|
|
||||||
int maxDegreeOfParallelism = (Environment.ProcessorCount * 3) / 4;
|
|
||||||
|
|
||||||
List<Thread> threads = new List<Thread>();
|
List<Thread> threads = new List<Thread>();
|
||||||
|
|
||||||
for (int i = 0; i < maxDegreeOfParallelism; i++)
|
for (int i = 0; i < degreeOfParallelism; i++)
|
||||||
{
|
{
|
||||||
Thread thread = new Thread(TranslateFuncs);
|
Thread thread = new Thread(TranslateFuncs);
|
||||||
thread.IsBackground = true;
|
thread.IsBackground = true;
|
||||||
|
@ -835,7 +855,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
|
|
||||||
PtcStateChanged?.Invoke(PtcLoadingState.Loaded, _translateCount, _translateTotalCount);
|
PtcStateChanged?.Invoke(PtcLoadingState.Loaded, _translateCount, _translateTotalCount);
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated");
|
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism}");
|
||||||
|
|
||||||
PtcJumpTable.Initialize(jumpTable);
|
PtcJumpTable.Initialize(jumpTable);
|
||||||
|
|
||||||
|
@ -849,7 +869,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
|
|
||||||
private static void ReportProgress(object state)
|
private static void ReportProgress(object state)
|
||||||
{
|
{
|
||||||
const int refreshRate = 50; // ms
|
const int refreshRate = 50; // ms.
|
||||||
|
|
||||||
AutoResetEvent endEvent = (AutoResetEvent)state;
|
AutoResetEvent endEvent = (AutoResetEvent)state;
|
||||||
|
|
||||||
|
@ -877,11 +897,10 @@ namespace ARMeilleure.Translation.PTC
|
||||||
_infosWriter.Write((ulong)guestSize); // InfoEntry.GuestSize
|
_infosWriter.Write((ulong)guestSize); // InfoEntry.GuestSize
|
||||||
_infosWriter.Write((bool)highCq); // InfoEntry.HighCq
|
_infosWriter.Write((bool)highCq); // InfoEntry.HighCq
|
||||||
_infosWriter.Write((bool)false); // InfoEntry.Stubbed
|
_infosWriter.Write((bool)false); // InfoEntry.Stubbed
|
||||||
_infosWriter.Write((int)ptcInfo.Code.Length); // InfoEntry.CodeLen
|
_infosWriter.Write((int)ptcInfo.Code.Length); // InfoEntry.CodeLength
|
||||||
_infosWriter.Write((int)ptcInfo.RelocEntriesCount); // InfoEntry.RelocEntriesCount
|
_infosWriter.Write((int)ptcInfo.RelocEntriesCount); // InfoEntry.RelocEntriesCount
|
||||||
|
|
||||||
// WriteCode.
|
WriteCode(ptcInfo.Code.AsSpan());
|
||||||
_codesStream.Write(ptcInfo.Code.AsSpan());
|
|
||||||
|
|
||||||
// WriteReloc.
|
// WriteReloc.
|
||||||
ptcInfo.RelocStream.WriteTo(_relocsStream);
|
ptcInfo.RelocStream.WriteTo(_relocsStream);
|
||||||
|
@ -891,6 +910,11 @@ namespace ARMeilleure.Translation.PTC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void WriteCode(ReadOnlySpan<byte> code)
|
||||||
|
{
|
||||||
|
_codesList.Add(code.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
private static bool GetEndianness()
|
private static bool GetEndianness()
|
||||||
{
|
{
|
||||||
return BitConverter.IsLittleEndian;
|
return BitConverter.IsLittleEndian;
|
||||||
|
@ -913,21 +937,68 @@ namespace ARMeilleure.Translation.PTC
|
||||||
return osPlatform;
|
return osPlatform;
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct Header
|
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 49*/)]
|
||||||
|
private struct OuterHeader
|
||||||
{
|
{
|
||||||
public const int Size = 41; // Bytes.
|
|
||||||
|
|
||||||
public ulong Magic;
|
public ulong Magic;
|
||||||
|
|
||||||
public uint CacheFileVersion;
|
public uint CacheFileVersion;
|
||||||
|
|
||||||
public bool Endianness;
|
public bool Endianness;
|
||||||
public ulong FeatureInfo;
|
public ulong FeatureInfo;
|
||||||
public uint OSPlatform;
|
public uint OSPlatform;
|
||||||
|
|
||||||
public int InfosLen;
|
public long UncompressedStreamSize;
|
||||||
public int CodesLen;
|
|
||||||
public int RelocsLen;
|
public Hash128 HeaderHash;
|
||||||
public int UnwindInfosLen;
|
|
||||||
|
public void SetHeaderHash()
|
||||||
|
{
|
||||||
|
Span<OuterHeader> spanHeader = MemoryMarshal.CreateSpan(ref this, 1);
|
||||||
|
|
||||||
|
HeaderHash = XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf<OuterHeader>() - Unsafe.SizeOf<Hash128>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsHeaderValid()
|
||||||
|
{
|
||||||
|
Span<OuterHeader> spanHeader = MemoryMarshal.CreateSpan(ref this, 1);
|
||||||
|
|
||||||
|
return XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf<OuterHeader>() - Unsafe.SizeOf<Hash128>())) == HeaderHash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)]
|
||||||
|
private struct InnerHeader
|
||||||
|
{
|
||||||
|
public ulong Magic;
|
||||||
|
|
||||||
|
public int InfosLength;
|
||||||
|
public long CodesLength;
|
||||||
|
public int RelocsLength;
|
||||||
|
public int UnwindInfosLength;
|
||||||
|
public int PtcJumpTableLength;
|
||||||
|
|
||||||
|
public Hash128 InfosHash;
|
||||||
|
public Hash128 CodesHash;
|
||||||
|
public Hash128 RelocsHash;
|
||||||
|
public Hash128 UnwindInfosHash;
|
||||||
|
public Hash128 PtcJumpTableHash;
|
||||||
|
|
||||||
|
public Hash128 HeaderHash;
|
||||||
|
|
||||||
|
public void SetHeaderHash()
|
||||||
|
{
|
||||||
|
Span<InnerHeader> spanHeader = MemoryMarshal.CreateSpan(ref this, 1);
|
||||||
|
|
||||||
|
HeaderHash = XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf<InnerHeader>() - Unsafe.SizeOf<Hash128>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsHeaderValid()
|
||||||
|
{
|
||||||
|
Span<InnerHeader> spanHeader = MemoryMarshal.CreateSpan(ref this, 1);
|
||||||
|
|
||||||
|
return XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf<InnerHeader>() - Unsafe.SizeOf<Hash128>())) == HeaderHash;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct InfoEntry
|
private struct InfoEntry
|
||||||
|
@ -938,7 +1009,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
public ulong GuestSize;
|
public ulong GuestSize;
|
||||||
public bool HighCq;
|
public bool HighCq;
|
||||||
public bool Stubbed;
|
public bool Stubbed;
|
||||||
public int CodeLen;
|
public int CodeLength;
|
||||||
public int RelocEntriesCount;
|
public int RelocEntriesCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -983,7 +1054,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
Wait();
|
Wait();
|
||||||
_waitEvent.Dispose();
|
_waitEvent.Dispose();
|
||||||
|
|
||||||
DisposeMemoryStreams();
|
DisposeCarriers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace ARMeilleure.Translation.PTC
|
namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
public class PtcFormatter
|
static class PtcFormatter
|
||||||
{
|
{
|
||||||
#region "Deserialize"
|
#region "Deserialize"
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static Dictionary<TKey, TValue> DeserializeDictionary<TKey, TValue>(Stream stream, Func<Stream, TValue> valueFunc) where TKey : unmanaged
|
public static Dictionary<TKey, TValue> DeserializeDictionary<TKey, TValue>(Stream stream, Func<Stream, TValue> valueFunc) where TKey : struct
|
||||||
{
|
{
|
||||||
Dictionary<TKey, TValue> dictionary = new();
|
Dictionary<TKey, TValue> dictionary = new();
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static List<T> DeserializeList<T>(Stream stream) where T : unmanaged
|
public static List<T> DeserializeList<T>(Stream stream) where T : struct
|
||||||
{
|
{
|
||||||
List<T> list = new();
|
List<T> list = new();
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T DeserializeStructure<T>(Stream stream) where T : unmanaged
|
public static T DeserializeStructure<T>(Stream stream) where T : struct
|
||||||
{
|
{
|
||||||
T structure = default(T);
|
T structure = default(T);
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
|
|
||||||
#region "GetSerializeSize"
|
#region "GetSerializeSize"
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int GetSerializeSizeDictionary<TKey, TValue>(Dictionary<TKey, TValue> dictionary, Func<TValue, int> valueFunc) where TKey : unmanaged
|
public static int GetSerializeSizeDictionary<TKey, TValue>(Dictionary<TKey, TValue> dictionary, Func<TValue, int> valueFunc) where TKey : struct
|
||||||
{
|
{
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int GetSerializeSizeList<T>(List<T> list) where T : unmanaged
|
public static int GetSerializeSizeList<T>(List<T> list) where T : struct
|
||||||
{
|
{
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
|
|
||||||
#region "Serialize"
|
#region "Serialize"
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void SerializeDictionary<TKey, TValue>(Stream stream, Dictionary<TKey, TValue> dictionary, Action<Stream, TValue> valueAction) where TKey : unmanaged
|
public static void SerializeDictionary<TKey, TValue>(Stream stream, Dictionary<TKey, TValue> dictionary, Action<Stream, TValue> valueAction) where TKey : struct
|
||||||
{
|
{
|
||||||
SerializeStructure<int>(stream, dictionary.Count);
|
SerializeStructure<int>(stream, dictionary.Count);
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void SerializeList<T>(Stream stream, List<T> list) where T : unmanaged
|
public static void SerializeList<T>(Stream stream, List<T> list) where T : struct
|
||||||
{
|
{
|
||||||
SerializeStructure<int>(stream, list.Count);
|
SerializeStructure<int>(stream, list.Count);
|
||||||
|
|
||||||
|
@ -111,11 +111,59 @@ namespace ARMeilleure.Translation.PTC
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void SerializeStructure<T>(Stream stream, T structure) where T : unmanaged
|
public static void SerializeStructure<T>(Stream stream, T structure) where T : struct
|
||||||
{
|
{
|
||||||
Span<T> spanT = MemoryMarshal.CreateSpan(ref structure, 1);
|
Span<T> spanT = MemoryMarshal.CreateSpan(ref structure, 1);
|
||||||
stream.Write(MemoryMarshal.AsBytes(spanT));
|
stream.Write(MemoryMarshal.AsBytes(spanT));
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region "Extension methods"
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void ReadFrom<T>(this List<T[]> list, Stream stream) where T : struct
|
||||||
|
{
|
||||||
|
int count = DeserializeStructure<int>(stream);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
int itemLength = DeserializeStructure<int>(stream);
|
||||||
|
|
||||||
|
T[] item = new T[itemLength];
|
||||||
|
|
||||||
|
stream.Read(MemoryMarshal.AsBytes(item.AsSpan()));
|
||||||
|
|
||||||
|
list.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static long Length<T>(this List<T[]> list) where T : struct
|
||||||
|
{
|
||||||
|
long size = 0L;
|
||||||
|
|
||||||
|
size += Unsafe.SizeOf<int>();
|
||||||
|
|
||||||
|
foreach (T[] item in list)
|
||||||
|
{
|
||||||
|
size += Unsafe.SizeOf<int>();
|
||||||
|
size += item.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void WriteTo<T>(this List<T[]> list, Stream stream) where T : struct
|
||||||
|
{
|
||||||
|
SerializeStructure<int>(stream, list.Count);
|
||||||
|
|
||||||
|
foreach (T[] item in list)
|
||||||
|
{
|
||||||
|
SerializeStructure<int>(stream, item.Length);
|
||||||
|
|
||||||
|
stream.Write(MemoryMarshal.AsBytes(item.AsSpan()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -59,4 +59,4 @@ namespace ARMeilleure.Translation.PTC
|
||||||
UnwindInfoStream.Dispose();
|
UnwindInfoStream.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,7 +17,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
public int EntryIndex;
|
public int EntryIndex;
|
||||||
public long GuestAddress;
|
public long GuestAddress;
|
||||||
public TAddress HostAddress; // int
|
public TAddress HostAddress;
|
||||||
|
|
||||||
public TableEntry(int entryIndex, long guestAddress, TAddress hostAddress)
|
public TableEntry(int entryIndex, long guestAddress, TAddress hostAddress)
|
||||||
{
|
{
|
||||||
|
|
|
@ -399,4 +399,4 @@ namespace ARMeilleure.Translation.PTC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,4 +18,4 @@ namespace ARMeilleure.Translation.PTC
|
||||||
return $"({nameof(Position)} = {Position}, {nameof(Index)} = {Index})";
|
return $"({nameof(Position)} = {Position}, {nameof(Index)} = {Index})";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -103,6 +103,7 @@ namespace ARMeilleure.Translation
|
||||||
|
|
||||||
if (Ptc.State == PtcState.Enabled)
|
if (Ptc.State == PtcState.Enabled)
|
||||||
{
|
{
|
||||||
|
Debug.Assert(_funcs.Count == 0);
|
||||||
Ptc.LoadTranslations(_funcs, _memory, _jumpTable);
|
Ptc.LoadTranslations(_funcs, _memory, _jumpTable);
|
||||||
Ptc.MakeAndSaveTranslations(_funcs, _memory, _jumpTable);
|
Ptc.MakeAndSaveTranslations(_funcs, _memory, _jumpTable);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue