PPTC & Pool Enhancements. (#1968)

* PPTC & Pool Enhancements.

* Avoid buffer allocations in CodeGenContext.GetCode(). Avoid stream allocations in PTC.PtcInfo.

Refactoring/nits.

* Use XXHash128, for Ptc.Load & Ptc.Save, x10 faster than Md5.

* Why not a nice Span.

* Added a simple PtcFormatter library for deserialization/serialization, which does not require reflection, in use at PtcJumpTable and PtcProfiler; improves maintainability and simplicity/readability of affected code.

* Nits.

* Revert #1987.

* Revert "Revert #1987."

This reverts commit 998be765cf7f7da5ff0c1c08de704c9012b0f49c.
This commit is contained in:
LDj3SNuD 2021-02-22 03:23:48 +01:00 committed by GitHub
parent 1586880114
commit dc0adb533d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 777 additions and 603 deletions

View file

@ -3,6 +3,7 @@ using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.CodeGen.X86;
using ARMeilleure.Memory;
using ARMeilleure.Translation.Cache;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using System;
@ -12,17 +13,20 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Threading;
using static ARMeilleure.Translation.PTC.PtcFormatter;
namespace ARMeilleure.Translation.PTC
{
public static class Ptc
{
private const string HeaderMagic = "PTChd";
private const string HeaderMagicString = "PTChd\0\0\0";
private const int InternalVersion = 2010; //! To be incremented manually for each change to the ARMeilleure project.
private const uint InternalVersion = 1968; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0";
private const string BackupDir = "1";
@ -37,12 +41,14 @@ namespace ARMeilleure.Translation.PTC
private const byte FillingByte = 0x00;
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
private static readonly MemoryStream _infosStream;
private static readonly MemoryStream _codesStream;
private static readonly MemoryStream _relocsStream;
private static readonly MemoryStream _unwindInfosStream;
private static MemoryStream _infosStream;
private static MemoryStream _codesStream;
private static MemoryStream _relocsStream;
private static MemoryStream _unwindInfosStream;
private static readonly BinaryWriter _infosWriter;
private static BinaryWriter _infosWriter;
private static readonly ulong _headerMagic;
private static readonly ManualResetEvent _waitEvent;
@ -66,12 +72,9 @@ namespace ARMeilleure.Translation.PTC
static Ptc()
{
_infosStream = new MemoryStream();
_codesStream = new MemoryStream();
_relocsStream = new MemoryStream();
_unwindInfosStream = new MemoryStream();
InitializeMemoryStreams();
_infosWriter = new BinaryWriter(_infosStream, EncodingCache.UTF8NoBOM, true);
_headerMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(HeaderMagicString).AsSpan());
_waitEvent = new ManualResetEvent(true);
@ -95,13 +98,13 @@ namespace ARMeilleure.Translation.PTC
public static void Initialize(string titleIdText, string displayVersion, bool enabled)
{
Wait();
ClearMemoryStreams();
PtcJumpTable.Clear();
PtcProfiler.Wait();
PtcProfiler.ClearEntries();
if (String.IsNullOrEmpty(titleIdText) || titleIdText == TitleIdTextDefault)
Logger.Info?.Print(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache (enabled: {enabled}).");
if (!enabled || string.IsNullOrEmpty(titleIdText) || titleIdText == TitleIdTextDefault)
{
TitleIdText = TitleIdTextDefault;
DisplayVersion = DisplayVersionDefault;
@ -114,55 +117,72 @@ namespace ARMeilleure.Translation.PTC
return;
}
Logger.Info?.Print(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache (enabled: {enabled}).");
TitleIdText = titleIdText;
DisplayVersion = !String.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault;
DisplayVersion = !string.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault;
if (enabled)
string workPathActual = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", ActualDir);
string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", BackupDir);
if (!Directory.Exists(workPathActual))
{
string workPathActual = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", ActualDir);
string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", BackupDir);
if (!Directory.Exists(workPathActual))
{
Directory.CreateDirectory(workPathActual);
}
if (!Directory.Exists(workPathBackup))
{
Directory.CreateDirectory(workPathBackup);
}
CachePathActual = Path.Combine(workPathActual, DisplayVersion);
CachePathBackup = Path.Combine(workPathBackup, DisplayVersion);
Enable();
PreLoad();
PtcProfiler.PreLoad();
Directory.CreateDirectory(workPathActual);
}
else
if (!Directory.Exists(workPathBackup))
{
CachePathActual = string.Empty;
CachePathBackup = string.Empty;
Disable();
Directory.CreateDirectory(workPathBackup);
}
CachePathActual = Path.Combine(workPathActual, DisplayVersion);
CachePathBackup = Path.Combine(workPathBackup, DisplayVersion);
PreLoad();
PtcProfiler.PreLoad();
Enable();
}
internal static void ClearMemoryStreams()
private static void InitializeMemoryStreams()
{
_infosStream.SetLength(0L);
_codesStream.SetLength(0L);
_relocsStream.SetLength(0L);
_unwindInfosStream.SetLength(0L);
_infosStream = new MemoryStream();
_codesStream = new MemoryStream();
_relocsStream = new MemoryStream();
_unwindInfosStream = new MemoryStream();
_infosWriter = new BinaryWriter(_infosStream, EncodingCache.UTF8NoBOM, true);
}
private static void DisposeMemoryStreams()
{
_infosWriter.Dispose();
_infosStream.Dispose();
_codesStream.Dispose();
_relocsStream.Dispose();
_unwindInfosStream.Dispose();
}
private static bool AreMemoryStreamsEmpty()
{
return _infosStream.Length == 0L && _codesStream.Length == 0L && _relocsStream.Length == 0L && _unwindInfosStream.Length == 0L;
}
private static void ResetMemoryStreamsIfNeeded()
{
if (AreMemoryStreamsEmpty())
{
return;
}
DisposeMemoryStreams();
InitializeMemoryStreams();
}
private static void PreLoad()
{
string fileNameActual = String.Concat(CachePathActual, ".cache");
string fileNameBackup = String.Concat(CachePathBackup, ".cache");
string fileNameActual = string.Concat(CachePathActual, ".cache");
string fileNameBackup = string.Concat(CachePathBackup, ".cache");
FileInfo fileInfoActual = new FileInfo(fileNameActual);
FileInfo fileInfoBackup = new FileInfo(fileNameBackup);
@ -183,106 +203,144 @@ namespace ARMeilleure.Translation.PTC
}
}
private static bool Load(string fileName, bool isBackup)
private static unsafe bool Load(string fileName, bool isBackup)
{
using (FileStream compressedStream = new FileStream(fileName, FileMode.Open))
using (DeflateStream deflateStream = new DeflateStream(compressedStream, CompressionMode.Decompress, true))
using (MemoryStream stream = new MemoryStream())
using (MD5 md5 = MD5.Create())
using (FileStream compressedStream = new(fileName, FileMode.Open))
using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true))
{
int hashSize = md5.HashSize / 8;
Hash128 currentSizeHash = DeserializeStructure<Hash128>(compressedStream);
Span<byte> sizeBytes = new byte[sizeof(int)];
compressedStream.Read(sizeBytes);
Hash128 expectedSizeHash = XXHash128.ComputeHash(sizeBytes);
if (currentSizeHash != expectedSizeHash)
{
InvalidateCompressedStream(compressedStream);
return false;
}
int size = BinaryPrimitives.ReadInt32LittleEndian(sizeBytes);
IntPtr intPtr = IntPtr.Zero;
try
{
deflateStream.CopyTo(stream);
intPtr = Marshal.AllocHGlobal(size);
using (UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), size, size, FileAccess.ReadWrite))
{
try
{
deflateStream.CopyTo(stream);
}
catch
{
InvalidateCompressedStream(compressedStream);
return false;
}
int hashSize = Unsafe.SizeOf<Hash128>();
stream.Seek(0L, SeekOrigin.Begin);
Hash128 currentHash = DeserializeStructure<Hash128>(stream);
ReadOnlySpan<byte> streamBytes = new(stream.PositionPointer, (int)(stream.Length - stream.Position));
Hash128 expectedHash = XXHash128.ComputeHash(streamBytes);
if (currentHash != expectedHash)
{
InvalidateCompressedStream(compressedStream);
return false;
}
stream.Seek((long)hashSize, SeekOrigin.Begin);
Header header = ReadHeader(stream);
if (header.Magic != _headerMagic)
{
InvalidateCompressedStream(compressedStream);
return false;
}
if (header.CacheFileVersion != InternalVersion)
{
InvalidateCompressedStream(compressedStream);
return false;
}
if (header.Endianness != GetEndianness())
{
InvalidateCompressedStream(compressedStream);
return false;
}
if (header.FeatureInfo != GetFeatureInfo())
{
InvalidateCompressedStream(compressedStream);
return false;
}
if (header.OSPlatform != GetOSPlatform())
{
InvalidateCompressedStream(compressedStream);
return false;
}
if (header.InfosLen % InfoEntry.Stride != 0)
{
InvalidateCompressedStream(compressedStream);
return false;
}
ReadOnlySpan<byte> infosBuf = new(stream.PositionPointer, header.InfosLen);
stream.Seek(header.InfosLen, SeekOrigin.Current);
ReadOnlySpan<byte> codesBuf = new(stream.PositionPointer, header.CodesLen);
stream.Seek(header.CodesLen, SeekOrigin.Current);
ReadOnlySpan<byte> relocsBuf = new(stream.PositionPointer, header.RelocsLen);
stream.Seek(header.RelocsLen, SeekOrigin.Current);
ReadOnlySpan<byte> unwindInfosBuf = new(stream.PositionPointer, header.UnwindInfosLen);
stream.Seek(header.UnwindInfosLen, SeekOrigin.Current);
try
{
PtcJumpTable = PtcJumpTable.Deserialize(stream);
}
catch
{
PtcJumpTable = new PtcJumpTable();
InvalidateCompressedStream(compressedStream);
return false;
}
_infosStream.Write(infosBuf);
_codesStream.Write(codesBuf);
_relocsStream.Write(relocsBuf);
_unwindInfosStream.Write(unwindInfosBuf);
}
}
catch
finally
{
InvalidateCompressedStream(compressedStream);
return false;
if (intPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(intPtr);
}
}
stream.Seek(0L, SeekOrigin.Begin);
byte[] currentHash = new byte[hashSize];
stream.Read(currentHash, 0, hashSize);
byte[] expectedHash = md5.ComputeHash(stream);
if (!CompareHash(currentHash, expectedHash))
{
InvalidateCompressedStream(compressedStream);
return false;
}
stream.Seek((long)hashSize, SeekOrigin.Begin);
Header header = ReadHeader(stream);
if (header.Magic != HeaderMagic)
{
InvalidateCompressedStream(compressedStream);
return false;
}
if (header.CacheFileVersion != InternalVersion)
{
InvalidateCompressedStream(compressedStream);
return false;
}
if (header.FeatureInfo != GetFeatureInfo())
{
InvalidateCompressedStream(compressedStream);
return false;
}
if (header.OSPlatform != GetOSPlatform())
{
InvalidateCompressedStream(compressedStream);
return false;
}
if (header.InfosLen % InfoEntry.Stride != 0)
{
InvalidateCompressedStream(compressedStream);
return false;
}
byte[] infosBuf = new byte[header.InfosLen];
byte[] codesBuf = new byte[header.CodesLen];
byte[] relocsBuf = new byte[header.RelocsLen];
byte[] unwindInfosBuf = new byte[header.UnwindInfosLen];
stream.Read(infosBuf, 0, header.InfosLen);
stream.Read(codesBuf, 0, header.CodesLen);
stream.Read(relocsBuf, 0, header.RelocsLen);
stream.Read(unwindInfosBuf, 0, header.UnwindInfosLen);
try
{
PtcJumpTable = PtcJumpTable.Deserialize(stream);
}
catch
{
PtcJumpTable = new PtcJumpTable();
InvalidateCompressedStream(compressedStream);
return false;
}
_infosStream.Write(infosBuf, 0, header.InfosLen);
_codesStream.Write(codesBuf, 0, header.CodesLen);
_relocsStream.Write(relocsBuf, 0, header.RelocsLen);
_unwindInfosStream.Write(unwindInfosBuf, 0, header.UnwindInfosLen);
}
long fileSize = new FileInfo(fileName).Length;
@ -292,20 +350,16 @@ namespace ARMeilleure.Translation.PTC
return true;
}
private static bool CompareHash(ReadOnlySpan<byte> currentHash, ReadOnlySpan<byte> expectedHash)
private static Header ReadHeader(Stream stream)
{
return currentHash.SequenceEqual(expectedHash);
}
private static Header ReadHeader(MemoryStream stream)
{
using (BinaryReader headerReader = new BinaryReader(stream, EncodingCache.UTF8NoBOM, true))
using (BinaryReader headerReader = new(stream, EncodingCache.UTF8NoBOM, true))
{
Header header = new Header();
header.Magic = headerReader.ReadString();
header.Magic = headerReader.ReadUInt64();
header.CacheFileVersion = headerReader.ReadUInt32();
header.Endianness = headerReader.ReadBoolean();
header.FeatureInfo = headerReader.ReadUInt64();
header.OSPlatform = headerReader.ReadUInt32();
@ -323,87 +377,133 @@ namespace ARMeilleure.Translation.PTC
compressedStream.SetLength(0L);
}
private static void PreSave(object state)
private static void PreSave()
{
_waitEvent.Reset();
string fileNameActual = String.Concat(CachePathActual, ".cache");
string fileNameBackup = String.Concat(CachePathBackup, ".cache");
FileInfo fileInfoActual = new FileInfo(fileNameActual);
if (fileInfoActual.Exists && fileInfoActual.Length != 0L)
try
{
File.Copy(fileNameActual, fileNameBackup, true);
}
string fileNameActual = string.Concat(CachePathActual, ".cache");
string fileNameBackup = string.Concat(CachePathBackup, ".cache");
Save(fileNameActual);
FileInfo fileInfoActual = new FileInfo(fileNameActual);
if (fileInfoActual.Exists && fileInfoActual.Length != 0L)
{
File.Copy(fileNameActual, fileNameBackup, true);
}
Save(fileNameActual);
}
finally
{
ResetMemoryStreamsIfNeeded();
PtcJumpTable.ClearIfNeeded();
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
}
_waitEvent.Set();
}
private static void Save(string fileName)
private static unsafe void Save(string fileName)
{
int translatedFuncsCount;
using (MemoryStream stream = new MemoryStream())
using (MD5 md5 = MD5.Create())
int hashSize = Unsafe.SizeOf<Hash128>();
int size = hashSize + Header.Size + GetMemoryStreamsLength() + PtcJumpTable.GetSerializeSize(PtcJumpTable);
Span<byte> sizeBytes = new byte[sizeof(int)];
BinaryPrimitives.WriteInt32LittleEndian(sizeBytes, size);
Hash128 sizeHash = XXHash128.ComputeHash(sizeBytes);
Span<byte> sizeHashBytes = new byte[hashSize];
MemoryMarshal.Write<Hash128>(sizeHashBytes, ref sizeHash);
IntPtr intPtr = IntPtr.Zero;
try
{
int hashSize = md5.HashSize / 8;
intPtr = Marshal.AllocHGlobal(size);
stream.Seek((long)hashSize, SeekOrigin.Begin);
WriteHeader(stream);
_infosStream.WriteTo(stream);
_codesStream.WriteTo(stream);
_relocsStream.WriteTo(stream);
_unwindInfosStream.WriteTo(stream);
PtcJumpTable.Serialize(stream, PtcJumpTable);
translatedFuncsCount = GetInfosEntriesCount();
ClearMemoryStreams();
PtcJumpTable.Clear();
stream.Seek((long)hashSize, SeekOrigin.Begin);
byte[] hash = md5.ComputeHash(stream);
stream.Seek(0L, SeekOrigin.Begin);
stream.Write(hash, 0, hashSize);
using (FileStream compressedStream = new FileStream(fileName, FileMode.OpenOrCreate))
using (DeflateStream deflateStream = new DeflateStream(compressedStream, SaveCompressionLevel, true))
using (UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), size, size, FileAccess.ReadWrite))
{
try
{
stream.WriteTo(deflateStream);
}
catch
{
compressedStream.Position = 0L;
}
stream.Seek((long)hashSize, SeekOrigin.Begin);
if (compressedStream.Position < compressedStream.Length)
WriteHeader(stream);
_infosStream.WriteTo(stream);
_codesStream.WriteTo(stream);
_relocsStream.WriteTo(stream);
_unwindInfosStream.WriteTo(stream);
PtcJumpTable.Serialize(stream, PtcJumpTable);
stream.Seek((long)hashSize, SeekOrigin.Begin);
ReadOnlySpan<byte> streamBytes = new(stream.PositionPointer, (int)(stream.Length - stream.Position));
Hash128 hash = XXHash128.ComputeHash(streamBytes);
stream.Seek(0L, SeekOrigin.Begin);
SerializeStructure(stream, hash);
translatedFuncsCount = GetInfosEntriesCount();
ResetMemoryStreamsIfNeeded();
PtcJumpTable.ClearIfNeeded();
using (FileStream compressedStream = new(fileName, FileMode.OpenOrCreate))
using (DeflateStream deflateStream = new(compressedStream, SaveCompressionLevel, true))
{
compressedStream.SetLength(compressedStream.Position);
try
{
compressedStream.Write(sizeHashBytes);
compressedStream.Write(sizeBytes);
stream.Seek(0L, SeekOrigin.Begin);
stream.CopyTo(deflateStream);
}
catch
{
compressedStream.Position = 0L;
}
if (compressedStream.Position < compressedStream.Length)
{
compressedStream.SetLength(compressedStream.Position);
}
}
}
}
finally
{
if (intPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(intPtr);
}
}
long fileSize = new FileInfo(fileName).Length;
Logger.Info?.Print(LogClass.Ptc, $"Saved Translation Cache (size: {fileSize} bytes, translated functions: {translatedFuncsCount}).");
if (fileSize != 0L)
{
Logger.Info?.Print(LogClass.Ptc, $"Saved Translation Cache (size: {fileSize} bytes, translated functions: {translatedFuncsCount}).");
}
}
private static void WriteHeader(MemoryStream stream)
private static int GetMemoryStreamsLength()
{
using (BinaryWriter headerWriter = new BinaryWriter(stream, EncodingCache.UTF8NoBOM, true))
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((string)HeaderMagic); // Header.Magic
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
@ -416,10 +516,7 @@ namespace ARMeilleure.Translation.PTC
internal static void LoadTranslations(ConcurrentDictionary<ulong, TranslatedFunction> funcs, IMemoryManager memory, JumpTable jumpTable)
{
if ((int)_infosStream.Length == 0 ||
(int)_codesStream.Length == 0 ||
(int)_relocsStream.Length == 0 ||
(int)_unwindInfosStream.Length == 0)
if (AreMemoryStreamsEmpty())
{
return;
}
@ -431,10 +528,10 @@ namespace ARMeilleure.Translation.PTC
_relocsStream.Seek(0L, SeekOrigin.Begin);
_unwindInfosStream.Seek(0L, SeekOrigin.Begin);
using (BinaryReader infosReader = new BinaryReader(_infosStream, EncodingCache.UTF8NoBOM, true))
using (BinaryReader codesReader = new BinaryReader(_codesStream, EncodingCache.UTF8NoBOM, true))
using (BinaryReader relocsReader = new BinaryReader(_relocsStream, EncodingCache.UTF8NoBOM, true))
using (BinaryReader unwindInfosReader = new BinaryReader(_unwindInfosStream, 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 unwindInfosReader = new(_unwindInfosStream, EncodingCache.UTF8NoBOM, true))
{
for (int i = 0; i < GetInfosEntriesCount(); i++)
{
@ -446,9 +543,9 @@ namespace ARMeilleure.Translation.PTC
SkipReloc(infoEntry.RelocEntriesCount);
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)
{
byte[] code = ReadCode(codesReader, infoEntry.CodeLen);
Span<byte> code = ReadCode(codesReader, infoEntry.CodeLen);
if (infoEntry.RelocEntriesCount != 0)
{
@ -529,11 +626,11 @@ namespace ARMeilleure.Translation.PTC
_unwindInfosStream.Seek(pushEntriesLength * UnwindPushEntry.Stride + UnwindInfo.Stride, SeekOrigin.Current);
}
private static byte[] ReadCode(BinaryReader codesReader, int codeLen)
private static Span<byte> ReadCode(BinaryReader codesReader, int codeLen)
{
byte[] codeBuf = new byte[codeLen];
Span<byte> codeBuf = new byte[codeLen];
codesReader.Read(codeBuf, 0, codeLen);
codesReader.Read(codeBuf);
return codeBuf;
}
@ -605,9 +702,9 @@ namespace ARMeilleure.Translation.PTC
return new UnwindInfo(pushEntries, prologueSize);
}
private static TranslatedFunction FastTranslate(byte[] code, ulong guestSize, UnwindInfo unwindInfo, bool highCq)
private static TranslatedFunction FastTranslate(ReadOnlySpan<byte> code, ulong guestSize, UnwindInfo unwindInfo, bool highCq)
{
CompiledFunction cFunc = new CompiledFunction(code, unwindInfo);
CompiledFunction cFunc = new CompiledFunction(code.ToArray(), unwindInfo);
IntPtr codePtr = JitCache.Map(cFunc);
@ -663,6 +760,11 @@ namespace ARMeilleure.Translation.PTC
if (profiledFuncsToTranslate.Count == 0)
{
ResetMemoryStreamsIfNeeded();
PtcJumpTable.ClearIfNeeded();
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
return;
}
@ -696,6 +798,8 @@ namespace ARMeilleure.Translation.PTC
break;
}
}
Translator.DisposePools();
}
int maxDegreeOfParallelism = (Environment.ProcessorCount * 3) / 4;
@ -715,8 +819,6 @@ namespace ARMeilleure.Translation.PTC
threads.Clear();
Translator.ResetPools();
_loggerEvent.Set();
PtcJumpTable.Initialize(jumpTable);
@ -724,7 +826,9 @@ namespace ARMeilleure.Translation.PTC
PtcJumpTable.ReadJumpTable(jumpTable);
PtcJumpTable.ReadDynamicTable(jumpTable);
ThreadPool.QueueUserWorkItem(PreSave);
Thread preSaveThread = new Thread(PreSave);
preSaveThread.IsBackground = true;
preSaveThread.Start();
}
private static void TranslationLogger(object state)
@ -751,11 +855,11 @@ namespace ARMeilleure.Translation.PTC
_infosWriter.Write((ulong)guestSize); // InfoEntry.GuestSize
_infosWriter.Write((bool)highCq); // InfoEntry.HighCq
_infosWriter.Write((bool)false); // InfoEntry.Stubbed
_infosWriter.Write((int)ptcInfo.CodeStream.Length); // InfoEntry.CodeLen
_infosWriter.Write((int)ptcInfo.Code.Length); // InfoEntry.CodeLen
_infosWriter.Write((int)ptcInfo.RelocEntriesCount); // InfoEntry.RelocEntriesCount
// WriteCode.
ptcInfo.CodeStream.WriteTo(_codesStream);
_codesStream.Write(ptcInfo.Code.AsSpan());
// WriteReloc.
ptcInfo.RelocStream.WriteTo(_relocsStream);
@ -765,6 +869,11 @@ namespace ARMeilleure.Translation.PTC
}
}
private static bool GetEndianness()
{
return BitConverter.IsLittleEndian;
}
private static ulong GetFeatureInfo()
{
return (ulong)HardwareCapabilities.FeatureInfoEdx << 32 | (uint)HardwareCapabilities.FeatureInfoEcx;
@ -784,9 +893,12 @@ namespace ARMeilleure.Translation.PTC
private struct Header
{
public string Magic;
public const int Size = 41; // Bytes.
public ulong Magic;
public uint CacheFileVersion;
public bool Endianness;
public ulong FeatureInfo;
public uint OSPlatform;
@ -849,12 +961,9 @@ namespace ARMeilleure.Translation.PTC
Wait();
_waitEvent.Dispose();
_infosWriter.Dispose();
_loggerEvent.Dispose();
_infosStream.Dispose();
_codesStream.Dispose();
_relocsStream.Dispose();
_unwindInfosStream.Dispose();
DisposeMemoryStreams();
}
}
}