Kaydet (Commit) 2fe77060 authored tarafından Gregory P. Smith's avatar Gregory P. Smith

- Issue #2862: Make int and float freelist management consistent with other

  freelists.  Changes their CompactFreeList apis into ClearFreeList apis and
  calls them via gc.collect().
üst 17f2e4ac
...@@ -86,10 +86,9 @@ Floating Point Objects ...@@ -86,10 +86,9 @@ Floating Point Objects
.. versionadded:: 2.6 .. versionadded:: 2.6
.. cfunction:: void PyFloat_CompactFreeList(size_t *bc, size_t *bf, size_t *sum) .. cfunction:: int PyFloat_ClearFreeList(void)
Compact the float free list. *bc* is the number of allocated blocks before Clear the float free list. Return the number of items that could not
blocks are freed, *bf* is the number of freed blocks and *sum* is the number be freed.
of remaining objects in the blocks.
.. versionadded:: 2.6 .. versionadded:: 2.6
...@@ -122,10 +122,9 @@ Plain Integer Objects ...@@ -122,10 +122,9 @@ Plain Integer Objects
(:const:`LONG_MAX`, as defined in the system header files). (:const:`LONG_MAX`, as defined in the system header files).
.. cfunction:: void PyInt_CompactFreeList(size_t *bc, size_t *bf, size_t *sum) .. cfunction:: int PyInt_ClearFreeList(void)
Compact the integer free list. *bc* is the number of allocated blocks before Clear the integer free list. Return the number of items that could not
blocks are freed, *bf* is the number of freed blocks and *sum* is the number be freed.
of remaining objects in the blocks.
.. versionadded:: 2.6 .. versionadded:: 2.6
...@@ -47,6 +47,12 @@ The :mod:`gc` module provides the following functions: ...@@ -47,6 +47,12 @@ The :mod:`gc` module provides the following functions:
.. versionchanged:: 2.5 .. versionchanged:: 2.5
The optional *generation* argument was added. The optional *generation* argument was added.
.. versionchanged:: 2.6
The free lists maintained for a number of builtin types are cleared
whenever a full collection or collection of the highest generation (2)
is run. Not all items in some free lists may be freed due to the
particular implementation, in particular :class:`int` and :class:`float`.
.. function:: set_debug(flags) .. function:: set_debug(flags)
......
...@@ -58,22 +58,6 @@ always available. ...@@ -58,22 +58,6 @@ always available.
A string containing the copyright pertaining to the Python interpreter. A string containing the copyright pertaining to the Python interpreter.
.. function:: _compact_freelists()
Compact the free lists of integers and floats by deallocating unused blocks.
It can reduce the memory usage of the Python process several tenth of
thousands of integers or floats have been allocated at once.
The return value is a tuple of tuples each containing three elements,
amount of used objects, total block count before the blocks are deallocated
and amount of freed blocks. The first tuple refers to ints, the second to
floats.
This function should be used for specialized purposes only.
.. versionadded:: 2.6
.. function:: _clear_type_cache() .. function:: _clear_type_cache()
Clear the internal type cache. The type cache is used to speed up attribute Clear the internal type cache. The type cache is used to speed up attribute
......
...@@ -113,7 +113,7 @@ PyAPI_FUNC(double) _PyFloat_Unpack4(const unsigned char *p, int le); ...@@ -113,7 +113,7 @@ PyAPI_FUNC(double) _PyFloat_Unpack4(const unsigned char *p, int le);
PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le); PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le);
/* free list api */ /* free list api */
PyAPI_FUNC(void) PyFloat_CompactFreeList(size_t *, size_t *, size_t *); PyAPI_FUNC(int) PyFloat_ClearFreeList(void);
/* Format the object based on the format_spec, as defined in PEP 3101 /* Format the object based on the format_spec, as defined in PEP 3101
(Advanced String Formatting). */ (Advanced String Formatting). */
......
...@@ -60,7 +60,7 @@ PyAPI_FUNC(unsigned long) PyOS_strtoul(char *, char **, int); ...@@ -60,7 +60,7 @@ PyAPI_FUNC(unsigned long) PyOS_strtoul(char *, char **, int);
PyAPI_FUNC(long) PyOS_strtol(char *, char **, int); PyAPI_FUNC(long) PyOS_strtol(char *, char **, int);
/* free list api */ /* 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. /* 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'. If base is 2, 8 or 16, add the proper prefix '0b', '0o' or '0x'.
......
...@@ -29,6 +29,10 @@ Core and Builtins ...@@ -29,6 +29,10 @@ Core and Builtins
would not cause a syntax error. This was regression from 2.4 caused by the would not cause a syntax error. This was regression from 2.4 caused by the
switch to the new compiler. switch to the new compiler.
- Issue #2862: Make int and float freelist management consistent with other
freelists. Changes their CompactFreeList apis into ClearFreeList apis and
calls them via gc.collect().
Library Library
------- -------
......
...@@ -736,6 +736,8 @@ clear_freelists(void) ...@@ -736,6 +736,8 @@ clear_freelists(void)
(void)PyCFunction_ClearFreeList(); (void)PyCFunction_ClearFreeList();
(void)PyTuple_ClearFreeList(); (void)PyTuple_ClearFreeList();
(void)PyUnicode_ClearFreeList(); (void)PyUnicode_ClearFreeList();
(void)PyInt_ClearFreeList();
(void)PyFloat_ClearFreeList();
} }
/* This is the main function. Read this to understand how the /* This is the main function. Read this to understand how the
......
...@@ -1608,30 +1608,28 @@ _PyFloat_Init(void) ...@@ -1608,30 +1608,28 @@ _PyFloat_Init(void)
PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc); PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc);
} }
void int
PyFloat_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum) PyFloat_ClearFreeList(void)
{ {
PyFloatObject *p; PyFloatObject *p;
PyFloatBlock *list, *next; PyFloatBlock *list, *next;
unsigned i; int i;
size_t bc = 0, bf = 0; /* block count, number of freed blocks */ int u; /* remaining unfreed ints per block */
size_t fsum = 0; /* total unfreed ints */ int freelist_size = 0;
int frem; /* remaining unfreed ints per block */
list = block_list; list = block_list;
block_list = NULL; block_list = NULL;
free_list = NULL; free_list = NULL;
while (list != NULL) { while (list != NULL) {
bc++; u = 0;
frem = 0;
for (i = 0, p = &list->objects[0]; for (i = 0, p = &list->objects[0];
i < N_FLOATOBJECTS; i < N_FLOATOBJECTS;
i++, p++) { i++, p++) {
if (PyFloat_CheckExact(p) && Py_REFCNT(p) != 0) if (PyFloat_CheckExact(p) && Py_REFCNT(p) != 0)
frem++; u++;
} }
next = list->next; next = list->next;
if (frem) { if (u) {
list->next = block_list; list->next = block_list;
block_list = list; block_list = list;
for (i = 0, p = &list->objects[0]; for (i = 0, p = &list->objects[0];
...@@ -1646,15 +1644,12 @@ PyFloat_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum) ...@@ -1646,15 +1644,12 @@ PyFloat_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum)
} }
} }
else { else {
PyMem_FREE(list); /* XXX PyObject_FREE ??? */ PyMem_FREE(list);
bf++;
} }
fsum += frem; freelist_size += u;
list = next; list = next;
} }
*pbc = bc; return freelist_size;
*pbf = bf;
*bsum = fsum;
} }
void void
...@@ -1662,25 +1657,21 @@ PyFloat_Fini(void) ...@@ -1662,25 +1657,21 @@ PyFloat_Fini(void)
{ {
PyFloatObject *p; PyFloatObject *p;
PyFloatBlock *list; PyFloatBlock *list;
unsigned i; int i;
size_t bc, bf; /* block count, number of freed blocks */ int u; /* total unfreed floats per block */
size_t fsum; /* total unfreed floats per block */
PyFloat_CompactFreeList(&bc, &bf, &fsum); u = PyFloat_ClearFreeList();
if (!Py_VerboseFlag) if (!Py_VerboseFlag)
return; return;
fprintf(stderr, "# cleanup floats"); fprintf(stderr, "# cleanup floats");
if (!fsum) { if (!u) {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
else { else {
fprintf(stderr, fprintf(stderr,
": %" PY_FORMAT_SIZE_T "d unfreed float%s in %" ": %d unfreed float%s\n",
PY_FORMAT_SIZE_T "d out of %" u, u == 1 ? "" : "s");
PY_FORMAT_SIZE_T "d block%s\n",
fsum, fsum == 1 ? "" : "s",
bc - bf, bc, bc == 1 ? "" : "s");
} }
if (Py_VerboseFlag > 1) { if (Py_VerboseFlag > 1) {
list = block_list; list = block_list;
......
...@@ -1296,35 +1296,33 @@ _PyInt_Init(void) ...@@ -1296,35 +1296,33 @@ _PyInt_Init(void)
return 1; return 1;
} }
void int
PyInt_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum) PyInt_ClearFreeList(void)
{ {
PyIntObject *p; PyIntObject *p;
PyIntBlock *list, *next; PyIntBlock *list, *next;
unsigned int ctr; int i;
size_t bc = 0, bf = 0; /* block count, number of freed blocks */ int u; /* remaining unfreed ints per block */
size_t isum = 0; /* total unfreed ints */ int freelist_size = 0;
int irem; /* remaining unfreed ints per block */
list = block_list; list = block_list;
block_list = NULL; block_list = NULL;
free_list = NULL; free_list = NULL;
while (list != NULL) { while (list != NULL) {
bc++; u = 0;
irem = 0; for (i = 0, p = &list->objects[0];
for (ctr = 0, p = &list->objects[0]; i < N_INTOBJECTS;
ctr < N_INTOBJECTS; i++, p++) {
ctr++, p++) {
if (PyInt_CheckExact(p) && p->ob_refcnt != 0) if (PyInt_CheckExact(p) && p->ob_refcnt != 0)
irem++; u++;
} }
next = list->next; next = list->next;
if (irem) { if (u) {
list->next = block_list; list->next = block_list;
block_list = list; block_list = list;
for (ctr = 0, p = &list->objects[0]; for (i = 0, p = &list->objects[0];
ctr < N_INTOBJECTS; i < N_INTOBJECTS;
ctr++, p++) { i++, p++) {
if (!PyInt_CheckExact(p) || if (!PyInt_CheckExact(p) ||
p->ob_refcnt == 0) { p->ob_refcnt == 0) {
Py_TYPE(p) = (struct _typeobject *) Py_TYPE(p) = (struct _typeobject *)
...@@ -1345,15 +1343,12 @@ PyInt_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum) ...@@ -1345,15 +1343,12 @@ PyInt_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum)
} }
else { else {
PyMem_FREE(list); PyMem_FREE(list);
bf++;
} }
isum += irem; freelist_size += u;
list = next; list = next;
} }
*pbc = bc; return freelist_size;
*pbf = bf;
*bsum = isum;
} }
void void
...@@ -1361,12 +1356,10 @@ PyInt_Fini(void) ...@@ -1361,12 +1356,10 @@ PyInt_Fini(void)
{ {
PyIntObject *p; PyIntObject *p;
PyIntBlock *list; PyIntBlock *list;
unsigned int ctr; int i;
size_t bc, bf; /* block count, number of freed blocks */ int u; /* total unfreed ints per block */
size_t isum; /* total unfreed ints per block */
#if NSMALLNEGINTS + NSMALLPOSINTS > 0 #if NSMALLNEGINTS + NSMALLPOSINTS > 0
int i;
PyIntObject **q; PyIntObject **q;
i = NSMALLNEGINTS + NSMALLPOSINTS; i = NSMALLNEGINTS + NSMALLPOSINTS;
...@@ -1376,27 +1369,24 @@ PyInt_Fini(void) ...@@ -1376,27 +1369,24 @@ PyInt_Fini(void)
*q++ = NULL; *q++ = NULL;
} }
#endif #endif
PyInt_CompactFreeList(&bc, &bf, &isum); u = PyInt_ClearFreeList();
if (!Py_VerboseFlag) if (!Py_VerboseFlag)
return; return;
fprintf(stderr, "# cleanup ints"); fprintf(stderr, "# cleanup ints");
if (!isum) { if (!u) {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
else { else {
fprintf(stderr, fprintf(stderr,
": %" PY_FORMAT_SIZE_T "d unfreed int%s in %" ": %d unfreed int%s\n",
PY_FORMAT_SIZE_T "d out of %" u, u == 1 ? "" : "s");
PY_FORMAT_SIZE_T "d block%s\n",
isum, isum == 1 ? "" : "s",
bc - bf, bc, bc == 1 ? "" : "s");
} }
if (Py_VerboseFlag > 1) { if (Py_VerboseFlag > 1) {
list = block_list; list = block_list;
while (list != NULL) { while (list != NULL) {
for (ctr = 0, p = &list->objects[0]; for (i = 0, p = &list->objects[0];
ctr < N_INTOBJECTS; i < N_INTOBJECTS;
ctr++, p++) { i++, p++) {
if (PyInt_CheckExact(p) && p->ob_refcnt != 0) if (PyInt_CheckExact(p) && p->ob_refcnt != 0)
/* XXX(twouters) cast refcount to /* XXX(twouters) cast refcount to
long until %zd is universally long until %zd is universally
......
...@@ -829,32 +829,12 @@ PyDoc_STRVAR(sys_clear_type_cache__doc__, ...@@ -829,32 +829,12 @@ PyDoc_STRVAR(sys_clear_type_cache__doc__,
Clear the internal type lookup cache."); Clear the internal type lookup cache.");
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);
}
PyDoc_STRVAR(sys_compact_freelists__doc__,
"_compact_freelists() -> ((remaing_objects, total_blocks, freed_blocks), ...)\n\
Compact the free lists of ints and floats.");
static PyMethodDef sys_methods[] = { static PyMethodDef sys_methods[] = {
/* Might as well keep this in alphabetic order */ /* Might as well keep this in alphabetic order */
{"callstats", (PyCFunction)PyEval_GetCallStats, METH_NOARGS, {"callstats", (PyCFunction)PyEval_GetCallStats, METH_NOARGS,
callstats_doc}, callstats_doc},
{"_clear_type_cache", sys_clear_type_cache, METH_NOARGS, {"_clear_type_cache", sys_clear_type_cache, METH_NOARGS,
sys_clear_type_cache__doc__}, sys_clear_type_cache__doc__},
{"_compact_freelists", sys_compact_freelists, METH_NOARGS,
sys_compact_freelists__doc__},
{"_current_frames", sys_current_frames, METH_NOARGS, {"_current_frames", sys_current_frames, METH_NOARGS,
current_frames_doc}, current_frames_doc},
{"displayhook", sys_displayhook, METH_O, displayhook_doc}, {"displayhook", sys_displayhook, METH_O, displayhook_doc},
......
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