Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Fix optimizer API.
  • Loading branch information
markshannon committed Jun 7, 2023
commit 2335db629b3172c44e913c0e81e0c53729739e8b
31 changes: 23 additions & 8 deletions Lib/test/test_capi/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1917,17 +1917,32 @@ def func():

class TestOptimizerAPI(unittest.TestCase):

def test_counter_optimizer(self):
def test_get_set_optimizer(self):
self.assertEqual(_testinternalcapi.get_optimizer(), None)
opt = _testinternalcapi.get_counter_optimizer()
self.assertEqual(opt.get_count(), 0)
try:
_testinternalcapi.set_optimizer(opt)
self.assertEqual(opt.get_count(), 0)
_testinternalcapi.set_optimizer(opt)
self.assertEqual(_testinternalcapi.get_optimizer(), opt)
_testinternalcapi.set_optimizer(None)
self.assertEqual(_testinternalcapi.get_optimizer(), None)

def test_counter_optimizer(self):

def loop():
for _ in range(1000):
pass
self.assertEqual(opt.get_count(), 1000)
finally:
_testinternalcapi.set_optimizer(None)

for repeat in range(5):
opt = _testinternalcapi.get_counter_optimizer()
self.assertEqual(opt.get_count(), 0)
try:
_testinternalcapi.set_optimizer(opt)
self.assertEqual(opt.get_count(), 0)
loop()
self.assertEqual(opt.get_count(), 1000)
finally:
_testinternalcapi.set_optimizer(None)
Comment thread
markshannon marked this conversation as resolved.
Outdated
#Clear executors
loop.__code__ = loop.__code__.replace()
Comment thread
markshannon marked this conversation as resolved.
Outdated

if __name__ == "__main__":
unittest.main()
11 changes: 11 additions & 0 deletions Modules/_testinternalcapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,16 @@ set_optimizer(PyObject *self, PyObject *opt)
Py_RETURN_NONE;
}

static PyObject *
get_optimizer(PyObject *self, PyObject *Py_UNUSED(ignored))
{
PyObject *opt = (PyObject *)PyUnstable_GetOptimizer();
if (opt == NULL) {
Py_RETURN_NONE;
}
return opt;
}

static PyMethodDef module_functions[] = {
{"get_configs", get_configs, METH_NOARGS},
{"get_recursion_depth", get_recursion_depth, METH_NOARGS},
Expand Down Expand Up @@ -866,6 +876,7 @@ static PyMethodDef module_functions[] = {
{"iframe_getcode", iframe_getcode, METH_O, NULL},
{"iframe_getline", iframe_getline, METH_O, NULL},
{"iframe_getlasti", iframe_getlasti, METH_O, NULL},
{"get_optimizer", get_optimizer, METH_NOARGS, NULL},
{"set_optimizer", set_optimizer, METH_O, NULL},
{"get_counter_optimizer", get_counter_optimizer, METH_NOARGS, NULL},
{NULL, NULL} /* sentinel */
Expand Down
32 changes: 28 additions & 4 deletions Objects/codeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1465,6 +1465,16 @@ PyCode_GetFreevars(PyCodeObject *code)
return _PyCode_GetFreevars(code);
}

static void
clear_executors(PyCodeObject *co)
{
for (int i = 0; i < co->co_executors->size; i++) {
Py_CLEAR(co->co_executors->executors[i]);
}
PyMem_Free(co->co_executors);
co->co_executors = NULL;
}

static void
deopt_code(PyCodeObject *code, _Py_CODEUNIT *instructions)
{
Expand All @@ -1478,6 +1488,20 @@ deopt_code(PyCodeObject *code, _Py_CODEUNIT *instructions)
}
i += caches;
}
if (code->co_executors == NULL) {
return;
}
for (int i = 0; i < len; i++) {
int opcode = instructions[i].op.code;
if (opcode == ENTER_EXECUTOR) {
_PyExecutorObject *exec = code->co_executors->executors[instructions[i].op.arg];
opcode = instructions[i].op.code = exec->vm_data.opcode;
instructions[i].op.arg = exec->vm_data.oparg;
assert(instructions[i+1].cache < (1 << OPTIMIZER_BITS_IN_COUNTER));
Comment thread
markshannon marked this conversation as resolved.
Outdated
}
int caches = _PyOpcode_Caches[opcode];
i += caches;
}
}

PyObject *
Expand Down Expand Up @@ -1679,10 +1703,7 @@ code_dealloc(PyCodeObject *co)
PyMem_Free(co_extra);
}
if (co->co_executors != NULL) {
for (int i = 0; i < co->co_executors->size; i++) {
Py_CLEAR(co->co_executors->executors[i]);
}
PyMem_Free(co->co_executors);
clear_executors(co);
}

Py_XDECREF(co->co_consts);
Expand Down Expand Up @@ -2278,6 +2299,9 @@ void
_PyStaticCode_Fini(PyCodeObject *co)
{
deopt_code(co, _PyCode_CODE(co));
if (co->co_executors != NULL) {
clear_executors(co);
}
PyMem_Free(co->co_extra);
if (co->_co_cached != NULL) {
Py_CLEAR(co->_co_cached->_co_code);
Expand Down
3 changes: 2 additions & 1 deletion Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2135,6 +2135,7 @@ dummy_func(
frame = cframe.current_frame;
goto error;
}
assert(frame == cframe.current_frame);
Comment thread
markshannon marked this conversation as resolved.
here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1);
goto resume_frame;
}
Expand All @@ -2143,7 +2144,7 @@ dummy_func(
}

inst(ENTER_EXECUTOR, (--)) {
_PyExecutorObject *executor = (_PyExecutorObject *)frame->f_code->co_executors->executors[oparg];
_PyExecutorObject *executor = (_PyExecutorObject *)frame->f_code->co_executors->executors[oparg&255];
Comment thread
markshannon marked this conversation as resolved.
Outdated
Py_INCREF(executor);
frame = executor->execute(executor, frame, stack_pointer);
if (frame == NULL) {
Expand Down
Loading