Skip to content

Commit 0c72490

Browse files
committed
revert commits
1 parent 2972b06 commit 0c72490

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
@@ -119,7 +119,8 @@ PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj);
119119
// Export for '_testinternalcapi' shared extension.
120120
PyAPI_FUNC(_PyOptimizerObject *) _Py_GetOptimizer(void);
121121
PyAPI_FUNC(int) _Py_SetTier2Optimizer(_PyOptimizerObject* optimizer);
122-
PyAPI_FUNC(void) _Py_SetUOpOptimize(_PyOptimizerObject* opt);
122+
PyAPI_FUNC(PyObject *) _PyOptimizer_NewCounter(void);
123+
PyAPI_FUNC(PyObject *) _PyOptimizer_NewUOpOptimizer(void);
123124

124125
#define _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS 3
125126
#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
@@ -2003,6 +2003,35 @@ def callback(code, instruction_offset):
20032003
sys.monitoring.set_events(0, 0)
20042004

20052005

2006+
class TestOptimizer(MonitoringTestBase, unittest.TestCase):
2007+
2008+
def setUp(self):
2009+
_testinternalcapi = import_module("_testinternalcapi")
2010+
if hasattr(_testinternalcapi, "get_optimizer"):
2011+
self.old_opt = _testinternalcapi.get_optimizer()
2012+
opt = _testinternalcapi.new_counter_optimizer()
2013+
_testinternalcapi.set_optimizer(opt)
2014+
super(TestOptimizer, self).setUp()
2015+
2016+
def tearDown(self):
2017+
super(TestOptimizer, self).tearDown()
2018+
import _testinternalcapi
2019+
if hasattr(_testinternalcapi, "get_optimizer"):
2020+
_testinternalcapi.set_optimizer(self.old_opt)
2021+
2022+
def test_for_loop(self):
2023+
def test_func(x):
2024+
i = 0
2025+
while i < x:
2026+
i += 1
2027+
2028+
code = test_func.__code__
2029+
sys.monitoring.set_local_events(TEST_TOOL, code, E.PY_START)
2030+
self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), E.PY_START)
2031+
test_func(1000)
2032+
sys.monitoring.set_local_events(TEST_TOOL, code, 0)
2033+
self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), 0)
2034+
20062035
class TestTier2Optimizer(CheckEvents):
20072036

20082037
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
{
@@ -2089,6 +2101,8 @@ static PyMethodDef module_functions[] = {
20892101
#ifdef _Py_TIER2
20902102
{"get_optimizer", get_optimizer, METH_NOARGS, NULL},
20912103
{"set_optimizer", set_optimizer, METH_O, NULL},
2104+
{"new_counter_optimizer", new_counter_optimizer, METH_NOARGS, NULL},
2105+
{"new_uop_optimizer", new_uop_optimizer, METH_NOARGS, NULL},
20922106
{"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL},
20932107
{"invalidate_executors", invalidate_executors, METH_O, NULL},
20942108
#endif

Python/optimizer.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,10 +1315,15 @@ PyTypeObject _PyUOpOptimizer_Type = {
13151315
.tp_dealloc = uop_opt_dealloc,
13161316
};
13171317

1318-
void
1319-
_Py_SetUOpOptimize(_PyOptimizerObject *opt)
1318+
PyObject *
1319+
_PyOptimizer_NewUOpOptimizer(void)
13201320
{
1321+
_PyOptimizerObject *opt = PyObject_New(_PyOptimizerObject, &_PyUOpOptimizer_Type);
1322+
if (opt == NULL) {
1323+
return NULL;
1324+
}
13211325
opt->optimize = uop_optimize;
1326+
return (PyObject *)opt;
13221327
}
13231328

13241329
static void
@@ -1399,6 +1404,18 @@ PyTypeObject _PyCounterOptimizer_Type = {
13991404
.tp_dealloc = (destructor)PyObject_Free,
14001405
};
14011406

1407+
PyObject *
1408+
_PyOptimizer_NewCounter(void)
1409+
{
1410+
_PyCounterOptimizerObject *opt = (_PyCounterOptimizerObject *)_PyObject_New(&_PyCounterOptimizer_Type);
1411+
if (opt == NULL) {
1412+
return NULL;
1413+
}
1414+
opt->base.optimize = counter_optimize;
1415+
opt->count = 0;
1416+
return (PyObject *)opt;
1417+
}
1418+
14021419

14031420
/*****************************************
14041421
* Executor management

Python/pylifecycle.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,11 +1334,10 @@ init_interp_main(PyThreadState *tstate)
13341334
} else
13351335
#endif
13361336
{
1337-
PyObject *opt = PyObject_New(_PyOptimizerObject, &_PyUOpOptimizer_Type);
1337+
PyObject *opt = _PyOptimizer_NewUOpOptimizer();
13381338
if (opt == NULL) {
13391339
return _PyStatus_ERR("can't initialize optimizer");
13401340
}
1341-
_Py_SetUOpOptimize((_PyOptimizerObject *)opt);
13421341
if (_Py_SetTier2Optimizer((_PyOptimizerObject *)opt)) {
13431342
return _PyStatus_ERR("can't install optimizer");
13441343
}

0 commit comments

Comments
 (0)