Simple Code Performance Testing

After posting Performance: Caching vs. Reading from an In-Memory XML Document, there have been some questions about how I actually do the performance testing.  My approach to performance testing is really simple… I just write some code, run that code in a big for loop, and time how long it takes to run through all of those iterations.  Nothing too complicated.  Calculating the speed of the operation becomes a simple matter of (iterations / time).  I’ve packaged this testing routine into a class I call the PerformanceTimer class, which simplifies things even more.  The code for the class follows, and an example of how to use the class to test a routine follows even further down.


using System;

namespace Rebel.Performance
{
    /// <summary>
    ///   Delegate to a testing method
    /// </summary>
    public delegate void TestingMethodDelegate(int iterations);

    /// <summary>
    ///   Executes a testing method and stores execution duration
    /// </summary>
    public class PerformanceTimer
    {
        /// <summary>
        ///   Property backer for the ExecutionSpan property
        /// </summary>
        private TimeSpan _propExecutionSpan;
        
        /// <summary>
        ///   Property backer for the Iterations property
        /// </summary>
        private int _propIterations;

        /// <summary>
        ///   Duration of testing method execution
        /// </summary>
        public TimeSpan ExecutionSpan
        {
            get { return _propExecutionSpan; }
            private set { _propExecutionSpan = value; }
        }

        /// <summary>
        ///   Number of iterations for the test
        /// </summary>
        public int Iterations
        {
            get { return _propIterations; }
            private set { _propIterations = value; }
        }

        /// <summary>
        ///   Executes testing method and determines execution duration
        /// </summary>
        /// <param name=”testingMethod”>Delegate to the testing method</param>
        public void Run(int iterations, TestingMethodDelegate testingMethod)
        {
            Iterations = iterations;
            long startTime, endTime;
            startTime = DateTime.Now.Ticks;
            testingMethod.Invoke(Iterations);
            endTime = DateTime.Now.Ticks;
            ExecutionSpan = new TimeSpan(endTime – startTime);
        }

        /// <summary>
        ///   Number of iterations per second
        /// </summary>
        public double IterationsPerSecond
        {
            get
            {
                return (Iterations / ExecutionSpan.TotalSeconds);
            }
        }

        /// <summary>
        ///   Number of iterations per millisecond
        /// </summary>
        public double IterationsPerMillisecond
        {
            get
            {
                return (Iterations / ExecutionSpan.TotalMilliseconds);
            }
        }

    } //class

} //namespace


So that’s the class, but how do you use it?  Here’s a simple test application that uses the PerformanceTimer class to check the speed of concatenation operations.  You’ve always heard that using a StringBuilder to build a string is faster than repeatedly concatenating a string directly?  Here’s a chance to actually prove it.   


using System;
using System.Text;
using Rebel.Performance;

namespace Rebel.PerformanceTest
{
    /// <summary>
    ///   Console Application
    /// </summary>
    class Program
    {

        static void Main(string[] args)
        {
            PerformanceTimer timer = new PerformanceTimer();
            int iterations = 100000;

            //Run TestA
            timer.Run(iterations, new TestingMethodDelegate(TestMethodA));
            Console.WriteLine(timer.IterationsPerMillisecond);
            
            //Run TestB
            timer.Run(iterations, new TestingMethodDelegate(TestMethodB));
            Console.WriteLine(timer.IterationsPerMillisecond);

            Console.ReadLine();

        }
        
        /// <summary>
        ///   Concatenation using a StringBuilder
        /// </summary>
        static void TestMethodA(int iterations)
        {
            StringBuilder s = new StringBuilder();
            for (int i = 0; i < iterations; i++)
            {
                s.Append(“A”);
            }
        }

        /// <summary>
        ///   Direct concatenation
        /// </summary>
        static void TestMethodB(int iterations)
        {
            string s = “”;
            for (int i = 0; i < iterations; i++)
            {
                s += “A”;
            }
        }

    } //class

} //namespace


WARNING: You will want to use as large of an iteration count as possible when testing.  This performance testing approach does the “best” it can when calculating exact start and end times, so some fluctuations are bound to occur when capturing the start and end times.  When they do, the fluctuations throw off the calculations.  Larger iteration counts spread out the effect of the fluctuations and minimize the error.  Think of it this way:  if you are off by 1 in 10, then you have a 10% error.  If you are off by 1 in 10000, you have a 0.01% error.


On my machine, the StringBuilder operates at 14629 iterations / second and the direct concatenation approach runs at 13 iterations / second.  Pretty significant difference.