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.
This commit is contained in:
Victor Stinner 2024-09-26 10:53:17 +02:00 committed by GitHub
parent 08a467b537
commit 0387c34f7c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 37 additions and 49 deletions

View File

@ -3,10 +3,13 @@ import unittest
from threading import Thread from threading import Thread
from unittest import TestCase from unittest import TestCase
from test import support
from test.support import threading_helper from test.support import threading_helper
NTHREAD = 10
OBJECT_COUNT = 5_000
class C: class C:
def __init__(self, v): def __init__(self, v):
self.v = v self.v = v
@ -14,11 +17,8 @@ class C:
@threading_helper.requires_working_threading() @threading_helper.requires_working_threading()
class TestList(TestCase): class TestList(TestCase):
@support.requires_resource('cpu')
def test_racing_iter_append(self): def test_racing_iter_append(self):
l = [] l = []
OBJECT_COUNT = 10000
def writer_func(): def writer_func():
for i in range(OBJECT_COUNT): for i in range(OBJECT_COUNT):
@ -34,7 +34,7 @@ class TestList(TestCase):
writer = Thread(target=writer_func) writer = Thread(target=writer_func)
readers = [] readers = []
for x in range(30): for x in range(NTHREAD):
reader = Thread(target=reader_func) reader = Thread(target=reader_func)
readers.append(reader) readers.append(reader)
reader.start() reader.start()
@ -44,39 +44,32 @@ class TestList(TestCase):
for reader in readers: for reader in readers:
reader.join() reader.join()
@support.requires_resource('cpu')
def test_racing_iter_extend(self): def test_racing_iter_extend(self):
iters = [ l = []
lambda x: [x],
]
for iter_case in iters:
with self.subTest(iter=iter_case):
l = []
OBJECT_COUNT = 10000
def writer_func(): def writer_func():
for i in range(OBJECT_COUNT): for i in range(OBJECT_COUNT):
l.extend(iter_case(C(i + OBJECT_COUNT))) l.extend([C(i + OBJECT_COUNT)])
def reader_func(): def reader_func():
while True: while True:
count = len(l) count = len(l)
for i, x in enumerate(l): for i, x in enumerate(l):
self.assertEqual(x.v, i + OBJECT_COUNT) self.assertEqual(x.v, i + OBJECT_COUNT)
if count == OBJECT_COUNT: if count == OBJECT_COUNT:
break break
writer = Thread(target=writer_func) writer = Thread(target=writer_func)
readers = [] readers = []
for x in range(30): for x in range(NTHREAD):
reader = Thread(target=reader_func) reader = Thread(target=reader_func)
readers.append(reader) readers.append(reader)
reader.start() reader.start()
writer.start() writer.start()
writer.join() writer.join()
for reader in readers: for reader in readers:
reader.join() reader.join()
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -7,7 +7,6 @@ import unittest
import weakref import weakref
from sys import monitoring from sys import monitoring
from test import support
from test.support import threading_helper from test.support import threading_helper
from threading import Thread, _PyRLock from threading import Thread, _PyRLock
from unittest import TestCase from unittest import TestCase
@ -15,7 +14,7 @@ from unittest import TestCase
class InstrumentationMultiThreadedMixin: class InstrumentationMultiThreadedMixin:
thread_count = 10 thread_count = 10
func_count = 200 func_count = 50
fib = 12 fib = 12
def after_threads(self): def after_threads(self):
@ -37,14 +36,13 @@ class InstrumentationMultiThreadedMixin:
def start_work(self, n, funcs): def start_work(self, n, funcs):
# With the GIL builds we need to make sure that the hooks have # 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. # 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) self.work(n, funcs)
def after_test(self): def after_test(self):
"""Runs once after the test is done""" """Runs once after the test is done"""
pass pass
@support.requires_resource('cpu')
def test_instrumentation(self): def test_instrumentation(self):
# Setup a bunch of functions which will need instrumentation... # Setup a bunch of functions which will need instrumentation...
funcs = [] funcs = []
@ -220,29 +218,31 @@ class MonitoringMisc(MonitoringTestMixin, TestCase):
for ref in self.refs: for ref in self.refs:
self.assertEqual(ref(), None) self.assertEqual(ref(), None)
@support.requires_resource('cpu')
def test_set_local_trace_opcodes(self): def test_set_local_trace_opcodes(self):
def trace(frame, event, arg): def trace(frame, event, arg):
frame.f_trace_opcodes = True frame.f_trace_opcodes = True
return trace return trace
loops = 1_000
sys.settrace(trace) sys.settrace(trace)
try: try:
l = _PyRLock() l = _PyRLock()
def f(): def f():
for i in range(3000): for i in range(loops):
with l: with l:
pass pass
t = Thread(target=f) t = Thread(target=f)
t.start() t.start()
for i in range(3000): for i in range(loops):
with l: with l:
pass pass
t.join() t.join()
finally: finally:
sys.settrace(None) sys.settrace(None)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -5,7 +5,6 @@ from concurrent.futures import ThreadPoolExecutor
from threading import Thread from threading import Thread
from unittest import TestCase from unittest import TestCase
from test import support
from test.support import threading_helper from test.support import threading_helper
@ -97,8 +96,9 @@ class TestType(TestCase):
self.run_one(writer_func, reader_func) self.run_one(writer_func, reader_func)
@support.requires_resource('cpu')
def test___class___modification(self): def test___class___modification(self):
loops = 200
class Foo: class Foo:
pass pass
@ -108,7 +108,7 @@ class TestType(TestCase):
thing = Foo() thing = Foo()
def work(): def work():
foo = thing foo = thing
for _ in range(5000): for _ in range(loops):
foo.__class__ = Bar foo.__class__ = Bar
type(foo) type(foo)
foo.__class__ = Foo foo.__class__ = Foo

View File

@ -4,7 +4,6 @@ import textwrap
import threading import threading
import unittest import unittest
from unittest.mock import patch from unittest.mock import patch
from test import support
from test.support import import_helper, threading_helper from test.support import import_helper, threading_helper
@ -515,10 +514,6 @@ class TestSuper(unittest.TestCase):
an audit hook. 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: class Foo:
pass pass
@ -528,7 +523,7 @@ class TestSuper(unittest.TestCase):
thing = Foo() thing = Foo()
def work(): def work():
foo = thing foo = thing
for _ in range(5000): for _ in range(200):
foo.__class__ = Bar foo.__class__ = Bar
type(foo) type(foo)
foo.__class__ = Foo foo.__class__ = Foo