Skip to content

time.sleep (floatsleep()) should use clock_nanosleep() on Linux #65501

Closed

Description

@shankarunni
BPO 21302
Nosy @vstinner, @4kir4, @1st1, @eryksun, @Livius90
PRs
  • [3.10] bpo-21302: Add clock_nanosleep() implementation for time.sleep() in Linux #28077
  • bpo-21302: Add clock_nanosleep() implementation for time.sleep() #28111
  • bpo-21302: Update time.sleep() doc for clock_nanosleep() #28311
  • bpo-21302: Add Waitable timer implementation for time.sleep() in Windows #28341
  • bpo-21302: Add _PyTime_AsNanoseconds() #28350
  • bpo-21302: time.sleep() uses waitable timer on Windows #28483
  • bpo-21302: Add nanosleep() implementation for time.sleep() in Unix #28526
  • bpo-21302: Add nanosleep() implementation for time.sleep() in Unix #28545
  • Files
  • wait.py
  • bench.py
  • 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']

    Activity

    1. shankarunni commented on Apr 18, 2014

      shankarunnimannequin
      MannequinAuthor

      I know that an earlier request to use nanosleep() has been rejected as "wontfix", but I'm filing this one for a different reason.

      Today, timemodule.c:floatsleep() calls select() on platforms that support it. On Linux, select() with a timeout has an unfortunate property that it is very sensitive to clock jumps, because it computes a sleep end time based on the current kernel timestamp.

      If the system clock is yanked back (by ntpd, or other processes), then the process can end up sleeping for a very long time. (E.g. if the clock is yanked back by half an hour while we are in the middle of, say, a sleep(10), then the process will sleep until "original_kernel_clock+10", which will turn into a half-hour sleep.

      Yes, systems shouldn't jerk their clocks around, but we can't often control this sort of thing on end-user environments.

      Using clock_nanosleep(CLOCK_MONOTONIC, 0, <timespec>, NULL) makes the sleep a much more reliable thing, and mostly insensitive to such jumps. (It'll still be affected by any adjtime(), but that's OK in this case).

    2. added
      stdlibStandard Library Python modules in the Lib/ directory
      type-bugAn unexpected behavior, bug, or error
      on Apr 18, 2014
    3. shankarunni commented on Apr 18, 2014

      shankarunnimannequin
      MannequinAuthor

      I'm working on a patch, but I noticed a similar issue in Condition.wait(), which also keeps re-evaluating the "remaining sleep time" based on the current kernel clock, with similar effects.

      I'll try to address both issues, or we could open a separate bug for the latter..

    4. vstinner commented on Apr 26, 2014

      @vstinner
      Member

      I know that an earlier request to use nanosleep() has been rejected as "wontfix"

      It was the issue bpo-13981. I created this issue while I worked on the PEP-410 (nanosecond timestamp). I closed the issue myself, it doesn't mean that Python must not use the function, just that I didn't want to work on it anymore at this time.

    5. vstinner commented on Apr 26, 2014

      @vstinner
      Member

      "I'm working on a patch, but I noticed a similar issue in Condition.wait(), which also keeps re-evaluating the "remaining sleep time" based on the current kernel clock, with similar effects."

      I see that Lock.acquire(timeout) uses the C function gettimeofday() to recompute the timeout if acquiring the lock was interrupted (C error "EINTR"). It would be better to use a monotonic clock here, but please open a new issue because it's unrelated to nanosleep().

      Or did you another bug?

      By the way, you didn't mention the Python version. Are you working on Python 2.7 or 3.5?

      See also the PEP-418.

    6. vstinner commented on Apr 26, 2014

      @vstinner
      Member

      If you want to modify time.sleep(), you must be careful of the portability: Windows, Linux, but also Mac OS X, FreeBSD, Solaris, etc.

      Try to describe the behaviour of each underlying C function on each platform to be able to describe the "portable behaviour" on all platforms, especially the expected behaviour when the system clock is changed (is time.sleep impacted or not? always?) and the expected behaviour when the system is suspended.

      For example, it looks like nanosleep() uses a different clock depending on OS (Linux uses CLOCK_MONOTONIC, other UNIX platforms use CLOCK_REALTIME).
      http://lists.gnu.org/archive/html/bug-coreutils/2012-08/msg00087.html

      I know that you suggest to use clock_nanosleep(), but this function is not available on all platforms. For example, I would not use it on Windows.

      Another example (on Fedora?): "sleep() ignores time spent with a suspended system"
      http://mjg59.dreamwidth.org/7846.html

      You should also decide how to handle interrupted sleep (C error "EINTR"). Currently, the sleep is interrupted, no error is raised.

      I began to describe all these functions in the PEP-418, even if I didn't change the implementation with the PEP:
      http://legacy.python.org/dev/peps/pep-0418/#sleep

    7. shankarunni commented on Apr 27, 2014

      shankarunnimannequin
      MannequinAuthor

      If you want to modify time.sleep(), you must be careful of the portability: Windows, Linux, but also Mac OS X, FreeBSD, Solaris, etc.

      Oh, I totally agree. What I'm trying to do is to define another autoconf flag (HAVE_CLOCK_NANOSLEEP), that does a feature test and enable that flag, and just use that if available.

      Now that's a good point that if we have clock_nanosleep() on another platform (non-Linux) and it does the wrong thing, then I might have to add further discrimination.

      For now, one sticking point that I've stumbled across is that clock_nanosleep() requires "-lrt". Complicates the autoconf check a bit.

    8. vstinner commented on Apr 27, 2014

      @vstinner
      Member

      2014-04-27 2:26 GMT+02:00 Shankar Unni <report@bugs.python.org>:

      > If you want to modify time.sleep(), you must be careful of the portability: Windows, Linux, but also Mac OS X, FreeBSD, Solaris, etc.

      Oh, I totally agree. What I'm trying to do is to define another autoconf flag (HAVE_CLOCK_NANOSLEEP), that does a feature test and enable that flag, and just use that if available.

      I'm talking about the expected behaviour which can be found in the
      documentation of the function:
      https://docs.python.org/dev/library/time.html#time.sleep

    9. Livius90 commented on Sep 5, 2021

      Livius90mannequin
      Mannequin

      Can you review my final implementation?
      #28111

    10. vstinner commented on Sep 13, 2021

      @vstinner
      Member

      New changeset 85a4748 by Livius in branch 'main':
      bpo-21302: Add clock_nanosleep() implementation for time.sleep() (GH-28111)
      85a4748

    11. vstinner commented on Sep 13, 2021

      @vstinner
      Member

      New changeset 85dc53a by Victor Stinner in branch 'main':
      bpo-21302: Update time.sleep() doc for clock_nanosleep() (GH-28311)
      85dc53a

    12. vstinner commented on Sep 15, 2021

      @vstinner
      Member

      New changeset b49263b by Victor Stinner in branch 'main':
      bpo-21302: Add _PyTime_AsNanoseconds() (GH-28350)
      b49263b

    13. vstinner commented on Sep 20, 2021

      @vstinner
      Member

      wait.py: script to test the time.sleep() function. Press CTRL+C multiple times during the sleep to check that even if the sleep is interrupted, time.sleep() sleeps the expected duration.

    14. 20 remaining items

    15. vstinner commented on Oct 11, 2021

      @vstinner
      Member

      This issue is closed. If you consider that time.sleep() has a bug or could be enhanced, please open a new issue.

    16. transferred this issue fromon Apr 10, 2022
    17. Livius90 commented on Nov 12, 2022

      @Livius90
      Contributor

      Just for some high-lights, i did some test-run with bench.py:

      Linux - i.MX7D ARM

      Python 3.8
      root@myARM:~# python3 bench.py
      time.sleep(0.001) benchmark...
      Mean +- std dev: 1.1 ms +- 22.5 us (26525 values)
      
      root@myARM:~# python3 bench.py
      time.sleep(0.0001) benchmark...
      Mean +- std dev: 227.1 us +- 18.6 us (125174 values)
      Python 3.11
      root@myARM:~# python3 bench.py
      time.sleep(0.001) benchmark...
      Mean +- std dev: 1.1 ms +- 6.4 us (27686 values)
      
      root@myARM:~# python3 bench.py
      time.sleep(0.0001) benchmark...
      Mean +- std dev: 170.2 us +- 5.7 us (164893 values)

      Windows 10 - i7-10850H PC

      Python 3.10
      time.sleep(0.001) benchmark...
      Mean +- std dev: 15.9 ms +- 350.9 us (1889 values)
      
      time.sleep(0.0001) benchmark...
      Mean +- std dev: 15.9 ms +- 341.1 us (1888 values)
      Python 3.11
      time.sleep(0.001) benchmark...
      Mean +- std dev: 1.6 ms +- 339.6 us (19180 values)
      
      time.sleep(0.0001) benchmark...
      Mean +- std dev: 574.6 us +- 95.2 us (51837 values)
    18. gpshead commented on Dec 1, 2023

      @gpshead
      Member

      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.sleep hang when you've compiled your 3.11 runtime such that it uses clock_nanosleep() instead of the old original select() code?

    19. vstinner commented on Dec 1, 2023

      @vstinner
      Member

      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.sleep hang when you've compiled your 3.11 runtime such that it uses clock_nanosleep() instead of the old original select() code?

      Python calls clock_nanosleep() on clock CLOCK_MONOTONIC. It computes the absolute time using _PyTime_GetMonotonicClockWithInfo(). On Linux, _PyTime_GetMonotonicClockWithInfo() should be clock_gettime(CLOCK_MONOTONIC). It should be the same clock.

      Maybe check that both code paths use the same clock?

    20. gpshead commented on Dec 2, 2023

      @gpshead
      Member

      we found a broken CLOCK_MONOTONIC in some environments. we've worked around it until that gets fixed.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      3.11only security fixesstdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions