mirror of
https://github.com/python/cpython.git
synced 2025-09-27 10:50:04 +00:00
GH-114911: use time.perf_counter in Stopwatch (GH-131469)
Co-authored-by: Petr Viktorin <encukou@gmail.com> Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
This commit is contained in:
parent
e577439803
commit
11f457cf41
3 changed files with 20 additions and 20 deletions
|
@ -2586,30 +2586,30 @@ def sleeping_retry(timeout, err_msg=None, /,
|
||||||
delay = min(delay * 2, max_delay)
|
delay = min(delay * 2, max_delay)
|
||||||
|
|
||||||
|
|
||||||
class CPUStopwatch:
|
class Stopwatch:
|
||||||
"""Context manager to roughly time a CPU-bound operation.
|
"""Context manager to roughly time a CPU-bound operation.
|
||||||
|
|
||||||
Disables GC. Uses CPU time if it can (i.e. excludes sleeps & time of
|
Disables GC. Uses perf_counter, which is a clock with the highest
|
||||||
other processes).
|
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.:
|
Note:
|
||||||
- This *includes* time spent in other threads.
|
- This *includes* time spent in other threads/processes.
|
||||||
- Some systems only have a coarse resolution; check
|
- Some systems only have a coarse resolution; check
|
||||||
stopwatch.clock_info.rseolution if.
|
stopwatch.clock_info.resolution when using the results.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
with ProcessStopwatch() as stopwatch:
|
with Stopwatch() as stopwatch:
|
||||||
...
|
...
|
||||||
elapsed = stopwatch.seconds
|
elapsed = stopwatch.seconds
|
||||||
resolution = stopwatch.clock_info.resolution
|
resolution = stopwatch.clock_info.resolution
|
||||||
"""
|
"""
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
get_time = time.process_time
|
get_time = time.perf_counter
|
||||||
clock_info = time.get_clock_info('process_time')
|
clock_info = time.get_clock_info('perf_counter')
|
||||||
if get_time() <= 0: # some platforms like WASM lack process_time()
|
|
||||||
get_time = time.monotonic
|
|
||||||
clock_info = time.get_clock_info('monotonic')
|
|
||||||
self.context = disable_gc()
|
self.context = disable_gc()
|
||||||
self.context.__enter__()
|
self.context.__enter__()
|
||||||
self.get_time = get_time
|
self.get_time = get_time
|
||||||
|
|
|
@ -590,7 +590,7 @@ class IntStrDigitLimitsTests(unittest.TestCase):
|
||||||
digits = 78_268
|
digits = 78_268
|
||||||
with (
|
with (
|
||||||
support.adjust_int_max_str_digits(digits),
|
support.adjust_int_max_str_digits(digits),
|
||||||
support.CPUStopwatch() as sw_convert):
|
support.Stopwatch() as sw_convert):
|
||||||
huge_decimal = str(huge_int)
|
huge_decimal = str(huge_int)
|
||||||
self.assertEqual(len(huge_decimal), digits)
|
self.assertEqual(len(huge_decimal), digits)
|
||||||
# Ensuring that we chose a slow enough conversion to measure.
|
# Ensuring that we chose a slow enough conversion to measure.
|
||||||
|
@ -605,7 +605,7 @@ class IntStrDigitLimitsTests(unittest.TestCase):
|
||||||
with support.adjust_int_max_str_digits(int(.995 * digits)):
|
with support.adjust_int_max_str_digits(int(.995 * digits)):
|
||||||
with (
|
with (
|
||||||
self.assertRaises(ValueError) as err,
|
self.assertRaises(ValueError) as err,
|
||||||
support.CPUStopwatch() as sw_fail_huge):
|
support.Stopwatch() as sw_fail_huge):
|
||||||
str(huge_int)
|
str(huge_int)
|
||||||
self.assertIn('conversion', str(err.exception))
|
self.assertIn('conversion', str(err.exception))
|
||||||
self.assertLessEqual(sw_fail_huge.seconds, sw_convert.seconds/2)
|
self.assertLessEqual(sw_fail_huge.seconds, sw_convert.seconds/2)
|
||||||
|
@ -615,7 +615,7 @@ class IntStrDigitLimitsTests(unittest.TestCase):
|
||||||
extra_huge_int = int(f'0x{"c"*500_000}', base=16) # 602060 digits.
|
extra_huge_int = int(f'0x{"c"*500_000}', base=16) # 602060 digits.
|
||||||
with (
|
with (
|
||||||
self.assertRaises(ValueError) as err,
|
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.
|
# If not limited, 8 seconds said Zen based cloud VM.
|
||||||
str(extra_huge_int)
|
str(extra_huge_int)
|
||||||
self.assertIn('conversion', str(err.exception))
|
self.assertIn('conversion', str(err.exception))
|
||||||
|
@ -630,7 +630,7 @@ class IntStrDigitLimitsTests(unittest.TestCase):
|
||||||
huge = '8'*digits
|
huge = '8'*digits
|
||||||
with (
|
with (
|
||||||
support.adjust_int_max_str_digits(digits),
|
support.adjust_int_max_str_digits(digits),
|
||||||
support.CPUStopwatch() as sw_convert):
|
support.Stopwatch() as sw_convert):
|
||||||
int(huge)
|
int(huge)
|
||||||
# Ensuring that we chose a slow enough conversion to measure.
|
# 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.
|
# It takes 0.1 seconds on a Zen based cloud VM in an opt build.
|
||||||
|
@ -642,7 +642,7 @@ class IntStrDigitLimitsTests(unittest.TestCase):
|
||||||
with support.adjust_int_max_str_digits(digits - 1):
|
with support.adjust_int_max_str_digits(digits - 1):
|
||||||
with (
|
with (
|
||||||
self.assertRaises(ValueError) as err,
|
self.assertRaises(ValueError) as err,
|
||||||
support.CPUStopwatch() as sw_fail_huge):
|
support.Stopwatch() as sw_fail_huge):
|
||||||
int(huge)
|
int(huge)
|
||||||
self.assertIn('conversion', str(err.exception))
|
self.assertIn('conversion', str(err.exception))
|
||||||
self.assertLessEqual(sw_fail_huge.seconds, sw_convert.seconds/2)
|
self.assertLessEqual(sw_fail_huge.seconds, sw_convert.seconds/2)
|
||||||
|
@ -652,7 +652,7 @@ class IntStrDigitLimitsTests(unittest.TestCase):
|
||||||
extra_huge = '7'*1_200_000
|
extra_huge = '7'*1_200_000
|
||||||
with (
|
with (
|
||||||
self.assertRaises(ValueError) as err,
|
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.
|
# If not limited, 8 seconds in the Zen based cloud VM.
|
||||||
int(extra_huge)
|
int(extra_huge)
|
||||||
self.assertIn('conversion', str(err.exception))
|
self.assertIn('conversion', str(err.exception))
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from test.support import (gc_collect, bigmemtest, _2G,
|
from test.support import (gc_collect, bigmemtest, _2G,
|
||||||
cpython_only, captured_stdout,
|
cpython_only, captured_stdout,
|
||||||
check_disallow_instantiation, linked_to_musl,
|
check_disallow_instantiation, linked_to_musl,
|
||||||
warnings_helper, SHORT_TIMEOUT, CPUStopwatch, requires_resource)
|
warnings_helper, SHORT_TIMEOUT, Stopwatch, requires_resource)
|
||||||
import locale
|
import locale
|
||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
|
@ -2467,7 +2467,7 @@ class ReTests(unittest.TestCase):
|
||||||
@requires_resource('cpu')
|
@requires_resource('cpu')
|
||||||
def test_search_anchor_at_beginning(self):
|
def test_search_anchor_at_beginning(self):
|
||||||
s = 'x'*10**7
|
s = 'x'*10**7
|
||||||
with CPUStopwatch() as stopwatch:
|
with Stopwatch() as stopwatch:
|
||||||
for p in r'\Ay', r'^y':
|
for p in r'\Ay', r'^y':
|
||||||
self.assertIsNone(re.search(p, s))
|
self.assertIsNone(re.search(p, s))
|
||||||
self.assertEqual(re.split(p, s), [s])
|
self.assertEqual(re.split(p, s), [s])
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue