Skip to content

Commit

Permalink
gh-124402: Speed up test_free_threading and test_super (#124491)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
vstinner authored Sep 26, 2024
1 parent 08a467b commit 0387c34
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 53 deletions.
67 changes: 30 additions & 37 deletions Lib/test/test_free_threading/test_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@
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


@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):
Expand All @@ -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()
Expand All @@ -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__":
Expand Down
14 changes: 7 additions & 7 deletions Lib/test/test_free_threading/test_monitoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@
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


class InstrumentationMultiThreadedMixin:
thread_count = 10
func_count = 200
func_count = 50
fib = 12

def after_threads(self):
Expand All @@ -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 = []
Expand Down Expand Up @@ -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()
6 changes: 3 additions & 3 deletions Lib/test/test_free_threading/test_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from threading import Thread
from unittest import TestCase

from test import support
from test.support import threading_helper


Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down
7 changes: 1 addition & 6 deletions Lib/test/test_super.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down

0 comments on commit 0387c34

Please sign in to comment.