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;
///
/// Minimal benchmark to test if BenchmarkDotNet works without stack overflow.
///
[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;
}
///
/// Binary vs JSON benchmark with simple flat objects (no circular references).
///
[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(_binaryData);
[Benchmark(Description = "JSON Deserialize")]
public PrimitiveTestClass? DeserializeJson() => AcJsonDeserializer.Deserialize(_jsonData, AcJsonSerializerOptions.WithoutReferenceHandling());
}
///
/// Complex hierarchy benchmark - AcBinary vs JSON only (no MessagePack to isolate the issue).
/// Uses AcBinary without reference handling.
///
[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(_acBinaryData);
[Benchmark(Description = "JSON Deserialize")]
public TestOrder? Deserialize_Json() => AcJsonDeserializer.Deserialize(_jsonData, _jsonOptions);
}
///
/// Full comparison with MessagePack and BSON - AcBinary uses NO reference handling everywhere.
///
[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();
}
// 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();
}
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(_acBinaryData);
[Benchmark(Description = "MessagePack Deserialize")]
public TestOrder? Deserialize_MsgPack() => MessagePackSerializer.Deserialize(_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(reader);
}
}
///
/// Comprehensive AcBinary vs MessagePack comparison benchmark.
/// Tests: NoRef (everywhere), Populate, Serialize, Deserialize, Size
///
[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 - WithRef uses Default (which has reference handling), NoRef explicitly disables it
_withRefOptions = AcBinarySerializerOptions.Default;
_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();
}
// 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)");
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 WithRef")]
public byte[] Serialize_AcBinary_WithRef() => AcBinarySerializer.Serialize(_testOrder, _withRefOptions);
[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 WithRef")]
public TestOrder? Deserialize_AcBinary_WithRef() => AcBinaryDeserializer.Deserialize(_acBinaryWithRef);
[Benchmark(Description = "AcBinary Deserialize NoRef")]
public TestOrder? Deserialize_AcBinary_NoRef() => AcBinaryDeserializer.Deserialize(_acBinaryNoRef);
[Benchmark(Description = "MessagePack Deserialize")]
public TestOrder? Deserialize_MsgPack() => MessagePackSerializer.Deserialize(_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(reader);
}
#endregion
#region Populate Benchmarks
[Benchmark(Description = "AcBinary Populate WithRef")]
public void Populate_AcBinary_WithRef()
{
var target = CreatePopulateTarget();
AcBinaryDeserializer.Populate(_acBinaryWithRef, target);
}
[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 WithRef")]
public void PopulateMerge_AcBinary_WithRef()
{
var target = CreatePopulateTarget();
AcBinaryDeserializer.PopulateMerge(_acBinaryWithRef.AsSpan(), 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
}
///
/// Detailed size comparison - not a performance benchmark, just size output.
/// Now includes BSON size output and uses AcBinary without reference handling.
///
[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(); }
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(MsgPackData, MsgPackOptions);
[Benchmark(Description = "AcBinary Deserialize")]
public TestOrder? Deserialize_AcBinary() => AcBinaryDeserializer.Deserialize(AcBinaryData);
}
///
/// Large-scale benchmark simulating production workloads.
/// Tests with ~50,000+ IId objects with deep hierarchy and shared references.
/// This is closer to real-world scenarios with 2200 root items and 4-5MB binary data.
///
[ShortRunJob]
[MemoryDiagnoser]
[RankColumn]
public class LargeScaleBinaryBenchmark
{
// Test data - smaller scale for benchmark (500 items ? 25K objects)
// Production would be 2200 items ? 100K+ objects
private TestOrder _testOrder = null!;
private TestOrder _populateTarget = null!;
// Serialized data
private byte[] _acBinaryData = null!;
private byte[] _msgPackData = null!;
// Options
private AcBinarySerializerOptions _binaryOptions = null!;
private MessagePackSerializerOptions _msgPackOptions = null!;
private int _objectCount;
[GlobalSetup]
public void Setup()
{
Console.WriteLine("Creating large-scale test data...");
// Use 500 root items for benchmark (?25K objects)
// Production would use 2200 (?100K+ objects)
const int rootItems = 500;
const int pallets = 3;
const int measurements = 3;
const int points = 4;
_objectCount = TestDataFactory.CalculateObjectCount(rootItems, pallets, measurements, points);
Console.WriteLine($"Creating ~{_objectCount:N0} IId objects...");
_testOrder = TestDataFactory.CreateLargeScaleBenchmarkOrder(rootItems, pallets, measurements, points);
Console.WriteLine($"Created order with {_testOrder.Items.Count} root items");
_binaryOptions = AcBinarySerializerOptions.WithoutReferenceHandling();
_msgPackOptions = ContractlessStandardResolver.Options.WithCompression(MessagePackCompression.None);
Console.WriteLine("Serializing AcBinary...");
_acBinaryData = AcBinarySerializer.Serialize(_testOrder, _binaryOptions);
Console.WriteLine("Serializing MessagePack...");
_msgPackData = MessagePackSerializer.Serialize(_testOrder, _msgPackOptions);
// Create populate target
_populateTarget = new TestOrder { Id = _testOrder.Id };
foreach (var item in _testOrder.Items.Take(10)) // Only first 10 for populate target
{
_populateTarget.Items.Add(new TestOrderItem { Id = item.Id });
}
PrintStats();
}
private void PrintStats()
{
Console.WriteLine("\n" + new string('=', 70));
Console.WriteLine("?? LARGE-SCALE BENCHMARK STATS");
Console.WriteLine(new string('=', 70));
Console.WriteLine($" Root Items: {_testOrder.Items.Count:N0}");
Console.WriteLine($" Total Objects: ~{_objectCount:N0} IId objects");
Console.WriteLine($" AcBinary Size: {_acBinaryData.Length:N0} bytes ({_acBinaryData.Length / 1024.0 / 1024.0:F2} MB)");
Console.WriteLine($" MsgPack Size: {_msgPackData.Length:N0} bytes ({_msgPackData.Length / 1024.0 / 1024.0:F2} MB)");
Console.WriteLine($" Size Ratio: {100.0 * _acBinaryData.Length / _msgPackData.Length:F1}% of MsgPack");
Console.WriteLine(new string('=', 70) + "\n");
}
[Benchmark(Description = "LargeScale AcBinary Deserialize")]
public TestOrder? Deserialize_AcBinary() => AcBinaryDeserializer.Deserialize(_acBinaryData);
[Benchmark(Description = "LargeScale MsgPack Deserialize", Baseline = true)]
public TestOrder? Deserialize_MsgPack() => MessagePackSerializer.Deserialize(_msgPackData, _msgPackOptions);
[Benchmark(Description = "LargeScale AcBinary Serialize")]
public byte[] Serialize_AcBinary() => AcBinarySerializer.Serialize(_testOrder, _binaryOptions);
[Benchmark(Description = "LargeScale MsgPack Serialize")]
public byte[] Serialize_MsgPack() => MessagePackSerializer.Serialize(_testOrder, _msgPackOptions);
}
///
/// AcJson vs System.Text.Json comparison - measures Newtonsoft.Json based AcJson against modern STJ.
/// Uses simple flat object (PrimitiveTestClass) to avoid circular reference issues.
///
[ShortRunJob]
[MemoryDiagnoser]
[RankColumn]
public class AcJsonVsSystemTextJsonBenchmark
{
private PrimitiveTestClass _testData = null!;
private string _acJsonData = null!;
private string _stjData = null!;
private AcJsonSerializerOptions _acJsonOptions = null!;
private JsonSerializerOptions _stjOptions = null!;
[GlobalSetup]
public void Setup()
{
Console.WriteLine("Creating test data for AcJson vs System.Text.Json...");
// Use simple flat object to avoid circular reference issues
_testData = TestDataFactory.CreatePrimitiveTestData();
// Setup options
_acJsonOptions = AcJsonSerializerOptions.WithoutReferenceHandling();
_stjOptions = new JsonSerializerOptions
{
WriteIndented = false,
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
ReferenceHandler = null // No reference handling
};
// Pre-serialize
_acJsonData = AcJsonSerializer.Serialize(_testData, _acJsonOptions);
_stjData = JsonSerializer.Serialize(_testData, _stjOptions);
Console.WriteLine($"AcJson size: {_acJsonData.Length:N0} chars");
Console.WriteLine($"STJ size: {_stjData.Length:N0} chars");
Console.WriteLine($"Size ratio: {100.0 * _acJsonData.Length / _stjData.Length:F1}%");
}
[Benchmark(Description = "AcJson Serialize", Baseline = true)]
public string Serialize_AcJson() =>
AcJsonSerializer.Serialize(_testData, _acJsonOptions);
[Benchmark(Description = "System.Text.Json Serialize")]
public string Serialize_STJ() =>
JsonSerializer.Serialize(_testData, _stjOptions);
[Benchmark(Description = "AcJson Deserialize")]
public PrimitiveTestClass? Deserialize_AcJson() =>
AcJsonDeserializer.Deserialize(_acJsonData, _acJsonOptions);
[Benchmark(Description = "System.Text.Json Deserialize")]
public PrimitiveTestClass? Deserialize_STJ() =>
JsonSerializer.Deserialize(_stjData, _stjOptions);
}