Skip to content

Performance regression looping over large arrays #114047

Open
@richardcocks

Description

@richardcocks

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

Metadata

Metadata

Assignees

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMItenet-performancePerformance related issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions