Skip to content

bpo-40521: Make float free list per-interpreter #20636

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Include/internal/pycore_gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
9 changes: 9 additions & 0 deletions Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down Expand Up @@ -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() */
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 1 addition & 1 deletion Modules/gcmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
55 changes: 29 additions & 26 deletions Objects/floatobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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));
}


Expand Down
2 changes: 1 addition & 1 deletion Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down