bpo-40521: Make float free list per-interpreter (GH-20636)

Each interpreter now has its own float free list:

* Move tuple numfree and free_list into PyInterpreterState.
* Add _Py_float_state structure.
* Add tstate parameter to _PyFloat_ClearFreeList()
  and _PyFloat_Fini().
This commit is contained in:
Victor Stinner 2020-06-05 00:50:05 +02:00 committed by GitHub
parent 69ac6e58fd
commit 2ba59370c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 45 additions and 32 deletions

View File

@ -167,7 +167,7 @@ PyAPI_FUNC(void) _PyGC_InitState(struct _gc_runtime_state *);
// Functions to clear types free lists // Functions to clear types free lists
extern void _PyFrame_ClearFreeList(void); extern void _PyFrame_ClearFreeList(void);
extern void _PyTuple_ClearFreeList(PyThreadState *tstate); extern void _PyTuple_ClearFreeList(PyThreadState *tstate);
extern void _PyFloat_ClearFreeList(void); extern void _PyFloat_ClearFreeList(PyThreadState *tstate);
extern void _PyList_ClearFreeList(void); extern void _PyList_ClearFreeList(void);
extern void _PyDict_ClearFreeList(void); extern void _PyDict_ClearFreeList(void);
extern void _PyAsyncGen_ClearFreeLists(void); extern void _PyAsyncGen_ClearFreeLists(void);

View File

@ -84,6 +84,14 @@ struct _Py_tuple_state {
#endif #endif
}; };
struct _Py_float_state {
/* Special free list
free_list is a singly-linked list of available PyFloatObjects,
linked via abuse of their ob_type members. */
int numfree;
PyFloatObject *free_list;
};
/* interpreter state */ /* interpreter state */
@ -178,6 +186,7 @@ struct _is {
PyLongObject* small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS]; PyLongObject* small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS];
#endif #endif
struct _Py_tuple_state tuple; struct _Py_tuple_state tuple;
struct _Py_float_state float_state;
}; };
/* Used by _PyImport_Cleanup() */ /* Used by _PyImport_Cleanup() */

View File

@ -64,7 +64,7 @@ extern void _PyTuple_Fini(PyThreadState *tstate);
extern void _PyList_Fini(void); extern void _PyList_Fini(void);
extern void _PySet_Fini(void); extern void _PySet_Fini(void);
extern void _PyBytes_Fini(void); extern void _PyBytes_Fini(void);
extern void _PyFloat_Fini(void); extern void _PyFloat_Fini(PyThreadState *tstate);
extern void _PySlice_Fini(void); extern void _PySlice_Fini(void);
extern void _PyAsyncGen_Fini(void); extern void _PyAsyncGen_Fini(void);

View File

@ -1 +1,2 @@
Each interpreter now has its own tuple free lists and empty tuple singleton. Tuple free lists, empty tuple singleton, and float free list are no longer
shared by all interpreters: each interpreter now its own free lists.

View File

@ -1028,7 +1028,7 @@ clear_freelists(void)
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
_PyFrame_ClearFreeList(); _PyFrame_ClearFreeList();
_PyTuple_ClearFreeList(tstate); _PyTuple_ClearFreeList(tstate);
_PyFloat_ClearFreeList(); _PyFloat_ClearFreeList(tstate);
_PyList_ClearFreeList(); _PyList_ClearFreeList();
_PyDict_ClearFreeList(); _PyDict_ClearFreeList();
_PyAsyncGen_ClearFreeLists(); _PyAsyncGen_ClearFreeLists();

View File

