C# class useful for timing the duration of an algorithm.
/******************************************************************************
Module: OperationTimer.cs
Notices: Copyright (c) 2006-2010 by Jeffrey Richter and Wintellect
******************************************************************************/
using System;
using System.Threading;
using System.Diagnostics;
/// <summary>
/// This class is useful for timing the duration of an algorithm
/// </summary>
public sealed class OperationTimer : IDisposable
{
private static Int32 s_NumOperationTimersStarted;
private Stopwatch m_sw;
private String m_text;
private Int32 m_collectionCount;
/// <summary>
/// Constructs an OperationTimer with an empty text string
/// </summary>
public OperationTimer() : this(String.Empty) { }
/// <summary>
/// Constructs an OperationTimer with text identifying the operation
/// </summary>
/// <param name="text">Text describing the operation.</param>
public OperationTimer(String text)
{
if (Interlocked.Increment(ref s_NumOperationTimersStarted) == 1)
{
PrepareForOperation();
}
m_text = text;
m_collectionCount = GC.CollectionCount(0);
m_sw = Stopwatch.StartNew(); // This should be the last statement in this method
}
/// <summary>
/// Call this when the operation is done to see how long it took and how many GCs occurred.
/// </summary>
public void Dispose()
{
//
// Console.WriteLine("{0,7:N0} (GCs={1,3}) {2}",
// m_sw.Elapsed.TotalMilliseconds,
// GC.CollectionCount(0) - m_collectionCount, m_text);
// >> 2,611 (GCs= 3) List<String>
// >> 3,001 (GCs= 1) ArrayList of String
Console.WriteLine(" {0} (GCs={1:0##}) {2}",
(m_sw.Elapsed),
GC.CollectionCount(0) - m_collectionCount, m_text);
// >> 00:00:02.4570664 (GCs= 3) List<String>
// >> 00:00:02.9909267 (GCs= 1) ArrayList of String
Interlocked.Decrement(ref s_NumOperationTimersStarted);
m_sw = null;
}
private static void PrepareForOperation()
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
//////////////////////////////// End of File //////////////////////////////////
// Example Usage:
public static class Performance
{
public static void ValueTypePerfTest()
{
const Int32 count = 100000000;
using(new OperationTimer("List<Int32>"))
{
List<Int32> l = new List<Int32>();
for (Int32 n = 0; n < count; n++)
{
l.Add(n); // No boxing
Int32 x = l[n]; // No unboxing
}
l = null; // Make sure this gets GC'd
}
using(new OperationTimer("ArrayList of Int32"))
{
ArrayList a = new ArrayList();
for (Int32 n = 0; n < count; n++)
{
a.Add(n); // Boxing
Int32 x = (Int32)a[n]; // Unboxing
}
a = null; // Make sure this gets GC'd
}
}
public static void ReferenceTypePerfTest()
{
const Int32 count = 100000000;
using(new OperationTimer("List<String>"))
{
List<String> l = new List<String>();
for (Int32 n = 0; n < count; n++)
{
l.Add("X"); // Reference copy
String x = l[n]; // Reference copy
}
l = null; // Make sure this gets GC'd
}
using(new OperationTimer("ArrayList of String"))
{
ArrayList a = new ArrayList();
for (Int32 n = 0; n < count; n++)
{
a.Add("X"); // Reference copy
String x = (String)a[n]; // Cast check & reference copy
}
a = null; // Make sure this gets GC'd
}
}
}
//
// Run performance in console...
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine("ReferenceTypePerfTest...\n");
Performance.ReferenceTypePerfTest();
Console.WriteLine("\nDone.\n");
Console.WriteLine("ValueTypePerfTest...\n");
Performance.ValueTypePerfTest();
Console.WriteLine("\nDone.\n");
}
}
// -------------------------------------------------------------------
// Console output
// -------------------------------------------------------------------
// >> ReferenceTypePerfTest...
// >>
// >> 00:00:02.4570664 (GCs=003) List<String>
// >> 00:00:02.9909267 (GCs=001) ArrayList of String
// >>
// >> Done.
// >>
// >> ValueTypePerfTest...
// >>
// >> 00:00:00.8276096 (GCs=003) List<Int32>
// >> 00:00:06.9304192 (GCs=568) ArrayList of Int32
// >>
// >> Done.