141 lines
5.0 KiB
C#
141 lines
5.0 KiB
C#
using AyCode.Core.Extensions;
|
||
using AyCode.Core.Tests.TestModels;
|
||
using BenchmarkDotNet.Attributes;
|
||
using Newtonsoft.Json;
|
||
using System.Text;
|
||
|
||
namespace AyCode.Core.Benchmarks;
|
||
|
||
/// <summary>
|
||
/// Serialization benchmarks comparing AcJsonSerializer/Deserializer with Newtonsoft.Json.
|
||
/// Uses shared TestModels from AyCode.Core.Tests for consistency.
|
||
/// </summary>
|
||
[MemoryDiagnoser]
|
||
public class SerializationBenchmarks
|
||
{
|
||
// Test data - uses shared TestModels
|
||
private TestOrder _testOrder = null!;
|
||
|
||
// Pre-serialized JSON for deserialization benchmarks
|
||
private string _newtonsoftJson = null!;
|
||
private string _ayCodeJson = null!;
|
||
|
||
// Target objects for Populate benchmarks
|
||
private TestOrder _populateTarget = null!;
|
||
|
||
// Settings
|
||
private JsonSerializerSettings _newtonsoftNoRefSettings = null!;
|
||
private JsonSerializerSettings _ayCodeSettings = null!;
|
||
|
||
[GlobalSetup]
|
||
public void Setup()
|
||
{
|
||
// Newtonsoft WITHOUT reference handling (baseline)
|
||
_newtonsoftNoRefSettings = new JsonSerializerSettings
|
||
{
|
||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
||
NullValueHandling = NullValueHandling.Ignore,
|
||
DefaultValueHandling = DefaultValueHandling.Ignore,
|
||
Formatting = Formatting.None
|
||
};
|
||
|
||
// AyCode WITH reference handling
|
||
_ayCodeSettings = SerializeObjectExtensions.Options;
|
||
|
||
// Create benchmark data using shared factory
|
||
// ~1500 objects: 5 items × 4 pallets × 3 measurements × 5 points = 300 points + containers
|
||
_testOrder = TestDataFactory.CreateBenchmarkOrder(
|
||
itemCount: 5,
|
||
palletsPerItem: 4,
|
||
measurementsPerPallet: 3,
|
||
pointsPerMeasurement: 5);
|
||
|
||
// Pre-serialize for deserialization benchmarks
|
||
_newtonsoftJson = JsonConvert.SerializeObject(_testOrder, _newtonsoftNoRefSettings);
|
||
_ayCodeJson = _testOrder.ToJson(_ayCodeSettings);
|
||
|
||
// Create target for populate benchmarks
|
||
_populateTarget = new TestOrder();
|
||
|
||
// Output sizes for comparison
|
||
var newtonsoftBytes = Encoding.UTF8.GetByteCount(_newtonsoftJson);
|
||
var ayCodeBytes = Encoding.UTF8.GetByteCount(_ayCodeJson);
|
||
|
||
Console.WriteLine("=== JSON Size Comparison ===");
|
||
Console.WriteLine($"Newtonsoft (skip defaults): {_newtonsoftJson.Length:N0} chars ({newtonsoftBytes:N0} bytes)");
|
||
Console.WriteLine($"AyCode (refs+skip): {_ayCodeJson.Length:N0} chars ({ayCodeBytes:N0} bytes)");
|
||
Console.WriteLine($"Size reduction: {(1.0 - (double)ayCodeBytes / newtonsoftBytes) * 100:F1}%");
|
||
}
|
||
|
||
#region Serialization Benchmarks
|
||
|
||
[Benchmark(Description = "Newtonsoft (no refs)")]
|
||
[BenchmarkCategory("Serialize")]
|
||
public string Serialize_Newtonsoft_NoRefs()
|
||
=> JsonConvert.SerializeObject(_testOrder, _newtonsoftNoRefSettings);
|
||
|
||
[Benchmark(Description = "AyCode (with refs)")]
|
||
[BenchmarkCategory("Serialize")]
|
||
public string Serialize_AyCode_WithRefs()
|
||
=> _testOrder.ToJson(_ayCodeSettings);
|
||
|
||
[Benchmark(Description = "AcJsonSerializer (custom)")]
|
||
[BenchmarkCategory("Serialize")]
|
||
public string Serialize_AcJsonSerializer()
|
||
=> AcJsonSerializer.Serialize(_testOrder);
|
||
|
||
#endregion
|
||
|
||
#region Deserialization Benchmarks
|
||
|
||
[Benchmark(Description = "Newtonsoft (no refs)")]
|
||
[BenchmarkCategory("Deserialize")]
|
||
public TestOrder? Deserialize_Newtonsoft_NoRefs()
|
||
=> JsonConvert.DeserializeObject<TestOrder>(_newtonsoftJson, _newtonsoftNoRefSettings);
|
||
|
||
[Benchmark(Description = "AyCode (with refs)")]
|
||
[BenchmarkCategory("Deserialize")]
|
||
public TestOrder? Deserialize_AyCode_WithRefs()
|
||
=> _ayCodeJson.JsonTo<TestOrder>(_ayCodeSettings);
|
||
|
||
[Benchmark(Description = "AcJsonDeserializer (custom)")]
|
||
[BenchmarkCategory("Deserialize")]
|
||
public TestOrder? Deserialize_AcJsonDeserializer()
|
||
=> AcJsonDeserializer.Deserialize<TestOrder>(_ayCodeJson);
|
||
|
||
#endregion
|
||
|
||
#region Populate Benchmarks
|
||
|
||
[Benchmark(Description = "AcJsonDeserializer.Populate")]
|
||
[BenchmarkCategory("Populate")]
|
||
public void Populate_AcJsonDeserializer()
|
||
{
|
||
// Create fresh target for each iteration to avoid state pollution
|
||
var target = new TestOrder();
|
||
AcJsonDeserializer.Populate(_ayCodeJson, target);
|
||
}
|
||
|
||
[Benchmark(Description = "Newtonsoft PopulateObject")]
|
||
[BenchmarkCategory("Populate")]
|
||
public void Populate_Newtonsoft()
|
||
{
|
||
// Create fresh target for each iteration to match the other benchmark
|
||
var target = new TestOrder();
|
||
JsonConvert.PopulateObject(_newtonsoftJson, target, _newtonsoftNoRefSettings);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region JSON Size Comparison
|
||
|
||
[Benchmark(Description = "JSON Size - Newtonsoft")]
|
||
[BenchmarkCategory("Size")]
|
||
public int JsonSize_Newtonsoft() => _newtonsoftJson.Length;
|
||
|
||
[Benchmark(Description = "JSON Size - AyCode")]
|
||
[BenchmarkCategory("Size")]
|
||
public int JsonSize_AyCode() => _ayCodeJson.Length;
|
||
|
||
#endregion
|
||
} |