/* /////////////////////////////////////////////////////////////////////////////
 * File:        perf.d
 *
 * Purpose:     Performance measurement classes. These classes were ported
 *              over to D from the STLSoft (http://stlsoft.org/) C++ libraries,
 *              which were documented in the article "Win32 Performance
 *              Measurement Option", May 2003 issue of Windows Develper Network
 *              (http://www.windevnet.com/documents/win0305a/).
 *
 * Created      19th March 2004
 * Updated:     18th July 2004
 *
 * www:         http://www.digitalmars.com/
 *
 * Copyright (C) 2004 by Digital Mars
 * All Rights Reserved
 * Written by Matthew Wilson
 * http://www.digitalmars.com
 * License for redistribution is by either the Artistic License in artistic.txt,
 * or the LGPL
 *
 * ////////////////////////////////////////////////////////////////////////// */


/** \file std/perf.d This file contains platform-independent performance classes
 * Source: $(PHOBOSSRC std/_math.d)
 */
module std.perf;

/// \brief Performance counter scope class generating template
///
/// This template declares the class PerformanceCounterScope which manages a
/// performance counter instance, scoping its measurement interval by virtue of
/// its supporting the RAII mechanism.

scope class PerformanceCounterScope(T)
{
    /// \name Construction
    /// @{
    public:
        /// Constructs an instance of the PerformanceCounterScope using a reference
        /// to the parameterising performance counter class, whose measurement is
        /// to be scoped. The measurement interval is commenced with a call to
        /// <b>start()</b> on the managed counter instance.
        this(T counter)
        in
        {
            assert(null !is counter);
        }
        body
        {
            m_counter = counter;

            m_counter.start();
        }
        /// The measurement interval is completed with a call to <b>stop()</b> on the
        /// managed counter instance.
        ~this()
        {
            m_counter.stop();
        }

        /// Calls <b>stop()</b> on the managed counter instance, so that intermediate
        /// timings can be taken.
        void stop()
        {
            m_counter.stop();
        }

        /// Returns a reference to the managed counter instance.
        T counter()
        {
            return m_counter;
        }
    /// @}

    /// \name Members
    /// @{
    private:
        T   m_counter;
    /// @}

    // Not to be implemented
    private:
        this(PerformanceCounterScope rhs);
}

