using AyCode.Core.Serializers.Attributes; using AyCode.Core.Serializers.Binaries; using BenchmarkDotNet.Attributes; using MessagePack; using MessagePack.Resolvers; namespace AyCode.Core.Benchmarks; /// /// Pure contractless model - NO MessagePack attributes. /// This tests TRUE runtime serialization without any source generation. /// [AcBinarySerializable] public class PureContractlessModel { public int Id { get; set; } public string Name { get; set; } = ""; public string Description { get; set; } = ""; public bool IsActive { get; set; } public double Value { get; set; } public decimal Price { get; set; } public long BigNumber { get; set; } public DateTime CreatedAt { get; set; } public Guid UniqueId { get; set; } public int Count { get; set; } public string Category { get; set; } = ""; public string Status { get; set; } = ""; } /// /// Benchmark model with only primitive types - fully supported by Source Generator. /// MessagePack attributes added for fair comparison with Source Generator. /// [AcBinarySerializable] [MessagePackObject] public class PrimitiveBenchmarkModel { [Key(0)] public int Id { get; set; } [Key(1)] public string Name { get; set; } = ""; [Key(2)] public string Description { get; set; } = ""; [Key(3)] public bool IsActive { get; set; } [Key(4)] public double Value { get; set; } [Key(5)] public decimal Price { get; set; } [Key(6)] public long BigNumber { get; set; } [Key(7)] public DateTime CreatedAt { get; set; } [Key(8)] public Guid UniqueId { get; set; } [Key(9)] public int Count { get; set; } [Key(10)] public string Category { get; set; } = ""; [Key(11)] public string Status { get; set; } = ""; } /// /// TRUE Contractless benchmark - no attributes, pure runtime serialization. /// [ShortRunJob] [MemoryDiagnoser] [RankColumn] public class PureContractlessBenchmark { private PureContractlessModel _testData = null!; private byte[] _acBinaryData = null!; private byte[] _msgPackContractlessData = null!; private AcBinarySerializerOptions _binaryOptions = null!; private MessagePackSerializerOptions _msgPackContractlessOptions = null!; [GlobalSetup] public void Setup() { _testData = new PureContractlessModel { Id = 12345, Name = "Test Product Name", Description = "This is a longer description for testing string serialization performance", IsActive = true, Value = 123.456789, Price = 99.99m, BigNumber = 9876543210L, CreatedAt = DateTime.UtcNow, UniqueId = Guid.NewGuid(), Count = 42, Category = "Electronics", Status = "Available" }; _binaryOptions = AcBinarySerializerOptions.WithoutReferenceHandling(); _msgPackContractlessOptions = ContractlessStandardResolver.Options.WithCompression(MessagePackCompression.None); _acBinaryData = AcBinarySerializer.Serialize(_testData, _binaryOptions); _msgPackContractlessData = MessagePackSerializer.Serialize(_testData, _msgPackContractlessOptions); Console.WriteLine($"=== Pure Contractless (NO attributes) ==="); Console.WriteLine($"AcBinary: {_acBinaryData.Length} bytes"); Console.WriteLine($"MsgPack Contractless: {_msgPackContractlessData.Length} bytes"); } [Benchmark(Description = "AcBinary Serialize")] public byte[] Serialize_AcBinary() => AcBinarySerializer.Serialize(_testData, _binaryOptions); [Benchmark(Description = "MsgPack Contractless Serialize", Baseline = true)] public byte[] Serialize_MsgPack_Contractless() => MessagePackSerializer.Serialize(_testData, _msgPackContractlessOptions); [Benchmark(Description = "AcBinary Deserialize")] public PureContractlessModel? Deserialize_AcBinary() => AcBinaryDeserializer.Deserialize(_acBinaryData); [Benchmark(Description = "MsgPack Contractless Deserialize")] public PureContractlessModel? Deserialize_MsgPack_Contractless() => MessagePackSerializer.Deserialize(_msgPackContractlessData, _msgPackContractlessOptions); } /// /// Benchmark comparing Source Generator vs Runtime serialization for primitive-only types. /// Uses MessagePack with [MessagePackObject] attributes for fair Source Generator comparison. /// [ShortRunJob] [MemoryDiagnoser] [RankColumn] public class SourceGeneratorVsRuntimeBenchmark { private PrimitiveBenchmarkModel _testData = null!; private byte[] _runtimeSerializedData = null!; private byte[] _msgPackData = null!; private byte[] _msgPackContractlessData = null!; private AcBinarySerializerOptions _binaryOptions = null!; private MessagePackSerializerOptions _msgPackOptions = null!; private MessagePackSerializerOptions _msgPackContractlessOptions = null!; [GlobalSetup] public void Setup() { _testData = new PrimitiveBenchmarkModel { Id = 12345, Name = "Test Product Name", Description = "This is a longer description for testing string serialization performance", IsActive = true, Value = 123.456789, Price = 99.99m, BigNumber = 9876543210L, CreatedAt = DateTime.UtcNow, UniqueId = Guid.NewGuid(), Count = 42, Category = "Electronics", Status = "Available" }; _binaryOptions = AcBinarySerializerOptions.WithoutReferenceHandling(); // MessagePack with Source Generator (uses [MessagePackObject] + [Key] attributes) _msgPackOptions = MessagePackSerializerOptions.Standard; // MessagePack without Source Generator (Contractless - reflection based, like AcBinary runtime) _msgPackContractlessOptions = ContractlessStandardResolver.Options.WithCompression(MessagePackCompression.None); // Pre-serialize for deserialize benchmarks _runtimeSerializedData = AcBinarySerializer.Serialize(_testData, _binaryOptions); _msgPackData = MessagePackSerializer.Serialize(_testData, _msgPackOptions); _msgPackContractlessData = MessagePackSerializer.Serialize(_testData, _msgPackContractlessOptions); // Print sizes Console.WriteLine($"=== Primitive Model Serialization ==="); Console.WriteLine($"AcBinary Runtime: {_runtimeSerializedData.Length} bytes"); Console.WriteLine($"MessagePack SourceGen: {_msgPackData.Length} bytes"); Console.WriteLine($"MessagePack Contractless:{_msgPackContractlessData.Length} bytes"); // Verify generated serializer exists var generatedType = typeof(PrimitiveBenchmarkModel).Assembly.GetType( $"{typeof(PrimitiveBenchmarkModel).FullName}_AcBinarySerializer"); Console.WriteLine($"AcBinary Generated serializer found: {generatedType != null}"); } #region Serialize Benchmarks [Benchmark(Description = "AcBinary Runtime Serialize")] public byte[] Serialize_AcBinary_Runtime() => AcBinarySerializer.Serialize(_testData, _binaryOptions); [Benchmark(Description = "MsgPack SourceGen Serialize", Baseline = true)] public byte[] Serialize_MsgPack_SourceGen() => MessagePackSerializer.Serialize(_testData, _msgPackOptions); [Benchmark(Description = "MsgPack Contractless Serialize")] public byte[] Serialize_MsgPack_Contractless() => MessagePackSerializer.Serialize(_testData, _msgPackContractlessOptions); #endregion #region Deserialize Benchmarks [Benchmark(Description = "AcBinary Runtime Deserialize")] public PrimitiveBenchmarkModel? Deserialize_AcBinary_Runtime() => AcBinaryDeserializer.Deserialize(_runtimeSerializedData); [Benchmark(Description = "MsgPack SourceGen Deserialize")] public PrimitiveBenchmarkModel? Deserialize_MsgPack_SourceGen() => MessagePackSerializer.Deserialize(_msgPackData, _msgPackOptions); [Benchmark(Description = "MsgPack Contractless Deserialize")] public PrimitiveBenchmarkModel? Deserialize_MsgPack_Contractless() => MessagePackSerializer.Deserialize(_msgPackContractlessData, _msgPackContractlessOptions); #endregion } /// /// Repeated string benchmark model - tests string interning performance. /// MessagePack attributes added for fair comparison. /// [AcBinarySerializable] [MessagePackObject] public class RepeatedStringBenchmarkModel { [Key(0)] public int Id { get; set; } [Key(1)] public string Status { get; set; } = ""; [Key(2)] public string Category { get; set; } = ""; [Key(3)] public string Priority { get; set; } = ""; [Key(4)] public string Type { get; set; } = ""; } /// /// Benchmark for types with repeated string values - where AcBinary string interning helps. /// Compares against both MessagePack SourceGen and Contractless modes. /// [ShortRunJob] [MemoryDiagnoser] [RankColumn] public class RepeatedStringBenchmark { private List _items = null!; private byte[] _acBinaryData = null!; private byte[] _msgPackData = null!; private byte[] _msgPackContractlessData = null!; private AcBinarySerializerOptions _binaryOptions = null!; private MessagePackSerializerOptions _msgPackOptions = null!; private MessagePackSerializerOptions _msgPackContractlessOptions = null!; [Params(100, 500)] public int ItemCount { get; set; } [GlobalSetup] public void Setup() { _items = Enumerable.Range(0, ItemCount).Select(i => new RepeatedStringBenchmarkModel { Id = i, Status = i % 3 == 0 ? "Pending" : i % 3 == 1 ? "Processing" : "Completed", Category = $"Category_{i % 5}", Priority = i % 2 == 0 ? "High" : "Low", Type = i % 4 == 0 ? "TypeA" : i % 4 == 1 ? "TypeB" : i % 4 == 2 ? "TypeC" : "TypeD" }).ToList(); _binaryOptions = AcBinarySerializerOptions.WithoutReferenceHandling(); _msgPackOptions = MessagePackSerializerOptions.Standard; _msgPackContractlessOptions = ContractlessStandardResolver.Options.WithCompression(MessagePackCompression.None); _acBinaryData = AcBinarySerializer.Serialize(_items, _binaryOptions); _msgPackData = MessagePackSerializer.Serialize(_items, _msgPackOptions); _msgPackContractlessData = MessagePackSerializer.Serialize(_items, _msgPackContractlessOptions); Console.WriteLine($"=== Repeated Strings ({ItemCount} items) ==="); Console.WriteLine($"AcBinary: {_acBinaryData.Length} bytes"); Console.WriteLine($"MsgPack SourceGen: {_msgPackData.Length} bytes"); Console.WriteLine($"MsgPack Contractless: {_msgPackContractlessData.Length} bytes"); } [Benchmark(Description = "AcBinary Serialize")] public byte[] Serialize_AcBinary() => AcBinarySerializer.Serialize(_items, _binaryOptions); [Benchmark(Description = "MsgPack SourceGen Serialize", Baseline = true)] public byte[] Serialize_MsgPack_SourceGen() => MessagePackSerializer.Serialize(_items, _msgPackOptions); [Benchmark(Description = "MsgPack Contractless Serialize")] public byte[] Serialize_MsgPack_Contractless() => MessagePackSerializer.Serialize(_items, _msgPackContractlessOptions); [Benchmark(Description = "AcBinary Deserialize")] public List? Deserialize_AcBinary() => AcBinaryDeserializer.Deserialize>(_acBinaryData); [Benchmark(Description = "MsgPack SourceGen Deserialize")] public List? Deserialize_MsgPack_SourceGen() => MessagePackSerializer.Deserialize>(_msgPackData, _msgPackOptions); [Benchmark(Description = "MsgPack Contractless Deserialize")] public List? Deserialize_MsgPack_Contractless() => MessagePackSerializer.Deserialize>(_msgPackContractlessData, _msgPackContractlessOptions); }