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
89
pep-0418.txt
89
pep-0418.txt
|
@ -13,7 +13,7 @@ Python-Version: 3.3
|
||||||
Abstract
|
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
|
Rationale
|
||||||
|
@ -24,12 +24,19 @@ 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()
|
||||||
* Benchmark, profiling, timeout: time.highres()
|
* Benchmark, profiling, timeout: time.highres()
|
||||||
* Event scheduler: time.monotonic()
|
* Event scheduler: time.monotonic(), or time.monotonic(fallback=False)
|
||||||
|
|
||||||
|
|
||||||
Functions
|
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()
|
time.time()
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@ -68,12 +75,12 @@ Pseudo-code [#pseudo]_: ::
|
||||||
return _time.time()
|
return _time.time()
|
||||||
|
|
||||||
|
|
||||||
time.monotonic()
|
time.monotonic(fallback=True)
|
||||||
----------------
|
-----------------------------
|
||||||
|
|
||||||
Clock advancing at a monotonic rate relative to real time. It cannot go
|
Clock that cannot go backward, its rate is as steady as possible. Its rate may
|
||||||
backward. Its rate may be adjusted by NTP. The reference point of the returned
|
be adjusted by NTP. The reference point of the returned value is undefined so
|
||||||
value is undefined so only the difference of consecutive calls is valid.
|
only the difference of consecutive calls is valid.
|
||||||
|
|
||||||
It is not available on all platforms and may raise an OSError. It is not
|
It is not available on all platforms and may raise an OSError. It is not
|
||||||
available on GNU/Hurd for example.
|
available on GNU/Hurd for example.
|
||||||
|
@ -85,34 +92,21 @@ 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'):
|
||||||
_get_tick_count = _time.GetTickCount64
|
def monotonic(fallback=True):
|
||||||
|
return _time.GetTickCount64()
|
||||||
else:
|
else:
|
||||||
def _get_tick_count():
|
def monotonic(fallback=True):
|
||||||
ticks = _time.GetTickCount()
|
ticks = _time.GetTickCount()
|
||||||
if ticks < _get_tick_count.last:
|
if ticks < monotonic.last:
|
||||||
# Integer overflow detected
|
# Integer overflow detected
|
||||||
_get_tick_count.delta += 2**32
|
monotonic.delta += 2**32
|
||||||
_get_tick_count.last = ticks
|
monotonic.last = ticks
|
||||||
return ticks + _get_tick_count.delta
|
return ticks + monotonic.delta
|
||||||
_get_tick_count.last = 0
|
monotonic.last = 0
|
||||||
_get_tick_count.delta = 0
|
monotonic.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
|
|
||||||
|
|
||||||
elif os.name == 'mac':
|
elif os.name == 'mac':
|
||||||
def monotonic():
|
def monotonic(fallback=True):
|
||||||
if monotonic.factor is None:
|
if monotonic.factor is None:
|
||||||
factor = _time.mach_timebase_info()
|
factor = _time.mach_timebase_info()
|
||||||
monotonic.factor = timebase[0] / timebase[1]
|
monotonic.factor = timebase[0] / timebase[1]
|
||||||
|
@ -120,31 +114,45 @@ Pseudo-code [#pseudo]_: ::
|
||||||
monotonic.factor = None
|
monotonic.factor = None
|
||||||
|
|
||||||
elif os.name.startswith('sunos'):
|
elif os.name.startswith('sunos'):
|
||||||
def monotonic():
|
def monotonic(fallback=True):
|
||||||
if monotonic.use_clock_highres:
|
if monotonic.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
|
monotonic.use_clock_highres = False
|
||||||
return time.gethrtime()
|
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')
|
monotonic.use_clock_highres = (hasattr(time, 'clock_gettime')
|
||||||
and hasattr(time, 'CLOCK_HIGHRES'))
|
and hasattr(time, 'CLOCK_HIGHRES'))
|
||||||
|
monotonic.use_gethrtime = True
|
||||||
|
|
||||||
elif hasattr(time, "clock_gettime"):
|
elif hasattr(time, "clock_gettime"):
|
||||||
def monotonic():
|
def monotonic(fallback=True):
|
||||||
while monotonic.clocks:
|
while monotonic.clocks:
|
||||||
try:
|
try:
|
||||||
clk_id = monotonic.clocks[0]
|
clk_id = monotonic.clocks[0]
|
||||||
return time.clock_gettime(clk_id)
|
return time.clock_gettime(clk_id)
|
||||||
except OSError:
|
except OSError:
|
||||||
# CLOCK_MONOTONIC_RAW requires a Linux kernel >= 2.6.28
|
# CLOCK_MONOTONIC_RAW requires a Linux kernel >= 2.6.28
|
||||||
|
if len(monotonic.clocks) == 1 and not fallback:
|
||||||
|
raise
|
||||||
del monotonic.clocks[0]
|
del monotonic.clocks[0]
|
||||||
return time.clock_gettime(time.CLOCK_MONOTONIC)
|
return time.time()
|
||||||
monotonic.clocks = []
|
monotonic.clocks = []
|
||||||
if hasattr(time, 'CLOCK_MONOTONIC_RAW'):
|
if hasattr(time, 'CLOCK_MONOTONIC_RAW'):
|
||||||
monotonic.clocks.append(time.CLOCK_MONOTONIC_RAW)
|
monotonic.clocks.append(time.CLOCK_MONOTONIC_RAW)
|
||||||
if hasattr(time, 'CLOCK_HIGHRES'):
|
if hasattr(time, 'CLOCK_HIGHRES'):
|
||||||
monotonic.clocks.append(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::
|
.. note::
|
||||||
|
|
||||||
|
@ -157,20 +165,29 @@ Pseudo-code [#pseudo]_: ::
|
||||||
time.highres()
|
time.highres()
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
High-resolution clock: use a monotonic clock if available, or fallback to the
|
Clock with the best available resolution.
|
||||||
system time.
|
|
||||||
|
|
||||||
It is available on all platforms and cannot fail.
|
It is available on all platforms and cannot fail.
|
||||||
|
|
||||||
Pseudo-code::
|
Pseudo-code::
|
||||||
|
|
||||||
def highres():
|
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:
|
if highres.use_monotonic:
|
||||||
|
# Monotonic clock is preferred over system clock
|
||||||
try:
|
try:
|
||||||
return time.monotonic()
|
return time.monotonic()
|
||||||
except OSError:
|
except OSError:
|
||||||
highres.use_monotonic = False
|
highres.use_monotonic = False
|
||||||
return time.time()
|
return time.time()
|
||||||
|
highres.use_performance_counter = (os.name == 'nt')
|
||||||
highres.use_monotonic = hasattr(time, 'monotonic')
|
highres.use_monotonic = hasattr(time, 'monotonic')
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue