Damon Armstrong

Caffeine Induced Tirades about .NET and Life
And don't forget to check out my latest Simple-Talk articles
Add to Technorati Favorites      Add to Google     

Simple Code Performance Testing

Published Friday, August 24, 2007 3:44 PM

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 iterationsTestingMethodDelegate testingMethod)
        
{
            Iterations 
iterations;
            
long startTimeendTime;
            
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(iterationsnew TestingMethodDelegate(TestMethodA));
            
Console.WriteLine(timer.IterationsPerMillisecond);
            
            
//Run TestB
            
timer.Run(iterationsnew 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 0iterationsi++)
            
{
                s.Append
("A");
            
}
        }

        
/// <summary>
        ///   Direct concatenation
        /// </summary>
        
static void TestMethodB(int iterations)
        
{
            
string "";
            
for (int 0iterationsi++)
            
{
                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. 

by Damon
Filed Under:

Comments

No Comments
You need to sign in to comment on this blog

















<August 2007>
SuMoTuWeThFrSa
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678
Creating Technical Presentations
 Making a technical presentation is like being interviewed. It is not a skill that you are likely to... Read more...

Go With the Flow
 Knowing enough about the routes that messages take is vital to being an effective Exchange admin,... Read more...

Policy-Based Management
 Every DBA knows the frustration of trying to manage tens of servers, each of which has a subtly... Read more...

When Email Collaboration Could Have Changed History
 In our mission to make history relevant to the busy IT executive, we speculate how Email might have... Read more...

Bunnikins!
 When an IT manager is selected as a victim of office politics of a large corporate, it is time for him... Read more...