.NET 6 vs .NET 5: up to 40% speedup!

A year ago I wrote a post comparing .NET 5 performance with its predecessor on Fusion performance tests, and honestly, I was quite impressed by the performance improvements in .NET 5. This year is no different: .NET 6 is truly the fastest .NET yet.

First, let’s look at the same test I ran last year at first:

.NET 5 output is on the left side, .NET 6 is on the right side

It’s Fusion’s “Caching” sample, which uses EF Core and ASP.NET Core. You can run it by cloning https://github.com/servicetitan/Stl.Fusion.Samples and starting or

Besides that, all .NET 6.0 tests mentioned here were run with PGO enabled:

A brief description of what above tests do:

  • Tests producing 20M+ operations/s (#1, #3) are mainly constrained by Fusion’s logic, Castle.DynamicProxy, and overall, it’s ~ mostly a cache key computation and lookup logic. Almost every iteration ends up with a cache hit there.
  • Tests producing <1M operations/s are constrained by either EF & SQL Server (#2, #5) or ASP.NET Core (#4 — it’s ~ the same as #5, but relying on Fusion’s caching features).

So what do we see here:

  • Caching / tight loop tests get up to 30% speedup
  • Test #4, which basically adds Fusion cache to a regular web API, gets 15% speedup with .NET 6
  • “Typical” HTTP pipeline test (HttpClient hitting ASP.NET Core controller that hosts a CRUD style EF Core service) gets ~ 4.5% speedup.

And interestingly, the same pattern is easy to see on performance test in Fusion test suite:

Spreadsheet w/ more data: https://docs.google.com/spreadsheets/d/1-zs6JMtsgQ3mll4whSDKl2T7l38ob4cW9trZNpEWaz4/edit?usp=sharing

You can run it by cloning https://github.com/servicetitan/Stl.Fusion and typing:

Top test set is exactly the same as the bottom one, the only difference is that it relies on Fusion’s compute service instead of a regular one, i.e. it heavily benefits of Fusion’s transparent caching logic.

So in terms of what happens under the hood,

  • Top tests mostly compute cache keys, hash them, acquire async locks, and run lookups
  • Bottom tests actually run SQL commands — mostly -s fetching a single row.

And it’s clear that PGO in .NET 6 shines in the first case, so in-process caching definitely brings more advantages with .NET 6.

As for the second category of tests, even ~ 5% speedup is quite impressive for a code which speed is mostly constrained by external service (PostgreSQL or SQL Server). And benchmarks with InMemory EF Core provider (which is also a .NET library) prove this by showing ~ 14–15% speedup.

The gist is: .NET 6 with PGO enabled may bring you:

  • +30–40% speed on tight loops & cache-friendly logic
  • +15% for an average code that doesn’t depend on networking & IO
  • +5% for a typical web service that mostly depends on networking & IO.

I plan to share a similar comparison w/ GCBurn (my garbage collection & allocation performance test) and the code I used to compare SIMD-accelerated logic on C# & C++. But again, it’s absolutely clear that .NET 6 is truly the fastest .NET yet, so huge thanks to everyone who made this possible!

P.S. My 3-month-old stealth startup is hiring a full-stack developer. If you know .NET really well and eager to use a cutting-edge real-time tech stack (Blazor, Fusion) to redefine the meaning of one of our daily activities, please PM me :)