mirror of
https://github.com/python/cpython.git
synced 2025-10-02 21:25:24 +00:00
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.
This commit is contained in:
parent
c1d9869cb9
commit
daa06544c8
1 changed files with 27 additions and 131 deletions
|
@ -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)
|
||||||
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
|
||||||
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)
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue