diff options
author | Donghee Na <donghee.na@python.org> | 2024-01-10 15:47:13 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-10 15:47:13 (GMT) |
commit | f728f7242c6008a16daaa5dde8e1db786857c50e (patch) | |
tree | 5e6dd8e921e432c9de0b0d8f60805ec03a8584eb | |
parent | a0c9cf9456c2ee7a89d9bd859c07afac8cf5e893 (diff) | |
download | cpython-f728f7242c6008a16daaa5dde8e1db786857c50e.zip cpython-f728f7242c6008a16daaa5dde8e1db786857c50e.tar.gz cpython-f728f7242c6008a16daaa5dde8e1db786857c50e.tar.bz2 |
gh-111968: Use per-thread freelists for float in free-threading (gh-113886)
-rw-r--r-- | Include/internal/pycore_floatobject.h | 21 | ||||
-rw-r--r-- | Include/internal/pycore_freelist.h | 26 | ||||
-rw-r--r-- | Include/internal/pycore_gc.h | 2 | ||||
-rw-r--r-- | Include/internal/pycore_interp.h | 1 | ||||
-rw-r--r-- | Objects/floatobject.c | 47 | ||||
-rw-r--r-- | Python/gc_free_threading.c | 1 | ||||
-rw-r--r-- | Python/gc_gil.c | 1 | ||||
-rw-r--r-- | Python/pylifecycle.c | 2 | ||||
-rw-r--r-- | Python/pystate.c | 1 |
9 files changed, 43 insertions, 59 deletions
diff --git a/Include/internal/pycore_floatobject.h b/Include/internal/pycore_floatobject.h index 4e54748..038578e 100644 --- a/Include/internal/pycore_floatobject.h +++ b/Include/internal/pycore_floatobject.h @@ -8,14 +8,14 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif - +#include "pycore_freelist.h" // _PyFreeListState #include "pycore_unicodeobject.h" // _PyUnicodeWriter /* runtime lifecycle */ extern void _PyFloat_InitState(PyInterpreterState *); extern PyStatus _PyFloat_InitTypes(PyInterpreterState *); -extern void _PyFloat_Fini(PyInterpreterState *); +extern void _PyFloat_Fini(_PyFreeListState *); extern void _PyFloat_FiniType(PyInterpreterState *); @@ -33,24 +33,7 @@ struct _Py_float_runtime_state { }; -#ifndef WITH_FREELISTS -// without freelists -# define PyFloat_MAXFREELIST 0 -#endif - -#ifndef PyFloat_MAXFREELIST -# define PyFloat_MAXFREELIST 100 -#endif -struct _Py_float_state { -#if PyFloat_MAXFREELIST > 0 - /* 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; -#endif -}; void _PyFloat_ExactDealloc(PyObject *op); diff --git a/Include/internal/pycore_freelist.h b/Include/internal/pycore_freelist.h index b725986..d961921 100644 --- a/Include/internal/pycore_freelist.h +++ b/Include/internal/pycore_freelist.h @@ -8,24 +8,34 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#ifndef WITH_FREELISTS -// without freelists -# define PyList_MAXFREELIST 0 -#endif - -/* Empty list reuse scheme to save calls to malloc and free */ -#ifndef PyList_MAXFREELIST +#ifdef WITH_FREELISTS +// with freelists # define PyList_MAXFREELIST 80 +# define PyFloat_MAXFREELIST 100 +#else +# define PyList_MAXFREELIST 0 +# define PyFloat_MAXFREELIST 0 #endif struct _Py_list_state { -#if PyList_MAXFREELIST > 0 +#ifdef WITH_FREELISTS PyListObject *free_list[PyList_MAXFREELIST]; int numfree; #endif }; +struct _Py_float_state { +#ifdef WITH_FREELISTS + /* 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; +#endif +}; + typedef struct _Py_freelist_state { + struct _Py_float_state float_state; struct _Py_list_state list; } _PyFreeListState; diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 5d90d3a..2a0730e 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -243,7 +243,7 @@ extern PyObject *_PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs); extern void _PyGC_ClearAllFreeLists(PyInterpreterState *interp); extern void _Py_ClearFreeLists(_PyFreeListState *state, int is_finalization); extern void _PyTuple_ClearFreeList(PyInterpreterState *interp); -extern void _PyFloat_ClearFreeList(PyInterpreterState *interp); +extern void _PyFloat_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyDict_ClearFreeList(PyInterpreterState *interp); extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp); diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 4d49fa2..dadc8e3 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -184,7 +184,6 @@ struct _is { #endif struct _py_object_state object_state; struct _Py_unicode_state unicode; - struct _Py_float_state float_state; struct _Py_long_state long_state; struct _dtoa_state dtoa; struct _py_func_state func_state; diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 364cf15..f1a09c0 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -26,17 +26,13 @@ class float "PyObject *" "&PyFloat_Type" #include "clinic/floatobject.c.h" -#ifndef PyFloat_MAXFREELIST -# define PyFloat_MAXFREELIST 100 -#endif - - -#if PyFloat_MAXFREELIST > 0 +#ifdef WITH_FREELISTS static struct _Py_float_state * get_float_state(void) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - return &interp->float_state; + _PyFreeListState *state = _PyFreeListState_GET(); + assert(state != NULL); + return &state->float_state; } #endif @@ -132,7 +128,7 @@ PyObject * PyFloat_FromDouble(double fval) { PyFloatObject *op; -#if PyFloat_MAXFREELIST > 0 +#ifdef WITH_FREELISTS struct _Py_float_state *state = get_float_state(); op = state->free_list; if (op != NULL) { @@ -252,13 +248,9 @@ _PyFloat_ExactDealloc(PyObject *obj) { assert(PyFloat_CheckExact(obj)); PyFloatObject *op = (PyFloatObject *)obj; -#if PyFloat_MAXFREELIST > 0 +#ifdef WITH_FREELISTS struct _Py_float_state *state = get_float_state(); -#ifdef Py_DEBUG - // float_dealloc() must not be called after _PyFloat_Fini() - assert(state->numfree != -1); -#endif - if (state->numfree >= PyFloat_MAXFREELIST) { + if (state->numfree >= PyFloat_MAXFREELIST || state->numfree < 0) { PyObject_Free(op); return; } @@ -275,7 +267,7 @@ static void float_dealloc(PyObject *op) { assert(PyFloat_Check(op)); -#if PyFloat_MAXFREELIST > 0 +#ifdef WITH_FREELISTS if (PyFloat_CheckExact(op)) { _PyFloat_ExactDealloc(op); } @@ -2002,10 +1994,10 @@ _PyFloat_InitTypes(PyInterpreterState *interp) } void -_PyFloat_ClearFreeList(PyInterpreterState *interp) +_PyFloat_ClearFreeList(_PyFreeListState *freelist_state, int is_finalization) { -#if PyFloat_MAXFREELIST > 0 - struct _Py_float_state *state = &interp->float_state; +#ifdef WITH_FREELISTS + struct _Py_float_state *state = &freelist_state->float_state; PyFloatObject *f = state->free_list; while (f != NULL) { PyFloatObject *next = (PyFloatObject*) Py_TYPE(f); @@ -2013,18 +2005,19 @@ _PyFloat_ClearFreeList(PyInterpreterState *interp) f = next; } state->free_list = NULL; - state->numfree = 0; + if (is_finalization) { + state->numfree = -1; + } + else { + state->numfree = 0; + } #endif } void -_PyFloat_Fini(PyInterpreterState *interp) +_PyFloat_Fini(_PyFreeListState *state) { - _PyFloat_ClearFreeList(interp); -#if defined(Py_DEBUG) && PyFloat_MAXFREELIST > 0 - struct _Py_float_state *state = &interp->float_state; - state->numfree = -1; -#endif + _PyFloat_ClearFreeList(state, 1); } void @@ -2037,7 +2030,7 @@ _PyFloat_FiniType(PyInterpreterState *interp) void _PyFloat_DebugMallocStats(FILE *out) { -#if PyFloat_MAXFREELIST > 0 +#ifdef WITH_FREELISTS struct _Py_float_state *state = get_float_state(); _PyDebugAllocatorStats(out, "free PyFloatObject", diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index aea2728..c19893a 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -15,7 +15,6 @@ void _PyGC_ClearAllFreeLists(PyInterpreterState *interp) { _PyTuple_ClearFreeList(interp); - _PyFloat_ClearFreeList(interp); _PyDict_ClearFreeList(interp); _PyAsyncGen_ClearFreeLists(interp); _PyContext_ClearFreeList(interp); diff --git a/Python/gc_gil.c b/Python/gc_gil.c index b0961cd..c8ca397 100644 --- a/Python/gc_gil.c +++ b/Python/gc_gil.c @@ -12,7 +12,6 @@ void _PyGC_ClearAllFreeLists(PyInterpreterState *interp) { _PyTuple_ClearFreeList(interp); - _PyFloat_ClearFreeList(interp); _PyDict_ClearFreeList(interp); _PyAsyncGen_ClearFreeLists(interp); _PyContext_ClearFreeList(interp); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index bd6475f..6468e72 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1757,10 +1757,10 @@ finalize_interp_types(PyInterpreterState *interp) _PySlice_Fini(interp); _PyUnicode_Fini(interp); - _PyFloat_Fini(interp); _PyFreeListState *state = _PyFreeListState_GET(); _PyList_Fini(state); + _PyFloat_Fini(state); #ifdef Py_DEBUG _PyStaticObjects_CheckRefcnt(interp); diff --git a/Python/pystate.c b/Python/pystate.c index ddd57f7..683e292 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1458,6 +1458,7 @@ clear_datastack(PyThreadState *tstate) void _Py_ClearFreeLists(_PyFreeListState *state, int is_finalization) { + _PyFloat_ClearFreeList(state, is_finalization); _PyList_ClearFreeList(state, is_finalization); } |