My tool of choice for finding out how long a piece of code executes is the
System.Diagnostics.Stopwatch
. In many cases (mostly utility console applications), I can add one, use it, and report its Elapsed time very easily. But last week, I needed to investigate some convoluted code that I didn't write. I needed to time several different areas without affecting the structure of the classes and then remove my code when I was done.
I also wanted a count of how many times the
Stopwatch
was started, so I wrapped a
Stopwatch
in a very simple class:
namespace PIEBALD.Types
{
public class Stopwatch : System.IDisposable
{
private readonly System.Diagnostics.Stopwatch stopwatch ;
public Stopwatch
(
)
{
this.CountOfStarts = 0 ;
this.stopwatch = new System.Diagnostics.Stopwatch() ;
return ;
}
public virtual ulong CountOfStarts { get ; private set ; }
public virtual System.TimeSpan
Elapsed
{
get
{
return ( this.stopwatch.Elapsed ) ;
}
}
public virtual void
Start
(
)
{
if ( !this.IsRunning )
{
this.CountOfStarts++ ;
this.stopwatch.Start() ;
}
return ;
}
public virtual void
Stop
(
)
{
this.stopwatch.Stop() ;
return ;
}
public virtual void
Dispose
(
)
{
this.Stop() ;
return ;
}
public override string
ToString
(
)
{
return ( System.String.Format
(
"{0} elapsed during {1} period{2}"
,
this.Elapsed
,
this.CountOfStarts
,
this.CountOfStarts==1?"":"s"
) ) ;
}
}
}
I pass through a few other methods as well, but they're less important. The important bit is the
Start
that increments the count, and the
Dispose
that stops the Stopwatch.
Then I wrapped a
Dictionary
in a
static
class:
namespace PIEBALD.Types
{
public static class StopwatchOmatic
{
public static System.Collections.Generic.Dictionary<string,PIEBALD.Types.Stopwatch> Items { get ; private set ; }
static StopwatchOmatic
(
)
{
Items = new System.Collections.Generic.Dictionary<string,PIEBALD.Types.Stopwatch>() ;
return ;
}
public static PIEBALD.Types.Stopwatch
Stopwatch
(
string Name
)
{
PIEBALD.Types.Stopwatch result ;
if ( !Items.TryGetValue ( Name , out result ) )
{
Items [ Name ] = result = new PIEBALD.Types.Stopwatch() ;
}
return ( result ) ;
}
public static PIEBALD.Types.Stopwatch
Start
(
string Name
)
{
PIEBALD.Types.Stopwatch result = Stopwatch ( Name ) ;
result.Start() ;
return ( result ) ;
}
public static System.Collections.Generic.IEnumerable<string>
Results
{
get
{
foreach
(
System.Collections.Generic.KeyValuePair<string,PIEBALD.Types.Stopwatch> p
in
Items
)
{
yield return ( System.String.Format
(
"Stopwatch {0} indicates {1}"
,
p.Key
,
p.Value
) ) ;
}
yield break ;
}
}
}
}
In this way, it's quite simple to wrap some code I want to time like so:
using ( PIEBALD.Types.Stopwatch sw = PIEBALD.Types.StopwatchOmatic.Start ( "Loop 1" ) )
{
/* Some suspicious code */
/* You may also use sw.Stop() in here if your needs require it */
}
Then report the Elapsed times of the various
Stopwatch
es like this:
foreach ( string s in PIEBALD.Types.StopwatchOmatic.Results )
{
System.Console.WriteLine ( s ) ;
}
So adding and removing
Stopwatch
es, ensuring that they
Stop
in case of an Exception, then reporting on them has become much simpler.