Welcome to MSDN Blogs Sign in | Join | Help

Historical Debugging in Visual Studio Team System 2010

Historical Debugging in Visual Studio Team System 2010

What is Historical Debugging in a nutshell?

If you’ve been in the development world for any length of time you’ve probably ended up in a situation like one of the following more than a few times.

·         You’ve received reports of a crash from a tester, but on your local box you can’t get the bug to reproduce.

·         You’ve received a crash dump from the tester along with the bug. But the callstack that actually caused the crash was just a cascading effect and you can’t trace the bug back to the root issue.

·         The bug that you are currently working at resolving has an extremely long set of reproduction steps and you just accidentally stepped over the function that is returning bad data.

·         You know that some part of your program is hitting the registry way too often,  but while stepping through all that you see are .Net framework calls and you are unable to isolate which of them is doing all the extra registry work.

With Visual Studio 2010 Team System Editions we are introducing a new Historical Debugger aimed at getting rid of these developer pain points. The Historical Debugger plays a role similar to that of a black box in a plane. We keep track of important points in your programs execution and allow you to play back what happened at those points at a later time. We’re very proud of the current experience that we offer with the Visual Studio debugger so we’ve worked hard to surface all this new historical data in a way that is both useful and consistent with what you would expect from debugging in Visual Studio.

 

A little more depth on the Historical Debugger

In the previous section I’ve mentioned some scenarios that the Historical Debugger is meant to help solve but I’ve not mentioned much about how the Historical Debugger actually works aside from the black box analogy. To get an overview about how the Historical Debugger actually works I’ll do a quick little rundown on what the Historical Debugger collects, when it collects it and how you can view this information after collecting it. I’m going to keep to rather general terms for now, but in later blog posts we’ll dig down deeper into each area and talk more about how to configure and use the Historical Debugger from within Visual Studio.

 

What does the Historical Debugger collect?

Consider what you usually see in Visual Studio when you stop at a breakpoint during your program’s execution. At a basic level, you will probably see a source file with an arrow in the margin indicating where you currently are in program execution. You’ll probably also have access to a window showing your local and watch variables, a window showing your current callstack and some intellisense values for variables in your source code. Also, you might be digging into some more advanced windows like the threads window or the memory window available in the debugger. With a few notable exceptions the basic data that we will be collecting with the Historical Debugger will be a subset of the information normally available to you when doing standard live debugging.

The first thing that might strike you about this is “Isn’t collecting all this information going to slow down debugging my application by some crazy amount?” Trust me when I say that this worry is the proverbial Sword of Damocles that dangles over the head of our team. As big of an issue as this is, I think that we’ve come up with some pretty clever solutions to collect a useful amount of information without perturbing normal debugging patterns (more of these solutions will be mentioned in the “when does the Historical Debugger collect?” section below). A big part of this process was selecting what information is most commonly used during debugging but without picking anything that overly bloats our log files or slows down debugging too much. For starters, every time we stop to collect data we will grab your current code context and the current callstack. Second, we will get the value for any primitive data types that would appear in the locals or watch window at that point, we also get the primitive values for up to one level deep on any objects that would be in the locals or watch windows .Third, to the immense relief of those doing multi-threaded debugging, we will collect the data on the currently active threads.

 

When does the Historical Debugger collect data?

Above, we’ve talked a little about the debugger information that the Historical Debugger collects. But now we need to address how often this information is collected. After all, even if we are collecting a tiny amount of information collecting it too often will quickly lead to your program being slowed down to a halt and generating massive log files. To make Historic Debugging useful we need to provide the user with some solid default settings for how often they collect data and allow for some tweaking to adjust these default values.

When designing the Historical Debugger we based it around two main default levels of data collection. The first level of collection is based around the concept of collecting debugger data at specific points of interest in your program called diagnostic events. Diagnostic events are locations that we have selected as being common points of interest for customers when debugging a managed application. These diagnostic events are selected by Visual Studio and are meant to cover a broad range of programming types. An example diagnostic event that is included with the Historical Debugger would be RegistryKey.SetValue. If this diagnostic event is enabled you well collect a full set of Historical Debugging data every time that RegistryKey.SetValue gets called. These diagnostic events will act like checkpoints when you go back to examine your historical data. We of course allow for you to tweak which sets of diagnostic events will be enabled anytime you are debugging.

