mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	- 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().
This commit is contained in:
		
							parent
							
								
									17f2e4acb9
								
							
						
					
					
						commit
						2fe77060eb
					
				
					 11 changed files with 62 additions and 107 deletions
				
			
		|  | @ -86,10 +86,9 @@ Floating Point Objects | |||
|    .. 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 | ||||
|    blocks are freed, *bf* is the number of freed blocks and *sum* is the number | ||||
|    of remaining objects in the blocks. | ||||
|    Clear the float free list. Return the number of items that could not | ||||
|    be freed. | ||||
| 
 | ||||
|    .. versionadded:: 2.6 | ||||
|  |  | |||
|  | @ -122,10 +122,9 @@ Plain Integer Objects | |||
|    (: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 | ||||
|    blocks are freed, *bf* is the number of freed blocks and *sum* is the number | ||||
|    of remaining objects in the blocks. | ||||
|    Clear the integer free list. Return the number of items that could not | ||||
|    be freed. | ||||
| 
 | ||||
|    .. versionadded:: 2.6 | ||||
|  |  | |||
|  | @ -47,6 +47,12 @@ The :mod:`gc` module provides the following functions: | |||
|    .. versionchanged:: 2.5 | ||||
|       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) | ||||
| 
 | ||||
|  |  | |||
|  | @ -58,22 +58,6 @@ always available. | |||
|    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() | ||||
| 
 | ||||
|    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); | |||
| 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); | ||||
| 
 | ||||
| /* Format the object based on the format_spec, as defined in PEP 3101
 | ||||
|    (Advanced String Formatting). */ | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ PyAPI_FUNC(unsigned long) PyOS_strtoul(char *, char **, int); | |||
| 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'. | ||||
|  |  | |||
|  | @ -29,6 +29,10 @@ Core and Builtins | |||
|   would not cause a syntax error.  This was regression from 2.4 caused by the | ||||
|   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 | ||||
| ------- | ||||
| 
 | ||||
|  |  | |||
|  | @ -736,6 +736,8 @@ clear_freelists(void) | |||
| 	(void)PyCFunction_ClearFreeList(); | ||||
| 	(void)PyTuple_ClearFreeList(); | ||||
| 	(void)PyUnicode_ClearFreeList(); | ||||
| 	(void)PyInt_ClearFreeList(); | ||||
| 	(void)PyFloat_ClearFreeList(); | ||||
| } | ||||
| 
 | ||||
| /* This is the main function.  Read this to understand how the
 | ||||
|  |  | |||
|  | @ -1608,30 +1608,28 @@ _PyFloat_Init(void) | |||
| 		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 */ | ||||
| 	int i; | ||||
| 	int u;			/* remaining unfreed ints per block */ | ||||
| 	int freelist_size = 0; | ||||
| 
 | ||||
| 	list = block_list; | ||||
| 	block_list = NULL; | ||||
| 	free_list = NULL; | ||||
| 	while (list != NULL) { | ||||
| 		bc++; | ||||
| 		frem = 0; | ||||
| 		u = 0; | ||||
| 		for (i = 0, p = &list->objects[0]; | ||||
| 		     i < N_FLOATOBJECTS; | ||||
| 		     i++, p++) { | ||||
| 			if (PyFloat_CheckExact(p) && Py_REFCNT(p) != 0) | ||||
| 				frem++; | ||||
| 				u++; | ||||
| 		} | ||||
| 		next = list->next; | ||||
| 		if (frem) { | ||||
| 		if (u) { | ||||
| 			list->next = block_list; | ||||
| 			block_list = list; | ||||
| 			for (i = 0, p = &list->objects[0]; | ||||
|  | @ -1646,15 +1644,12 @@ PyFloat_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum) | |||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			PyMem_FREE(list); /* XXX PyObject_FREE ??? */ | ||||
| 			bf++; | ||||
| 			PyMem_FREE(list); | ||||
| 		} | ||||
| 		fsum += frem; | ||||
| 		freelist_size += u; | ||||
| 		list = next; | ||||
| 	} | ||||
| 	*pbc = bc; | ||||
| 	*pbf = bf; | ||||
| 	*bsum = fsum; | ||||
| 	return freelist_size; | ||||
| } | ||||
| 
 | ||||
| void | ||||
|  | @ -1662,25 +1657,21 @@ 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 */ | ||||
| 	int i; | ||||
| 	int u;			/* total unfreed floats per block */ | ||||
| 
 | ||||
| 	PyFloat_CompactFreeList(&bc, &bf, &fsum); | ||||
| 	u = PyFloat_ClearFreeList(); | ||||
| 
 | ||||
