From b8567326e628fe8c280ea721fcadc7a84cb4621e Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Tue, 28 Jan 2025 22:03:28 -0800 Subject: [PATCH 1/3] Optimize ``_PyFloat_FromDouble_ConsumeInputs()`` Add optimization for ``_PyFloat_FromDouble_ConsumeInputs()`` for the free-threaded build. Implement free-threaded versions of ``_Py_DECREF_SPECIALIZED`` and ``_Py_DECREF_NO_DEALLOC`` as well. --- Include/internal/pycore_object.h | 38 +++++++++++++++++++++++++++++--- Objects/floatobject.c | 17 ++------------ 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 0b1df7e68b8dfa..509d7e6b23e1f2 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -261,17 +261,49 @@ _Py_DECREF_NO_DEALLOC(PyObject *op) } #else -// TODO: implement Py_DECREF specializations for Py_GIL_DISABLED build + static inline void _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct) { - Py_DECREF(op); + if (_Py_IsOwnedByCurrentThread(op) && + _Py_atomic_load_ssize_relaxed(&op->ob_ref_shared) == 0) { + uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local); + if (local == _Py_IMMORTAL_REFCNT_LOCAL) { + _Py_DECREF_IMMORTAL_STAT_INC(); + return; + } + _Py_DECREF_STAT_INC(); + _Py_DECREF_DecRefTotal(); + local--; + _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local); + if (local == 0) { + destruct(op); + } + } + else { + Py_DECREF(op); + } } static inline void _Py_DECREF_NO_DEALLOC(PyObject *op) { - Py_DECREF(op); + if (_Py_IsOwnedByCurrentThread(op) && + _Py_atomic_load_ssize_relaxed(&op->ob_ref_shared) == 0) { + uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local); + if (local == _Py_IMMORTAL_REFCNT_LOCAL) { + _Py_DECREF_IMMORTAL_STAT_INC(); + return; + } + _Py_DECREF_STAT_INC(); + _Py_DECREF_DecRefTotal(); + local--; + assert(local > 0); + _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local); + } + else { + Py_DECREF(op); + } } static inline int diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 7ca43033d722ab..363a7354f80f7f 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -134,27 +134,16 @@ PyFloat_FromDouble(double fval) return (PyObject *) op; } -#ifdef Py_GIL_DISABLED - -PyObject *_PyFloat_FromDouble_ConsumeInputs(_PyStackRef left, _PyStackRef right, double value) -{ - PyStackRef_CLOSE(left); - PyStackRef_CLOSE(right); - return PyFloat_FromDouble(value); -} - -#else // Py_GIL_DISABLED - PyObject *_PyFloat_FromDouble_ConsumeInputs(_PyStackRef left, _PyStackRef right, double value) { PyObject *left_o = PyStackRef_AsPyObjectSteal(left); PyObject *right_o = PyStackRef_AsPyObjectSteal(right); - if (Py_REFCNT(left_o) == 1) { + if (_PyObject_IsUniquelyReferenced(left_o)) { ((PyFloatObject *)left_o)->ob_fval = value; _Py_DECREF_SPECIALIZED(right_o, _PyFloat_ExactDealloc); return left_o; } - else if (Py_REFCNT(right_o) == 1) { + else if (_PyObject_IsUniquelyReferenced(right_o)) { ((PyFloatObject *)right_o)->ob_fval = value; _Py_DECREF_NO_DEALLOC(left_o); return right_o; @@ -167,8 +156,6 @@ PyObject *_PyFloat_FromDouble_ConsumeInputs(_PyStackRef left, _PyStackRef right, } } -#endif // Py_GIL_DISABLED - static PyObject * float_from_string_inner(const char *s, Py_ssize_t len, void *obj) { From 970949e144309acc598ea8c4ecb88ca20333c6a2 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Wed, 5 Feb 2025 11:11:43 -0800 Subject: [PATCH 2/3] Add NEWS. --- .../2025-02-05-11-11-40.gh-issue-129695.qt2Jsz.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-02-05-11-11-40.gh-issue-129695.qt2Jsz.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-02-05-11-11-40.gh-issue-129695.qt2Jsz.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-05-11-11-40.gh-issue-129695.qt2Jsz.rst new file mode 100644 index 00000000000000..55fc7f31d88ead --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-05-11-11-40.gh-issue-129695.qt2Jsz.rst @@ -0,0 +1,2 @@ +Add an optimized version of the ``_PyFloat_FromDouble_ConsumeInputs`` +function for the free-threaded build. From ecf15ed7a4df02c87e2f5606a6408f8e2ddaf488 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Wed, 5 Feb 2025 14:20:50 -0800 Subject: [PATCH 3/3] Fix bug, _Py_DECREF_DecRefTotal(). These calls need to be be wrapped in Py_REF_DEBUG ifdefs. --- Include/internal/pycore_object.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 509d7e6b23e1f2..3eb7f33de406fd 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -273,7 +273,9 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct) return; } _Py_DECREF_STAT_INC(); +#ifdef Py_REF_DEBUG _Py_DECREF_DecRefTotal(); +#endif local--; _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local); if (local == 0) { @@ -296,7 +298,9 @@ _Py_DECREF_NO_DEALLOC(PyObject *op) return; } _Py_DECREF_STAT_INC(); +#ifdef Py_REF_DEBUG _Py_DECREF_DecRefTotal(); +#endif local--; assert(local > 0); _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local);