version(Posix)
{

    extern (C)
    {
        private struct timeval
        {
            int tv_sec;    /*!< The number of seconds, since Jan. 1, 1970, in the time value. */
            int tv_usec;   /*!< The number of microseconds in the time value. */
        };
        private struct timezone
        {
            int tz_minuteswest; /*!< minutes west of Greenwich. */
            int tz_dsttime;     /*!< type of dst corrections to apply. */
        };
        private void gettimeofday(timeval *tv, timezone *tz);
    }

    /* ////////////////////////////////////////////////////////////////////////// */

    /// \brief A performance counter that uses the most accurate measurement APIs available on the host machine
    ///
    /// This class attempts to use the high performance hardware counter as its measurement resource, but failing
    /// that it defaults to less accurate resources in order to guarantee that meaningful measurements are always
    /// available to application code
    ///
    /// \ingroup group_synsoft_linux_perf
    class PerformanceCounter
    {
    /// \name Types
    /// @{
    private:
        alias   timeval epoch_type;
    public:
        /// \brief The interval type
        ///
        /// The type of the interval measurement, a 64-bit signed integer
        alias   long    interval_type;

        /// \brief The scope type
        ///
        /// The type with which instances of the counter class can be subject to the RAII mechanism in order
        /// to scope particular measurement intervals
        alias PerformanceCounterScope!(PerformanceCounter)  scope_type;
    /// @}

    /// \name Operations
    /// @{
    public:
        /// \brief Starts measurement
        ///
        /// Begins the measurement period
        void start()
        {
            timezone tz;

            gettimeofday(&m_start, &tz);
        }

        /// \brief Ends measurement
        ///
        /// Ends the measurement period
        void stop()
        {
            timezone tz;

            gettimeofday(&m_end, &tz);
        }
    /// @}

    /// \name Attributes
    /// @{
    public:
        /// \brief The elapsed count in the measurement period
        ///
        /// This represents the extent, in machine-specific increments, of the measurement period
        interval_type periodCount()
        {
            return microseconds;
        }

        /// \brief The number of whole seconds in the measurement period
        ///
        /// This represents the extent, in whole seconds, of the measurement period
        interval_type seconds()
        {
            interval_type   start   =   cast(interval_type)m_start.tv_sec + cast(interval_type)m_start.tv_usec / (1000 * 1000);
            interval_type   end     =   cast(interval_type)m_end.tv_sec   + cast(interval_type)m_end.tv_usec   / (1000 * 1000);

            return end - start;
        }

        /// \brief The number of whole milliseconds in the measurement period
        ///
        /// This represents the extent, in whole milliseconds, of the measurement period
        interval_type milliseconds()
        {
            interval_type   start   =   cast(interval_type)m_start.tv_sec * 1000 + cast(interval_type)m_start.tv_usec / 1000;
            interval_type   end     =   cast(interval_type)m_end.tv_sec   * 1000 + cast(interval_type)m_end.tv_usec   / 1000;

            return end - start;
        }

        /// \brief The number of whole microseconds in the measurement period
        ///
        /// This represents the extent, in whole microseconds, of the measurement period
        interval_type microseconds()
        {
            interval_type   start   =   cast(interval_type)m_start.tv_sec * 1000 * 1000 + cast(interval_type)m_start.tv_usec;
            interval_type   end     =   cast(interval_type)m_end.tv_sec   * 1000 * 1000 + cast(interval_type)m_end.tv_usec;

            return end - start;
        }
    /// @}

    /// \name Members
    /// @{
    private:
        epoch_type  m_start;    // start of measurement period
        epoch_type  m_end;      // End of measurement period
    /// @}
    }

    unittest
    {
        alias PerformanceCounter    counter_type;

        counter_type    counter = new counter_type();

        counter.start();
        volatile for(int i = 0; i < 10000000; ++i)
        {   }
        counter.stop();

        counter_type.interval_type  us1 =   counter.microseconds();
        counter_type.interval_type  ms1 =   counter.milliseconds();
        counter_type.interval_type  s1  =   counter.seconds();

        volatile for(int i = 0; i < 10000000; ++i)
        {   }
        counter.stop();

        counter_type.interval_type  us2 =   counter.microseconds();
        counter_type.interval_type  ms2 =   counter.milliseconds();
        counter_type.interval_type  s2  =   counter.seconds();

        assert(us2 >= us1);
        assert(ms2 >= ms1);
        assert(s2 >= s1);
    }

    /* ////////////////////////////////////////////////////////////////////////// */
}
else version(Windows)
{

    private import std.c.windows.windows;

    /* ////////////////////////////////////////////////////////////////////////// */

    /// \defgroup group_synsoft_win32_perf synsoft.win32.perf
    /// \ingroup group_synsoft_win32
    /// \brief This library provides Win32 Performance facilities

    /* ////////////////////////////////////////////////////////////////////////// */

    /// \brief A performance counter that uses the high performance hardware counter on the host machine
    ///
    /// This class provides high-resolution performance monitoring using the host machine's high performance
    /// hardware counter. This class does not provide meaningful timing information on operating systems
    /// that do not provide a high performance hardware counter.
    ///
    /// \ingroup group_synsoft_win32_perf
    class HighPerformanceCounter
    {
    /// \name Types
    /// @{
    private:
        alias   long    epoch_type;
    public:
        /// \brief The interval type
        ///
        /// The type of the interval measurement, a 64-bit signed integer
        alias   long    interval_type;

        /// \brief The scope type
        ///
        /// The type with which instances of the counter class can be subject to the RAII mechanism in order
        /// to scope particular measurement intervals
        alias PerformanceCounterScope!(HighPerformanceCounter)  scope_type;
    /// @}

    /// \name Construction
    /// @{
    private:
        static this()
        {
            if(!QueryPerformanceFrequency(&sm_freq))
            {
                sm_freq = 0x7fffffffffffffffL;
            }
        }
    /// @}

    /// \name Operations
    /// @{
    public:
        /// \brief Starts measurement
        ///
        /// Begins the measurement period
        void start()
        {
            QueryPerformanceCounter(&m_start);
        }

        /// \brief Ends measurement
        ///
        /// Ends the measurement period
        void stop()
        {
            QueryPerformanceCounter(&m_end);
        }
    /// @}

    /// \name Attributes
    /// @{
    public:
        /// \brief The elapsed count in the measurement period
        ///
        /// This represents the extent, in machine-specific increments, of the measurement period
        interval_type periodCount()
        {
            return m_end - m_start;
        }

        /// \brief The number of whole seconds in the measurement period
        ///
        /// This represents the extent, in whole seconds, of the measurement period
        interval_type seconds()
        {
            return periodCount() / sm_freq;
        }

        /// \brief The number of whole milliseconds in the measurement period
        ///
        /// This represents the extent, in whole milliseconds, of the measurement period
        interval_type milliseconds()
        {
            interval_type   result;
            interval_type   count   =   periodCount();

            if(count < 0x20C49BA5E353F7L)
            {
                result = (count * 1000) / sm_freq;
            }
            else
            {
                result = (count / sm_freq) * 1000;
            }

            return result;
        }

        /// \brief The number of whole microseconds in the measurement period
        ///
        /// This represents the extent, in whole microseconds, of the measurement period
        interval_type microseconds()
        {
            interval_type   result;
            interval_type   count   =   periodCount();

            if(count < 0x8637BD05AF6L)
            {
                result = (count * 1000000) / sm_freq;
            }
            else
            {
                result = (count / sm_freq) * 1000000;
            }

            return result;
        }
    /// @}

    /// \name Members
    /// @{
    private:
        epoch_type              m_start;    // start of measurement period
        epoch_type              m_end;      // End of measurement period
        static interval_type    sm_freq;    // Frequency
    /// @}
    }

    unittest
    {
        alias   HighPerformanceCounter  counter_type;

        counter_type    counter = new counter_type();

        counter.start();
        volatile for(int i = 0; i < 10000000; ++i)
        {   }
        counter.stop();

        counter_type.interval_type  us1 =   counter.microseconds();
        counter_type.interval_type  ms1 =   counter.milliseconds();
        counter_type.interval_type  s1  =   counter.seconds();

        volatile for(int i = 0; i < 10000000; ++i)
        {   }
        counter.stop();

        counter_type.interval_type  us2 =   counter.microseconds();
        counter_type.interval_type  ms2 =   counter.milliseconds();
        counter_type.interval_type  s2  =   counter.seconds();

        assert(us2 >= us1);
        assert(ms2 >= ms1);
        assert(s2 >= s1);
    }

    /* ////////////////////////////////////////////////////////////////////////// */

    /// \brief A low-cost, low-resolution performance counter
    ///
    /// This class provides low-resolution, but low-latency, performance monitoring
    /// and is guaranteed to be meaningful on all operating systems.
    ///
    /// \ingroup group_synsoft_win32_perf
    class TickCounter
    {
    /// \name Types
    /// @{
    private:
        alias   long    epoch_type;
    public:
        /// \brief The interval type
        ///
        /// The type of the interval measurement, a 64-bit signed integer
        alias   long    interval_type;

        /// \brief The scope type
        ///
        /// The type with which instances of the counter class can be subject to the RAII mechanism in order
        /// to scope particular measurement intervals
        alias PerformanceCounterScope!(TickCounter) scope_type;
    /// @}

    /// \name Construction
    /// @{
    public:
    /// @}

    /// \name Operations
    /// @{
    public:
        /// \brief Starts measurement
        ///
        /// Begins the measurement period
        void start()
        {
            m_start = GetTickCount();
        }

        /// \brief Ends measurement
        ///
        /// Ends the measurement period
        void stop()
        {
            m_end = GetTickCount();
        }
    /// @}

    /// \name Attributes
    /// @{
    public:
        /// \brief The elapsed count in the measurement period
        ///
        /// This represents the extent, in machine-specific increments, of the measurement period
        interval_type periodCount()
        {
            return m_end - m_start;
        }

        /// \brief The number of whole seconds in the measurement period
        ///
        /// This represents the extent, in whole seconds, of the measurement period
        interval_type seconds()
        {
            return periodCount() / 1000;
        }

        /// \brief The number of whole milliseconds in the measurement period
        ///
        /// This represents the extent, in whole milliseconds, of the measurement period
        interval_type milliseconds()
        {
            return periodCount();
        }

        /// \brief The number of whole microseconds in the measurement period
        ///
        /// This represents the extent, in whole microseconds, of the measurement period
        interval_type microseconds()
        {
            return periodCount() * 1000;
        }
    /// @}

    /// \name Members
    /// @{
    private:
        uint    m_start;    // start of measurement period
        uint    m_end;      // End of measurement period
    /// @}
    }

    unittest
    {
        alias TickCounter   counter_type;

        counter_type    counter = new counter_type();

        counter.start();
        volatile for(int i = 0; i < 10000000; ++i)
        {   }
        counter.stop();

        counter_type.interval_type  us1 =   counter.microseconds();
        counter_type.interval_type  ms1 =   counter.milliseconds();
        counter_type.interval_type  s1  =   counter.seconds();

        volatile for(int i = 0; i < 10000000; ++i)
        {   }
        counter.stop();

        counter_type.interval_type  us2 =   counter.microseconds();
        counter_type.interval_type  ms2 =   counter.milliseconds();
        counter_type.interval_type  s2  =   counter.seconds();

        assert(us2 >= us1);
        assert(ms2 >= ms1);
        assert(s2 >= s1);
    }

    /* ////////////////////////////////////////////////////////////////////////// */

    /// \brief A performance counter that provides thread-specific performance timings
    ///
    /// This class uses the operating system's performance monitoring facilities to provide timing
    /// information pertaining to the calling thread only, irrespective of the activities of other
    /// threads on the system. This class does not provide meaningful timing information on operating
    /// systems that do not provide thread-specific monitoring.
    ///
    /// \ingroup group_synsoft_win32_perf
    class ThreadTimesCounter
    {
    /// \name Types
    /// @{
    private:
        alias   long    epoch_type;
    public:
        /// \brief The interval type
        ///
        /// The type of the interval measurement, a 64-bit signed integer
        alias   long    interval_type;

        /// \brief The scope type
        ///
        /// The type with which instances of the counter class can be subject to the RAII mechanism in order
        /// to scope particular measurement intervals
        alias PerformanceCounterScope!(ThreadTimesCounter)  scope_type;
    /// @}

    /// \name Construction
    /// @{
    public:
        /// \brief Constructor
        ///
        /// Creates an instance of the class, and caches the thread token so that measurements will
        /// be taken with respect to the thread in which the class was created.
        this()
        {
            m_thread = GetCurrentThread();
        }
    /// @}

    /// \name Operations
    /// @{
    public:
        /// \brief Starts measurement
        ///
        /// Begins the measurement period
        void start()
        {
            FILETIME    creationTime;
            FILETIME    exitTime;

            GetThreadTimes(m_thread, &creationTime, &exitTime, cast(FILETIME*)&m_kernelStart, cast(FILETIME*)&m_userStart);
        }

        /// \brief Ends measurement
        ///
        /// Ends the measurement period
        void stop()
        {
            FILETIME    creationTime;
            FILETIME    exitTime;

            GetThreadTimes(m_thread, &creationTime, &exitTime, cast(FILETIME*)&m_kernelEnd, cast(FILETIME*)&m_userEnd);
        }
    /// @}

    /// \name Attributes
    /// @{
    public:
        /// \name Kernel
        /// @{

        /// \brief The elapsed count in the measurement period for kernel mode activity
        ///
        /// This represents the extent, in machine-specific increments, of the measurement period for kernel mode activity
        interval_type kernelPeriodCount()
        {
            return m_kernelEnd - m_kernelStart;
        }
        /// \brief The number of whole seconds in the measurement period for kernel mode activity
        ///
        /// This represents the extent, in whole seconds, of the measurement period for kernel mode activity
        interval_type kernelSeconds()
        {
            return kernelPeriodCount() / 10000000;
        }
        /// \brief The number of whole milliseconds in the measurement period for kernel mode activity
        ///
        /// This represents the extent, in whole milliseconds, of the measurement period for kernel mode activity
        interval_type kernelMilliseconds()
        {
            return kernelPeriodCount() / 10000;
        }
        /// \brief The number of whole microseconds in the measurement period for kernel mode activity
        ///
        /// This represents the extent, in whole microseconds, of the measurement period for kernel mode activity
        interval_type kernelMicroseconds()
        {
            return kernelPeriodCount() / 10;
        }
        /// @}

        /// \name User
        /// @{

        /// \brief The elapsed count in the measurement period for user mode activity
        ///
        /// This represents the extent, in machine-specific increments, of the measurement period for user mode activity
        interval_type userPeriodCount()
        {
            return m_userEnd - m_userStart;
        }
        /// \brief The number of whole seconds in the measurement period for user mode activity
        ///
        /// This represents the extent, in whole seconds, of the measurement period for user mode activity
        interval_type userSeconds()
        {
            return userPeriodCount() / 10000000;
        }
        /// \brief The number of whole milliseconds in the measurement period for user mode activity
        ///
        /// This represents the extent, in whole milliseconds, of the measurement period for user mode activity
        interval_type userMilliseconds()
        {
            return userPeriodCount() / 10000;
        }
        /// \brief The number of whole microseconds in the measurement period for user mode activity
        ///
        /// This represents the extent, in whole microseconds, of the measurement period for user mode activity
        interval_type userMicroseconds()
        {
            return userPeriodCount() / 10;
        }
        /// @}

        /// \name Total
        /// @{

        /// \brief The elapsed count in the measurement period
        ///
        /// This represents the extent, in machine-specific increments, of the measurement period
        interval_type periodCount()
        {
            return kernelPeriodCount() + userPeriodCount();
        }

        /// \brief The number of whole seconds in the measurement period
        ///
        /// This represents the extent, in whole seconds, of the measurement period
        interval_type seconds()
        {
            return periodCount() / 10000000;
        }

        /// \brief The number of whole milliseconds in the measurement period
        ///
        /// This represents the extent, in whole milliseconds, of the measurement period
        interval_type milliseconds()
        {
            return periodCount() / 10000;
        }

        /// \brief The number of whole microseconds in the measurement period
        ///
        /// This represents the extent, in whole microseconds, of the measurement period
        interval_type microseconds()
        {
            return periodCount() / 10;
        }
        /// @}
    /// @}

    /// \name Members
    /// @{
    private:
        epoch_type  m_kernelStart;
        epoch_type  m_kernelEnd;
        epoch_type  m_userStart;
        epoch_type  m_userEnd;
        HANDLE      m_thread;
    /// @}
    }

    unittest
    {
        alias ThreadTimesCounter    counter_type;

        counter_type    counter = new counter_type();

        counter.start();
        volatile for(int i = 0; i < 10000000; ++i)
        {   }
        counter.stop();

        counter_type.interval_type  us1 =   counter.microseconds();
        counter_type.interval_type  ms1 =   counter.milliseconds();
        counter_type.interval_type  s1  =   counter.seconds();

        volatile for(int i = 0; i < 10000000; ++i)
        {   }
        counter.stop();

        counter_type.interval_type  us2 =   counter.microseconds();
        counter_type.interval_type  ms2 =   counter.milliseconds();
        counter_type.interval_type  s2  =   counter.seconds();

        assert(us2 >= us1);
        assert(ms2 >= ms1);
        assert(s2 >= s1);
    }

    /* ////////////////////////////////////////////////////////////////////////// */

    /// \brief A performance counter that provides process-specific performance timings
    ///
    /// This class uses the operating system's performance monitoring facilities to provide timing
    /// information pertaining to the calling process only, irrespective of the activities of other
    /// processes on the system. This class does not provide meaningful timing information on operating
    /// systems that do not provide process-specific monitoring.
    ///
    /// \ingroup group_synsoft_win32_perf
    class ProcessTimesCounter
    {
    /// \name Types
    /// @{
    private:
        alias   long    epoch_type;
    public:
        /// \brief The interval type
        ///
        /// The type of the interval measurement, a 64-bit signed integer
        alias   long    interval_type;

        /// \brief The scope type
        ///
        /// The type with which instances of the counter class can be subject to the RAII mechanism in order
        /// to scope particular measurement intervals
        alias PerformanceCounterScope!(ProcessTimesCounter) scope_type;
    /// @}

    /// \name Construction
    /// @{
    private:
        /// \brief Class constructor
        ///
        /// Detects availability of the high performance hardware counter, and if
        /// not available adjusts
        static this()
        {
            sm_process = GetCurrentProcess();
        }
    /// @}

    /// \name Operations
    /// @{
    public:
        /// \brief Starts measurement
        ///
        /// Begins the measurement period
        void start()
        {
            FILETIME    creationTime;
            FILETIME    exitTime;

            GetProcessTimes(sm_process, &creationTime, &exitTime, cast(FILETIME*)&m_kernelStart, cast(FILETIME*)&m_userStart);
        }

        /// \brief Ends measurement
        ///
        /// Ends the measurement period
        void stop()
        {
            FILETIME    creationTime;
            FILETIME    exitTime;

            GetProcessTimes(sm_process, &creationTime, &exitTime, cast(FILETIME*)&m_kernelEnd, cast(FILETIME*)&m_userEnd);
        }
    /// @}

    /// \name Attributes
    /// @{
    public:
        /// \name Kernel
        /// @{

        /// \brief The elapsed count in the measurement period for kernel mode activity
        ///
        /// This represents the extent, in machine-specific increments, of the measurement period for kernel mode activity
        interval_type kernelPeriodCount()
        {
            return m_kernelEnd - m_kernelStart;
        }
        /// \brief The number of whole seconds in the measurement period for kernel mode activity
        ///
        /// This represents the extent, in whole seconds, of the measurement period for kernel mode activity
        interval_type kernelSeconds()
        {
            return kernelPeriodCount() / 10000000;
        }
        /// \brief The number of whole milliseconds in the measurement period for kernel mode activity
        ///
        /// This represents the extent, in whole milliseconds, of the measurement period for kernel mode activity
        interval_type kernelMilliseconds()
        {
            return kernelPeriodCount() / 10000;
        }
        /// \brief The number of whole microseconds in the measurement period for kernel mode activity
        ///
        /// This represents the extent, in whole microseconds, of the measurement period for kernel mode activity
        interval_type kernelMicroseconds()
        {
            return kernelPeriodCount() / 10;
        }
        /// @}

        /// \name User
        /// @{

        /// \brief The elapsed count in the measurement period for user mode activity
        ///
        /// This represents the extent, in machine-specific increments, of the measurement period for user mode activity
        interval_type userPeriodCount()
        {
            return m_userEnd - m_userStart;
        }
        /// \brief The number of whole seconds in the measurement period for user mode activity
        ///
        /// This represents the extent, in whole seconds, of the measurement period for user mode activity
        interval_type userSeconds()
        {
            return userPeriodCount() / 10000000;
        }
        /// \brief The number of whole milliseconds in the measurement period for user mode activity
        ///
        /// This represents the extent, in whole milliseconds, of the measurement period for user mode activity
        interval_type userMilliseconds()
        {
            return userPeriodCount() / 10000;
        }
        /// \brief The number of whole microseconds in the measurement period for user mode activity
        ///
        /// This represents the extent, in whole microseconds, of the measurement period for user mode activity
        interval_type userMicroseconds()
        {
            return userPeriodCount() / 10;
        }
        /// @}

        /// \name Total
        /// @{

        /// \brief The elapsed count in the measurement period
        ///
        /// This represents the extent, in machine-specific increments, of the measurement period
        interval_type periodCount()
        {
            return kernelPeriodCount() + userPeriodCount();
        }

        /// \brief The number of whole seconds in the measurement period
        ///
        /// This represents the extent, in whole seconds, of the measurement period
        interval_type seconds()
        {
            return periodCount() / 10000000;
        }

        /// \brief The number of whole milliseconds in the measurement period
        ///
        /// This represents the extent, in whole milliseconds, of the measurement period
        interval_type milliseconds()
        {
            return periodCount() / 10000;
        }

        /// \brief The number of whole microseconds in the measurement period
        ///
        /// This represents the extent, in whole microseconds, of the measurement period
        interval_type microseconds()
        {
            return periodCount() / 10;
        }
        /// @}
    /// @}

    /// \name Members
    /// @{
    private:
        epoch_type      m_kernelStart;
        epoch_type      m_kernelEnd;
        epoch_type      m_userStart;
        epoch_type      m_userEnd;
        static HANDLE   sm_process;
    /// @}
    }

    unittest
    {
        alias ProcessTimesCounter   counter_type;

        counter_type    counter = new counter_type();

        counter.start();
        volatile for(int i = 0; i < 10000000; ++i)
        {   }
        counter.stop();

        counter_type.interval_type  us1 =   counter.microseconds();
        counter_type.interval_type  ms1 =   counter.milliseconds();
        counter_type.interval_type  s1  =   counter.seconds();

        volatile for(int i = 0; i < 10000000; ++i)
        {   }
        counter.stop();

        counter_type.interval_type  us2 =   counter.microseconds();
        counter_type.interval_type  ms2 =   counter.milliseconds();
        counter_type.interval_type  s2  =   counter.seconds();

        assert(us2 >= us1);
        assert(ms2 >= ms1);
        assert(s2 >= s1);
    }

    /* ////////////////////////////////////////////////////////////////////////// */

    /// \brief A performance counter that uses the most accurate measurement APIs available on the host machine
    ///
    /// This class attempts to use the high performance hardware counter as its measurement resource, but failing
    /// that it defaults to less accurate resources in order to guarantee that meaningful measurements are always
    /// available to application code
    ///
    /// \ingroup group_synsoft_win32_perf
    class PerformanceCounter
    {
    /// \name Types
    /// @{
    private:
        alias   long    epoch_type;
    public:
        /// \brief The interval type
        ///
        /// The type of the interval measurement, a 64-bit signed integer
        alias   long    interval_type;

        /// \brief The scope type
        ///
        /// The type with which instances of the counter class can be subject to the RAII mechanism in order
        /// to scope particular measurement intervals
        alias PerformanceCounterScope!(PerformanceCounter)    scope_type;
    /// @}

    /// \name Constructors
    /// @{
    private:
        /// \brief Class constructor
        ///
        /// Detects availability of the high performance hardware counter, and if
        /// not available adjusts
        static this()
        {
            if(QueryPerformanceFrequency(&sm_freq))
            {
                sm_fn   =   &_qpc;
            }
            else
            {
                sm_freq =   1000;
                sm_fn   =   &_qtc;
            }
        }
    /// @}

    /// \name Operations
    /// @{
    public:
        /// \brief Starts measurement
        ///
        /// Begins the measurement period
        void start()
        {
            sm_fn(m_start);
        }

        /// \brief Ends measurement
        ///
        /// Ends the measurement period
        void stop()
        {
            sm_fn(m_end);
        }
    /// @}

    /// \name Attributes
    /// @{
    public:
        /// \brief The elapsed count in the measurement period
        ///
        /// This represents the extent, in machine-specific increments, of the measurement period
        interval_type periodCount()
        {
            return m_end - m_start;
        }

        /// \brief The number of whole seconds in the measurement period
        ///
        /// This represents the extent, in whole seconds, of the measurement period
        interval_type seconds()
        {
            return periodCount() / sm_freq;
        }

        /// \brief The number of whole milliseconds in the measurement period
        ///
        /// This represents the extent, in whole milliseconds, of the measurement period
        interval_type milliseconds()
        {
            interval_type   result;
            interval_type   count   =   periodCount();

            if(count < 0x20C49BA5E353F7L)
            {
                result = (count * 1000) / sm_freq;
            }
            else
            {
                result = (count / sm_freq) * 1000;
            }

            return result;
        }

        /// \brief The number of whole microseconds in the measurement period
        ///
        /// This represents the extent, in whole microseconds, of the measurement period
        interval_type microseconds()
        {
            interval_type   result;
            interval_type   count   =   periodCount();

            if(count < 0x8637BD05AF6L)
            {
                result = (count * 1000000) / sm_freq;
            }
            else
            {
                result = (count / sm_freq) * 1000000;
            }

            return result;
        }
    /// @}

    /// \name Implementation
    /// @{
    private:
        alias void function(out epoch_type interval)    measure_func;

        static void _qpc(out epoch_type interval)
        {
            QueryPerformanceCounter(&interval);
        }

        static void _qtc(out epoch_type interval)
        {
            interval = GetTickCount();
        }
    /// @}

    /// \name Members
    /// @{
    private:
        epoch_type              m_start;    // start of measurement period
        epoch_type              m_end;      // End of measurement period
        static interval_type    sm_freq;    // Frequency
        static measure_func     sm_fn;      // Measurement function
    /// @}
    }

    unittest
    {
        alias PerformanceCounter    counter_type;

        counter_type    counter = new counter_type();

        counter.start();
        volatile for(int i = 0; i < 10000000; ++i)
        {   }
        counter.stop();

        counter_type.interval_type  us1 =   counter.microseconds();
        counter_type.interval_type  ms1 =   counter.milliseconds();
        counter_type.interval_type  s1  =   counter.seconds();

        volatile for(int i = 0; i < 10000000; ++i)
        {   }
        counter.stop();

        counter_type.interval_type  us2 =   counter.microseconds();
        counter_type.interval_type  ms2 =   counter.milliseconds();
        counter_type.interval_type  s2  =   counter.seconds();

        assert(us2 >= us1);
        assert(ms2 >= ms1);
        assert(s2 >= s1);
    }

    /* ////////////////////////////////////////////////////////////////////////// */
}
else
{
    const int platform_not_supported = 0;

    static assert(platform_not_supported);
}
