Improved Toolbox Performance Delivers Highly Responsive Visual Studio 2012
As mentioned in the previous performance post on Typing and Editing we would follow with a post on the improvements to Visual Studio 2012 from enhancements in the Toolbox. I would like to introduce Duke Kamstra and Chuck England from two teams in Visual Studio to describe to you the work done to improve responsiveness via the Toolbox.
Visual Studio is packed with awesome rapid application development features. Sometimes getting all of these great features comes at a price. Producing Intellisense, red squiggles, smart rename, refactoring, etc. can require quite a bit of work. As features have become more versatile, and solutions have grown in size and complexity, we’ve seen that the additional workload can cause the UI to become slow to respond, repaint, or even hang. In Visual Studio 2012, we wanted to improve this experience. In today’s blog post, we will discuss one of the features, the toolbox, and the performance enhancements we have made.
Why Focus On Toolbox?
In previous blog posts on performance we mentioned PerfWaston. The Toolbox is one of the features that generated a lot of hits. Armed with this data we designed several test scenarios. We profiled these scenarios using solutions provided by customers as well as ones we created to simulate large, complex solutions.
We learned several things analyzing the performance traces:
- Scenarios seemingly unrelated to interacting with the toolbox were being impacted by the logic used to refresh the toolbox. For example, with a large solution we observed that Toolbox was blocking the Visual Studio UI by 30 seconds when we closed the solution.
- The impact could vary in subtle ways depending on which designer was in use
- Larger solutions seemed to show more potential for improvement
- The implementation of the designers impacted the Toolbox’s performance. This meant it would not just be a simple matter of refactoring a single class or tuning some main routines within the toolbox, we also needed to tune the individual designers themselves.
How Does the Toolbox Work?
To help explain what we changed to improve toolbox performance, it may help to first describe how the toolbox works. At a high-level, the toolbox works in conjunction with a designer to filter the list of all known visual components to a list that is contextually relevant for the loaded designer. So, for example, if you are working in the Windows Forms designer, you see Windows Forms controls, and when working in the WPF designer, you see WPF controls.
The list is built from two distinct types of visual components. First, there are the items that are registered on the machine. These are items that are supplied with Visual Studio out of the box or installed by the user from a 3rd party vendor. The toolbox builds a cached list of these components and makes that list available to the designer. The designer then filters them as appropriate for its needs.
Second, there are user components that are defined in user projects. These are the custom components like user controls, datasets, etc. that you define. For these components, the designer itself is responsible for searching through the built solution’s output and adding them to the toolbox.
The big distinction between these two types is that the registered components are static and seldom change, whereas user components may change often as you update the code in your solution.
For user components, the basic discovery process consists of iterating through all of the build outputs for the solution to locate potential controls that are available for use in the designers. This is performed through a reflection-like process to find the controls. We learned through our performance traces that this “discovery” of user controls is proportionately expensive to the size and complexity of your solution.
What Did We Focus On?
While the general mechanism of updating the list of user components was common across most of the designers in the product, each designer had to be specifically investigated to understand the opportunities to improve performance. While there are many designers in the product (e.g. Workflow, UML modeling, DSL (Domain Specific Languages), WCF, DataSet), most are based on one of three common base implementations (WinForms, WebForms, and WPF/XAML). For each of these base implementations, we saw that the largest performance opportunities existed when a user was performing one of the following operations:
- Loading a solution
- Opening a designer
- Changing the build configuration (Debug/Release)
- Building a solution
- Closing a solution
To improve the performance in these scenarios, we followed a few basic principles.
Don’t Do Work If We Don’t Need To
The first principle we followed was to stop doing work we did not have to do. It seems to go without saying, but life is rarely that simple. Just because you have established a simple and viable design at one point in time does not mean it will stay that way. This is where performance tuning is required.
One such case for the toolbox is the choice on when the work is performed. If you have a designer open and you have the Toolbox open, then we presume you want to interact with the Toolbox and the design surface. So, we make sure that all the visual components in the toolbox are up to date and relevant.
But what if you never open a designer? What if you have a designer open, but the toolbox window itself is closed? In these cases, we found that we were still making sure that the toolbox stayed up to date. As a result of our tuning work, we have eliminated this work until we see that you have an open designer and the Toolbox is visible.
Another tuning opportunity was found in designers’ code that ensured the toolbox is always up to date. After a designer searches for new or changed visual components, the toolbox window is updated with the results. In Visual Studio 2010, several designers accomplished this by removing everything and then adding all of the newly discovered items in bulk. In many cases, the items may not have changed much if at all. Our analysis showed this to be very inefficient, requiring considerable work and UI repainting. To improve, we only add or remove visual components from the Toolbox that have changed since the last update.
Stay off the UI thread
A second principle we applied was to remove work from the UI thread. When long running work occurs on the UI thread, Visual Studio can’t respond to messages from the operating system to repaint the window or to process user input such as mouse clicks or typing. In contrast work that occurs asynchronously on a background thread does not prevent the UI thread from processing messages. This is how we ensure a responsive UI.
The performance traces identified several cases where work for toolbox was being performed on the UI thread. One example was the work that is performed by designers to discover the custom components in the solution.
After we applied these principles, we compared the before and after of some common scenarios with the toolbox and a designer open. The chart below shows the performance gains that we made based on all of the tuning and targeted performance changes that we made over the course of Visual Studio 2012. (Yes, these are % gains over previous times.)
Note that these numbers are against a set of internal benchmark solutions. Different solutions may see different results. The typical margin of error for these test cases is +/-5%.
Load Solution with Toolbox and Designer Open
Load Solution with Toolbox Open
Open Designer with Toolbox Open
Change Build Configuration with Toolbox Open
Rebuild with Toolbox Open
Incremental build with Toolbox Open
Close Solution with Toolbox Open
Remember the ~30 seconds of unresponsiveness I mentioned when closing a large solution in Visual Studio 2010 SP1? Our tuning reduced this time in our test case down to ~700ms.
But the numbers are only part of the story. To see the impact, you really have to see it for yourself. You can pick up the latest pre-release version of Visual Studio 2012 here. For those of you who have tried the RC, feel free share your impressions on its overall performance in the comments section, on our UserVoice Site, or you can report new issues to us using the Visual Studio 11 Feedback Tool. If you regularly work with a large number of custom components, in Visual Studio 2012 you will find that it is now much more responsive and you can almost immediately get to work.
Short Bio: Chuck England is a Program Manager who currently works on core architectural and performance related improvements in Visual Studio. He previously worked to help deliver the Project System and MSBuild which shipped in Visual Studio 2010 / .NET 4.0 and now in the upcoming Visual Studio 2012 / .NET 4.5 releases. Chuck has an extensive history in development with a little over 30 years as an architect and developer in various software industries prior to joining Microsoft in 2008.
Short Bio: Duke has been at Microsoft 8 years, working on various parts of Visual Studio for the last 5 years. His current role is driving performance improvements across the Visual Studio product line.
We hope these and the other improvements we’ve made Visual Studio 2012 RC are providing you additional productivity gains and making your development experience a great one. Please help us continue to improve through your feedback and suggestions! I greatly appreciate you taking the time to read and comment on these posts and as always I appreciate your continued support of Visual Studio.
Director of Engineering