bpo-37340: remove free_list for bound method objects (GH-14232)

This commit is contained in:
Inada Naoki 2019-07-26 15:05:50 +09:00 committed by GitHub
parent 76b645124b
commit 3e54b57531
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 14 additions and 101 deletions

View File

@ -99,11 +99,6 @@ typedef struct {
PyAPI_FUNC(int) PyCFunction_ClearFreeList(void); PyAPI_FUNC(int) PyCFunction_ClearFreeList(void);
#ifndef Py_LIMITED_API
PyAPI_FUNC(void) _PyCFunction_DebugMallocStats(FILE *out);
PyAPI_FUNC(void) _PyMethod_DebugMallocStats(FILE *out);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -0,0 +1,3 @@
Removed object cache (``free_list``) for bound method objects. Temporary
bound method objects are less used than before thanks to the ``LOAD_METHOD``
opcode and the ``_PyObject_VectorcallMethod`` C API.

View File

@ -8,15 +8,6 @@
#define TP_DESCR_GET(t) ((t)->tp_descr_get) #define TP_DESCR_GET(t) ((t)->tp_descr_get)
/* Free list for method objects to safe malloc/free overhead
* The im_self element is used to chain the elements.
*/
static PyMethodObject *free_list;
static int numfree = 0;
#ifndef PyMethod_MAXFREELIST
#define PyMethod_MAXFREELIST 256
#endif
_Py_IDENTIFIER(__name__); _Py_IDENTIFIER(__name__);
_Py_IDENTIFIER(__qualname__); _Py_IDENTIFIER(__qualname__);
@ -103,21 +94,13 @@ method_vectorcall(PyObject *method, PyObject *const *args,
PyObject * PyObject *
PyMethod_New(PyObject *func, PyObject *self) PyMethod_New(PyObject *func, PyObject *self)
{ {
PyMethodObject *im;
if (self == NULL) { if (self == NULL) {
PyErr_BadInternalCall(); PyErr_BadInternalCall();
return NULL; return NULL;
} }
im = free_list; PyMethodObject *im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);
if (im != NULL) { if (im == NULL) {
free_list = (PyMethodObject *)(im->im_self); return NULL;
(void)PyObject_INIT(im, &PyMethod_Type);
numfree--;
}
else {
im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);
if (im == NULL)
return NULL;
} }
im->im_weakreflist = NULL; im->im_weakreflist = NULL;
Py_INCREF(func); Py_INCREF(func);
@ -252,14 +235,7 @@ method_dealloc(PyMethodObject *im)
PyObject_ClearWeakRefs((PyObject *)im); PyObject_ClearWeakRefs((PyObject *)im);
Py_DECREF(im->im_func); Py_DECREF(im->im_func);
Py_XDECREF(im->im_self); Py_XDECREF(im->im_self);
if (numfree < PyMethod_MAXFREELIST) { PyObject_GC_Del(im);
im->im_self = (PyObject *)free_list;
free_list = im;
numfree++;
}
else {
PyObject_GC_Del(im);
}
} }
static PyObject * static PyObject *
@ -395,16 +371,7 @@ PyTypeObject PyMethod_Type = {
int int
PyMethod_ClearFreeList(void) PyMethod_ClearFreeList(void)
{ {
int freelist_size = numfree; return 0;
while (free_list) {
PyMethodObject *im = free_list;
free_list = (PyMethodObject *)(im->im_self);
PyObject_GC_Del(im);
numfree--;
}
assert(numfree == 0);
return freelist_size;
} }
void void
@ -413,15 +380,6 @@ PyMethod_Fini(void)
(void)PyMethod_ClearFreeList(); (void)PyMethod_ClearFreeList();
} }
/* Print summary info about the state of the optimized allocator */
void
_PyMethod_DebugMallocStats(FILE *out)
{
_PyDebugAllocatorStats(out,
"free PyMethodObject",
numfree, sizeof(PyMethodObject));
}
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
* instance method * instance method
*/ */

View File

@ -7,15 +7,6 @@
#include "pycore_pystate.h" #include "pycore_pystate.h"
#include "structmember.h" #include "structmember.h"
/* Free list for method objects to safe malloc/free overhead
* The m_self element is used to chain the objects.
*/
static PyCFunctionObject *free_list = NULL;
static int numfree = 0;
#ifndef PyCFunction_MAXFREELIST
#define PyCFunction_MAXFREELIST 256
#endif
/* undefine macro trampoline to PyCFunction_NewEx */ /* undefine macro trampoline to PyCFunction_NewEx */
#undef PyCFunction_New #undef PyCFunction_New
@ -66,17 +57,10 @@ PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
return NULL; return NULL;
} }
PyCFunctionObject *op; PyCFunctionObject *op =
op = free_list; PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type);
if (op != NULL) { if (op == NULL) {
free_list = (PyCFunctionObject *)(op->m_self); return NULL;
(void)PyObject_INIT(op, &PyCFunction_Type);
numfree--;
}
else {
op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type);
if (op == NULL)
return NULL;
} }
op->m_weakreflist = NULL; op->m_weakreflist = NULL;
op->m_ml = ml; op->m_ml = ml;
@ -130,14 +114,7 @@ meth_dealloc(PyCFunctionObject *m)
} }
Py_XDECREF(m->m_self); Py_XDECREF(m->m_self);
Py_XDECREF(m->m_module); Py_XDECREF(m->m_module);
if (numfree < PyCFunction_MAXFREELIST) { PyObject_GC_Del(m);
m->m_self = (PyObject *)free_list;
free_list = m;
numfree++;
}
else {
PyObject_GC_Del(m);
}
} }
static PyObject * static PyObject *
@ -338,16 +315,7 @@ PyTypeObject PyCFunction_Type = {
int int
PyCFunction_ClearFreeList(void) PyCFunction_ClearFreeList(void)
{ {
int freelist_size = numfree; return 0;
while (free_list) {
PyCFunctionObject *v = free_list;
free_list = (PyCFunctionObject *)(v->m_self);
PyObject_GC_Del(v);
numfree--;
}
assert(numfree == 0);
return freelist_size;
} }
void void
@ -356,15 +324,6 @@ PyCFunction_Fini(void)
(void)PyCFunction_ClearFreeList(); (void)PyCFunction_ClearFreeList();
} }
/* Print summary info about the state of the optimized allocator */
void
_PyCFunction_DebugMallocStats(FILE *out)
{
_PyDebugAllocatorStats(out,
"free PyCFunctionObject",
numfree, sizeof(PyCFunctionObject));
}
/* Vectorcall functions for each of the PyCFunction calling conventions, /* Vectorcall functions for each of the PyCFunction calling conventions,
* except for METH_VARARGS (possibly combined with METH_KEYWORDS) which * except for METH_VARARGS (possibly combined with METH_KEYWORDS) which

View File

@ -1959,12 +1959,10 @@ Py_ssize_t (*_Py_abstract_hack)(PyObject *) = PyObject_Size;
void void
_PyObject_DebugTypeStats(FILE *out) _PyObject_DebugTypeStats(FILE *out)
{ {
_PyCFunction_DebugMallocStats(out);
_PyDict_DebugMallocStats(out); _PyDict_DebugMallocStats(out);
_PyFloat_DebugMallocStats(out); _PyFloat_DebugMallocStats(out);
_PyFrame_DebugMallocStats(out); _PyFrame_DebugMallocStats(out);
_PyList_DebugMallocStats(out); _PyList_DebugMallocStats(out);
_PyMethod_DebugMallocStats(out);
_PyTuple_DebugMallocStats(out); _PyTuple_DebugMallocStats(out);
} }