Files
CBDD/tests/CBDD.Tests.Benchmark/Serialization/SerializationBenchmarks.cs
Joseph Doherty c5def6dbe1
Some checks failed
NuGet Publish / build-and-pack (push) Failing after 33s
NuGet Publish / publish-to-gitea (push) Has been skipped
Cleanup
2026-02-21 08:12:22 -05:00

205 lines
6.4 KiB
C#
Executable File

using System.Collections.Concurrent;
using System.Text.Json;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using ZB.MOM.WW.CBDD.Bson;
using ZB.MOM.WW.CBDD.Bson.IO;
namespace ZB.MOM.WW.CBDD.Tests.Benchmark;
[InProcess]
[MemoryDiagnoser]
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
[HtmlExporter]
[JsonExporterAttribute.Full]
public class SerializationBenchmarks
{
private const int BatchSize = 10000;
private static readonly ConcurrentDictionary<string, ushort> _keyMap = new(StringComparer.OrdinalIgnoreCase);
private static readonly ConcurrentDictionary<ushort, string> _keys = new();
private readonly List<byte[]> _bsonDataList = new();
private readonly List<byte[]> _jsonDataList = new();
private readonly PersonMapper _mapper = new();
private byte[] _bsonData = Array.Empty<byte>();
private byte[] _jsonData = Array.Empty<byte>();
private List<Person> _people = null!;
private Person _person = null!;
private byte[] _serializeBuffer = Array.Empty<byte>();
static SerializationBenchmarks()
{
ushort id = 1;
string[] initialKeys =
{
"_id", "firstname", "lastname", "age", "bio", "createdat", "balance", "homeaddress", "street", "city",
"zipcode", "employmenthistory", "companyname", "title", "durationyears", "tags"
};
foreach (string key in initialKeys)
{
_keyMap[key] = id;
_keys[id] = key;
id++;
}
// Add some indices for arrays
for (var i = 0; i < 100; i++)
{
var s = i.ToString();
_keyMap[s] = id;
_keys[id] = s;
id++;
}
}
/// <summary>
/// Prepares benchmark data for serialization and deserialization scenarios.
/// </summary>
[GlobalSetup]
public void Setup()
{
_person = CreatePerson(0);
_people = new List<Person>(BatchSize);
for (var i = 0; i < BatchSize; i++) _people.Add(CreatePerson(i));
// Pre-allocate buffer for BSON serialization
_serializeBuffer = new byte[8192];
var writer = new BsonSpanWriter(_serializeBuffer, _keyMap);
// Single item data
int len = _mapper.Serialize(_person, writer);
_bsonData = _serializeBuffer.AsSpan(0, len).ToArray();
_jsonData = JsonSerializer.SerializeToUtf8Bytes(_person);
// List data
foreach (var p in _people)
{
len = _mapper.Serialize(p, writer);
_bsonDataList.Add(_serializeBuffer.AsSpan(0, len).ToArray());
_jsonDataList.Add(JsonSerializer.SerializeToUtf8Bytes(p));
}
}
private Person CreatePerson(int i)
{
var p = new Person
{
Id = ObjectId.NewObjectId(),
FirstName = $"First_{i}",
LastName = $"Last_{i}",
Age = 25,
Bio = null,
CreatedAt = DateTime.UtcNow,
Balance = 1000.50m,
HomeAddress = new Address
{
Street = $"{i} Main St",
City = "Tech City",
ZipCode = "12345"
}
};
for (var j = 0; j < 10; j++)
p.EmploymentHistory.Add(new WorkHistory
{
CompanyName = $"TechCorp_{i}_{j}",
Title = "Developer",
DurationYears = j,
Tags = new List<string> { "C#", "BSON", "Performance", "Database", "Complex" }
});
return p;
}
/// <summary>
/// Benchmarks BSON serialization for a single document.
/// </summary>
[Benchmark(Description = "Serialize Single (BSON)")]
[BenchmarkCategory("Single")]
public void Serialize_Bson()
{
var writer = new BsonSpanWriter(_serializeBuffer, _keyMap);
_mapper.Serialize(_person, writer);
}
/// <summary>
/// Benchmarks JSON serialization for a single document.
/// </summary>
[Benchmark(Description = "Serialize Single (JSON)")]
[BenchmarkCategory("Single")]
public void Serialize_Json()
{
JsonSerializer.SerializeToUtf8Bytes(_person);
}
/// <summary>
/// Benchmarks BSON deserialization for a single document.
/// </summary>
[Benchmark(Description = "Deserialize Single (BSON)")]
[BenchmarkCategory("Single")]
public Person Deserialize_Bson()
{
var reader = new BsonSpanReader(_bsonData, _keys);
return _mapper.Deserialize(reader);
}
/// <summary>
/// Benchmarks JSON deserialization for a single document.
/// </summary>
[Benchmark(Description = "Deserialize Single (JSON)")]
[BenchmarkCategory("Single")]
public Person? Deserialize_Json()
{
return JsonSerializer.Deserialize<Person>(_jsonData);
}
/// <summary>
/// Benchmarks BSON serialization for a list of documents.
/// </summary>
[Benchmark(Description = "Serialize List 10k (BSON loop)")]
[BenchmarkCategory("Batch")]
public void Serialize_List_Bson()
{
foreach (var p in _people)
{
var writer = new BsonSpanWriter(_serializeBuffer, _keyMap);
_mapper.Serialize(p, writer);
}
}
/// <summary>
/// Benchmarks JSON serialization for a list of documents.
/// </summary>
[Benchmark(Description = "Serialize List 10k (JSON loop)")]
[BenchmarkCategory("Batch")]
public void Serialize_List_Json()
{
foreach (var p in _people) JsonSerializer.SerializeToUtf8Bytes(p);
}
/// <summary>
/// Benchmarks BSON deserialization for a list of documents.
/// </summary>
[Benchmark(Description = "Deserialize List 10k (BSON loop)")]
[BenchmarkCategory("Batch")]
public void Deserialize_List_Bson()
{
foreach (byte[] data in _bsonDataList)
{
var reader = new BsonSpanReader(data, _keys);
_mapper.Deserialize(reader);
}
}
/// <summary>
/// Benchmarks JSON deserialization for a list of documents.
/// </summary>
[Benchmark(Description = "Deserialize List 10k (JSON loop)")]
[BenchmarkCategory("Batch")]
public void Deserialize_List_Json()
{
foreach (byte[] data in _jsonDataList) JsonSerializer.Deserialize<Person>(data);
}
}