| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- using ARMeilleure.State;
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.IO.Compression;
- using System.Runtime.Serialization.Formatters.Binary;
- using System.Security.Cryptography;
- using System.Threading;
- namespace ARMeilleure.Translation.PTC
- {
- public static class PtcProfiler
- {
- private const int SaveInterval = 30; // Seconds.
- private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
- private static readonly BinaryFormatter _binaryFormatter;
- private static readonly System.Timers.Timer _timer;
- private static readonly ManualResetEvent _waitEvent;
- private static readonly object _lock;
- private static bool _disposed;
- internal static Dictionary<ulong, (ExecutionMode mode, bool highCq)> ProfiledFuncs { get; private set; } //! Not to be modified.
- internal static bool Enabled { get; private set; }
- public static ulong StaticCodeStart { internal get; set; }
- public static int StaticCodeSize { internal get; set; }
- static PtcProfiler()
- {
- _binaryFormatter = new BinaryFormatter();
- _timer = new System.Timers.Timer((double)SaveInterval * 1000d);
- _timer.Elapsed += PreSave;
- _waitEvent = new ManualResetEvent(true);
- _lock = new object();
- _disposed = false;
- ProfiledFuncs = new Dictionary<ulong, (ExecutionMode, bool)>();
- Enabled = false;
- }
- internal static void AddEntry(ulong address, ExecutionMode mode, bool highCq)
- {
- if (IsAddressInStaticCodeRange(address))
- {
- lock (_lock)
- {
- Debug.Assert(!highCq && !ProfiledFuncs.ContainsKey(address));
- ProfiledFuncs.TryAdd(address, (mode, highCq));
- }
- }
- }
- internal static void UpdateEntry(ulong address, ExecutionMode mode, bool highCq)
- {
- if (IsAddressInStaticCodeRange(address))
- {
- lock (_lock)
- {
- Debug.Assert(highCq && ProfiledFuncs.ContainsKey(address));
- ProfiledFuncs[address] = (mode, highCq);
- }
- }
- }
- internal static bool IsAddressInStaticCodeRange(ulong address)
- {
- return address >= StaticCodeStart && address < StaticCodeStart + (ulong)StaticCodeSize;
- }
- internal static void ClearEntries()
- {
- ProfiledFuncs.Clear();
- }
- internal static void PreLoad()
- {
- string fileNameActual = String.Concat(Ptc.CachePathActual, ".info");
- string fileNameBackup = String.Concat(Ptc.CachePathBackup, ".info");
- FileInfo fileInfoActual = new FileInfo(fileNameActual);
- FileInfo fileInfoBackup = new FileInfo(fileNameBackup);
- if (fileInfoActual.Exists && fileInfoActual.Length != 0L)
- {
- if (!Load(fileNameActual))
- {
- if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L)
- {
- Load(fileNameBackup);
- }
- }
- }
- else if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L)
- {
- Load(fileNameBackup);
- }
- }
- private static bool Load(string fileName)
- {
- 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())
- {
- int hashSize = md5.HashSize / 8;
- deflateStream.CopyTo(stream);
- 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);
- try
- {
- ProfiledFuncs = (Dictionary<ulong, (ExecutionMode, bool)>)_binaryFormatter.Deserialize(stream);
- }
- catch
- {
- ProfiledFuncs = new Dictionary<ulong, (ExecutionMode, bool)>();
- InvalidateCompressedStream(compressedStream);
- return false;
- }
- return true;
- }
- }
- private static bool CompareHash(ReadOnlySpan<byte> currentHash, ReadOnlySpan<byte> expectedHash)
- {
- return currentHash.SequenceEqual(expectedHash);
- }
- private static void InvalidateCompressedStream(FileStream compressedStream)
- {
- compressedStream.SetLength(0L);
- }
- private static void PreSave(object source, System.Timers.ElapsedEventArgs e)
- {
- _waitEvent.Reset();
- string fileNameActual = String.Concat(Ptc.CachePathActual, ".info");
- string fileNameBackup = String.Concat(Ptc.CachePathBackup, ".info");
- FileInfo fileInfoActual = new FileInfo(fileNameActual);
- if (fileInfoActual.Exists && fileInfoActual.Length != 0L)
- {
- File.Copy(fileNameActual, fileNameBackup, true);
- }
- Save(fileNameActual);
- _waitEvent.Set();
- }
- private static void Save(string fileName)
- {
- using (MemoryStream stream = new MemoryStream())
- using (MD5 md5 = MD5.Create())
- {
- int hashSize = md5.HashSize / 8;
- stream.Seek((long)hashSize, SeekOrigin.Begin);
- lock (_lock)
- {
- _binaryFormatter.Serialize(stream, ProfiledFuncs);
- }
- 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))
- {
- try
- {
- stream.WriteTo(deflateStream);
- }
- catch
- {
- compressedStream.Position = 0L;
- }
- if (compressedStream.Position < compressedStream.Length)
- {
- compressedStream.SetLength(compressedStream.Position);
- }
- }
- }
- }
- internal static void Start()
- {
- if (Ptc.State == PtcState.Enabled ||
- Ptc.State == PtcState.Continuing)
- {
- Enabled = true;
- _timer.Enabled = true;
- }
- }
- public static void Stop()
- {
- Enabled = false;
- if (!_disposed)
- {
- _timer.Enabled = false;
- }
- }
- internal static void Wait()
- {
- _waitEvent.WaitOne();
- }
- public static void Dispose()
- {
- if (!_disposed)
- {
- _disposed = true;
- _timer.Elapsed -= PreSave;
- _timer.Dispose();
- Wait();
- _waitEvent.Dispose();
- }
- }
- }
- }
|