@@ -37,7 +37,8 @@ def clear_executors(func):
3737
3838@requires_specialization
3939@unittest .skipIf (Py_GIL_DISABLED , "optimizer not yet supported in free-threaded builds" )
40- @unittest .skipUnless (hasattr (_testinternalcapi , "get_optimizer" ),
40+ @unittest .skipUnless (hasattr (_testinternalcapi , "get_optimizer" ) and
41+ hasattr (_testinternalcapi , "new_counter_optimizer" ),
4142 "Requires optimizer infrastructure" )
4243class TestOptimizerAPI (unittest .TestCase ):
4344
@@ -141,89 +142,8 @@ def get_opnames(ex):
141142
142143@requires_specialization
143144@unittest .skipIf (Py_GIL_DISABLED , "optimizer not yet supported in free-threaded builds" )
144- @unittest .skipUnless (hasattr (_testinternalcapi , "get_optimizer" ),
145- "Requires optimizer infrastructure" )
146- class TestExecutorInvalidation (unittest .TestCase ):
147-
148- def setUp (self ):
149- self .old = _testinternalcapi .get_optimizer ()
150- self .opt = _testinternalcapi .new_counter_optimizer ()
151- _testinternalcapi .set_optimizer (self .opt )
152-
153- def tearDown (self ):
154- _testinternalcapi .set_optimizer (self .old )
155-
156- def test_invalidate_object (self ):
157- # Generate a new set of functions at each call
158- ns = {}
159- func_src = "\n " .join (
160- f"""
161- def f{ n } ():
162- for _ in range(1000):
163- pass
164- """ for n in range (5 )
165- )
166- exec (textwrap .dedent (func_src ), ns , ns )
167- funcs = [ ns [f'f{ n } ' ] for n in range (5 )]
168- objects = [object () for _ in range (5 )]
169-
170- for f in funcs :
171- f ()
172- executors = [get_first_executor (f ) for f in funcs ]
173- # Set things up so each executor depends on the objects
174- # with an equal or lower index.
175- for i , exe in enumerate (executors ):
176- self .assertTrue (exe .is_valid ())
177- for obj in objects [:i + 1 ]:
178- _testinternalcapi .add_executor_dependency (exe , obj )
179- self .assertTrue (exe .is_valid ())
180- # Assert that the correct executors are invalidated
181- # and check that nothing crashes when we invalidate
182- # an executor multiple times.
183- for i in (4 ,3 ,2 ,1 ,0 ):
184- _testinternalcapi .invalidate_executors (objects [i ])
185- for exe in executors [i :]:
186- self .assertFalse (exe .is_valid ())
187- for exe in executors [:i ]:
188- self .assertTrue (exe .is_valid ())
189-
190- def test_uop_optimizer_invalidation (self ):
191- # Generate a new function at each call
192- ns = {}
193- exec (textwrap .dedent ("""
194- def f():
195- for i in range(1000):
196- pass
197- """ ), ns , ns )
198- f = ns ['f' ]
199- opt = _testinternalcapi .new_uop_optimizer ()
200- with temporary_optimizer (opt ):
201- f ()
202- exe = get_first_executor (f )
203- self .assertIsNotNone (exe )
204- self .assertTrue (exe .is_valid ())
205- _testinternalcapi .invalidate_executors (f .__code__ )
206- self .assertFalse (exe .is_valid ())
207-
208- def test_sys__clear_internal_caches (self ):
209- def f ():
210- for _ in range (1000 ):
211- pass
212- opt = _testinternalcapi .new_uop_optimizer ()
213- with temporary_optimizer (opt ):
214- f ()
215- exe = get_first_executor (f )
216- self .assertIsNotNone (exe )
217- self .assertTrue (exe .is_valid ())
218- sys ._clear_internal_caches ()
219- self .assertFalse (exe .is_valid ())
220- exe = get_first_executor (f )
221- self .assertIsNone (exe )
222-
223-
224- @requires_specialization
225- @unittest .skipIf (Py_GIL_DISABLED , "optimizer not yet supported in free-threaded builds" )
226- @unittest .skipUnless (hasattr (_testinternalcapi , "get_optimizer" ),
145+ @unittest .skipUnless (hasattr (_testinternalcapi , "get_optimizer" ) and
146+ hasattr (_testinternalcapi , "new_counter_optimizer" ),
227147 "Requires optimizer infrastructure" )
228148class TestExecutorInvalidation (unittest .TestCase ):
229149
0 commit comments