runtime: Performance regression on Guid.Equals

When it’s equal .NET Core is faster but when not, which happens probably more often, .NET Framework is faster.

BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362
Intel Core i7-4960X CPU 3.60GHz (Haswell), 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=3.0.100-preview7-012593
  [Host] : .NET Core 3.0.0-preview7-27824-03 (CoreCLR 4.700.19.32302, CoreFX 4.700.19.32001), 64bit RyuJIT
  Clr    : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.8.3815.0
  Core   : .NET Core 3.0.0-preview7-27824-03 (CoreCLR 4.700.19.32302, CoreFX 4.700.19.32001), 64bit RyuJIT
Method Job Runtime Mean Error StdDev
NoMatchGuid Clr Clr 1.780 ns 0.0016 ns 0.0012 ns
NoMatchGuid Core Core 2.279 ns 0.0010 ns 0.0008 ns
[ClrJob]
[CoreJob]
[RPlotExporter]
public class GuidTest
{

    static byte[] FixedGUI = new byte[16] { 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x2 };
    static byte[] FixedGUITwo = new byte[16] { 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5 };
    Guid OneGuid = new Guid(FixedGUI);
    Guid TwoGuid = new Guid(FixedGUITwo);

    [Benchmark]
    public bool NoMatchGuid() => OneGuid.Equals(TwoGuid);


}

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 23 (19 by maintainers)

Most upvoted comments

Codegen for Guid.Equals is the same in 2.2 and 3.0 (note this method is normally prejitted; in 3.0 the tiered version is more or less the same as the prejitted one). I don’t see any regression locally.

BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18917
Intel Core i7-4770HQ CPU 2.20GHz (Haswell), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.0.100-preview8-012981
  [Host]     : .NET Core 3.0.0-preview8-27910-02 (CoreCLR 4.700.19.35902, CoreFX 4.700.19.35911), 64bit RyuJIT
  Job-EAXLBN : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.8.3752.0
  Job-FXILZR : .NET Core 2.2.4 (CoreCLR 4.6.27521.02, CoreFX 4.6.27521.01), 64bit RyuJIT
  Job-TTFNJI : .NET Core 3.0.0-preview8-27910-02 (CoreCLR 4.700.19.35902, CoreFX 4.700.19.35911), 64bit RyuJIT


|                   Method | Runtime |     Toolchain |     Mean |     Error |    StdDev | Ratio | RatioSD |
|------------------------- |-------- |-------------- |---------:|----------:|----------:|------:|--------:|
|               EqualsSame |     Clr |        net472 | 7.135 ns | 0.0768 ns | 0.0718 ns |  1.00 |    0.00 |
|               EqualsSame |    Core | netcoreapp2.2 | 3.025 ns | 0.0383 ns | 0.0359 ns |  0.42 |    0.01 |
|               EqualsSame |    Core | netcoreapp3.0 | 2.348 ns | 0.0874 ns | 0.0897 ns |  0.33 |    0.01 |
|                          |         |               |          |           |           |       |         |
|  EqualsLastCharDifferent |     Clr |        net472 | 7.002 ns | 0.1750 ns | 0.2149 ns |  1.00 |    0.00 |
|  EqualsLastCharDifferent |    Core | netcoreapp2.2 | 2.717 ns | 0.0896 ns | 0.1165 ns |  0.39 |    0.01 |
|  EqualsLastCharDifferent |    Core | netcoreapp3.0 | 2.355 ns | 0.0461 ns | 0.0408 ns |  0.34 |    0.02 |
|                          |         |               |          |           |           |       |         |
| EqualsFirstCharDifferent |     Clr |        net472 | 6.956 ns | 0.0514 ns | 0.0456 ns |  1.00 |    0.00 |
| EqualsFirstCharDifferent |    Core | netcoreapp2.2 | 2.430 ns | 0.0886 ns | 0.1213 ns |  0.35 |    0.02 |
| EqualsFirstCharDifferent |    Core | netcoreapp3.0 | 2.764 ns | 0.0282 ns | 0.0264 ns |  0.40 |    0.00 |

So I’m still thinking the measured differences are some kind of artifact in the interaction of the benchmarking with HW.

Suggest we close this and keep an eye on the performance history of dotnet/performance#630, and maybe update that test also try first byte diff cases?

const string diffStr = “a8a110d5-fc49-43c5-bf46-802db8f843fe”; // last char is different

A difference in the last byte of the GUID won’t ever show anything interesting because it results in all Equals code being run and there’s very little chance that the huge .NET FX version will be anything other than slow. The interesting part is when the difference is in the first int of the GUID, that will result into an early out and then both .NET FX and .NET Core should have similar speed.

Method Job Runtime Toolchain Mean Error StdDev
NoMatchGuid Default Core .NET Core 2.2 1.794 ns 0.0702 ns 0.0657 ns
NoMatchGuid Clr Clr Default 1.790 ns 0.0107 ns 0.0100 ns
NoMatchGuid Core Core Default 2.279 ns 0.0008 ns 0.0007 ns