65 lines
3.2 KiB
C#
65 lines
3.2 KiB
C#
using AyCode.Core.Serializers.Binaries;
|
|
using AyCode.Core.Tests.TestModels;
|
|
using System.Buffers;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace AyCode.Core.Serializers.Console.Benchmarks;
|
|
|
|
/// <summary>
|
|
/// Benchmarks AcBinary via the IBufferWriter overload, allocating a FRESH ArrayBufferWriter on EVERY call.
|
|
/// One-shot scenario — represents code that doesn't reuse a writer across calls.
|
|
/// Uses BufferWriterChunkSize=4096 (production-realistic, SignalR-aligned) instead of the 65535 default —
|
|
/// otherwise AcBinary would request 64KB upfront via GetSpan(), forcing the fresh ABW to allocate 64KB
|
|
/// regardless of payload size (heavy over-allocation for small payloads).
|
|
/// </summary>
|
|
internal sealed class AcBinaryFreshBufferWriterBenchmark<T> : ISerializerBenchmark where T : class
|
|
{
|
|
private readonly T _order;
|
|
private readonly AcBinarySerializerOptions _options;
|
|
private readonly byte[] _serialized;
|
|
|
|
public BenchmarkEngine Engine => BenchmarkEngine.AcBinary;
|
|
public BenchmarkIoMode IoMode => BenchmarkIoMode.BufWrNew;
|
|
public BenchmarkDispatchMode DispatchMode => _options.UseGeneratedCode ? BenchmarkDispatchMode.SGen : BenchmarkDispatchMode.Runtime;
|
|
public Type OrderType => typeof(T);
|
|
public string OptionsPreset { get; }
|
|
public int SerializedSize => _serialized.Length;
|
|
public long SetupSerializeAllocBytes => 0;
|
|
public long SetupDeserializeAllocBytes => 0;
|
|
public string OptionsDescription => BenchmarkOptions.BuildAcBinary(_options, $", BufferSize={_options.BufferWriterChunkSize}B");
|
|
|
|
public AcBinaryFreshBufferWriterBenchmark(T order, AcBinarySerializerOptions options, string optionsPreset)
|
|
{
|
|
_order = order;
|
|
// BufferWriterChunkSize comes from the caller (central source of truth in CreateSerializers
|
|
// — the binaryFastMode4KbChunk options instance). Do NOT mutate _options here; tune the chunk
|
|
// size in CreateSerializers only.
|
|
_options = options;
|
|
OptionsPreset = optionsPreset;
|
|
_serialized = AcBinarySerializer.Serialize(order, _options);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
public void Serialize()
|
|
{
|
|
var abw = new ArrayBufferWriter<byte>(); // FRESH every call — alloc + grow as needed
|
|
AcBinarySerializer.Serialize(_order, abw, _options);
|
|
}
|
|
|
|
// BufWr semantic: read from a ReadOnlySequence<byte> (the ROS overload), NOT from byte[] —
|
|
// single-segment array-backed sequence triggers the fast-path in AcBinaryDeserializer.cs:298 which
|
|
// redirects to the byte[] overload. This means the bench actually exercises the ROS-input path
|
|
// (the production-realistic surface for SignalR / Pipe consumers) rather than secretly testing
|
|
// byte[] Deser under the BufWr label.
|
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
public void Deserialize() => AcBinaryDeserializer.Deserialize<T>(new ReadOnlySequence<byte>(_serialized), _options);
|
|
|
|
public bool VerifyRoundTrip()
|
|
{
|
|
var abw = new ArrayBufferWriter<byte>();
|
|
AcBinarySerializer.Serialize(_order, abw, _options);
|
|
var roundTripped = AcBinaryDeserializer.Deserialize<T>(new ReadOnlySequence<byte>(abw.WrittenMemory), _options);
|
|
return BenchmarkLoop.DeepEqualsViaJson(_order, roundTripped);
|
|
}
|
|
}
|