summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-06-04 22:50:05 (GMT)
committerGitHub <noreply@github.com>2020-06-04 22:50:05 (GMT)
commit2ba59370c3dda2ac229c14510e53a05074b133d1 (patch)
tree88cd810f62d0c5ae34a83a10e05268e33ea0da57
parent69ac6e58fd98de339c013fe64cd1cf763e4f9bca (diff)
downloadcpython-2ba59370c3dda2ac229c14510e53a05074b133d1.zip
cpython-2ba59370c3dda2ac229c14510e53a05074b133d1.tar.gz
cpython-2ba59370c3dda2ac229c14510e53a05074b133d1.tar.bz2
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().
-rw-r--r--Include/internal/pycore_gc.h2
-rw-r--r--Include/internal/pycore_interp.h9
-rw-r--r--Include/internal/pycore_pylifecycle.h2
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst3
-rw-r--r--Modules/gcmodule.c2
-rw-r--r--Objects/floatobject.c55
-rw-r--r--Python/pylifecycle.c2
7 files changed, 44 insertions, 31 deletions
diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h
index e8e5d32..f90d80b 100644
--- a/Include/internal/pycore_gc.h
+++ b/Include/internal/pycore_gc.h
@@ -167,7 +167,7 @@ PyAPI_FUNC(void) _PyGC_InitState(struct _gc_runtime_state *);
// Functions to clear types free lists
extern void _PyFrame_ClearFreeList(void);
extern void _PyTuple_ClearFreeList(PyThreadState *tstate);
-extern void _PyFloat_ClearFreeList(void);
+extern void _PyFloat_ClearFreeList(PyThreadState *tstate);
extern void _PyList_ClearFreeList(void);
extern void _PyDict_ClearFreeList(void);
extern void _PyAsyncGen_ClearFreeLists(void);
diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h
index b90bfbe..c0eed00 100644
--- a/Include/internal/pycore_interp.h
+++ b/Include/internal/pycore_interp.h
@@ -84,6 +84,14 @@ struct _Py_tuple_state {
#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 */
@@ -178,6 +186,7 @@ struct _is {
PyLongObject* small_ints[_PY_NSMALLNEGINTS + _PY_NSMALLPOSINTS];
#endif
struct _Py_tuple_state tuple;
+ struct _Py_float_state float_state;
};
/* Used by _PyImport_Cleanup() */
diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h
index 3f2ff5b..2643abc 100644
--- a/Include/internal/pycore_pylifecycle.h
+++ b/Include/internal/pycore_pylifecycle.h
@@ -64,7 +64,7 @@ extern void _PyTuple_Fini(PyThreadState *tstate);
extern void _PyList_Fini(void);
extern void _PySet_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 _PyAsyncGen_Fini(void);
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst
index f364d36..016f116 100644
--- a/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst
+++ b/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst
@@ -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.
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 1f5aa93..0bad0f8 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -1028,7 +1028,7 @@ clear_freelists(void)
PyThreadState *tstate = _PyThreadState_GET();
_PyFrame_ClearFreeList();
_PyTuple_ClearFreeList(tstate);
- _PyFloat_ClearFreeList();
+ _PyFloat_ClearFreeList(tstate);
_PyList_ClearFreeList();
_PyDict_ClearFreeList();
_PyAsyncGen_ClearFreeLists();
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index 868b729..d72fd21 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -5,6 +5,8 @@
#include "Python.h"
#include "pycore_dtoa.h"
+#include "pycore_interp.h" // _PyInterpreterState.float_state
+#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include <ctype.h>
#include <float.h>
@@ -16,16 +18,9 @@ class float "PyObject *" "&PyFloat_Type"
#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
-#define PyFloat_MAXFREELIST 100
+# define PyFloat_MAXFREELIST 100
#endif
-static int numfree = 0;
-static PyFloatObject *free_list = NULL;
double
PyFloat_GetMax(void)
@@ -117,16 +112,19 @@ PyFloat_GetInfo(void)
PyObject *
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) {
- free_list = (PyFloatObject *) Py_TYPE(op);
- numfree--;
- } else {
- op = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject));
- if (!op)
+ state->free_list = (PyFloatObject *) Py_TYPE(op);
+ state->numfree--;
+ }
+ else {
+ op = PyObject_Malloc(sizeof(PyFloatObject));
+ if (!op) {
return PyErr_NoMemory();
+ }
}
- /* Inline PyObject_New */
(void)PyObject_INIT(op, &PyFloat_Type);
op->ob_fval = fval;
return (PyObject *) op;
@@ -219,13 +217,15 @@ static void
float_dealloc(PyFloatObject *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);
return;
}
- numfree++;
- Py_SET_TYPE(op, (PyTypeObject *)free_list);
- free_list = op;
+ state->numfree++;
+ Py_SET_TYPE(op, (PyTypeObject *)state->free_list);
+ state->free_list = op;
}
else
Py_TYPE(op)->tp_free((PyObject *)op);
@@ -1981,30 +1981,33 @@ _PyFloat_Init(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) {
next = (PyFloatObject*) Py_TYPE(f);
PyObject_FREE(f);
}
- free_list = NULL;
- numfree = 0;
+ state->free_list = NULL;
+ state->numfree = 0;
}
void
-_PyFloat_Fini(void)
+_PyFloat_Fini(PyThreadState *tstate)
{
- _PyFloat_ClearFreeList();
+ _PyFloat_ClearFreeList(tstate);
}
/* Print summary info about the state of the optimized allocator */
void
_PyFloat_DebugMallocStats(FILE *out)
{
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ struct _Py_float_state *state = &interp->float_state;
_PyDebugAllocatorStats(out,
"free PyFloatObject",
- numfree, sizeof(PyFloatObject));
+ state->numfree, sizeof(PyFloatObject));
}
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 9da3fb0..716303c 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -1261,9 +1261,9 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp)
}
_PyLong_Fini(tstate);
+ _PyFloat_Fini(tstate);
if (is_main_interp) {
- _PyFloat_Fini();
_PyDict_Fini();
_PySlice_Fini();
}