Index: Python/sysmodule.c =================================================================== --- Python/sysmodule.c (Revision 60721) +++ Python/sysmodule.c (Arbeitskopie) @@ -787,15 +787,12 @@ static PyObject * sys_compact_freelists(PyObject* self, PyObject* args) { - size_t isum, ibc, ibf; - size_t fsum, fbc, fbf; - - PyInt_CompactFreeList(&ibc, &ibf, &isum); - PyFloat_CompactFreeList(&fbc, &fbf, &fsum); - - return Py_BuildValue("(kkk)(kkk)", isum, ibc, ibf, - fsum, fbc, fbf); - + return NULL; + /* + return Py_BuildValue("{OiOi}", + &PyInt_Type, PyInt_ClearFreeList(), + &PyFloat_Type, PyFloat_ClearFreeList() + ); */ } PyDoc_STRVAR(sys_compact_freelists__doc__, Index: Include/intobject.h =================================================================== --- Include/intobject.h (Revision 60721) +++ 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); /* Convert an integer to the given base. Returns a string. If base is 2, 8 or 16, add the proper prefix '0b', '0o' or '0x'. Index: Include/floatobject.h =================================================================== --- Include/floatobject.h (Revision 60721) +++ 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 60721) +++ Objects/intobject.c (Arbeitskopie) @@ -12,57 +12,15 @@ 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 - via abuse of their ob_type members. +/* The integer free_listis using a fixed size list instead of a linked list + for performance reason. */ +#define PyInt_MAXFREELIST 0 +#if PyInt_MAXFREELIST +static PyIntObject *free_list[PyInt_MAXFREELIST]; +static int numfree = 0; +#endif -#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 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,14 +56,21 @@ return (PyObject *) v; } #endif - if (free_list == NULL) { - if ((free_list = fill_free_list()) == NULL) +#if PyInt_MAXFREELIST + if (numfree) { + v = free_list[--numfree]; + _Py_NewReference((PyObject *)v); + assert(PyInt_CheckExact(v)); + } + else +#endif + { + /* Inline PyObject_New */ + v = (PyIntObject *)PyObject_MALLOC(sizeof(PyIntObject)); + if (v == NULL) return NULL; + PyObject_INIT(v, &PyInt_Type); } - /* 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 +94,15 @@ static void int_dealloc(PyIntObject *v) { - if (PyInt_CheckExact(v)) { - Py_TYPE(v) = (struct _typeobject *)free_list; - free_list = v; +#if PyInt_MAXFREELIST + if (PyInt_CheckExact(v) && numfree < PyInt_MAXFREELIST) { + free_list[numfree++] = v; } else +#endif 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) { @@ -1230,7 +1189,7 @@ 0, /* tp_init */ 0, /* tp_alloc */ int_new, /* tp_new */ - (freefunc)int_free, /* tp_free */ + PyObject_Del, /* tp_free */ }; int @@ -1240,11 +1199,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; @@ -1253,75 +1211,27 @@ 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; +#if PyInt_MAXFREELIST + int freelist_size = numfree; + PyIntObject *op; + + while (numfree) { + op = free_list[--numfree]; + assert(PyInt_CheckExact(op)); + PyInt_Type.tp_free(op); } - - *pbc = bc; - *pbf = bf; - *bsum = isum; + return freelist_size; +#else + return 0; +#endif } 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; @@ -1333,38 +1243,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; - } - } + PyInt_ClearFreeList(); } Index: Objects/floatobject.c =================================================================== --- Objects/floatobject.c (Revision 60721) +++ Objects/floatobject.c (Arbeitskopie) @@ -21,39 +21,13 @@ 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)) +/* see intobject.c */ +#define PyFloat_MAXFREELIST 0 +#if PyFloat_MAXFREELIST +static PyFloatObject *free_list[PyFloat_MAXFREELIST]; +static int numfree = 0; +#endif -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 * -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,14 +117,21 @@ PyFloat_FromDouble(double fval) { register PyFloatObject *op; - if (free_list == NULL) { - if ((free_list = fill_free_list()) == NULL) +#if PyFloat_MAXFREELIST + if (numfree) { + op = free_list[--numfree]; + _Py_NewReference((PyObject *)op); + assert(PyFloat_CheckExact(op)); + } + else +#endif + { + /* Inline PyObject_New */ + op = (PyFloatObject *)PyObject_MALLOC(sizeof(PyFloatObject)); + if (op == NULL) return NULL; + PyObject_INIT(op, &PyFloat_Type); } - /* 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,11 +268,12 @@ static void float_dealloc(PyFloatObject *op) { - if (PyFloat_CheckExact(op)) { - Py_TYPE(op) = (struct _typeobject *)free_list; - free_list = op; +#if PyFloat_MAXFREELIST + if (PyFloat_CheckExact(op) && numfree < PyFloat_MAXFREELIST) { + free_list[numfree++] = op; } else +#endif Py_TYPE(op)->tp_free((PyObject *)op); } @@ -1548,6 +1530,7 @@ 0, /* tp_init */ 0, /* tp_alloc */ float_new, /* tp_new */ + PyObject_Del, /* tp_free */ }; void @@ -1608,102 +1591,30 @@ PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc); } -void -PyFloat_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum) + +int +PyFloat_ClearFreeList(void) { - 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 */ +#if PyFloat_MAXFREELIST + int freelist_size = numfree; - 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; + PyFloatObject *op; + + while (numfree) { + op = free_list[--numfree]; + assert(PyFloat_CheckExact(op)); + PyFloat_Type.tp_free(op); } - *pbc = bc; - *pbf = bf; - *bsum = fsum; + return freelist_size; +#else + return 0; +#endif } 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(); } /*----------------------------------------------------------------------------