diff options
author | Petr Viktorin <encukou@gmail.com> | 2024-02-28 11:53:48 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-28 11:53:48 (GMT) |
commit | 7acf1fb5a70776429bd99e741d69471eb2d1c1bb (patch) | |
tree | 4b2f0bd7f2aaa03f84f3b77638de09eac892f150 /Lib/test/support | |
parent | 3b63d0769f49171f53e9cecc686fa01a383bd4b1 (diff) | |
download | cpython-7acf1fb5a70776429bd99e741d69471eb2d1c1bb.zip cpython-7acf1fb5a70776429bd99e741d69471eb2d1c1bb.tar.gz cpython-7acf1fb5a70776429bd99e741d69471eb2d1c1bb.tar.bz2 |
gh-114911: Add CPUStopwatch test helper (GH-114912)
A few of our tests measure the time of CPU-bound operation, mainly
to avoid quadratic or worse behaviour.
Add a helper to ignore GC and time spent in other processes.
Diffstat (limited to 'Lib/test/support')
-rw-r--r-- | Lib/test/support/__init__.py | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 1d03ec0..401b2ce 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2381,6 +2381,46 @@ def sleeping_retry(timeout, err_msg=None, /, delay = min(delay * 2, max_delay) +class CPUStopwatch: + """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). + + N.B.: + - This *includes* time spent in other threads. + - Some systems only have a coarse resolution; check + stopwatch.clock_info.rseolution if. + + Usage: + + with ProcessStopwatch() 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') + self.context = disable_gc() + self.context.__enter__() + self.get_time = get_time + self.clock_info = clock_info + self.start_time = get_time() + return self + + def __exit__(self, *exc): + try: + end_time = self.get_time() + finally: + result = self.context.__exit__(*exc) + self.seconds = end_time - self.start_time + return result + + @contextlib.contextmanager def adjust_int_max_str_digits(max_digits): """Temporarily change the integer string conversion length limit.""" |