| 	if (!Py_VerboseFlag) | ||||
| 		return; | ||||
| 	fprintf(stderr, "# cleanup floats"); | ||||
| 	if (!fsum) { | ||||
| 	if (!u) { | ||||
| 		fprintf(stderr, "\n"); | ||||
| 	} | ||||
| 	else { | ||||
| 		fprintf(stderr, | ||||
| 			": %" PY_FORMAT_SIZE_T "d unfreed float%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"); | ||||
| 			": %d unfreed float%s\n", | ||||
| 			u, u == 1 ? "" : "s"); | ||||
| 	} | ||||
| 	if (Py_VerboseFlag > 1) { | ||||
| 		list = block_list; | ||||
|  |  | |||
|  | @ -1296,35 +1296,33 @@ _PyInt_Init(void) | |||
| 	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 */ | ||||
| 	int i; | ||||
| 	int u;			/* remaining unfreed ints per block */ | ||||
| 	int freelist_size = 0; | ||||
| 
 | ||||
| 	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++) { | ||||
| 		u = 0; | ||||
| 		for (i = 0, p = &list->objects[0]; | ||||
| 		     i < N_INTOBJECTS; | ||||
| 		     i++, p++) { | ||||
| 			if (PyInt_CheckExact(p) && p->ob_refcnt != 0) | ||||
| 				irem++; | ||||
| 				u++; | ||||
| 		} | ||||
| 		next = list->next; | ||||
| 		if (irem) { | ||||
| 		if (u) { | ||||
| 			list->next = block_list; | ||||
| 			block_list = list; | ||||
| 			for (ctr = 0, p = &list->objects[0]; | ||||
| 			     ctr < N_INTOBJECTS; | ||||
| 			     ctr++, p++) { | ||||
| 			for (i = 0, p = &list->objects[0]; | ||||
| 			     i < N_INTOBJECTS; | ||||
| 			     i++, p++) { | ||||
| 				if (!PyInt_CheckExact(p) || | ||||
| 				    p->ob_refcnt == 0) { | ||||
| 					Py_TYPE(p) = (struct _typeobject *) | ||||
|  | @ -1345,15 +1343,12 @@ PyInt_CompactFreeList(size_t *pbc, size_t *pbf, size_t *bsum) | |||
| 		} | ||||
| 		else { | ||||
| 			PyMem_FREE(list); | ||||
| 			bf++; | ||||
| 		} | ||||
| 		isum += irem; | ||||
| 		freelist_size += u; | ||||
| 		list = next; | ||||
| 	} | ||||
| 
 | ||||
| 	*pbc = bc; | ||||
| 	*pbf = bf; | ||||
| 	*bsum = isum; | ||||
| 	return freelist_size; | ||||
| } | ||||
| 
 | ||||
| void | ||||
|  | @ -1361,12 +1356,10 @@ 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 */ | ||||
| 	int i; | ||||
| 	int u;			/* total unfreed ints per block */ | ||||
| 
 | ||||
| #if NSMALLNEGINTS + NSMALLPOSINTS > 0 | ||||
| 	int i; | ||||
| 	PyIntObject **q; | ||||
| 
 | ||||
| 	i = NSMALLNEGINTS + NSMALLPOSINTS; | ||||
|  | @ -1376,27 +1369,24 @@ PyInt_Fini(void) | |||
| 		*q++ = NULL; | ||||
| 	} | ||||
| #endif | ||||
| 	PyInt_CompactFreeList(&bc, &bf, &isum); | ||||
| 	u = PyInt_ClearFreeList(); | ||||
| 	if (!Py_VerboseFlag) | ||||
| 		return; | ||||
| 	fprintf(stderr, "# cleanup ints"); | ||||
| 	if (!isum) { | ||||
| 	if (!u) { | ||||
| 		fprintf(stderr, "\n"); | ||||
| 	} | ||||
| 	else { | ||||
| 		fprintf(stderr, | ||||
| 			": %" PY_FORMAT_SIZE_T "d unfreed int%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"); | ||||
| 			": %d unfreed int%s\n", | ||||
| 			u, u == 1 ? "" : "s"); | ||||
| 	} | ||||
| 	if (Py_VerboseFlag > 1) { | ||||
| 		list = block_list; | ||||
| 		while (list != NULL) { | ||||
| 			for (ctr = 0, p = &list->objects[0]; | ||||
| 			     ctr < N_INTOBJECTS; | ||||
| 			     ctr++, p++) { | ||||
| 			for (i = 0, p = &list->objects[0]; | ||||
| 			     i < N_INTOBJECTS; | ||||
| 			     i++, p++) { | ||||
| 				if (PyInt_CheckExact(p) && p->ob_refcnt != 0) | ||||
| 					/* XXX(twouters) cast refcount to
 | ||||
| 					   long until %zd is universally | ||||
|  |  | |||
|  | @ -829,32 +829,12 @@ PyDoc_STRVAR(sys_clear_type_cache__doc__, | |||
| 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[] = { | ||||
| 	/* Might as well keep this in alphabetic order */ | ||||
| 	{"callstats", (PyCFunction)PyEval_GetCallStats, METH_NOARGS, | ||||
| 	 callstats_doc}, | ||||
| 	{"_clear_type_cache",	sys_clear_type_cache,	  METH_NOARGS, | ||||
| 	 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_doc}, | ||||
| 	{"displayhook",	sys_displayhook, METH_O, displayhook_doc}, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Gregory P. Smith
						Gregory P. Smith