@@ -55,6 +55,80 @@ def get_opnames(ex):
5555 return list (iter_opnames (ex ))
5656
5757
58+ @requires_specialization
59+ @unittest .skipIf (Py_GIL_DISABLED , "optimizer not yet supported in free-threaded builds" )
60+ class TestExecutorInvalidation (unittest .TestCase ):
61+
62+ def test_invalidate_object (self ):
63+ # Generate a new set of functions at each call
64+ ns = {}
65+ func_src = "\n " .join (
66+ f"""
67+ def f{ n } ():
68+ for _ in range(1000):
69+ pass
70+ """ for n in range (5 )
71+ )
72+ exec (textwrap .dedent (func_src ), ns , ns )
73+ funcs = [ ns [f'f{ n } ' ] for n in range (5 )]
74+ objects = [object () for _ in range (5 )]
75+
76+ opt = _testinternalcapi .new_uop_optimizer ()
77+ with temporary_optimizer (opt ):
78+ for f in funcs :
79+ f ()
80+ executors = [get_first_executor (f ) for f in funcs ]
81+ # Set things up so each executor depends on the objects
82+ # with an equal or lower index.
83+ for i , exe in enumerate (executors ):
84+ self .assertTrue (exe .is_valid ())
85+ for obj in objects [:i + 1 ]:
86+ _testinternalcapi .add_executor_dependency (exe , obj )
87+ self .assertTrue (exe .is_valid ())
88+ # Assert that the correct executors are invalidated
89+ # and check that nothing crashes when we invalidate
90+ # an executor multiple times.
91+ for i in (4 ,3 ,2 ,1 ,0 ):
92+ _testinternalcapi .invalidate_executors (objects [i ])
93+ for exe in executors [i :]:
94+ self .assertFalse (exe .is_valid ())
95+ for exe in executors [:i ]:
96+ self .assertTrue (exe .is_valid ())
97+
98+ def test_uop_optimizer_invalidation (self ):
99+ # Generate a new function at each call
100+ ns = {}
101+ exec (textwrap .dedent ("""
102+ def f():
103+ for i in range(1000):
104+ pass
105+ """ ), ns , ns )
106+ f = ns ['f' ]
107+ opt = _testinternalcapi .new_uop_optimizer ()
108+ with temporary_optimizer (opt ):
109+ f ()
110+ exe = get_first_executor (f )
111+ self .assertIsNotNone (exe )
112+ self .assertTrue (exe .is_valid ())
113+ _testinternalcapi .invalidate_executors (f .__code__ )
114+ self .assertFalse (exe .is_valid ())
115+
116+ def test_sys__clear_internal_caches (self ):
117+ def f ():
118+ for _ in range (1000 ):
119+ pass
120+ opt = _testinternalcapi .new_uop_optimizer ()
121+ with temporary_optimizer (opt ):
122+ f ()
123+ exe = get_first_executor (f )
124+ self .assertIsNotNone (exe )
125+ self .assertTrue (exe .is_valid ())
126+ sys ._clear_internal_caches ()
127+ self .assertFalse (exe .is_valid ())
128+ exe = get_first_executor (f )
129+ self .assertIsNone (exe )
130+
131+
58132@requires_specialization
59133@unittest .skipIf (Py_GIL_DISABLED , "optimizer not yet supported in free-threaded builds" )
60134@unittest .skipUnless (hasattr (_testinternalcapi , "get_optimizer" ),
0 commit comments