global unified freelist #3

Open
wants to merge 11 commits into
from
View
@@ -104,6 +104,64 @@ PyAPI_FUNC(void) PyObject_Free(void *ptr);
#ifndef Py_LIMITED_API
/* This function returns the number of allocated memory blocks, regardless of size */
PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void);
+
+
+#define _PY_FREELIST_ALIGNMENT (8)
+#define _PY_FREELIST_MAXSIZECLASS (24)
+#define _PY_FREELIST_MAXLENGTH (1024)
+#define _PY_FREELIST_STAT 0
+
+typedef struct {
+ void *ptr;
+ size_t nfree;
+#if _PY_FREELIST_STAT
+ size_t reused, alloc;
+#endif
+} _Py_freelist_slot;
+
+extern _Py_freelist_slot _Py_global_freelist[_PY_FREELIST_MAXSIZECLASS];
+
+static inline void*
+_PyFreelist_Malloc(size_t size)
+{
+ size_t sc = (size-1) / _PY_FREELIST_ALIGNMENT;
+ if (sc < _PY_FREELIST_MAXSIZECLASS) {
+ _Py_freelist_slot *slot = &_Py_global_freelist[sc];
+ if (slot->nfree > 0) {
+ void *ret = slot->ptr;
+ slot->ptr = *((void**)ret);
+ slot->nfree--;
+#if _PY_FREELIST_STAT
+ slot->reused++;
+#endif
+ return ret;
+ }
+#if _PY_FREELIST_STAT
+ slot->alloc++;
+#endif
+ size = (sc + 1) * _PY_FREELIST_ALIGNMENT;
+ }
+ return PyObject_Malloc(size);
+}
+
+static inline void
+_PyFreelist_Free(void *ptr, size_t size)
+{
+ size_t sc = (size-1) / _PY_FREELIST_ALIGNMENT;
+ if (sc < _PY_FREELIST_MAXSIZECLASS) {
+ _Py_freelist_slot *slot = &_Py_global_freelist[sc];
+ if (slot->nfree < _PY_FREELIST_MAXLENGTH) {
+ *((void**)ptr) = slot->ptr;
+ slot->ptr = ptr;
+ slot->nfree++;
+ return;
+ }
+ }
+ PyObject_Free(ptr);
+}
+
+/* TODO: Support ClearFreelist and stats */
+
#endif /* !Py_LIMITED_API */
/* Macros */
@@ -330,6 +388,9 @@ extern PyGC_Head *_PyGC_generation0;
#ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) _PyObject_GC_Malloc(size_t size);
PyAPI_FUNC(PyObject *) _PyObject_GC_Calloc(size_t size);
+PyAPI_FUNC(void) _PyObject_GC_Recycle(void *, size_t size);
+
+
#endif /* !Py_LIMITED_API */
PyAPI_FUNC(PyObject *) _PyObject_GC_New(PyTypeObject *);
PyAPI_FUNC(PyVarObject *) _PyObject_GC_NewVar(PyTypeObject *, Py_ssize_t);
View
@@ -1738,12 +1738,12 @@ _PyObject_GC_Alloc(int use_calloc, size_t basicsize)
if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head))
return PyErr_NoMemory();
size = sizeof(PyGC_Head) + basicsize;
- if (use_calloc)
- g = (PyGC_Head *)PyObject_Calloc(1, size);
- else
- g = (PyGC_Head *)PyObject_Malloc(size);
+ g = _PyFreelist_Malloc(size);
if (g == NULL)
return PyErr_NoMemory();
+ if (use_calloc) {
+ memset((void*)g, 0, size);
+ }
g->gc.gc_refs = 0;
_PyGCHead_SET_REFS(g, GC_UNTRACKED);
generations[0].count++; /* number of allocated GC objects */
@@ -1824,3 +1824,16 @@ PyObject_GC_Del(void *op)
}
PyObject_FREE(g);
}
+
+void
+_PyObject_GC_Recycle(void *op, size_t basicsize)
+{
+ size_t size = sizeof(PyGC_Head) + basicsize;
+ PyGC_Head *g = AS_GC(op);
+ if (IS_TRACKED(op))
+ gc_list_remove(g);
+ if (generations[0].count > 0) {
+ generations[0].count--;
+ }
+ _PyFreelist_Free(g, size);
+}
View
@@ -808,7 +808,7 @@ _PyObject_FastCall_Prepend(PyObject *callable,
args2 = small_stack;
}
else {
- args2 = PyMem_Malloc(nargs * sizeof(PyObject *));
+ args2 = _PyFreelist_Malloc(nargs * sizeof(PyObject *));
if (args2 == NULL) {
PyErr_NoMemory();
return NULL;
@@ -823,7 +823,7 @@ _PyObject_FastCall_Prepend(PyObject *callable,
result = _PyObject_FastCall(callable, args2, nargs);
if (args2 != small_stack) {
- PyMem_Free(args2);
+ _PyFreelist_Free(args2, nargs * sizeof(PyObject *));
}
return result;
}
@@ -846,7 +846,7 @@ _PyObject_Call_Prepend(PyObject *callable,
stack = small_stack;
}
else {
- stack = PyMem_Malloc((argcount + 1) * sizeof(PyObject *));
+ stack = _PyFreelist_Malloc((argcount + 1) * sizeof(PyObject *));
if (stack == NULL) {
PyErr_NoMemory();
return NULL;
@@ -863,7 +863,7 @@ _PyObject_Call_Prepend(PyObject *callable,
stack, argcount + 1,
kwargs);
if (stack != small_stack) {
- PyMem_Free(stack);
+ _PyFreelist_Free(stack, (argcount + 1) * sizeof(PyObject *));
}
return result;
}
@@ -919,7 +919,7 @@ _PyObject_CallFunctionVa(PyObject *callable, const char *format,
Py_DECREF(stack[i]);
}
if (stack != small_stack) {
- PyMem_Free(stack);
+ PyMem_FREE(stack);
}
return result;
}
@@ -1150,7 +1150,7 @@ object_vacall(PyObject *callable, va_list vargs)
stack = small_stack;
}
else {
- stack = PyMem_Malloc(nargs * sizeof(stack[0]));
+ stack = _PyFreelist_Malloc(nargs * sizeof(stack[0]));
if (stack == NULL) {
PyErr_NoMemory();
return NULL;
@@ -1165,7 +1165,7 @@ object_vacall(PyObject *callable, va_list vargs)
result = _PyObject_FastCall(callable, stack, nargs);
if (stack != small_stack) {
- PyMem_Free(stack);
+ _PyFreelist_Free(stack, nargs * sizeof(PyObject*));
}
return result;
}
View
@@ -5,14 +5,6 @@
#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(__qualname__);
@@ -50,17 +42,9 @@ PyMethod_New(PyObject *func, PyObject *self)
PyErr_BadInternalCall();
return NULL;
}
- im = free_list;
- if (im != NULL) {
- free_list = (PyMethodObject *)(im->im_self);
- (void)PyObject_INIT(im, &PyMethod_Type);
- numfree--;
- }
- else {
- im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);
- if (im == NULL)
- return NULL;
- }
+ im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);
+ if (im == NULL)
+ return NULL;
im->im_weakreflist = NULL;
Py_INCREF(func);
im->im_func = func;
@@ -196,10 +180,8 @@ method_dealloc(PyMethodObject *im)
PyObject_ClearWeakRefs((PyObject *)im);
Py_DECREF(im->im_func);
Py_XDECREF(im->im_self);
- if (numfree < PyMethod_MAXFREELIST) {
- im->im_self = (PyObject *)free_list;
- free_list = im;
- numfree++;
+ if (Py_TYPE((PyObject*)im) == &PyMethod_Type) {
+ _PyObject_GC_Recycle(im, sizeof(PyMethodObject));
}
else {
PyObject_GC_Del(im);
@@ -377,16 +359,7 @@ PyTypeObject PyMethod_Type = {
int
PyMethod_ClearFreeList(void)
{
- int freelist_size = numfree;
-
- while (free_list) {
- PyMethodObject *im = free_list;
- free_list = (PyMethodObject *)(im->im_self);
- PyObject_GC_Del(im);
- numfree--;
- }
- assert(numfree == 0);
- return freelist_size;
+ return 0;
}
void
@@ -399,9 +372,6 @@ PyMethod_Fini(void)
void
_PyMethod_DebugMallocStats(FILE *out)
{
- _PyDebugAllocatorStats(out,
- "free PyMethodObject",
- numfree, sizeof(PyMethodObject));
}
/* ------------------------------------------------------------------------
@@ -484,7 +454,12 @@ static void
instancemethod_dealloc(PyObject *self) {
_PyObject_GC_UNTRACK(self);
Py_DECREF(PyInstanceMethod_GET_FUNCTION(self));
- PyObject_GC_Del(self);
+ if (Py_TYPE(self) == &PyInstanceMethod_Type) {
+ _PyObject_GC_Recycle(self, sizeof(PyInstanceMethodObject));
+ }
+ else {
+ PyObject_GC_Del(self);
+ }
}
static int
Oops, something went wrong.