Skip to content

Commit 6a8453d

Browse files
committed
revert commits
1 parent 9973709 commit 6a8453d

File tree

6 files changed

+149
-9
lines changed

6 files changed

+149
-9
lines changed

Include/internal/pycore_optimizer.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj);
116116
// Export for '_testinternalcapi' shared extension.
117117
PyAPI_FUNC(_PyOptimizerObject *) _Py_GetOptimizer(void);
118118
PyAPI_FUNC(int) _Py_SetTier2Optimizer(_PyOptimizerObject* optimizer);
119-
PyAPI_FUNC(void) _Py_SetUOpOptimize(_PyOptimizerObject* opt);
119+
PyAPI_FUNC(PyObject *) _PyOptimizer_NewCounter(void);
120+
PyAPI_FUNC(PyObject *) _PyOptimizer_NewUOpOptimizer(void);
120121

121122
#define _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS 3
122123
#define _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS 6

Lib/test/test_capi/test_opt.py

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,89 @@ def get_opnames(ex):
140140

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

@@ -589,8 +670,7 @@ def testfunc(n):
589670

590671
@requires_specialization
591672
@unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds")
592-
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer") and
593-
hasattr(_testinternalcapi, "new_uop_optimizer"),
673+
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer"),
594674
"Requires optimizer infrastructure")
595675
@unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.")
596676
class TestUopsOptimization(unittest.TestCase):

Lib/test/test_monitoring.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,35 @@ def callback(code, instruction_offset):
19591959
sys.monitoring.set_events(0, 0)
19601960

19611961

1962+
class TestOptimizer(MonitoringTestBase, unittest.TestCase):
1963+
1964+
def setUp(self):
1965+
_testinternalcapi = import_module("_testinternalcapi")
1966+
if hasattr(_testinternalcapi, "get_optimizer"):
1967+
self.old_opt = _testinternalcapi.get_optimizer()
1968+
opt = _testinternalcapi.new_counter_optimizer()
1969+
_testinternalcapi.set_optimizer(opt)
1970+
super(TestOptimizer, self).setUp()
1971+
1972+
def tearDown(self):
1973+
super(TestOptimizer, self).tearDown()
1974+
import _testinternalcapi
1975+
if hasattr(_testinternalcapi, "get_optimizer"):
1976+
_testinternalcapi.set_optimizer(self.old_opt)
1977+
1978+
def test_for_loop(self):
1979+
def test_func(x):
1980+
i = 0
1981+
while i < x:
1982+
i += 1
1983+
1984+
code = test_func.__code__
1985+
sys.monitoring.set_local_events(TEST_TOOL, code, E.PY_START)
1986+
self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), E.PY_START)
1987+
test_func(1000)
1988+
sys.monitoring.set_local_events(TEST_TOOL, code, 0)
1989+
self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), 0)
1990+
19621991
class TestTier2Optimizer(CheckEvents):
19631992

19641993
def test_monitoring_already_opimized_loop(self):

Modules/_testinternalcapi.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,18 @@ get_co_framesize(PyObject *self, PyObject *arg)
989989

990990
#ifdef _Py_TIER2
991991

992+
static PyObject *
993+
new_counter_optimizer(PyObject *self, PyObject *arg)
994+
{
995+
return _PyOptimizer_NewCounter();
996+
}
997+
998+
static PyObject *
999+
new_uop_optimizer(PyObject *self, PyObject *arg)
1000+
{
1001+
return _PyOptimizer_NewUOpOptimizer();
1002+
}
1003+
9921004
static PyObject *
9931005
set_optimizer(PyObject *self, PyObject *opt)
9941006
{
@@ -2100,6 +2112,8 @@ static PyMethodDef module_functions[] = {
21002112
#ifdef _Py_TIER2
21012113
{"get_optimizer", get_optimizer, METH_NOARGS, NULL},
21022114
{"set_optimizer", set_optimizer, METH_O, NULL},
2115+
{"new_counter_optimizer", new_counter_optimizer, METH_NOARGS, NULL},
2116+
{"new_uop_optimizer", new_uop_optimizer, METH_NOARGS, NULL},
21032117
{"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL},
21042118
{"invalidate_executors", invalidate_executors, METH_O, NULL},
21052119
#endif

Python/optimizer.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,10 +1308,15 @@ PyTypeObject _PyUOpOptimizer_Type = {
13081308
.tp_dealloc = uop_opt_dealloc,
13091309
};
13101310

1311-
void
1312-
_Py_SetUOpOptimize(_PyOptimizerObject *opt)
1311+
PyObject *
1312+
_PyOptimizer_NewUOpOptimizer(void)
13131313
{
1314+
_PyOptimizerObject *opt = PyObject_New(_PyOptimizerObject, &_PyUOpOptimizer_Type);
1315+
if (opt == NULL) {
1316+
return NULL;
1317+
}
13141318
opt->optimize = uop_optimize;
1319+
return (PyObject *)opt;
13151320
}
13161321

13171322
static void
@@ -1392,6 +1397,18 @@ PyTypeObject _PyCounterOptimizer_Type = {
13921397
.tp_dealloc = (destructor)PyObject_Free,
13931398
};
13941399

1400+
PyObject *
1401+
_PyOptimizer_NewCounter(void)
1402+
{
1403+
_PyCounterOptimizerObject *opt = (_PyCounterOptimizerObject *)_PyObject_New(&_PyCounterOptimizer_Type);
1404+
if (opt == NULL) {
1405+
return NULL;
1406+
}
1407+
opt->base.optimize = counter_optimize;
1408+
opt->count = 0;
1409+
return (PyObject *)opt;
1410+
}
1411+
13951412

13961413
/*****************************************
13971414
* Executor management

Python/pylifecycle.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,11 +1321,10 @@ init_interp_main(PyThreadState *tstate)
13211321
} else
13221322
#endif
13231323
{
1324-
PyObject *opt = PyObject_New(_PyOptimizerObject, &_PyUOpOptimizer_Type);
1324+
PyObject *opt = _PyOptimizer_NewUOpOptimizer();
13251325
if (opt == NULL) {
13261326
return _PyStatus_ERR("can't initialize optimizer");
13271327
}
1328-
_Py_SetUOpOptimize((_PyOptimizerObject *)opt);
13291328
if (_Py_SetTier2Optimizer((_PyOptimizerObject *)opt)) {
13301329
return _PyStatus_ERR("can't install optimizer");
13311330
}

0 commit comments

Comments
 (0)