Skip to content

Commit 16681b0

Browse files
committed
revert commits
1 parent 089f2b9 commit 16681b0

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
@@ -141,8 +141,89 @@ def get_opnames(ex):
141141

142142
@requires_specialization
143143
@unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds")
144-
@unittest.skipUnless(hasattr(_testinternalcapi, "get_optimizer") and
145-
hasattr(_testinternalcapi, "new_uop_optimizer"),
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"),
146227
"Requires optimizer infrastructure")
147228
class TestExecutorInvalidation(unittest.TestCase):
148229

@@ -590,8 +671,7 @@ def testfunc(n):
590671

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

Lib/test/test_monitoring.py

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

20872087

2088+
class TestOptimizer(MonitoringTestBase, unittest.TestCase):
2089+
2090+
def setUp(self):
2091+
_testinternalcapi = import_module("_testinternalcapi")
2092+
if hasattr(_testinternalcapi, "get_optimizer"):
2093+
self.old_opt = _testinternalcapi.get_optimizer()
2094+
opt = _testinternalcapi.new_counter_optimizer()
2095+
_testinternalcapi.set_optimizer(opt)
2096+
super(TestOptimizer, self).setUp()
2097+
2098+
def tearDown(self):
2099+
super(TestOptimizer, self).tearDown()
2100+
import _testinternalcapi
2101+
if hasattr(_testinternalcapi, "get_optimizer"):
2102+
_testinternalcapi.set_optimizer(self.old_opt)
2103+
2104+
def test_for_loop(self):
2105+
def test_func(x):
2106+
i = 0
2107+
while i < x:
2108+
i += 1
2109+
2110+
code = test_func.__code__
2111+
sys.monitoring.set_local_events(TEST_TOOL, code, E.PY_START)
2112+
self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), E.PY_START)
2113+
test_func(1000)
2114+
sys.monitoring.set_local_events(TEST_TOOL, code, 0)
2115+
self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), 0)
2116+
20882117
class TestTier2Optimizer(CheckEvents):
20892118

20902119
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
@@ -1321,10 +1321,15 @@ PyTypeObject _PyUOpOptimizer_Type = {
13211321
.tp_dealloc = uop_opt_dealloc,
13221322
};
13231323

1324-
void
1325-
_Py_SetUOpOptimize(_PyOptimizerObject *opt)
1324+
PyObject *
1325+
_PyOptimizer_NewUOpOptimizer(void)
13261326
{
1327+
_PyOptimizerObject *opt = PyObject_New(_PyOptimizerObject, &_PyUOpOptimizer_Type);
1328+
if (opt == NULL) {
1329+
return NULL;
1330+
}
13271331
opt->optimize = uop_optimize;
1332+
return (PyObject *)opt;
13281333
}
13291334

13301335
static void
@@ -1405,6 +1410,18 @@ PyTypeObject _PyCounterOptimizer_Type = {
14051410
.tp_dealloc = (destructor)PyObject_Free,
14061411
};
14071412

1413+
PyObject *
1414+
_PyOptimizer_NewCounter(void)
1415+
{
1416+
_PyCounterOptimizerObject *opt = (_PyCounterOptimizerObject *)_PyObject_New(&_PyCounterOptimizer_Type);
1417+
if (opt == NULL) {
1418+
return NULL;
1419+
}
1420+
opt->base.optimize = counter_optimize;
1421+
opt->count = 0;
1422+
return (PyObject *)opt;
1423+
}
1424+
14081425

14091426
/*****************************************
14101427
* Executor management

Python/pylifecycle.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,11 +1351,10 @@ init_interp_main(PyThreadState *tstate)
13511351
} else
13521352
#endif
13531353
{
1354-
PyObject *opt = PyObject_New(_PyOptimizerObject, &_PyUOpOptimizer_Type);
1354+
PyObject *opt = _PyOptimizer_NewUOpOptimizer();
13551355
if (opt == NULL) {
13561356
return _PyStatus_ERR("can't initialize optimizer");
13571357
}
1358-
_Py_SetUOpOptimize((_PyOptimizerObject *)opt);
13591358
if (_Py_SetTier2Optimizer((_PyOptimizerObject *)opt)) {
13601359
return _PyStatus_ERR("can't install optimizer");
13611360
}

0 commit comments

Comments
 (0)