{"id":245259,"date":"2023-09-25T07:49:32","date_gmt":"2023-09-25T14:49:32","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/visualstudio\/?p=245259"},"modified":"2023-09-25T07:49:32","modified_gmt":"2023-09-25T14:49:32","slug":"a-unit-of-profiling-makes-the-allocations-go-away","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/visualstudio\/a-unit-of-profiling-makes-the-allocations-go-away\/","title":{"rendered":"A unit of profiling makes the allocations go away"},"content":{"rendered":"<p>In Visual Studio 17.8 Preview 2 we have updated unit test profiling, allowing you to use any of the available tools in the performance profiler \u2013 not just the instrumentation tool. With this change, it\u2019s easy to quickly profile small units of work in isolation, make changes, and then remeasure and validate the impact of the change. Assuming you have good test coverage, this is a great way to leverage existing assets to help performance-tune your application.<\/p>\n<h2>Who moved my cheese?<\/h2>\n<p>With this new release, we have updated the unit test profiling experience. Previously when selecting profile in the context menu for a unit test, it ran under the Instrumentation tool, and you got the report at the end of the run.\n<a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/TestExplorer.png\"><img decoding=\"async\" class=\"wp-image-245262 size-full aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/TestExplorer.png\" alt=\"Test explorer showing profile command in context menu\" width=\"1022\" height=\"555\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/TestExplorer.png 1022w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/TestExplorer-300x163.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/TestExplorer-768x417.png 768w\" sizes=\"(max-width: 1022px) 100vw, 1022px\" \/><\/a><\/p>\n<p>Now when you select a profile, the Performance Profiler launch page will appear, and you can choose any of the available tools.\n<a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/ProfilerLaunchPage.png\"><img decoding=\"async\" class=\"size-full wp-image-245263 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/ProfilerLaunchPage.png\" alt=\"Visual Studio profiler launch page\" width=\"1024\" height=\"597\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/ProfilerLaunchPage.png 1024w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/ProfilerLaunchPage-300x175.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/ProfilerLaunchPage-768x448.png 768w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<p>This lets you do things like profiling a unit test with the .NET Object Allocation tool to see all the allocations and where they come from. This is a great way to trim down unnecessary allocations and then validate your changes.<\/p>\n<h2>Let&#8217;s reduce some allocations!<\/h2>\n<p>Now that we can use any of the tools, let\u2019s take 5 minutes and see if we can trim some allocations from the performance profiler. To start, I have a unit test called \u201cVerifySimpleCallTree\u201d that we use with to verify our profiler correctly builds a calltree. From the test explorer I right click the test and select \u201cProfile\u201d, get presented with the Performance Profiler, select the .NET Object Allocation tool, and hit \u201cStart\u201d. From here my test runs and once complete I get the normal allocation report which I can use to dig into allocations and see what I can trim to ease the burden on the GC.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/AllocationsBefore.png\"><img decoding=\"async\" class=\"size-full wp-image-245264 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/AllocationsBefore.png\" alt=\".NET Allocation tool showing enumerator allocations\" width=\"1024\" height=\"768\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/AllocationsBefore.png 1024w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/AllocationsBefore-300x225.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/AllocationsBefore-768x576.png 768w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a>\nAs I poke through the types, I notice a bunch of Enumerators being allocated. While this is not immediately wrong, it does seem odd. With the backtraces I can see this is coming from our JmcConfigurationService, and looking at the code sure enough an enumerator is being created from an Any() extension method.<\/p>\n<pre class=\"prettyprint\">this.patternsLock.EnterReadLock();\r\ntry\r\n{\r\n    if (this.unknownModulePatterns.Any(t =&gt; t.IsMatch(moduleString)))\r\n    {\r\n        return JmcState.UnknownCode;\r\n    }\r\n    else if (this.systemModulePatterns.Any(t =&gt; t.IsMatch(moduleString)))\r\n    {\r\n        return JmcState.SystemCode;\r\n    }\r\n    else\r\n    {\r\n        return IsStringJmc(moduleString, this.excModulePatterns, this.incModulePatterns) ? JmcState.UserCode : JmcState.LibraryCode;\r\n    }\r\n}\r\nfinally\r\n{\r\n    this.patternsLock.ExitReadLock();\r\n}\r\n<\/pre>\n<p>With a quick rewrite using a static local function, we can remove the enumerator and reduce the allocations.<\/p>\n<pre class=\"prettyprint\">this.patternsLock.EnterReadLock();\r\ntry\r\n{\r\n    if (CheckMatch(this.unknownModulePatterns, moduleString))\r\n    {\r\n        return JmcState.UnknownCode;\r\n    }\r\n    else if (CheckMatch(this.systemModulePatterns, moduleString))\r\n    {\r\n        return JmcState.SystemCode;\r\n    }\r\n    else\r\n    {\r\n        return IsStringJmc(moduleString, this.excModulePatterns, this.incModulePatterns) ? JmcState.UserCode : JmcState.LibraryCode;\r\n    }\r\n}\r\nfinally\r\n{\r\n    this.patternsLock.ExitReadLock();\r\n}\r\n\r\nstatic bool CheckMatch(List patterns, string moduleStr)\r\n{\r\n    foreach (var pattern in patterns)\r\n    {\r\n        if (pattern.IsMatch(moduleStr))\r\n        {\r\n            return true;\r\n        }\r\n    }\r\n\r\n    return false;\r\n}\r\n<\/pre>\n<p>Rerunning the profiler on the unit test I can then validate that yes; I have in fact removed these unneeded allocations and helped reduce the burden on the GC.\n<a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/AllocationsAfter.png\"><img decoding=\"async\" class=\"size-full wp-image-245265 aligncenter\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/AllocationsAfter.png\" alt=\".NET Allocation tool showing enumerator allocation reduction\" width=\"1024\" height=\"768\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/AllocationsAfter.png 1024w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/AllocationsAfter-300x225.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2023\/09\/AllocationsAfter-768x576.png 768w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<p>While this small tweak isn\u2019t going to make my app magically 20% faster, slowly reducing unneeded allocations over time is a great way to gradually improve your apps performance. With the new unit test profiling this is easy to do with your existing test assets and then verify the change had the desired impact.<\/p>\n<p>&nbsp;<\/p>\n<h2 id=\"let-us-know-what-you-think\">Let us know what you think!<\/h2>\n<p>The ability to use unit tests for isolated performance analysis is awesome. By isolating specific regions of code, it\u2019s easy to get a good before and after trace to compare and see the impact of your performance optimizations. We eagerly welcome any bright ideas, thoughts, or valuable insights, we&#8217;re all ears! Don&#8217;t hold back\u2014share them with us at this <a href=\"https:\/\/www.surveymonkey.com\/r\/BTYD6GM?sessionId=%5bsessionId_value%5d\" target=\"_blank\" rel=\"noopener\">link<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In Visual Studio 17.8 Preview 2 we have updated unit test profiling, allowing you to use any of the available tools in the performance profiler \u2013 not just the instrumentation tool. With this change, it\u2019s easy to quickly profile small units of work in isolation, make changes, and then remeasure and validate the impact of [&hellip;]<\/p>\n","protected":false},"author":54885,"featured_media":245262,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[155],"tags":[9,6839,6872,6815],"class_list":["post-245259","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-visual-studio","tag-debug","tag-developer-productivity","tag-unit-test-performance","tag-visual-studio-2022"],"acf":[],"blog_post_summary":"<p>In Visual Studio 17.8 Preview 2 we have updated unit test profiling, allowing you to use any of the available tools in the performance profiler \u2013 not just the instrumentation tool. With this change, it\u2019s easy to quickly profile small units of work in isolation, make changes, and then remeasure and validate the impact of [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/245259","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/users\/54885"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/comments?post=245259"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/245259\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media\/245262"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media?parent=245259"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/categories?post=245259"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/tags?post=245259"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}