.NET: HiResTimer class

This simple little C# class wraps Kernel32's QueryPerformanceCounter API.

Usage is straightforward:

HiResTimer hrt = new HiResTimer();

hrt.Start();
DoSomethingLengthy();
hrt.Stop();

Console.WriteLine("{0}", hrt.ElapsedMicroseconds);

The hi-res timer API deals in unsigned, 64-bit (ulong) values, so the problem of rollover (or "lapping") is not really an issue -- even on a box with a 1GHz timer frequency, 500 years will pass by before the counter laps its start position.

However, not all systems support the hi-res timer API (pre-Pentium II? non-Intel?).  The constructor will throw a Win32Exception on those systems.

Finally, because the code must invoke functions in kernel32.dll, it may not be desirable to include in retail components, destined for use in partially-trusted scenarios.  But because it can be somewhat awkward to comment-out all of the references to HiResTimer (4 non-contiguous lines, in the above trivial example!) I've included a handy preprocessor symbol (NOTIMER) to render the class inert.

using System;
using System.Runtime.InteropServices; // for DllImport attribute
using System.ComponentModel; // for Win32Exception class
using System.Threading; // for Thread.Sleep method

namespace Util
{
    class HiResTimer
    {
        // Construction

        public HiResTimer()
        {
#if (!NOTIMER)
            a = b = 0UL;
            if ( QueryPerformanceFrequency( out f) == 0) 
                throw new Win32Exception();
#endif
        }

        // Properties

        public ulong ElapsedTicks
        {
#if (!NOTIMER)
            get
            { return (b-a); }
#else
        get
        { return 0UL; }
#endif
        }

        public ulong ElapsedMicroseconds
        {
#if (!NOTIMER)
            get
            { 
                ulong d = (b-a); 
                if (d < 0x10c6f7a0b5edUL) // 2^64 / 1e6
                    return (d*1000000UL)/f; 
                else
                    return (d/f)*1000000UL;
            }
#else
        get
        { return 0UL; }
#endif
        }

        public TimeSpan ElapsedTimeSpan
        {
#if (!NOTIMER)
            get
            { 
                ulong t = 10UL*ElapsedMicroseconds;
                if ((t&0x8000000000000000UL) == 0UL)
                    return new TimeSpan((long)t);
                else
                    return TimeSpan.MaxValue;
            }
#else
        get
        { return TimeSpan.Zero; }
#endif
        }

        public ulong Frequency
        {
#if (!NOTIMER)
            get
            { return f; }
#else
        get
        { return 1UL; }
#endif
        }

        // Methods

        public void Start()
        {
#if (!NOTIMER)
            Thread.Sleep( 0);
            QueryPerformanceCounter( out a);
#endif
        }

        public ulong Stop()
        {
#if (!NOTIMER)
            QueryPerformanceCounter( out b);
            return ElapsedTicks;
#else
        return 0UL;
#endif
        }

        // Implementation

#if (!NOTIMER)
        [ DllImport("kernel32.dll", SetLastError=true) ]
        protected static extern 
            int QueryPerformanceFrequency( out ulong x);

        [ DllImport("kernel32.dll") ]
        protected static extern 
            int QueryPerformanceCounter( out ulong x);

        protected ulong a, b, f;
#endif
    }
}