Tuesday, September 21, 2010

Measure Execution Time with "Using"

To have an instrument measuring code execution time could be very desired when optimization of an application is a high concern. We've seen code doing that, but it's through the way of putting code to record the current time before and after the to-be-measured code block, it then calculates the duration and outputs the result or generating logs. It works. But obviously it is tedious for a developer to implement here there in the code. It also messes up the business code flow by adding time-measuring code snippets. C# language's "using" element provides a clean way to maintain a live instance context without developer caring about disposal of the instance. Is "using" can be used to measure execution time? Yes, I wrote a "watch" and I am "using" the watch measure time. lt looks pretty cute.

The Watch class

using System;
using System.Text;

namespace Instrument
{
public class Watch : IDisposable
{
DateTime _begin;
DateTime _end;

// ref string x; //c# doesn't have ref
//object _ret;
StringBuilder _ret;
public Watch(out StringBuilder ret)
{
ret = new StringBuilder();
_ret = ret;
_begin = DateTime.Now;
}

~Watch()
{
// can not rely on GC's call

}
public void Dispose()
{
_end = DateTime.Now;
_ret.Append((_end - _begin).ToString());
}
}
}


Example of "using" the Watch to measure execution time

StringBuilder span;
#if DEBUG
using (Instrument.Watch wat = new Instrument.Watch( out span))
{
#endif
Console.WriteLine("elapsing...");
Thread.Sleep(1000 * 5);
#if DEBUG
}
#endif
Console.WriteLine(span.ToString());


How it works
Under the hood, "using" creates and disposes an instance without developer writing any code. So I have my Watch implemented Idisposable, when the "using" scope is over, the .Net runtime calls the Dispose method, where the time span is calculated. The execution time of the code part included in "using" block is exactly the time the using scope lives.

Then I need to pass back the result to the caller. Originally I want to pass a reference of a string variable, and assign the result from within the Watch, but it doen't work. As a workaround, I use StringBuilder type, that is a reference type, and there is no warries with it.

To measure execution time is part of optimization. As such, I may want run the function only in development and testing code, without in production, one solution is using conditional compiling, I show it in above code.

No comments: