.NET faster? Monster Post by Microsoft Software Engineer Shows Significant Registry Improvements



The next .NET 6 will be significantly faster than its predecessors, according to a monstrous article by Stephen Toub, Microsoft’s partner software engineer.

Toub’s 45,000 word message follows similar versions for earlier versions since .NET Core 2.0 and is based on an analysis of all merged pull requests (PRs – code changes) that could affect performance.

About 400 PRs are covered, out of 550 applicants, compared to 250 for .NET 5. These posts are always worth studying for .NET developers because they include performance tips as well as a deep dive into the inner workings of the. Microsoft’s cross-platform runtime. .

There is no single answer to the question “how much faster is .NET 6.0?” (And there may be cases where it is slower). What Toub provides is a benchmark code that compares both the performance and size of code generated from .NET 6.0, currently in late preview, with .NET Framework 4.8 (the final version of old-style Windows only .NET) and .NET 5.0 (the current version).

The .NET 6.0 runtime is especially important because it is a long-term support release. Looking at the references Toub publishes for each case, the results vary although around 25% is common.

In this example, .NET 6.0 is about 25% faster than older versions, but generates slightly larger code

Significant acceleration in .NET 6.0. In this example, .NET 6.0 is about 25% faster than older versions, but generates slightly larger code

In some cases, .NET 6.0 cuts the time to next to nothing. An example is the new Environment.ProcessPath API to get the current process path, which is 72,000 times faster and does not generate any code, compared to the previous approach using Process.GetCurrentProcess (). MainModule.FileName. Likewise, there is a fun case where the new optimizer notices that a function in code always has the same inputs, which are defined as constants, and is therefore able to replace the entire function with a constant, reducing both the time taken and the size to almost zero.

The latter case uses a technique called Dynamic Profile Guided Optimization (PGO) which is new in .NET 6.0. The idea is that the compiler performs a first compilation with instrumentation and then uses the results to optimize a second compilation.

Note that Toub said: “In .NET 6, dynamic PGO is disabled by default. To enable it, you need to set the DOTNET_TieredPGO environment variable. “

Toub also stated that the Filestream code, used to read and write files, has been rewritten in .NET 6.0. “FileStream has also been plagued over the years with a number of performance-related issues, most of which are part of its asynchronous I / O implementation on Windows,” he said, claiming that in the new version “all these problems are solved”.

Another change is that more than 2,300 “internal and private” classes in .NET 6.0 code have recently been marked sealed. A sealed class cannot be inherited, which means that the compiler can infer that a virtual method (which, if inherited, can be replaced by a different code) is in fact not replaced and that it therefore, it is not necessary to search for this different code.

In a network, data sent via Websockets can now be compressed by message. This is a tradeoff because the compression takes longer to process, but the smaller message is faster to transmit. “It could be a good compromise if you are communicating over a real network with longer latencies,” said Toub.

A recent framework called Blazor means that .NET code can run in a web browser as a WebAssembly. Microsoft has put a lot of effort into optimizing this for .NET 6.0.

With Blazor, “an entire .NET application, including the runtime, is downloaded and executed in a browser,” Toub explained. The size of a Hello World Blazor application in .NET 5.0 is approximately 2.10MB. In .NET 6.0, this drops to 1.88MB, for reasons he detailed in the post. Using additional tools based on Emscripten, the size drops to 1.82MB.

At this point, Toub adds a handy hint: There is a ton of code in .NET’s globalization routines to format output for different languages ​​and cultures. If not needed, developers can set a switch that further reduces the size, to just 1.07MB. Unfortunately, this is for Hello World and an actual Blazor app will likely be much larger, but it is always an impressive result.

Toub also noted that the Blazor runtime is based on Mono. “There are actually two runtime implementations in dotnet / runtime: coreclr and mono … Blazor WebAssembly relies on mono, which has been refined over the years to be small and nimble for these kinds of scenarios, and has also received a lot of investment performance in .NET 6. “

Other performance techniques include smarter code embedding (copying code where it is called), optimization of value types such as structures, loop alignment which moves compiled code so that the processor can retrieve it more efficiently, and better performance for code that checks if a type implements an interface and a new faster algorithm implementation for pseudorandom numbers (although the old algorithm is used for reasons compatibility if a seed is provided).

Awesome, but why isn’t there a native code compiler for .NET that can compile single file executables? The answer can be found in this article on .NET runtime form factors in which the .NET team explained:

Instead, Microsoft chose to make smaller improvements to the .NET Runtime so that all .NET code benefits – although there is still a NativeAOT experimental project for those who find the compromise worth pursuing. ®



Comments are closed.