PEP 418: merge time.try_monotonic() and time.hires() into time.hires()
Cleanup the PEP.
This commit is contained in:
parent
280378cb3a
commit
02b9a5bcb3
211
pep-0418.txt
211
pep-0418.txt
|
@ -13,8 +13,7 @@ Python-Version: 3.3
|
||||||
Abstract
|
Abstract
|
||||||
========
|
========
|
||||||
|
|
||||||
Add time.monotonic(), time.hires() and time.try_monotonic() functions to Python
|
Add time.monotonic() and time.hires() functions to Python 3.3.
|
||||||
3.3.
|
|
||||||
|
|
||||||
|
|
||||||
Rationale
|
Rationale
|
||||||
|
@ -24,33 +23,9 @@ Use cases:
|
||||||
|
|
||||||
* Display the current time to a human (e.g. display a calendar or draw a wall
|
* 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()
|
clock): use system clock. time.time() or datetime.datetime.now()
|
||||||
* Implement a timeout: use monotonic clock, or fallback to the clock with
|
* Benchmark, profiling, timeout: time.hires()
|
||||||
the highest resolution. time.try_monotonic()
|
|
||||||
* Benchmark and profiling: time.hires(), with a manual fallback to time.time()
|
|
||||||
* Event scheduler: time.monotonic()
|
* Event scheduler: time.monotonic()
|
||||||
|
|
||||||
time.try_monotonic() tries to use a monotonic clock, but it falls back to a
|
|
||||||
non-monotonic clock if no monotonic clock is available or if reading a
|
|
||||||
monotonic clock failed.
|
|
||||||
|
|
||||||
The pybench benchmark tool supports the following clocks: time.clock(),
|
|
||||||
time.time() and systimes.processtime(). By default, it uses time.clock() on
|
|
||||||
Windows, and time.time() otherwise. It is possible to choose the clock using
|
|
||||||
the --timer command line option.
|
|
||||||
|
|
||||||
Which clock?
|
|
||||||
|
|
||||||
* System time: pthread_mutex_timedlock(), pthread_cond_wait() (CLOCK_REALTIME)
|
|
||||||
* Monotonic: clock_nanosleep() (CLOCK_MONOTONIC)
|
|
||||||
|
|
||||||
Timeouts:
|
|
||||||
|
|
||||||
* threading.Lock.wait()
|
|
||||||
* select.select()
|
|
||||||
* time.sleep()
|
|
||||||
* subprocess.Popen.communicate()
|
|
||||||
* etc.
|
|
||||||
|
|
||||||
|
|
||||||
Functions
|
Functions
|
||||||
=========
|
=========
|
||||||
|
@ -60,7 +35,7 @@ time.time()
|
||||||
|
|
||||||
The system time is the "wall clock". It can be set manually by the system
|
The system time is the "wall clock". It can be set manually by the system
|
||||||
administrator or automatically by a NTP daemon. It can jump backward and
|
administrator or automatically by a NTP daemon. It can jump backward and
|
||||||
forward, and is not monotonic.
|
forward. It is not monotonic.
|
||||||
|
|
||||||
It is available on all platforms and cannot fail.
|
It is available on all platforms and cannot fail.
|
||||||
|
|
||||||
|
@ -96,12 +71,12 @@ Pseudo-code [#pseudo]_: ::
|
||||||
time.monotonic()
|
time.monotonic()
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
Monotonic clock advancing at a monotonic rate relative to real time. It
|
Clock advancing at a monotonic rate relative to real time. It cannot go
|
||||||
cannot go backward. Its rate may be adjusted by NTP. The reference point of the
|
backward. Its rate may be adjusted by NTP. The reference point of the returned
|
||||||
returned value is undefined so only the difference of consecutive calls is
|
value is undefined so only the difference of consecutive calls is valid.
|
||||||
valid.
|
|
||||||
|
It is not available on all platforms and may raise an OSError.
|
||||||
|
|
||||||
It is not avaialble on all platforms and raise an OSError on error.
|
|
||||||
The monotonic clock may stop while the system is suspended.
|
The monotonic clock may stop while the system is suspended.
|
||||||
|
|
||||||
Pseudo-code [#pseudo]_: ::
|
Pseudo-code [#pseudo]_: ::
|
||||||
|
@ -157,53 +132,21 @@ Pseudo-code [#pseudo]_: ::
|
||||||
time.hires()
|
time.hires()
|
||||||
------------
|
------------
|
||||||
|
|
||||||
High-resolution clock. It has an unspecified starting point and may be
|
High-resolution clock: use a monotonic clock if available, or fallback to the
|
||||||
adjusted. The clock starting point changes when the system is resumed after
|
system time.
|
||||||
being suspended.
|
|
||||||
|
It is available on all platforms and cannot fail.
|
||||||
|
|
||||||
Pseudo-code [#pseudo]_: ::
|
Pseudo-code [#pseudo]_: ::
|
||||||
|
|
||||||
if os.name == 'nt':
|
|
||||||
def hires():
|
def hires():
|
||||||
return _time.QueryPerformanceCounter()
|
if hires.use_monotonic:
|
||||||
elif hasattr(time, "monotonic"):
|
|
||||||
hires = time.monotonic
|
|
||||||
elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_REALTIME"):
|
|
||||||
def hires():
|
|
||||||
return time.clock_gettime(time.CLOCK_REALTIME)
|
|
||||||
|
|
||||||
It is not available on all platforms and may raise an OSError.
|
|
||||||
|
|
||||||
|
|
||||||
time.try_monotonic()
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
This clock advances at a steady rate relative to real time. It may be adjusted.
|
|
||||||
The reference point of the returned value is undefined so only the difference
|
|
||||||
of consecutive calls is valid.
|
|
||||||
|
|
||||||
Pseudo-code::
|
|
||||||
|
|
||||||
def try_monotonic():
|
|
||||||
if try_monotonic.use_monotonic:
|
|
||||||
try:
|
try:
|
||||||
return time.monotonic()
|
return time.monotonic()
|
||||||
except (AttributeError, OSError):
|
except OSError:
|
||||||
try_monotonic.use_monotonic = False
|
hires.use_monotonic = False
|
||||||
if try_monotonic.use_hires:
|
|
||||||
try:
|
|
||||||
return time.hires()
|
|
||||||
except (AttributeError, OSError):
|
|
||||||
try_monotonic.use_hires = False
|
|
||||||
return time.time()
|
return time.time()
|
||||||
try_monotonic.use_monotonic = True
|
hires.use_monotonic = hasattr(time, 'monotonic')
|
||||||
try_monotonic.use_hires = True
|
|
||||||
|
|
||||||
|
|
||||||
If available, a monotonic clock is used. The function falls back to another
|
|
||||||
clock if the monotonic clock failed or is not available.
|
|
||||||
|
|
||||||
This function cannot fail.
|
|
||||||
|
|
||||||
|
|
||||||
Clocks
|
Clocks
|
||||||
|
@ -212,54 +155,75 @@ Clocks
|
||||||
Monotonic
|
Monotonic
|
||||||
---------
|
---------
|
||||||
|
|
||||||
* mach_absolute_time(): Mac OS X provides a monotonic clock:
|
mach_absolute_time
|
||||||
mach_absolute_time(). mach_timebase_info() provides a fraction to convert it
|
^^^^^^^^^^^^^^^^^^
|
||||||
to a number of nanoseconds. According to the documentation,
|
|
||||||
mach_timebase_info() is always equals to one and does never fail, even if
|
|
||||||
the function may fail according to its prototype.
|
|
||||||
* clock_gettime(CLOCK_MONOTONIC): Clock that cannot be set and represents
|
|
||||||
monotonic time since some unspecified starting point.
|
|
||||||
* clock_gettime(CLOCK_MONOTONIC_RAW), since Linux 2.6.28; Linux-specific:
|
|
||||||
Similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time
|
|
||||||
that is not subject to NTP adjustments.
|
|
||||||
* Windows: GetTickCount(), GetTickCount64().
|
|
||||||
|
|
||||||
CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW clocks cannot be set.
|
Mac OS X provides a monotonic clock: mach_absolute_time(). mach_timebase_info()
|
||||||
|
provides a fraction to convert the clock value to a number of nanoseconds.
|
||||||
|
|
||||||
|
According to the documentation, mach_timebase_info() is always equals to one
|
||||||
|
and does never fail, even if the function may fail according to its prototype.
|
||||||
|
|
||||||
|
mach_absolute_time() has a resolution of 1 nanosecond.
|
||||||
|
|
||||||
|
CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW represents monotonic time since some
|
||||||
|
unspecified starting point. They cannot be set.
|
||||||
|
|
||||||
|
CLOCK_MONOTONIC_RAW is specific to Linux. It is similar to CLOCK_MONOTONIC, but
|
||||||
|
provides access to a raw hardware-based time that is not subject to NTP
|
||||||
|
adjustments. CLOCK_MONOTONIC_RAW requires Linux 2.6.28 or later.
|
||||||
|
|
||||||
On Linux, NTP may adjust CLOCK_MONOTONIC rate, but not jump backward. If
|
On Linux, NTP may adjust CLOCK_MONOTONIC rate, but not jump backward. If
|
||||||
available, CLOCK_MONOTONIC_RAW should be used instead of CLOCK_MONOTONIC to
|
available, CLOCK_MONOTONIC_RAW should be used instead of CLOCK_MONOTONIC to
|
||||||
avoid the NTP adjustement. CLOCK_MONOTONIC stops while the machine is
|
avoid the NTP adjustement.
|
||||||
suspended.
|
|
||||||
|
|
||||||
Resolution:
|
CLOCK_MONOTONIC stops while the machine is suspended.
|
||||||
|
|
||||||
* mach_absolute_time(): 1 nanosecond
|
clock_gettime() fails if the system does not support the specified clock,
|
||||||
* CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW: be read using clock_getres().
|
|
||||||
1 nanosecond on Linux for example.
|
|
||||||
* GetTickCount(), GetTickCount64(): 1 millisecond
|
|
||||||
|
|
||||||
May fail?
|
|
||||||
|
|
||||||
* mach_absolute_time() cannot fail. According to the documentation,
|
|
||||||
mach_timebase_info() does never fail, even if the function has a return
|
|
||||||
value.
|
|
||||||
* clock_gettime() can fail if the system does not support the specified clock,
|
|
||||||
whereas the standard C library supports it. For example, CLOCK_MONOTONIC_RAW
|
whereas the standard C library supports it. For example, CLOCK_MONOTONIC_RAW
|
||||||
requires a kernel version 2.6.28 or later.
|
requires a kernel version 2.6.28 or later.
|
||||||
* GetTickCount() and GetTickCount64() cannot fail
|
|
||||||
|
clock_getres() gives the clock resolution. It is 1 nanosecond on Linux.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
clock_gettime() requires to link the program with the realtime ("rt") library.
|
clock_gettime() requires to link the program with the realtime ("rt") library.
|
||||||
|
|
||||||
.. note::
|
QueryPerformanceCounter
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
High-resolution performance counter. It is monotonic.
|
||||||
|
QueryPerformanceFrequency() gives its frequency.
|
||||||
|
|
||||||
|
|
||||||
|
On Windows XP, QueryPerformanceFrequency() is the processor frequency and
|
||||||
|
QueryPerformanceCounter() is the TSC of the current processor. Windows XP
|
||||||
|
had a bug (see `KB896256 <http://support.microsoft.com/?id=896256>`_): on a
|
||||||
|
multiprocessor computer, QueryPerformanceCounter() returned a different value
|
||||||
|
for each processor.
|
||||||
|
|
||||||
|
QueryPerformanceFrequency() should only be called once: the frequency will not
|
||||||
|
change while the system is running. It fails if the installed hardware does not
|
||||||
|
support a high-resolution performance counter.
|
||||||
|
|
||||||
|
|
||||||
|
GetTickCount(), GetTickCount64()
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
GetTickCount() and GetTickCount64() are monotonic and cannot fail.
|
||||||
|
|
||||||
GetTickCount64() was added to Windows Vista and Windows Server 2008.
|
GetTickCount64() was added to Windows Vista and Windows Server 2008.
|
||||||
|
|
||||||
|
The clock resolution is 1 millisecond.
|
||||||
|
|
||||||
|
|
||||||
System time
|
System time
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
System time on Windows
|
Windows: GetSystemTimeAsFileTime
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
The system time can be read using GetSystemTimeAsFileTime(), ftime() and
|
The system time can be read using GetSystemTimeAsFileTime(), ftime() and
|
||||||
time().
|
time().
|
||||||
|
@ -276,12 +240,12 @@ The system time can be set using SetSystemTime().
|
||||||
System time on UNIX
|
System time on UNIX
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
gettimeofday(), ftime(), time() and clock_settime(CLOCK_REALTIME) return the
|
gettimeofday(), ftime(), time() and clock_gettime(CLOCK_REALTIME) return the
|
||||||
system clock.
|
system clock.
|
||||||
|
|
||||||
Resolution:
|
Resolution:
|
||||||
|
|
||||||
* clock_settime(): clock_getres(CLOCK_REALTIME), 1 nanosecond on Linux
|
* clock_gettime(): clock_getres(CLOCK_REALTIME), 1 nanosecond on Linux
|
||||||
* gettimeofday(): 1 microsecond
|
* gettimeofday(): 1 microsecond
|
||||||
* ftime(): 1 millisecond
|
* ftime(): 1 millisecond
|
||||||
* time(): 1 second
|
* time(): 1 second
|
||||||
|
@ -299,7 +263,8 @@ Process
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
|
|
||||||
* Windows: GetProcessTimes()
|
* Windows: GetProcessTimes()
|
||||||
* clock_gettime(CLOCK_PROCESS_CPUTIME_ID): High-resolution per-process timer from the CPU.
|
* clock_gettime(CLOCK_PROCESS_CPUTIME_ID): High-resolution per-process timer
|
||||||
|
from the CPU.
|
||||||
* clock():
|
* clock():
|
||||||
|
|
||||||
* Windows: The elapsed wall-clock time since the start of the process
|
* Windows: The elapsed wall-clock time since the start of the process
|
||||||
|
@ -331,28 +296,6 @@ Resolution:
|
||||||
See also pthread_getcpuclockid().
|
See also pthread_getcpuclockid().
|
||||||
|
|
||||||
|
|
||||||
QueryPerformanceCounter
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
Windows provides a high-resolution performance counter:
|
|
||||||
QueryPerformanceCounter(). Its frequency can be retrieved using
|
|
||||||
QueryPerformanceFrequency().
|
|
||||||
|
|
||||||
On Windows XP, QueryPerformanceFrequency() is the processor frequency and
|
|
||||||
QueryPerformanceCounter() is the TSC of the current processor. Windows XP
|
|
||||||
had a bug (see `KB896256 <http://support.microsoft.com/?id=896256>`_): on a
|
|
||||||
multiprocessor computer, QueryPerformanceCounter() returned a different value
|
|
||||||
for each processor.
|
|
||||||
|
|
||||||
QueryPerformanceCounter() is monotonic.
|
|
||||||
|
|
||||||
QueryPerformanceFrequency() fails if the installed hardware does not support a
|
|
||||||
high-resolution performance counter.
|
|
||||||
|
|
||||||
QueryPerformanceFrequency() should only be called once: the frequency will not
|
|
||||||
change while the system is running.
|
|
||||||
|
|
||||||
|
|
||||||
QueryUnbiasedInterruptTime
|
QueryUnbiasedInterruptTime
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
@ -369,12 +312,12 @@ QueryUnbiasedInterruptTime() was introduced in Windows 7.
|
||||||
Alternatives: API design
|
Alternatives: API design
|
||||||
========================
|
========================
|
||||||
|
|
||||||
One function with a flag: time.try_monotonic(strict=False)
|
One function with a flag: time.monotonic(strict=False)
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
|
|
||||||
* time.try_monotonic(strict=False) falls back to another clock if no monotonic clock
|
* time.monotonic(strict=False) falls back to another clock if no monotonic clock
|
||||||
is not available or does not work, but it does never fail.
|
is not available or does not work, but it does never fail.
|
||||||
* time.try_monotonic(strict=True) raises OSError if monotonic clock fails or
|
* time.monotonic(strict=True) raises OSError if monotonic clock fails or
|
||||||
NotImplementedError if the system does not provide a monotonic clock
|
NotImplementedError if the system does not provide a monotonic clock
|
||||||
|
|
||||||
"A keyword argument that gets passed as a constant in the caller is usually
|
"A keyword argument that gets passed as a constant in the caller is usually
|
||||||
|
@ -387,10 +330,10 @@ should be avoided.
|
||||||
One function, no flag
|
One function, no flag
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
time.try_monotonic() returns (time: float, is_monotonic: bool).
|
time.monotonic() returns (time: float, is_monotonic: bool).
|
||||||
|
|
||||||
An alternative is to use a function attribute: time.try_monotonic.monotonic. The
|
An alternative is to use a function attribute: time.monotonic.is_monotonic. The
|
||||||
attribute value would be None before the first call to time.try_monotonic().
|
attribute value would be None before the first call to time.monotonic().
|
||||||
|
|
||||||
|
|
||||||
Working around operating system bugs?
|
Working around operating system bugs?
|
||||||
|
|
Loading…
Reference in New Issue