PEP 418: Rename time.hires() to time.highres(); add Solaris monotonic clocks

Mention also other time.highres() name propositions.
This commit is contained in:
Victor Stinner 2012-03-28 15:02:58 +02:00
parent aaa1107673
commit 319f49544b
1 changed files with 83 additions and 22 deletions

View File

@ -13,7 +13,7 @@ Python-Version: 3.3
Abstract
========
Add time.monotonic() and time.hires() functions to Python 3.3.
Add time.monotonic() and time.highres() functions to Python 3.3.
Rationale
@ -23,7 +23,7 @@ Use cases:
* Display the current time to a human (e.g. display a calendar or draw a wall
clock): use system clock. time.time() or datetime.datetime.now()
* Benchmark, profiling, timeout: time.hires()
* Benchmark, profiling, timeout: time.highres()
* Event scheduler: time.monotonic()
@ -118,19 +118,36 @@ Pseudo-code [#pseudo]_: ::
return _time.mach_absolute_time() * monotonic.factor
monotonic.factor = None
elif os.name.startswith('sunos'):
def monotonic():
if monotonic.use_clock_highres:
try:
time.clock_gettime(time.CLOCK_HIGHRES)
except OSError:
monotonic.use_clock_highres = False
return time.gethrtime()
monotonic.use_clock_highres = (hasattr(time, 'clock_gettime')
and hasattr(time, 'CLOCK_HIGHRES'))
elif hasattr(time, "clock_gettime"):
def monotonic():
if monotonic.use_monotonic_raw:
while monotonic.clocks:
try:
return time.clock_gettime(time.CLOCK_MONOTONIC_RAW)
clk_id = monotonic.clocks[0]
return time.clock_gettime(clk_id)
except OSError:
# CLOCK_MONOTONIC_RAW requires a Linux kernel >= 2.6.28
monotonic.use_monotonic_raw = False
del monotonic.clocks[0]
return time.clock_gettime(time.CLOCK_MONOTONIC)
monotonic.use_monotonic_raw = hasattr(time, "CLOCK_MONOTONIC_RAW")
monotonic.clocks = []
if hasattr(time, 'CLOCK_MONOTONIC_RAW'):
monotonic.clocks.append(time.CLOCK_MONOTONIC_RAW)
if hasattr(time, 'CLOCK_HIGHRES'):
monotonic.clocks.append(time.CLOCK_HIGHRES)
time.hires()
------------
time.highres()
--------------
High-resolution clock: use a monotonic clock if available, or fallback to the
system time.
@ -139,14 +156,14 @@ It is available on all platforms and cannot fail.
Pseudo-code::
def hires():
if hires.use_monotonic:
def highres():
if highres.use_monotonic:
try:
return time.monotonic()
except OSError:
hires.use_monotonic = False
highres.use_monotonic = False
return time.time()
hires.use_monotonic = hasattr(time, 'monotonic')
highres.use_monotonic = hasattr(time, 'monotonic')
Clocks
@ -195,8 +212,8 @@ clock_getres() gives the clock resolution. It is 1 nanosecond on Linux.
.. note::
clock_gettime() requires to link the program to the rt (real-time) library.
QueryPerformanceCounter
^^^^^^^^^^^^^^^^^^^^^^^
Windows: QueryPerformanceCounter
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
High-resolution performance counter. It is monotonic.
QueryPerformanceFrequency() gives its frequency.
@ -212,8 +229,8 @@ change while the system is running. It fails if the installed hardware does not
support a high-resolution performance counter.
GetTickCount(), GetTickCount64()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Windows: GetTickCount(), GetTickCount64()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
GetTickCount() and GetTickCount64() are monotonic and cannot fail.
@ -221,6 +238,27 @@ GetTickCount64() was added to Windows Vista and Windows Server 2008.
The clock resolution is 1 millisecond.
Solaris: CLOCK_HIGHRES
^^^^^^^^^^^^^^^^^^^^^^
The Solaris OS has an CLOCK_HIGHRES timer that attempts to use an optimal
hardware source, and may give close to nanosecond resolution. CLOCK_HIGHRES is
the nonadjustable, high-resolution clock. For timers created with a clockid_t
value of CLOCK_HIGHRES, the system will attempt to use an optimal hardware
source.
Solaris: gethrtime
^^^^^^^^^^^^^^^^^^
The gethrtime() function returns the current high-resolution real time. Time is
expressed as nanoseconds since some arbitrary time in the past; it is not
correlated in any way to the time of day, and thus is not subject to
resetting or drifting by way of adjtime() or settimeofday(). The hires timer
is ideally suited to performance measurement tasks, where cheap, accurate
interval timing is required.
On Solaris, gethrtime() is the same as clock_gettime(CLOCK_MONOTONIC).
System time
-----------
@ -299,8 +337,8 @@ Resolution:
See also pthread_getcpuclockid().
QueryUnbiasedInterruptTime
--------------------------
Windows: QueryUnbiasedInterruptTime
-----------------------------------
Gets the current unbiased interrupt time from the biased interrupt time and the
current sleep bias amount. This time is not affected by power management sleep
@ -311,12 +349,25 @@ Is it monotonic?
QueryUnbiasedInterruptTime() was introduced in Windows 7.
Alternatives: API design
========================
time.highres() function name
----------------------------
Other names were proposed:
* time.hires(): "hires" can be read as "to hire" as in "he hires a car to go
on holiday", rather than a "HIgh-RESolution clock".
* time.steady(): no OS provides a clock advancing at a steady rate, so
"steady" should be avoided.
* time.try_monotonic(): it is a clear and obvious solution for the use-case of
"I prefer the monotonic clock, if it is available, otherwise I'll take my
chances with a best-effect clock."
* time.wallclock()
One function with a flag: time.monotonic(strict=False)
----------------------------------------------------------
------------------------------------------------------
* time.monotonic(strict=False) falls back to the system clock if no monotonic
clock is available or if the monotonic clock failed.
@ -345,6 +396,10 @@ Working around operating system bugs?
Should Python ensure manually that a monotonic clock is truly monotonic by
computing the maximum with the clock value and the previous value?
Since it's relatively straightforward to cache the last value returned using a
static variable, it might be interesting to use this to make sure that the
values returned are indeed monotonic.
* Virtual machines provide less reliable clocks.
* QueryPerformanceCounter() had a bug in 2006 on multiprocessor computers
@ -352,8 +407,8 @@ computing the maximum with the clock value and the previous value?
Footnotes
=========
.. [#pseudo] _time is an hypothetical module used for the example. In practice,
functions will be implemented in C and so don't need a module.
.. [#pseudo] "_time" is an hypothetical module only used for the example.
The time module is implemented in C and so there is no need for such module.
Links
@ -365,15 +420,21 @@ Links
<http://bugs.python.org/issue14222>`_
* `Issue #14397: Use GetTickCount/GetTickCount64 instead of QueryPerformanceCounter for monotonic clock
<http://bugs.python.org/issue14397>`_
* `Issue #14428: Implementation of the PEP 418
<http://bugs.python.org/issue14428>`_
* `python-monotonic-time
<http://code.google.com/p/python-monotonic-time/>`_
(`github <https://github.com/gavinbeatty/python-monotonic-time>`_)
* `Qt library: QElapsedTimer
<http://qt-project.org/doc/qt-4.8/qelapsedtimer.html>`_
* `monotonic_clock
<https://github.com/ThomasHabets/monotonic_clock>`_
* `Windows: Game Timing and Multicore Processors
<http://msdn.microsoft.com/en-us/library/ee417693.aspx>`_
* `Implement a Continuously Updating, High-Resolution Time Provider for Windows
<http://msdn.microsoft.com/en-us/magazine/cc163996.aspx>`_
* `Perl: Time::HiRes
<http://perldoc.perl.org/Time/HiRes.html>`_
* `C++ Timeout Specification
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3128.html>`_