Learn how you can profile your .NET applications and see a walk-through using the Concurrency Visualizer in Microsoft Visual Studio 2010 Premium and Ultimate.
Multi-core processors are here to say, and to stay competitive developers need to learn new tricks to utilize these swift chips. With the introduction of Microsoft Visual Studio 2010 and .NET Framework 4.0, Microsoft has given developers betters tools and class libraries to create multi-threaded applications. In this article, you are going to learn how you can profile your .NET applications with Microsoft Visual Studio 2010.
Even now with technologies like Task Parallel Library ( TPL ) and Parallel LINQ (PLINQ), writing scalable and high-performance multi-threaded applications still requires work. Luckily, Microsoft Visual Studio 2010 aims to make this process at least a little easier, especially when performance profiling is considered. The newest Microsoft Visual Studio contains a completely new feature called Concurrency Visualizer. This feature gives you a highly visual view to the performance of your .NET framework code.
Concurrency Visualizer extends the previous performance profiling functions in the product, and allows you to quickly identify coding issues and see how efficiently your application is performing on multi-core systems. Performance data is collected to millisecond accuracy, and the visualizer can also point back to source code lines to show locations where most pressing issues are.
The new profiling features are available in the high-end versions of Microsoft Visual Studio 2010. Both Premium and Ultimate versions contain the Concurrency Visualizer feature, but it is missing from the Professional version. Furthermore, the Concurrency Visualizer feature is only available on newer Windows operating systems. This means that you can only profile concurrency issues on Windows Vista and Windows 7; Windows XP users cannot use the feature. The technical reason for this is that the new profiling functions in Microsoft Visual Studio rely on the Event Tracing for Windows (ETW) functionality which is not available on Windows XP.
In this article, you are going to see a walk-through of using the Concurrency Visualizer in Visual Studio 2010 Premium and Ultimate. Note that although the new Concurrency Visualizer is only a small part of the overall profiling features in these versions, this article will only focus on the concurrency features not available in previously. Remember that you will need Windows 7 (preferably) to try these features as you are progressing.
Starting a Performance Session
To get started with the Concurrency Visualizer in Visual Studio 2010, you first need to create what is called a performance session. To do so, start Visual Studio, and open a project you wish to profile. Although there other ways to start a performance session, an easy way is to use the wizard. To launch this wizard, go to Visual Studio's Analyze menu, and choose the Launch Performance Wizard command (or press Alt+N, Z). This will bring up the Performance Wizard dialog box (Figure 1).
If you have used Visual Studio's profiling features before, for instance with Microsoft Visual Studio 2008, then you will immediately recognize this dialog box. In Microsoft Visual Studio 2010, this dialog box contains a new option at the bottom called Concurrency. When you select this option, you will have two additional choices: to collect contention data and visualize threads. Once you have made your pick, click Next. (Initially, you might wish to select both options to see what kind of results you get.)
In the second step of the wizard, you are given the option to select the application you want to profile. Since you already have a project open, then the default option will usually be correct. However, you also can profile any application running or on disk, or select the correct project if your Microsoft Visual Studio solution contains more than one project.
In the third and final step of the wizard, you can select whether you want to start profiling immediately. This is usually what you want to do, so by simply clicking Finish, your selected project will start. Once the application has started, start working with it as you normally would. Note that while your application is running, Microsoft Visual Studio will tell you that a profiling session is in progress.
Analyzing Profiling Results
Once you are done working with your application, simply close it, and Microsoft Visual Studio will then start to analyze the results. At this point, Microsoft Visual Studio will need access to symbols. These contain information about functions and their entry points within the modules (DLLs) used by your application.
If you have a freshly installed Visual Studio, then you might not have previously loaded the necessary symbols to your machine. If this is the case, Visual Studio will kindly open the Tools/Options dialog box for you, and navigate right into the Debugging/Symbols section. Here (see Figure 2), you can either specify symbol file (.pdb, "Programmer's DataBase") locations, or alternatively use Microsoft's web-based symbol servers.
[Figure 2 - Symbol Settings.png]
The symbols servers are usually a good option, and once you have downloaded the symbols from the web, they are cached on your machine under the cache symbol directory you specify. Thus, you will only need an Internet connection once; after that you can work with the cached files even if you are on the beach with your laptop. Note that the cached files take around 100 MB of disk space, so it can also take some minutes to download them, especially if you have a slow Internet connection.
With the symbol server set and a cache directory given, click OK in the Options dialog box, and then let Visual Studio continue analyzing your profiling results. Usually, it will take around 30 to 90 seconds to analyze profiling results on a moderate speed PC, but of course, your mileage may vary. All in all, it is best to keep profiling sessions as short as possible, because otherwise inspecting the results gets more difficult. A single, sub-minute profiling session is usually around 400 to 500 MB in size, so if you are doing lots of long profiling sessions, prepare with plenty of disk space.
Once Visual Studio has finished loading all necessary symbol files and has completed analyzing the results, you will see a screen similar to the one shown in Figure 3. At the middle, the Concurrency Profiling Report window (these reports use the .vsp file extension) displays a contention graph, which gives you an overview of internal resource bottlenecks inside you application. Shortly put, lower values are better.
[Figure 3 - Main Screen.png]
Above the graph, you can see three buttons that lead you to additional information: CPU Utilization, Threads and Cores. Below the graph you can see quantitative details about your application, with information such as resources and threads causing most contention. Finally, the Visual Studio Error List displays statistical information and associated performance tips. This includes information such as overall memory and CPU usage, paging and .NET garbage collection metrics, and so on. All this is summary information in nature, and gives you an overview of the workings of your application with concurrency in mind. With the three additional buttons above the graph however, you can really see how your application behaves.
The CPU, Thread and Core Views
To really get into business with Visual Studio 2010's Concurrency Visualizer feature, you need to click the three buttons above the initial resource contention graph. Let's start from the left with the CPU Utilization graph (see Figure 4).
[Figure 4 - CPU Utilization.png]
The CPU Utilization graph displays a visual indication of how your application is using the CPU(s) overall. The graph is shown relative to the number of logical processors available to Windows; for example, in the above graph, an Intel Core 2 Duo processor enables two logical processors in the operating system.
While the profiling session is in place, Visual Studio will collect information about your application, but also the CPU usage of every other process in the system. With the default color scheme, your own application's processor usage is shown in green, other processes in yellow, and idle time in gray.
At the top of the screen, you can see a slider with which you can zoom in and out in the graph. You can also drag an area over the graph to zoom directly into the selection. The graph is time-based: time runs from left to right and is given in milliseconds, i.e. one-thousandth of a second.
One indicator of successful threading is that the processor usage of your application can raise over the bar of a single logical processor. And if your application is computation-intensive, the closer to the top of the graph your application's green area rises, the more efficiently it can utilize the multiple logical processors in the system.
The second and even more interesting graph provided by Visual Studio is the Threads graph. To activate it, simply click the Threads button at the top of the window, or choose the similarly named view from the Current View dropdown list at the top.
The Threads graph (Figure 5) displays all the threads that existed during the lifetime of your application, and shows when they executed (green), waited to be synchronized (red), did input/output (purple), or slept idle (blue). The more green lines (or parts thereof) in the graph you see, usually the better. Also, in addition to threads, you will also see two lines at the top monitoring disk reads and writes. If you have more than one disk, then two additional lines are used for each disk.
[Figure 5 - Threads.png]
Again, you can zoom into this graph with your mouse, or alternatively by grabbing the zoom slider at the top. You can also sort the graph from the top-left corner; by default the threads are sorted by start time, but you can also sort by monitored operations or the stop time.
In addition to basic sorting, the Threads graph allows you to move threads to a convenient order using the arrow button at the top. This is useful if you need to compare the performance of two or more threads; being able to place them close to each other, your work is much easier.
When you want to fine-tune into a particular time period, the threads shown in the Threads graph are fully clickable. This means that especially after zooming in close enough, you can see segments in different colors. You can click each of these to see more details about the particular segment. Also note how Visual Studio gives you additional commands below the graph whenever you click a segment.
Whenever you click a segment in the Threads graph, below the graph you can see additional tabs with interesting information. For instance, Visual Studio can display you a so-called Unblocking stack, which gives you information about a thread that allowed another to run. The hints tab is also useful, and the Demystify button gives you more information about a particular feature in the product.
The third major view provided by the Concurrency Visualizer feature is called Cores. Technically speaking, this is not a fully accurate name, as the purpose of the Cores feature is to show how efficiently your application is utilizing the multiple logical processors in the system.
However, the Cores feature will work even if you had multiple physical processors instead of multiple cores. This happens because to the operating system, a physical processor or the multiple cores in them look the same: they all are logical processors on which threads can be executed. But even with this small technical accuracy, the term "core" in this case is reasonably correct, because most systems today in fact are multi-core instead of multi-processor.
The Cores view (see Figure 6) allows you to see on a time-scale, how much work is executed on each of the logical processors on the system. Just as with the other two views, you can zoom in to the Cores graph, and hover the mouse over the timeline to see more details. Each thread on the graph has a different color, and a legend is shown below the graph. Spotting the different colors can be difficult if your application contains dozens of threads, but in most cases, the graph is convenient to use.
[Figure 6 - Cores.png]
Understanding the Graphs
Being able to see detailed information about your threads and how they run is a great addition to the developer toolbox. However, the more complex applications you are writing, the more important it is to be able to understand what the graphics and details mean.
If simplifying things a bit, the most pressing need for today's developers is to make sure the applications can take most out of the multiple cores in contemporary processors. This in itself can be somewhat complex at times, but it gets even more so when you want to make sure your code runs with full throttle. This requires the understanding of different performance bottlenecks, and how they manifest themselves in the different profiling graphs shown by Microsoft Visual Studio.
Fully understanding these graphs would be a topic of another article, but you can get started by a nice little Visual Studio 2010 help topic. This topic is titled "Common Patterns for Poorly-Behaved Multithreaded Applications", and can be found online on MSDN documentation. Or, if you have a locally installed documentation using the new enabled-using-a-local-web-server help, then the URL is of the format
http://127.0.0.1:45678/help/1-960/ms.help?Product=VS&ProductVersion=100&query=vs.cv.threads.tools.gallery. Remember to change the port number 45678 to the one used by your system!
In this article, you learned what the new Visual Studio 2010 feature called Concurrency Visualizer is, and what kind of information it can give. Additionally, you learned that you will need at least the Premium version of Microsoft Visual Studio to use the feature, and even with a Premium edition, you need to be using at least Windows Vista.
Especially if you are using the Task Parallel Library (TPL) and/or Parallel LINQ (PLINQ) to thread your applications, then you will greatly benefit from the new debugging and profiling features available in Microsoft Visual Studio 2010. For example, by combining the new Parallel Stacks and Parallel Tasks windows with the Concurrency Visualizer, it is easier than ever to make sure your applications take the best out of modern multi-core processors.
Enjoy Visual Studio 2010!