]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-126703: Add freelist for `PyMethodObject` (#128594)
authorPieter Eendebak <pieter.eendebak@gmail.com>
Sun, 12 Jan 2025 13:01:49 +0000 (14:01 +0100)
committerGitHub <noreply@github.com>
Sun, 12 Jan 2025 13:01:49 +0000 (18:31 +0530)
Include/internal/pycore_freelist_state.h
Misc/NEWS.d/next/Core_and_Builtins/2025-01-07-19-48-56.gh-issue-126703.0ISs-7.rst [new file with mode: 0644]
Objects/classobject.c
Objects/object.c

index a1a94c1f2dc88054ea785b6ab9b75dc294197f9b..2ccd1ac055b7472b64b9f7826375901528cf75da 100644 (file)
@@ -22,6 +22,7 @@ extern "C" {
 #  define Py_futureiters_MAXFREELIST 255
 #  define Py_object_stack_chunks_MAXFREELIST 4
 #  define Py_unicode_writers_MAXFREELIST 1
+#  define Py_pymethodobjects_MAXFREELIST 20
 
 // A generic freelist of either PyObjects or other data structures.
 struct _Py_freelist {
@@ -48,6 +49,7 @@ struct _Py_freelists {
     struct _Py_freelist futureiters;
     struct _Py_freelist object_stack_chunks;
     struct _Py_freelist unicode_writers;
+    struct _Py_freelist pymethodobjects;
 };
 
 #ifdef __cplusplus
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-01-07-19-48-56.gh-issue-126703.0ISs-7.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-07-19-48-56.gh-issue-126703.0ISs-7.rst
new file mode 100644 (file)
index 0000000..ecb8edd
--- /dev/null
@@ -0,0 +1 @@
+Improve performance of class methods by using a freelist.
index 775894ad5a716641a812afc69b83eecda0e20cdd..58e1d17977322e6e9ed36342aa73e13fc2fa0969 100644 (file)
@@ -3,6 +3,7 @@
 #include "Python.h"
 #include "pycore_call.h"          // _PyObject_VectorcallTstate()
 #include "pycore_ceval.h"         // _PyEval_GetBuiltin()
+#include "pycore_freelist.h"
 #include "pycore_object.h"
 #include "pycore_pyerrors.h"
 #include "pycore_pystate.h"       // _PyThreadState_GET()
@@ -112,9 +113,12 @@ PyMethod_New(PyObject *func, PyObject *self)
         PyErr_BadInternalCall();
         return NULL;
     }
-    PyMethodObject *im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);
+    PyMethodObject *im = _Py_FREELIST_POP(PyMethodObject, pymethodobjects);
     if (im == NULL) {
-        return NULL;
+        im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);
+        if (im == NULL) {
+            return NULL;
+        }
     }
     im->im_weakreflist = NULL;
     im->im_func = Py_NewRef(func);
@@ -245,7 +249,8 @@ method_dealloc(PyObject *self)
         PyObject_ClearWeakRefs((PyObject *)im);
     Py_DECREF(im->im_func);
     Py_XDECREF(im->im_self);
-    PyObject_GC_Del(im);
+    assert(Py_IS_TYPE(self, &PyMethod_Type));
+    _Py_FREELIST_FREE(pymethodobjects, (PyObject *)im, PyObject_GC_Del);
 }
 
 static PyObject *
index 4c30257ca26938a3d6d561a5289420b207c42bd2..9befd92e3231c8efc7880a426295ab3f29f84e88 100644 (file)
@@ -937,6 +937,7 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization)
     }
     clear_freelist(&freelists->unicode_writers, is_finalization, PyMem_Free);
     clear_freelist(&freelists->ints, is_finalization, free_object);
+    clear_freelist(&freelists->pymethodobjects, is_finalization, free_object);
 }
 
 /*