Issue #14435: Remove special block allocation code from floatobject.c

PyFloatObjects are now allocated using PyObject_MALLOC like all other
internal types, but maintain a limited freelist of objects at hand for
performance.  This will result in more consistent memory usage by Python.
parent 3d7de87d
...@@ -16,53 +16,16 @@ ...@@ -16,53 +16,16 @@
/* Special free list /* Special free list
Since some Python programs can spend much of their time allocating
and deallocating floats, these operations should be very fast.
Therefore we use a dedicated allocation scheme with a much lower
overhead (in space and time) than straight malloc(): a simple
dedicated free list, filled when necessary with memory from malloc().
block_list is a singly-linked list of all PyFloatBlocks ever allocated,
linked via their next members. PyFloatBlocks are never returned to the
system before shutdown (PyFloat_Fini).
free_list is a singly-linked list of available PyFloatObjects, linked free_list is a singly-linked list of available PyFloatObjects, linked
via abuse of their ob_type members. via abuse of their ob_type members.
*/ */
#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ #ifndef PyFloat_MAXFREELIST
#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */ #define PyFloat_MAXFREELIST 100
#define N_FLOATOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyFloatObject)) #endif
static int numfree = 0;
struct _floatblock {
struct _floatblock *next;
PyFloatObject objects[N_FLOATOBJECTS];
};
typedef struct _floatblock PyFloatBlock;
static PyFloatBlock *block_list = NULL;
static PyFloatObject *free_list = NULL; static PyFloatObject *free_list = NULL;
static PyFloatObject *
fill_free_list(void)
{
PyFloatObject *p, *q;
/* XXX Float blocks escape the object heap. Use PyObject_MALLOC ??? */
p = (PyFloatObject *) PyMem_MALLOC(sizeof(PyFloatBlock));
if (p == NULL)
return (PyFloatObject *) PyErr_NoMemory();
((PyFloatBlock *)p)->next = block_list;
block_list = (PyFloatBlock *)p;
p = &((PyFloatBlock *)p)->objects[0];
q = p + N_FLOATOBJECTS;
while (--q > p)
Py_TYPE(q) = (struct _typeobject *)(q-1);
Py_TYPE(q) = NULL;
return p + N_FLOATOBJECTS - 1;
}
double double
PyFloat_GetMax(void) PyFloat_GetMax(void)
{ {
...@@ -151,14 +114,16 @@ PyFloat_GetInfo(void) ...@@ -151,14 +114,16 @@ PyFloat_GetInfo(void)
PyObject * PyObject *
PyFloat_FromDouble(double fval) PyFloat_FromDouble(double fval)
{ {
register PyFloatObject *op; register PyFloatObject *op = free_list;
if (free_list == NULL) { if (op != NULL) {
if ((free_list = fill_free_list()) == NULL) free_list = (PyFloatObject *) Py_TYPE(op);
return NULL; numfree--;
} else {
op = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject));
if (!op)
return PyErr_NoMemory();
} }
/* Inline PyObject_New */ /* Inline PyObject_New */
op = free_list;
free_list = (PyFloatObject *)Py_TYPE(op);
PyObject_INIT(op, &PyFloat_Type); PyObject_INIT(op, &PyFloat_Type);
op->ob_fval = fval; op->ob_fval = fval;
return (PyObject *) op; return (PyObject *) op;
...@@ -217,6 +182,11 @@ static void ...@@ -217,6 +182,11 @@ static void
float_dealloc(PyFloatObject *op) float_dealloc(PyFloatObject *op)
{ {
if (PyFloat_CheckExact(op)) { if (PyFloat_CheckExact(op)) {
if (numfree >= PyFloat_MAXFREELIST) {
PyObject_FREE(op);
return;
}
numfree++;
Py_TYPE(op) = (struct _typeobject *)free_list; Py_TYPE(op) = (struct _typeobject *)free_list;
free_list = op; free_list = op;
} }
...@@ -1932,96 +1902,22 @@ _PyFloat_Init(void) ...@@ -1932,96 +1902,22 @@ _PyFloat_Init(void)
int int
PyFloat_ClearFreeList(void) PyFloat_ClearFreeList(void)
{ {
PyFloatObject *p; PyFloatObject *f = free_list, *next;
PyFloatBlock *list, *next; int i = numfree;
int i; while (f) {
int u; /* remaining unfreed floats per block */ next = (PyFloatObject*) Py_TYPE(f);
int freelist_size = 0; PyObject_FREE(f);
f = next;
list = block_list;
block_list = NULL;
free_list = NULL;
while (list != NULL) {
u = 0;
for (i = 0, p = &list->objects[0];
i < N_FLOATOBJECTS;
i++, p++) {
if (PyFloat_CheckExact(p) && Py_REFCNT(p) != 0)
u++;
}
next = list->next;
if (u) {
list->next = block_list;
block_list = list;
for (i = 0, p = &list->objects[0];
i < N_FLOATOBJECTS;
i++, p++) {
if (!PyFloat_CheckExact(p) ||
Py_REFCNT(p) == 0) {
Py_TYPE(p) = (struct _typeobject *)
free_list;
free_list = p;
}
}
}
else {
PyMem_FREE(list);
}
freelist_size += u;
list = next;
} }
return freelist_size; free_list = NULL;
numfree = 0;
return i;
} }
void void
PyFloat_Fini(void) PyFloat_Fini(void)
{ {
PyFloatObject *p; (void)PyFloat_ClearFreeList();
PyFloatBlock *list;
int i;
int u; /* total unfreed floats per block */
u = PyFloat_ClearFreeList();
if (!Py_VerboseFlag)
return;
fprintf(stderr, "# cleanup floats");
if (!u) {
fprintf(stderr, "\n");
}
else {
fprintf(stderr,
": %d unfreed float%s\n",
u, u == 1 ? "" : "s");
}
if (Py_VerboseFlag > 1) {
list = block_list;
while (list != NULL) {
for (i = 0, p = &list->objects[0];
i < N_FLOATOBJECTS;
i++, p++) {
if (PyFloat_CheckExact(p) &&
Py_REFCNT(p) != 0) {
char *buf = PyOS_double_to_string(
PyFloat_AS_DOUBLE(p), 'r',
0, 0, NULL);
if (buf) {
/* XXX(twouters) cast
refcount to long
until %zd is
universally
available
*/
fprintf(stderr,
"# <float at %p, refcnt=%ld, val=%s>\n",
p, (long)Py_REFCNT(p), buf);
PyMem_Free(buf);
}
}
}
list = list->next;
}
}
} }
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment