From 8b9c28ac7d666718ac58ceffd684ca05c73589e9 Mon Sep 17 00:00:00 2001 From: LDj3SNuD Date: Sun, 14 Feb 2021 03:04:12 +0100 Subject: [PATCH] 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. --- ARMeilleure/State/ExecutionMode.cs | 2 +- ARMeilleure/Translation/EmitterContext.cs | 3 +- ARMeilleure/Translation/PTC/Ptc.cs | 4 +- ARMeilleure/Translation/PTC/PtcFormatter.cs | 121 +++++++++++++ ARMeilleure/Translation/PTC/PtcJumpTable.cs | 180 +++----------------- ARMeilleure/Translation/PTC/PtcProfiler.cs | 64 +++---- 6 files changed, 171 insertions(+), 203 deletions(-) create mode 100644 ARMeilleure/Translation/PTC/PtcFormatter.cs diff --git a/ARMeilleure/State/ExecutionMode.cs b/ARMeilleure/State/ExecutionMode.cs index f43c5569f5..29154a2559 100644 --- a/ARMeilleure/State/ExecutionMode.cs +++ b/ARMeilleure/State/ExecutionMode.cs @@ -1,6 +1,6 @@ namespace ARMeilleure.State { - enum ExecutionMode + enum ExecutionMode : int { Aarch32Arm = 0, Aarch32Thumb = 1, diff --git a/ARMeilleure/Translation/EmitterContext.cs b/ARMeilleure/Translation/EmitterContext.cs index f41f3464b9..5c608b3d36 100644 --- a/ARMeilleure/Translation/EmitterContext.cs +++ b/ARMeilleure/Translation/EmitterContext.cs @@ -1,6 +1,7 @@ using ARMeilleure.Diagnostics; using ARMeilleure.IntermediateRepresentation; using ARMeilleure.State; +using ARMeilleure.Translation.PTC; using System; using System.Collections.Generic; using System.Reflection; @@ -9,8 +10,6 @@ using static ARMeilleure.IntermediateRepresentation.OperandHelper; namespace ARMeilleure.Translation { - using PTC; - class EmitterContext { private readonly Dictionary _irLabels; diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs index ec98fb0181..447496cbff 100644 --- a/ARMeilleure/Translation/PTC/Ptc.cs +++ b/ARMeilleure/Translation/PTC/Ptc.cs @@ -549,7 +549,7 @@ 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) { Span code = ReadCode(codesReader, infoEntry.CodeLen); @@ -808,7 +808,7 @@ namespace ARMeilleure.Translation.PTC Translator.DisposePools(); } - int maxDegreeOfParallelism = Environment.ProcessorCount; + int maxDegreeOfParallelism = (Environment.ProcessorCount * 3) / 4; List threads = new List(); diff --git a/ARMeilleure/Translation/PTC/PtcFormatter.cs b/ARMeilleure/Translation/PTC/PtcFormatter.cs new file mode 100644 index 0000000000..e4d450593f --- /dev/null +++ b/ARMeilleure/Translation/PTC/PtcFormatter.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ARMeilleure.Translation.PTC +{ + public class PtcFormatter + { + #region "Deserialize" + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Dictionary DeserializeDictionary(Stream stream, Func valueFunc) where TKey : unmanaged + { + Dictionary dictionary = new(); + + int count = DeserializeStructure(stream); + + for (int i = 0; i < count; i++) + { + TKey key = DeserializeStructure(stream); + TValue value = valueFunc(stream); + + dictionary.Add(key, value); + } + + return dictionary; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static List DeserializeList(Stream stream) where T : unmanaged + { + List list = new(); + + int count = DeserializeStructure(stream); + + for (int i = 0; i < count; i++) + { + T item = DeserializeStructure(stream); + + list.Add(item); + } + + return list; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T DeserializeStructure(Stream stream) where T : unmanaged + { + T structure = default(T); + + Span spanT = MemoryMarshal.CreateSpan(ref structure, 1); + stream.Read(MemoryMarshal.AsBytes(spanT)); + + return structure; + } + #endregion + + #region "GetSerializeSize" + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int GetSerializeSizeDictionary(Dictionary dictionary, Func valueFunc) where TKey : unmanaged + { + int size = 0; + + size += Unsafe.SizeOf(); + + foreach ((_, TValue value) in dictionary) + { + size += Unsafe.SizeOf(); + size += valueFunc(value); + } + + return size; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int GetSerializeSizeList(List list) where T : unmanaged + { + int size = 0; + + size += Unsafe.SizeOf(); + + size += list.Count * Unsafe.SizeOf(); + + return size; + } + #endregion + + #region "Serialize" + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SerializeDictionary(Stream stream, Dictionary dictionary, Action valueAction) where TKey : unmanaged + { + SerializeStructure(stream, ref Unsafe.AsRef(dictionary.Count)); + + foreach ((TKey key, TValue value) in dictionary) + { + SerializeStructure(stream, ref Unsafe.AsRef(key)); + valueAction(stream, value); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SerializeList(Stream stream, List list) where T : unmanaged + { + SerializeStructure(stream, ref Unsafe.AsRef(list.Count)); + + foreach (T item in list) + { + SerializeStructure(stream, ref Unsafe.AsRef(item)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SerializeStructure(Stream stream, ref T structure) where T : unmanaged + { + Span spanT = MemoryMarshal.CreateSpan(ref structure, 1); + stream.Write(MemoryMarshal.AsBytes(spanT)); + } + #endregion + } +} \ No newline at end of file diff --git a/ARMeilleure/Translation/PTC/PtcJumpTable.cs b/ARMeilleure/Translation/PTC/PtcJumpTable.cs index 43d64f19d1..4c0c150573 100644 --- a/ARMeilleure/Translation/PTC/PtcJumpTable.cs +++ b/ARMeilleure/Translation/PTC/PtcJumpTable.cs @@ -6,14 +6,15 @@ using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; +using static ARMeilleure.Translation.PTC.PtcFormatter; + namespace ARMeilleure.Translation.PTC { class PtcJumpTable { + [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 16*/)] public struct TableEntry { - public const int Stride = 16; // Bytes. - public int EntryIndex; public long GuestAddress; public TAddress HostAddress; // int @@ -70,179 +71,38 @@ namespace ARMeilleure.Translation.PTC public static PtcJumpTable Deserialize(Stream stream) { - using (BinaryReader reader = new BinaryReader(stream, EncodingCache.UTF8NoBOM, true)) - { - var jumpTable = new List>(); + var jumpTable = DeserializeList>(stream); + var dynamicTable = DeserializeList>(stream); - int jumpTableCount = reader.ReadInt32(); + var targets = DeserializeList(stream); + var dependants = DeserializeDictionary>(stream, (stream) => DeserializeList(stream)); + var owners = DeserializeDictionary>(stream, (stream) => DeserializeList(stream)); - for (int i = 0; i < jumpTableCount; i++) - { - int entryIndex = reader.ReadInt32(); - long guestAddress = reader.ReadInt64(); - DirectHostAddress hostAddress = (DirectHostAddress)reader.ReadInt32(); - - jumpTable.Add(new TableEntry(entryIndex, guestAddress, hostAddress)); - } - - var dynamicTable = new List>(); - - int dynamicTableCount = reader.ReadInt32(); - - for (int i = 0; i < dynamicTableCount; i++) - { - int entryIndex = reader.ReadInt32(); - long guestAddress = reader.ReadInt64(); - IndirectHostAddress hostAddress = (IndirectHostAddress)reader.ReadInt32(); - - dynamicTable.Add(new TableEntry(entryIndex, guestAddress, hostAddress)); - } - - var targets = new List(); - - int targetsCount = reader.ReadInt32(); - - for (int i = 0; i < targetsCount; i++) - { - ulong address = reader.ReadUInt64(); - - targets.Add(address); - } - - var dependants = new Dictionary>(); - - int dependantsCount = reader.ReadInt32(); - - for (int i = 0; i < dependantsCount; i++) - { - ulong address = reader.ReadUInt64(); - - var entries = new List(); - - int entriesCount = reader.ReadInt32(); - - for (int j = 0; j < entriesCount; j++) - { - int entry = reader.ReadInt32(); - - entries.Add(entry); - } - - dependants.Add(address, entries); - } - - var owners = new Dictionary>(); - - int ownersCount = reader.ReadInt32(); - - for (int i = 0; i < ownersCount; i++) - { - ulong address = reader.ReadUInt64(); - - var entries = new List(); - - int entriesCount = reader.ReadInt32(); - - for (int j = 0; j < entriesCount; j++) - { - int entry = reader.ReadInt32(); - - entries.Add(entry); - } - - owners.Add(address, entries); - } - - return new PtcJumpTable(jumpTable, dynamicTable, targets, dependants, owners); - } + return new PtcJumpTable(jumpTable, dynamicTable, targets, dependants, owners); } public static int GetSerializeSize(PtcJumpTable ptcJumpTable) { - const int CountSize = 4; // Bytes. - int size = 0; - size += CountSize + ptcJumpTable._jumpTable.Count * TableEntry.Stride; + size += GetSerializeSizeList>(ptcJumpTable._jumpTable); + size += GetSerializeSizeList>(ptcJumpTable._dynamicTable); - size += CountSize + ptcJumpTable._dynamicTable.Count * TableEntry.Stride; - - size += CountSize + ptcJumpTable.Targets.Count * 8; - - size += CountSize; - foreach (var kv in ptcJumpTable.Dependants) - { - size += 8; // kv.Key (address) - size += CountSize + kv.Value.Count * 4; - } - - size += CountSize; - foreach (var kv in ptcJumpTable.Owners) - { - size += 8; // kv.Key (address) - size += CountSize + kv.Value.Count * 4; - } + size += GetSerializeSizeList(ptcJumpTable.Targets); + size += GetSerializeSizeDictionary>(ptcJumpTable.Dependants, (list) => GetSerializeSizeList(list)); + size += GetSerializeSizeDictionary>(ptcJumpTable.Owners, (list) => GetSerializeSizeList(list)); return size; } public static void Serialize(Stream stream, PtcJumpTable ptcJumpTable) { - using (BinaryWriter writer = new BinaryWriter(stream, EncodingCache.UTF8NoBOM, true)) - { - writer.Write((int)ptcJumpTable._jumpTable.Count); + SerializeList>(stream, ptcJumpTable._jumpTable); + SerializeList>(stream, ptcJumpTable._dynamicTable); - foreach (var tableEntry in ptcJumpTable._jumpTable) - { - writer.Write((int)tableEntry.EntryIndex); - writer.Write((long)tableEntry.GuestAddress); - writer.Write((int)tableEntry.HostAddress); - } - - writer.Write((int)ptcJumpTable._dynamicTable.Count); - - foreach (var tableEntry in ptcJumpTable._dynamicTable) - { - writer.Write((int)tableEntry.EntryIndex); - writer.Write((long)tableEntry.GuestAddress); - writer.Write((int)tableEntry.HostAddress); - } - - writer.Write((int)ptcJumpTable.Targets.Count); - - foreach (ulong address in ptcJumpTable.Targets) - { - writer.Write((ulong)address); - } - - writer.Write((int)ptcJumpTable.Dependants.Count); - - foreach (var kv in ptcJumpTable.Dependants) - { - writer.Write((ulong)kv.Key); // address - - writer.Write((int)kv.Value.Count); - - foreach (int entry in kv.Value) - { - writer.Write((int)entry); - } - } - - writer.Write((int)ptcJumpTable.Owners.Count); - - foreach (var kv in ptcJumpTable.Owners) - { - writer.Write((ulong)kv.Key); // address - - writer.Write((int)kv.Value.Count); - - foreach (int entry in kv.Value) - { - writer.Write((int)entry); - } - } - } + SerializeList(stream, ptcJumpTable.Targets); + SerializeDictionary>(stream, ptcJumpTable.Dependants, (stream, list) => SerializeList(stream, list)); + SerializeDictionary>(stream, ptcJumpTable.Owners, (stream, list) => SerializeList(stream, list)); } public void Initialize(JumpTable jumpTable) @@ -349,7 +209,7 @@ namespace ARMeilleure.Translation.PTC } else { - if (!PtcProfiler.ProfiledFuncs.TryGetValue((ulong)guestAddress, out var value) || !value.highCq) + if (!PtcProfiler.ProfiledFuncs.TryGetValue((ulong)guestAddress, out var value) || !value.HighCq) { throw new KeyNotFoundException($"({nameof(guestAddress)} = 0x{(ulong)guestAddress:X16})"); } diff --git a/ARMeilleure/Translation/PTC/PtcProfiler.cs b/ARMeilleure/Translation/PTC/PtcProfiler.cs index e39795fcc7..246556a476 100644 --- a/ARMeilleure/Translation/PTC/PtcProfiler.cs +++ b/ARMeilleure/Translation/PTC/PtcProfiler.cs @@ -6,9 +6,12 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Threading; +using static ARMeilleure.Translation.PTC.PtcFormatter; + namespace ARMeilleure.Translation.PTC { public static class PtcProfiler @@ -31,7 +34,7 @@ namespace ARMeilleure.Translation.PTC private static byte[] _lastHash; - internal static Dictionary ProfiledFuncs { get; private set; } + internal static Dictionary ProfiledFuncs { get; private set; } internal static bool Enabled { get; private set; } @@ -49,7 +52,7 @@ namespace ARMeilleure.Translation.PTC _disposed = false; - ProfiledFuncs = new Dictionary(); + ProfiledFuncs = new Dictionary(); Enabled = false; } @@ -62,7 +65,7 @@ namespace ARMeilleure.Translation.PTC lock (_lock) { - ProfiledFuncs.TryAdd(address, (mode, highCq: false)); + ProfiledFuncs.TryAdd(address, new FuncProfile(mode, highCq: false)); } } } @@ -77,7 +80,7 @@ namespace ARMeilleure.Translation.PTC { Debug.Assert(ProfiledFuncs.ContainsKey(address)); - ProfiledFuncs[address] = (mode, highCq: true); + ProfiledFuncs[address] = new FuncProfile(mode, highCq: true); } } } @@ -97,7 +100,7 @@ namespace ARMeilleure.Translation.PTC if (!funcs.ContainsKey(address)) { - profiledFuncsToTranslate.Enqueue((address, profiledFunc.Value.mode, profiledFunc.Value.highCq)); + profiledFuncsToTranslate.Enqueue((address, profiledFunc.Value.Mode, profiledFunc.Value.HighCq)); } } @@ -194,7 +197,7 @@ namespace ARMeilleure.Translation.PTC } catch { - ProfiledFuncs = new Dictionary(); + ProfiledFuncs = new Dictionary(); InvalidateCompressedStream(compressedStream); @@ -230,26 +233,9 @@ namespace ARMeilleure.Translation.PTC } } - private static Dictionary Deserialize(Stream stream) + private static Dictionary Deserialize(Stream stream) { - using (BinaryReader reader = new BinaryReader(stream, EncodingCache.UTF8NoBOM, true)) - { - var profiledFuncs = new Dictionary(); - - int profiledFuncsCount = reader.ReadInt32(); - - for (int i = 0; i < profiledFuncsCount; i++) - { - ulong address = reader.ReadUInt64(); - - ExecutionMode mode = (ExecutionMode)reader.ReadInt32(); - bool highCq = reader.ReadBoolean(); - - profiledFuncs.Add(address, (mode, highCq)); - } - - return profiledFuncs; - } + return DeserializeDictionary(stream, (stream) => DeserializeStructure(stream)); } private static void InvalidateCompressedStream(FileStream compressedStream) @@ -348,20 +334,9 @@ namespace ARMeilleure.Translation.PTC } } - private static void Serialize(Stream stream, Dictionary profiledFuncs) + private static void Serialize(Stream stream, Dictionary profiledFuncs) { - using (BinaryWriter writer = new BinaryWriter(stream, EncodingCache.UTF8NoBOM, true)) - { - writer.Write((int)profiledFuncs.Count); - - foreach (var kv in profiledFuncs) - { - writer.Write((ulong)kv.Key); // address - - writer.Write((int)kv.Value.mode); - writer.Write((bool)kv.Value.highCq); - } - } + SerializeDictionary(stream, profiledFuncs, (stream, structure) => SerializeStructure(stream, ref structure)); } private struct Header @@ -371,6 +346,19 @@ namespace ARMeilleure.Translation.PTC public uint InfoFileVersion; } + [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 5*/)] + internal struct FuncProfile + { + public ExecutionMode Mode; + public bool HighCq; + + public FuncProfile(ExecutionMode mode, bool highCq) + { + Mode = mode; + HighCq = highCq; + } + } + internal static void Start() { if (Ptc.State == PtcState.Enabled ||