YamlDotNet
YamlDotNet copied to clipboard
Avoid closures in CachedTypeInspector
trafficstars
The CachedTypeInspector creates a closure in order to capture the method parameters. This results in 2 allocations per object serialized. I switched to using the ConcurrentDictionary.GetOrAdd() method that takes a third context parameter in order to avoid allocations.
I also added an extension method as described in https://github.com/dotnet/runtime/issues/13978 for runtimes where the overload doesn't exist. I also updated the language version from 8 to 9 in order to get access to static lambdas in order to ensure that the lambdas don't capture.
This reduces allocations by about ~4% in the benchmark:
Before
// * Summary *
BenchmarkDotNet v0.14.0, Windows 11 (10.0.22635.4010)
Intel Core i9-10940X CPU 3.30GHz, 1 CPU, 28 logical and 14 physical cores
.NET SDK 9.0.100-preview.7.24407.12
[Host] : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX-512F+CD+BW+DQ+VL
MediumRun-.NET 8.0 : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX-512F+CD+BW+DQ+VL
MediumRun-.NET Framework 4.7 : .NET Framework 4.8.1 (4.8.9261.0), X64 RyuJIT VectorSize=256
IterationCount=15 LaunchCount=2 WarmupCount=10
| Method | Job | Runtime | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
|----------- |----------------------------- |------------------- |----------:|---------:|---------:|----------:|---------:|---------:|----------:|
| Serializer | MediumRun-.NET 8.0 | .NET 8.0 | 50.25 ms | 1.055 ms | 1.578 ms | 2000.0000 | 500.0000 | - | 24.44 MB |
| Serializer | MediumRun-.NET Framework 4.7 | .NET Framework 4.7 | 118.87 ms | 3.662 ms | 5.367 ms | 7800.0000 | 600.0000 | 200.0000 | 48 MB |
// * Warnings *
MinIterationTime
SerializationBenchmarks.Serializer: MediumRun-.NET 8.0 -> The minimum observed iteration time is 93.442ms which is very small. It's recommended to increase it to at least 100ms using more operations.
After
// * Summary *
BenchmarkDotNet v0.14.0, Windows 11 (10.0.22635.4010)
Intel Core i9-10940X CPU 3.30GHz, 1 CPU, 28 logical and 14 physical cores
.NET SDK 9.0.100-preview.7.24407.12
[Host] : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX-512F+CD+BW+DQ+VL
MediumRun-.NET 8.0 : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX-512F+CD+BW+DQ+VL
MediumRun-.NET Framework 4.7 : .NET Framework 4.8.1 (4.8.9261.0), X64 RyuJIT VectorSize=256
IterationCount=15 LaunchCount=2 WarmupCount=10
| Method | Job | Runtime | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
|----------- |----------------------------- |------------------- |----------:|---------:|---------:|----------:|---------:|----------:|
| Serializer | MediumRun-.NET 8.0 | .NET 8.0 | 49.40 ms | 1.186 ms | 1.701 ms | 2000.0000 | 500.0000 | 23.52 MB |
| Serializer | MediumRun-.NET Framework 4.7 | .NET Framework 4.7 | 115.33 ms | 5.518 ms | 8.259 ms | 7500.0000 | 500.0000 | 47.08 MB |
// * Warnings *
MinIterationTime
SerializationBenchmarks.Serializer: MediumRun-.NET 8.0 -> The minimum observed iteration time is 89.875ms which is very small. It's recommended to increase it to at least 100ms using more operations.