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:
parent
69ac6e58fd
commit
2ba59370c3
|
@ -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);
|
||||||
|
|
|
@ -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() */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue