Programming Tips & Tricks

Home Categories: C# | C++ | General | Other

C# Tips & Tricks: Measuring Performance with the Stopwatch class

When you first start learning C#, your book or tutorial will propably introduce you to the DateTime and TimeSpan classes early on, so that when you come into a situation where you want to measure the speed of your code, you will be inclined to use these classes to accomplish your goal, with code like
DateTime t1 = DateTime.Now;
MyFunction();
TimeSpan elapsed = DateTime.Now - t1;
double elapsedMS = elapsed.TotalMilliseconds;
where you take the current DateTime, run the method whose performance you want to measure, take the current time again, and subtract the inital time to get a TimeSpan object representing the length of time your function took to execute.

Unfortunately, this method only gives a good measure of performance when the method you're measuring has a long run time (a second or longer), since DateTime.Now uses the system timer, which only has a resolution of about 10 milliseconds, meaning that if your method completes in less then 10 milliseconds, the elapsedMS variable above might return 0, telling you nothing about how long your method actually took to complete.

Luckily since .Net 2.0, there is a better alternative to DateTime.Now: the Stopwatch class in the System.Diagnostics namespace. This class was, as the name implies, designed for performance measuring, and uses your computer's high-resolution performance counter, which usually has a resolution of less than one microsecond.

To rewrite the above code to use the Stopwatch class is easy:
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
MyFunction();
watch.Stop();
double elapsedMS = watch.ElapsedMilliseconds;
the code is pretty self-explanatory: you start the stopwatch, execute your function, stop it and look at the number of elapsed milliseconds. If your function is short, you might want to use something more accurate than milliseconds, in which case you can use watch.ElapsedTicks, which is the number of ticks (smallest unit of time the high-res performance counter can measure) that has elapsed. You can get the number of ticks per second via the static Stopwatch.Frequency.
To get the elapsed time in seconds (and fractions of seconds), you can compute it like this:
double elapsedSeconds = (double)watch.ElapsedTicks / (double)System.Diagnostics.Stopwatch.Frequency;
Some additional notes to Stopwatch: First, you don't need to call Stop before querying ElapsedTicks or ElapsedMilliseconds. You can just let it run and query it multiple times, if for example you want to measure multiple functions in a row individually. And secondly, if you call Stop() and then Start() again, the count of ElapsedTicks/Milliseconds will start at the value it was when Stop was called. To start anew, you first have to set the value to 0 with a call to watch.Reset().

And finally a disclaimer: with both of the above methods, you are only measuring 'real' time elapsed, which includes time spent by the system in other threads or processes, and might thus be more than the actual execution time of the function you're measuring. Unfortunately there is no managed way (that i know of) to measure the time spent in your application and thread alone, excluding time spent in other threads, processes or the kernel. Because of this you should make sure that you have no other cpu-consuming programs running while you run your benchmarks, and you should measure each function multiple times and take an average (even better: call each function you want to measure once before actually measuring it. This should be done because the C# JIT compiler will often compile .Net bytecode to actual executable code only when it enters a code block for the first time. So the first call to a method might take longer to execute than all subsequent calls (unless you compiled to native with ngen.exe).
To measure actual execution time for your function alone, you need to use a profiler, or you need to leave the managed environment by using P/Invoke to GetThreadTimes. This enables you to get the time spent by the cpu in the current thread, but unfortunately restricts you to the low system timer accuracy again. Look here for an example of implementing a Stopwatch class with GetThreadTimes.