From ed061f604c30e7432862095617381be966c44869 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Wed, 1 Jun 2022 00:33:49 +0800 Subject: [PATCH 1/6] Cache result of PyCode_GetCode in codeobject --- Include/cpython/code.h | 1 + Objects/codeobject.c | 7 +++++++ Programs/test_frozenmain.h | 8 ++++---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index ba7324b48d8675..f544ea87406e25 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -88,6 +88,7 @@ typedef uint16_t _Py_CODEUNIT; PyObject *co_qualname; /* unicode (qualname, for reference) */ \ PyObject *co_linetable; /* bytes object that holds location info */ \ PyObject *co_weakreflist; /* to support weakrefs to code objects */ \ + void *_co_code; /* cached co_code object/attribute */ \ /* Scratch space for extra data relating to the code object. \ Type is a void* to keep the format private in codeobject.c to force \ people to go through the proper APIs. */ \ diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 68b0b1efb2e14c..dc6dec1b2a549b 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -334,6 +334,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) /* not set */ co->co_weakreflist = NULL; co->co_extra = NULL; + co->_co_code = NULL; co->co_warmup = QUICKENING_INITIAL_WARMUP_VALUE; memcpy(_PyCode_CODE(co), PyBytes_AS_STRING(con->code), @@ -1367,12 +1368,17 @@ deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len) PyObject * _PyCode_GetCode(PyCodeObject *co) { + if (co->_co_code != NULL) { + return Py_NewRef(co->_co_code); + } PyObject *code = PyBytes_FromStringAndSize((const char *)_PyCode_CODE(co), _PyCode_NBYTES(co)); if (code == NULL) { return NULL; } deopt_code((_Py_CODEUNIT *)PyBytes_AS_STRING(code), Py_SIZE(co)); + assert(co->_co_code == NULL); + co->_co_code = (void *)Py_NewRef(code); return code; } @@ -1531,6 +1537,7 @@ code_dealloc(PyCodeObject *co) Py_XDECREF(co->co_qualname); Py_XDECREF(co->co_linetable); Py_XDECREF(co->co_exceptiontable); + Py_XDECREF(co->_co_code); if (co->co_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject*)co); } diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index e6e2ef26b1c373..8d4ba94bd76ee0 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,7 +1,7 @@ // Auto-generated by Programs/freeze_test_frozenmain.py unsigned char M_test_frozenmain[] = { 227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, - 0,0,0,0,0,115,160,0,0,0,151,0,100,0,100,1, + 0,0,0,0,0,243,160,0,0,0,151,0,100,0,100,1, 108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2, 100,2,171,1,0,0,0,0,0,0,0,0,1,0,2,0, 101,2,100,3,101,0,106,3,0,0,0,0,0,0,0,0, @@ -23,10 +23,10 @@ unsigned char M_test_frozenmain[] = { 32,122,2,58,32,41,7,218,3,115,121,115,218,17,95,116, 101,115,116,105,110,116,101,114,110,97,108,99,97,112,105,218, 5,112,114,105,110,116,218,4,97,114,103,118,218,11,103,101, - 116,95,99,111,110,102,105,103,115,114,2,0,0,0,218,3, + 116,95,99,111,110,102,105,103,115,114,3,0,0,0,218,3, 107,101,121,169,0,243,0,0,0,0,250,18,116,101,115,116, 95,102,114,111,122,101,110,109,97,105,110,46,112,121,250,8, - 60,109,111,100,117,108,101,62,114,17,0,0,0,1,0,0, + 60,109,111,100,117,108,101,62,114,18,0,0,0,1,0,0, 0,115,140,0,0,0,248,240,6,0,1,11,128,10,128,10, 128,10,216,0,24,208,0,24,208,0,24,208,0,24,224,0, 5,128,5,208,6,26,212,0,27,208,0,27,216,0,5,128, @@ -36,5 +36,5 @@ unsigned char M_test_frozenmain[] = { 67,240,14,0,5,10,128,69,208,10,40,144,67,208,10,40, 208,10,40,152,54,160,35,156,59,208,10,40,208,10,40,212, 4,41,208,4,41,208,4,41,240,15,7,1,42,240,0,7, - 1,42,114,15,0,0,0, + 1,42,114,16,0,0,0, }; From 1077bd3427f04d71316c60eb0f3a4f4e7b4498ef Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 31 May 2022 16:36:31 +0000 Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst new file mode 100644 index 00000000000000..717d87d7b98a62 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst @@ -0,0 +1 @@ +Speed up the ``PyCode_GetCode`` function which also improves accessing the ``co_code`` attribute in Python. From 76ada157daf64390c9dbe3d3fe08cd8bcf773f62 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Fri, 3 Jun 2022 17:56:35 +0800 Subject: [PATCH 3/6] Update Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> --- .../2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst index 717d87d7b98a62..04b9e8ba481874 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2022-05-31-16-36-30.gh-issue-93382.Jf6gAj.rst @@ -1 +1 @@ -Speed up the ``PyCode_GetCode`` function which also improves accessing the ``co_code`` attribute in Python. +Speed up the :c:func:`PyCode_GetCode` function which also improves accessing the :attr:`~types.CodeType.co_code` attribute in Python. From fde8a30c5594cdcf85b96a56f48e8a99e5ae4387 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Fri, 3 Jun 2022 23:07:27 +0800 Subject: [PATCH 4/6] invalidate cached code object when frame adds LOAD_FAST_CHECK Co-Authored-By: Dennis Sweeney <36520290+sweeneyde@users.noreply.github.com> --- Objects/frameobject.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index a448ba3a6c6f90..59c453c1dfd5fd 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -474,6 +474,10 @@ add_load_fast_null_checks(PyCodeObject *co) break; } } + // invalidate cached co_code object + if (co->_co_code != NULL) { + Py_CLEAR(co->_co_code); + } } /* Setter for f_lineno - you can set f_lineno from within a trace function in From 0c7226c10fb037b8aa74629e06662b5a1e7bf3db Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Fri, 3 Jun 2022 23:08:32 +0800 Subject: [PATCH 5/6] Py_CLEAR already checks for NULL --- Objects/frameobject.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 59c453c1dfd5fd..87d8b0c63d2558 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -475,9 +475,7 @@ add_load_fast_null_checks(PyCodeObject *co) } } // invalidate cached co_code object - if (co->_co_code != NULL) { - Py_CLEAR(co->_co_code); - } + Py_CLEAR(co->_co_code); } /* Setter for f_lineno - you can set f_lineno from within a trace function in From 0b11670788ae7e0b5bc53ece22faa9f42f47ba61 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sat, 4 Jun 2022 00:10:49 +0800 Subject: [PATCH 6/6] only invalidate cache if opcode changed --- Objects/frameobject.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 87d8b0c63d2558..545c1b6b90f1a8 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -458,24 +458,30 @@ _PyFrame_GetState(PyFrameObject *frame) static void add_load_fast_null_checks(PyCodeObject *co) { + int changed = 0; _Py_CODEUNIT *instructions = _PyCode_CODE(co); for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { switch (_Py_OPCODE(instructions[i])) { case LOAD_FAST: case LOAD_FAST__LOAD_FAST: case LOAD_FAST__LOAD_CONST: + changed = 1; _Py_SET_OPCODE(instructions[i], LOAD_FAST_CHECK); break; case LOAD_CONST__LOAD_FAST: + changed = 1; _Py_SET_OPCODE(instructions[i], LOAD_CONST); break; case STORE_FAST__LOAD_FAST: + changed = 1; _Py_SET_OPCODE(instructions[i], STORE_FAST); break; } } - // invalidate cached co_code object - Py_CLEAR(co->_co_code); + if (changed) { + // invalidate cached co_code object + Py_CLEAR(co->_co_code); + } } /* Setter for f_lineno - you can set f_lineno from within a trace function in