We think that we’ve selected diagnostic events that will be useful across a broad range of scenarios, but there will be plenty of times where the area you are interested in debugging after the fact will not have any diagnostic events of interest in it. For this scenario we’ve added an option to also collect debugging data at all method entry points in your program. Also, in this mode we will collect additional data on the parameters that were passed into each method. As would be expected this mode will increase the overhead that the Historical Debugger creates, so be aware of the effect it will have on your applications performance when debugging. Overhead aside, we believe that the data collected in this mode can be very useful especially in that it give a better idea of the shape of your program as opposed to just diagnostic events.

 

How do we show the Historical Debugger information?

For the most part the Historical Debugger information will be shown in the normal debugger windows such as the watch window, the locals window and the thread window that you already know and love. Although as mentioned above we do only collect a subset of total debugger information, so don’t expect to see everything when debugging historically. When you are in the middle of a normal debug session you will be able to just step backward to the most recent diagnostic event (or method enter / callsite if you are collecting them) from there you will be able to move about between the various points that we collected data during your current debugging session. As we dig into the new historical debugging UI in later blog posts I’ll talk more about the features that we’ve integrated into VS to help make this navigation easier.

In addition to being able to move back in time from a normal debugging session you can also save off historical debugging data in a separate .tdlog file and open this later or on another computer. This tdlog file is a key component of what we call the “no repro” scenario, the scenario in which testers pass off a bug to developers but developers are unable to recreate and debugger the error condition locally. We’ve provided integration with Camano (our new standalone test case management tool) and TFS to make it super easy for testers to attach tdlog files to any bugs that they file. Now when developers open up a bug they will be able to also open up the attached tdlog file and debug to any point where historical data was collected to help track down the issue.

 

What’s next?

This goal of this little intro was to tell you the very basics about the how the Historical Debugger works. In the upcoming weeks I’m going to start rolling out more articles that provide in-depth detail about how the Historical Debugger works and about how you can use it from Visual Studio 2010. Expect more pictures of how the UI will actually look and function as well as more samples about how Historical Debugging can help to solve common (and uncommon) programming issues.

 

Published Wednesday, May 13, 2009 4:56 PM by ianhu

Comments

# Anith » Historical Debugging in Visual Studio Team System 2010

# Historical Debugging in Visual Studio Team System 2010

Thank you for submitting this cool story - Trackback from DotNetShoutout

Thursday, May 14, 2009 4:24 AM by DotNetShoutout

# More Information about Historical Debugging in VSTS 2010

IanWho’s blog has a great post about historical debugging in VSTS 2010.  If you are not aware, the

Thursday, May 14, 2009 11:33 PM by Ken's Place

# re: Historical Debugging in Visual Studio Team System 2010

I am trying out the Historical Debugger in VS2010 Beta 1.

I have it turned on in the settings (at least I think I do), but when I try to examine objects the value is:

[Historical Data Has Not Been Collected]

Any Ideas how to get this to show the actual value?

Here is the code in question:

   public partial class Form1 : Form

   {

       public Form1()

       {InitializeComponent();}

       private void button1_Click(object sender, EventArgs e)

       {

           int numer = Int32.Parse(txtNumerator.Text) ;

           int denom = Int32.Parse(txtDemoninator.Text);

           float answer = DivideValues(numer, denom);

           txtAnswer.Text = answer.ToString();

       }

       private static float DivideValues(int numer, int denom)

       {

           float answer = numer / denom;

           return answer;

       }

   }

Sunday, May 24, 2009 1:41 PM by Vaccano

# VSTS Links – 05/26/2009

Larry Guger on Work Items Hands-on Lab Ian Hu on Historical Debugging in Visual Studio Team System 2010

Tuesday, May 26, 2009 8:12 AM by Team System News

# re: Historical Debugging in Visual Studio Team System 2010

Vaccano. Can you give me a little more information about your scenario? Mostly I'm interested in where you are setting your historical context to and what objects you are trying to examine.

Tuesday, May 26, 2009 12:10 PM by IanHu

# Additional Debugging Features in Beta 1

There are a couple other debugging features that are not part of the core debugger, and I won’t be blogging

Thursday, May 28, 2009 5:33 PM by Debugging by Brad Sullivan

# How Does VS2010 Historical Debugging Work?

Visual Studio 2010's Historical Debugging feature fascinates me. As you sit in the debugger, being able

Tuesday, June 16, 2009 2:24 PM by John Robbins' Blog

# Diagnostic Events in Historical Debugging

Diagnostic Events in Historical Debugging If this post is the first time that you have heard about the

Thursday, June 18, 2009 1:18 PM by Historical Debugging with Visual Studio
New Comments to this post are disabled
 
Page view tracker