From 39bb0b1f0d3bc4dc6e5350d0db18b72fb25e4f49 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 25 Oct 2021 00:09:41 +0900 Subject: [PATCH 1/9] bpo-45429: Support CREATE_WAITABLE_TIMER_HIGH_RESOLUTION if possible Co-authored-by: Eryk Sun --- Doc/whatsnew/3.11.rst | 4 +++ .../2021-10-25-01-22-49.bpo-45429.VaEyN9.rst | 3 +++ Modules/timemodule.c | 27 +++++++++++-------- 3 files changed, 23 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2021-10-25-01-22-49.bpo-45429.VaEyN9.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index a03fff8a9e10aef..a7b5a947699146c 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -272,6 +272,10 @@ time a resolution of 1 millisecond (10\ :sup:`-3` seconds). (Contributed by Benjamin Szőke and Victor Stinner in :issue:`21302`.) +* On Windows, :func:`time.sleep` now uses a waitable timer which supports high-resolution timers + without increasing the timer frequency if possible. + (Contributed by Dong-hee Na and Eryk Sun in :issue:`45429`.) + unicodedata ----------- diff --git a/Misc/NEWS.d/next/Library/2021-10-25-01-22-49.bpo-45429.VaEyN9.rst b/Misc/NEWS.d/next/Library/2021-10-25-01-22-49.bpo-45429.VaEyN9.rst new file mode 100644 index 000000000000000..e5c15410be4ee9a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-10-25-01-22-49.bpo-45429.VaEyN9.rst @@ -0,0 +1,3 @@ +On Windows, :func:`time.sleep` now uses a waitable timer which supports +high-resolution timers without increasing the timer frequency if possible. +Patch by Dong-hee Na and Eryk Sun. diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 0ef3b2ffaa89871..e2f0e9c06faeeb3 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -2129,6 +2129,10 @@ pysleep(_PyTime_t timeout) return 0; #else // MS_WINDOWS + +#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION + #define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002 +#endif _PyTime_t timeout_100ns = _PyTime_As100Nanoseconds(timeout, _PyTime_ROUND_CEILING); @@ -2150,20 +2154,21 @@ pysleep(_PyTime_t timeout) // SetWaitableTimer(): a negative due time indicates relative time relative_timeout.QuadPart = -timeout_100ns; - HANDLE timer = CreateWaitableTimerW(NULL, FALSE, NULL); + HANDLE timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); if (timer == NULL) { - PyErr_SetFromWindowsErr(0); - return -1; + timer = CreateWaitableTimerExW(NULL, NULL, 0, TIMER_ALL_ACCESS); + if (timer == NULL) { + // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is not supported. + PyErr_SetFromWindowsErr(0); + return -1; + } } - if (!SetWaitableTimer(timer, &relative_timeout, - // period: the timer is signaled once - 0, - // no completion routine - NULL, NULL, - // Don't restore a system in suspended power - // conservation mode when the timer is signaled. - FALSE)) + if (!SetWaitableTimerEx(timer, &relative_timeout, + 0, // no period; the timer is signaled once + NULL, NULL, // no completion routine + NULL, // no wake context; do not resume from suspend + 0)) // no tolerable delay for timer coalescing { PyErr_SetFromWindowsErr(0); goto error; From 06850bc0d10645f9dbd6ea811bdd22cbdf6bf769 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 25 Oct 2021 01:51:07 +0900 Subject: [PATCH 2/9] bpo-45429: Check timer flags is avaialbe when the module exec phase --- Modules/timemodule.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c index e2f0e9c06faeeb3..83ac6a730b30c03 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -408,6 +408,13 @@ static PyStructSequence_Desc struct_time_type_desc = { static int initialized; static PyTypeObject StructTimeType; +#if defined(MS_WINDOWS) +#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION + #define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002 +#endif + +static DWORD timer_flags = CREATE_WAITABLE_TIMER_HIGH_RESOLUTION; +#endif static PyObject * tmtotuple(struct tm *p @@ -2017,6 +2024,16 @@ time_exec(PyObject *module) utc_string = tm.tm_zone; #endif +#if defined(MS_WINDOWS) + HANDLE timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); + if (timer == NULL) { + timer_flags = 0; + } + else { + CloseHandle(timer); + } +#endif + return 0; } @@ -2130,9 +2147,6 @@ pysleep(_PyTime_t timeout) return 0; #else // MS_WINDOWS -#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION - #define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002 -#endif _PyTime_t timeout_100ns = _PyTime_As100Nanoseconds(timeout, _PyTime_ROUND_CEILING); @@ -2154,14 +2168,11 @@ pysleep(_PyTime_t timeout) // SetWaitableTimer(): a negative due time indicates relative time relative_timeout.QuadPart = -timeout_100ns; - HANDLE timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); + HANDLE timer = CreateWaitableTimerExW(NULL, NULL, timer_flags, TIMER_ALL_ACCESS); if (timer == NULL) { - timer = CreateWaitableTimerExW(NULL, NULL, 0, TIMER_ALL_ACCESS); - if (timer == NULL) { - // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is not supported. - PyErr_SetFromWindowsErr(0); - return -1; - } + // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is not supported. + PyErr_SetFromWindowsErr(0); + return -1; } if (!SetWaitableTimerEx(timer, &relative_timeout, From b8078324b72f6e1934a7ec78df2d43e929ff1589 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 25 Oct 2021 02:01:35 +0900 Subject: [PATCH 3/9] bpo-45429: nit --- Modules/timemodule.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 83ac6a730b30c03..e94afb7d6ee798c 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -2027,6 +2027,7 @@ time_exec(PyObject *module) #if defined(MS_WINDOWS) HANDLE timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); if (timer == NULL) { + // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is not supported. timer_flags = 0; } else { @@ -2146,7 +2147,6 @@ pysleep(_PyTime_t timeout) return 0; #else // MS_WINDOWS - _PyTime_t timeout_100ns = _PyTime_As100Nanoseconds(timeout, _PyTime_ROUND_CEILING); @@ -2170,7 +2170,6 @@ pysleep(_PyTime_t timeout) HANDLE timer = CreateWaitableTimerExW(NULL, NULL, timer_flags, TIMER_ALL_ACCESS); if (timer == NULL) { - // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is not supported. PyErr_SetFromWindowsErr(0); return -1; } From efe9a4c539e2a024d40ecf05007360f871947b84 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 25 Oct 2021 02:09:10 +0900 Subject: [PATCH 4/9] bpo-45429: nit --- Modules/timemodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c index e94afb7d6ee798c..5119d8ba20138ae 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -2025,7 +2025,7 @@ time_exec(PyObject *module) #endif #if defined(MS_WINDOWS) - HANDLE timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); + HANDLE timer = CreateWaitableTimerExW(NULL, NULL, timer_flags, TIMER_ALL_ACCESS); if (timer == NULL) { // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is not supported. timer_flags = 0; From 88dc92400e98bb6af220de93980ae69dde18e379 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 25 Oct 2021 02:24:34 +0900 Subject: [PATCH 5/9] bpo-45429: Address code review --- Modules/timemodule.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 5119d8ba20138ae..88312fd25976d18 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -413,7 +413,7 @@ static PyTypeObject StructTimeType; #define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002 #endif -static DWORD timer_flags = CREATE_WAITABLE_TIMER_HIGH_RESOLUTION; +static DWORD timer_flags = 0x00000003; #endif static PyObject * @@ -2025,13 +2025,19 @@ time_exec(PyObject *module) #endif #if defined(MS_WINDOWS) - HANDLE timer = CreateWaitableTimerExW(NULL, NULL, timer_flags, TIMER_ALL_ACCESS); - if (timer == NULL) { - // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is not supported. - timer_flags = 0; - } - else { - CloseHandle(timer); + if (timer_flags == 0x00000003) { + DWORD test_flags = CREATE_WAITABLE_TIMER_HIGH_RESOLUTION; + HANDLE timer = CreateWaitableTimerExW(NULL, NULL, test_flags, + TIMER_ALL_ACCESS); + if (timer == NULL) { + // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is not supported. + timer_flags = 0; + } + else { + // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is supported. + timer_flags = CREATE_WAITABLE_TIMER_HIGH_RESOLUTION; + CloseHandle(timer); + } } #endif @@ -2168,7 +2174,8 @@ pysleep(_PyTime_t timeout) // SetWaitableTimer(): a negative due time indicates relative time relative_timeout.QuadPart = -timeout_100ns; - HANDLE timer = CreateWaitableTimerExW(NULL, NULL, timer_flags, TIMER_ALL_ACCESS); + HANDLE timer = CreateWaitableTimerExW(NULL, NULL, timer_flags, + TIMER_ALL_ACCESS); if (timer == NULL) { PyErr_SetFromWindowsErr(0); return -1; From 8fb1819a4f8852fd1fc4db8e10a6e54527274c2d Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sun, 24 Oct 2021 17:49:19 +0000 Subject: [PATCH 6/9] bpo-45429: nit --- Modules/timemodule.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 88312fd25976d18..f060524771275ec 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -413,7 +413,8 @@ static PyTypeObject StructTimeType; #define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002 #endif -static DWORD timer_flags = 0x00000003; +#define UNKNOWN_WAITABLE_TIMER_RESOLUTION 0x000000ee +static DWORD timer_flags = UNKNOWN_WAITABLE_TIMER_RESOLUTION; #endif static PyObject * @@ -2025,7 +2026,7 @@ time_exec(PyObject *module) #endif #if defined(MS_WINDOWS) - if (timer_flags == 0x00000003) { + if (timer_flags == UNKNOWN_WAITABLE_TIMER_RESOLUTION) { DWORD test_flags = CREATE_WAITABLE_TIMER_HIGH_RESOLUTION; HANDLE timer = CreateWaitableTimerExW(NULL, NULL, test_flags, TIMER_ALL_ACCESS); From eb073060ef77ce725a3df85984fa5c902b0e4c2c Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sun, 24 Oct 2021 17:54:23 +0000 Subject: [PATCH 7/9] bpo-45429: Address code review --- Modules/timemodule.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Modules/timemodule.c b/Modules/timemodule.c index f060524771275ec..a68e8aefbd1e03a 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -413,8 +413,7 @@ static PyTypeObject StructTimeType; #define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002 #endif -#define UNKNOWN_WAITABLE_TIMER_RESOLUTION 0x000000ee -static DWORD timer_flags = UNKNOWN_WAITABLE_TIMER_RESOLUTION; +static DWORD timer_flags = -1; #endif static PyObject * @@ -2026,7 +2025,7 @@ time_exec(PyObject *module) #endif #if defined(MS_WINDOWS) - if (timer_flags == UNKNOWN_WAITABLE_TIMER_RESOLUTION) { + if ((LONG)timer_flags == -1) { DWORD test_flags = CREATE_WAITABLE_TIMER_HIGH_RESOLUTION; HANDLE timer = CreateWaitableTimerExW(NULL, NULL, test_flags, TIMER_ALL_ACCESS); From ba18321ed5c333ebaf4f0f016a673cdca18b3d73 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Tue, 16 Nov 2021 21:25:29 +0900 Subject: [PATCH 8/9] bpo-45429: Address code review --- .../next/Library/2021-10-25-01-22-49.bpo-45429.VaEyN9.rst | 3 +-- Modules/timemodule.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2021-10-25-01-22-49.bpo-45429.VaEyN9.rst b/Misc/NEWS.d/next/Library/2021-10-25-01-22-49.bpo-45429.VaEyN9.rst index e5c15410be4ee9a..0a274f1ef8ab74c 100644 --- a/Misc/NEWS.d/next/Library/2021-10-25-01-22-49.bpo-45429.VaEyN9.rst +++ b/Misc/NEWS.d/next/Library/2021-10-25-01-22-49.bpo-45429.VaEyN9.rst @@ -1,3 +1,2 @@ On Windows, :func:`time.sleep` now uses a waitable timer which supports -high-resolution timers without increasing the timer frequency if possible. -Patch by Dong-hee Na and Eryk Sun. +high-resolution timers. Patch by Dong-hee Na and Eryk Sun. diff --git a/Modules/timemodule.c b/Modules/timemodule.c index a68e8aefbd1e03a..bb713908eb1e496 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -413,7 +413,7 @@ static PyTypeObject StructTimeType; #define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002 #endif -static DWORD timer_flags = -1; +static DWORD timer_flags = (DWORD)-1; #endif static PyObject * @@ -2025,7 +2025,7 @@ time_exec(PyObject *module) #endif #if defined(MS_WINDOWS) - if ((LONG)timer_flags == -1) { + if (timer_flags == (DWORD)-1) { DWORD test_flags = CREATE_WAITABLE_TIMER_HIGH_RESOLUTION; HANDLE timer = CreateWaitableTimerExW(NULL, NULL, test_flags, TIMER_ALL_ACCESS); From 4c6c9042e9bb97e1040d30a63696f9c7decce5df Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Tue, 16 Nov 2021 21:32:30 +0900 Subject: [PATCH 9/9] bpo-45429: Update whatsnew 3.11 --- Doc/whatsnew/3.11.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index a7b5a947699146c..307e818eb7b3b69 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -272,8 +272,8 @@ time a resolution of 1 millisecond (10\ :sup:`-3` seconds). (Contributed by Benjamin Szőke and Victor Stinner in :issue:`21302`.) -* On Windows, :func:`time.sleep` now uses a waitable timer which supports high-resolution timers - without increasing the timer frequency if possible. +* On Windows, :func:`time.sleep` now uses a waitable timer which supports high-resolution timers. + In Python 3.10, the best resolution was 1 ms, from Python 3.11 it's now smaller than 1 ms. (Contributed by Dong-hee Na and Eryk Sun in :issue:`45429`.) unicodedata