PEP 418: Add fallback=True argument to time.monotonic()
* time.monotonic() doesn't use QPC anymore * Rewrite also time.monotonic() and time.highres() definitions.
This commit is contained in:
parent
2e69f4914f
commit
8e9a3c50ca
87
pep-0418.txt
87
pep-0418.txt
|
@ -13,7 +13,7 @@ Python-Version: 3.3
|
|||
Abstract
|
||||
========
|
||||
|
||||
Add time.monotonic() and time.highres() functions to Python 3.3.
|
||||
Add time.monotonic(fallback=True) and time.highres() functions to Python 3.3.
|
||||
|
||||
|
||||
Rationale
|
||||
|
@ -24,12 +24,19 @@ 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.highres()
|
||||
* Event scheduler: time.monotonic()
|
||||
* Event scheduler: time.monotonic(), or time.monotonic(fallback=False)
|
||||
|
||||
|
||||
Functions
|
||||
=========
|
||||
|
||||
* time.time(): system clock, "wall clock"
|
||||
* time.highres(): clock with the best accuracy
|
||||
* time.monotonic(fallback=True): monotonic clock. If no monotonic clock is
|
||||
available, falls back to system clock by default, or raises an OSError if
|
||||
*fallback* is False. time.monotonic(fallback=True) cannot go backward.
|
||||
|
||||
|
||||
time.time()
|
||||
-----------
|
||||
|
||||
|
@ -68,12 +75,12 @@ Pseudo-code [#pseudo]_: ::
|
|||
return _time.time()
|
||||
|
||||
|
||||
time.monotonic()
|
||||
----------------
|
||||
time.monotonic(fallback=True)
|
||||
-----------------------------
|
||||
|
||||
Clock advancing at a monotonic rate relative to real time. It cannot go
|
||||
backward. Its rate may be adjusted by NTP. The reference point of the returned
|
||||
value is undefined so only the difference of consecutive calls is valid.
|
||||
Clock that cannot go backward, its rate is as steady as possible. Its rate may
|
||||
be adjusted by NTP. The reference point of the returned value is undefined so
|
||||
only the difference of consecutive calls is valid.
|
||||
|
||||
It is not available on all platforms and may raise an OSError. It is not
|
||||
available on GNU/Hurd for example.
|
||||
|
@ -85,34 +92,21 @@ Pseudo-code [#pseudo]_: ::
|
|||
if os.name == 'nt':
|
||||
# GetTickCount64() requires Windows Vista, Server 2008 or later
|
||||
if hasattr(time, '_GetTickCount64'):
|
||||
_get_tick_count = _time.GetTickCount64
|
||||
def monotonic(fallback=True):
|
||||
return _time.GetTickCount64()
|
||||
else:
|
||||
def _get_tick_count():
|
||||
def monotonic(fallback=True):
|
||||
ticks = _time.GetTickCount()
|
||||
if ticks < _get_tick_count.last:
|
||||
if ticks < monotonic.last:
|
||||
# Integer overflow detected
|
||||
_get_tick_count.delta += 2**32
|
||||
_get_tick_count.last = ticks
|
||||
return ticks + _get_tick_count.delta
|
||||
_get_tick_count.last = 0
|
||||
_get_tick_count.delta = 0
|
||||
|
||||
def monotonic():
|
||||
if monotonic.use_performance_counter:
|
||||
try:
|
||||
return _time.QueryPerformanceCounter()
|
||||
except OSError:
|
||||
# QueryPerformanceFrequency() may fail, if the installed
|
||||
# hardware does not support a high-resolution performance
|
||||
# counter for example
|
||||
monotonic.use_performance_counter = False
|
||||
# Fallback to GetTickCount/GetTickCount64 which has
|
||||
# a lower resolution
|
||||
return _get_tick_count()
|
||||
monotonic.use_performance_counter = True
|
||||
monotonic.delta += 2**32
|
||||
monotonic.last = ticks
|
||||
return ticks + monotonic.delta
|
||||
monotonic.last = 0
|
||||
monotonic.delta = 0
|
||||
|
||||
elif os.name == 'mac':
|
||||
def monotonic():
|
||||
def monotonic(fallback=True):
|
||||
if monotonic.factor is None:
|
||||
factor = _time.mach_timebase_info()
|
||||
monotonic.factor = timebase[0] / timebase[1]
|
||||
|
@ -120,31 +114,45 @@ Pseudo-code [#pseudo]_: ::
|
|||
monotonic.factor = None
|
||||
|
||||
elif os.name.startswith('sunos'):
|
||||
def monotonic():
|
||||
def monotonic(fallback=True):
|
||||
if monotonic.use_clock_highres:
|
||||
try:
|
||||
time.clock_gettime(time.CLOCK_HIGHRES)
|
||||
except OSError:
|
||||
monotonic.use_clock_highres = False
|
||||
if monotonic.use_gethrtime:
|
||||
try:
|
||||
return time.gethrtime()
|
||||
except OSError:
|
||||
if not fallback:
|
||||
raise
|
||||
monotonic.use_gethrtime = False
|
||||
return time.time()
|
||||
monotonic.use_clock_highres = (hasattr(time, 'clock_gettime')
|
||||
and hasattr(time, 'CLOCK_HIGHRES'))
|
||||
monotonic.use_gethrtime = True
|
||||
|
||||
elif hasattr(time, "clock_gettime"):
|
||||
def monotonic():
|
||||
def monotonic(fallback=True):
|
||||
while monotonic.clocks:
|
||||
try:
|
||||
clk_id = monotonic.clocks[0]
|
||||
return time.clock_gettime(clk_id)
|
||||
except OSError:
|
||||
# CLOCK_MONOTONIC_RAW requires a Linux kernel >= 2.6.28
|
||||
if len(monotonic.clocks) == 1 and not fallback:
|
||||
raise
|
||||
del monotonic.clocks[0]
|
||||
return time.clock_gettime(time.CLOCK_MONOTONIC)
|
||||
return time.time()
|
||||
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)
|
||||
monotonic.clocks.append(time.CLOCK_MONOTONIC)
|
||||
|
||||
On Windows, QueryPerformanceCounter() is not used even if it has a better
|
||||
resolution than GetTickCount(). It is not reliable and has too much issues.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -157,20 +165,29 @@ Pseudo-code [#pseudo]_: ::
|
|||
time.highres()
|
||||
--------------
|
||||
|
||||
High-resolution clock: use a monotonic clock if available, or fallback to the
|
||||
system time.
|
||||
Clock with the best available resolution.
|
||||
|
||||
It is available on all platforms and cannot fail.
|
||||
|
||||
Pseudo-code::
|
||||
|
||||
def highres():
|
||||
if monotonic.use_performance_counter:
|
||||
try:
|
||||
return _time.QueryPerformanceCounter()
|
||||
except OSError:
|
||||
# QueryPerformanceFrequency() may fail, if the installed
|
||||
# hardware does not support a high-resolution performance
|
||||
# counter for example
|
||||
monotonic.use_performance_counter = False
|
||||
if highres.use_monotonic:
|
||||
# Monotonic clock is preferred over system clock
|
||||
try:
|
||||
return time.monotonic()
|
||||
except OSError:
|
||||
highres.use_monotonic = False
|
||||
return time.time()
|
||||
highres.use_performance_counter = (os.name == 'nt')
|
||||
highres.use_monotonic = hasattr(time, 'monotonic')
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue