Click here to Skip to main content
15,881,172 members
Articles / Desktop Programming / MFC
Article

CCPUTicker v1.22 - Precision Timing

Rate me:
Please Sign up or sign in to vote.
4.44/5 (10 votes)
3 Mar 2000 154.7K   2.1K   45   19
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 <a href="#Usage">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:

    License

    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


    Written By
    United States United States
    This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

    Comments and Discussions

     
    GeneralLaptops and Processor load speed adjustment Pin
    ndl9-Jun-09 7:15
    ndl9-Jun-09 7:15 
    There is a problem in using this class with laptops and some desktops that have their power management scheme configured to adjust processor speed based on load. If the clock speed is reduced or increased by the power management system, the class methods return incorrect time values. I believe disabling processor speed changes before using this class would solve the problem. Anyone know the "correct" way to do this, and how to set it back?

    Neil
    Answer!! OUTDATED CODE - Don't use it anymore!! Pin
    Elmue20-Sep-10 15:06
    Elmue20-Sep-10 15:06 
    QuestionCWinthread Problems? Pin
    AAntix4-Mar-03 17:38
    AAntix4-Mar-03 17:38 
    AnswerRe: CWinthread Problems? Pin
    pjnaughter5-Mar-03 7:04
    pjnaughter5-Mar-03 7:04 
    GeneralRe: CWinthread Problems? Pin
    AAntix6-Mar-03 22:48
    AAntix6-Mar-03 22:48 
    GeneralSystem time manipulation Pin
    13-Feb-02 5:46
    suss13-Feb-02 5:46 
    GeneralRe: System time manipulation Pin
    5-Jul-02 17:15
    suss5-Jul-02 17:15 
    Generalgenerate calender Pin
    Rizwan Ali21-Jun-01 17:58
    Rizwan Ali21-Jun-01 17:58 
    Questionhow to delay 0.00002 second Pin
    26-Apr-01 5:37
    suss26-Apr-01 5:37 
    AnswerRe: how to delay 0.00002 second Pin
    7-May-01 23:10
    suss7-May-01 23:10 
    Questionhow to delay 0.00002 second Pin
    26-Apr-01 5:37
    suss26-Apr-01 5:37 
    AnswerRe: how to delay 0.00002 second Pin
    11-Jun-01 1:52
    suss11-Jun-01 1:52 
    GeneralHard drive performance monitoring Pin
    Steve Portly20-Sep-00 5:40
    sussSteve Portly20-Sep-00 5:40 
    GeneralHard drive performance monitoring Pin
    Steve Portly20-Sep-00 5:39
    sussSteve Portly20-Sep-00 5:39 
    Generalreturn type of CCPUTicker::Measure() Pin
    Rufus V. Smith17-May-00 6:23
    sussRufus V. Smith17-May-00 6:23 
    GeneralRe: return type of CCPUTicker::Measure() Pin
    pjnaughter17-May-00 10:59
    pjnaughter17-May-00 10:59 
    QuestionWhat about Win32 HighResolutionTimer Pin
    Christian Rodemeyer15-Mar-00 0:44
    professionalChristian Rodemeyer15-Mar-00 0:44 
    AnswerRe: What about Win32 HighResolutionTimer Pin
    pjnaughter16-May-00 13:45
    pjnaughter16-May-00 13:45 
    GeneralRe: What about Win32 HighResolutionTimer Pin
    Rufus V. Smith17-May-00 6:34
    sussRufus V. Smith17-May-00 6:34 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.