AyCode.Core/BenchmarkSuite1/SerializationBenchmarks.cs

141 lines
5.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}