This post was authored by Xy Ziemba, the Program Manager for .NET Native performance, and Andrew Pardoe, Program Manager on the .NET runtime team.
In our previous blog post introducing .NET Native, we talked about how .NET Native gives you the performance of C++ with the productivity of C#. Putting that in quantitative terms, Windows Store apps compiled with .NET Native start up to 60% faster and use up to 25% less reference set compared to when the apps are compiled with NGen. This means your users get into your app even faster after a tile tap!
While developing .NET Native, we made a number of design choices to allow for better optimization and a refactored .NET stack. Let’s go through some of those choices and how they allow Store apps to perform better on .NET Native.
The .NET Native runtime (MRT) is a refactored CLR tuned and optimized for static compilation. It still includes all the core features including type safety and automatic memory management (yes, even with static compilation!) We even moved non-core runtime features into the compilation tool chain and libraries so that you only have the runtime functionality that you use in your app. The end result is that Store apps get a substantial performance boost.
Optimized and Converged Libraries
The framework libraries shipped with .NET Native Preview are also refactored and layered, which allows us to separate out the library code that our program uses from the parts that it doesn’t. Whereas the .NET that ships in Windows includes libraries for many scenarios, a .NET Native app only links against the smaller library contracts that it needs. Removing code that isn’t used for the scenarios .NET Native targets—currently Windows Store apps—improves both app speed and memory footprint.
Unused Code Removal
The .NET Native compiler analyzes your app at multiple stages for all code that can be removed—even parts of library contracts. This gives your app a smaller memory footprint too because every memory page loaded by the operating system has a higher density of useful code.
Whole Program Optimization
After linking your app with both framework library code and library code included with your app package, the Microsoft C++ optimizer does global analysis of your app and optimizes the whole program as a single unit. This means that apps get better inlining of function calls and optimizations performed across the whole program scope. The C++ optimizer writes the app executable to disk with its functions arranged so that Windows can load the program as quickly as possible!
Better and Faster Windows Runtime Interop
In .NET Native, all interop code is generated at compile time and linked into the app itself. This removes the need for the app to read Windows Runtime metadata, create marshaling stubs, and JIT code when making an interop call. Also, the compiler is able to analyze and optimize these stubs at compile time. All this makes calling your favorite Windows API faster!
Similar to what’s done with interop code, .NET Native generates serialization code during compile time, instead of at runtime, when you use a serializer provided by .NET Framework. This shaves off CPU cycles when your app first deserializes an object. This directly translates to faster app startup because most apps deserialize state information at launch.
.NET reflection is a powerful tool but it requires metadata about the types you want to inspect. All the app and framework metadata is kept around in .NET Framework that ships in Windows. In .NET Native, the app developer controls how much metadata is kept in the app. Our compiler keeps the metadata used by your code, but removes most of the metadata for the .NET Framework code. Using Runtime Directives, you can fine-tune our compiler’s choices by specifying what types and members your app reflects on. Our default improves memory density of .NET Native code over Desktop .NET code, but you can push this further by customizing your Runtime Directives. We’ll talk a lot more about these directives in a set up upcoming blog posts.
Try It Out
We really want you to try .NET Native on your apps. The current preview only supports Windows Store apps written in C# and running on x64 or ARM machines, but we’re hard at work adding support for other scenarios.
Download the tools at https://aka.ms/dotnetnative and measure your app’s performance. We would love to hear what kind of performance improvements* you see. Shoot us an email at firstname.lastname@example.org.
*If you don’t see performance improvements, we really want to hear from you. We want to investigate what’s going on and fix it.