{"id":8463,"date":"2015-02-23T09:53:00","date_gmt":"2015-02-23T09:53:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/2015\/02\/23\/performance-improvement-when-debugging-net-code-with-visual-studio-2015\/"},"modified":"2022-07-28T01:37:12","modified_gmt":"2022-07-28T09:37:12","slug":"performance-improvement-when-debugging-net-code-with-visual-studio-2015","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/devops\/performance-improvement-when-debugging-net-code-with-visual-studio-2015\/","title":{"rendered":"Performance Improvement When Debugging .NET Code With Visual Studio 2015"},"content":{"rendered":"<p>Nothing is more frustrating than trying to debug an application that runs significantly slower when you\u2019re debugging it than <ins cite=\"mailto:John%20Kemnetz\" datetime=\"2015-02-12T11:49\">it does <\/ins>when it runs without a debugger attached. Over the years we\u2019ve received numerous complaints along the lines of \u201cwhen I run my application without the debugger it takes a few seconds to execute a scenario, but with the debugger it can take several minutes.\u201d By far the most common cause is a large number of exceptions being thrown and caught somewhere in the application (we\u2019ll look at why later in the post).<\/p>\n<p>You can usually work around this issue by reducing the number of exceptions being thrown, but unfortunately if the exceptions are fully contained in a 3<sup>rd<\/sup> party library there is nothing you can do other than suffer through a slow debugging experience. So we\u2019re pleased to announce that in Visual Studio 2015 in conjunction with .NET 4.6 (available in [Visual Studio 2015 CTP 6][1]) we significantly reduced the performance overhead when <em>handled<\/em> exceptions occur outside of your code (meaning they are thrown and handled in a module excluded by <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/dn457346.aspx#BKMK__NET_Framework_Just_My_Code\">the debugger\u2019s \u201cJust My Code\u201d (JMC) setting<\/a>). In this post we\u2019ll briefly look at how much this can improve performance, then we\u2019ll talk about what you can expect to see based on this change.<\/p>\n<h3>Example of performance speedup for handled exceptions<\/h3>\n<p>First, let\u2019s look at what this means in practical terms. I <a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/6\/2019\/02\/ExceptionTest.zip\" title=\"created an application\">created an application<\/a> that will throw and catch the number of exceptions I instruct it to before completing the method call. First, let\u2019s look at how long it takes for the debugger to run the method when 100 exceptions are thrown and handled (also referred to as \u201cfirst chance exceptions\u201d)<\/p>\n<p><img decoding=\"async\" style=\"padding-top: 0px;padding-left: 0px;padding-right: 0px;border: 0px\" title=\"clip_image002\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2015\/02\/0003.clip_image002_thumb_3ECBC204.jpg\" alt=\"clip_image002\" width=\"627\" height=\"124\" border=\"0\" \/><\/p>\n<p><em>Note: I\u2019m using a *<a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/System.Diagnostics.Stopwatch(v=vs.110).aspx\"><em>StopWatch<\/em><\/a><\/em> to record the time and have displayed it by *<a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/ea46xwzd.aspx\"><em>pinning the DataTip to the editor<\/em><\/a>**<\/p>\n<p>Notice that it took ~813ms seconds to execute a method that did nothing other than throw and catch 100 exceptions with the debugger attached. Next, to simulate this code running in an external library, I\u2019ll tell the debugger this isn\u2019t user code by adding a <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.diagnostics.debuggernonusercodeattribute(v=vs.140).aspx\">DebuggerNonUserCode<\/a> attribute to the <em>ClassWithInternalExceptions<\/em> definition. Running it again yields a time of ~26ms meaning it ran ~97% faster!<\/p>\n<p><img decoding=\"async\" style=\"padding-top: 0px;padding-left: 0px;padding-right: 0px;border: 0px\" title=\"clip_image004\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2015\/02\/1563.clip_image004_thumb_37AC858C.jpg\" alt=\"clip_image004\" width=\"628\" height=\"232\" border=\"0\" \/><\/p>\n<p>Marking the code as non-user on VS versions prior to VS2015 (or with a .NET Framework prior to 4.6) will not provide any savings and you still have to suffer though the slow performance.<\/p>\n<h3>A peek under the hood<\/h3>\n<p>To understand the reasons behind the performance gains, it\u2019s important to understand how exceptions work when a debugger is attached to a .NET process. When an exception is thrown (even if it will be handled) the runtime pauses the process to send a notification to the debugger so it has the opportunity to stop on the throw <a href=\"http:\/\/blogs.msdn.com\/b\/visualstudioalm\/archive\/2015\/01\/08\/understanding-exceptions-while-debugging-with-visual-studio.aspx\">if you have enabled this in your exception settings<\/a>; if not, the debugger resumes the process. As you can see, it doesn\u2019t take many exception events to significantly impact the performance of your application when debugging. There are a few factors that contribute to the exact performance overhead including the number of threads in the process and the depth of the call stack where the exception occurs, but in both cases more will mean higher overhead. However, regardless of your exception settings, when Just My Code is enabled the debugger will never break for an exception that is thrown and handled in non-user code. Meaning you were paying a performance penalty that would yield little benefit, so we fixed it!<\/p>\n<p>Feel free to <a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/6\/2019\/02\/ExceptionTest.zip\" title=\"download the attached project\">download the attached project<\/a> and experiment with the performance impact of exceptions in various scenarios including stack depth and the number of threads in the process.<\/p>\n<h3>Notable points<\/h3>\n<p>There are a few things to note about how this change works.<\/p>\n<ul>\n<li>It only applies when Just My Code is enabled (the default setting) and you are debugging a .NET application running on the 4.6 (or newer) runtime. Since 4.6 installs with Visual Studio 2015<ins cite=\"mailto:John%20Kemnetz\" datetime=\"2015-02-12T12:00\">,<\/ins> this is only a potential issue if you are remote debugging on a machine without Visual Studio 2015 installed or are debugging an application that is running on the .NET 2\/3\/3.5 runtime.<\/li>\n<li>\n<p>It will not change the performance overhead for exceptions that are thrown in your code<\/p>\n<\/li>\n<li>\n<p>As demonstrated above you can potentially work around this issue if you absolutely can\u2019t avoid a large number of exceptions in your code by marking offending code as non-user code for sessions where you don\u2019t need to debug into that code.<\/p>\n<\/li>\n<li>\n<p>With this change, you will not be able to see exceptions that were thrown and handled outside of user code in the <a href=\"http:\/\/blogs.msdn.com\/b\/visualstudioalm\/archive\/2015\/01\/16\/intellitrace-in-visual-studio-ultimate-2015.aspx\">IntelliTrace events view<\/a>.<\/p>\n<\/li>\n<\/ul>\n<h3>Conclusion<\/h3>\n<p>You saw that a high volume of thrown exceptions can severely impact the performance of your debugging session, so to address this we significantly reduced the impact when they occur in non-user code. If you have any questions or comments, please let me know below, through <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/zzszcehe.aspx\">Visual Studio\u2019s Send a Smile feature<\/a><del datetime=\"2015-02-12T12:02\">,<\/del> or in our <a href=\"http:\/\/social.msdn.microsoft.com\/Forums\/en-US\/vsdebug\/threads\">MSDN forum<\/a>.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/6\/2019\/02\/ExceptionTest.zip\">ExceptionTest.zip<\/a><\/p>\n<p>[1]: http:\/\/blogs.msdn.com\/controlpanel\/blogs\/posteditor.aspx\/Visual Studio 2015 CTP 6 &#8220;http:\/\/www.visualstudio.com\/downloads\/visual-studio-2015-ctp-vs&#8221;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Nothing is more frustrating than trying to debug an application that runs significantly slower when you\u2019re debugging it than it does when it runs without a debugger attached. Over the years we\u2019ve received numerous complaints along the lines of \u201cwhen I run my application without the debugger it takes a few seconds to execute a [&hellip;]<\/p>\n","protected":false},"author":68,"featured_media":45953,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,225],"tags":[],"class_list":["post-8463","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","category-git"],"acf":[],"blog_post_summary":"<p>Nothing is more frustrating than trying to debug an application that runs significantly slower when you\u2019re debugging it than it does when it runs without a debugger attached. Over the years we\u2019ve received numerous complaints along the lines of \u201cwhen I run my application without the debugger it takes a few seconds to execute a [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/8463","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/users\/68"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/comments?post=8463"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/8463\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media\/45953"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media?parent=8463"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/categories?post=8463"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/tags?post=8463"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}