@ -5,6 +5,8 @@
#include "Python.h" #include "Python.h"
#include "pycore_dtoa.h" #include "pycore_dtoa.h"
#include "pycore_interp.h" // _PyInterpreterState.float_state
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include <ctype.h> #include <ctype.h>
#include <float.h> #include <float.h>
@ -16,16 +18,9 @@ class float "PyObject *" "&PyFloat_Type"
#include "clinic/floatobject.c.h" #include "clinic/floatobject.c.h"
/* Special free list
free_list is a singly-linked list of available PyFloatObjects, linked
via abuse of their ob_type members.
*/
#ifndef PyFloat_MAXFREELIST #ifndef PyFloat_MAXFREELIST
# define PyFloat_MAXFREELIST 100 # define PyFloat_MAXFREELIST 100
#endif #endif
static int numfree = 0;
static PyFloatObject *free_list = NULL;
double double
PyFloat_GetMax(void) PyFloat_GetMax(void)
@ -117,16 +112,19 @@ PyFloat_GetInfo(void)
PyObject * PyObject *
PyFloat_FromDouble(double fval) PyFloat_FromDouble(double fval)
{ {
PyFloatObject *op = free_list; PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_float_state *state = &interp->float_state;
PyFloatObject *op = state->free_list;
if (op != NULL) { if (op != NULL) {
free_list = (PyFloatObject *) Py_TYPE(op); state->free_list = (PyFloatObject *) Py_TYPE(op);
numfree--; state->numfree--;
} else { }
op = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject)); else {
if (!op) op = PyObject_Malloc(sizeof(PyFloatObject));
if (!op) {
return PyErr_NoMemory(); return PyErr_NoMemory();
} }
/* Inline PyObject_New */ }
(void)PyObject_INIT(op, &PyFloat_Type); (void)PyObject_INIT(op, &PyFloat_Type);
op->ob_fval = fval; op->ob_fval = fval;
return (PyObject *) op; return (PyObject *) op;
@ -219,13 +217,15 @@ static void
float_dealloc(PyFloatObject *op) float_dealloc(PyFloatObject *op)
{ {
if (PyFloat_CheckExact(op)) { if (PyFloat_CheckExact(op)) {
if (numfree >= PyFloat_MAXFREELIST) { PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_float_state *state = &interp->float_state;
if (state->numfree >= PyFloat_MAXFREELIST) {
PyObject_FREE(op); PyObject_FREE(op);
return; return;
} }
numfree++; state->numfree++;
Py_SET_TYPE(op, (PyTypeObject *)free_list); Py_SET_TYPE(op, (PyTypeObject *)state->free_list);
free_list = op; state->free_list = op;
} }
else else
Py_TYPE(op)->tp_free((PyObject *)op); Py_TYPE(op)->tp_free((PyObject *)op);
@ -1981,30 +1981,33 @@ _PyFloat_Init(void)
} }
void void
_PyFloat_ClearFreeList(void) _PyFloat_ClearFreeList(PyThreadState *tstate)
{ {
PyFloatObject *f = free_list, *next; struct _Py_float_state *state = &tstate->interp->float_state;
PyFloatObject *f = state->free_list, *next;
for (; f; f = next) { for (; f; f = next) {
next = (PyFloatObject*) Py_TYPE(f); next = (PyFloatObject*) Py_TYPE(f);
PyObject_FREE(f); PyObject_FREE(f);
} }
free_list = NULL; state->free_list = NULL;
numfree = 0; state->numfree = 0;
} }
void void
_PyFloat_Fini(void) _PyFloat_Fini(PyThreadState *tstate)
{ {
_PyFloat_ClearFreeList(); _PyFloat_ClearFreeList(tstate);
} }
/* Print summary info about the state of the optimized allocator */ /* Print summary info about the state of the optimized allocator */
void void
_PyFloat_DebugMallocStats(FILE *out) _PyFloat_DebugMallocStats(FILE *out)
{ {
PyInterpreterState *interp = _PyInterpreterState_GET();
struct _Py_float_state *state = &interp->float_state;
_PyDebugAllocatorStats(out, _PyDebugAllocatorStats(out,
"free PyFloatObject", "free PyFloatObject",
numfree, sizeof(PyFloatObject)); state->numfree, sizeof(PyFloatObject));
} }

View File

@ -1261,9 +1261,9 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp)
} }
_PyLong_Fini(tstate); _PyLong_Fini(tstate);
_PyFloat_Fini(tstate);
if (is_main_interp) { if (is_main_interp) {
_PyFloat_Fini();
_PyDict_Fini(); _PyDict_Fini();
_PySlice_Fini(); _PySlice_Fini();
} }