Of the many interesting features shipping in Visual Studio 2013, async-aware debugging is one of the most useful especially for developers who work with asynchronous code. It introduces many changes to the debugging windows that developers were accustomed to in Visual Studio 2012. In this article, I explain the new async debug features and how they help with certain kinds of code, and I dig into the
await keywords in managed code.
Asynchronous Debugging Assistance
C# 5.0 incorporated the new
await modifiers to make it easy to control the asynchronous flows required by the new user experience (UX) for Windows 8 and 8.1 apps. While the language move ahead, the debugging features in Visual Studio 2012 didn't provide all the necessary information for developers to understand the state of the asynchronous code execution and easily find and fix the asynchronous code. Asynchronous code generated responsive apps, but made it difficult for developers to find and fix bugs in their code.
If you aren't familiar with the
await modifiers introduced in C# 5.0, look at Using Asynchronous Methods in ASP.NET 4.5 and in MVC 4 before diving into the new debugging features provided by the combination of Visual Studio 2013 and Windows 8.1. In this article, I assume that you understand the asynchronous programming model and that you have coded at least a simple Windows 8 app. If you still aren't familiar with Windows 8 or 8.1 apps, you can refer to Writing Your First Windows 8 App: The Lay of the Land.
To create Windows 8 or Windows 8.1 apps with Visual Studio 2013, you must run the IDE on Windows 8.1. The new debugging features are available only on that particular stack, so if you haven't upgraded, you are out of luck.
The Enhanced Call Stack Window
When you work with synchronous code, the Call Stack window provides accurate information that allows you to understand the sequence of method calls that has occurred, and how the execution flow arrived at your current location. However, with asynchronous code that executes different pieces of code in diverse tasks, Visual Studio 2012 doesn't provide complete information in the Call Stack window to show how you arrived there.
For example, when code running in a task throws an exception, the task is running in a thread, and the Call Stack window in Visual Studio 2012 shows the information for that specific thread. But there is no information in the Call Stack window about the call stack that you had in that thread, which scheduled the task in another thread. You lose valuable information about the code sequence responsible for creating and scheduling the task and the sequence that was ultimately responsible for launching the code you were trying to debug. You have other Windows that provide valuable information, but the Call Stack window isn't enough. When an exception occurs, the Call Stack window can't tell you which code path triggered the exception. As you chain more asynchronous method calls in your applications, you start missing the way the Call Stack window information is presented when the method calls are synchronous.
The new Call Stack window in Visual Studio 2013 running on top of Windows 8.1 enables you to see where you are and how you got there when you work with asynchronous method calls. It provides similar information to what you would have if the method calls were synchronous. The window displays the frames that existed on the call stack when each task was created. Because you have information about the context of the code sequence that led up to an asynchronous task, you can easily navigate to the frame's source code by double-clicking on the added frames.
Whenever there is an asynchronous call, the Call Stack window shows the additional frames below the task's actual call stack and displays a an annotated frame with the
[Async Call] label to identify them. As you might guess, this causes a performance hit during the debugging session because it is necessary to add frames for each task that the code creates. By default, the maximum number of additional frames that will appear in the Call Stack window is limited to 10 in Debug mode (you will only see the information for the last 10 chained asynchronous calls). When you are in Release mode, the Call Stack window will only display one frame for the last asynchronous call. You can customize the
PPL_TASK_SAVE_FRAME_COUNT macro in the source code to specify the desired number of frames you want the Call Stack window to display.
Figure 1 shows the graph generated by the Code Map debugger for two chained asynchronous calls in a Windows 8.1 app. I'm using the sample application introduced in the recent series of articles on Windows 8 apps development in Dr. Dobb's. The only difference is that, here, I'm debugging the app with Visual Studio 2013 running on top of Windows 8.1. The Code Map debugger allows you to map relationships in code. It is extremely useful for easily debugging asynchronous calls, but it is only available in the Visual Studio Ultimate version. If you have Visual Studio 2013 Ultimate, you simply need to right-click on any Call Stack frame and select Show Call Stack on Code Map to generate the Code Map. In my case, I'm just using it to understand the code that I'm debugging and to see the new Call Stack window frames that are available in all the Visual Studio 2013 versions that support Windows 8.1 apps development.
Figure 1: Two asynchronous calls displayed in Code Map debugger.
OnLaunched method executed the following line to make an asynchronous call to the
RefreshDataSource method executed the following line to make an asynchronous call to the
GetAll method for an instance of the
GroupService class called
var allGroups = await groupService.GetAll();
The debugger has a breakpoint in the
GetAll method. Figure 1 makes it easy to see how you get to the
GetAll method and which were the two asynchronous method calls before you reached your actual position. Figure 2 shows the information displayed by the new Call Stack Window with two additional frames, one for each asynchronous call.
Figure 2: The new Call Stack window displaying the two additional frames that add information about the two asynchronous calls.