Find Out What's Taking Your .NET Code So Long to Run
Profiling generally is learning about your code's behavior. A big part of profiling is knowing where your code spends a lot of its time. Although I don't encourage profiling in early development, it can become critical when debugging subsystems that are too slow. It also is a useful technique near the end of a significant subsystem's development, especially if that subsystem performs outside of an acceptable range.
Visual Studio .NET 2005—especially Team Test—has some great tools for profiling, but they are designed to run in the IDE. An auto profiler that stays with your code would allow you to decide when to turn it off and on, even after deployment. This article demonstrates how to employ some useful .NET features like hashtables to build an easy-to-use auto profiler that can time a single statement or your entire application.
Implementing the Timestamp Class
The first step is building a class that tracks start and stop times. You need to know when you began profiling a block of code and the elapsed time since. You can use the DateTime class for start and stop times and incorporate the elapsed-time calculation into this class. Listing 1 shows the Stamp class.
Listing 1: The Stamp Class Contains Start and Stop Times
Friend Class Stamp Private start As DateTime Public Sub New() start = DateTime.Now End Sub Public ReadOnly Property ElapsedTimeString() As String Get Return ElapsedTime.ToString() End Get End Property Public ReadOnly Property StartTime() Get Return start.ToLongTimeString() End Get End Property Public ReadOnly Property ElapsedTime() As TimeSpan Get Return DateTime.Now.Subtract(start) End Get End Property End Class
Implementing the MarkTime Class
To keep the class easy to consume, place most of the work on yourself—the producer. The next class, MarkTime, uses a generic tack of Stamp objects. It constructs the Stamp objects, places them in a Stack, and returns the time stamp. You need something like a Stack here to handle recursion. For example, you could recurse 10 times in the same method, adding 10 starts to the MarkTime stack, before you pop and calculate any of the end times. Listing 2 shows the MarkTime class.
Listing 2: The MarkTime Class Contains a Stack to Handle Recursion
Friend Class MarkTime
Private stack As Stack(Of Stamp) = Nothing Public Sub New() stack = New Stack(Of Stamp)() End Sub Public Function AddStart() As String Dim start As Stamp = New Stamp() stack.Push(start) Return start.StartTime End Function Public Function RemoveStart() As String If (stack.Peek() Is Nothing = False) Then Return stack.Pop().ElapsedTimeString Else Return "" End If End Function End Class