From cd4863c22f37ac8cab0ef39f6fd796c726c2c2a2 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 30 Dec 2023 22:30:55 +0900 Subject: [PATCH 01/53] gh-111968: Introduce _Py_freelist_state and _PyFreeListState_GET API --- Include/internal/pycore_gc.h | 2 +- Include/internal/pycore_interp.h | 4 +++- Include/internal/pycore_pystate.h | 14 ++++++++++++++ Include/internal/pycore_tstate.h | 5 +++++ Include/pytypedefs.h | 1 + Modules/gcmodule.c | 15 ++++++++++++++- Objects/listobject.c | 19 ++++++++++--------- 7 files changed, 48 insertions(+), 12 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 2d33aa76d78229..f099f02c15d4c9 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -209,7 +209,7 @@ extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate); // Functions to clear types free lists extern void _PyTuple_ClearFreeList(PyInterpreterState *interp); extern void _PyFloat_ClearFreeList(PyInterpreterState *interp); -extern void _PyList_ClearFreeList(PyInterpreterState *interp); +extern void _PyList_ClearFreeList(PyFreeListState *state); extern void _PyDict_ClearFreeList(PyInterpreterState *interp); extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp); extern void _PyContext_ClearFreeList(PyInterpreterState *interp); diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 04d7a6a615e370..ac05dd00d7f4af 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -174,6 +174,9 @@ struct _is { // One bit is set for each non-NULL entry in code_watchers uint8_t active_code_watchers; +#if !defined(Py_GIL_DISABLED) + struct _Py_freelist_state freelist_state; +#endif struct _py_object_state object_state; struct _Py_unicode_state unicode; struct _Py_float_state float_state; @@ -185,7 +188,6 @@ struct _is { PySliceObject *slice_cache; struct _Py_tuple_state tuple; - struct _Py_list_state list; struct _Py_dict_state dict_state; struct _Py_async_gen_state async_gen; struct _Py_context_state context; diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 37b45faf8a74a0..05a0d80a9f74cc 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -9,6 +9,7 @@ extern "C" { #endif #include "pycore_runtime.h" // _PyRuntime +#include "pycore_tstate.h" // _PyThreadStateImpl // Values for PyThreadState.state. A thread must be in the "attached" state @@ -239,6 +240,19 @@ PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void); // See also PyInterpreterState_Get() and _PyInterpreterState_GET(). extern PyInterpreterState* _PyGILState_GetInterpreterStateUnsafe(void); +static inline PyFreeListState* _PyFreeListState_GET(void) { + PyThreadState *tstate = _PyThreadState_GET(); +#ifdef Py_DEBUG + _Py_EnsureTstateNotNULL(tstate); +#endif + +#ifdef Py_GIL_DISABLED + return &((_PyThreadStateImpl*)tstate)->freelist_state; +#else + return &tstate->interp->freelist_state; +#endif +} + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h index 856ddd5e7e5ff0..11d0ee35315b16 100644 --- a/Include/internal/pycore_tstate.h +++ b/Include/internal/pycore_tstate.h @@ -11,6 +11,10 @@ extern "C" { #include "pycore_mimalloc.h" // struct _mimalloc_thread_state +typedef struct _Py_freelist_state { + struct _Py_list_state list; +} _Py_freelist_state; + // Every PyThreadState is actually allocated as a _PyThreadStateImpl. The // PyThreadState fields are exposed as part of the C API, although most fields // are intended to be private. The _PyThreadStateImpl fields not exposed. @@ -20,6 +24,7 @@ typedef struct _PyThreadStateImpl { #ifdef Py_GIL_DISABLED struct _mimalloc_thread_state mimalloc; + struct _Py_freelist_state freelist_state; #endif } _PyThreadStateImpl; diff --git a/Include/pytypedefs.h b/Include/pytypedefs.h index e78ed56a3b67cd..f218298f6ef5e1 100644 --- a/Include/pytypedefs.h +++ b/Include/pytypedefs.h @@ -23,6 +23,7 @@ typedef struct _frame PyFrameObject; typedef struct _ts PyThreadState; typedef struct _is PyInterpreterState; +typedef struct _Py_freelist_state PyFreeListState; #ifdef __cplusplus } diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 2d1f381e622226..631aa096d238ca 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1070,12 +1070,25 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate, static void clear_freelists(PyInterpreterState *interp) { + // TODO: Unify with clear_all_freelists _PyTuple_ClearFreeList(interp); _PyFloat_ClearFreeList(interp); - _PyList_ClearFreeList(interp); _PyDict_ClearFreeList(interp); _PyAsyncGen_ClearFreeLists(interp); _PyContext_ClearFreeList(interp); +#if defined(Py_GIL_DISABLED) + HEAD_LOCK(&_PyRuntime); + _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; + while (tstate != NULL) { + _PyList_ClearFreeList(&tstate->freelist_state); + tstate = tstate->base.next; + } + HEAD_UNLOCK(&_PyRuntime); +#else + // Only free-lists per interpreter are existed. + PyFreeListState* state = _PyFreeListState_GET(); + _PyList_ClearFreeList(state); +#endif } // Show stats for objects in each generations diff --git a/Objects/listobject.c b/Objects/listobject.c index 2d04218439bd20..db06d7597ec21a 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -24,8 +24,9 @@ _Py_DECLARE_STR(list_err, "list index out of range"); static struct _Py_list_state * get_list_state(void) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - return &interp->list; + PyFreeListState *state = _PyFreeListState_GET(); + assert(state != NULL); + return &state->list; } #endif @@ -120,12 +121,12 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size) } void -_PyList_ClearFreeList(PyInterpreterState *interp) +_PyList_ClearFreeList(PyFreeListState *state) { #if PyList_MAXFREELIST > 0 - struct _Py_list_state *state = &interp->list; - while (state->numfree) { - PyListObject *op = state->free_list[--state->numfree]; + struct _Py_list_state *list_state = &state->list; + while (list_state->numfree) { + PyListObject *op = list_state->free_list[--list_state->numfree]; assert(PyList_CheckExact(op)); PyObject_GC_Del(op); } @@ -135,10 +136,10 @@ _PyList_ClearFreeList(PyInterpreterState *interp) void _PyList_Fini(PyInterpreterState *interp) { - _PyList_ClearFreeList(interp); + PyFreeListState *state = _PyFreeListState_GET(); + _PyList_ClearFreeList(state); #if defined(Py_DEBUG) && PyList_MAXFREELIST > 0 - struct _Py_list_state *state = &interp->list; - state->numfree = -1; + state->list.numfree = -1; #endif } From 333873d77e196a3fd5d7d959c812830c027441a9 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 31 Dec 2023 00:06:40 +0900 Subject: [PATCH 02/53] nit --- Modules/gcmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 631aa096d238ca..886fa0003e3287 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1081,7 +1081,7 @@ clear_freelists(PyInterpreterState *interp) _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; while (tstate != NULL) { _PyList_ClearFreeList(&tstate->freelist_state); - tstate = tstate->base.next; + tstate = (_PyThreadStateImpl *)tstate->base.next; } HEAD_UNLOCK(&_PyRuntime); #else From 8b7e2618e146ff45643455be0bcf36719a6c02cc Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 31 Dec 2023 00:08:42 +0900 Subject: [PATCH 03/53] Remove comment --- Modules/gcmodule.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 886fa0003e3287..d8fd9bda8ee5ed 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1070,7 +1070,6 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate, static void clear_freelists(PyInterpreterState *interp) { - // TODO: Unify with clear_all_freelists _PyTuple_ClearFreeList(interp); _PyFloat_ClearFreeList(interp); _PyDict_ClearFreeList(interp); From dd0afa24964ae3983dc23d5e0b6df2ba81f9c32a Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 31 Dec 2023 00:28:10 +0900 Subject: [PATCH 04/53] Update _PyList_Fini --- Include/internal/pycore_list.h | 2 +- Objects/listobject.c | 3 +-- Python/pylifecycle.c | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 55d67b32bc8a63..44bfca9a4d5db7 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -15,7 +15,7 @@ extern void _PyList_DebugMallocStats(FILE *out); /* runtime lifecycle */ -extern void _PyList_Fini(PyInterpreterState *); +extern void _PyList_Fini(PyFreeListState *); /* other API */ diff --git a/Objects/listobject.c b/Objects/listobject.c index db06d7597ec21a..fab985daddb885 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -134,9 +134,8 @@ _PyList_ClearFreeList(PyFreeListState *state) } void -_PyList_Fini(PyInterpreterState *interp) +_PyList_Fini(PyFreeListState *state) { - PyFreeListState *state = _PyFreeListState_GET(); _PyList_ClearFreeList(state); #if defined(Py_DEBUG) && PyList_MAXFREELIST > 0 state->list.numfree = -1; diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 1d8af26e4a1cb7..38e63f909eb149 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1751,8 +1751,9 @@ finalize_interp_types(PyInterpreterState *interp) // a dict internally. _PyUnicode_ClearInterned(interp); + PyFreeListState *state = _PyFreeListState_GET(); _PyDict_Fini(interp); - _PyList_Fini(interp); + _PyList_Fini(state); _PyTuple_Fini(interp); _PySlice_Fini(interp); From f0d55dee36f062847eebee0af8a24da9620c08e2 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 31 Dec 2023 13:28:11 +0900 Subject: [PATCH 05/53] nit refactor --- Modules/gcmodule.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index d8fd9bda8ee5ed..7f92c40b909cb1 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1062,13 +1062,19 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate, } } +static void +clear_freelists(PyFreeListState *state) +{ + _PyList_ClearFreeList(state); +} + /* Clear all free lists * All free lists are cleared during the collection of the highest generation. * Allocated items in the free list may keep a pymalloc arena occupied. * Clearing the free lists may give back memory to the OS earlier. */ static void -clear_freelists(PyInterpreterState *interp) +clear_all_freelists(PyInterpreterState *interp) { _PyTuple_ClearFreeList(interp); _PyFloat_ClearFreeList(interp); @@ -1079,14 +1085,14 @@ clear_freelists(PyInterpreterState *interp) HEAD_LOCK(&_PyRuntime); _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; while (tstate != NULL) { - _PyList_ClearFreeList(&tstate->freelist_state); + clear_freelists(&tstate->freelist_state); tstate = (_PyThreadStateImpl *)tstate->base.next; } HEAD_UNLOCK(&_PyRuntime); #else // Only free-lists per interpreter are existed. - PyFreeListState* state = _PyFreeListState_GET(); - _PyList_ClearFreeList(state); + PyFreeListState *state = _PyFreeListState_GET(); + clear_freelists(state) #endif } @@ -1497,7 +1503,7 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason) /* Clear free list only during the collection of the highest * generation */ if (generation == NUM_GENERATIONS-1) { - clear_freelists(tstate->interp); + clear_all_freelists(tstate->interp); } if (_PyErr_Occurred(tstate)) { From 5e8e3b4ab8c8a0ccdc4dc63304233b47f4ffe6ef Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 31 Dec 2023 13:30:05 +0900 Subject: [PATCH 06/53] fix --- Modules/gcmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 7f92c40b909cb1..91d094a176f426 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1092,7 +1092,7 @@ clear_all_freelists(PyInterpreterState *interp) #else // Only free-lists per interpreter are existed. PyFreeListState *state = _PyFreeListState_GET(); - clear_freelists(state) + clear_freelists(state); #endif } From 7aa956a100e1a5b2b25314eca91cb37883037fbb Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 31 Dec 2023 14:06:56 +0900 Subject: [PATCH 07/53] Update finalize step --- Python/pylifecycle.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 38e63f909eb149..0b158a198cabde 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1727,6 +1727,11 @@ flush_std_files(void) */ +static void +finalize_free_lists(PyFreeListState *state) +{ + _PyList_Fini(state); +} static void finalize_interp_types(PyInterpreterState *interp) @@ -1751,15 +1756,27 @@ finalize_interp_types(PyInterpreterState *interp) // a dict internally. _PyUnicode_ClearInterned(interp); - PyFreeListState *state = _PyFreeListState_GET(); _PyDict_Fini(interp); - _PyList_Fini(state); _PyTuple_Fini(interp); _PySlice_Fini(interp); _PyUnicode_Fini(interp); _PyFloat_Fini(interp); + +#if defined(Py_GIL_DISABLED) + HEAD_LOCK(&_PyRuntime); + _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; + while (tstate != NULL) { + finalize_free_lists(&tstate->freelist_state); + tstate = (_PyThreadStateImpl *)tstate->base.next; + } + HEAD_UNLOCK(&_PyRuntime); +#else + PyFreeListState *state = _PyFreeListState_GET(); + finalize_free_lists(state); +#endif + #ifdef Py_DEBUG _PyStaticObjects_CheckRefcnt(interp); #endif From 908ef135a8dea022be98192886b4a7fd8ff5c8aa Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sun, 31 Dec 2023 14:39:36 +0900 Subject: [PATCH 08/53] pep7 --- Include/internal/pycore_pystate.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 05a0d80a9f74cc..e542298ca95a6d 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -240,7 +240,8 @@ PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void); // See also PyInterpreterState_Get() and _PyInterpreterState_GET(). extern PyInterpreterState* _PyGILState_GetInterpreterStateUnsafe(void); -static inline PyFreeListState* _PyFreeListState_GET(void) { +static inline PyFreeListState* _PyFreeListState_GET(void) +{ PyThreadState *tstate = _PyThreadState_GET(); #ifdef Py_DEBUG _Py_EnsureTstateNotNULL(tstate); From 00963832074fceafffda3da5ad9aee0592e2b76d Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 2 Jan 2024 15:37:55 +0900 Subject: [PATCH 09/53] Update --- Include/internal/pycore_gc.h | 2 +- Include/internal/pycore_list.h | 2 +- Include/internal/pycore_pystate.h | 2 +- Include/pytypedefs.h | 2 +- Modules/gcmodule.c | 4 ++-- Objects/listobject.c | 6 +++--- Python/pylifecycle.c | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index f099f02c15d4c9..cdb0e113d3f5b4 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -209,7 +209,7 @@ extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate); // Functions to clear types free lists extern void _PyTuple_ClearFreeList(PyInterpreterState *interp); extern void _PyFloat_ClearFreeList(PyInterpreterState *interp); -extern void _PyList_ClearFreeList(PyFreeListState *state); +extern void _PyList_ClearFreeList(_PyFreeListState *state); extern void _PyDict_ClearFreeList(PyInterpreterState *interp); extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp); extern void _PyContext_ClearFreeList(PyInterpreterState *interp); diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 44bfca9a4d5db7..9d7f6e427f7f82 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -15,7 +15,7 @@ extern void _PyList_DebugMallocStats(FILE *out); /* runtime lifecycle */ -extern void _PyList_Fini(PyFreeListState *); +extern void _PyList_Fini(_PyFreeListState *); /* other API */ diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index e542298ca95a6d..e85256fb95a304 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -240,7 +240,7 @@ PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void); // See also PyInterpreterState_Get() and _PyInterpreterState_GET(). extern PyInterpreterState* _PyGILState_GetInterpreterStateUnsafe(void); -static inline PyFreeListState* _PyFreeListState_GET(void) +static inline _PyFreeListState* _PyFreeListState_GET(void) { PyThreadState *tstate = _PyThreadState_GET(); #ifdef Py_DEBUG diff --git a/Include/pytypedefs.h b/Include/pytypedefs.h index f218298f6ef5e1..c9291316da205c 100644 --- a/Include/pytypedefs.h +++ b/Include/pytypedefs.h @@ -23,7 +23,7 @@ typedef struct _frame PyFrameObject; typedef struct _ts PyThreadState; typedef struct _is PyInterpreterState; -typedef struct _Py_freelist_state PyFreeListState; +typedef struct _Py_freelist_state _PyFreeListState; #ifdef __cplusplus } diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 91d094a176f426..c08e757ddc5929 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1063,7 +1063,7 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate, } static void -clear_freelists(PyFreeListState *state) +clear_freelists(_PyFreeListState *state) { _PyList_ClearFreeList(state); } @@ -1091,7 +1091,7 @@ clear_all_freelists(PyInterpreterState *interp) HEAD_UNLOCK(&_PyRuntime); #else // Only free-lists per interpreter are existed. - PyFreeListState *state = _PyFreeListState_GET(); + _PyFreeListState *state = _PyFreeListState_GET(); clear_freelists(state); #endif } diff --git a/Objects/listobject.c b/Objects/listobject.c index fab985daddb885..b4f15021f4807d 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -24,7 +24,7 @@ _Py_DECLARE_STR(list_err, "list index out of range"); static struct _Py_list_state * get_list_state(void) { - PyFreeListState *state = _PyFreeListState_GET(); + _PyFreeListState *state = _PyFreeListState_GET(); assert(state != NULL); return &state->list; } @@ -121,7 +121,7 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size) } void -_PyList_ClearFreeList(PyFreeListState *state) +_PyList_ClearFreeList(_PyFreeListState *state) { #if PyList_MAXFREELIST > 0 struct _Py_list_state *list_state = &state->list; @@ -134,7 +134,7 @@ _PyList_ClearFreeList(PyFreeListState *state) } void -_PyList_Fini(PyFreeListState *state) +_PyList_Fini(_PyFreeListState *state) { _PyList_ClearFreeList(state); #if defined(Py_DEBUG) && PyList_MAXFREELIST > 0 diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 0b158a198cabde..7220f960a7be5c 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1728,7 +1728,7 @@ flush_std_files(void) */ static void -finalize_free_lists(PyFreeListState *state) +finalize_free_lists(_PyFreeListState *state) { _PyList_Fini(state); } @@ -1773,7 +1773,7 @@ finalize_interp_types(PyInterpreterState *interp) } HEAD_UNLOCK(&_PyRuntime); #else - PyFreeListState *state = _PyFreeListState_GET(); + _PyFreeListState *state = _PyFreeListState_GET(); finalize_free_lists(state); #endif From bc8dd4a7ea9d1092a4d6bd1fa65f7e2604ec0c18 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 2 Jan 2024 16:01:18 +0900 Subject: [PATCH 10/53] Update --- Include/internal/pycore_freelist.h | 35 ++++++++++++++++++++++++++++++ Include/internal/pycore_gc.h | 4 +++- Include/internal/pycore_list.h | 22 ++----------------- Include/internal/pycore_pystate.h | 2 +- Include/internal/pycore_tstate.h | 5 +---- Include/pytypedefs.h | 1 - Makefile.pre.in | 1 + Modules/gcmodule.c | 2 +- Objects/listobject.c | 6 ++--- PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 6 +++++ Python/pylifecycle.c | 2 +- 12 files changed, 55 insertions(+), 32 deletions(-) create mode 100644 Include/internal/pycore_freelist.h diff --git a/Include/internal/pycore_freelist.h b/Include/internal/pycore_freelist.h new file mode 100644 index 00000000000000..f3b38e7dda55ac --- /dev/null +++ b/Include/internal/pycore_freelist.h @@ -0,0 +1,35 @@ +#ifndef Py_INTERNAL_FREELIST_H +#define Py_INTERNAL_FREELIST_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# 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 +# define PyList_MAXFREELIST 80 +#endif + +struct _Py_list_state { +#if PyList_MAXFREELIST > 0 + PyListObject *free_list[PyList_MAXFREELIST]; + int numfree; +#endif +}; + +typedef struct _Py_freelist_state { + struct _Py_list_state list; +} _Py_freelist_state; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_FREELIST_H */ diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index cdb0e113d3f5b4..bb7e1cdc69c6f8 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -8,6 +8,8 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_tstate.h" // _Py_freelist_state + /* GC information is stored BEFORE the object structure. */ typedef struct { // Pointer to next object in the list. @@ -209,7 +211,7 @@ extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate); // Functions to clear types free lists extern void _PyTuple_ClearFreeList(PyInterpreterState *interp); extern void _PyFloat_ClearFreeList(PyInterpreterState *interp); -extern void _PyList_ClearFreeList(_PyFreeListState *state); +extern void _PyList_ClearFreeList(_Py_freelist_state *state); extern void _PyDict_ClearFreeList(PyInterpreterState *interp); extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp); extern void _PyContext_ClearFreeList(PyInterpreterState *interp); diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 9d7f6e427f7f82..8d49c0bdff6109 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -8,6 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_freelist.h" // _Py_freelist_state extern PyObject* _PyList_Extend(PyListObject *, PyObject *); extern void _PyList_DebugMallocStats(FILE *out); @@ -15,28 +16,9 @@ extern void _PyList_DebugMallocStats(FILE *out); /* runtime lifecycle */ -extern void _PyList_Fini(_PyFreeListState *); +extern void _PyList_Fini(_Py_freelist_state *); -/* other API */ - -#ifndef WITH_FREELISTS -// without freelists -# define PyList_MAXFREELIST 0 -#endif - -/* Empty list reuse scheme to save calls to malloc and free */ -#ifndef PyList_MAXFREELIST -# define PyList_MAXFREELIST 80 -#endif - -struct _Py_list_state { -#if PyList_MAXFREELIST > 0 - PyListObject *free_list[PyList_MAXFREELIST]; - int numfree; -#endif -}; - #define _PyList_ITEMS(op) _Py_RVALUE(_PyList_CAST(op)->ob_item) extern int diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index e85256fb95a304..6ffd61d6db0589 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -240,7 +240,7 @@ PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void); // See also PyInterpreterState_Get() and _PyInterpreterState_GET(). extern PyInterpreterState* _PyGILState_GetInterpreterStateUnsafe(void); -static inline _PyFreeListState* _PyFreeListState_GET(void) +static inline _Py_freelist_state* _PyFreeListState_GET(void) { PyThreadState *tstate = _PyThreadState_GET(); #ifdef Py_DEBUG diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h index 11d0ee35315b16..472fa08154e8f9 100644 --- a/Include/internal/pycore_tstate.h +++ b/Include/internal/pycore_tstate.h @@ -8,13 +8,10 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_freelist.h" // struct _Py_freelist_state #include "pycore_mimalloc.h" // struct _mimalloc_thread_state -typedef struct _Py_freelist_state { - struct _Py_list_state list; -} _Py_freelist_state; - // Every PyThreadState is actually allocated as a _PyThreadStateImpl. The // PyThreadState fields are exposed as part of the C API, although most fields // are intended to be private. The _PyThreadStateImpl fields not exposed. diff --git a/Include/pytypedefs.h b/Include/pytypedefs.h index c9291316da205c..e78ed56a3b67cd 100644 --- a/Include/pytypedefs.h +++ b/Include/pytypedefs.h @@ -23,7 +23,6 @@ typedef struct _frame PyFrameObject; typedef struct _ts PyThreadState; typedef struct _is PyInterpreterState; -typedef struct _Py_freelist_state _PyFreeListState; #ifdef __cplusplus } diff --git a/Makefile.pre.in b/Makefile.pre.in index 6a64547e97d266..767a127a86bc7e 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1827,6 +1827,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_floatobject.h \ $(srcdir)/Include/internal/pycore_format.h \ $(srcdir)/Include/internal/pycore_frame.h \ + $(srcdir)/Include/internal/pycore_freelist.h \ $(srcdir)/Include/internal/pycore_function.h \ $(srcdir)/Include/internal/pycore_genobject.h \ $(srcdir)/Include/internal/pycore_getopt.h \ diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index c08e757ddc5929..4c0da630fc9dc5 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1063,7 +1063,7 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate, } static void -clear_freelists(_PyFreeListState *state) +clear_freelists(_Py_freelist_state *state) { _PyList_ClearFreeList(state); } diff --git a/Objects/listobject.c b/Objects/listobject.c index b4f15021f4807d..8bb760ee0fdb7e 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -24,7 +24,7 @@ _Py_DECLARE_STR(list_err, "list index out of range"); static struct _Py_list_state * get_list_state(void) { - _PyFreeListState *state = _PyFreeListState_GET(); + _Py_freelist_state *state = _PyFreeListState_GET(); assert(state != NULL); return &state->list; } @@ -121,7 +121,7 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size) } void -_PyList_ClearFreeList(_PyFreeListState *state) +_PyList_ClearFreeList(_Py_freelist_state *state) { #if PyList_MAXFREELIST > 0 struct _Py_list_state *list_state = &state->list; @@ -134,7 +134,7 @@ _PyList_ClearFreeList(_PyFreeListState *state) } void -_PyList_Fini(_PyFreeListState *state) +_PyList_Fini(_Py_freelist_state *state) { _PyList_ClearFreeList(state); #if defined(Py_DEBUG) && PyList_MAXFREELIST > 0 diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index c90ad1a3592f67..d9211d9468a65e 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -231,6 +231,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index a96ca24cf08b66..4bd15ffd449a06 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -618,6 +618,12 @@ Include\internal + + Include\internal + + + Include\internal + Include\internal diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 7220f960a7be5c..954cb7fcc103c7 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1728,7 +1728,7 @@ flush_std_files(void) */ static void -finalize_free_lists(_PyFreeListState *state) +finalize_free_lists(_Py_freelist_state *state) { _PyList_Fini(state); } From 40bad6b0a460f3dfb04fee526ec02f2767dc029a Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 2 Jan 2024 16:08:12 +0900 Subject: [PATCH 11/53] fix --- Include/internal/pycore_pystate.h | 1 + Python/pylifecycle.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 6ffd61d6db0589..a339171e3ecf82 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -8,6 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_freelist.h" // _Py_freelist_state #include "pycore_runtime.h" // _PyRuntime #include "pycore_tstate.h" // _PyThreadStateImpl diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 954cb7fcc103c7..6e7692ec11f1c8 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1773,7 +1773,7 @@ finalize_interp_types(PyInterpreterState *interp) } HEAD_UNLOCK(&_PyRuntime); #else - _PyFreeListState *state = _PyFreeListState_GET(); + _Py_freelist_state *state = _PyFreeListState_GET(); finalize_free_lists(state); #endif From 1b0f37009ad367c30b02659d76e66375e512ec39 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 2 Jan 2024 16:15:34 +0900 Subject: [PATCH 12/53] fix --- Modules/gcmodule.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 4c0da630fc9dc5..035058a7290e37 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -27,6 +27,7 @@ #include "pycore_ceval.h" // _Py_set_eval_breaker_bit() #include "pycore_context.h" #include "pycore_dict.h" // _PyDict_MaybeUntrack() +#include "pycore_freelist.h" // _Py_freelist_state #include "pycore_initconfig.h" #include "pycore_interp.h" // PyInterpreterState.gc #include "pycore_object.h" From 3d6042ed3a938c7410450c11302bdcb588b0f089 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 2 Jan 2024 16:16:03 +0900 Subject: [PATCH 13/53] fix --- Modules/gcmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 035058a7290e37..821de33c7f8009 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1092,7 +1092,7 @@ clear_all_freelists(PyInterpreterState *interp) HEAD_UNLOCK(&_PyRuntime); #else // Only free-lists per interpreter are existed. - _PyFreeListState *state = _PyFreeListState_GET(); + _Py_freelist_state *state = _PyFreeListState_GET(); clear_freelists(state); #endif } From 09403dba16683798e562a8311c3efd7ef5a3acce Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 2 Jan 2024 16:42:32 +0900 Subject: [PATCH 14/53] fix --- Include/internal/pycore_gc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index bb7e1cdc69c6f8..df4df3a78faae7 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -8,7 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_tstate.h" // _Py_freelist_state +#include "pycore_freelist.h" // _Py_freelist_state /* GC information is stored BEFORE the object structure. */ typedef struct { From c05491eba6c08391576bf096efe87effd840a74a Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 2 Jan 2024 17:00:23 +0900 Subject: [PATCH 15/53] Update --- Include/internal/pycore_freelist.h | 2 +- Include/internal/pycore_gc.h | 4 ++-- Include/internal/pycore_list.h | 2 +- Include/internal/pycore_pystate.h | 4 ++-- Modules/gcmodule.c | 4 ++-- Objects/listobject.c | 6 +++--- Python/pylifecycle.c | 5 +++-- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Include/internal/pycore_freelist.h b/Include/internal/pycore_freelist.h index f3b38e7dda55ac..b725986528d864 100644 --- a/Include/internal/pycore_freelist.h +++ b/Include/internal/pycore_freelist.h @@ -27,7 +27,7 @@ struct _Py_list_state { typedef struct _Py_freelist_state { struct _Py_list_state list; -} _Py_freelist_state; +} _PyFreeListState; #ifdef __cplusplus } diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index df4df3a78faae7..e77ff5902d4ec7 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -8,7 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_freelist.h" // _Py_freelist_state +#include "pycore_freelist.h" // _PyFreeListState /* GC information is stored BEFORE the object structure. */ typedef struct { @@ -211,7 +211,7 @@ extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate); // Functions to clear types free lists extern void _PyTuple_ClearFreeList(PyInterpreterState *interp); extern void _PyFloat_ClearFreeList(PyInterpreterState *interp); -extern void _PyList_ClearFreeList(_Py_freelist_state *state); +extern void _PyList_ClearFreeList(_PyFreeListState *state); extern void _PyDict_ClearFreeList(PyInterpreterState *interp); extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp); extern void _PyContext_ClearFreeList(PyInterpreterState *interp); diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 8d49c0bdff6109..9c6a24c50a9d79 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -16,7 +16,7 @@ extern void _PyList_DebugMallocStats(FILE *out); /* runtime lifecycle */ -extern void _PyList_Fini(_Py_freelist_state *); +extern void _PyList_Fini(_PyFreeListState *); #define _PyList_ITEMS(op) _Py_RVALUE(_PyList_CAST(op)->ob_item) diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index a339171e3ecf82..348c5c634284b0 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -8,7 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_freelist.h" // _Py_freelist_state +#include "pycore_freelist.h" // _PyFreeListState #include "pycore_runtime.h" // _PyRuntime #include "pycore_tstate.h" // _PyThreadStateImpl @@ -241,7 +241,7 @@ PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void); // See also PyInterpreterState_Get() and _PyInterpreterState_GET(). extern PyInterpreterState* _PyGILState_GetInterpreterStateUnsafe(void); -static inline _Py_freelist_state* _PyFreeListState_GET(void) +static inline _PyFreeListState* _PyFreeListState_GET(void) { PyThreadState *tstate = _PyThreadState_GET(); #ifdef Py_DEBUG diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 821de33c7f8009..10c133e30206a3 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -27,7 +27,7 @@ #include "pycore_ceval.h" // _Py_set_eval_breaker_bit() #include "pycore_context.h" #include "pycore_dict.h" // _PyDict_MaybeUntrack() -#include "pycore_freelist.h" // _Py_freelist_state +#include "pycore_freelist.h" // _PyFreeListState #include "pycore_initconfig.h" #include "pycore_interp.h" // PyInterpreterState.gc #include "pycore_object.h" @@ -1064,7 +1064,7 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate, } static void -clear_freelists(_Py_freelist_state *state) +clear_freelists(_PyFreeListState *state) { _PyList_ClearFreeList(state); } diff --git a/Objects/listobject.c b/Objects/listobject.c index 8bb760ee0fdb7e..b4f15021f4807d 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -24,7 +24,7 @@ _Py_DECLARE_STR(list_err, "list index out of range"); static struct _Py_list_state * get_list_state(void) { - _Py_freelist_state *state = _PyFreeListState_GET(); + _PyFreeListState *state = _PyFreeListState_GET(); assert(state != NULL); return &state->list; } @@ -121,7 +121,7 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size) } void -_PyList_ClearFreeList(_Py_freelist_state *state) +_PyList_ClearFreeList(_PyFreeListState *state) { #if PyList_MAXFREELIST > 0 struct _Py_list_state *list_state = &state->list; @@ -134,7 +134,7 @@ _PyList_ClearFreeList(_Py_freelist_state *state) } void -_PyList_Fini(_Py_freelist_state *state) +_PyList_Fini(_PyFreeListState *state) { _PyList_ClearFreeList(state); #if defined(Py_DEBUG) && PyList_MAXFREELIST > 0 diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 6e7692ec11f1c8..7085e4af0b799f 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1728,7 +1728,7 @@ flush_std_files(void) */ static void -finalize_free_lists(_Py_freelist_state *state) +finalize_free_lists(_PyFreeListState *state) { _PyList_Fini(state); } @@ -1773,7 +1773,8 @@ finalize_interp_types(PyInterpreterState *interp) } HEAD_UNLOCK(&_PyRuntime); #else - _Py_freelist_state *state = _PyFreeListState_GET(); + // Only free-lists per interpreter are existed. + _PyFreeListState *state = _PyFreeListState_GET(); finalize_free_lists(state); #endif From d5f9559da157ec851a07848254f714d948edd1a3 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 2 Jan 2024 17:01:35 +0900 Subject: [PATCH 16/53] fix --- Modules/gcmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 10c133e30206a3..6bf11cae82813e 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1092,7 +1092,7 @@ clear_all_freelists(PyInterpreterState *interp) HEAD_UNLOCK(&_PyRuntime); #else // Only free-lists per interpreter are existed. - _Py_freelist_state *state = _PyFreeListState_GET(); + _PyFreeListState *state = _PyFreeListState_GET(); clear_freelists(state); #endif } From 3dd3c3f3e42511f99f4317d252750f232de315ff Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 2 Jan 2024 17:02:22 +0900 Subject: [PATCH 17/53] update --- Include/internal/pycore_list.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 9c6a24c50a9d79..6c29d882335512 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -8,7 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_freelist.h" // _Py_freelist_state +#include "pycore_freelist.h" // _PyFreeListState extern PyObject* _PyList_Extend(PyListObject *, PyObject *); extern void _PyList_DebugMallocStats(FILE *out); From 0d8ea53dc0be0ce1197f3765ac5c045467d0614d Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 2 Jan 2024 17:34:08 +0900 Subject: [PATCH 18/53] nit --- Modules/gcmodule.c | 3 +-- Python/pylifecycle.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 6bf11cae82813e..86e65ac85a466d 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1092,8 +1092,7 @@ clear_all_freelists(PyInterpreterState *interp) HEAD_UNLOCK(&_PyRuntime); #else // Only free-lists per interpreter are existed. - _PyFreeListState *state = _PyFreeListState_GET(); - clear_freelists(state); + clear_freelists(&interp->freelist_state); #endif } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 7085e4af0b799f..307eb9620b833c 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1774,8 +1774,7 @@ finalize_interp_types(PyInterpreterState *interp) HEAD_UNLOCK(&_PyRuntime); #else // Only free-lists per interpreter are existed. - _PyFreeListState *state = _PyFreeListState_GET(); - finalize_free_lists(state); + finalize_free_lists(&interp->freelist_state); #endif #ifdef Py_DEBUG From e9d813859951bb829d8aa42b18f79b9d410b1be8 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 2 Jan 2024 22:26:14 +0900 Subject: [PATCH 19/53] Address code review --- Objects/listobject.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index b4f15021f4807d..ba5128fd973e31 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -121,12 +121,12 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size) } void -_PyList_ClearFreeList(_PyFreeListState *state) +_PyList_ClearFreeList(_PyFreeListState *freelist_state) { #if PyList_MAXFREELIST > 0 - struct _Py_list_state *list_state = &state->list; - while (list_state->numfree) { - PyListObject *op = list_state->free_list[--list_state->numfree]; + struct _Py_list_state *state = &freelist_state->list; + while (state->numfree) { + PyListObject *op = state->free_list[--state->numfree]; assert(PyList_CheckExact(op)); PyObject_GC_Del(op); } From 07e05360f86ac856e5befc6655e6b43135ef9d0c Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 2 Jan 2024 23:41:16 +0900 Subject: [PATCH 20/53] Update Python/pylifecycle.c Co-authored-by: Erlend E. Aasland --- Python/pylifecycle.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 307eb9620b833c..6b46252d7b704c 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1765,6 +1765,7 @@ finalize_interp_types(PyInterpreterState *interp) _PyFloat_Fini(interp); #if defined(Py_GIL_DISABLED) + // Finalize all per-thread free-lists. HEAD_LOCK(&_PyRuntime); _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; while (tstate != NULL) { @@ -1773,7 +1774,8 @@ finalize_interp_types(PyInterpreterState *interp) } HEAD_UNLOCK(&_PyRuntime); #else - // Only free-lists per interpreter are existed. + // No per-thread free-lists in GIL builds; + // we only need to finalize per-interpreter free-lists. finalize_free_lists(&interp->freelist_state); #endif From 6c8ba678a8770feb10ebaf97cb52492d9221dae1 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 2 Jan 2024 23:42:24 +0900 Subject: [PATCH 21/53] Address code review --- Modules/gcmodule.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 86e65ac85a466d..00bc23c9038908 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1083,6 +1083,7 @@ clear_all_freelists(PyInterpreterState *interp) _PyAsyncGen_ClearFreeLists(interp); _PyContext_ClearFreeList(interp); #if defined(Py_GIL_DISABLED) + // Finalize all per-thread free-lists. HEAD_LOCK(&_PyRuntime); _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; while (tstate != NULL) { @@ -1091,7 +1092,8 @@ clear_all_freelists(PyInterpreterState *interp) } HEAD_UNLOCK(&_PyRuntime); #else - // Only free-lists per interpreter are existed. + // No per-thread free-lists in GIL builds; + // we only need to finalize per-interpreter free-lists. clear_freelists(&interp->freelist_state); #endif } From 8a809702157ba17a19700709943b5a66df7d9cd1 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 00:52:44 +0900 Subject: [PATCH 22/53] Address code review --- Include/internal/pycore_gc.h | 5 +++++ Python/pylifecycle.c | 18 ++---------------- Python/pystate.c | 5 +++++ 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index e77ff5902d4ec7..1c3ddf8639adcc 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -218,6 +218,11 @@ extern void _PyContext_ClearFreeList(PyInterpreterState *interp); extern void _Py_ScheduleGC(PyInterpreterState *interp); extern void _Py_RunGC(PyThreadState *tstate); +static inline void _Py_ClearFreeLists(_PyFreeListState *state) +{ + _PyList_ClearFreeList(state); +} + #ifdef __cplusplus } #endif diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 6b46252d7b704c..9ca1171abedf5a 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1727,11 +1727,6 @@ flush_std_files(void) */ -static void -finalize_free_lists(_PyFreeListState *state) -{ - _PyList_Fini(state); -} static void finalize_interp_types(PyInterpreterState *interp) @@ -1764,19 +1759,10 @@ finalize_interp_types(PyInterpreterState *interp) _PyUnicode_Fini(interp); _PyFloat_Fini(interp); -#if defined(Py_GIL_DISABLED) - // Finalize all per-thread free-lists. - HEAD_LOCK(&_PyRuntime); - _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; - while (tstate != NULL) { - finalize_free_lists(&tstate->freelist_state); - tstate = (_PyThreadStateImpl *)tstate->base.next; - } - HEAD_UNLOCK(&_PyRuntime); -#else +#ifndef Py_GIL_DISABLED // No per-thread free-lists in GIL builds; // we only need to finalize per-interpreter free-lists. - finalize_free_lists(&interp->freelist_state); + _Py_ClearFreeLists(&interp->freelist_state); #endif #ifdef Py_DEBUG diff --git a/Python/pystate.c b/Python/pystate.c index 84e2d6ea172f2b..f070fc834cfe65 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1528,6 +1528,11 @@ PyThreadState_Clear(PyThreadState *tstate) Py_CLEAR(tstate->context); +#ifdef Py_GIL_DISABLED + // Each thread should clear own freelists for the free-threading build. + _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; + _Py_ClearFreeLists(freelist_state); +#endif if (tstate->on_delete != NULL) { // For the "main" thread of each interpreter, this is meant // to be done in _PyInterpreterState_SetNotRunningMain(). From 6d2f2d42ec83bd4ba9174bbb1d466c29b8859fe6 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 00:54:41 +0900 Subject: [PATCH 23/53] nit --- Python/pystate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index f070fc834cfe65..8e7cc89e6207ba 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1529,7 +1529,7 @@ PyThreadState_Clear(PyThreadState *tstate) Py_CLEAR(tstate->context); #ifdef Py_GIL_DISABLED - // Each thread should clear own freelists for the free-threading build. + // Each thread should clear own freelists in free-threading builds. _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; _Py_ClearFreeLists(freelist_state); #endif From 887bacf9850d04d6d5e6e260dd70e8e73904d2ed Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 01:08:44 +0900 Subject: [PATCH 24/53] Use _Py_FinalizeFreeLists --- Include/internal/pycore_gc.h | 6 +----- Python/pylifecycle.c | 7 ++++++- Python/pystate.c | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 1c3ddf8639adcc..eec3ee7486d48a 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -209,6 +209,7 @@ extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate); // Functions to clear types free lists +extern void _Py_FinalizeFreeLists(_PyFreeListState *state); extern void _PyTuple_ClearFreeList(PyInterpreterState *interp); extern void _PyFloat_ClearFreeList(PyInterpreterState *interp); extern void _PyList_ClearFreeList(_PyFreeListState *state); @@ -218,11 +219,6 @@ extern void _PyContext_ClearFreeList(PyInterpreterState *interp); extern void _Py_ScheduleGC(PyInterpreterState *interp); extern void _Py_RunGC(PyThreadState *tstate); -static inline void _Py_ClearFreeLists(_PyFreeListState *state) -{ - _PyList_ClearFreeList(state); -} - #ifdef __cplusplus } #endif diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 9ca1171abedf5a..46fdd0c1077e67 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1728,6 +1728,11 @@ flush_std_files(void) */ +void _Py_FinalizeFreeLists(_PyFreeListState *state) +{ + _PyList_Fini(state); +} + static void finalize_interp_types(PyInterpreterState *interp) { @@ -1762,7 +1767,7 @@ finalize_interp_types(PyInterpreterState *interp) #ifndef Py_GIL_DISABLED // No per-thread free-lists in GIL builds; // we only need to finalize per-interpreter free-lists. - _Py_ClearFreeLists(&interp->freelist_state); + _Py_FinalizeFreeLists(&interp->freelist_state); #endif #ifdef Py_DEBUG diff --git a/Python/pystate.c b/Python/pystate.c index 8e7cc89e6207ba..3d718d13a14fd8 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1531,7 +1531,7 @@ PyThreadState_Clear(PyThreadState *tstate) #ifdef Py_GIL_DISABLED // Each thread should clear own freelists in free-threading builds. _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; - _Py_ClearFreeLists(freelist_state); + _Py_FinalizeFreeLists(freelist_state); #endif if (tstate->on_delete != NULL) { // For the "main" thread of each interpreter, this is meant From e65952f516418a80c47a60be7379ad032b75936b Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 01:10:58 +0900 Subject: [PATCH 25/53] nit --- Python/pystate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index 3d718d13a14fd8..da07029caa6b7c 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1529,7 +1529,7 @@ PyThreadState_Clear(PyThreadState *tstate) Py_CLEAR(tstate->context); #ifdef Py_GIL_DISABLED - // Each thread should clear own freelists in free-threading builds. + // Each thread should finalize own freelists in free-threading builds. _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; _Py_FinalizeFreeLists(freelist_state); #endif From 25a67148a42d147783933de7a5a6949f09a60061 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 01:19:42 +0900 Subject: [PATCH 26/53] fix --- Include/internal/pycore_gc.h | 1 - Python/pylifecycle.c | 8 +------- Python/pystate.c | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index eec3ee7486d48a..e77ff5902d4ec7 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -209,7 +209,6 @@ extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate); // Functions to clear types free lists -extern void _Py_FinalizeFreeLists(_PyFreeListState *state); extern void _PyTuple_ClearFreeList(PyInterpreterState *interp); extern void _PyFloat_ClearFreeList(PyInterpreterState *interp); extern void _PyList_ClearFreeList(_PyFreeListState *state); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 46fdd0c1077e67..17f5354f4313c7 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1727,12 +1727,6 @@ flush_std_files(void) */ - -void _Py_FinalizeFreeLists(_PyFreeListState *state) -{ - _PyList_Fini(state); -} - static void finalize_interp_types(PyInterpreterState *interp) { @@ -1767,7 +1761,7 @@ finalize_interp_types(PyInterpreterState *interp) #ifndef Py_GIL_DISABLED // No per-thread free-lists in GIL builds; // we only need to finalize per-interpreter free-lists. - _Py_FinalizeFreeLists(&interp->freelist_state); + _PyList_Fini(&interp->freelist_state); #endif #ifdef Py_DEBUG diff --git a/Python/pystate.c b/Python/pystate.c index da07029caa6b7c..f565f14d86a815 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1531,7 +1531,7 @@ PyThreadState_Clear(PyThreadState *tstate) #ifdef Py_GIL_DISABLED // Each thread should finalize own freelists in free-threading builds. _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; - _Py_FinalizeFreeLists(freelist_state); + _PyList_ClearFreeList(freelist_state); #endif if (tstate->on_delete != NULL) { // For the "main" thread of each interpreter, this is meant From 3fd9baad8b83758125db92fe13b53bf4be90c707 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 01:23:36 +0900 Subject: [PATCH 27/53] fix --- Include/internal/pycore_gc.h | 1 + Modules/gcmodule.c | 10 ++-------- Python/pylifecycle.c | 7 ++++++- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index e77ff5902d4ec7..cd7c69786ca46a 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -209,6 +209,7 @@ extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate); // Functions to clear types free lists +extern void _Py_ClearFreeLists(_PyFreeListState *state); extern void _PyTuple_ClearFreeList(PyInterpreterState *interp); extern void _PyFloat_ClearFreeList(PyInterpreterState *interp); extern void _PyList_ClearFreeList(_PyFreeListState *state); diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 00bc23c9038908..5027e97b27470f 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1063,12 +1063,6 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate, } } -static void -clear_freelists(_PyFreeListState *state) -{ - _PyList_ClearFreeList(state); -} - /* Clear all free lists * All free lists are cleared during the collection of the highest generation. * Allocated items in the free list may keep a pymalloc arena occupied. @@ -1087,14 +1081,14 @@ clear_all_freelists(PyInterpreterState *interp) HEAD_LOCK(&_PyRuntime); _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; while (tstate != NULL) { - clear_freelists(&tstate->freelist_state); + _Py_ClearFreeLists(&tstate->freelist_state); tstate = (_PyThreadStateImpl *)tstate->base.next; } HEAD_UNLOCK(&_PyRuntime); #else // No per-thread free-lists in GIL builds; // we only need to finalize per-interpreter free-lists. - clear_freelists(&interp->freelist_state); + _Py_ClearFreeLists(&interp->freelist_state); #endif } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 17f5354f4313c7..185f3e63dbf621 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1727,6 +1727,11 @@ flush_std_files(void) */ +void _Py_ClearFreeLists(_PyFreeListState *state) +{ + _PyList_ClearFreeList(state); +} + static void finalize_interp_types(PyInterpreterState *interp) { @@ -1761,7 +1766,7 @@ finalize_interp_types(PyInterpreterState *interp) #ifndef Py_GIL_DISABLED // No per-thread free-lists in GIL builds; // we only need to finalize per-interpreter free-lists. - _PyList_Fini(&interp->freelist_state); + _Py_ClearFreeLists(&interp->freelist_state); #endif #ifdef Py_DEBUG From e175b613e8d6b97e3f3851a9644ea134ab1e0e4b Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 01:26:55 +0900 Subject: [PATCH 28/53] fix --- Python/pylifecycle.c | 7 +------ Python/pystate.c | 6 ++++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 185f3e63dbf621..17f5354f4313c7 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1727,11 +1727,6 @@ flush_std_files(void) */ -void _Py_ClearFreeLists(_PyFreeListState *state) -{ - _PyList_ClearFreeList(state); -} - static void finalize_interp_types(PyInterpreterState *interp) { @@ -1766,7 +1761,7 @@ finalize_interp_types(PyInterpreterState *interp) #ifndef Py_GIL_DISABLED // No per-thread free-lists in GIL builds; // we only need to finalize per-interpreter free-lists. - _Py_ClearFreeLists(&interp->freelist_state); + _PyList_Fini(&interp->freelist_state); #endif #ifdef Py_DEBUG diff --git a/Python/pystate.c b/Python/pystate.c index f565f14d86a815..afc1107dac8a11 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1455,6 +1455,12 @@ clear_datastack(PyThreadState *tstate) } } +void _Py_ClearFreeLists(_PyFreeListState *state) +{ + _PyList_ClearFreeList(state); +} + + void PyThreadState_Clear(PyThreadState *tstate) { From 295a292f10b2c3840e9549d55675e245848bf5f1 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 01:27:51 +0900 Subject: [PATCH 29/53] nit --- Python/pylifecycle.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 17f5354f4313c7..5dea5ceab2bf36 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1727,6 +1727,7 @@ flush_std_files(void) */ + static void finalize_interp_types(PyInterpreterState *interp) { From 5836c4bca2071eb41276d0ea164679a93f16bd75 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 01:29:59 +0900 Subject: [PATCH 30/53] nit --- Python/pystate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index afc1107dac8a11..85359338ffe577 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1460,7 +1460,6 @@ void _Py_ClearFreeLists(_PyFreeListState *state) _PyList_ClearFreeList(state); } - void PyThreadState_Clear(PyThreadState *tstate) { From 7cb261f63485d5c604d8f3c392a0f255288089e0 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 01:30:26 +0900 Subject: [PATCH 31/53] nit --- Python/pystate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index 85359338ffe577..49a150b4b0ac42 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1455,7 +1455,8 @@ clear_datastack(PyThreadState *tstate) } } -void _Py_ClearFreeLists(_PyFreeListState *state) +void +_Py_ClearFreeLists(_PyFreeListState *state) { _PyList_ClearFreeList(state); } From 01bbc7a8ba38ab3333e4ed214df83c5ab831136a Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 01:32:26 +0900 Subject: [PATCH 32/53] Revert naming of clear_all_freelists --- Modules/gcmodule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 5027e97b27470f..4be782f0ba7c5b 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1069,7 +1069,7 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate, * Clearing the free lists may give back memory to the OS earlier. */ static void -clear_all_freelists(PyInterpreterState *interp) +clear_freelists(PyInterpreterState *interp) { _PyTuple_ClearFreeList(interp); _PyFloat_ClearFreeList(interp); @@ -1499,7 +1499,7 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason) /* Clear free list only during the collection of the highest * generation */ if (generation == NUM_GENERATIONS-1) { - clear_all_freelists(tstate->interp); + clear_freelists(tstate->interp); } if (_PyErr_Occurred(tstate)) { From b08f65f319c6d14301f981aab828335587e42f52 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 01:39:22 +0900 Subject: [PATCH 33/53] Use _Py_ClearFreeLists as possible --- Python/pystate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index 49a150b4b0ac42..08443ddaa76ef3 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1537,7 +1537,7 @@ PyThreadState_Clear(PyThreadState *tstate) #ifdef Py_GIL_DISABLED // Each thread should finalize own freelists in free-threading builds. _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; - _PyList_ClearFreeList(freelist_state); + _Py_ClearFreeLists(freelist_state); #endif if (tstate->on_delete != NULL) { // For the "main" thread of each interpreter, this is meant From 65cedee6eff016d16d969c1b0a599d0c148f92a9 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 01:39:46 +0900 Subject: [PATCH 34/53] nit --- Python/pystate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index 08443ddaa76ef3..1b6e6003b6d971 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1535,7 +1535,7 @@ PyThreadState_Clear(PyThreadState *tstate) Py_CLEAR(tstate->context); #ifdef Py_GIL_DISABLED - // Each thread should finalize own freelists in free-threading builds. + // Each thread should clear own freelists in free-threading builds. _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; _Py_ClearFreeLists(freelist_state); #endif From 9a4070845985933e9ae95dd210690481a6db5307 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 02:01:22 +0900 Subject: [PATCH 35/53] Fix finalize code --- Python/pylifecycle.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 5dea5ceab2bf36..215dd2ef3bed44 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1727,6 +1727,11 @@ flush_std_files(void) */ +static void +finalize_freelists(_PyFreeListState *state) +{ + _PyList_Fini(state); +} static void finalize_interp_types(PyInterpreterState *interp) @@ -1759,11 +1764,8 @@ finalize_interp_types(PyInterpreterState *interp) _PyUnicode_Fini(interp); _PyFloat_Fini(interp); -#ifndef Py_GIL_DISABLED - // No per-thread free-lists in GIL builds; - // we only need to finalize per-interpreter free-lists. - _PyList_Fini(&interp->freelist_state); -#endif + _PyFreeListState *state = _PyFreeListState_GET(); + finalize_freelists(state); #ifdef Py_DEBUG _PyStaticObjects_CheckRefcnt(interp); From af86a200d263bff9dff4043f9a89d8178e3d5799 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 3 Jan 2024 02:05:36 +0900 Subject: [PATCH 36/53] nit --- Python/pylifecycle.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 215dd2ef3bed44..bd6475f99e464b 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1727,11 +1727,6 @@ flush_std_files(void) */ -static void -finalize_freelists(_PyFreeListState *state) -{ - _PyList_Fini(state); -} static void finalize_interp_types(PyInterpreterState *interp) @@ -1765,7 +1760,7 @@ finalize_interp_types(PyInterpreterState *interp) _PyFloat_Fini(interp); _PyFreeListState *state = _PyFreeListState_GET(); - finalize_freelists(state); + _PyList_Fini(state); #ifdef Py_DEBUG _PyStaticObjects_CheckRefcnt(interp); From 7ffa64cf5760f3fe359b41553b5f51e4309258bb Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 6 Jan 2024 08:27:14 +0900 Subject: [PATCH 37/53] Split implementation --- Include/internal/pycore_gc.h | 1 + Makefile.pre.in | 2 ++ PCbuild/_freeze_module.vcxproj | 2 ++ PCbuild/_freeze_module.vcxproj.filters | 6 ++++++ PCbuild/pythoncore.vcxproj | 2 ++ PCbuild/pythoncore.vcxproj.filters | 6 ++++++ Python/gc.c | 17 +---------------- 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 491d160b0d2ca0..ac5dbc66666f34 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -249,6 +249,7 @@ extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp); extern void _PyContext_ClearFreeList(PyInterpreterState *interp); extern void _Py_ScheduleGC(PyInterpreterState *interp); extern void _Py_RunGC(PyThreadState *tstate); +extern void _PyGC_Clear_FreeList(PyInterpreterState *interp); #ifdef __cplusplus } diff --git a/Makefile.pre.in b/Makefile.pre.in index 2930ee43cd9820..965abf2a0225cc 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -418,6 +418,8 @@ PYTHON_OBJS= \ Python/frozenmain.o \ Python/future.o \ Python/gc.o \ + Python/gc_free_threading.o \ + Python/gc_gil.o \ Python/getargs.o \ Python/getcompiler.o \ Python/getcopyright.o \ diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj index f16a763772e42e..610581bc96cb1a 100644 --- a/PCbuild/_freeze_module.vcxproj +++ b/PCbuild/_freeze_module.vcxproj @@ -208,6 +208,8 @@ + + diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters index 7f03cfea1b3e6f..3141913c043869 100644 --- a/PCbuild/_freeze_module.vcxproj.filters +++ b/PCbuild/_freeze_module.vcxproj.filters @@ -169,6 +169,12 @@ Source Files + + Source Files + + + Source Files + Source Files diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index dc958f1323b235..12635e2ffdfc34 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -568,6 +568,8 @@ + + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index cc90f60fa54ac9..5ae7e0d75c7135 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -1289,6 +1289,12 @@ Python + + Python + + + Python + Python diff --git a/Python/gc.c b/Python/gc.c index f47c74f87a9166..ee3e25e020a90f 100644 --- a/Python/gc.c +++ b/Python/gc.c @@ -1019,21 +1019,6 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate, } } -/* Clear all free lists - * All free lists are cleared during the collection of the highest generation. - * Allocated items in the free list may keep a pymalloc arena occupied. - * Clearing the free lists may give back memory to the OS earlier. - */ -static void -clear_freelists(PyInterpreterState *interp) -{ - _PyTuple_ClearFreeList(interp); - _PyFloat_ClearFreeList(interp); - _PyList_ClearFreeList(interp); - _PyDict_ClearFreeList(interp); - _PyAsyncGen_ClearFreeLists(interp); - _PyContext_ClearFreeList(interp); -} // Show stats for objects in each generations static void @@ -1449,7 +1434,7 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason) /* Clear free list only during the collection of the highest * generation */ if (generation == NUM_GENERATIONS-1) { - clear_freelists(tstate->interp); + _PyGC_Clear_FreeList(tstate->interp); } if (_PyErr_Occurred(tstate)) { From d6a2feb422c5825c79b64706fe8fb0a582ff7566 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 6 Jan 2024 08:28:16 +0900 Subject: [PATCH 38/53] Add files --- Python/gc_free_threading.c | 31 +++++++++++++++++++++++++++++++ Python/gc_gil.c | 24 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 Python/gc_free_threading.c create mode 100644 Python/gc_gil.c diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c new file mode 100644 index 00000000000000..360dbb4c4b1cdc --- /dev/null +++ b/Python/gc_free_threading.c @@ -0,0 +1,31 @@ +#ifdef Py_GIL_DISABLED + +#include "Python.h" +#include "pycore_pystate.h" // _PyFreeListState_GET() +#include "pycore_tstate.h" // _PyThreadStateImpl + +/* Clear all free lists + * All free lists are cleared during the collection of the highest generation. + * Allocated items in the free list may keep a pymalloc arena occupied. + * Clearing the free lists may give back memory to the OS earlier. + */ +void +_PyGC_Clear_FreeList(PyInterpreterState *interp) +{ + _PyTuple_ClearFreeList(interp); + _PyFloat_ClearFreeList(interp); + _PyList_ClearFreeList(interp); + _PyDict_ClearFreeList(interp); + _PyAsyncGen_ClearFreeLists(interp); + _PyContext_ClearFreeList(interp); + HEAD_LOCK(&_PyRuntime); + _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; + while (tstate != NULL) { + _PyList_ClearFreeList(&tstate->freelist_state); + tstate = tstate->base.next; + } + HEAD_UNLOCK(&_PyRuntime); +} + + +#endif \ No newline at end of file diff --git a/Python/gc_gil.c b/Python/gc_gil.c new file mode 100644 index 00000000000000..d3e441a0237561 --- /dev/null +++ b/Python/gc_gil.c @@ -0,0 +1,24 @@ +#ifndef Py_GIL_DISABLED + +#include "Python.h" +#include "pycore_pystate.h" // _PyFreeListState_GET() + +/* Clear all free lists + * All free lists are cleared during the collection of the highest generation. + * Allocated items in the free list may keep a pymalloc arena occupied. + * Clearing the free lists may give back memory to the OS earlier. + */ +void +_PyGC_Clear_FreeList(PyInterpreterState *interp) +{ + _PyTuple_ClearFreeList(interp); + _PyFloat_ClearFreeList(interp); + _PyList_ClearFreeList(interp); + _PyDict_ClearFreeList(interp); + _PyAsyncGen_ClearFreeLists(interp); + _PyContext_ClearFreeList(interp); + + _PyFreeListState* state = _PyFreeListState_GET(); + _PyList_ClearFreeList(state); +} +#endif \ No newline at end of file From 458aadb4910eb40e282e569288d6264cecaceca9 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 6 Jan 2024 08:29:16 +0900 Subject: [PATCH 39/53] nit --- Python/gc_free_threading.c | 2 +- Python/gc_gil.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 360dbb4c4b1cdc..d8897098bf7e04 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -28,4 +28,4 @@ _PyGC_Clear_FreeList(PyInterpreterState *interp) } -#endif \ No newline at end of file +#endif diff --git a/Python/gc_gil.c b/Python/gc_gil.c index d3e441a0237561..8bd9d32dea2b81 100644 --- a/Python/gc_gil.c +++ b/Python/gc_gil.c @@ -21,4 +21,4 @@ _PyGC_Clear_FreeList(PyInterpreterState *interp) _PyFreeListState* state = _PyFreeListState_GET(); _PyList_ClearFreeList(state); } -#endif \ No newline at end of file +#endif From b105bda651a65f08bbc0b3df3abd1efe1a8f92a3 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 6 Jan 2024 08:30:23 +0900 Subject: [PATCH 40/53] nit --- Python/gc_free_threading.c | 1 - Python/gc_gil.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index d8897098bf7e04..22a1987f4e0719 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -27,5 +27,4 @@ _PyGC_Clear_FreeList(PyInterpreterState *interp) HEAD_UNLOCK(&_PyRuntime); } - #endif diff --git a/Python/gc_gil.c b/Python/gc_gil.c index 8bd9d32dea2b81..95d3f22a52587e 100644 --- a/Python/gc_gil.c +++ b/Python/gc_gil.c @@ -21,4 +21,5 @@ _PyGC_Clear_FreeList(PyInterpreterState *interp) _PyFreeListState* state = _PyFreeListState_GET(); _PyList_ClearFreeList(state); } + #endif From 18e92163906f28b6ce717f1610922c8f27db940b Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 6 Jan 2024 08:35:24 +0900 Subject: [PATCH 41/53] fix --- Python/gc_free_threading.c | 4 ++-- Python/gc_gil.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 22a1987f4e0719..6d67bcae602c7c 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -14,14 +14,14 @@ _PyGC_Clear_FreeList(PyInterpreterState *interp) { _PyTuple_ClearFreeList(interp); _PyFloat_ClearFreeList(interp); - _PyList_ClearFreeList(interp); _PyDict_ClearFreeList(interp); _PyAsyncGen_ClearFreeLists(interp); _PyContext_ClearFreeList(interp); + HEAD_LOCK(&_PyRuntime); _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; while (tstate != NULL) { - _PyList_ClearFreeList(&tstate->freelist_state); + _Py_ClearFreeLists(&tstate->freelist_state); tstate = tstate->base.next; } HEAD_UNLOCK(&_PyRuntime); diff --git a/Python/gc_gil.c b/Python/gc_gil.c index 95d3f22a52587e..afb6c6125c0fea 100644 --- a/Python/gc_gil.c +++ b/Python/gc_gil.c @@ -13,13 +13,12 @@ _PyGC_Clear_FreeList(PyInterpreterState *interp) { _PyTuple_ClearFreeList(interp); _PyFloat_ClearFreeList(interp); - _PyList_ClearFreeList(interp); _PyDict_ClearFreeList(interp); _PyAsyncGen_ClearFreeLists(interp); _PyContext_ClearFreeList(interp); _PyFreeListState* state = _PyFreeListState_GET(); - _PyList_ClearFreeList(state); + _Py_ClearFreeLists(state); } #endif From 5bb8d3f3d77f9b9f341e1e3485d03d9c0e7d9cc3 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 6 Jan 2024 08:37:49 +0900 Subject: [PATCH 42/53] nit --- Python/gc_gil.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Python/gc_gil.c b/Python/gc_gil.c index afb6c6125c0fea..422e92e3dad9b7 100644 --- a/Python/gc_gil.c +++ b/Python/gc_gil.c @@ -1,7 +1,7 @@ #ifndef Py_GIL_DISABLED #include "Python.h" -#include "pycore_pystate.h" // _PyFreeListState_GET() +#include "pycore_pystate.h" // _Py_ClearFreeLists() /* Clear all free lists * All free lists are cleared during the collection of the highest generation. @@ -17,8 +17,7 @@ _PyGC_Clear_FreeList(PyInterpreterState *interp) _PyAsyncGen_ClearFreeLists(interp); _PyContext_ClearFreeList(interp); - _PyFreeListState* state = _PyFreeListState_GET(); - _Py_ClearFreeLists(state); + _Py_ClearFreeLists(&interp->freelist_state); } #endif From 2811a12db8abcc5e6c41d892bd1483bf7d4fe0c0 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 6 Jan 2024 09:21:47 +0900 Subject: [PATCH 43/53] fix --- Python/gc_free_threading.c | 4 ++-- Python/gc_gil.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 6d67bcae602c7c..de1e59ea525b85 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -1,9 +1,9 @@ -#ifdef Py_GIL_DISABLED - #include "Python.h" #include "pycore_pystate.h" // _PyFreeListState_GET() #include "pycore_tstate.h" // _PyThreadStateImpl +#ifdef Py_GIL_DISABLED + /* Clear all free lists * All free lists are cleared during the collection of the highest generation. * Allocated items in the free list may keep a pymalloc arena occupied. diff --git a/Python/gc_gil.c b/Python/gc_gil.c index 422e92e3dad9b7..b9796a2aabf81d 100644 --- a/Python/gc_gil.c +++ b/Python/gc_gil.c @@ -1,13 +1,14 @@ -#ifndef Py_GIL_DISABLED - #include "Python.h" #include "pycore_pystate.h" // _Py_ClearFreeLists() +#ifndef Py_GIL_DISABLED + /* Clear all free lists * All free lists are cleared during the collection of the highest generation. * Allocated items in the free list may keep a pymalloc arena occupied. * Clearing the free lists may give back memory to the OS earlier. */ + void _PyGC_Clear_FreeList(PyInterpreterState *interp) { From a5f494d65052748f204ecaaecfc411087b9fbfa4 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 6 Jan 2024 09:37:51 +0900 Subject: [PATCH 44/53] fix compiler warn --- Python/gc_free_threading.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index de1e59ea525b85..ac35cab3d3ab49 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -3,7 +3,6 @@ #include "pycore_tstate.h" // _PyThreadStateImpl #ifdef Py_GIL_DISABLED - /* Clear all free lists * All free lists are cleared during the collection of the highest generation. * Allocated items in the free list may keep a pymalloc arena occupied. @@ -22,7 +21,7 @@ _PyGC_Clear_FreeList(PyInterpreterState *interp) _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; while (tstate != NULL) { _Py_ClearFreeLists(&tstate->freelist_state); - tstate = tstate->base.next; + tstate = (_PyThreadStateImpl *)tstate->base.next; } HEAD_UNLOCK(&_PyRuntime); } From 837ae6054d4bdcd0afb6872ffdbb530a30c6785c Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 6 Jan 2024 09:54:58 +0900 Subject: [PATCH 45/53] nit --- Include/internal/pycore_gc.h | 2 +- Python/gc.c | 2 +- Python/gc_free_threading.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index ac5dbc66666f34..545ce43f31c912 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -240,6 +240,7 @@ extern PyObject *_PyGC_GetObjects(PyInterpreterState *interp, Py_ssize_t generat extern PyObject *_PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs); // Functions to clear types free lists +extern void _PyGC_ClearFreeList(PyInterpreterState *interp); extern void _Py_ClearFreeLists(_PyFreeListState *state); extern void _PyTuple_ClearFreeList(PyInterpreterState *interp); extern void _PyFloat_ClearFreeList(PyInterpreterState *interp); @@ -249,7 +250,6 @@ extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp); extern void _PyContext_ClearFreeList(PyInterpreterState *interp); extern void _Py_ScheduleGC(PyInterpreterState *interp); extern void _Py_RunGC(PyThreadState *tstate); -extern void _PyGC_Clear_FreeList(PyInterpreterState *interp); #ifdef __cplusplus } diff --git a/Python/gc.c b/Python/gc.c index ee3e25e020a90f..047ecfc96ee09f 100644 --- a/Python/gc.c +++ b/Python/gc.c @@ -1434,7 +1434,7 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason) /* Clear free list only during the collection of the highest * generation */ if (generation == NUM_GENERATIONS-1) { - _PyGC_Clear_FreeList(tstate->interp); + _PyGC_ClearFreeList(tstate->interp); } if (_PyErr_Occurred(tstate)) { diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index ac35cab3d3ab49..1c300aead6b247 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -9,7 +9,7 @@ * Clearing the free lists may give back memory to the OS earlier. */ void -_PyGC_Clear_FreeList(PyInterpreterState *interp) +_PyGC_ClearFreeList(PyInterpreterState *interp) { _PyTuple_ClearFreeList(interp); _PyFloat_ClearFreeList(interp); From 08c861335d8aa56efd9b6a789e6376099b66b2c7 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 6 Jan 2024 09:58:59 +0900 Subject: [PATCH 46/53] fix --- Python/gc_gil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/gc_gil.c b/Python/gc_gil.c index b9796a2aabf81d..416b4255ef5ab5 100644 --- a/Python/gc_gil.c +++ b/Python/gc_gil.c @@ -10,7 +10,7 @@ */ void -_PyGC_Clear_FreeList(PyInterpreterState *interp) +_PyGC_ClearFreeList(PyInterpreterState *interp) { _PyTuple_ClearFreeList(interp); _PyFloat_ClearFreeList(interp); From b5eb4729dffcac2aca5ad04e64b566094b7b4074 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Sat, 6 Jan 2024 13:30:39 +0900 Subject: [PATCH 47/53] Adjust comment --- Python/gc_free_threading.c | 3 +++ Python/gc_gil.c | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 1c300aead6b247..909cd6f65e0314 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -3,10 +3,13 @@ #include "pycore_tstate.h" // _PyThreadStateImpl #ifdef Py_GIL_DISABLED + /* Clear all free lists * All free lists are cleared during the collection of the highest generation. * Allocated items in the free list may keep a pymalloc arena occupied. * Clearing the free lists may give back memory to the OS earlier. + * Free-threading version: Since freelists are managed per thread, + * GC should clear all freelists by traversing all threads. */ void _PyGC_ClearFreeList(PyInterpreterState *interp) diff --git a/Python/gc_gil.c b/Python/gc_gil.c index 416b4255ef5ab5..5d43be38d9754c 100644 --- a/Python/gc_gil.c +++ b/Python/gc_gil.c @@ -8,7 +8,6 @@ * Allocated items in the free list may keep a pymalloc arena occupied. * Clearing the free lists may give back memory to the OS earlier. */ - void _PyGC_ClearFreeList(PyInterpreterState *interp) { From 0d8dc3df929d768470572a709e52bc9f15342a28 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 6 Jan 2024 14:51:23 +0100 Subject: [PATCH 48/53] 2 tabs, not 8 spaces --- Makefile.pre.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index 965abf2a0225cc..e266f80d914062 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -419,7 +419,7 @@ PYTHON_OBJS= \ Python/future.o \ Python/gc.o \ Python/gc_free_threading.o \ - Python/gc_gil.o \ + Python/gc_gil.o \ Python/getargs.o \ Python/getcompiler.o \ Python/getcopyright.o \ From fe859e18d05beacf96363706ad31db4f5f564af0 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 9 Jan 2024 09:18:37 +0900 Subject: [PATCH 49/53] Rename to _PyGC_ClearAllFreeLists --- Include/internal/pycore_gc.h | 2 +- Python/gc.c | 2 +- Python/gc_free_threading.c | 2 +- Python/gc_gil.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 545ce43f31c912..aa572e8b887d40 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -240,7 +240,7 @@ extern PyObject *_PyGC_GetObjects(PyInterpreterState *interp, Py_ssize_t generat extern PyObject *_PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs); // Functions to clear types free lists -extern void _PyGC_ClearFreeList(PyInterpreterState *interp); +extern void _PyGC_ClearAllFreeLists(PyInterpreterState *interp); extern void _Py_ClearFreeLists(_PyFreeListState *state); extern void _PyTuple_ClearFreeList(PyInterpreterState *interp); extern void _PyFloat_ClearFreeList(PyInterpreterState *interp); diff --git a/Python/gc.c b/Python/gc.c index 047ecfc96ee09f..9f9a755f6ac95e 100644 --- a/Python/gc.c +++ b/Python/gc.c @@ -1434,7 +1434,7 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason) /* Clear free list only during the collection of the highest * generation */ if (generation == NUM_GENERATIONS-1) { - _PyGC_ClearFreeList(tstate->interp); + _PyGC_ClearAllFreeLists(tstate->interp); } if (_PyErr_Occurred(tstate)) { diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 909cd6f65e0314..351ad0a7a020e6 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -12,7 +12,7 @@ * GC should clear all freelists by traversing all threads. */ void -_PyGC_ClearFreeList(PyInterpreterState *interp) +_PyGC_ClearAllFreeLists(PyInterpreterState *interp) { _PyTuple_ClearFreeList(interp); _PyFloat_ClearFreeList(interp); diff --git a/Python/gc_gil.c b/Python/gc_gil.c index 5d43be38d9754c..b7a1cf701b9182 100644 --- a/Python/gc_gil.c +++ b/Python/gc_gil.c @@ -9,7 +9,7 @@ * Clearing the free lists may give back memory to the OS earlier. */ void -_PyGC_ClearFreeList(PyInterpreterState *interp) +_PyGC_ClearAllFreeLists(PyInterpreterState *interp) { _PyTuple_ClearFreeList(interp); _PyFloat_ClearFreeList(interp); From c284061df756b2046121aa0af511a0b9d4bde03e Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 9 Jan 2024 09:33:17 +0900 Subject: [PATCH 50/53] Pass is_finalization to _PyList_ClearFreeList --- Include/internal/pycore_gc.h | 4 ++-- Objects/listobject.c | 10 +++++----- Python/pystate.c | 14 +++++++------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index aa572e8b887d40..5d90d3a7f865da 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -241,10 +241,10 @@ extern PyObject *_PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs); // Functions to clear types free lists extern void _PyGC_ClearAllFreeLists(PyInterpreterState *interp); -extern void _Py_ClearFreeLists(_PyFreeListState *state); +extern void _Py_ClearFreeLists(_PyFreeListState *state, int is_finalization); extern void _PyTuple_ClearFreeList(PyInterpreterState *interp); extern void _PyFloat_ClearFreeList(PyInterpreterState *interp); -extern void _PyList_ClearFreeList(_PyFreeListState *state); +extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization); extern void _PyDict_ClearFreeList(PyInterpreterState *interp); extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp); extern void _PyContext_ClearFreeList(PyInterpreterState *interp); diff --git a/Objects/listobject.c b/Objects/listobject.c index 8ca0178f982d9c..8d1f3b63e2dce2 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -121,7 +121,7 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size) } void -_PyList_ClearFreeList(_PyFreeListState *freelist_state) +_PyList_ClearFreeList(_PyFreeListState *freelist_state, int is_finalization) { #if PyList_MAXFREELIST > 0 struct _Py_list_state *state = &freelist_state->list; @@ -130,16 +130,16 @@ _PyList_ClearFreeList(_PyFreeListState *freelist_state) assert(PyList_CheckExact(op)); PyObject_GC_Del(op); } + if (is_finalization) { + state->numfree = -1; + } #endif } void _PyList_Fini(_PyFreeListState *state) { - _PyList_ClearFreeList(state); -#if defined(Py_DEBUG) && PyList_MAXFREELIST > 0 - state->list.numfree = -1; -#endif + _PyList_ClearFreeList(state, 1); } /* Print summary info about the state of the optimized allocator */ diff --git a/Python/pystate.c b/Python/pystate.c index 0c68489c99d6a3..c34b3487cb7dfd 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1456,9 +1456,9 @@ clear_datastack(PyThreadState *tstate) } void -_Py_ClearFreeLists(_PyFreeListState *state) +_Py_ClearFreeLists(_PyFreeListState *state, int is_finalization) { - _PyList_ClearFreeList(state); + _PyList_ClearFreeList(state, is_finalization); } void @@ -1534,11 +1534,6 @@ PyThreadState_Clear(PyThreadState *tstate) Py_CLEAR(tstate->context); -#ifdef Py_GIL_DISABLED - // Each thread should clear own freelists in free-threading builds. - _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; - _Py_ClearFreeLists(freelist_state); -#endif if (tstate->on_delete != NULL) { // For the "main" thread of each interpreter, this is meant // to be done in _PyInterpreterState_SetNotRunningMain(). @@ -1548,6 +1543,11 @@ PyThreadState_Clear(PyThreadState *tstate) // don't call _PyInterpreterState_SetNotRunningMain() yet. tstate->on_delete(tstate->on_delete_data); } +#ifdef Py_GIL_DISABLED + // Each thread should clear own freelists in free-threading builds. + _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; + _Py_ClearFreeLists(freelist_state, 1); +#endif _PyThreadState_ClearMimallocHeaps(tstate); From a8e39b312c8fc566bedfa37623b9862868690106 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 9 Jan 2024 10:07:41 +0900 Subject: [PATCH 51/53] fix --- Objects/listobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 8d1f3b63e2dce2..c557ad20119327 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -125,7 +125,7 @@ _PyList_ClearFreeList(_PyFreeListState *freelist_state, int is_finalization) { #if PyList_MAXFREELIST > 0 struct _Py_list_state *state = &freelist_state->list; - while (state->numfree) { + while (state->numfree > 0) { PyListObject *op = state->free_list[--state->numfree]; assert(PyList_CheckExact(op)); PyObject_GC_Del(op); From 99ac37539bfefb15561cf08cfd28a0153e448827 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 9 Jan 2024 10:08:50 +0900 Subject: [PATCH 52/53] fix --- Python/gc_free_threading.c | 2 +- Python/gc_gil.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 351ad0a7a020e6..aea272840f950d 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -23,7 +23,7 @@ _PyGC_ClearAllFreeLists(PyInterpreterState *interp) HEAD_LOCK(&_PyRuntime); _PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; while (tstate != NULL) { - _Py_ClearFreeLists(&tstate->freelist_state); + _Py_ClearFreeLists(&tstate->freelist_state, 0); tstate = (_PyThreadStateImpl *)tstate->base.next; } HEAD_UNLOCK(&_PyRuntime); diff --git a/Python/gc_gil.c b/Python/gc_gil.c index b7a1cf701b9182..b0961cdbee904f 100644 --- a/Python/gc_gil.c +++ b/Python/gc_gil.c @@ -17,7 +17,7 @@ _PyGC_ClearAllFreeLists(PyInterpreterState *interp) _PyAsyncGen_ClearFreeLists(interp); _PyContext_ClearFreeList(interp); - _Py_ClearFreeLists(&interp->freelist_state); + _Py_ClearFreeLists(&interp->freelist_state, 0); } #endif From 0c331c77d2db5e346ebd3386b9b92a49944dbba6 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 9 Jan 2024 10:25:45 +0900 Subject: [PATCH 53/53] fix --- Python/pystate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index c34b3487cb7dfd..ddd57f75f3f363 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1546,7 +1546,7 @@ PyThreadState_Clear(PyThreadState *tstate) #ifdef Py_GIL_DISABLED // Each thread should clear own freelists in free-threading builds. _PyFreeListState *freelist_state = &((_PyThreadStateImpl*)tstate)->freelist_state; - _Py_ClearFreeLists(freelist_state, 1); + _Py_ClearFreeLists(freelist_state, 0); #endif _PyThreadState_ClearMimallocHeaps(tstate);