Repository navigation
time.sleep (floatsleep()) should use clock_nanosleep() on Linux #65501
Copy link
Copy link
Closed
Labels
3.11only security fixesonly security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee = None
closed_at = <Date 2021-09-25.12:37:55.425>
created_at = <Date 2014-04-18.20:12:03.043>
labels = ['type-bug', 'library', '3.11']
title = 'time.sleep (floatsleep()) should use clock_nanosleep() on Linux'
updated_at = <Date 2021-10-11.08:30:28.782>
user = 'https://bugs.python.org/shankarunni'bugs.python.org fields:
activity = <Date 2021-10-11.08:30:28.782>
actor = 'vstinner'
assignee = 'none'
closed = True
closed_date = <Date 2021-09-25.12:37:55.425>
closer = 'vstinner'
components = ['Library (Lib)']
creation = <Date 2014-04-18.20:12:03.043>
creator = 'shankarunni'
dependencies = []
files = ['50289', '50294']
hgrepos = []
issue_num = 21302
keywords = ['patch']
message_count = 32.0
messages = ['216799', '216814', '217225', '217226', '217227', '217233', '217235', '401108', '401701', '401706', '401824', '402279', '402437', '402438', '402440', '402441', '402442', '402448', '402618', '402619', '402630', '402632', '403528', '403544', '403550', '403568', '403569', '403581', '403583', '403610', '403632', '403633']
nosy_count = 7.0
nosy_names = ['vstinner', 'akira', 'python-dev', 'yselivanov', 'eryksun', 'shankarunni', 'Livius']
pr_nums = ['28077', '28111', '28311', '28341', '28350', '28483', '28526', '28545']
priority = 'normal'
resolution = 'fixed'
stage = 'resolved'
status = 'closed'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue21302'
versions = ['Python 3.11']Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
3.11only security fixesonly security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Activity
vstinner commentedon Sep 22, 2021
New changeset 58f8adf by Victor Stinner in branch 'main':
bpo-21302: time.sleep() uses waitable timer on Windows (GH-28483)
58f8adf
vstinner commentedon Sep 22, 2021
Livius: your first PR modified Sleep() in Modules/_tkinter.c to use nanosleep(). I don't see the point since this function has a solution of 1 ms (10^-3). Using select() on Unix is enough: resolution of 1 us (10^-6).
vstinner commentedon Sep 22, 2021
bench.py: measure the shortest possible sleep. Use time.sleep(1e-10): 0.1 nanosecond. It should be rounded to the resolution of the used sleep function, like 1 ns on Linux.
On Linux with Fedora 34 Python 3.10 executable, I get:
On Windows with a Python 3.11 debug build, I get:
Sadly, it seems like on Windows 10, one of the following function still uses the infamous 15.6 ms resolution:
vstinner commentedon Sep 22, 2021
I wrote an optimization to cache the Windows timer handle between time.sleep() calls (don't close it). I don't think that it's needed because they shortest sleep is about 15.6 ms. CreateWaitableTimerW() is likely way more fast than 15.6 ms. So this optimization is basically useless.
vstinner commentedon Sep 22, 2021
Livius: do you care about using nanosleep(), or can I close the issue?
vstinner commentedon Sep 22, 2021
See also bpo-19007: "precise time.time() under Windows 8: use GetSystemTimePreciseAsFileTime".
vstinner commentedon Sep 25, 2021
New changeset 7834ff2 by Victor Stinner in branch 'main':
bpo-21302: Add nanosleep() implementation for time.sleep() in Unix (GH-28545)
7834ff2
vstinner commentedon Sep 25, 2021
Thanks Livius for all these nice enhancements!
Livius90 commentedon Sep 25, 2021
Do you have any information about when will be it released in 3.11?
vstinner commentedon Sep 25, 2021
Here is a schedule of Python 3.11 releases:
https://www.python.org/dev/peps/pep-0664/
In the meanwhile, you can develop a C extension to get the feature.
Livius90 commentedon Oct 9, 2021
https://www.python.org/downloads/windows/
"Note that Python 3.10.0 cannot be used on Windows 7 or earlier."
vstinner: Is it true that Windows 7 is not supported OS anymore? In this case we do not need to care about Windows 7 and earlier Windows OS compatibility and it is time to use nicely GetSystemTimePreciseAsFileTime() in time.time() and time.sleep() as absolute sleeping because it is available since Windows 8.
vstinner commentedon Oct 9, 2021
See bpo-19007 for that.
In Python 3.11, time.sleep() is now always implemented with a waitable timer. I chose to use a relative timeout since it's simpler to implement. Is there any benefit of calling SetWaitableTimer() with an absolute timeout, compared to calling it with a relative timeout?
eryksun commentedon Oct 9, 2021
A regular waitable timer in Windows becomes signaled with the same resolution as Sleep(). It's based on the current interrupt timer period, which can be lowered to 1 ms via timeBeginPeriod(). Compared to Sleep() it's more flexible in terms of periodic waits, WaitForMultipleObjects(), or MsgWaitForMultipleObjects() -- not that time.sleep() needs this flexibility.
That said, using a waitable timer leaves the door open for improvement in future versions of Python. In particular, it's possible to get higher resolution in newer versions of Windows 10 and Windows 11 with CreateWaitableTimerExW() and the undocumented flag CREATE_WAITABLE_TIMER_HIGH_RESOLUTION (2).
Livius90 commentedon Oct 10, 2021
Absolute timeout implementation via SetWaitableTimer() and GetSystemTimePreciseAsFileTime() is always better because it can reduce the "waste time" or "overhead time" what is always exist in any simple interval sleep implementation. Moreover, it is the only one which is eqvivalent with clock_nanosleep() implementation of Linux which is now the most state of the art implementation for precise sleeping.
So, my opinion is that absolute timeout implementation could be the most modern and sustainable for future python.
eryksun commentedon Oct 10, 2021
No, the due time of a timer object is stored in absolute interrupt time, not absolute system time. This has to be calculated either way, and it's actually more work for the kernel if an absolute system time is passed.
Livius90 commentedon Oct 10, 2021
It is not true that there are no benefits. Absolute timeout using can reduce the overhead time of any variable and object intialization cost before the WaitForMultipleObjects() which will perform the real sleeping via blocking wait in pysleep(). GetSystemTimePreciseAsFileTime() must be call at the first line as much as it can in pysleep(). This is the same implementation in Linux via clock_nanosleep().
So, to using absolute timeout and GetSystemTimePreciseAsFileTime() can improves the accuracy of the desired sleep time. For example if sleep = 2.0 sec then real relative sleep time = 2.001234 sec, but absolute sleep time = 2.000012 sec.
Benefits are in not the technicaly backgorund, rather it is in the usecase.
Livius90 commentedon Oct 10, 2021
In other words, using absolute timeout can eliminate the systematic error of desired sleep time.
eryksun commentedon Oct 10, 2021
Again, timer objects store the due time in interrupt time, not system time (i.e. InterruptTime vs SystemTime in the KUSER_SHARED_DATA record). The due time gets set as the current interrupt time plus a relative due time. If the due time is passed as absolute system time, the kernel just computes the delta from the current system time.
The timer object does record whether the requested due time is an absolute system time. This allows the kernel to recompute all absolute due times when the system time is changed manually. This is also the primary reason one wouldn't implement time.sleep() with absolute system time.
It would not improve the resolution. Timer objects are signaled when their due time is at or before the current interrupt time. The latter gets updated by the timer interrupt service routine, by default every 15.625 ms -- or at least that used to be the case.
The undocumented flag CREATE_WAITABLE_TIMER_HIGH_RESOLUTION creates a different timer type, called an "IRTimer" (implemented in Windows 8.1, but back then only accessible in the NT API). This timer type is based on precise interrupt time, which is interpolated using the performance counter. I don't know how the implementation of the timer interrupt has changed to support this increased resolution. It could be that the default 15.625 ms interrupt period is being simulated for compatibility with classic timers and Sleep(). I'd love for the CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag and the behavior of IRTimer objects to be documented.
vstinner commentedon Oct 11, 2021
I created bpo-45429 "[Windows] time.sleep() should use CREATE_WAITABLE_TIMER_HIGH_RESOLUTION".
vstinner commentedon Oct 11, 2021
This issue is closed. If you consider that time.sleep() has a bug or could be enhanced, please open a new issue.
Livius90 commentedon Nov 12, 2022
Just for some high-lights, i did some test-run with bench.py:
Linux - i.MX7D ARM
Python 3.8
Python 3.11
Windows 10 - i7-10850H PC
Python 3.10
Python 3.11
executors: allow clock_nanosleep in Python. clean up syscalls
gpshead commentedon Dec 1, 2023
While I'm assuming this has to do with something we'll discover on our internal production platforms at work... is anyone else seeing
time.sleephang when you've compiled your 3.11 runtime such that it usesclock_nanosleep()instead of the old originalselect()code?vstinner commentedon Dec 1, 2023
Python calls
clock_nanosleep()on clockCLOCK_MONOTONIC. It computes the absolute time using_PyTime_GetMonotonicClockWithInfo(). On Linux,_PyTime_GetMonotonicClockWithInfo()should beclock_gettime(CLOCK_MONOTONIC). It should be the same clock.Maybe check that both code paths use the same clock?
gpshead commentedon Dec 2, 2023
we found a broken CLOCK_MONOTONIC in some environments. we've worked around it until that gets fixed.
executors: allow clock_nanosleep in Python. clean up syscalls
executors: allow clock_nanosleep in Python. clean up syscalls
executors: allow clock_nanosleep in Python. clean up syscalls
executors: allow clock_nanosleep in Python. clean up syscalls
executors: allow clock_nanosleep in Python. clean up syscalls
executors: allow clock_nanosleep in Python. clean up syscalls
executors: allow clock_nanosleep in Python. clean up syscalls
executors: allow clock_nanosleep in Python. clean up syscalls