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.
Implementing the Timestamp 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
Listing 2: The MarkTime Class Contains a Stack to Handle Recursion
Friend Class MarkTime<o:p>
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
Building the AutoProfiler with a Hashtable
Listing 3: The Implementation of the AutoProfiler Class
Public Class AutoProfiler
Private Shared hash As Hashtable = Nothing
Private Shared output As OutputType = OutputType.Console
Shared Sub New()
hash = New Hashtable
End Sub
Private Shared Function GetKey() As String
Const mask As String = "{0}.{1}"
Dim trace As StackTrace = New StackTrace
Dim method As MethodBase = trace.GetFrame(2).GetMethod()
Return String.Format(mask, _
method.ReflectedType.FullName, method.Name)
End Function
Public Shared Property OutputTo() As OutputType
Get
Return output
End Get
Set(ByVal value As OutputType)
output = value
End Set
End Property
<Conditional("DEBUG")> _
Public Shared Sub Start()
Dim marker As MarkTime = Nothing
Dim key As String = GetKey()
If (hash(key) Is Nothing) Then
marker = New MarkTime()
hash.Add(key, marker)
Else
marker = CType(hash(key), MarkTime)
End If
WriteLine("Started {0} at {1}", key, marker.AddStart())
End Sub
<Conditional("DEBUG")> _
Public Shared Sub Stopp()
Dim marker As MarkTime = Nothing
Dim key As String = GetKey()
If (hash(key) Is Nothing) Then
Throw New ArgumentOutOfRangeException(key, _
"Can't find start time entry")
End If
marker = CType(hash(key), MarkTime)
WriteLine("Stopped: {0}, elapsed time {1}", _
key, marker.RemoveStart())
End Sub
Private Shared Sub WriteLine(ByVal format As String, _
ByVal ParamArray args() As Object)
If (output = OutputType.Console) Then
System.Console.WriteLine(String.Format(format, args))
Else ' debug
System.Diagnostics.Debug.WriteLine( _
String.Format(format, args))
End If
End Sub
End Class
Listing 4: The Complete AutoProfiler Implementation with a Sample Console App
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.IO
Imports System.Reflection
Imports System.Text
Module Module1
Sub Main()
Test()
End Sub
Sub Test()
Profiler.AutoProfiler.Start()
System.Threading.Thread.Sleep(5000)
Profiler.AutoProfiler.Stopp()
Console.ReadLine()
End Sub
End Module
Namespace Profiler
Public Enum OutputType
Console
Debug
Window
End Enum
Public Class AutoProfiler
Private Shared hash As Hashtable = Nothing
Private Shared output As OutputType = OutputType.Console
Shared Sub New()
hash = New Hashtable
End Sub
Private Shared Function GetKey() As String
Const mask As String = "{0}.{1}"
Dim trace As StackTrace = New StackTrace
Dim method As MethodBase = trace.GetFrame(2).GetMethod()
Return String.Format(mask, _
method.ReflectedType.FullName, method.Name)
End Function
Public Shared Property OutputTo() As OutputType
Get
Return output
End Get
Set(ByVal value As OutputType)
output = value
End Set
End Property
<Conditional("DEBUG")> _
Public Shared Sub Start()
Dim marker As MarkTime = Nothing
Dim key As String = GetKey()
If (hash(key) Is Nothing) Then
marker = New MarkTime()
hash.Add(key, marker)
Else
marker = CType(hash(key), MarkTime)
End If
WriteLine("Started {0} at {1}", key, marker.AddStart())
End Sub
<Conditional("DEBUG")> _
Public Shared Sub Stopp()
Dim marker As MarkTime = Nothing
Dim key As String = GetKey()
If (hash(key) Is Nothing) Then
Throw New ArgumentOutOfRangeException(key, _
"Can't find start time entry")
End If
marker = CType(hash(key), MarkTime)
WriteLine("Stopped: {0}, elapsed time {1}", _
key, marker.RemoveStart())
End Sub
Private Shared Sub WriteLine(ByVal format As String, _
ByVal ParamArray args() As Object)
If (output = OutputType.Console) Then
System.Console.WriteLine(String.Format(format, args))
Else ' debug
System.Diagnostics.Debug.WriteLine( _
String.Format(format, args))
End If
End Sub
End Class
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
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
End Namespace
No comments:
Post a Comment