runtime: .Net 7 performance regression with struct fields
Description
I noticed a ~5-15% performance regression when benchmarking my library ProtoPromise in .Net 6 vs .Net 7. I wasn’t sure what the cause could be, so I tried making a simplified benchmark.
public class PromiseBenchmarks
{
private Promise.Deferred deferred;
[Benchmark]
public void PromiseVoid()
{
deferred = Promise.NewDeferred();
deferred.Promise.Forget();
deferred.Resolve();
deferred = default;
}
}
Then I realized I didn’t need the field and used a local instead.
public class PromiseBenchmarks
{
private Promise.Deferred deferred;
[Benchmark]
public void PromiseField()
{
deferred = Promise.NewDeferred();
deferred.Promise.Forget();
deferred.Resolve();
deferred = default;
}
[Benchmark]
public void PromiseLocal()
{
var deferred = Promise.NewDeferred();
deferred.Promise.Forget();
deferred.Resolve();
}
}
And that yielded these surprising results
| Method | Runtime | Mean | Error | StdDev | Ratio | Code Size |
|---|---|---|---|---|---|---|
| PromiseField | .NET 6.0 | 93.05 ns | 1.227 ns | 1.148 ns | 1.00 | 448 B |
| PromiseField | .NET 7.0 | 100.94 ns | 2.033 ns | 2.342 ns | 1.08 | 425 B |
| PromiseLocal | .NET 6.0 | 97.22 ns | 1.916 ns | 1.792 ns | 1.00 | 438 B |
| PromiseLocal | .NET 7.0 | 92.66 ns | 1.617 ns | 1.513 ns | 0.95 | 361 B |
Clearly .Net 7 is generating better code for the actual work, but there’s something weird with using the field rather than local. The Promise.Deferred struct is simply this:
public struct Deferred
{
internal readonly Internal.PromiseRefBase.DeferredPromise<Internal.VoidResult> _ref; // class reference.
internal readonly short _promiseId;
internal readonly int _deferredId;
}
Configuration
I ran this benchmark with BenchmarkDotNet arguments --runtimes net6.0 net7.0 --disasm --disasmDepth 10000
OS is Windows 10 x64 CPU is AMD Phenom II X6 1055T
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 1
- Comments: 16 (10 by maintainers)
Results with 8.0 preview 5
It looks like performance is much better in .Net 8, but still weirdly slower in .Net 7 with the field. I expect it’s CPU related. Maybe it’s not even worth looking into though since it’s apparently already solved in 8.
@En3Tho Nice. I never upgraded to bulldozer since I heard it was worse than Phenom in some cases, and then just kinda stuck with it. But this thing is really starting to show its age!
@timcassell Kinda offtopic but cheers for Phenom 😄 Had x4 955 and then 8320 FX that somehow happened to be an overcloking beast (5.2ghz @ 1.55v and crazy 2800 nb freq)