From 0f14aa8f1ecdf4d16ea283ef62c83e61d1314016 Mon Sep 17 00:00:00 2001 From: yunnypuff <66578503+yunnypuff@users.noreply.github.com> Date: Thu, 8 Apr 2021 21:57:58 -0700 Subject: [PATCH] Added progress reporter for loading existing translations from PTC - Refactored existing progress reporter - Added reporting progress when loading existing translations from PTC --- ARMeilleure/Translation/PTC/Ptc.cs | 233 ++++++++++++++++++----------- 1 file changed, 147 insertions(+), 86 deletions(-) diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs index 6e1a73f66..3eb291835 100644 --- a/ARMeilleure/Translation/PTC/Ptc.cs +++ b/ARMeilleure/Translation/PTC/Ptc.cs @@ -66,9 +66,6 @@ namespace ARMeilleure.Translation.PTC internal static PtcState State { get; private set; } - // Progress reporting helpers - private static volatile int _translateCount; - private static volatile int _translateTotalCount; public static event Action PtcStateChanged; static Ptc() @@ -527,12 +524,17 @@ namespace ARMeilleure.Translation.PTC _relocsStream.Seek(0L, SeekOrigin.Begin); _unwindInfosStream.Seek(0L, SeekOrigin.Begin); + // Get total entries to process for progress reporting and for looping. + int infoEntriesCount = GetInfosEntriesCount(); + + using ProgressReporter progressReporter = ProgressReporter.CreateAndStart(infoEntriesCount, PtcStateChanged); + 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++) + for (int i = 0; i < infoEntriesCount; i++) { InfoEntry infoEntry = ReadInfo(infosReader); @@ -570,6 +572,8 @@ namespace ARMeilleure.Translation.PTC StubReloc(infoEntry.RelocEntriesCount); StubUnwindInfo(unwindInfosReader); } + + progressReporter.Increment(); } } @@ -767,76 +771,56 @@ namespace ARMeilleure.Translation.PTC return; } - _translateCount = 0; - _translateTotalCount = profiledFuncsToTranslate.Count; - - PtcStateChanged?.Invoke(PtcLoadingState.Start, _translateCount, _translateTotalCount); - - using AutoResetEvent progressReportEvent = new AutoResetEvent(false); - - Thread progressReportThread = new Thread(ReportProgress) + using (ProgressReporter progressReporter = ProgressReporter.CreateAndStart(profiledFuncsToTranslate.Count, PtcStateChanged)) { - Name = "Ptc.ProgressReporter", - Priority = ThreadPriority.Lowest, - IsBackground = true - }; - - progressReportThread.Start(progressReportEvent); - - void TranslateFuncs() - { - while (profiledFuncsToTranslate.TryDequeue(out var item)) + void TranslateFuncs() { - 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) + while (profiledFuncsToTranslate.TryDequeue(out var item)) { - jumpTable.RegisterFunction(address, func); + 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); + } + + progressReporter.Increment(); + + if (State != PtcState.Enabled) + { + break; + } } - Interlocked.Increment(ref _translateCount); - - if (State != PtcState.Enabled) - { - break; - } + Translator.DisposePools(); } - Translator.DisposePools(); + int maxDegreeOfParallelism = (Environment.ProcessorCount * 3) / 4; + + List threads = new List(); + + 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(); } - int maxDegreeOfParallelism = (Environment.ProcessorCount * 3) / 4; - - List threads = new List(); - - 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(); - - progressReportEvent.Set(); - progressReportThread.Join(); - - PtcStateChanged?.Invoke(PtcLoadingState.Loaded, _translateCount, _translateTotalCount); - - Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated"); - PtcJumpTable.Initialize(jumpTable); PtcJumpTable.ReadJumpTable(jumpTable); @@ -847,27 +831,6 @@ namespace ARMeilleure.Translation.PTC preSaveThread.Start(); } - private static void ReportProgress(object state) - { - const int refreshRate = 50; // ms - - AutoResetEvent endEvent = (AutoResetEvent)state; - - int count = 0; - - do - { - int newCount = _translateCount; - - if (count != newCount) - { - PtcStateChanged?.Invoke(PtcLoadingState.Loading, newCount, _translateTotalCount); - count = newCount; - } - } - while (!endEvent.WaitOne(refreshRate)); - } - internal static void WriteInfoCodeRelocUnwindInfo(ulong address, ulong guestSize, bool highCq, PtcInfo ptcInfo) { lock (_lock) @@ -986,5 +949,103 @@ namespace ARMeilleure.Translation.PTC DisposeMemoryStreams(); } } + + /// + /// Class for reporting PTC translation / loading item progress to the UI + /// + private class ProgressReporter : IDisposable + { + private bool _disposed; + + private volatile int _itemsProcessed; + private readonly int _itemsTotal; + + private readonly AutoResetEvent _progressReportEvent; + private readonly Thread _progressReportThread; + private readonly Action _onPtcStateChanged; + + private ProgressReporter(int totalItems, Action onPtcStateChanged) + { + _disposed = false; + _itemsProcessed = 0; + _itemsTotal = totalItems; + + _progressReportEvent = new AutoResetEvent(false); + + _progressReportThread = new Thread(ReportProgress) + { + Name = "Ptc.ProgressReporter", + Priority = ThreadPriority.Lowest, + IsBackground = true + }; + + _onPtcStateChanged = onPtcStateChanged; + } + + /// + /// Creates a progress reporter and starts the background reporting thread + /// + /// + /// + /// + public static ProgressReporter CreateAndStart(int totalItems, Action onPtcStateChanged) + { + var reporter = new ProgressReporter(totalItems, onPtcStateChanged); + reporter.Start(); + + return reporter; + } + + /// + /// Report progress for one item + /// + public void Increment() + { + Interlocked.Increment(ref _itemsProcessed); + } + + public void Dispose() + { + if (!_disposed) + { + _progressReportEvent.Set(); + _progressReportThread.Join(); + _onPtcStateChanged?.Invoke(PtcLoadingState.Loaded, 0, _itemsTotal); + _disposed = true; + } + } + + private void Start() + { + if (_disposed) + { + throw new ObjectDisposedException(nameof(ProgressReporter)); + } + + _onPtcStateChanged?.Invoke(PtcLoadingState.Start, 0, _itemsTotal); + _progressReportThread.Start(_progressReportEvent); + } + + private void ReportProgress(object state) + { + const int refreshRate = 50; // ms + + AutoResetEvent endEvent = (AutoResetEvent)state; + + int count = 0; + + do + { + int newCount = _itemsProcessed; + + if (count != newCount) + { + _onPtcStateChanged?.Invoke(PtcLoadingState.Loading, newCount, _itemsTotal); + count = newCount; + } + } + while (!endEvent.WaitOne(refreshRate)); + } + } } } \ No newline at end of file