summaryrefslogtreecommitdiffstats
path: root/Python/optimizer.c
diff options
context:
space:
mode:
authorSavannah Ostrowski <savannahostrowski@gmail.com>2024-09-27 00:35:42 (GMT)
committerGitHub <noreply@github.com>2024-09-27 00:35:42 (GMT)
commit65f12370982b9982b204d07f9f26ca8740f21845 (patch)
tree4ae4d96bd67052e4c801a805292fb081adf792b4 /Python/optimizer.c
parent23e812b84ae688a56a1011ed69a0d178c70e35ea (diff)
downloadcpython-65f12370982b9982b204d07f9f26ca8740f21845.zip
cpython-65f12370982b9982b204d07f9f26ca8740f21845.tar.gz
cpython-65f12370982b9982b204d07f9f26ca8740f21845.tar.bz2
GH-123516: Improve JIT memory consumption by invalidating cold executors (GH-124443)
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Diffstat (limited to 'Python/optimizer.c')
-rw-r--r--Python/optimizer.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/Python/optimizer.c b/Python/optimizer.c
index bb7a90b..978649f 100644
--- a/Python/optimizer.c
+++ b/Python/optimizer.c
@@ -565,6 +565,7 @@ translate_bytecode_to_trace(
code->co_firstlineno,
2 * INSTR_IP(initial_instr, code));
ADD_TO_TRACE(_START_EXECUTOR, 0, (uintptr_t)instr, INSTR_IP(instr, code));
+ ADD_TO_TRACE(_MAKE_WARM, 0, 0, 0);
uint32_t target = 0;
for (;;) {
@@ -1194,6 +1195,9 @@ make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFil
executor->jit_code = NULL;
executor->jit_side_entry = NULL;
executor->jit_size = 0;
+ // This is initialized to true so we can prevent the executor
+ // from being immediately detected as cold and invalidated.
+ executor->vm_data.warm = true;
if (_PyJIT_Compile(executor, executor->trace, length)) {
Py_DECREF(executor);
return NULL;
@@ -1659,4 +1663,42 @@ _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation)
}
}
+void
+_Py_Executors_InvalidateCold(PyInterpreterState *interp)
+{
+ /* Walk the list of executors */
+ /* TO DO -- Use a tree to avoid traversing as many objects */
+ PyObject *invalidate = PyList_New(0);
+ if (invalidate == NULL) {
+ goto error;
+ }
+
+ /* Clearing an executor can deallocate others, so we need to make a list of
+ * executors to invalidate first */
+ for (_PyExecutorObject *exec = interp->executor_list_head; exec != NULL;) {
+ assert(exec->vm_data.valid);
+ _PyExecutorObject *next = exec->vm_data.links.next;
+
+ if (!exec->vm_data.warm && PyList_Append(invalidate, (PyObject *)exec) < 0) {
+ goto error;
+ }
+ else {
+ exec->vm_data.warm = false;
+ }
+
+ exec = next;
+ }
+ for (Py_ssize_t i = 0; i < PyList_GET_SIZE(invalidate); i++) {
+ _PyExecutorObject *exec = (_PyExecutorObject *)PyList_GET_ITEM(invalidate, i);
+ executor_clear(exec);
+ }
+ Py_DECREF(invalidate);
+ return;
+error:
+ PyErr_Clear();
+ Py_XDECREF(invalidate);
+ // If we're truly out of memory, wiping out everything is a fine fallback
+ _Py_Executors_InvalidateAll(interp, 0);
+}
+
#endif /* _Py_TIER2 */