Friday, June 29, 2012

Measure C# Code Performance

Conscious developers always try to squeeze another millisecond or two of their code's execution time. But in order to know whether their code's performance has actually improved or not, they should be able to measure the the time their code has worked. Many developers use the DateTime.Now property for this purpose, but it has one major flaw - it is not very accurate. The most precise method to measure elapsed time in the .NET framework is the Stopwatch class.

To measure the execution time of a given code fragment using a stopwatch we can use the following piece of code:

Stopwatch s = Stopwatch.StartNew();
// Tested code here
s.Stop();

But there's one more problem. Doing only one test does not guarantee that we will get an accurate time of the code execution as another task may occupy the CPU or slow down the system at the time we took our measurement and it may not be precise enough. A good solution to this problem is to repeat the test many times, then remove the best and the worst times and calculate the average of the rest of the times. The following piece of code demonstrates how to do this:

const int repetitions = 1000;
long[] times = new long[repetitions];

for (int i = 0; i < repetitions; i++)
{
    Stopwatch stopwatch = Stopwatch.StartNew();

    // TO DO: tested code here

    stopwatch.Stop();
    times[i] = stopwatch.ElapsedMilliseconds;
}

/// Sort the elapsed times for all test runs
Array.Sort(times);

// Calculate the total times discarding
// the 5% min and 5% max test times
long totalTime = 0;
int discardCount = (int)Math.Round(repetitions * 0.05);
int count = repetitions - discardCount;
for (int i = discardCount; i < count; i++)
{
    totalTime += times[i];
}

double averageTime = ((double)totalTime) / (count - discardCount);
Console.WriteLine("Average time: {0:N2} ms", averageTime);

All you have to do is to replace the "TO DO" comment (the one in bold) with the code you want to test.

See also:

1 comment:

  1. Depending on the number of milliseconds, if this is less than 0 you might try .ElapsedTicks instead

    ReplyDelete