private static void PreSave() { _waitEvent.Reset(); try { string fileNameActual = string.Concat(CachePathActual, ".cache"); string fileNameBackup = string.Concat(CachePathBackup, ".cache"); FileInfo fileInfoActual = new FileInfo(fileNameActual); if (fileInfoActual.Exists && fileInfoActual.Length != 0L) { File.Copy(fileNameActual, fileNameBackup, true); } Save(fileNameActual); } finally { ResetCarriersIfNeeded(); PtcJumpTable.ClearIfNeeded(); GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; } _waitEvent.Set(); }
internal static void MakeAndSaveTranslations( ConcurrentDictionary <ulong, TranslatedFunction> funcs, IMemoryManager memory, JumpTable jumpTable, EntryTable <uint> countTable) { var profiledFuncsToTranslate = PtcProfiler.GetProfiledFuncsToTranslate(funcs); _translateCount = 0; _translateTotalCount = profiledFuncsToTranslate.Count; int degreeOfParallelism = new DegreeOfParallelism(4d, 75d, 12.5d).GetDegreeOfParallelism(0, 32); if (_translateTotalCount == 0 || degreeOfParallelism == 0) { ResetCarriersIfNeeded(); PtcJumpTable.ClearIfNeeded(); GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; return; } Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism}"); PtcStateChanged?.Invoke(PtcLoadingState.Start, _translateCount, _translateTotalCount); using AutoResetEvent progressReportEvent = new AutoResetEvent(false); Thread progressReportThread = new Thread(ReportProgress) { Name = "Ptc.ProgressReporter", Priority = ThreadPriority.Lowest, IsBackground = true }; progressReportThread.Start(progressReportEvent); void TranslateFuncs() { while (profiledFuncsToTranslate.TryDequeue(out var item)) { ulong address = item.address; Debug.Assert(PtcProfiler.IsAddressInStaticCodeRange(address)); TranslatedFunction func = Translator.Translate(memory, jumpTable, countTable, address, item.funcProfile.Mode, item.funcProfile.HighCq); bool isAddressUnique = funcs.TryAdd(address, func); Debug.Assert(isAddressUnique, $"The address 0x{address:X16} is not unique."); if (func.HighCq) { jumpTable.RegisterFunction(address, func); } Interlocked.Increment(ref _translateCount); if (State != PtcState.Enabled) { break; } } Translator.DisposePools(); } List <Thread> threads = new List <Thread>(); for (int i = 0; i < degreeOfParallelism; i++) { Thread thread = new Thread(TranslateFuncs); thread.IsBackground = true; threads.Add(thread); } threads.ForEach((thread) => thread.Start()); threads.ForEach((thread) => thread.Join()); threads.Clear(); progressReportEvent.Set(); progressReportThread.Join(); PtcStateChanged?.Invoke(PtcLoadingState.Loaded, _translateCount, _translateTotalCount); Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism}"); PtcJumpTable.Initialize(jumpTable); PtcJumpTable.ReadJumpTable(jumpTable); PtcJumpTable.ReadDynamicTable(jumpTable); Thread preSaveThread = new Thread(PreSave); preSaveThread.IsBackground = true; preSaveThread.Start(); }
private static unsafe void Save(string fileName) { int translatedFuncsCount; InnerHeader innerHeader = new InnerHeader(); innerHeader.Magic = _innerHeaderMagic; innerHeader.InfosLength = (int)_infosStream.Length; innerHeader.CodesLength = _codesList.Length(); innerHeader.RelocsLength = (int)_relocsStream.Length; innerHeader.UnwindInfosLength = (int)_unwindInfosStream.Length; innerHeader.PtcJumpTableLength = PtcJumpTable.GetSerializeSize(PtcJumpTable); OuterHeader outerHeader = new OuterHeader(); outerHeader.Magic = _outerHeaderMagic; outerHeader.CacheFileVersion = InternalVersion; outerHeader.Endianness = GetEndianness(); outerHeader.FeatureInfo = GetFeatureInfo(); outerHeader.MemoryManagerMode = GetMemoryManagerMode(); 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; try { intPtr = Marshal.AllocHGlobal(new IntPtr(outerHeader.UncompressedStreamSize)); using (UnmanagedMemoryStream stream = new((byte *)intPtr.ToPointer(), outerHeader.UncompressedStreamSize, outerHeader.UncompressedStreamSize, FileAccess.ReadWrite)) { stream.Seek((long)Unsafe.SizeOf <InnerHeader>(), SeekOrigin.Begin); ReadOnlySpan <byte> infosBytes = new(stream.PositionPointer, innerHeader.InfosLength); _infosStream.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); ReadOnlySpan <byte> unwindInfosBytes = new(stream.PositionPointer, innerHeader.UnwindInfosLength); _unwindInfosStream.WriteTo(stream); ReadOnlySpan <byte> ptcJumpTableBytes = new(stream.PositionPointer, innerHeader.PtcJumpTableLength); PtcJumpTable.Serialize(stream, PtcJumpTable); Debug.Assert(stream.Position == stream.Length); 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); SerializeStructure(stream, innerHeader); translatedFuncsCount = GetEntriesCount(); ResetCarriersIfNeeded(); PtcJumpTable.ClearIfNeeded(); using (FileStream compressedStream = new(fileName, FileMode.OpenOrCreate)) using (DeflateStream deflateStream = new(compressedStream, SaveCompressionLevel, true)) { try { SerializeStructure(compressedStream, outerHeader); 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; if (fileSize != 0L) { Logger.Info?.Print(LogClass.Ptc, $"Saved Translation Cache (size: {fileSize} bytes, translated functions: {translatedFuncsCount})."); } }
private static unsafe void Save(string fileName) { int translatedFuncsCount; int headerSize = Unsafe.SizeOf <Header>(); Header header = new Header() { Magic = _headerMagic, CacheFileVersion = InternalVersion, Endianness = GetEndianness(), FeatureInfo = GetFeatureInfo(), OSPlatform = GetOSPlatform(), InfosLength = (int)_infosStream.Length, CodesLength = _codesList.Length(), RelocsLength = (int)_relocsStream.Length, UnwindInfosLength = (int)_unwindInfosStream.Length, PtcJumpTableLength = PtcJumpTable.GetSerializeSize(PtcJumpTable) }; long size = (long)headerSize + header.InfosLength + header.CodesLength + header.RelocsLength + header.UnwindInfosLength + header.PtcJumpTableLength; Span <byte> sizeBytes = new byte[sizeof(long)]; BinaryPrimitives.WriteInt64LittleEndian(sizeBytes, size); Hash128 sizeHash = XXHash128.ComputeHash(sizeBytes); Span <byte> sizeHashBytes = new byte[Unsafe.SizeOf <Hash128>()]; MemoryMarshal.Write <Hash128>(sizeHashBytes, ref sizeHash); IntPtr intPtr = IntPtr.Zero; try { intPtr = Marshal.AllocHGlobal(new IntPtr(size)); using (UnmanagedMemoryStream stream = new((byte *)intPtr.ToPointer(), size, size, FileAccess.ReadWrite)) { stream.Seek((long)headerSize, SeekOrigin.Begin); ReadOnlySpan <byte> infosBytes = new(stream.PositionPointer, header.InfosLength); _infosStream.WriteTo(stream); ReadOnlySpan <byte> codesBytes = (int)header.CodesLength > 0 ? new(stream.PositionPointer, (int)header.CodesLength) : ReadOnlySpan <byte> .Empty; _codesList.WriteTo(stream); ReadOnlySpan <byte> relocsBytes = new(stream.PositionPointer, header.RelocsLength); _relocsStream.WriteTo(stream); ReadOnlySpan <byte> unwindInfosBytes = new(stream.PositionPointer, header.UnwindInfosLength); _unwindInfosStream.WriteTo(stream); ReadOnlySpan <byte> ptcJumpTableBytes = new(stream.PositionPointer, header.PtcJumpTableLength); PtcJumpTable.Serialize(stream, PtcJumpTable); header.InfosHash = XXHash128.ComputeHash(infosBytes); header.CodesHash = XXHash128.ComputeHash(codesBytes); header.RelocsHash = XXHash128.ComputeHash(relocsBytes); header.UnwindInfosHash = XXHash128.ComputeHash(unwindInfosBytes); header.PtcJumpTableHash = XXHash128.ComputeHash(ptcJumpTableBytes); Debug.Assert(stream.Position == stream.Length); stream.Seek(0L, SeekOrigin.Begin); SerializeStructure(stream, header); translatedFuncsCount = GetEntriesCount(); ResetCarriersIfNeeded(); PtcJumpTable.ClearIfNeeded(); using (FileStream compressedStream = new(fileName, FileMode.OpenOrCreate)) using (DeflateStream deflateStream = new(compressedStream, SaveCompressionLevel, true)) { 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; if (fileSize != 0L) { Logger.Info?.Print(LogClass.Ptc, $"Saved Translation Cache (size: {fileSize} bytes, translated functions: {translatedFuncsCount})."); } }
internal static void MakeAndSaveTranslations(ConcurrentDictionary <ulong, TranslatedFunction> funcs, IMemoryManager memory, JumpTable jumpTable) { var profiledFuncsToTranslate = PtcProfiler.GetProfiledFuncsToTranslate(funcs); if (profiledFuncsToTranslate.Count == 0) { ResetMemoryStreamsIfNeeded(); PtcJumpTable.ClearIfNeeded(); GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; return; } _translateCount = 0; ThreadPool.QueueUserWorkItem(TranslationLogger, profiledFuncsToTranslate.Count); PtcTranslationStateChanged?.Invoke(true); void TranslateFuncs() { while (profiledFuncsToTranslate.TryDequeue(out var item)) { ulong address = item.address; Debug.Assert(PtcProfiler.IsAddressInStaticCodeRange(address)); TranslatedFunction func = Translator.Translate(memory, jumpTable, address, item.mode, item.highCq); bool isAddressUnique = funcs.TryAdd(address, func); Debug.Assert(isAddressUnique, $"The address 0x{address:X16} is not unique."); if (func.HighCq) { jumpTable.RegisterFunction(address, func); } Interlocked.Increment(ref _translateCount); if (State != PtcState.Enabled) { break; } } Translator.DisposePools(); } int maxDegreeOfParallelism = (Environment.ProcessorCount * 3) / 4; List <Thread> threads = new List <Thread>(); for (int i = 0; i < maxDegreeOfParallelism; i++) { Thread thread = new Thread(TranslateFuncs); thread.IsBackground = true; threads.Add(thread); } threads.ForEach((thread) => thread.Start()); threads.ForEach((thread) => thread.Join()); threads.Clear(); _loggerEvent.Set(); PtcTranslationStateChanged?.Invoke(false); PtcJumpTable.Initialize(jumpTable); PtcJumpTable.ReadJumpTable(jumpTable); PtcJumpTable.ReadDynamicTable(jumpTable); Thread preSaveThread = new Thread(PreSave); preSaveThread.IsBackground = true; preSaveThread.Start(); }
private static unsafe void Save(string fileName) { int translatedFuncsCount; 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 { intPtr = Marshal.AllocHGlobal(size); using (UnmanagedMemoryStream stream = new((byte *)intPtr.ToPointer(), size, size, FileAccess.ReadWrite)) { stream.Seek((long)hashSize, SeekOrigin.Begin); 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)) { 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; if (fileSize != 0L) { Logger.Info?.Print(LogClass.Ptc, $"Saved Translation Cache (size: {fileSize} bytes, translated functions: {translatedFuncsCount})."); } }