Simplify Time Measurement in Tests and Debug Code
A simple helper class I derived from a more generic pattern: For debugging and testing, I quite often want to measure the time used for a given process. Usually, this looks somewhat like this:
public void TestElapsedTime() { DateTime start = DateTime.Now; //do some work DateTime end = DateTime.Now; double elapsedTime = end.Subtract(start).TotalMilliseconds; Console.Out.WriteLine("Work took {0} milliseconds", elapsedTime); }
However: The code above, while being pretty simple, can be easily wrapped into a generic helper class:
/// <summary> /// A guard that can be used to measure the time /// used for a given process by simply wrapping it /// in a using statement. /// </summary> public class TimeGuard : IDisposable { private readonly Action<double> action; private readonly DateTime startTime; /// <summary> /// Creates the guard with a given action that receives the /// elapsed time in milliseconds. /// </summary> /// <param name="setDelta">The action that is being invoked /// with time (in milleconds) that was taken between construction /// of this instance until disposal.</param> /// <exception cref="ArgumentNullException">If <paramref name="setDelta"/> /// is a null reference.</exception> public TimeGuard(Action<double> setDelta) { if (setDelta == null) throw new ArgumentNullException("setDelta"); action = setDelta; startTime = DateTime.Now; } /// <summary> /// Calculates the elapsed time since construction /// and submits the delta to the <see cref="action"/> /// action. /// </summary> public void Dispose() { var now = DateTime.Now; action(now.Subtract(startTime).TotalMilliseconds); } }
Using the TimeGuard class, I can perform time measurements without having to deal with DateTime instances and the calculation of the elapsed time at all. Two samples:
public void TestElapsedTime() { double elapsedTime = 0; using (new TimeGuard(t => elapsedTime = t)) { //do some work } Console.Out.WriteLine("Work took {0} milliseconds", elapsedTime); }
[Test] public void TestElapsedTime() { using (new TimeGuard(t => Assert.Less(t, 500))) { //do some work here that should take less than 500 ms } }
Apart from providing cleaner code, I also prefer this approach because it encapsulates time measurement functionality in a single class and simplifies adjustments, like using a different pattern to retrieve time stamps, or using the StopWatch class to get a more accurate measurement (thanks to Simone Chiaretta for the hint).
You should use the StopWatch class instead of the DateTime since it’s a more precise timer and doesn’t have the same activation cost that might influence the actual timing.
Simone,
Thanks for your comment – I’ve included a link to the StopWatch class in the article. As a matter of fact, I’m using neither of these – my own implementation relies on a variant of Ayende’s SystemTime class (see link in the article) but I felt the sample in the article is more accessible for most readers.
But that’s the nice thing about encapsulation – it only takes you a few seconds to switch to your own implementation 🙂
Cheers,
Philipp
A very cunning use of IDisposable! I also quite like the way you use an action to invoke an Assert. Very cunning indeed 🙂
Colin E.
thx Colin 🙂
Simone’s already observed that you should use StopWatch (and she’s right). However, if you’re going to stick with DateTime.Now you should really switch it to DateTime.UtcNow. The non-UTC version is hideously slow (use Reflector to look at the code it manages to end up invoking if you don’t believe me).