This is the final post in a five-part series covering performance improvements for Visual Studio “15”.
This series covers the following topics:
- Part 1: Faster Visual Studio “15” Startup
- Part 2: Shorter Solution Load Time in VS “15”
- Part 3: Reduced out-of-memory crashes in VS “15”
- Part 4: VS “15” gets faster for C++
- Part 5: Improving overall VS “15” responsiveness
In this post we will highlight some of the improvements we’ve made in the Preview 5 release that make using Visual Studio more responsive as part of your daily use. We’ll first talk about improvements to debugging performance, Git source control, editing XAML, and finally how you can improve your typing experience by managing your extensions.
Debugging is faster and doesn’t cause delays while editing
In Visual Studio 2005 we introduced what’s known as the hosting process for WPF, Windows Forms, and Managed Console projects to make “start debugging” faster by spinning up a process in the background that can be used for the next debug session. This well-intentioned feature was causing Visual Studio to temporarily become unresponsive for seconds when pressing “stop debugging” or otherwise using Visual Studio after the debug session ended.
In Preview 5 we have turned off the hosting process and optimized “start debugging” so that it is just as fast without the hosting process, and even faster for projects that never used the hosting process such as ASP.NET, Universal Windows, and C++ projects. For example, here are some startup times we’ve measured on our test machines for our sample UWP Photo Sharing app, a C++ app that does Prime Visualization, and a simpler WPF app:
To achieve these improvements, we’ve optimized costs related to initializing the Diagnostic Tools window and IntelliTrace (which appears by default at the start of every debugging session) from the start debugging path. We changed the initialization from IntelliTrace so that it can be initialized in parallel with the rest of the debugger and application startup. Additionally we eliminated several inefficiencies with the way the IntelliTrace logger and Visual Studio processes communicate when stopping at a breakpoint.
We also eliminated several places where background threads related to the Diagnostic Tools window had to synchronously run code on the main Visual Studio UI thread. This made our ETW event collection more asynchronous so that we don’t have to wait for old ETW sessions to finish when restarting debugging.
Source code operations are faster with Git.exe
When we introduced Git support in Visual Studio we used a library called libgit2. With libgit2, we have had issues with functionality being different between libgit2 and the git.exe you use from the command prompt and that libgit2 can add 100s of megabytes of memory pressure to the main Visual Studio process.
In Preview 5, we have swapped this implementation out and are calling git.exe out of process instead, so while git is still using memory on the machine it is not adding memory pressure to the main VS process. We expect that using git.exe will also allow us to make git operations faster over time. So far we have found git clone operations to faster with large repos: cloning the Roslyn .NET Compiler repo on our machines is 30% faster: takes 4 minutes in Visual Studio ‘15’ compared with 5 minutes, 40 seconds with Visual Studio 2015. The following video shows this (for convenience the playback is at 4x speed):
In the coming release we hope to make more operations faster with this new architecture.
We have also improved a top complaint when using git: switching branches from the command line can in cause Visual Studio to reload all projects in the solution one at a time. In the file change notification dialog we’ve replaced ‘Reload All’ with ‘Reload Solution’:
This will kick off a single async solution reload which is much faster than the individual project reloads.
Improved XAML Tab switch speed
Based on data and customer feedback, we believe that 25% developers experience at least one tab switch delay > 1 sec in a day when switching between XAML tabs. On further investigation, we found that these delays were caused by running the markup compiler, and we’ve made use of the XAML language service to make this substantially faster. Here’s a video showing the improvements we’ve made:
The markup compiler is what creates the g.i.* file for each XAML file which, among other things, contains fields that represent the named elements in the XAML file that enables you to reference those named elements from code-behind. For example, given <Button x:Name=”myButton” />, the g.i.* file will contain a field named button of type Button that allows you to use “myButton” in code.
Certain user actions such as saving or switching away from an unsaved XAML file will cause Visual Studio to update the g.i.* file to ensure that IntelliSense has an up-to-date view of your named elements when you open your code-behind file. In past releases, this g.i.* update was always done by the markup compiler. In managed (C#/VB) projects the markup compiler is run on the UI thread resulting in a noticeable delay switching between tabs on complex projects.
We have fixed this issue in Preview 5 by leveraging the XAML Language Service’s knowledge of the XAML file to determine the names and types of the fields to populate IntelliSense, and then update the g.i.* file using Roslyn on a background thread. This is substantially faster than running the markup compiler because the language service has already done all the parsing and type metadata loading that causes the compiler to be slow. If the g.i.* file does not exist (e.g. after renaming a XAML file, or after you delete your project’s obj directory), we will need to run the markup compiler to generate the g.i.* file from scratch and you may still see a delay.
Snappier XAML typing experience
The main cause of UI delays in our XAML Language Service were related to initialization, responding to metadata changes, and loading design assemblies. We have addressed all three of these delays by moving the work to a background thread.
We’ve also made the following improvements to the design of assembly metadata loading include:
- A new serialization layer for design assembly metadata that significantly reduces cross boundary calls.
- Reuse of the designer’s assembly shadow cache for WPF projects. Reuse of the shadow cache across sessions for all project types. The shadow cache used to be recreated on every metadata change.
- Design assembly metadata is now cached for the duration of the session instead of being recomputed on every metadata change.
These changes also allow XAML IntelliSense to be available before the solution is fully loaded.
Find out which extensions cause typing delays
We have received a number of reports about delays while typing. We are continuing to make bug fixes to improve these issues, but in many cases delays while typing are caused by extensions running code during key strokes. To help you determine if there are extensions impacting your typing experience, we have added reporting to Help -> Manage Visual Studio performance, and will notify you when we detect extensions slowing down typing.
Notification of extensions slowing down typing
You can see more details about extensions in Help -> Manage Visual Studio Performance
Try it out and report issues
We are continuing to work on improving the responsiveness of Visual Studio, and this post contains some examples of what we have accomplished in Preview 5. We need your help to focus our efforts on the areas that matter most to you, so please download Visual Studio ‘15’ Preview 5, and use the Report-a-Problem tool to report areas where we can make Visual Studio better for you.
|Dan Taylor, Senior Program Manager
Dan Taylor has been at Microsoft for 5 years working on performance improvements to .NET and Visual Studio, as well as profiling and diagnostic tools in Visual Studio and Azure