PEP 418: Rename time.monotonic() to time.steady()

This commit is contained in:
Victor Stinner 2012-04-03 01:42:42 +02:00
parent 4416dc13ff
commit 66c23f28d7
1 changed files with 49 additions and 50 deletions

View File

@ -1,5 +1,5 @@
PEP: 418 PEP: 418
Title: Add monotonic and high-resolution time functions Title: Add steady and high-resolution time functions
Version: $Revision$ Version: $Revision$
Last-Modified: $Date$ Last-Modified: $Date$
Author: Victor Stinner <victor.stinner@gmail.com> Author: Victor Stinner <victor.stinner@gmail.com>
@ -13,7 +13,7 @@ Python-Version: 3.3
Abstract Abstract
======== ========
Add time.monotonic(), time.highres(), time.get_clock_info(name) functions to Add time.steady(), time.highres(), time.get_clock_info(name) functions to
Python 3.3. Python 3.3.
@ -26,7 +26,7 @@ Use cases:
a wall clock): use system clock, i.e. time.time() or a wall clock): use system clock, i.e. time.time() or
datetime.datetime.now(). datetime.datetime.now().
* Benchmark, profiling: time.highres(). * Benchmark, profiling: time.highres().
* Event scheduler, timeout: time.monotonic(). * Event scheduler, timeout: time.steady().
Functions Functions
@ -36,8 +36,7 @@ To fulfill the use cases, the functions' properties are:
* time.time(): system clock, "wall clock". * time.time(): system clock, "wall clock".
* time.highres(): clock with the best accuracy. * time.highres(): clock with the best accuracy.
* time.monotonic(): monotonic clock, or system clock if no monotonic * time.steady(): steady clock, should be monotonic
clock is available
* time.get_clock_info(name): get information on the specified time function * time.get_clock_info(name): get information on the specified time function
@ -79,15 +78,14 @@ Pseudo-code [#pseudo]_::
return _time.time() return _time.time()
time.monotonic() time.steady()
---------------- -------------
Monotonic clock, or system clock if the platform does not provide a monotonic Steady clock. Use a monotonic clock, or falls back to the system clock. Its
clock (e.g. on GNU/Hurd). Its rate is as steady as possible. Its rate may be rate may be adjusted by NTP. The reference point of the returned value is
adjusted by NTP. The reference point of the returned value is undefined so undefined so only the difference of consecutive calls is valid.
only the difference of consecutive calls is valid.
Use time.get_clock_info('monotonic')['is_monotonic'] to check if the clock Use time.get_clock_info('steady')['is_monotonic'] to check if the clock
monotonic or not. monotonic or not.
The elapsed time may or may not include time the system spends in The elapsed time may or may not include time the system spends in
@ -98,60 +96,60 @@ Pseudo-code [#pseudo]_::
if os.name == 'nt': if os.name == 'nt':
# GetTickCount64() requires Windows Vista, Server 2008 or later # GetTickCount64() requires Windows Vista, Server 2008 or later
if hasattr(time, '_GetTickCount64'): if hasattr(time, '_GetTickCount64'):
def monotonic(): def steady():
return _time.GetTickCount64() return _time.GetTickCount64()
else: else:
def monotonic(): def steady():
ticks = _time.GetTickCount() ticks = _time.GetTickCount()
if ticks < monotonic.last: if ticks < steady.last:
# Integer overflow detected # Integer overflow detected
monotonic.delta += 2**32 steady.delta += 2**32
monotonic.last = ticks steady.last = ticks
return ticks + monotonic.delta return ticks + steady.delta
monotonic.last = 0 steady.last = 0
monotonic.delta = 0 steady.delta = 0
elif os.name == 'mac': elif os.name == 'mac':
def monotonic(): def steady():
if monotonic.factor is None: if steady.factor is None:
factor = _time.mach_timebase_info() factor = _time.mach_timebase_info()
monotonic.factor = timebase[0] / timebase[1] steady.factor = timebase[0] / timebase[1]
return _time.mach_absolute_time() * monotonic.factor return _time.mach_absolute_time() * steady.factor
monotonic.factor = None steady.factor = None
elif os.name.startswith('sunos'): elif os.name.startswith('sunos'):
def monotonic(): def steady():
if monotonic.use_clock_highres: if steady.use_clock_highres:
try: try:
time.clock_gettime(time.CLOCK_HIGHRES) time.clock_gettime(time.CLOCK_HIGHRES)
except OSError: except OSError:
monotonic.use_clock_highres = False steady.use_clock_highres = False
if monotonic.use_gethrtime: if steady.use_gethrtime:
try: try:
return time.gethrtime() return time.gethrtime()
except OSError: except OSError:
monotonic.use_gethrtime = False steady.use_gethrtime = False
return time.time() return time.time()
monotonic.use_clock_highres = (hasattr(time, 'clock_gettime') steady.use_clock_highres = (hasattr(time, 'clock_gettime')
and hasattr(time, 'CLOCK_HIGHRES')) and hasattr(time, 'CLOCK_HIGHRES'))
monotonic.use_gethrtime = True steady.use_gethrtime = True
elif hasattr(time, "clock_gettime"): elif hasattr(time, "clock_gettime"):
def monotonic(): def steady():
while monotonic.clocks: while steady.clocks:
try: try:
clk_id = monotonic.clocks[0] clk_id = steady.clocks[0]
return time.clock_gettime(clk_id) return time.clock_gettime(clk_id)
except OSError: except OSError:
del monotonic.clocks[0] del steady.clocks[0]
return time.time() return time.time()
monotonic.clocks = [] steady.clocks = []
if hasattr(time, 'CLOCK_HIGHRES'): if hasattr(time, 'CLOCK_HIGHRES'):
monotonic.clocks.append(time.CLOCK_HIGHRES) steady.clocks.append(time.CLOCK_HIGHRES)
monotonic.clocks.append(time.CLOCK_MONOTONIC) steady.clocks.append(time.CLOCK_MONOTONIC)
else: else:
def monotonic(): def steady():
return time.time() return time.time()
On Windows, QueryPerformanceCounter() is not used even though it has a On Windows, QueryPerformanceCounter() is not used even though it has a
@ -160,10 +158,10 @@ many issues.
.. note:: .. note::
time.monotonic() detects GetTickCount() integer overflow (32 bits, time.steady() detects GetTickCount() integer overflow (32 bits,
roll-over after 49.7 days): it increases a delta by 2\ :sup:`32` roll-over after 49.7 days): it increases a delta by 2\ :sup:`32`
each time than an overflow is detected. The delta is stored in the each time than an overflow is detected. The delta is stored in the
process-local state and so the value of time.monotonic() may be process-local state and so the value of time.steady() may be
different in two Python processes. different in two Python processes.
@ -185,15 +183,15 @@ Pseudo-code::
# hardware does not support a high-resolution performance # hardware does not support a high-resolution performance
# counter for example # counter for example
highres.use_performance_counter = False highres.use_performance_counter = False
if highres.use_monotonic: if highres.use_steady:
# Monotonic clock is preferred over system clock # Monotonic clock is preferred over system clock
try: try:
return time.monotonic() return time.steady()
except OSError: except OSError:
highres.use_monotonic = False highres.use_steady = False
return time.time() return time.time()
highres.use_performance_counter = (os.name == 'nt') highres.use_performance_counter = (os.name == 'nt')
highres.use_monotonic = hasattr(time, 'monotonic') highres.use_steady = hasattr(time, 'steady')
time.get_clock_info(name) time.get_clock_info(name)
------------------------- -------------------------
@ -202,7 +200,7 @@ Get information on the specified clock. Supported clocks:
* "clock": time.clock() * "clock": time.clock()
* "highres": time.highres() * "highres": time.highres()
* "monotonic": time.monotonic() * "steady": time.steady()
* "time": time.time() * "time": time.time()
Return a dictionary with the following keys: Return a dictionary with the following keys:
@ -766,10 +764,11 @@ time.highres():
* time.timer(): "it would be too easy to confuse with (or misspell as) * time.timer(): "it would be too easy to confuse with (or misspell as)
time.time()" time.time()"
time.monotonic(): time.steady():
* time.steady(): no OS provides a clock advancing at a steady rate, so * time.monotonic(): QueryPerformanceCounter() is monotonic but it is not used
"steady" should be avoided. by time.steady() because it is not steady, and it is surprising to have to
check for time.get_clock_info('monotonic')['is_monotonic'].
* time.try_monotonic(): it is a clear and obvious solution for the * time.try_monotonic(): it is a clear and obvious solution for the
use-case of "I prefer the monotonic clock, if it is available, use-case of "I prefer the monotonic clock, if it is available,
otherwise I'll take my chances with a best-effect clock." otherwise I'll take my chances with a best-effect clock."