Skip to content

33% performance degradation in .NET 5 #44457

@koszeggy

Description

@koszeggy

Description

Note: I don't know whether the root cause of my issue is related with #36907 so I report an easily reproducible scenario here.

I have a high performance core library, which has some multidimensional span-like types such as Array2D and Array3D structs, which are affected by the performance degradation: accessing elements of these types are faster on .NET Core 3 than accessing elements of a regular multidimensional array but not when executing on .NET 5.

Reproduction:

  • Fork or download this repository
  • The library targets a bunch of target frameworks. To observe the degradation it is enough to target .NET Core 3.x and .NET 5.0 only.
  • From the KGySoft.CoreLibraries.PerformanceTest project execute the Array2DPerformanceTest.AccessTest against both .NET Core 3 and .NET 5
  • Observe the results in the console output

Online living version: I created also an online example. As per 11/10/2020 this executes the performance test on .NET Core 3.1 (this is a somewhat shortened test in order not to timeout). Targeting .NET 5 is not possible on .NET Fiddle yet.

Configuration

  • dotnet --version: 5.0.100-rc.2.20479.15
  • Windows 10 [Version 10.0.19042.572] 64 bit version

Regression?

The regression can be observed between .NET Core 3.0/3.1 and .NET 5.0

Data

  • .NET Core 3.0 results on my machine:
==[AccessTest (.NET Core 3.0.0) Results]================================================
Iterations: 10,000
Warming up: Yes
Test cases: 3
Repeats: 5
Calling GC.Collect: Yes
Forced CPU Affinity: 2
Cases are sorted by time (quickest first)
--------------------------------------------------
1. int[y][x] = value: average time: 389.46 ms
  #1         389.59 ms
  #2         389.14 ms
  #3         388.61 ms	 <---- Best
  #4         389.39 ms
  #5         390.58 ms	 <---- Worst
  Worst-Best difference: 1,98 ms (0,51%)
2. Array2D<int>[y, x] = value: average time: 642.20 ms (+252.74 ms / 164.89%)
  #1         641.34 ms
  #2         642.98 ms
  #3         642.63 ms
  #4         643.43 ms	 <---- Worst
  #5         640.61 ms	 <---- Best
  Worst-Best difference: 2.83 ms (0.44%)
3. int[y, x] = value: average time: 701.46 ms (+312.00 ms / 180.11%)
  #1         702.69 ms
  #2         704.56 ms	 <---- Worst
  #3         700.29 ms
  #4         701.06 ms
  #5         698.72 ms	 <---- Best
  Worst-Best difference: 5.84 ms (0.84%)
  • .NET 5.0 RC2 results on my machine:
    The Array2D case has a 33% performance degradation (860 ms vs. 642 ms) while the regular 2D array and jagged array performance did not change essentially.
==[AccessTest (.NET Core 5.0.0-rc.2.20475.5) Results]================================================
Iterations: 10,000
Warming up: Yes
Test cases: 3
Repeats: 5
Calling GC.Collect: Yes
Forced CPU Affinity: 2
Cases are sorted by time (quickest first)
--------------------------------------------------
1. int[y][x] = value: average time: 395.04 ms
  #1         395.01 ms
  #2         393.34 ms	 <---- Best
  #3         397.91 ms	 <---- Worst
  #4         394.28 ms
  #5         394.68 ms
  Worst-Best difference: 4.57 ms (1.16%)
2. int[y, x] = value: average time: 704.27 ms (+309.23 ms / 178.28%)
  #1         702.28 ms
  #2         702.97 ms
  #3         703.96 ms
  #4         700.14 ms	 <---- Best
  #5         712.02 ms	 <---- Worst
  Worst-Best difference: 11.89 ms (1.70%)
3. Array2D<int>[y, x] = value: average time: 860.47 ms (+465.42 ms / 217.82%)
  #1         848.51 ms	 <---- Best
  #2         870.71 ms	 <---- Worst
  #3         853.88 ms
  #4         866.94 ms
  #5         862.30 ms
  Worst-Best difference: 22.20 ms (2.62%)
  • .NET Core 3.1 online results (.NET Fiddle): https://dotnetfiddle.net/02BdPF
    Note: This test is reduced (both in time and cases) in order not to timeout .NET Fiddle. As it is not possible to run .NET 5 codes online yet it is only good for demonstrating that Array2D access is faster than regular 2D array access.

Analysis

I'm not sure whether I could identify the hot-spot correctly but since Array2D uses ArraySection internally, and I could not observe any significant performance degradation in ArraySection performance test (feel free to set Repeat = 5 to get more reliable results just like above) I suspect that the issue lies in accessing the wrapped ArraySection struct inside the Array2D struct here. However, I could not find any suspicious in the IL code, and I could not check the JITted machine code of the .NET 5 version.

Metadata

Metadata

Assignees

Type

No type

Projects

Status

Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions