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
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