A first hand look from the .NET engineering teams
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.
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.
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.
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!
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.
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 http://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 email@example.com.
*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.
Very interesting! Though It would have been nicer if guys you had some benchmarks to go along with this post.
I'm confused about .NET Native
Does the app run faster? If an app is doing some computation will it be faster in general? Startup time/memory that's cool but does it effect other performance?
This is a great move from you and it sounds great!! Are you planing to do the same with the rest of the application types?
Apps are ok, but at least my customers all want/prefer the "normal" desktop applications. My customers have got exactly the same problems that you are solving for the apps: slow loading times, memory needs, "wait" times when loading new big assemblies that need to be JITed, ...
They already laugh at me when I try to "sell" them that this is the advantage of .NET software. You know, all this mantra about JIT using dynamic information for doing better optimizations and target the right CPU architecture.
It would be great if we could use .NET Native for desktop and server applications.
@David Hewson: I think, from the moment that no JIT will be around, we expect to see better runtime performance. I mean, there will be no time lost to code generation at runtime, so, code running will be faster.
However, it would be very nice for .net team to clarify this.
@gawicks: We've been focusing on apps more than benchmarks. Our goal with the preview is to improve app performance and memory utilization, especially focusing on app startup. We have been running benchmarks but they can be misleading because a CPU-intensive benchmark usually has very different characteristics from a real-world app.
@David Hewson & King Kikapu: So far we've focused on startup performance more than steady-state performance. Steady-state performance benefits from a number of the optimizations we've done--especially the pregenerated serializers and interop code as well as the whole-program optimization and tree shaking--but there are more steady-state gains to be had when we focus on more specific optimizations.
@Raúl: Thank you for the feedback about desktop applications--we received a lot of this feedback in comments on our previous posts. We're continuing to invest in fundamental performance improvements in the desktop CLR and will bring back key aspects of .NET Native to the desktop. We started with Windows Store apps but everything is on our radar.
I will try this when you finish support for VB and non Windows Store apps
I know, that I must wait some time, because of 'limited resources'
Making 7B profit / quarter is really limited value...
".NET Native runtime (MRT)". Should that "M" be an "N" (NRT)?
What about runtime performance when compared to ngen?
@Tristan, thanks for the feedback. Supporting VB.NET and other platforms than Windows Store are definitely in our plans.
@JVimes: Oops, typo! No, just kidding. We mean for it to be called MRT, not NRT, even though it's the runtime for "N". We've been thinking about it internally as the "MinRT" or "Minimal Runtime" but the DLL name isn't the most important decision. I will admit that we had a few pictures of B. A. Baracus hanging up in our hallways...
@pnsm: All of the performance numbers we're quoting are relative to NGen. From the first paragraph of the post: "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."
That is great if I can get .NET Native for the desktop. For serialization I would like to see added capabilities to DataCotnractSerializer to pregenerate code for it as well. Besides this I hope we will finally get pdbs out of .NET Native that do not need to be regenerated every time by Ngen createpdb when profiling with WPT.
Currently it is nearly impossible to improve startup time by profiling before and after a change because every recompilation of a dll will invalidate all dependant NGen Images. That means 10s to recompile and 20 minutes for a large application to rebuild the NGen Images to get the same baseline.
@Alois: I sent you a mail. Hope to see you soon!
Thanks for the feedback about desktop and NGen. We will bring key learnings from .NET Native back to the desktop.
Incidentally, would this improve startup times of Windows Phone? Please whenever you consider Windows Phone / ARM instruction set, consider Skype your primary test app because it takes most time to launch than any app out in the store (metaphorically speaking but this is true). The best way to underscore its performance is when it launches on low-end devices; Lumia 520, 620 and 720.
Thanks and keep up the large work!
Is there any progress to report on net native for plain .net code?
This sounds really good. I was exited and downloaded the compiler, but then only realized that it only works on Windows Store apps. - which is good start. I am really hoping to see a version with I can compile WPF program with it.
@Jerry T: We're actually doing ARM already with the Windows Store. ARM and x64--x86 coming real soon now. We also plan on getting Windows Phone up and running, though I'm not free to discuss schedules.
Thanks for the suggestion about Skype. I'll reach out to that team!