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);
}