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
A SysAdmin's Guide to Change Management
 In the first in a series of monthly articles, ‘Confessions of a Sys Admin’, Matt describes the issues... Read more...

Exchange: Recovery Storage Groups
 It can happen at any time: You get a request, as Admin, from your company, to provide the contents of... Read more...

Build Your Own Virtualized Test Lab
 Desmon explains the fundamentals of building a test lab for Windows servers and Enterprise applications... Read more...

Rendering Hierarchical Data with the Treeview
 It sometimes happens that Web Server controls that visualize data don't quite fit with the way that... Read more...

SQL Server 2008: Performance Data Collector
 With Performance Data Collector in SQL Server 2008, you can now store performance data from a number of... Read more...