Index: Python/sysmodule.c =================================================================== --- Python/sysmodule.c (Revision 60644) +++ Python/sysmodule.c (Arbeitskopie) @@ -787,15 +787,16 @@ static PyObject * sys_compact_freelists(PyObject* self, PyObject* args) { - size_t isum, ibc, ibf; + /*size_t isum, ibc, ibf; size_t fsum, fbc, fbf; PyInt_CompactFreeList(&ibc, &ibf, &isum); - PyFloat_CompactFreeList(&fbc, &fbf, &fsum); + PyFloat_ClearFreeList(&fbc, &fbf, &fsum); return Py_BuildValue("(kkk)(kkk)", isum, ibc, ibf, fsum, fbc, fbf); - + */ + return NULL; } PyDoc_STRVAR(sys_compact_freelists__doc__, Index: Include/intobject.h =================================================================== --- Include/intobject.h (Revision 60644) +++ Include/intobject.h (Arbeitskopie) @@ -60,7 +60,7 @@ PyAPI_FUNC(long) PyOS_strtol(char *, char **, int); /* free list api */ -PyAPI_FUNC(void) PyInt_CompactFreeList(size_t *, size_t *, size_t *); +PyAPI_FUNC(int) PyInt_ClearFreeList(void); #ifdef __cplusplus } Index: Include/floatobject.h =================================================================== --- Include/floatobject.h (Revision 60644) +++ Include/floatobject.h (Arbeitskopie) @@ -102,7 +102,7 @@ PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le); /* free list api */ -PyAPI_FUNC(void) PyFloat_CompactFreeList(size_t *, size_t *, size_t *); +PyAPI_FUNC(int) PyFloat_ClearFreeList(void); #ifdef __cplusplus } Index: Objects/intobject.c =================================================================== --- Objects/intobject.c (Revision 60645) +++ Objects/intobject.c (Arbeitskopie) @@ -12,57 +12,13 @@ return LONG_MAX; /* To initialize sys.maxint */ } -/* Integers are quite normal objects, to make object handling uniform. - (Using odd pointers to represent integers would save much space - but require extra checks for this special case throughout the code.) - Since a typical Python program spends much of its time allocating - and deallocating integers, 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 PyIntBlocks ever allocated, - linked via their next members. PyIntBlocks are never returned to the - system before shutdown (PyInt_Fini). - - free_list is a singly-linked list of available PyIntObjects, linked +/* free_list is a singly-linked list of available PyIntObjects, linked via abuse of their ob_type members. */ - -#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ -#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */ -#define N_INTOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyIntObject)) - -struct _intblock { - struct _intblock *next; - PyIntObject objects[N_INTOBJECTS]; -}; - -typedef struct _intblock PyIntBlock; - -static PyIntBlock *block_list = NULL; static PyIntObject *free_list = NULL; +static int numfree = 0; +#define PyInt_MAXFREELIST 8192 -static PyIntObject * -fill_free_list(void) -{ - PyIntObject *p, *q; - /* Python's object allocator isn't appropriate for large blocks. */ - p = (PyIntObject *) PyMem_MALLOC(sizeof(PyIntBlock)); - if (p == NULL) - return (PyIntObject *) PyErr_NoMemory(); - ((PyIntBlock *)p)->next = block_list; - block_list = (PyIntBlock *)p; - /* Link the int objects together, from rear to front, then return - the address of the last int object in the block. */ - p = &((PyIntBlock *)p)->objects[0]; - q = p + N_INTOBJECTS; - while (--q > p) - Py_TYPE(q) = (struct _typeobject *)(q-1); - Py_TYPE(q) = NULL; - return p + N_INTOBJECTS - 1; -} - #ifndef NSMALLPOSINTS #define NSMALLPOSINTS 257 #endif @@ -98,13 +54,18 @@ return (PyObject *) v; } #endif - if (free_list == NULL) { - if ((free_list = fill_free_list()) == NULL) + v = free_list; + if (v != NULL) { + free_list = (PyIntObject *)Py_TYPE(v); + numfree--; + } + else { + /* Inline PyObject_New */ + v = (PyIntObject *)PyObject_MALLOC(sizeof(PyIntObject)); + if (v == NULL) return NULL; } - /* Inline PyObject_New */ - v = free_list; - free_list = (PyIntObject *)Py_TYPE(v); + PyObject_INIT(v, &PyInt_Type); v->ob_ival = ival; return (PyObject *) v; @@ -129,21 +90,15 @@ static void int_dealloc(PyIntObject *v) { - if (PyInt_CheckExact(v)) { - Py_TYPE(v) = (struct _typeobject *)free_list; + if (PyInt_CheckExact(v) && numfree < PyInt_MAXFREELIST) { + Py_TYPE(v) = (PyTypeObject *)free_list; free_list = v; + numfree++; } else Py_TYPE(v)->tp_free((PyObject *)v); } -static void -int_free(PyIntObject *v) -{ - Py_TYPE(v) = (struct _typeobject *)free_list; - free_list = v; -} - long PyInt_AsLong(register PyObject *op) { @@ -1178,7 +1133,7 @@ 0, /* tp_init */ 0, /* tp_alloc */ int_new, /* tp_new */ - (freefunc)int_free, /* tp_free */ + PyObject_Del, /* tp_free */ }; int @@ -1188,11 +1143,10 @@ int ival; #if NSMALLNEGINTS + NSMALLPOSINTS > 0 for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++) { - if (!free_list && (free_list = fill_free_list()) == NULL) - return 0; /* PyObject_New is inlined */ - v = free_list; - free_list = (PyIntObject *)Py_TYPE(v); + v = (PyIntObject *)PyObject_MALLOC(sizeof(PyIntObject)); + if (v == NULL) + return 0; PyObject_INIT(v, &PyInt_Type); v->ob_ival = ival; small_ints[ival + NSMALLNEGINTS] = v; @@ -1201,75 +1155,25 @@ return 1; } -void -PyInt_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum) +int +PyInt_ClearFreeList(void) { - PyIntObject *p; - PyIntBlock *list, *next; - unsigned int ctr; - size_t bc = 0, bf = 0; /* block count, number of freed blocks */ - size_t isum = 0; /* total unfreed ints */ - int irem; /* remaining unfreed ints per block */ - - list = block_list; - block_list = NULL; - free_list = NULL; - while (list != NULL) { - bc++; - irem = 0; - for (ctr = 0, p = &list->objects[0]; - ctr < N_INTOBJECTS; - ctr++, p++) { - if (PyInt_CheckExact(p) && p->ob_refcnt != 0) - irem++; - } - next = list->next; - if (irem) { - list->next = block_list; - block_list = list; - for (ctr = 0, p = &list->objects[0]; - ctr < N_INTOBJECTS; - ctr++, p++) { - if (!PyInt_CheckExact(p) || - p->ob_refcnt == 0) { - Py_TYPE(p) = (struct _typeobject *) - free_list; - free_list = p; - } -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 - else if (-NSMALLNEGINTS <= p->ob_ival && - p->ob_ival < NSMALLPOSINTS && - small_ints[p->ob_ival + - NSMALLNEGINTS] == NULL) { - Py_INCREF(p); - small_ints[p->ob_ival + - NSMALLNEGINTS] = p; - } -#endif - } - } - else { - PyMem_FREE(list); - bf++; - } - isum += irem; - list = next; + int freelist_size = numfree; + PyIntObject *op; + + while (free_list) { + op = free_list; + free_list = (PyIntObject *)Py_TYPE(op); + PyInt_Type.tp_free((PyObject *)op); + numfree--; } - - *pbc = bc; - *pbf = bf; - *bsum = isum; + assert(numfree == 0); + return freelist_size; } void PyInt_Fini(void) { - PyIntObject *p; - PyIntBlock *list; - unsigned int ctr; - size_t bc, bf; /* block count, number of freed blocks */ - size_t isum; /* total unfreed ints per block */ - #if NSMALLNEGINTS + NSMALLPOSINTS > 0 int i; PyIntObject **q; @@ -1281,38 +1185,5 @@ *q++ = NULL; } #endif - PyInt_CompactFreeList(&bc, &bf, &isum); - if (!Py_VerboseFlag) - return; - fprintf(stderr, "# cleanup ints"); - if (!isum) { - fprintf(stderr, "\n"); - } - else { - fprintf(stderr, - ": %" PY_FORMAT_SIZE_T "d unfreed ints%s in %" - PY_FORMAT_SIZE_T "d out of %" - PY_FORMAT_SIZE_T "d block%s\n", - isum, isum == 1 ? "" : "s", - bc - bf, bc, bc == 1 ? "" : "s"); - } - if (Py_VerboseFlag > 1) { - list = block_list; - while (list != NULL) { - for (ctr = 0, p = &list->objects[0]; - ctr < N_INTOBJECTS; - ctr++, p++) { - if (PyInt_CheckExact(p) && p->ob_refcnt != 0) - /* XXX(twouters) cast refcount to - long until %zd is universally - available - */ - fprintf(stderr, - "# \n", - p, (long)p->ob_refcnt, - p->ob_ival); - } - list = list->next; - } - } + PyFloat_ClearFreeList(); } Index: Objects/floatobject.c =================================================================== --- Objects/floatobject.c (Revision 60645) +++ Objects/floatobject.c (Arbeitskopie) @@ -21,39 +21,11 @@ extern int finite(double); #endif -/* Special free list -- see comments for same code in intobject.c. */ -#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ -#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */ -#define N_FLOATOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyFloatObject)) - -struct _floatblock { - struct _floatblock *next; - PyFloatObject objects[N_FLOATOBJECTS]; -}; - -typedef struct _floatblock PyFloatBlock; - -static PyFloatBlock *block_list = NULL; +/* see floatobject.c */ static PyFloatObject *free_list = NULL; +static int numfree = 0; +#define PyFloat_MAXFREELIST 8192 -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 PyFloat_GetMax(void) { @@ -143,13 +115,17 @@ PyFloat_FromDouble(double fval) { register PyFloatObject *op; - if (free_list == NULL) { - if ((free_list = fill_free_list()) == NULL) + op = free_list; + if (op != NULL) { + free_list = (PyFloatObject *)Py_TYPE(op); + numfree--; + } + else { + /* Inline PyObject_New */ + op = (PyFloatObject *)PyObject_MALLOC(sizeof(PyFloatObject)); + if (op == NULL) return NULL; } - /* Inline PyObject_New */ - op = free_list; - free_list = (PyFloatObject *)Py_TYPE(op); PyObject_INIT(op, &PyFloat_Type); op->ob_fval = fval; return (PyObject *) op; @@ -287,9 +263,10 @@ static void float_dealloc(PyFloatObject *op) { - if (PyFloat_CheckExact(op)) { - Py_TYPE(op) = (struct _typeobject *)free_list; + if (PyFloat_CheckExact(op) && numfree < PyFloat_MAXFREELIST) { + Py_TYPE(op) = (PyTypeObject *)free_list; free_list = op; + numfree++; } else Py_TYPE(op)->tp_free((PyObject *)op); @@ -1548,6 +1525,7 @@ 0, /* tp_init */ 0, /* tp_alloc */ float_new, /* tp_new */ + PyObject_Del, /* tp_free */ }; void @@ -1608,102 +1586,27 @@ PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc); } -void -PyFloat_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum) -{ - PyFloatObject *p; - PyFloatBlock *list, *next; - unsigned i; - size_t bc = 0, bf = 0; /* block count, number of freed blocks */ - size_t fsum = 0; /* total unfreed ints */ - int frem; /* remaining unfreed ints per block */ - list = block_list; - block_list = NULL; - free_list = NULL; - while (list != NULL) { - bc++; - frem = 0; - for (i = 0, p = &list->objects[0]; - i < N_FLOATOBJECTS; - i++, p++) { - if (PyFloat_CheckExact(p) && Py_REFCNT(p) != 0) - frem++; - } - next = list->next; - if (frem) { - 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); /* XXX PyObject_FREE ??? */ - bf++; - } - fsum += frem; - list = next; +int +PyFloat_ClearFreeList(void) +{ + int freelist_size = numfree; + PyFloatObject *op; + + while (free_list) { + op = free_list; + free_list = (PyFloatObject *)Py_TYPE(op); + PyFloat_Type.tp_free((PyObject *)op); + numfree--; } - *pbc = bc; - *pbf = bf; - *bsum = fsum; + assert(numfree == 0); + return freelist_size; } void PyFloat_Fini(void) { - PyFloatObject *p; - PyFloatBlock *list; - unsigned i; - size_t bc, bf; /* block count, number of freed blocks */ - size_t fsum; /* total unfreed floats per block */ - - PyFloat_CompactFreeList(&bc, &bf, &fsum); - - if (!Py_VerboseFlag) - return; - fprintf(stderr, "# cleanup floats"); - if (!fsum) { - fprintf(stderr, "\n"); - } - else { - fprintf(stderr, - ": %" PY_FORMAT_SIZE_T "d unfreed floats%s in %" - PY_FORMAT_SIZE_T "d out of %" - PY_FORMAT_SIZE_T "d block%s\n", - fsum, fsum == 1 ? "" : "s", - bc - bf, bc, bc == 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[100]; - PyFloat_AsString(buf, p); - /* XXX(twouters) cast refcount to - long until %zd is universally - available - */ - fprintf(stderr, - "# \n", - p, (long)Py_REFCNT(p), buf); - } - } - list = list->next; - } - } + PyFloat_ClearFreeList(); } /*----------------------------------------------------------------------------