From 0387c34f7c91428681ca8a4ba4e3d22b9acffde4 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 26 Sep 2024 10:53:17 +0200 Subject: [PATCH] gh-124402: Speed up test_free_threading and test_super (#124491) * Reduce the number of iterations and the number of threads so a whole test file takes less than a minute. * Refactor test_racing_iter_extend() to remove two levels of indentation. * test_monitoring() uses a sleep of 100 ms instead of 1 second. --- Lib/test/test_free_threading/test_list.py | 67 +++++++++---------- .../test_free_threading/test_monitoring.py | 14 ++-- Lib/test/test_free_threading/test_type.py | 6 +- Lib/test/test_super.py | 7 +- 4 files changed, 41 insertions(+), 53 deletions(-) diff --git a/Lib/test/test_free_threading/test_list.py b/Lib/test/test_free_threading/test_list.py index c6b58fcd86f449..a705161369e8dd 100644 --- a/Lib/test/test_free_threading/test_list.py +++ b/Lib/test/test_free_threading/test_list.py @@ -3,10 +3,13 @@ from threading import Thread from unittest import TestCase -from test import support from test.support import threading_helper +NTHREAD = 10 +OBJECT_COUNT = 5_000 + + class C: def __init__(self, v): self.v = v @@ -14,11 +17,8 @@ def __init__(self, v): @threading_helper.requires_working_threading() class TestList(TestCase): - @support.requires_resource('cpu') def test_racing_iter_append(self): - l = [] - OBJECT_COUNT = 10000 def writer_func(): for i in range(OBJECT_COUNT): @@ -34,7 +34,7 @@ def reader_func(): writer = Thread(target=writer_func) readers = [] - for x in range(30): + for x in range(NTHREAD): reader = Thread(target=reader_func) readers.append(reader) reader.start() @@ -44,39 +44,32 @@ def reader_func(): for reader in readers: reader.join() - @support.requires_resource('cpu') def test_racing_iter_extend(self): - iters = [ - lambda x: [x], - ] - for iter_case in iters: - with self.subTest(iter=iter_case): - l = [] - OBJECT_COUNT = 10000 - - def writer_func(): - for i in range(OBJECT_COUNT): - l.extend(iter_case(C(i + OBJECT_COUNT))) - - def reader_func(): - while True: - count = len(l) - for i, x in enumerate(l): - self.assertEqual(x.v, i + OBJECT_COUNT) - if count == OBJECT_COUNT: - break - - writer = Thread(target=writer_func) - readers = [] - for x in range(30): - reader = Thread(target=reader_func) - readers.append(reader) - reader.start() - - writer.start() - writer.join() - for reader in readers: - reader.join() + l = [] + + def writer_func(): + for i in range(OBJECT_COUNT): + l.extend([C(i + OBJECT_COUNT)]) + + def reader_func(): + while True: + count = len(l) + for i, x in enumerate(l): + self.assertEqual(x.v, i + OBJECT_COUNT) + if count == OBJECT_COUNT: + break + + writer = Thread(target=writer_func) + readers = [] + for x in range(NTHREAD): + reader = Thread(target=reader_func) + readers.append(reader) + reader.start() + + writer.start() + writer.join() + for reader in readers: + reader.join() if __name__ == "__main__": diff --git a/Lib/test/test_free_threading/test_monitoring.py b/Lib/test/test_free_threading/test_monitoring.py index be582455d118ac..8fec01715531cb 100644 --- a/Lib/test/test_free_threading/test_monitoring.py +++ b/Lib/test/test_free_threading/test_monitoring.py @@ -7,7 +7,6 @@ import weakref from sys import monitoring -from test import support from test.support import threading_helper from threading import Thread, _PyRLock from unittest import TestCase @@ -15,7 +14,7 @@ class InstrumentationMultiThreadedMixin: thread_count = 10 - func_count = 200 + func_count = 50 fib = 12 def after_threads(self): @@ -37,14 +36,13 @@ def work(self, n, funcs): def start_work(self, n, funcs): # With the GIL builds we need to make sure that the hooks have # a chance to run as it's possible to run w/o releasing the GIL. - time.sleep(1) + time.sleep(0.1) self.work(n, funcs) def after_test(self): """Runs once after the test is done""" pass - @support.requires_resource('cpu') def test_instrumentation(self): # Setup a bunch of functions which will need instrumentation... funcs = [] @@ -220,29 +218,31 @@ def test_register_callback(self): for ref in self.refs: self.assertEqual(ref(), None) - @support.requires_resource('cpu') def test_set_local_trace_opcodes(self): def trace(frame, event, arg): frame.f_trace_opcodes = True return trace + loops = 1_000 + sys.settrace(trace) try: l = _PyRLock() def f(): - for i in range(3000): + for i in range(loops): with l: pass t = Thread(target=f) t.start() - for i in range(3000): + for i in range(loops): with l: pass t.join() finally: sys.settrace(None) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_free_threading/test_type.py b/Lib/test/test_free_threading/test_type.py index 977bfd2c7fd2f7..51463b6bb8c1b4 100644 --- a/Lib/test/test_free_threading/test_type.py +++ b/Lib/test/test_free_threading/test_type.py @@ -5,7 +5,6 @@ from threading import Thread from unittest import TestCase -from test import support from test.support import threading_helper @@ -97,8 +96,9 @@ def reader_func(): self.run_one(writer_func, reader_func) - @support.requires_resource('cpu') def test___class___modification(self): + loops = 200 + class Foo: pass @@ -108,7 +108,7 @@ class Bar: thing = Foo() def work(): foo = thing - for _ in range(5000): + for _ in range(loops): foo.__class__ = Bar type(foo) foo.__class__ = Foo diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py index b0d1f12513d404..1222ec6a3c4109 100644 --- a/Lib/test/test_super.py +++ b/Lib/test/test_super.py @@ -4,7 +4,6 @@ import threading import unittest from unittest.mock import patch -from test import support from test.support import import_helper, threading_helper @@ -515,10 +514,6 @@ def test___class___modification_multithreaded(self): an audit hook. """ - if support.Py_GIL_DISABLED: - # gh-124402: On a Free Threaded build, the test takes a few minutes - support.requires('cpu') - class Foo: pass @@ -528,7 +523,7 @@ class Bar: thing = Foo() def work(): foo = thing - for _ in range(5000): + for _ in range(200): foo.__class__ = Bar type(foo) foo.__class__ = Foo