using System.Diagnostics; using System.Runtime.CompilerServices; using AyCode.Core.Serializers.Binaries; using AyCode.Core.Tests.TestModels; using MessagePack; using MessagePack.Resolvers; namespace AyCode.Core.Serializers.Console; /// /// Console application for Performance Diagnostics profiling. /// Run with: Debug > Performance Profiler in Visual Studio /// /// Usage: /// dotnet run -- serialize # Profile serialize only /// dotnet run -- deserialize # Profile deserialize only /// dotnet run -- all # Profile both (default) /// public static class Program { private const int WarmupIterations = 50; private const int TestIterations = 5000; // Keep references to prevent GC during profiling private static TestOrder s_testOrder = null!; private static byte[] s_acBinaryData = null!; private static byte[] s_acBinaryNoRefData = null!; private static byte[] s_msgPackData = null!; private static AcBinarySerializerOptions s_acBinaryOptions = null!; private static AcBinarySerializerOptions s_acBinaryNoRefOptions = null!; private static MessagePackSerializerOptions s_msgPackOptions = null!; public static void Main(string[] args) { var mode = args.Length > 0 ? args[0].ToLower() : "all"; System.Console.WriteLine("=".PadRight(60, '=')); System.Console.WriteLine($"AcBinary Performance Profiler - Mode: {mode}"); System.Console.WriteLine("=".PadRight(60, '=')); Setup(); Warmup(); System.Console.WriteLine($"\nRunning {TestIterations} iterations...\n"); var sw = Stopwatch.StartNew(); switch (mode) { case "serialize": case "ser": RunSerializeTests(); break; case "deserialize": case "des": RunDeserializeTests(); break; default: RunSerializeTests(); RunDeserializeTests(); break; } sw.Stop(); System.Console.WriteLine($"\nTotal time: {sw.ElapsedMilliseconds:N0} ms"); System.Console.WriteLine("=".PadRight(60, '=')); } private static void Setup() { System.Console.WriteLine("Creating test data..."); TestDataFactory.ResetIdCounter(); var sharedTag = TestDataFactory.CreateTag("SharedTag"); var sharedUser = TestDataFactory.CreateUser("shareduser"); var sharedMeta = TestDataFactory.CreateMetadata("shared", withChild: true); s_testOrder = TestDataFactory.CreateOrder( itemCount: 3, palletsPerItem: 3, measurementsPerPallet: 3, pointsPerMeasurement: 4, sharedTag: sharedTag, sharedUser: sharedUser, sharedMetadata: sharedMeta); s_acBinaryOptions = AcBinarySerializerOptions.Default; s_acBinaryNoRefOptions = AcBinarySerializerOptions.WithoutReferenceHandling(); s_msgPackOptions = ContractlessStandardResolver.Options.WithCompression(MessagePackCompression.None); s_acBinaryData = AcBinarySerializer.Serialize(s_testOrder, s_acBinaryOptions); s_acBinaryNoRefData = AcBinarySerializer.Serialize(s_testOrder, s_acBinaryNoRefOptions); s_msgPackData = MessagePackSerializer.Serialize(s_testOrder, s_msgPackOptions); System.Console.WriteLine($" AcBinary (WithRef): {s_acBinaryData.Length:N0} bytes"); System.Console.WriteLine($" AcBinary (NoRef): {s_acBinaryNoRefData.Length:N0} bytes"); System.Console.WriteLine($" MessagePack: {s_msgPackData.Length:N0} bytes"); } private static void Warmup() { System.Console.WriteLine($"Warming up ({WarmupIterations} iterations)..."); for (int i = 0; i < WarmupIterations; i++) { DoSerializeAcBinary(); DoSerializeAcBinaryNoRef(); DoSerializeMsgPack(); DoDeserializeAcBinary(); DoDeserializeAcBinaryNoRef(); DoDeserializeMsgPack(); } } private static void RunSerializeTests() { System.Console.WriteLine("--- SERIALIZE ---"); var sw = Stopwatch.StartNew(); for (int i = 0; i < TestIterations; i++) { DoSerializeAcBinary(); } sw.Stop(); System.Console.WriteLine($" AcBinary (WithRef): {sw.ElapsedMilliseconds,6:N0} ms"); sw.Restart(); for (int i = 0; i < TestIterations; i++) { DoSerializeAcBinaryNoRef(); } sw.Stop(); System.Console.WriteLine($" AcBinary (NoRef): {sw.ElapsedMilliseconds,6:N0} ms"); sw.Restart(); for (int i = 0; i < TestIterations; i++) { DoSerializeMsgPack(); } sw.Stop(); System.Console.WriteLine($" MessagePack: {sw.ElapsedMilliseconds,6:N0} ms"); } private static void RunDeserializeTests() { System.Console.WriteLine("--- DESERIALIZE ---"); var sw = Stopwatch.StartNew(); for (int i = 0; i < TestIterations; i++) { DoDeserializeAcBinary(); } sw.Stop(); System.Console.WriteLine($" AcBinary (WithRef): {sw.ElapsedMilliseconds,6:N0} ms"); sw.Restart(); for (int i = 0; i < TestIterations; i++) { DoDeserializeAcBinaryNoRef(); } sw.Stop(); System.Console.WriteLine($" AcBinary (NoRef): {sw.ElapsedMilliseconds,6:N0} ms"); sw.Restart(); for (int i = 0; i < TestIterations; i++) { DoDeserializeMsgPack(); } sw.Stop(); System.Console.WriteLine($" MessagePack: {sw.ElapsedMilliseconds,6:N0} ms"); } // Separate methods for better profiler visibility - NO INLINING [MethodImpl(MethodImplOptions.NoInlining)] private static byte[] DoSerializeAcBinary() => AcBinarySerializer.Serialize(s_testOrder, s_acBinaryOptions); [MethodImpl(MethodImplOptions.NoInlining)] private static byte[] DoSerializeAcBinaryNoRef() => AcBinarySerializer.Serialize(s_testOrder, s_acBinaryNoRefOptions); [MethodImpl(MethodImplOptions.NoInlining)] private static byte[] DoSerializeMsgPack() => MessagePackSerializer.Serialize(s_testOrder, s_msgPackOptions); [MethodImpl(MethodImplOptions.NoInlining)] private static TestOrder? DoDeserializeAcBinary() => AcBinaryDeserializer.Deserialize(s_acBinaryData); [MethodImpl(MethodImplOptions.NoInlining)] private static TestOrder? DoDeserializeAcBinaryNoRef() => AcBinaryDeserializer.Deserialize(s_acBinaryNoRefData); [MethodImpl(MethodImplOptions.NoInlining)] private static TestOrder? DoDeserializeMsgPack() => MessagePackSerializer.Deserialize(s_msgPackData, s_msgPackOptions); }