{"id":303,"date":"2014-05-24T12:00:00","date_gmt":"2014-05-24T12:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/dotnet\/2014\/05\/24\/net-native-deep-dive-optimizing-with-runtime-directives\/"},"modified":"2023-06-19T14:11:17","modified_gmt":"2023-06-19T21:11:17","slug":"net-native-deep-dive-optimizing-with-runtime-directives","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/net-native-deep-dive-optimizing-with-runtime-directives\/","title":{"rendered":".NET Native Deep Dive: Optimizing with Runtime Directives"},"content":{"rendered":"<p><em>This post was authored by Morgan Brown, a Software Development Engineer on the .NET Native team. It is the fifth post in a series of five about Runtime Directives. Please see the first posts in this series, <a href=\"http:\/\/blogs.msdn.com\/b\/dotnet\/archive\/2014\/05\/20\/net-native-deep-dive-dynamic-features-in-static-code.aspx\">Dynamic Features in Static Code<\/a>, <a href=\"http:\/\/blogs.msdn.com\/b\/dotnet\/archive\/2014\/05\/21\/net-native-deep-dive-help-i-hit-a-missingmetadataexception.aspx\">Help! I Hit a MissingMetadataException!<\/a>, <a href=\"http:\/\/blogs.msdn.com\/b\/dotnet\/archive\/2014\/05\/22\/net-native-deep-dive-help-i-didn-t-hit-a-missingmetadataexception.aspx\">Help! I Didn&#8217;t Hit a MissingMetadataException!<\/a>, and <a href=\"http:\/\/blogs.msdn.com\/b\/dotnet\/archive\/2014\/05\/23\/net-native-deep-dive-making-your-library-great.aspx\">Making Your Library Great<\/a>, before reading this post.<\/em><\/p>\n<p>The previous posts in this series are about getting your app working with .NET Native, but you don\u2019t want just working. You want excellent. We\u2019ll focus on how to tune your runtime directives and other dynamic behavior to make your app or library sing. In particular, we\u2019ll dig into cutting down app size, which in turn improves memory usage, runtime performance, and build time (that\u2019s right, as you optimize, building will get easier!)<\/p>\n<p>Let\u2019s start out with something that sounds a little crazy, but will make a big difference: delete your rd.xml file. (Ok, make a backup first.)<\/p>\n<p>Try doing a quick release build and measure your results \u2013 did your resulting binaries get significantly smaller? If they didn\u2019t, you may have an app that really uses all of the code in the app package and your application doesn\u2019t have many optimization opportunities available through Runtime Directives. It\u2019s much more likely you saw a big difference, so this can be a good baseline \u2013 this is the minimum size you could possibly get to (and there\u2019s a chance your app doesn\u2019t work).<\/p>\n<p>The default rd.xml file that gets added to your project when you enable .NET Native was chosen for a balance of compatibility with any app and good performance. The directive included in it says to compile all code found in your app package and include extra reflection information for it. Most apps include .NET libraries in the app package and often, only pieces of those libraries are needed. That default rd.xml tells the compiler to skip optimizing all of that unwanted code away and instead spend megabytes of binary size and tens of seconds compiling it.<\/p>\n<p>So now that you\u2019ve deleted your rd.xml, your app may be hitting MissingMetadataExceptions. Before diving for that backup copy, let\u2019s see if we can make your app work by including only the code you need and not large amounts you don\u2019t. At a high level, what that takes is having runtime directives that explain how reflection in your app works to the compiler. Here\u2019s how you get there:<\/p>\n<ol>\n<li>You probably don\u2019t have to start from scratch. If your app is like most, lots of the dynamic behavior in your app really happens in third party libraries. For some of those, we\u2019ve included rd.xml files in the SDK that automatically get used by the compiler. If you see MissingMetadataExceptions coming out of calls to libraries, check if there\u2019s a newer version of the library that includes rd.xml; if there\u2019s not, tell the author that you want their library to be part of your fast and lightweight .NET Native App and they should check out <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/net-native-deep-dive-making-your-library-great\/\">Making Your Library Great<\/a>.<\/li>\n<li>If you\u2019ve factored your own code into libraries that work off of reflection, try the same article. The goal here is that the library code should use reflection directives like GenericParameter and Parameter that can automatically pick up all of the individual types you use with a library. That way, your code will work every time, without you either having to write a ton of directives or picking one that includes lots of stuff you don\u2019t need. A good goal is to not use any Namespace or Assembly directives and instead just use Parameter and GenericParameter directives and maybe a few individual types.<\/li>\n<li>See if there are some places you use reflection that you don\u2019t need to. A few good candidates are:\n<ul>\n<li>Replace the C# dynamic keyword with strongly typed code using interfaces or generics. It turns out that behind that simple-looking keyword is a ton a reflection. As a bonus, this will make IL versions of your app faster too.<\/li>\n<li>Compiled LINQ expressions are a useful optimization on a runtime with a JIT since they get compiled at runtime. However, on a static runtime like .NET Native, they get interpreted instead of compiled and use lots of reflection too. Instead, think about using handwritten methods that will get compiled up-front. On .NET Native, compiled methods are always faster than interpreted code (and don\u2019t need rd.xml).<\/li>\n<li>Instead of Type.GetType(\u201cMyWellKnownType\u201d), consider typeof(MyWellKnownType). Similarly, when you can, construct delegates directly from methods instead of using MethodInfo.CreateDelegate.<\/li>\n<li>Lots of apps use an old trick to avoid having to come up with strings for INotifyPropertyChanged involving a LINQ Expression with the property. You can now use the CallerMemberName attribute, which will cause the C# compiler to automatically fill in the string without adding any reflection requirements.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>So how do you know if you\u2019ve done a good job? Of course, getting your app working with more specific directives is a pretty good sign. Aside from your total binary size, there\u2019s a simple metric that can help you understand how well you\u2019re cutting down on excess reflection metadata. In your Visual Studio project directory, under <code>obj\\(Architecture)\\(Debug or Release)\\(Name of your project).ilc\\intermediate\\ILTransformed<\/code>, there\u2019s a file named <code>(Name of your project).reflectionlog.csv<\/code>. That file contains all of the types and members that have been enabled for reflection and which degrees were applied to them. You can use the size of that file as a proxy for how much compiled stuff you\u2019re asking for and you can also skim the contents to get an idea of what you might be pulling in and whether it seems like there are large swaths of things you don\u2019t expect.<\/p>\n<p>If you go through all of that and either couldn\u2019t get your app working without the original rd.xml or it really just didn\u2019t get much smaller despite having library code you probably don\u2019t need, we\u2019d love to hear from you. We\u2019re constantly improving the compiler and data helps us come up with new ways to make apps better automatically. Please feel free to leave comments at the end of this post or email us at <a href=\"http:\/\/blogs.msdn.commailto:dotnetnative@microsoft.com\">dotnetnative@microsoft.com<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post was authored by Morgan Brown, a Software Development Engineer on the .NET Native team. It is the fifth post in a series of five about Runtime Directives. Please see the first posts in this series, Dynamic Features in Static Code, Help! I Hit a MissingMetadataException!, Help! I Didn&#8217;t Hit a MissingMetadataException!, and Making [&hellip;]<\/p>\n","protected":false},"author":11288,"featured_media":58792,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685],"tags":[66],"class_list":["post-303","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","tag-dotnetnative"],"acf":[],"blog_post_summary":"<p>This post was authored by Morgan Brown, a Software Development Engineer on the .NET Native team. It is the fifth post in a series of five about Runtime Directives. Please see the first posts in this series, Dynamic Features in Static Code, Help! I Hit a MissingMetadataException!, Help! I Didn&#8217;t Hit a MissingMetadataException!, and Making [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/303","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/11288"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=303"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/303\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}