https://github.com/python/cpython/commit/11f457cf41beede182d7387080f35c73f8f4a46f
commit: 11f457cf41beede182d7387080f35c73f8f4a46f
branch: main
author: Chris Eibl <138194463+chris-e...@users.noreply.github.com>
committer: encukou <encu...@gmail.com>
date: 2025-04-28T13:55:08+02:00
summary:

GH-114911: use time.perf_counter in Stopwatch (GH-131469)


Co-authored-by: Petr Viktorin <encu...@gmail.com>
Co-authored-by: Hugo van Kemenade <1324225+hug...@users.noreply.github.com>

files:
M Lib/test/support/__init__.py
M Lib/test/test_int.py
M Lib/test/test_re.py

diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 146cbaaf4cb854..82f881094982f6 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -2586,30 +2586,30 @@ def sleeping_retry(timeout, err_msg=None, /,
         delay = min(delay * 2, max_delay)
 
 
-class CPUStopwatch:
+class Stopwatch:
     """Context manager to roughly time a CPU-bound operation.
 
-    Disables GC. Uses CPU time if it can (i.e. excludes sleeps & time of
-    other processes).
+    Disables GC. Uses perf_counter, which is a clock with the highest
+    available resolution. It is chosen even though it does include
+    time elapsed during sleep and is system-wide, because the
+    resolution of process_time is too coarse on Windows and
+    process_time does not exist everywhere (for example, WASM).
 
-    N.B.:
-    - This *includes* time spent in other threads.
+    Note:
+    - This *includes* time spent in other threads/processes.
     - Some systems only have a coarse resolution; check
-      stopwatch.clock_info.rseolution if.
+      stopwatch.clock_info.resolution when using the results.
 
     Usage:
 
-    with ProcessStopwatch() as stopwatch:
+    with Stopwatch() as stopwatch:
         ...
     elapsed = stopwatch.seconds
     resolution = stopwatch.clock_info.resolution
     """
     def __enter__(self):
-        get_time = time.process_time
-        clock_info = time.get_clock_info('process_time')
-        if get_time() <= 0:  # some platforms like WASM lack process_time()
-            get_time = time.monotonic
-            clock_info = time.get_clock_info('monotonic')
+        get_time = time.perf_counter
+        clock_info = time.get_clock_info('perf_counter')
         self.context = disable_gc()
         self.context.__enter__()
         self.get_time = get_time
diff --git a/Lib/test/test_int.py b/Lib/test/test_int.py
index d1bf847a7a3e9f..245528ce57a146 100644
--- a/Lib/test/test_int.py
+++ b/Lib/test/test_int.py
@@ -590,7 +590,7 @@ def test_denial_of_service_prevented_int_to_str(self):
         digits = 78_268
         with (
                 support.adjust_int_max_str_digits(digits),
-                support.CPUStopwatch() as sw_convert):
+                support.Stopwatch() as sw_convert):
             huge_decimal = str(huge_int)
         self.assertEqual(len(huge_decimal), digits)
         # Ensuring that we chose a slow enough conversion to measure.
@@ -605,7 +605,7 @@ def test_denial_of_service_prevented_int_to_str(self):
         with support.adjust_int_max_str_digits(int(.995 * digits)):
             with (
                     self.assertRaises(ValueError) as err,
-                    support.CPUStopwatch() as sw_fail_huge):
+                    support.Stopwatch() as sw_fail_huge):
                 str(huge_int)
         self.assertIn('conversion', str(err.exception))
         self.assertLessEqual(sw_fail_huge.seconds, sw_convert.seconds/2)
@@ -615,7 +615,7 @@ def test_denial_of_service_prevented_int_to_str(self):
         extra_huge_int = int(f'0x{"c"*500_000}', base=16)  # 602060 digits.
         with (
                 self.assertRaises(ValueError) as err,
-                support.CPUStopwatch() as sw_fail_extra_huge):
+                support.Stopwatch() as sw_fail_extra_huge):
             # If not limited, 8 seconds said Zen based cloud VM.
             str(extra_huge_int)
         self.assertIn('conversion', str(err.exception))
@@ -630,7 +630,7 @@ def test_denial_of_service_prevented_str_to_int(self):
         huge = '8'*digits
         with (
                 support.adjust_int_max_str_digits(digits),
-                support.CPUStopwatch() as sw_convert):
+                support.Stopwatch() as sw_convert):
             int(huge)
         # Ensuring that we chose a slow enough conversion to measure.
         # It takes 0.1 seconds on a Zen based cloud VM in an opt build.
@@ -642,7 +642,7 @@ def test_denial_of_service_prevented_str_to_int(self):
         with support.adjust_int_max_str_digits(digits - 1):
             with (
                     self.assertRaises(ValueError) as err,
-                    support.CPUStopwatch() as sw_fail_huge):
+                    support.Stopwatch() as sw_fail_huge):
                 int(huge)
         self.assertIn('conversion', str(err.exception))
         self.assertLessEqual(sw_fail_huge.seconds, sw_convert.seconds/2)
@@ -652,7 +652,7 @@ def test_denial_of_service_prevented_str_to_int(self):
         extra_huge = '7'*1_200_000
         with (
                 self.assertRaises(ValueError) as err,
-                support.CPUStopwatch() as sw_fail_extra_huge):
+                support.Stopwatch() as sw_fail_extra_huge):
             # If not limited, 8 seconds in the Zen based cloud VM.
             int(extra_huge)
         self.assertIn('conversion', str(err.exception))
diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py
index f65b4076aee2c6..cf8525ed901ad3 100644
--- a/Lib/test/test_re.py
+++ b/Lib/test/test_re.py
@@ -1,7 +1,7 @@
 from test.support import (gc_collect, bigmemtest, _2G,
                           cpython_only, captured_stdout,
                           check_disallow_instantiation, linked_to_musl,
-                          warnings_helper, SHORT_TIMEOUT, CPUStopwatch, 
requires_resource)
+                          warnings_helper, SHORT_TIMEOUT, Stopwatch, 
requires_resource)
 import locale
 import re
 import string
@@ -2467,7 +2467,7 @@ def test_bug_40736(self):
     @requires_resource('cpu')
     def test_search_anchor_at_beginning(self):
         s = 'x'*10**7
-        with CPUStopwatch() as stopwatch:
+        with Stopwatch() as stopwatch:
             for p in r'\Ay', r'^y':
                 self.assertIsNone(re.search(p, s))
                 self.assertEqual(re.split(p, s), [s])

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to