546 lines
22 KiB
C#
546 lines
22 KiB
C#
using AyCode.Core.Extensions;
|
|
using AyCode.Core.Tests.TestModels;
|
|
using BenchmarkDotNet.Attributes;
|
|
using BenchmarkDotNet.Jobs;
|
|
using MessagePack;
|
|
using MessagePack.Resolvers;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using JsonSerializer = System.Text.Json.JsonSerializer;
|
|
using MongoDB.Bson;
|
|
using MongoDB.Bson.IO;
|
|
using MongoDB.Bson.Serialization;
|
|
using System.IO;
|
|
using AyCode.Core.Serializers.Binaries;
|
|
using AyCode.Core.Serializers.Jsons;
|
|
|
|
namespace AyCode.Core.Benchmarks;
|
|
|
|
/// <summary>
|
|
/// Minimal benchmark to test if BenchmarkDotNet works without stack overflow.
|
|
/// </summary>
|
|
[ShortRunJob]
|
|
[MemoryDiagnoser]
|
|
public class MinimalBenchmark
|
|
{
|
|
private byte[] _data = null!;
|
|
private string _json = null!;
|
|
|
|
[GlobalSetup]
|
|
public void Setup()
|
|
{
|
|
// Use very simple data - no circular references
|
|
var simpleData = new { Id = 1, Name = "Test", Value = 42.5 };
|
|
_json = System.Text.Json.JsonSerializer.Serialize(simpleData);
|
|
_data = Encoding.UTF8.GetBytes(_json);
|
|
Console.WriteLine($"Setup complete. Data size: {_data.Length} bytes");
|
|
}
|
|
|
|
[Benchmark]
|
|
public int GetLength() => _data.Length;
|
|
|
|
[Benchmark]
|
|
public string GetJson() => _json;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Binary vs JSON benchmark with simple flat objects (no circular references).
|
|
/// </summary>
|
|
[ShortRunJob]
|
|
[MemoryDiagnoser]
|
|
public class SimpleBinaryBenchmark
|
|
{
|
|
private PrimitiveTestClass _testData = null!;
|
|
private byte[] _binaryData = null!;
|
|
private string _jsonData = null!;
|
|
|
|
[GlobalSetup]
|
|
public void Setup()
|
|
{
|
|
_testData = TestDataFactory.CreatePrimitiveTestData();
|
|
_binaryData = AcBinarySerializer.Serialize(_testData, AcBinarySerializerOptions.WithoutReferenceHandling());
|
|
_jsonData = AcJsonSerializer.Serialize(_testData, AcJsonSerializerOptions.WithoutReferenceHandling());
|
|
|
|
Console.WriteLine($"Binary: {_binaryData.Length} bytes, JSON: {_jsonData.Length} chars");
|
|
}
|
|
|
|
[Benchmark(Description = "Binary Serialize")]
|
|
public byte[] SerializeBinary() => AcBinarySerializer.Serialize(_testData, AcBinarySerializerOptions.WithoutReferenceHandling());
|
|
|
|
[Benchmark(Description = "JSON Serialize", Baseline = true)]
|
|
public string SerializeJson() => AcJsonSerializer.Serialize(_testData, AcJsonSerializerOptions.WithoutReferenceHandling());
|
|
|
|
[Benchmark(Description = "Binary Deserialize")]
|
|
public PrimitiveTestClass? DeserializeBinary() => AcBinaryDeserializer.Deserialize<PrimitiveTestClass>(_binaryData);
|
|
|
|
[Benchmark(Description = "JSON Deserialize")]
|
|
public PrimitiveTestClass? DeserializeJson() => AcJsonDeserializer.Deserialize<PrimitiveTestClass>(_jsonData, AcJsonSerializerOptions.WithoutReferenceHandling());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Complex hierarchy benchmark - AcBinary vs JSON only (no MessagePack to isolate the issue).
|
|
/// Uses AcBinary without reference handling.
|
|
/// </summary>
|
|
[ShortRunJob]
|
|
[MemoryDiagnoser]
|
|
[RankColumn]
|
|
public class ComplexBinaryBenchmark
|
|
{
|
|
private TestOrder _testOrder = null!;
|
|
private byte[] _acBinaryData = null!;
|
|
private string _jsonData = null!;
|
|
|
|
private AcBinarySerializerOptions _binaryOptions = null!;
|
|
private AcJsonSerializerOptions _jsonOptions = null!;
|
|
|
|
[GlobalSetup]
|
|
public void Setup()
|
|
{
|
|
Console.WriteLine("Creating test data...");
|
|
_testOrder = TestDataFactory.CreateBenchmarkOrder(
|
|
itemCount: 2,
|
|
palletsPerItem: 2,
|
|
measurementsPerPallet: 2,
|
|
pointsPerMeasurement: 3);
|
|
Console.WriteLine($"Created order with {_testOrder.Items.Count} items");
|
|
|
|
_binaryOptions = AcBinarySerializerOptions.WithoutReferenceHandling();
|
|
_jsonOptions = AcJsonSerializerOptions.WithoutReferenceHandling();
|
|
|
|
Console.WriteLine("Serializing AcBinary...");
|
|
_acBinaryData = AcBinarySerializer.Serialize(_testOrder, _binaryOptions);
|
|
Console.WriteLine($"AcBinary size: {_acBinaryData.Length} bytes");
|
|
|
|
Console.WriteLine("Serializing JSON...");
|
|
_jsonData = AcJsonSerializer.Serialize(_testOrder, _jsonOptions);
|
|
Console.WriteLine($"JSON size: {_jsonData.Length} chars");
|
|
|
|
var jsonBytes = Encoding.UTF8.GetByteCount(_jsonData);
|
|
Console.WriteLine($"\n=== SIZE COMPARISON ===");
|
|
Console.WriteLine($"AcBinary: {_acBinaryData.Length,8:N0} bytes ({100.0 * _acBinaryData.Length / jsonBytes:F1}%)");
|
|
Console.WriteLine($"JSON: {jsonBytes,8:N0} bytes (100.0%)");
|
|
}
|
|
|
|
[Benchmark(Description = "AcBinary Serialize")]
|
|
public byte[] Serialize_AcBinary() => AcBinarySerializer.Serialize(_testOrder, _binaryOptions);
|
|
|
|
[Benchmark(Description = "JSON Serialize", Baseline = true)]
|
|
public string Serialize_Json() => AcJsonSerializer.Serialize(_testOrder, _jsonOptions);
|
|
|
|
[Benchmark(Description = "AcBinary Deserialize")]
|
|
public TestOrder? Deserialize_AcBinary() => AcBinaryDeserializer.Deserialize<TestOrder>(_acBinaryData);
|
|
|
|
[Benchmark(Description = "JSON Deserialize")]
|
|
public TestOrder? Deserialize_Json() => AcJsonDeserializer.Deserialize<TestOrder>(_jsonData, _jsonOptions);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Full comparison with MessagePack and BSON - AcBinary uses NO reference handling everywhere.
|
|
/// </summary>
|
|
[ShortRunJob]
|
|
[MemoryDiagnoser]
|
|
[RankColumn]
|
|
public class MessagePackComparisonBenchmark
|
|
{
|
|
private TestOrder _testOrder = null!;
|
|
private byte[] _acBinaryData = null!;
|
|
private byte[] _msgPackData = null!;
|
|
private byte[] _bsonData = null!;
|
|
private string _jsonData = null!;
|
|
|
|
private AcBinarySerializerOptions _binaryOptions = null!;
|
|
private MessagePackSerializerOptions _msgPackOptions = null!;
|
|
private AcJsonSerializerOptions _jsonOptions = null!;
|
|
|
|
[GlobalSetup]
|
|
public void Setup()
|
|
{
|
|
Console.WriteLine("Creating test data...");
|
|
_testOrder = TestDataFactory.CreateBenchmarkOrder(
|
|
itemCount: 2,
|
|
palletsPerItem: 2,
|
|
measurementsPerPallet: 2,
|
|
pointsPerMeasurement: 3);
|
|
|
|
_binaryOptions = AcBinarySerializerOptions.WithoutReferenceHandling();
|
|
_msgPackOptions = ContractlessStandardResolver.Options.WithCompression(MessagePackCompression.None);
|
|
_jsonOptions = AcJsonSerializerOptions.WithoutReferenceHandling();
|
|
|
|
_acBinaryData = AcBinarySerializer.Serialize(_testOrder, _binaryOptions);
|
|
_jsonData = AcJsonSerializer.Serialize(_testOrder, _jsonOptions);
|
|
|
|
// MessagePack serialization in try-catch to see if it fails
|
|
try
|
|
{
|
|
Console.WriteLine("Serializing MessagePack...");
|
|
_msgPackData = MessagePackSerializer.Serialize(_testOrder, _msgPackOptions);
|
|
Console.WriteLine($"MessagePack size: {_msgPackData.Length} bytes");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"MessagePack serialization failed: {ex.Message}");
|
|
_msgPackData = Array.Empty<byte>();
|
|
}
|
|
|
|
// BSON serialization
|
|
try
|
|
{
|
|
Console.WriteLine("Serializing BSON...");
|
|
var bsonDoc = _testOrder.ToBsonDocument();
|
|
_bsonData = bsonDoc.ToBson();
|
|
Console.WriteLine($"BSON size: {_bsonData.Length} bytes");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"BSON serialization failed: {ex.Message}");
|
|
_bsonData = Array.Empty<byte>();
|
|
}
|
|
|
|
var jsonBytes = Encoding.UTF8.GetByteCount(_jsonData);
|
|
Console.WriteLine($"\n=== SIZE COMPARISON ===");
|
|
Console.WriteLine($"AcBinary: {_acBinaryData.Length,8:N0} bytes ({100.0 * _acBinaryData.Length / jsonBytes:F1}%)");
|
|
Console.WriteLine($"MessagePack: {_msgPackData.Length,8:N0} bytes ({100.0 * _msgPackData.Length / jsonBytes:F1}%)");
|
|
Console.WriteLine($"BSON: {_bsonData.Length,8:N0} bytes ({100.0 * _bsonData.Length / jsonBytes:F1}%)");
|
|
Console.WriteLine($"JSON: {jsonBytes,8:N0} bytes (100.0%)");
|
|
}
|
|
|
|
[Benchmark(Description = "AcBinary Serialize")]
|
|
public byte[] Serialize_AcBinary() => AcBinarySerializer.Serialize(_testOrder, _binaryOptions);
|
|
|
|
[Benchmark(Description = "MessagePack Serialize", Baseline = true)]
|
|
public byte[] Serialize_MsgPack() => MessagePackSerializer.Serialize(_testOrder, _msgPackOptions);
|
|
|
|
[Benchmark(Description = "BSON Serialize")]
|
|
public byte[] Serialize_Bson() => _testOrder.ToBsonDocument().ToBson();
|
|
|
|
[Benchmark(Description = "AcBinary Deserialize")]
|
|
public TestOrder? Deserialize_AcBinary() => AcBinaryDeserializer.Deserialize<TestOrder>(_acBinaryData);
|
|
|
|
[Benchmark(Description = "MessagePack Deserialize")]
|
|
public TestOrder? Deserialize_MsgPack() => MessagePackSerializer.Deserialize<TestOrder>(_msgPackData, _msgPackOptions);
|
|
|
|
[Benchmark(Description = "BSON Deserialize")]
|
|
public TestOrder? Deserialize_Bson()
|
|
{
|
|
if (_bsonData == null || _bsonData.Length == 0) return null;
|
|
using var ms = new MemoryStream(_bsonData);
|
|
using var reader = new BsonBinaryReader(ms);
|
|
return BsonSerializer.Deserialize<TestOrder>(reader);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Comprehensive AcBinary vs MessagePack comparison benchmark.
|
|
/// Tests: NoRef (everywhere), Populate, Serialize, Deserialize, Size
|
|
/// </summary>
|
|
[ShortRunJob]
|
|
[MemoryDiagnoser]
|
|
[RankColumn]
|
|
public class AcBinaryVsMessagePackFullBenchmark
|
|
{
|
|
// Test data
|
|
private TestOrder _testOrder = null!;
|
|
private TestOrder _populateTarget = null!;
|
|
|
|
// Serialized data - AcBinary
|
|
private byte[] _acBinaryWithRef = null!;
|
|
private byte[] _acBinaryNoRef = null!;
|
|
|
|
// Serialized data - MessagePack
|
|
private byte[] _msgPackData = null!;
|
|
private byte[] _bsonData = null!;
|
|
|
|
// Options
|
|
private AcBinarySerializerOptions _withRefOptions = null!;
|
|
private AcBinarySerializerOptions _noRefOptions = null!;
|
|
private MessagePackSerializerOptions _msgPackOptions = null!;
|
|
|
|
[GlobalSetup]
|
|
public void Setup()
|
|
{
|
|
// Create test data with shared references
|
|
TestDataFactory.ResetIdCounter();
|
|
var sharedTag = TestDataFactory.CreateTag("SharedTag");
|
|
var sharedUser = TestDataFactory.CreateUser("shareduser");
|
|
var sharedMeta = TestDataFactory.CreateMetadata("shared", withChild: true);
|
|
|
|
_testOrder = TestDataFactory.CreateOrder(
|
|
itemCount: 3,
|
|
palletsPerItem: 3,
|
|
measurementsPerPallet: 3,
|
|
pointsPerMeasurement: 4,
|
|
sharedTag: sharedTag,
|
|
sharedUser: sharedUser,
|
|
sharedMetadata: sharedMeta);
|
|
|
|
// Setup options - enforce no reference handling everywhere
|
|
_withRefOptions = AcBinarySerializerOptions.WithoutReferenceHandling();
|
|
_noRefOptions = AcBinarySerializerOptions.WithoutReferenceHandling();
|
|
_msgPackOptions = ContractlessStandardResolver.Options.WithCompression(MessagePackCompression.None);
|
|
|
|
// Serialize with different options
|
|
_acBinaryWithRef = AcBinarySerializer.Serialize(_testOrder, _withRefOptions);
|
|
_acBinaryNoRef = AcBinarySerializer.Serialize(_testOrder, _noRefOptions);
|
|
_msgPackData = MessagePackSerializer.Serialize(_testOrder, _msgPackOptions);
|
|
|
|
// BSON
|
|
try
|
|
{
|
|
_bsonData = _testOrder.ToBsonDocument().ToBson();
|
|
}
|
|
catch
|
|
{
|
|
_bsonData = Array.Empty<byte>();
|
|
}
|
|
|
|
// Create populate target
|
|
_populateTarget = new TestOrder { Id = _testOrder.Id };
|
|
foreach (var item in _testOrder.Items)
|
|
{
|
|
_populateTarget.Items.Add(new TestOrderItem { Id = item.Id });
|
|
}
|
|
|
|
// Print size comparison
|
|
PrintSizeComparison();
|
|
}
|
|
|
|
private void PrintSizeComparison()
|
|
{
|
|
Console.WriteLine("\n" + new string('=', 60));
|
|
Console.WriteLine("?? SIZE COMPARISON (AcBinary vs MessagePack vs BSON)");
|
|
Console.WriteLine(new string('=', 60));
|
|
Console.WriteLine($" AcBinary WithRef: {_acBinaryWithRef.Length,8:N0} bytes");
|
|
Console.WriteLine($" AcBinary NoRef: {_acBinaryNoRef.Length,8:N0} bytes");
|
|
Console.WriteLine($" MessagePack: {_msgPackData.Length,8:N0} bytes");
|
|
Console.WriteLine($" BSON: {_bsonData.Length,8:N0} bytes");
|
|
Console.WriteLine(new string('-', 60));
|
|
Console.WriteLine($" AcBinary/MsgPack: {100.0 * _acBinaryWithRef.Length / Math.Max(1, _msgPackData.Length):F1}% (WithRef - actually NoRef)");
|
|
Console.WriteLine($" AcBinary/MsgPack: {100.0 * _acBinaryNoRef.Length / Math.Max(1, _msgPackData.Length):F1}% (NoRef)");
|
|
Console.WriteLine(new string('=', 60) + "\n");
|
|
}
|
|
|
|
#region Serialize Benchmarks
|
|
|
|
[Benchmark(Description = "AcBinary Serialize NoRef")]
|
|
public byte[] Serialize_AcBinary_NoRef() => AcBinarySerializer.Serialize(_testOrder, _noRefOptions);
|
|
|
|
[Benchmark(Description = "MessagePack Serialize", Baseline = true)]
|
|
public byte[] Serialize_MsgPack() => MessagePackSerializer.Serialize(_testOrder, _msgPackOptions);
|
|
|
|
[Benchmark(Description = "BSON Serialize")]
|
|
public byte[] Serialize_Bson() => _testOrder.ToBsonDocument().ToBson();
|
|
|
|
#endregion
|
|
|
|
#region Deserialize Benchmarks
|
|
|
|
[Benchmark(Description = "AcBinary Deserialize NoRef")]
|
|
public TestOrder? Deserialize_AcBinary_NoRef() => AcBinaryDeserializer.Deserialize<TestOrder>(_acBinaryNoRef);
|
|
|
|
[Benchmark(Description = "MessagePack Deserialize")]
|
|
public TestOrder? Deserialize_MsgPack() => MessagePackSerializer.Deserialize<TestOrder>(_msgPackData, _msgPackOptions);
|
|
|
|
[Benchmark(Description = "BSON Deserialize")]
|
|
public TestOrder? Deserialize_Bson()
|
|
{
|
|
if (_bsonData == null || _bsonData.Length == 0) return null;
|
|
using var ms = new MemoryStream(_bsonData);
|
|
using var reader = new BsonBinaryReader(ms);
|
|
return BsonSerializer.Deserialize<TestOrder>(reader);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Populate Benchmarks
|
|
|
|
[Benchmark(Description = "AcBinary Populate NoRef")]
|
|
public void Populate_AcBinary_NoRef()
|
|
{
|
|
// Create fresh target each time to avoid state accumulation
|
|
var target = CreatePopulateTarget();
|
|
AcBinaryDeserializer.Populate(_acBinaryNoRef, target);
|
|
}
|
|
|
|
[Benchmark(Description = "AcBinary PopulateMerge NoRef")]
|
|
public void PopulateMerge_AcBinary_NoRef()
|
|
{
|
|
// Create fresh target each time to avoid state accumulation
|
|
var target = CreatePopulateTarget();
|
|
AcBinaryDeserializer.PopulateMerge(_acBinaryNoRef.AsSpan(), target);
|
|
}
|
|
|
|
private TestOrder CreatePopulateTarget()
|
|
{
|
|
var target = new TestOrder { Id = _testOrder.Id };
|
|
foreach (var item in _testOrder.Items)
|
|
{
|
|
target.Items.Add(new TestOrderItem { Id = item.Id });
|
|
}
|
|
return target;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// Detailed size comparison - not a performance benchmark, just size output.
|
|
/// Now includes BSON size output and uses AcBinary without reference handling.
|
|
/// </summary>
|
|
[ShortRunJob]
|
|
[MemoryDiagnoser]
|
|
public class SizeComparisonBenchmark
|
|
{
|
|
private TestOrder _smallOrder = null!;
|
|
private TestOrder _mediumOrder = null!;
|
|
private TestOrder _largeOrder = null!;
|
|
|
|
private MessagePackSerializerOptions _msgPackOptions = null!;
|
|
private AcBinarySerializerOptions _withRefOptions = null!;
|
|
private AcBinarySerializerOptions _noRefOptions = null!;
|
|
|
|
[GlobalSetup]
|
|
public void Setup()
|
|
{
|
|
_msgPackOptions = ContractlessStandardResolver.Options.WithCompression(MessagePackCompression.None);
|
|
_withRefOptions = AcBinarySerializerOptions.WithoutReferenceHandling();
|
|
_noRefOptions = AcBinarySerializerOptions.WithoutReferenceHandling();
|
|
|
|
// Small order
|
|
TestDataFactory.ResetIdCounter();
|
|
_smallOrder = TestDataFactory.CreateOrder(itemCount: 1, palletsPerItem: 1, measurementsPerPallet: 1, pointsPerMeasurement: 2);
|
|
|
|
// Medium order
|
|
TestDataFactory.ResetIdCounter();
|
|
var sharedTag = TestDataFactory.CreateTag("Shared");
|
|
var sharedUser = TestDataFactory.CreateUser("shared");
|
|
_mediumOrder = TestDataFactory.CreateOrder(
|
|
itemCount: 3, palletsPerItem: 2, measurementsPerPallet: 2, pointsPerMeasurement: 3,
|
|
sharedTag: sharedTag, sharedUser: sharedUser);
|
|
|
|
// Large order
|
|
TestDataFactory.ResetIdCounter();
|
|
sharedTag = TestDataFactory.CreateTag("SharedLarge");
|
|
sharedUser = TestDataFactory.CreateUser("sharedlarge");
|
|
var sharedMeta = TestDataFactory.CreateMetadata("meta", withChild: true);
|
|
_largeOrder = TestDataFactory.CreateOrder(
|
|
itemCount: 5, palletsPerItem: 4, measurementsPerPallet: 3, pointsPerMeasurement: 5,
|
|
sharedTag: sharedTag, sharedUser: sharedUser, sharedMetadata: sharedMeta);
|
|
|
|
PrintDetailedSizeComparison();
|
|
}
|
|
|
|
private void PrintDetailedSizeComparison()
|
|
{
|
|
Console.WriteLine("\n" + new string('=', 80));
|
|
Console.WriteLine("?? DETAILED SIZE COMPARISON: AcBinary vs MessagePack vs BSON");
|
|
Console.WriteLine(new string('=', 80));
|
|
|
|
PrintOrderSize("Small Order (1x1x1x2)", _smallOrder);
|
|
PrintOrderSize("Medium Order (3x2x2x3) + SharedRefs", _mediumOrder);
|
|
PrintOrderSize("Large Order (5x4x3x5) + SharedRefs", _largeOrder);
|
|
|
|
Console.WriteLine(new string('=', 80) + "\n");
|
|
}
|
|
|
|
private void PrintOrderSize(string name, TestOrder order)
|
|
{
|
|
var acWithRef = AcBinarySerializer.Serialize(order, _withRefOptions);
|
|
var acNoRef = AcBinarySerializer.Serialize(order, _noRefOptions);
|
|
var msgPack = MessagePackSerializer.Serialize(order, _msgPackOptions);
|
|
byte[] bson;
|
|
try { bson = order.ToBsonDocument().ToBson(); } catch { bson = Array.Empty<byte>(); }
|
|
|
|
Console.WriteLine($"\n {name}:");
|
|
Console.WriteLine($" AcBinary WithRef: {acWithRef.Length,8:N0} bytes ({100.0 * acWithRef.Length / Math.Max(1, msgPack.Length),5:F1}% of MsgPack)");
|
|
Console.WriteLine($" AcBinary NoRef: {acNoRef.Length,8:N0} bytes ({100.0 * acNoRef.Length / Math.Max(1, msgPack.Length),5:F1}% of MsgPack)");
|
|
Console.WriteLine($" MessagePack: {msgPack.Length,8:N0} bytes (100.0%)");
|
|
Console.WriteLine($" BSON: {bson.Length,8:N0} bytes (compared to MsgPack)");
|
|
|
|
var withRefSaving = msgPack.Length - acWithRef.Length;
|
|
var noRefSaving = msgPack.Length - acNoRef.Length;
|
|
if (withRefSaving > 0)
|
|
Console.WriteLine($" ?? AcBinary WithRef saves: {withRefSaving:N0} bytes ({100.0 * withRefSaving / msgPack.Length:F1}%)");
|
|
else
|
|
Console.WriteLine($" ?? AcBinary WithRef larger by: {-withRefSaving:N0} bytes");
|
|
}
|
|
|
|
[Benchmark(Description = "Placeholder")]
|
|
public int Placeholder() => 1; // Just to make BenchmarkDotNet happy
|
|
}
|
|
|
|
public enum BinaryBenchmarkMode
|
|
{
|
|
Default,
|
|
NoReferenceHandling,
|
|
FastMode
|
|
}
|
|
|
|
public abstract class AcBinaryOptionsBenchmarkBase
|
|
{
|
|
protected TestOrder TestOrder = null!;
|
|
protected AcBinarySerializerOptions BinaryOptions = null!;
|
|
protected MessagePackSerializerOptions MsgPackOptions = null!;
|
|
protected byte[] AcBinaryData = null!;
|
|
protected byte[] MsgPackData = null!;
|
|
|
|
[Params(BinaryBenchmarkMode.Default, BinaryBenchmarkMode.NoReferenceHandling, BinaryBenchmarkMode.FastMode)]
|
|
public BinaryBenchmarkMode Mode { get; set; }
|
|
|
|
[GlobalSetup]
|
|
public void GlobalSetup()
|
|
{
|
|
TestDataFactory.ResetIdCounter();
|
|
TestOrder = TestDataFactory.CreateBenchmarkOrder(
|
|
itemCount: 4,
|
|
palletsPerItem: 3,
|
|
measurementsPerPallet: 3,
|
|
pointsPerMeasurement: 6);
|
|
|
|
BinaryOptions = CreateBinaryOptions(Mode);
|
|
MsgPackOptions = ContractlessStandardResolver.Options.WithCompression(MessagePackCompression.None);
|
|
|
|
AcBinaryData = AcBinarySerializer.Serialize(TestOrder, BinaryOptions);
|
|
MsgPackData = MessagePackSerializer.Serialize(TestOrder, MsgPackOptions);
|
|
|
|
var ratio = MsgPackData.Length == 0 ? 0 : 100.0 * AcBinaryData.Length / MsgPackData.Length;
|
|
Console.WriteLine($"[BenchmarkSetup] Mode={Mode} | AcBinary={AcBinaryData.Length} bytes | MessagePack={MsgPackData.Length} bytes | Ratio={ratio:F1}%");
|
|
}
|
|
|
|
private static AcBinarySerializerOptions CreateBinaryOptions(BinaryBenchmarkMode mode) => mode switch
|
|
{
|
|
BinaryBenchmarkMode.Default => new AcBinarySerializerOptions(),
|
|
BinaryBenchmarkMode.NoReferenceHandling => AcBinarySerializerOptions.WithoutReferenceHandling(),
|
|
BinaryBenchmarkMode.FastMode => new AcBinarySerializerOptions
|
|
{
|
|
UseMetadata = false,
|
|
UseStringInterning = false,
|
|
UseReferenceHandling = false
|
|
},
|
|
_ => new AcBinarySerializerOptions()
|
|
};
|
|
}
|
|
|
|
[ShortRunJob]
|
|
[MemoryDiagnoser]
|
|
[RankColumn]
|
|
public class AcBinaryOptionsSerializeBenchmark : AcBinaryOptionsBenchmarkBase
|
|
{
|
|
[Benchmark(Description = "MessagePack Serialize", Baseline = true)]
|
|
public byte[] Serialize_MessagePack() => MessagePackSerializer.Serialize(TestOrder, MsgPackOptions);
|
|
|
|
[Benchmark(Description = "AcBinary Serialize")]
|
|
public byte[] Serialize_AcBinary() => AcBinarySerializer.Serialize(TestOrder, BinaryOptions);
|
|
}
|
|
|
|
[ShortRunJob]
|
|
[MemoryDiagnoser]
|
|
[RankColumn]
|
|
public class AcBinaryOptionsDeserializeBenchmark : AcBinaryOptionsBenchmarkBase
|
|
{
|
|
[Benchmark(Description = "MessagePack Deserialize", Baseline = true)]
|
|
public TestOrder? Deserialize_MessagePack() => MessagePackSerializer.Deserialize<TestOrder>(MsgPackData, MsgPackOptions);
|
|
|
|
[Benchmark(Description = "AcBinary Deserialize")]
|
|
public TestOrder? Deserialize_AcBinary() => AcBinaryDeserializer.Deserialize<TestOrder>(AcBinaryData);
|
|
} |