Module tsc_time
TSC time library.
Introduction
This module implements a "Time" object that is based on the TSC value of the
x86 processor. This is a monotonically increasing value that is somewhat
dependable (whereas system time may change). It is also very high resolution
and very efficient to retrieve.
This library is designed to be as high-performance as possible. If you use it
correctly, you can ensure your code maintains that high level of performance.
Objects
There are 4 objects in this module all deriving from the base Time object.
They are:
- TSC: TSC value
- Posix: POSIX, seconds since 1970
- uPosix: POSIX, microseconds since 1970
- fPosix: POSIX, floating-point seconds since 1970
Each of these objects are relatively the same. The main difference is when
adding or comparing the objects, they behave as their type describes.
The base Time object defines methods for converting the TSC value to another
type. They are as_posix_sec, as_posix_usec, and as_posix_fsec.
There are a three classes of functions in the module for creating these
objects. The now_* functions compute the current time. The mktime_*
functions convert a Python "time tuple" to a Time object. The *_from_*
functions take a raw value (TSC, Posix, etc.) and create a Time object.
Raw Conversions
The module also provides methods for converting raw values from one type to
another. These are the *_to_* functions, and generally should not be needed
if your code uses Time objects throughout.
Wall Clock Synchronization
When the module is first imported, it captures the current wall-clock time and
TSC value. This information is used for doing conversions between TSC and
Posix time. It is important to call the update_time_relation function
whenever the wall-clock is changed. Also, it is a good idea to call it
periodically to retain accuracy. This is necessary because the library uses
the ticks_per_sec value for conversions. This value is obtained from the
machdep.tsc_freq sysctl, and may be slightly off (my system is about 0.002%
off which is about 10 minutes per year). Long-term computations based on the
ticks_per_sec value should not be trusted to be very accurate.
Accuracy and Precision
The conversion functions use roughly imprecise, but faster integer arithmetic.
The reason it is inaccurate is because it uses the ticks_per_usec value which
is less accurate than ticks_per_sec. To compute the inaccuracy, you can use
the formula:
(1000000 / ticks_per_sec)
This is a rough estimate. On my 3.5 GHz system, this is about 0.027% or about
2.3 hours per year. Slower systems have less accuracy (about 0.09% for a 1 GHz
machine or about 8 hours per year).
To be more accurate, we would either need to use numbers larger than 64 bits
(bignums, Python Longs, 80-bit C doubles, etc.), but it would slow the
conversions down a little (for C doubles it was about 30% slower on my system).
TSC values that are significantly far from the current time should not be
trusted to be very accurate.
External C Access
The C functions in this module are available for direct access from other C
extension modules. For C modules, simply include "tsc_time.h" and call the
initialization function once. For Pyrex modules, include
"tsc_time_include.pyx". See the respective files for more detail.
Signedness
TSC values may be negative (to indicate a time before the computer booted). In
general, this library uses signed data types to avoid signed/unsigned
multiplication/division. A particular exception is the ticks_per_sec value
because it is currently defined as a 32-bit number, and we need to support
machines with CPU's faster than 2GHz.
On most POSIX systems, time_t is a signed 32-bit integer (on some it is a
signed 64-bit integer, whose negative value extends past the beginning of the
universe). In theory, a signed 32-bit value can handle negative values from
1901 to 1970 and 1970 to 2038 positive. Some foolish systems have attempted to
define time_t as an unsigned value to extend the overflow point to 2106, but
this is rare.
Notes
The rate of the TSC value may change on systems with thermal and power
throttling. (though rumor has it some processors adjust the TSC rate when
auto-throttling to ensure it runs at a constant speed). This invalidates
assumptions made in this library, so do not use those features.
On SMP kernels, FreeBSD will synchronize the TSC value on all CPU's at
boot time, and the assumption is made that they will remain roughly in sync.
Rumor has it that some motherboards will attempt to keep the TSC value in
sync on all processors over time. AMD CPU's are rumored to be especially
vulnerable to this.
RDTSC
This is detailed low-level information about the rdtsc instruction that is used
to obtain the TSC value.
rdtsc - ReaD TimeStamp Counter
The cycle counter in the Pentium series of processors is incremented once for
every clock cycle. It starts out as 0 on system boot. It is a 64-bit number,
and thus will wrap over in 292 years on a 2 gigahertz processor. It should
keep counting unless the system goes into deep sleep mode.
FYI, the control registers on the Pentium can be configured to restrict RDTSC
to privileged level 0.
The RDTSC instruction is generally not synchronized. Thus, with out of order
execution, it is possible for it to run ahead of other instructions that came
before it. This is mainly only important if you are trying to do exact
profiling of instruction cycles.
Other Counters
Most x86 systems have other hardware timers. They all have different
frequencies, accuracies, performance characteristics, etc. The following is a
list of alternate counters that we may want to investigate:
- Intel 8254 Interval Timer (i8254). This was introduced in the IBM AT (the
8253 was used in the IBM XT).
- ACPI (Advanced Configuration and Power Interface) counter (ACPI was
introduced around 1996).
- HPET (High Precision Event Timer) introduced by Intel around 2004 as a
replacement to the i8254.
Further Reading
Some interesting papers:
TODO
- Investigate SMP drift over long periods of time.
- Find a way to detect if the current platform has thermal or power
throttling, and whether or not it compensates the TSC rate to remain constant.
- machdep.tsc_freq is a 32-bit unsigned integer. For systems with CPU's faster
that 4 GHz, this is no longer sufficient.
- Get a better (more accurate) value of machdep.tsc_freq. Investigate
CLK_USE_TSC_CALIBRATION, CLK_USE_I8254_CALIBRATION, CLK_CALIBRATION_LOOP in
FreeBSD kernel which use the mc146818A chip. (CLK_USE_TSC_CALIBRATION seems
to have disappeared, but is available in older kernels.)
- Write something that will periodically adjust the ticks_per_sec value to be
more accurate, comparing against the wall clock assuming the wall clock is
adjusted with NTP. See djb's clockspeed for inspiration.
Version:
$Revision: 1.4 $
|
Posix
Time in POSIX seconds.
|
|
TSC
Time in TSC ticks.
|
|
Time
Base time object.
|
|
fPosix
Time in POSIX seconds as a floating-point number.
|
|
uPosix
Time in POSIX microseconds.
|
|
Posix_from_posix_fsec(...)
Convert a raw POSIX floating-point seconds value to a Posix object. |
|
|
|
Posix_from_posix_sec(...)
Convert a raw POSIX seconds value to a Posix object. |
|
|
|
Posix_from_posix_usec(...)
Convert a raw POSIX microseconds value to a Posix object. |
|
|
|
Posix_from_ticks(...)
Convert a raw TSC value to a Posix object. |
|
|
|
TSC_from_posix_fsec(...)
Convert a raw POSIX floating-point seconds value to a TSC object. |
|
|
|
TSC_from_posix_sec(...)
Convert a raw POSIX seconds value to a TSC object. |
|
|
|
TSC_from_posix_usec(...)
Convert a raw POSIX microseconds value to a TSC object. |
|
|
|
TSC_from_ticks(...)
Convert a raw TSC value to a TSC object. |
|
|
|
fPosix_from_posix_fsec(...)
Convert a raw POSIX floating-point seconds value to an fPosix object. |
|
|
|
fPosix_from_posix_sec(...)
Convert a raw POSIX seconds value to an fPosix object. |
|
|
|
fPosix_from_posix_usec(...)
Convert a raw POSIX microseconds value to an fPosix object. |
|
|
|
fPosix_from_ticks(...)
Convert a raw TSC value to an fPosix object. |
|
|
|
fsec_to_ticks(...)
Convert POSIX seconds (a floating-point number) to ticks. |
|
|
|
|
|
mktime_posix_fsec(...)
Convert a Python time-tuple to an fPosix object. |
|
|
|
mktime_posix_sec(...)
Convert a Python time-tuple to a Posix object. |
|
|
|
mktime_posix_usec(...)
Convert a Python time-tuple to a uPosix object. |
|
|
|
mktime_tsc(...)
Convert a Python time-tuple to a TSC object. |
|
|
|
now_posix_fsec(...)
Return an fPosix object of the current time. |
|
|
|
now_posix_sec(...)
Return a Posix object of the current time. |
|
|
|
now_posix_usec(...)
Return a uPosix object of the current time. |
|
|
|
now_raw_posix_fsec(...)
Get the current time as raw POSIX floating-point seconds. |
|
|
|
now_raw_posix_sec(...)
Get the current time as raw POSIX seconds. |
|
|
|
now_raw_posix_usec(...)
Get the current time as raw POSIX microseconds. |
|
|
|
now_raw_tsc(...)
Get the current time as raw ticks. |
|
|
|
now_tsc(...)
Return a TSC object of the current time. |
|
|
|
rdtsc(...)
Return the current TSC value. |
|
|
|
|
|
set_time(...)
Emulate setting the system time to the given timestamp. |
|
|
|
step_time(...)
Emulate changing the system time by the given number of seconds. |
|
|
|
ticks_to_fsec(...)
Convert ticks to POSIX seconds (a floating-point number). |
|
|
|
ticks_to_sec(...)
Convert ticks to POSIX seconds (an integer). |
|
|
|
|
|
|
|
uPosix_from_posix_fsec(...)
Convert a raw POSIX floating-point seconds value to a uPosix object. |
|
|
|
uPosix_from_posix_sec(...)
Convert a raw POSIX seconds value to a uPosix object. |
|
|
|
uPosix_from_posix_usec(...)
Convert a raw POSIX microseconds value to a uPosix object. |
|
|
|
uPosix_from_ticks(...)
Convert a raw TSC value to a uPosix object. |
|
|
|
|
|
|
|
|
|
__package__ = ' coro.clocks '
|
|
__test__ = { }
|
|
_extern_pointers = <PyCObject object at 0x80278b5f8>
|
|
relative_sec_time = 1329444398
: Value of POSIX time (in seconds) that relates to
relative_tsc_time.
|
|
relative_tsc_time = 6412134585926439
: Value of TSC counter that corresponds to
relative_usec_time.
|
|
relative_usec_time = 1329444398554662
: Value of POSIX time (in microseconds) that relates
to relative_tsc_time.
|
|
ticks_per_sec = 2659636680
: Number of processor ticks per second.
|
|
ticks_per_usec = 2659
: Number of processor ticks per microsecond.
|
Convert POSIX seconds (a floating-point number) to ticks.
- Parameters:
t - : The time in POSIX seconds (a float).
- Returns:
- Returns the time in TSC ticks.
|
Get the current time from the kernel in microseconds.
Avoid using this unless absolutely necessary due to performance reasons.
- Returns:
- Returns the current time in microseconds.
|
Convert POSIX seconds to ticks.
- Parameters:
t - : The time in POSIX seconds (an integer).
- Returns:
- Returns the time in TSC ticks.
|
Emulate setting the system time to the given timestamp.
This alters the library to behave as-if the current time is the given time.
Note that this is different than changing the clock on the system.
Changing the clock on the system does not affect TSC values, but this
function does affect TSC values to behave as-if time has elapsed in the
real world.
- Parameters:
posix_timestamp - : The POSIX timestamp (in seconds) to set the
current time. Pass in a value of 0 to disable emulation.
|
Emulate changing the system time by the given number of seconds.
See set_time for more detail.
- Parameters:
delta_secs - : The number of seconds to alter the current time.
|
Convert ticks to POSIX seconds (a floating-point number).
- Parameters:
- Returns:
- Returns the time in POSIX microseconds.
|
Convert ticks to POSIX seconds (an integer).
- Parameters:
- Returns:
- Returns the time in POSIX microseconds.
|
Convert ticks to POSIX microseconds.
- Parameters:
- Returns:
- Returns the time in POSIX microseconds.
|
Convert ticks to POSIX microseconds.
This is "safe" in that if the value is zero, then it returns zero.
- Parameters:
- Returns:
- Returns the time in POSIX microseconds.
|
update_time_relation(...)
|
|
Update the relative time stamps.
You should call this whenever you think the clock has been changed. It
should also be called periodically due to inaccuracies in the
ticks_per_sec value.
|
Convert POSIX microseconds to ticks.
- Parameters:
t - : The time in POSIX microseconds.
- Returns:
- Returns the time in TSC ticks.
|
Convert POSIX microseconds to ticks.
This is "safe" in that if the value is zero, then it returns zero.
- Parameters:
t - : The time in POSIX microseconds.
- Returns:
- Returns the time in TSC ticks.
|