Description
Description
While performing a comparison of memcmp
, ReadOnlySpan<T>SequenceEqual
and a naive for
loop, I noticed a weird performance regression between .NET 8 and .NET 9 / 10.
The naive for loop of course supposed to be efficient, but it slowed down dramatically between .NET 8 and .NET 9.
It's possible that this is a benchmark.NET issue not a dotnet runtime issue, but I'm not sure how to diagnose whether that is the case. I'd be happy to receive instruction to verify that.
BenchmarkDotNet v0.14.1-develop (2025-03-30), Windows 10 (10.0.19045.5679/22H2/2022Update)
AMD Ryzen 7 3800X 3.90GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK 10.0.100-preview.2.25164.34
[Host] : .NET 10.0.0 (10.0.25.16302), X64 RyuJIT AVX2
.NET 10.0 : .NET 10.0.0 (10.0.25.16302), X64 RyuJIT AVX2
.NET 6.0 : .NET 6.0.36 (6.0.3624.51421), X64 RyuJIT AVX2
.NET 7.0 : .NET 7.0.20 (7.0.2024.26716), X64 RyuJIT AVX2
.NET 8.0 : .NET 8.0.14 (8.0.1425.11118), X64 RyuJIT AVX2
.NET 9.0 : .NET 9.0.3 (9.0.325.11113), X64 RyuJIT AVX2
Method | Job | Runtime | Length | Mean | Error | StdDev | Ratio | RatioSD | Allocated | Alloc Ratio |
---|---|---|---|---|---|---|---|---|---|---|
Loop | .NET 6.0 | .NET 6.0 | 1073741824 | 273.5 ms | 5.30 ms | 5.21 ms | 0.98 | 0.02 | 1648 B | 8.24 |
Loop | .NET 7.0 | .NET 7.0 | 1073741824 | 523.3 ms | 10.18 ms | 9.52 ms | 1.87 | 0.04 | 600 B | 3.00 |
Loop | .NET 8.0 | .NET 8.0 | 1073741824 | 279.3 ms | 4.65 ms | 3.88 ms | 1.00 | 0.02 | 200 B | 1.00 |
Loop | .NET 9.0 | .NET 9.0 | 1073741824 | 524.4 ms | 5.10 ms | 4.52 ms | 1.88 | 0.03 | 400 B | 2.00 |
Loop | .NET 10.0 | .NET 10.0 | 1073741824 | 537.7 ms | 9.20 ms | 8.16 ms | 1.93 | 0.04 | 400 B | 2.00 |
The results are strange to say the least. Allocations are least in .NET 8.0 by a factor of 2, but runtime is minimised in both .NET 6 (despite more memory allocation) and .NET 8.
Source code to generate this is at https://github.com/richardcocks/dotnet8_9_10_regression.
The jist of it is:
[Benchmark]
public void Loop()
{
EqualsLoop(first, second);
}
public static bool EqualsLoop(byte[] b1, byte[] b2)
{
if (b1.Length != b2.Length) return false;
for (int i = 0; i < b1.Length; i++)
{
if (b1[i] != b2[i]) return false;
}
return true;
}
Running command: dotnet run -c:Release -f net10.0