Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CCPUTicker v1.22 - Precision Timing

0.00/5 (No votes)
3 Mar 2000 1  
An ultra high precision MFC timing class for Pentium or greater CPUs.
  • Download source files - 16 Kb
  • Introduction

    Welcome to CCPUTicker, An ultra high precision MFC timing class for Pentium or greater CPU's resolution timing.


    Features
    History
    API Reference
    Usage
    Contacting the Author


    Features

    This class implements an MFC wrapper class for the Pentium-specific time stamp counter which can be accessed using the RDTSC assembly language instruction. This counter has a resolution in terms of PCLKS (processor clocks) so if you have a 200 MHz CPU then this class will give a frequency of 200 MHz. The value returned is a 64 bit integer so assuming your CPU runs at 200 MHZ, the value will take roughly 3000 years to roll over. As the value also starts counting from 0, the value returned is the number of CPU ticks since the computer was turned on i.e. the "UP" time.

    Because the timer is part of the CPU hardware, it is unaffected by processor activity and workload. The class has only been tested on Intel CPU's. Feedback about its behavior on other CPU types would be appreciated. The class can also be used on Windows NT without any problems.

    The class itself was developed originally by J.M.McGuiness and continues to be co-developed by both authors.

    The source zip file contains the CCPUTicker source code and also includes a simple MFC message box based demonstration application which will time the accuracy of a call to the SDK call Sleep(1000) and also report how long your machine has been "Up".


    History

    V1.0 (26 March 1996)

    V1.1 (16 July 1997)

    • Support for running on Windows NT.
    • now uses the built-in 64 bit data type __int64.
    • Improved diagnostic info thanks to the above.
    • Usage of static variables to improve efficiency.
    • Addition of a function which will convert from CPU ticks to seconds.
    • Improved adherence to the MFC coding style and standards.

    V1.2 (14 January 1999)

    • Fixed a bug discovered by David Green-Seed where he was experiencing access violations when the code was compiled with optimizations turned on on a Pentium II. The problem was that (on a PII) the RDTSC instruction touches more registers than expected. This has now been fixed by saving and restoring the EAX and EBX registers around the call to RDTSC.
    • Provision of HTML documentation (this file) for the class.
    • A Visual C++ 5.0 workspace file is now provided as standard.
    • Code now compiles cleanly at warning level 4.
    • General code tidy up of const functions, parameters etc.
    • Sample program now also reports the "Up" time of the computer.

    V1.21 (14 January 1999)

    • No code changes included. Just updated the help file regarding some development notes which may be of interest to the user of CCPUTicker.

    21 January 1999

    • No code changes included. Just updated this file regarding use on SMP machines.

    27 January 1999

    • No code changes included. Just updated this file regarding use on SMP machines.

    v1.22 (3 December 1999)

    • Fixed a problem in when compiling in VC 6 in release mode.


    API Reference

    The API is made of the following public methods of the CCPUTicker class:

    CCPUTicker()
    operator=()
    Measure()
    GetTickCountAsSeconds()
    GetTickCount()
    GetCPUFrequency()
    IsAvailable()
    AssertValid()
    Dump()


    CCPUTicker::CCPUTicker

    CCPUTicker();
    CCPUTicker(const CCPUTicker &ticker);

    Parameters:

    • ticker -- another instance of a CCPUTicker

    Remarks:
    Standard constructor and copy constructor for the class which just initialize some internal variables.


    CCPUTicker::operator=

    CCPUTicker& operator=(const CCPUTicker &ticker);

    Parameters:

    • ticker -- another instance of a CCPUTicker

    Return Value:
    Usual reference to this from a C++ operator= function.

    Remarks:
    Standard operator= for the class.


    CCPUTicker::Measure

    void CCPUTicker::Measure();

    Remarks:
    Calling this function retrieves the current value of the RDTSC counter into this CCPUTicker instance.


    CCPUTicker::GetTickCountAsSeconds

    double GetTickCountAsSeconds() const;

    Return Value:
    The current RDTSC counter value in seconds.

    Remarks:
    Calling this function retrieves the stored value of the RDTSC counter from this instance as seconds. The number of seconds is the "Up" time of the computer. Because the counter is stored in clock ticks, the first time this function is called by any of your code, the processor clock frequency will be estimated using an internal timing routine. Please note that this can appear to hang the current process for up to 20 seconds when this is being performed. Please see the Usage section below for important development notes regarding this function.


    CCPUTicker::GetTickCount

    __int64 CCPUTicker::GetTickCount() const;

    Return Value:
    The current RDTSC counter value in clock ticks.

    Remarks:
    Calling this function retrieves the stored value of the RDTSC counter from this instance as clock ticks. This function is a simple accessor on the value which the class will have obtained on the last call to its Measure method.


    CCPUTicker::GetCPUFrequency

    static BOOL GetCPUFrequency(double& frequency, double& target_ave_dev, unsigned long interval = 1000, unsigned int max_loops = 20) const;

    Parameters:

    • frequency -- Upon successful return, this will contain the processor clock frequency in Hertz.
    • target_ave_dev -- Upon successful return, this will contain the estimated average deviation of the processor clock frequency in Hertz.
    • interval -- Interval in milliseconds for each timing loop.
    • max_loops -- The maximum number of timing loops to use to estimate the processor clock frequency with.

    Return Value:
    TRUE if the CPU frequency was returned successfully, otherwise FALSE. Use GetLastError() to determine the cause if this happens.

    Remarks:
    This function will work out the processor clock frequency to a specified accuracy determined by the target average deviation required. Note that the worst average deviation of the result is less than 5MHz for a mean frequency of 90MHz. So basically the target average deviation is supplied only if you want a more accurate result, it won't let you get a worse one. (Units are Hz.). The average deviation is a better and more robust measure than it's cousin the standard deviation of a quantity. The item determined by each is essentially similar. See "Numerical Recipies", W.Press et al for more details. This function will run for a maximum of 20 seconds by default before giving up on trying to improve the average deviation, with the average deviation actually achieved replacing the supplied target value. Use "max_loops" to change this. To improve the value the function converges to increase "interval" (which is in units of ms, default value=1000ms). Please see the Usage section below for important development notes regarding this function.


    CCPUTicker::IsAvailable

    BOOL IsAvailable() const;

    Return value:
    TRUE if this machine has the "RDTSC" instruction available for timing otherwise FALSE.


    CCPUTicker::AssertValid

    virtual void AssertValid() const;

    Remarks:
    Standard MFC diagnostic function.


    CCPUTicker::Dump

    virtual void Dump(CDumpContext& dc) const;

    Remarks:
    Standard MFC diagnostic function.



    Usage

    The sample app is a simple MFC message box based demonstration which will time the accuracy of a call to the SDK call Sleep(1000) and also report how long your machine has been "Up".

    To use CCPUTicker in your project simply include cputicker.cpp from the test application in your application and #include "cputicker.h" in which ever files you want to use the class.

    The following points should be born in mind when developing code with CCPUTicker:

    Usage on SMP Machines (Symmetric Multiprocessing Machines) i.e. NT with 2 or more CPU's
    Consider the following scenario: we intend to get an idea of how long (real time) something takes by taking two readings of RDTSC, and using the difference/frequency to give us a time reading. Suppose the first reading is taken from CPU0, and the second reading is taken from CPU1 (the process is not necessarily always run on the same CPU). Since the the CPU's RDTSC instructions are separate, the RDTSC on one CPU is not related at all to the RDTSC on the other CPU - so the readings would have no relation at all!. You should work around this problem at your application level. Detecting a SMP machine can be done by calling the GetSystemInfo SDK function and examining the dwNumberOfProcessors in the structure returned. You should also have a look at the SetProcessAffinityMask function to ensure that your code will always run on only a single CPU.

    Re: APM, ACPI, CPU overheating
    On many machines, the clock speed of the CPU can be slowed (and later increased) by these. Thus calculating real time from clock cycles may not be valid. (Suppose the clock was changed between the first and second reading, or suppose that the clock frequency was calculated at one speed, and later it was changed....). Please bear in mind that calls to GetCPUFrequency and GetTickCountAsSeconds are dependent on the CPU frequency being invariant over timer. If the CPU frequency does change over time then anything reported as seconds may not be accurate. If you just want to retrieve the up time of the computer, you should use the GetTickCount SDK function.


    Contacting the Author

    PJ Naughter
    Email: pjn@indigo..ie
    Web:

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here